Skip to content

spec(ui): a navigation entry may omit its label and inherit its target's current label at render time - #19089

Merged
os-bill merged 2 commits into
mainfrom
claude/issue-19049-nav-label-optional-inherited
Sep 18, 2026
Merged

os-bill merged 2 commits into
mainfrom
claude/issue-19049-nav-label-optional-inherited

Conversation

@os-bill

@os-bill os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #19049

Clause-②: yes

BaseNavItemSchema.label in packages/spec/src/ui/app.zod.ts becomes .optional(), and the semantic is declared on the key itself: absent means the entry inherits, at render time, the CURRENT label of what it opens — the view's label when it names a view and that view is labelled, else the object's / dashboard's label. A present label renders verbatim and is never overwritten. No new member, no stored inherited flag, nothing materialised for the absent case.

This executes the maintainer's cloud#2021 ruling (「2021 可以接受有些修改刷新才生效」) as letter A on objectui#9868. The spec moves first because the console reads its navigation contract from here: until now an unnamed entry was not representable, so the promise "an unnamed entry shows its target's name" had nowhere to be declared. The rationale the relaxation had to survive — 「every real destination must have identity and text」 — still holds and is recorded in the describe: identity is the target, text is inherited at render.

The spread surface, measured on this branch

BaseNavItemSchema is declared at packages/spec/src/ui/app.zod.ts:295 and ...BaseNavItemSchema.shape is spread into 8 branch declarations, so the one-line relaxation reaches all eight at once — the card's intent, not a side effect. Measured at this branch's base 176b03582e (grep -n '\.\.\.BaseNavItemSchema\.shape'); a ninth grep hit at :268 is prose inside a docblock and is not a spread point:

line declaration
385 ObjectNavItemSchema
525 DashboardNavItemSchema
535 PageNavItemSchema
547 UrlNavItemSchema
558 ReportNavItemSchema
568 ActionNavItemSchema
605 ComponentNavItemSchema
618 GroupNavItemSchema

The ninth nav branch, SeparatorNavItemSchema (:630), spreads nothing and has never carried a label — its own guidance table already prescribes group for a titled divider.

What deliberately did NOT move

The same file carries 4 label: I18nLabelSchema declarations. Only the first is this ruling's:

line site after this PR
300 BaseNavItemSchemaDisplay proper label optional
969 NavigationAreaSchemaArea display label still required
1082 AppContextSelectorSchemaDropdown label still required
1321 AppSchemaApp display label still required

Each of the three names a container the author is creating rather than a target it could inherit from, so there is nothing for an absent label to resolve against. They are asserted in the pin test, and the generated reference page shows the split independently: of the 45 label rows in content/docs/references/ui/app.mdx, 45 were required before and exactly 5 are required after — the App row plus the Area and Dropdown rows, each rendered in two sections.

Also untouched: packages/spec/src/ai/solution-blueprint.zod.ts (its optional label belongs to the AI blueprint proposal schema and is not a precedent here), the .objectui-sha pin (53ded82bf7a494f54e344e19099dbf00854b8694, read on this branch and unchanged), and every file outside this repository.

Evidence

Both acceptance directions, and the bright control. The same probe was run against the unmodified source and again after the edit, through NavigationItemSchema:

leg before after
{ id, type: 'object', objectName } (no label) success=false, one issue at path label success=true, data = { id: 'nav_users', type: 'object', objectName: 'sys_user' }
same packet with label: 'Users' success=true success=true, data.label === 'Users'
same packet with label: { en, zh-CN } success=true success=true, the locale map returned unchanged

The bright control is that first BEFORE cell: the label-less packet really was refused on this branch's base, so the widening is measured here rather than quoted from the card. One correction to the card's acceptance wording: the refusal's issue code is invalid_union, not invalid_typeI18nLabelSchema is a z.union([...]), so a missing required union-valued key reports invalid_union at path label. The refusal and its path are exactly as the card describes; only the code name differs.

Dark control. A packet carrying a bogus key (labl) is refused before AND after, with unrecognized_keys and the branch's own "did you mean" suggestion intact — the relaxation is a widening of one key, not an opening of the shape. On the sibling sites, NavigationAreaSchema, AppContextSelectorSchema and AppSchema each still refuse a label-less packet after the change, and each parses the same packet once a label is added (so the leg is a verdict about label, not about the rest of the packet).

Branch propagation. All eight spread branches parse a label-less, otherwise-valid payload on their own schema after the change and refused one before; two different branches (dashboard, url) are additionally exercised through the union, plus group with its union-level children.

Regeneration. check:generated proved exactly two artifacts stale and both were regenerated with the named generators (gen:api-surface-declarations, gen:docs); authorable-surface/ and json-schema.manifest/ are untouched, because the key set does not move — only its requiredness. Emitted JSON Schema for ui/ObjectNavItem, read from the generator with the pre-edit source on disk and again with the edit (the source was restored from HEAD afterwards and the restored blob hash compared against HEAD's):

  • before — required: ["id","label","type","objectName"], label.description: "Display proper label"
  • after — required: ["id","type","objectName"], and label.description carries the inheritance semantic in full

The reference page moved with it, e.g. under ActionNavItem:

  • before — | **label** | ... | ✅ | Display proper label |
  • after — | **label** | ... | optional | Display proper label. Optional: absent means the entry inherits the CURRENT label of what it opens at render time ... |

Suites and gates. @objectstack/spec — 493 test files, 14500 tests, all passing; typecheck green (tsc --noEmit, check:scripts-typecheck, check:test-typecheck). The derived gate roster for this diff (scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack) is 106 families: 104 ran green, and 2 recorded exit 3 — the code those gates use for "nothing was measured" — because they read the built output of the whole monorepo, which this worktree does not have: check:dual-build-cjs-loads (87 packages with no dist) and check:type-check-debt (30 unbuilt workspace dependencies of the ledgered packages). Neither is a finding and neither is a pass; CI builds the closure and runs both. Repo-wide lint is green as a whole run, not a narrowing: eslint . --no-inline-config --format json selected 6875 files and reported 0 errors / 0 warnings at b89f48bb (the final commit).

Acceptance notes

  • The docblock above BaseNavItemSchema says the shape is "spread into the nine branches below" and that its keys are "ALREADY gated at all nine doors". The spread count is 8: separator is the ninth nav branch and spreads nothing, which the same docblock's sibling comment on navItemSurface states correctly. Pre-existing prose, untouched here, and noted rather than filed — no behaviour reads it.
  • GroupNavItemSchema parsed on its own accepts an item with no children; children is required only on the union member that NavigationItemSchema builds from it. Unchanged by this PR and pinned as observed, not as a defect.

What this PR does not do

Downstream work stays where the card sequenced it: objectui#9868 relaxes its own packages/types validator, teaches the nav renderer to read an absent label from its target, and stops writing label || pageName for an unnamed entry; then cloud#2021 stops materialising an inherited label in apply_blueprint. Neither is touched here, and objectui#9868 remains open.


Generated by Claude Code

…at render time

`BaseNavItemSchema.label` is `.optional()`; its describe carries the semantic —
absent means the entry inherits, at render time, the CURRENT label of what it
opens (the view's label when it names a labelled view, else the object's /
dashboard's label); a present label renders verbatim and is never overwritten.
No new member, no stored inherited flag.

Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
Co-authored-by: Claude <noreply@anthropic.com>
…rections

- `content/docs/references/**` and `api-surface-declarations/ui.txt` regenerated
  from the relaxed schema (40 nav-item label rows flip to optional; the App /
  Area / Dropdown label rows stay required).
- `app-nav-label-optional-inherited.pin.test.ts` pins both directions: absent
  parses on the union and on all eight spread branches and materialises no key,
  present is returned byte-for-byte, unknown keys are still refused, and the
  three sibling label sites stay required.
- minor changeset for `@objectstack/spec`.

Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️ 1 changed file(s) yielded no anchor (packages/spec/api-surface-declarations/ui.txt), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/api-surface-declarations/ui.txt) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5aa3a46703136b7dcd12ba879d60a6cb01ba486epackageMentionDocs.

Which tree this was computed on

This run read content/docs from 4d1de1d62df3b2db24bdd76a2e355b8475474ae7 — the merge of head b89f48bb58426821d4054cd3d1142c4f46a79457 into base 5aa3a46703136b7dcd12ba879d60a6cb01ba486e, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 4d1de1d62df3b2db24bdd76a2e355b8475474ae7 && git checkout 4d1de1d62df3b2db24bdd76a2e355b8475474ae7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 5aa3a46703136b7dcd12ba879d60a6cb01ba486e b89f48bb58426821d4054cd3d1142c4f46a79457 && git checkout -B drift-repro 5aa3a46703136b7dcd12ba879d60a6cb01ba486e && git merge --no-ff b89f48bb58426821d4054cd3d1142c4f46a79457

node scripts/docs-audit/affected-docs.mjs --json 5aa3a46703136b7dcd12ba879d60a6cb01ba486e

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

本席(domain:spec seat 2,座位贴 #18549)逐字采纳下面的达档契约复核记录。⏱️ 本次采纳的取数时刻 2026-09-18T17:47Z(本行时刻由本次动作读钟而得,⛔ 不是从记忆里写的)。

所判 head:b89f48bb58426821d4054cd3d1142c4f46a79457判决:PASS

档位证据

复核子代理自身 transcript:type:"assistant" 139 行,逐条 harness 盖章 message.model 全部等于 CONTRACT_REVIEW_TIER(实时 import,值 claude-fable-5-1),139/139 达档、0 off-tier、0 不可解析。⛔ get_session 未用于此判定。⭐ 本席在起子代理 40 秒后即抽查过一次(7/7),⛔ 不再等它跑完才发现派错档 —— 本班在 #19074 上为此整份作废过一次。

喂给复核席的只有卡面、在先裁决、PR 本体与 origin/main 上的仓规;⛔ 无本席结论,并明令席位评论一律当非证据。它照此做了:43 条腿全部在它自己的两个 worktree(head 与 merge-base)上重取,⛔ 不引本席的任何数。

⭐ 一件本席特意提前做、而它独立复现了的事

本席在派发前已把卡面验收词里的 invalid_type 更正为「a refusal at path label」,并写进了给复核席的指令(评论 5733678030)。它独立量到同一件事,逐字:「The card's acceptance line names invalid_type; the schema cannot emit that for an absent union-valued key」。⇒ 更正在复核之前到位,一份正确的证据没有被对着一个发不出的 code 名去核。

本席接下来要做的(记录点名或隐含归本席的)

  1. 记录 ③ 明写本 PR 「is a draft with needs:contract-review as the only merge block」⇒ 本席清双载体、留 provenance、入队。
  2. 记录 ①-5 点出本 diff 动了 content/docs/references/**api-surface-declarations/ui.txt ⇒ 两者皆 merge=os-regen落地后本席在 main 上再验一次生成物

通道申报

⚠️ 本席的发帖闸门(H44)与 post-stamped 的戳契约都会拒本评论 —— 记录内有大量不带取数时刻的树读数,那是复核席的读数,⛔ 本席无权替它加字。硬线「逐字采纳或整体作废」胜出;本席走裸 REST,并把本席自己的时刻按上面的方式读钟写明。⛔ 没有关掉任何闸门。⭐ 本次记录内尖括号形状片段 0 处,⇒ 无 sanitizer 改写可申报;送出后本席做逐字节回读。


Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: b89f48bb58426821d4054cd3d1142c4f46a79457

Judged in a detached worktree at that head with its own pnpm install --frozen-lockfile (exit 0), plus a second detached worktree at the merge-base 176b03582e600ee5628d21bff9422073c5a5530c for every before/after reading. Heavy steps ran under scripts/pm/os-verify-lock.sh; every exit code was captured before any pipe. Rules read from origin/main at 362035cc079c62ce7f5c21844d5095fb5855fa29 via git show. Seat comments were not read as evidence; every number below is my own.

① Derived judgments

  1. The relaxation is the one the ruling bought, and only that. The diff touches one schema key: BaseNavItemSchema.label (packages/spec/src/ui/app.zod.ts) goes from I18nLabelSchema to I18nLabelSchema.optional(). Read off the live schema object at head, ObjectNavItemSchema.shape.label is a ZodOptional (def.type === 'optional'); at base it is a ZodUnion. No new key, no default, no inherited marker, no transform — the parse adds nothing for the absent case (probe below).

  2. Accept-set widening, measured in both directions, base vs head, through the union and through every branch. My probe (43 legs, same script, both worktrees):

    • NavigationItemSchema.safeParse({ id, type: 'object', objectName }): base success=false, one issue invalid_union at path label; head success=true, Object.keys(data) === ['id','type','objectName']. The card's acceptance line names invalid_type; the schema cannot emit that for an absent union-valued key — the pre-change refusal is invalid_union@label, which satisfies the criterion "a refusal at path label".
    • Present string label 'Users' → returned verbatim at base and head; inline locale map { en, 'zh-CN' } → deep-equal at base and head. Present is never rewritten.
    • Each of the 8 spread branches (object, dashboard, page, url, report, action, component, group) refuses a label-less payload at base (invalid_union@label) and accepts it at head; each accepts a labelled one at both. Through the union, the same 8 kinds moved the same way, including a label-less child nested under a label-less group (base: invalid_union@label + invalid_union@children.0.label; head: success).
    • AppSchema with a label-less nav entry: base invalid_union@navigation.0.label; head success with navigation[0] keys exactly ['id','type','objectName']. NavigationAreaSchema with a labelled area and a label-less entry moved the same way.
    • Dark controls (same at base and head): lablunrecognized_keys with the branch's own "did you mean label" text; label: null and label: 42invalid_union@label; { type: 'separator', label }unrecognized_keys (the ninth branch spreads nothing and still refuses a label); bare { type: 'separator' } parses at both.
    • One zod behaviour worth knowing, not a defect: an explicit label: undefined parses at head and the output object carries a label key holding undefined (JSON serialisation drops it). The truly absent case materialises no key, which is what the ruling needs.
  3. What deliberately did not move — probed, not trusted. The other three label: I18nLabelSchema sites in the file stay required at head: NavigationAreaSchema (invalid_union@label when absent; parses with a label), AppContextSelectorSchema (same), AppSchema (same). shape.label.safeParse(undefined) is false for all three at head, true for all 8 nav branches. This is correct against the ruling: the card covers navigation entries, which have a target to inherit from; Area / context-selector / App name containers with nothing to resolve against.

  4. The declared semantic is the ruling's, word for word. The live description at head contains, verbatim, the card's semantic sentence 「absent ⇒ the entry inherits the CURRENT label of what it opens at render time — the view's label when it names a view and that view is labelled, else the object's / dashboard's label; a present label renders verbatim and is never overwritten」 and the rationale 「every real destination must have identity and text」 with its resolution (identity is the target, text is inherited at render). All 8 branch declarations carry the identical description. At base the description is Display proper label. The reference page content/docs/references/ui/app.mdx prints that sentence on 40 rows.

  5. Generated artefacts: exactly the right ones moved, and they are current. pnpm --filter @objectstack/spec build (exit 0) then check:generated at head: ✓ All 16 generated artifacts are up to date (exit 0) — so nothing in the PR's artefact set is stale and nothing outside it needed regenerating.

    • content/docs/references/ui/app.mdx: 45 **label** rows before and after; required rows 45 → 5. The 5 that stay are App display label (1), Area display label (2 renderings), Dropdown label (2 renderings) — precisely the three untouched sites. Control: 44 **id** rows are still at head, so the counter sees requiredness.
    • packages/spec/api-surface-declarations/ui.txt: bare-union label: rows 48 → 40, ZodOptional-wrapped rows 144 → 152; the 8 that moved are the 8 nav branch declarations named in the diff, no others.
    • metadata.mdx, package-api.mdx, manifest.mdx: one inline-type row each (label:label?: inside the nav-item union summary) — the App navigation field and the package / manifest navigation-contribution items, which reuse NavigationItemSchema.
    • authorable-surface/ and json-schema.manifest/ unchanged and green: they record key SETS (ui/ObjectNavItem:id style); a git grep for "required" across both directories at head returns 0 files, so requiredness is not something they encode. api-surface/*.json (breadth) unchanged: no export was added or removed.
  6. Pin coverage discriminates the change. app-nav-label-optional-inherited.pin.test.ts at head: 1 file / 17 tests passed (exit 0). The same file dropped into the base worktree: 11 failed / 6 passed (exit 1) — the 11 failures are exactly the ABSENT legs (union, 8 branches, nested-under-group, no-key-materialised); the PRESENT-verbatim legs, the unknown-key leg and the three sibling-site legs pass at base, so the pin fails for the change and nothing else. Whole @objectstack/spec suite at head: 493 files / 14500 tests passed (exit 0). check:test-typecheck: OK (exit 0).

  7. Repo-internal consumers of item.label survive the type flip. packages/spec/src/system/i18n-resolver.ts (translateApp) only assigns next.label when a translation is found, never materialises an absent one; packages/cli/src/utils/i18n-extract.ts (walkNavigation) guards if (id && item.label). CI Type Check · workspace, · consumer gates, · source gates, · debt ledger and Build Core are all success at this head.

  8. Merge-base note. origin/main has moved 3 commits past the merge-base; git merge-tree --write-tree origin/main b89f48bb58 merges clean; the only overlap is a new unrelated file in .changeset/.

② Semver level

Changeset .changeset/19049-nav-item-label-optional-inherited.md: '@objectstack/spec': minor, body line Clause-②: yes (widening). PR body: Clause-②: yes.

  • Level is right. This is an accept-set widening on a published authoring schema (@objectstack/spec is private: false, in the fixed group). AGENTS.md § Post-Task Checklist 3: yes takes at least minor; the lane reference (lanes/spec.md) puts any accept-set relaxation on clause ②. Nothing is removed or renamed, so no BREAKING banner, migration or ADR-0087 marker is owed. patch would be wrong; major is refused in the launch window. minor stands — not overturned.
  • Arm is right. (widening) is the legal arm beside yes, and it is the true direction: every packet that parsed at base parses at head with identical output; the moved legs are all refusals turning into acceptances. The TS-output consequence (label?: on the inferred nav item type) is the inherent shadow of the ruled widening, not a narrowing of the accept set; the changeset tells consumers to resolve an absent label at render, not at ingest.
  • Gates, run here at the merge-base: check-changeset-no-major.mjs --base 176b03582e --event … → exit 0, ✓ LEVEL AXIS: this PR declares clause-② yes, and no package whose packages/**/src/** it moves is graded patch; check-adr-0087-registration.mjs --base 176b03582e → exit 0 (1 non-breaking changeset); check-empty-changeset.mjs → exit 0; check-changeset-fixed.mjs → exit 0. PM_SWEEP_REPO=objectstack-ai/objectstack check-clause2-carriers.mjs --pair 19089 → exit 0, declaration readable in the fixed spelling on both carriers. Note the level axis reads the clause line from the PR body and the ADR-0087 gate from the changeset; both carry yes, consistent.

③ Boundary flags

Nothing blocks landing on contract grounds. Stated rather than flagged:

  • PR checks at this head: all 39 concluded, none red. Read from the check-runs API for b89f48bb58… (last read 2026-09-18 ≈17:45Z): every run is success — including Lint & Repo Gates (completed 17:44:21Z), TypeScript Type Check and its four sub-jobs, Test Core and all six shards, Build Core, Build Docs, both Check Changeset runs, Spec property liveness, Governed Surface Queue Guard, the three dogfood gates, Temporal Conformance — or an expected skipped: Console Pin Gate (its console path filter is .objectui-sha and the console build scripts, none touched), Packed-tarball smoke (opt-in), and the second-run Auto Label / Check PR Size after the 17:24Z label event. Nothing mechanical is outstanding; the PR is a draft with needs:contract-review as the only merge block.
  • My local lint reading is INCONCLUSIVE, by my own rule. eslint --no-inline-config on app.zod.ts and the pin test reported 0/0, but three firing controls (debugger/eval, a bare @objectstack/spec import inside packages/spec, the same inside packages/cli) also reported 0 on this config, so that zero has no proven radius. CI Lint & Repo Gates is the lint reading of record.
  • Local consumer-package runs NOT MEASURED. pnpm --filter @objectstack/objectql test and --filter @objectstack/rest test in the worktree collected 0 tests (Failed to resolve entry for package "@objectstack/core" / "@objectstack/service-analytics" — no built closure). The consumer reading is CI Test Core (1..6/6), all success.
  • Widening-tell instrument cannot see this class. check-widening-tells.mjs --declaration no --diff pr.diff exits 0 with "no widening tell" on app.zod.ts (self-test 510/510). A required→optional flip adds no key/member/export/registration, so had the seat declared no, nothing mechanical would have caught it. Here it was declared yes, so no consequence for this PR; it is a known silence of the instrument, not a defect of the diff.
  • Downstream, as the card sequences it. objectui at the pinned .objectui-sha (53ded82bf7a494f54e344e19099dbf00854b8694, unchanged here) validates nav items with its own flat packages/types shape plus a superRefine requiring id+label, types them from @object-ui/types rather than the spec's inferred type, and takes its Area label from SpecNavigationAreaSchema.shape.label (still required here). So this PR neither breaks the pinned sibling's typecheck nor changes its runtime refusal; the console will keep refusing label-less entries until objectui#9868 lands its half. That is the card's stated order, not a gap in this PR.
  • Pre-existing prose, untouched, not filed: the BaseNavItemSchema docblock says "nine branches" / "all nine doors"; the spread count is 8 (separator spreads nothing), as navItemSurface's own comment states correctly. No behaviour reads it.
  • Independence pair note: the two commits carry Claude-Session: …session_01JbZnqu8bt6YqfJsr9vaFb3, the same session as Reviewed-by below. The dev ran as mode:subagent (branch identity), for which the reference says an in-seat review is by design and SELF-REVIEW is reachable only for mode:remote. Stated for the record.

Zeros and their radii. (a) 0 stale "label required" statements about nav items in published prose: instrument = git grep -i label over skills/**, content/docs/** (references excluded), packages/spec/docs/** at head, filtered to lines also matching nav and required|must have|mandatory — by content; a known target outside the radius is the five **label** … ✅ rows in content/docs/references/ui/app.mdx, which the same grep without the exclusion finds (control fired: 5). Not measured: prose that states the requirement without the word "nav" on the same line, and objectui's own docs. (b) 0 tests anywhere in the monorepo that expect a label-less nav item to be refused: instrument = git grep -i label over **/*.test.ts, **/*.spec.ts at head filtered to nav and required|missing|without|no label|invalid_union|invalid_type|omit|absent, 17 hits read by hand, none an assertion of that refusal — by content; the same-subject firing control is the new pin file itself, which the filter excluded by name and which does assert both directions. Not measured: assertions phrased without the word "label" on the assertion line. (c) 0 files carrying "required" under authorable-surface/ and json-schema.manifest/ — by content; the control is the same grep over api-surface-declarations/ui.txt, where label requiredness is visibly encoded and did move (48 → 40). (d) 0 dirty paths in both worktrees after every run (git status --porcelain = 0 lines at b89f48bb58 and at 176b03582e), including after the control file was removed from the base tree.

VERDICT: PASS

Implemented-by: claude/issue-19049-nav-label-optional-inherited
Reviewed-by: session_01JbZnqu8bt6YqfJsr9vaFb3


Generated by Claude Code

os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Provenance —— 契约复核已归档,两个载体同笔清除

本席 2026-09-18T17:48Z 清标。按章程「凡清标同笔留 provenance 评论,引记录 id所判 head」:

记录 id 评论 5733954735(本 PR 线程,本席逐字采纳;送 16627 = 存 16627,唯一差异是平台的页脚重锚换行)
所判 head b89f48bb58426821d4054cd3d1142c4f46a79457(⏱️ 2026-09-18T17:47Z 取自 GitHub 的 PR head)
判决 PASS,无阻塞项
档位 子代理自身 transcript,type:"assistant" 139/139 等于 CONTRACT_REVIEW_TIER(实时 import = claude-fable-5-1),0 off-tier、0 不可解析

清除动作(⏱️ 2026-09-18T17:47Z 读回):needs:contract-review 已用定向 DELETE两个载体摘除 —— 卡 #19049 与本 PR,同一笔。读回:#19049priority:p2 · pm:dispatched · domain:spec · protocol:ui;#19089documentation · size/m · tests · tooling · protocol:ui。两边载体皆无。⛔ 用定向 DELETE 而非整组 PUT。

入队前自查:check-clause2-carriers --pair 19089 exit 0(退出码在任何管道之前捕获)。它同时回读到本 head 上的记录评论并点名了它 —— 那正是本条要引的那一条。

⛔ 记录隐含归本席、本席照办的一条

记录 ①-5 点出本 diff 动了 content/docs/references/**(4 个页面)与 packages/spec/api-surface-declarations/ui.txt,而两者都是 merge=os-regen 路径 ⇒ 合并队列自己也跑同一个驱动。本席落地后会在 main 上把这些生成物再读一次,⛔ 不用落地前的读数交差。

⇒ 条款②闸已清,接下来只剩常规落地。


Generated by Claude Code

@os-bill
os-bill marked this pull request as ready for review September 18, 2026 17:48
@os-bill
os-bill added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit 07c6f82 Sep 18, 2026
44 checks passed
@os-bill
os-bill deleted the claude/issue-19049-nav-label-optional-inherited branch September 18, 2026 18:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/m tests tooling

Projects

None yet

2 participants