Skip to content

spec(ui): retire PageHeaderProps.breadcrumb ("Show breadcrumb", default true) — no renderer draws a trail and the console shell already draws one; the spec half of objectui#11166 #20758

Description

@objectstack-fleet

Filed by the triage seat (objectstack-wide, seat post #6015, session_01AavokzJ5DndAwitDXvKy4U) as the spec half of objectstack-ai/objectui#11166, per that card's first grade. ⛔ Not a claim, ⛔ not a dispatch. Graded here: enhancement · priority:p3 · domain:spec · area:records · pm:queue.

What is declared, and what honours it

Ruling (triage, under the standing rule #18900 A′④: 「有 ⇒ 补消费端;没有 ⇒ 退役」)

RETIRE. The key has no consumer. The default-true slot has rendered empty on every page header without anyone missing a trail, and the trail it would draw is the shell's. So a renderer would duplicate the shell, not supply something missing.

  • This card (spec): retire breadcrumb from PageHeaderProps through the ADR-0087 route, the way icon was retired from the same row (ADR-0087 D2). An authored breadcrumb (true or false) on a stored or bundled page loads with the key stripped and the ADR-0087 notice. ⛔ It is never a hard refusal of an existing page. The generated artefacts, forms and docs the retirement playbook lists move in the same PR.
  • The objectui half (objectui#11166): the renderer stops reading the key and drops the empty slot. The docs stop showing the key. That half lands after this one reaches objectui's install face, or reads the key defensively until it does.
  • Same family, measured by this card, not assumed: the spec also declares a nav:breadcrumb component (emptyProps, about :5311), and objectui has no renderer for it (git grep "nav:breadcrumb" over objectui packages/*/src: 0 hits). The dev measures whether any producer writes it. With none, it retires under the same rule in the same PR. With one, the report names it and it stays.
  • Clause-②: yes (a key leaves a published strictObject). The ADR-0087 conversion keeps stored pages loading, and the changeset carries the BREAKING banner the playbook requires.
  • Pins:
    • a page header authored with breadcrumb: true and one with breadcrumb: false both load, with the key stripped and the notice recorded;
    • the ADR-0087 ledger row is present;
    • a page header without the key is unchanged (the control).

If the maintainer wants a page-level trail after all (for example on pages outside /apps/*, where the shell draws none), that is ENFORCE: a renderer in objectui plus a real trail source. Say so on this card and it is re-graded. The ruling above reflects no measured pull today.

Dedupe: this repo's issues were searched for breadcrumb PageHeaderProps (0 hits, as the objectui card also recorded) and nav:breadcrumb (0 open cards on it).

Activity

  1. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 17 · 2026-09-30T04:03Z
    Session: session_01Sfe5YjBLwB9J3y8fvm2xq1
    Account: os-justin (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-20758-page-header-breadcrumb-retired
    Worktree: objectstack-issue-20758
    Domain: domain:spec
    Seat: domain:spec#5 (seat post #19357)
    Clause-②: no (narrowing). The card's triage section declares the plain widening arm. A key leaving a published strictObject narrows the accept set and widens nothing the seat can name, so the seat declares no (narrowing), with the BREAKING banner and the ADR-0087 disposition, as on #20637 (PR #20710). If the diff widens something, the report names it and the line becomes yes (narrowing).
    Direction: the card's RETIRE ruling, taken whole. breadcrumb leaves PageHeaderProps through the ADR-0087 route. A stored or bundled page with breadcrumb (true or false) loads with the key stripped and a notice, and is ⛔ never hard-refused. nav:breadcrumb retires in the same PR only if the dev measures no producer. With a producer, the report names it and it stays. The card's three pins.
    File surface (stop on breach and explain it in the report):


    Generated by Claude Code

  2. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20758,
    "status": "blocked",
    "branch": "claude/issue-20758-page-header-breadcrumb-retired",
    "pr": "#20785",
    "session": "session_01Sfe5YjBLwB9J3y8fvm2xq1",
    "premise_still_valid": true,
    "summary": "BLOCKED on one surface decision only the seat can make; everything inside the claimed surface is done and pushed as draft PR #20785 (head 2805a3f, main merged in via os-regen-merge.sh). The census found a published author outside the claim: skills/objectstack-ui/rules/pages.md teaches breadcrumb: true (:89, an os:check definePage example) and lists breadcrumb in the page:header table row (:50). skills/** is a Tier H governed path not in the claim, so per the dispatch I stopped on that file and did not edit it. The new tree-scoped absence pin reds on exactly that file (and only it: ablation A12 excluding it turns the pin green). See open_questions. DONE: PageHeaderProps.breadcrumb is a retiredKey() tombstone (wording was removed in @objectstack/spec 17 (ADR-0087 D2) + os migrate meta --from 17, the #20710 post-17.5.0 precedent); D2 conversion page-header-breadcrumb-removed (toMajor 18, retiredFromLoadPath, retiredAfter 17.5.0, scoped by type page:header, strips true and false in regions / nested children / slotted pages, order 49 in MAJOR_18_CONVERSIONS, defined above permissionAllowRestorePurgeRemoved); RETIRED_KEYS_BY_MAJOR[18] entry ui/PageHeaderProps:breadcrumb (entries/retired-keys/18.ui__PageHeaderProps__breadcrumb.ts); D3 semantic entry page-header-breadcrumb-retired; STEP18_RATIONALE fragment (order 51); generated authorable-surface/ui.json ([RETIRED]), authorable-defaults/ui.json (default row gone), content/docs/references/ui/component.mdx; layout-dsl.mdx:61; component.test.ts :39/:48-52/:72 re-pinned on recordChrome; lint fixture validate-component-props.test.ts:68 swapped to recordChrome; changeset .changeset/20758-page-header-breadcrumb-retired.md (minor, BREAKING, FROM-TO, Clause-② no (narrowing), marker registered page-header-breadcrumb-removed, page-header-breadcrumb-retired). No retired-default residue stage: the true default was never materialized (page properties is an open bag; only the advisory props lint parses the row and writes nothing back). Nothing widens, so Clause-② stays no (narrowing). nav:breadcrumb MEASURED and KEPT: the card's 0-hit reading is an instrument artifact. git grep nav:breadcrumb -- packages/*/src answers 0 for the control nav:menu too (the non-magic pathspec does not descend). With :(glob)packages/*/src/** the result is 8 hits at objectui pin dd3f7e1be3 (the claim-time pin), 8 at db11afd4967c (the pin after #20706), and 8 at objectui origin/main 81f849852a; the control nav:menu gives 12 files at each. The producer is objectui app-shell previews/block-types.ts:118 BLOCK_TYPE_META['nav:breadcrumb'], which the Studio page designer's Add block picker writes as a { type: 'nav:breadcrumb' } node (PageBlockCanvas.tsx addBlock). It renders only the placeholder scaffold (components/renderers/placeholders.tsx PALETTE_PLACEHOLDER_BLOCKS). So component.zod.ts :342/:5311, page.zod.ts:159, component.test.ts:1335, format-type.test.ts:1378 and pages.mdx:184 are untouched. breadcrumb premise re-verified at pin db11afd4967c: containers.tsx:1508 reads it, :2346/:2380 draw an empty data-page-breadcrumb-slot, and block-config.ts:401 (Studio inspector 'Show breadcrumb') is the producer of stored values.",
    "tests": "All at HEAD 2805a3f unless marked pre-merge (de0687f). spec build: VERDICT command-exit 0. check:generated: all 15 artifacts up to date. spec pnpm test (local project): 577 files, 17021 passed | 1 todo. New repo test src/ui/page-header-breadcrumb-retirement.test.ts, with conversions-major18-merge.test.ts and step18-rationale-merge.test.ts: 39 passed | 1 failed. The failure is the absence pin: offenders ['skills/objectstack-ui/rules/pages.md authors breadcrumb: true']. spec test:repo, pre-merge: 45/46 files and 812/813 tests pass; the 1 failure is the same pin. spec typecheck: OK (tsc, scripts, test-typecheck held at 53 files / 251 errors); the new test is in tsconfig.test.json (listFilesOnly count 1), so its @ts-expect-error is live. lint pnpm test: 117 files, 5437 passed; lint typecheck OK (pre-merge). dogfood test/expression-conformance.test.ts: 7 passed (pre-merge). Local gates: dispatch-gates derived 112 families at 2805a3f. With --ran exit-coded, 111 ran with exit 0 and 1 is NOT MEASURED: check:dual-build-cjs-loads (exit 3, prerequisite is a full workspace build, and the diff touches no package.json, exports or entry). check:type-check-debt was measured green (4 ledger entries, 53 errors, none above record). check-adr-0087-registration: registered, both ids new here. check-changeset-no-major: ok. check:skill-examples: 259 blocks green; tsc cannot see into the open properties bag, so only the new pin catches the skill. Not run locally (CI-owned): repo-wide pnpm lint. ABLATIONS, each run from committed HEAD through scripts/ablation-replace.mjs (anchor hit x1, blob changed; restore blob == HEAD and git diff HEAD empty). Each suite run was page-header-breadcrumb-retirement.test.ts plus conversions.test.ts. The absence pin is red in every leg because of the skill, which is not attributable to any leg. A1 tombstone to z.boolean().default(true): 5 red: 'refuses true AND false at the key, with the prescription', 'the row the props lint dispatches on is the same schema, so it refuses it too', 'refuses the key by the TOMBSTONE, not by the strict unknown-key arm', 'CONTROL: a header without the key parses, grows no breadcrumb...', 'fails tsc at the authoring site...'. A2 unwire the conversion: 'a STORED page whose header says true, and one that says false, both load with the key stripped and the notice recorded' (card pin 1), 'a BUILT artifact replays the same strip', and 'wires the D2 conversion into the step-18 chain...'. A3 drop the RETIRED_KEYS_BY_MAJOR row: 'declares ONE key under major 18' (card pin 2). A4 copy-on-write guard removed: 'CONTROL: a header without the key is unchanged — no notice, and the row comes back by reference' (card pin 3) and 'is idempotent by construction'. A5 type scope widened: 'is scoped by component TYPE...' and conversions.test.ts 'page-header-breadcrumb-removed: before → after, emits 4 notice(s)'. A6 D3 id renamed: 'carries ONE D3 entry for the family...'. A7 nav:breadcrumb dropped from the enum. The first attempt was a NULL OP, refused by the tool because the replacement was a prefix of the anchor, so no run happened. The redo A7b red 'nav:breadcrumb is NOT part of it...'. A8 page door refuses the key: 'never hard-refuses an existing page...'. A9 key renamed: 'the walked shape keeps breadcrumb as a key' plus the 4 tombstone pins. A10 retiredFromLoadPath false: 'is retired from the load path...' and the wiring pin. A11 lint pin via dist. The first attempt was VOID: the spec build refused the mutation at gate (b2) ('RETIRED_KEYS_BY_MAJOR names a key that is still LIVE'), the marker was absent from dist, and the lint run read the old dist. The redo A11b used a JS-only tsup rebuild; ablation-dist-preflight found the marker PRESENT (exit 0), and lint 'reports a retired page-header breadcrumb as a warning carrying the prescription, for true and false' went red (1 failed / 48 passed). Restore: full spec build, preflight --absent exit 0, lint 49/49 green, tree clean. A12 skill excluded from the walk: absence pin green (19/19), which proves the skill is the only offender.",
    "mcp_calls": "0",
    "api_writes": "3 relay writes, each sent as one POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls (draft #20785, run 36675816851); (2) label-write --assign os-justin, POST /repos//issues/20785/assignees (run 36675867834; read back: assignees os-justin; labels documentation, size/l, tests, tooling, protocol:ui were set by Auto Label, not by me); (3) this os-dev-report comment, POST /repos//issues/20758/comments. No label writes: the dispatch named no labels, and skip-changeset does not apply because a changeset publishes. git push is not a REST write.",
    "open_questions": [
    {
    "question": "The published skill skills/objectstack-ui/rules/pages.md teaches the retired key (breadcrumb: true, at :89 inside an os:check definePage example, and 'Title + subtitle + breadcrumb + actions: string[]' in the page:header row at :50). It is outside the claim's file surface and is a Tier H governed path. How does it land?",
    "options": [
    "A: extend this PR's file surface to that one file (delete the :89 line; the :50 row becomes 'Title + subtitle + actions: string[] (action ids)'). The PR becomes Tier H: it needs an authorized approval to land and stays one PR. The absence pin goes green, and the changeset's measured sentence stays true as written.",
    "B: split the skill edit into its own Tier H PR that lands first. This PR's absence pin stays red until then, so the order is forced (or the pin moves into that PR). That means two PRs and a sequencing dependency.",
    "C: leave the skill as is. The published skill keeps teaching a retired key to AI authors, and the playbook-required absence pin stays red. Rejected."
    ],
    "recommendation": "A. The retirement playbook lists published skills as part of a retirement, the edit is two lines in one file, and a single landing avoids a forced order between two PRs. The cost is one maintainer approval."
    }
    ],
    "out_of_scope_findings": [
    "noted, not filed · carrier: objectui#11166 (the objectui half) · the Studio page palette offers nav:breadcrumb (block-types.ts:118), and it renders only the dashed 'Component Placeholder' scaffold in every host (placeholders.tsx PALETTE_PLACEHOLDER_BLOCKS), so an author-placeable block has no renderer. Not a/b/c: the metadata is neither refused nor dropped. It is the reason nav:breadcrumb stays in the spec. dedupe words: nav:breadcrumb palette placeholder, PALETTE_PLACEHOLDER_BLOCKS, block-types navBreadcrumb",
    "noted, not filed · carrier: objectui#11166 plus the next .objectui-sha bump (manifest regeneration) · until then the committed sdui.manifest.json:2489 still publishes breadcrumb as a page:header input, while the props lint now warns on it. That is two platform authorities disagreeing, the same interim shape the quickAdd retirement had. dedupe words: sdui manifest page:header breadcrumb input, block-config breadcrumb inspector",
    "noted, not filed · carrier: objectui#11166 · a stored header that said breadcrumb: false reads as absent after the D2 strip, so objectui draws the empty slot's spacing again (mb-1, or one extra gap-2 in the non-record layout) until the renderer drops the slot. This is recorded in the D3 entry page-header-breadcrumb-retired and the conversion docblock. dedupe words: data-page-breadcrumb-slot, empty breadcrumb slot spacing"
    ]
    }

  3. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling 1 on the dev report 5905125466 · 2026-09-30T06:03Z

    domain:spec seat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1), holder of claim 5903804962. Draft PR #20785 at 2805a3f033.

    Accepted as delivered, inside the claim:

    • The retiredKey() tombstone, the D2 conversion page-header-breadcrumb-removed, the RETIRED_KEYS_BY_MAJOR[18] row and the D3 entry page-header-breadcrumb-retired.
    • The STEP18_RATIONALE fragment, the generated artefacts and the re-pinned tests.
    • The changeset: minor, BREAKING, Clause-②: no (narrowing).
    • The twelve ablations, each red by name. The absence pin's only offender is the skill named below, as A12 shows.

    nav:breadcrumb stays: accepted.

    • The dev measured a producer: objectui's Studio palette writes { type: 'nav:breadcrumb' } nodes.
    • The card's "0 hits" reading came from a pathspec that does not descend into subdirectories, and the control nav:menu also reads 0 under it.
    • So the RETIRE rule does not reach this component, and the files that list it stay untouched.

    The skill: A. The claim's file surface extends to skills/objectstack-ui/rules/pages.md in this PR.

    • :89 teaches breadcrumb: true inside an os:check definePage example, and :50 lists breadcrumb in the page:header row. The seat read both at origin/main. Both go, as the dev proposes.
    • The retirement playbook counts published skills as part of a retirement, so one landing keeps the absence pin and the changeset's sentence true together.
    • This is the seat's composition error. The claim's text census covered packages/spec, content/docs and package sources, and skipped skills/**.
    • check-governed-merges --test on that path: 1 of 1 hits the register. The PR becomes Tier H, so it does not go ready, into the queue or onto auto-merge without an authorized approval on record. The seat puts it to the maintainer once the at-tier review passes.
    • No open PR touches skills/objectstack-ui/.

    Out-of-scope notes, recorded and not filed (carrier: objectstack-ai/objectui#11166 and the next .objectui-sha bump):

    • The palette's nav:breadcrumb renders only a placeholder.
    • sdui.manifest.json still publishes breadcrumb as a page:header input until the manifest regenerates.
    • A stored breadcrumb: false header regains the empty slot's spacing until the renderer drops the slot.

    Next: round 2 on the same branch, for the skill's two lines. Then CI, and then the at-tier contract review.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20758,
    "status": "done",
    "branch": "claude/issue-20758-page-header-breadcrumb-retired",
    "pr": "#20785",
    "session": "session_01Sfe5YjBLwB9J3y8fvm2xq1",
    "premise_still_valid": true,
    "summary": "Round 2, per seat ruling 5905149162 (A): the file surface was extended to skills/objectstack-ui/rules/pages.md. One new commit 70e0f05 (parent 2805a3f, no history rewrite, no force-push, model-free trailer pair) makes the two ruled edits. :50 BEFORE '| page:header | Title + subtitle + breadcrumb + actions: string[] (action ids) |' AFTER '| page:header | Title + subtitle + actions: string[] (action ids) |'. :89 BEFORE ' breadcrumb: true,' (between subtitle: '{company}', and actions: ['convert_lead'],) AFTER the line is deleted. Nothing else in the file moved. git diff --stat 2805a3f033..70e0f052ff is skills/objectstack-ui/rules/pages.md | 3 +--, 1 file changed, 1 insertion(+), 2 deletions(-). Skill readings: pages.md is 454 to 453 lines. The SKILL.md sum is 4404 to 4404 (pages.md is a rules file, not a SKILL.md). The whole skills/ tree is 13424 to 13423 lines, a pure deletion. Published text re-checked, nothing added. The changeset's 'The one in-repo author found was the published objectstack-ui skill's record-page example' is still true as a measurement. The D2 conversion docblock's 'No example app, skill or doc in this repo authors it' was false at 2805a3f and is true from 70e0f05. The PR body was not touched (it is the seat's; its 'Open gap' paragraph is now stale for the seat to revise).",
    "tests": "At head 70e0f05. check:skill-examples: exit 0, 259 marked blocks type-check across 3 surfaces; the edited os:check definePage example still passes. The absence pin src/ui/page-header-breadcrumb-retirement.test.ts is now GREEN: 1 file, 19/19 passed, VERDICT command-exit 0 (it was 18/19 at 2805a3f, red only on this file). check-governed-merges: --test with the final 15-path list (merge-base 9ad6544, +775/-12) exits 3 = GOVERNED, '1 of 15 path(s) hit the register', 'landing tier: H(人合)', 'skills/** ×1 — skills/objectstack-ui/rules/pages.md', size 787 ≤ 5000. --pr 20785 gives the same reading from the PR object (exit 3, 1 of 15, Tier H). This is expected per the ruling: the PR is Tier H and does not go ready, into the queue or onto auto-merge without an authorized approval. check-adr-0087-registration --base origin/main: exit 0, '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition', registered page-header-breadcrumb-removed, page-header-breadcrumb-retired, both new here. check-changeset-no-major --base origin/main: exit 0, 'This diff introduces no major bump'. check:nul-bytes: exit 0, 9406 text files, no raw control bytes; the self-scan of pages.md has no hits. dispatch-gates at 70e0f05 derives 118 families. The 6 that the skill path added all ran with exit 0: check-skills-token-ratchet (54 files within their ceilings) plus its --self-test, check:agent-test-spelling, check:pm-governed-merges, check:skill-compatibility, check:skill-frame-sync. Of round 1's other 112, the 40 whose names read skills or docs were re-run at 70e0f05, and all 40 exited 0. Among them: check:skill-refs, check:doc-authoring, check:issue-citations, check:skill-identifier-liveness, check:corpus-claim-drift, check:llms-txt, check:quick-reference-counts, check:published-files, check:doc-anchors, the docs-* family, and the lint doc-formula/doc-security-posture gates. The remaining 72 read no skills path and were not re-run; round 1 ran them green at 2805a3f, except check:dual-build-cjs-loads, which is still NOT MEASURED (it needs a full workspace build). CI, one reading at 2026-09-30T06:10:44Z on 70e0f05, 32 names deduplicated. success: Auto Label, Build Docs, Check Changeset, Check Documentation Links, Check PR Size, Flag docs affected by code changes, Governed Surface Queue Guard, both claim guards, Part-of guard, Spec property liveness, card-claims-branch, Type Check · source gates, filter. skipped: Console Pin Gate (filter output console=false: the diff has no console input) and Packed-tarball smoke (opt-in) (needs the needs:pack-smoke label). in_progress: Build Core, Dogfood Regression Gate 1-3, Dogfood Verify CLI, Lint & Repo Gates, Temporal Conformance, Test Core 1-6, Type Check consumer gates / debt ledger / workspace. The prior head 2805a3f shows 'TypeScript Type Check' and 'Dogfood Regression Gate' failure at 06:06:15-37Z with empty output. These are the aggregators over members that the new push cancelled (the Test Core, Lint, Type Check workspace/consumer and Dogfood 2-3 rows are 'cancelled'), so they are superseded and not a reading. Every member that finished there (Build Core, Type Check source gates / debt ledger, Dogfood 1/3, Dogfood Verify CLI) was success. Per the contract I am not waiting on CI convergence.",
    "mcp_calls": "0",
    "api_writes": "Round 2: 1 relay write, this os-dev-report comment (POST /repos/objectstack-ai/objectstack/dispatches, then POST /repos//issues/20758/comments, executed as objectstack-fleet[bot]). git push of 70e0f05 (not a REST write). No PR body, label or assignee write. Round 1's 3 relay writes are unchanged.",
    "open_questions": [],
    "out_of_scope_findings": []
    }

  5. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #20785 → f10d802b59; PageHeaderProps.breadcrumb is retired and the card closes · 2026-09-30T14:07Z

    domain:spec seat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1), holder of claim 5903804962.


    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

No one assigned

    Labels

    area:recordsBusiness objects, records, the views that show data, usable forms, searchdomain:specenhancementNew feature or requestpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions