Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

[finding] app-shell 还有第二个 PageHeader,副标题键拼写 description 且无 subtitle —— 与 layout 侧刚收敛的拼写再度分叉 #4761

Closed

Description

@yinlianghui

发现于 #3789 的实施(PR #4759),回传立单。observation-class:两组件各自渲染正确,今天无用户可见错误;缺陷是同仓两个同名组件对同一概念用不同键。

事实

待裁

app-shell 的 PageHeader 是否收敛到 subtitle(改公开 prop,涉及其消费面枚举与 changeset 定档),或明确记录两组件受众不同、拼写分叉可接受(那也应有一条钉子写死这个判断)。分诊时建议先量 app-shell PageHeader 的消费面再定。

参考

Activity

  1. os-support-ai commented on Aug 18, 2026

    @os-support-ai
    Collaborator

    First-touch grading (triage seat): promoted to pm:queue, type Task, measurement-first. Step 1 per the card: enumerate app-shell PageHeader's consumer surface. If convergence to subtitle (the #3789/PR #4759 direction — one concept, one key) is achievable non-breaking or with a deprecation alias + changeset at the repo's normal tier, do it; if the measurement shows it requires a breaking prop removal on a published surface, STOP and report the enumeration instead of pushing — that half becomes a maintainer decision. Either outcome must leave a pin: converged spelling, or an explicit test recording that the two components' audiences diverge deliberately.

    Size/model suggestion: S–M, mode:subagent.


    Generated by Claude Code

  2. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 21, 2026
  3. self-assigned this
    on Aug 22, 2026
  4. os-sales commented on Aug 22, 2026

    @os-sales
    Collaborator

    Claim — domain:ui execution seat, round 14.

    • Session: session_012u2pRjcqAYtoEjgr3wwhnK
    • Branch: claude/issue-4761-app-shell-pageheader-subtitle

    Dispatching measurement-first, exactly as triage ruled: enumerate app-shell PageHeader's consumer surface first. Converge to subtitle only if that is non-breaking or reachable with a deprecation alias at the normal changeset tier; if the enumeration shows it needs a breaking prop removal on a published surface, stop and report the enumeration rather than pushing — that half is the maintainer's. Either outcome leaves a pin.


    Generated by Claude Code

  5. os-sales commented on Aug 22, 2026

    @os-sales
    Collaborator
    {
      "issue": 4761,
      "status": "done",
      "branch": "claude/issue-4761-app-shell-pageheader-subtitle",
      "pr": "https://github.com/objectstack-ai/objectui/pull/5681",
      "premise_still_valid": true,
      "summary": "Measurement first, as triage ruled, and it landed on the CONVERGE branch rather than the stop-and-report one. app-shell's PageHeader is not on the published surface: the TypeScript checker (getExportsOfModule, never grep — `export *` propagates silently) reports 226 exports from both `src/index.ts` and the built `dist/index.d.ts`, and `PageHeader`/`PageHeaderComponentProps` are in neither (controls AppShell/ConsoleLayout/PreviewBadge reachable, a nonsense name not); the `exports` map declares only `.` and `./styles.css`, and Node's own resolver refuses `@object-ui/app-shell/layout`, `.../dist/layout/PageHeader.js` and `.../src/layout/PageHeader.js` with ERR_PACKAGE_PATH_NOT_EXPORTED while the declared entry resolves. In-repo: exactly 2 import sites and 2 JSX call sites, all four inside this same package (ObjectView.tsx, ObjectDataPage.tsx), both passing `description`. Contrast measured on the sibling: `@object-ui/layout`'s entry exports 33 symbols and PageHeader IS reachable — through an `export *` a text search of the barrel would have missed — which is why #3789 was a real breaking removal there and this is not one here. So: plain rename to `subtitle`, NO deprecation alias (with no supported specifier reaching the prop there is nothing to keep compatible, and an alias would be exactly the second dialect AGENTS.md #0.1 forbids). Rendered DOM unchanged; `dist/index.d.ts` and `dist/layout/index.d.ts` byte-identical across the change, only the unreachable `dist/layout/PageHeader.d.ts` moves. The pin is `packages/app-shell/src/layout/__tests__/PageHeader.subtitle.test.tsx` (5 cases): the subtitle asserted on the DOM a reader gets (a <p>, in the same block as the <h1> and after it, via compareDocumentPosition), the no-subtitle case, the `hidden sm:block` class contract, `description` drawing nothing AND rejected by tsc, and a compile-time assertion that BOTH packages' PageHeaderComponentProps declare `subtitle` — the one that goes red if either side drifts again. External consumers cannot be enumerated from this repo and the PR says so; what was enumerated is the set of import paths through which one could reach the component, which is empty. Two judgment calls worth a reviewer's eye, both stated in the PR body: (a) changeset tier — I chose `patch` on @object-ui/app-shell rather than an empty-frontmatter 'no release', because the tarball's bytes do move even though no supported consumer can observe it; (b) one clause of stale prose in the props doc comment ('@object-ui/layout ... should adopt this same name') was corrected to past tense in the same declaration I was editing, since layout adopted it in #3789. No docs edit was needed and none was made: every content/docs PageHeader page documents @object-ui/layout's component or the SDUI block, so the fenced docs paths were never touched. Nothing in the #4482 / #4594 / #4605 / #4758 fences was touched either.",
      "tests": "All at HEAD 0c37726, re-run after the final commit; every heavy step through scripts/pm/os-verify-lock.sh, verdicts read from the gate's own printed line, exit codes captured before any pipe.\n\nBUILD_EXIT=0 — `turbo run build --filter=@object-ui/app-shell --concurrency=2`, 29/29 tasks.\nTEST_EXIT=0 — `pnpm exec vitest run packages/app-shell/src/layout/ + every ObjectView.*/ObjectDataPage.* suite --reporter=verbose` (repo-root invocation, per AGENTS.md; `pnpm --filter <pkg> test` is the silent-false-green trap there) → `Test Files  40 passed (40)` / `Tests  338 passed (338)`.\nTC_EXIT=0 — `pnpm --filter @object-ui/app-shell type-check`, output echoed `> tsc --noEmit && tsc -p tsconfig.test.json` (so the filter matched a real script rather than exiting 0 on zero matches).\nPKG_LINT_EXIT=0 — `pnpm --filter @object-ui/app-shell lint` (whole package): 0 errors, 2551 pre-existing warnings.\nGates: check:control-bytes OK (4722 tracked files) · changeset:check OK · check-changeset-presence OK ('3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)') · check:spec-symbols OK · check:self-import OK · check:phantom-deps OK. Plus a control-byte self-scan of the five touched paths (grep -naP, no hits).\n\nDECLARED NARROWING: repo-wide `turbo run lint` was not run locally. Evidence it is a measurement and not a gap: the diff touches four files, all in @object-ui/app-shell, whose ENTIRE package was linted above (file count read from eslint's own --format json output on the targeted run: 4 files, 0 errors, 176 warnings); and eslint.config.js enables no type-aware linting (tseslint.configs.recommended, no parserOptions.project, no projectService), so an untouched file's verdict is computed from that file alone and cannot move because of this diff. CI runs the full farm regardless.\n\nABLATION — 3 legs, directions predicted BEFORE running, mutations confirmed on disk by counting the injected AND the removed text (an editor's exit code proves nothing: sed/perl -i/str.replace all exit 0 on zero matches), restores under `trap ... EXIT INT TERM` and verified BY HASH against the committed blobs (both files RESTORE OK: PageHeader.tsx f4e59819..., the pin c22a4530...).\nREBUILD: none required and none performed — a claim about resolution, not an omission. The pin imports `../PageHeader`, a RELATIVE specifier no `exports` map can intercept, so vitest transforms the mutated source directly and both tsc projects compile that same source; the only dist-resolved import in the file is `import type ... from '@object-ui/layout'`, and no leg mutates that package.\n  A) undo the convergence in PageHeader.tsx — predicted vitest RED (3 of 4 render cases) + tsc RED; observed `Tests  3 failed | 2 passed (5)` and tsc exit 2 with TS2322 at BOTH call sites (ObjectDataPage.tsx:514, ObjectView.tsx:2269). Came in slightly NARROWER than predicted: `type-check` is `tsc --noEmit && tsc -p tsconfig.test.json`, so the source project went red first and short-circuited before the test project reported its own errors — recorded as observed, not as templated.\n  B) drop `sm:block` from the subtitle class — predicted exactly 1 failing case + tsc GREEN; observed `Tests  1 failed | 4 passed (5)`, tsc exit 0. The class pin is not a tautology.\n  C) flip the compile-time `subtitle` assert — predicted vitest GREEN (type assertions are erased) + tsc RED; observed `Tests  5 passed (5)` and tsc exit 2 with `TS2344: Type 'false' does not satisfy the constraint 'true'`. This is the asymmetry worth recording: vitest proves nothing about case 5, and `tsc -p tsconfig.test.json` is the only thing that can.\nNo void legs — every mutation was confirmed present on disk and every restore confirmed absent, by count, before any result was read.\n\nCI: reported at draft-PR time per the dispatch contract; PR #5681 was `mergeable_state: unstable` (checks still running) when this was written. Not waited on.",
      "open_questions": [
        {
          "question": "Changeset tier for a prop rename that no supported consumer can reach: `patch` on @object-ui/app-shell, or an empty-frontmatter 'no release' declaration? Non-blocking — a changeset exists either way and the presence gate is green.",
          "options": [
            "A — `patch` (what I shipped): the tarball's bytes do move (dist/layout/PageHeader.d.ts changes and `files` ships dist), and the release-note prose is worth one line even though no API moved.",
            "B — empty frontmatter: AGENTS.md reserves that spelling for 纯内部改动, and this qualifies on every gauge a consumer can observe — dist/index.d.ts byte-identical, rendered DOM identical, no reachable specifier."
          ],
          "recommendation": "A, because the failure mode of over-declaring is one version number in a group that bumps constantly, while the failure mode of under-declaring is precisely the defect objectui#3387 exists to stop. Downgrading to B is a one-line edit if the maintainer reads it the other way."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions