Uh oh!
There was an error while loading. Please reload this page.
feat(spec): retire record:highlights highlight-field icon — advertised on six surfaces, drawn by nothing (#10054, ADR-0049) - #10910
Conversation
…d on six surfaces, drawn by nothing (#10054, ADR-0049) Strict deletion + guidance prescription at the union's object arm (strictObject route, the data/Metric:filters precedent — no retiredKey tombstone); the two advertising describes corrected; ADR-0087 registration (retired-key entry ui/RecordHighlightsField:icon, D2 conversion record-highlights-field-icon-removed, step-18 chain); packages/lint entry-shape prose corrected; pin flips + refusal pins through the zod-4 union collapse; regenerated reference docs; minor changeset per the launch-window convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B4h3medzvhB9rpfoja9jcw
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B4h3medzvhB9rpfoja9jcw
…tire-highlights-icon
📓 Docs Drift CheckThis PR changes 2 package(s): ⛔ 1 release-owned page(s) name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5778905b8c04bdf35d77de5b3ed9444449d801a9 && git checkout 5778905b8c04bdf35d77de5b3ed9444449d801a9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 58563be069a70d09c4d9cc5f522bb27c5f8a78b2 0a58f719ec128bcf85984fdcb18d8dc67a28d9e5 && git checkout -B drift-repro 58563be069a70d09c4d9cc5f522bb27c5f8a78b2 && git merge --no-ff 0a58f719ec128bcf85984fdcb18d8dc67a28d9e5
node scripts/docs-audit/affected-docs.mjs --json 58563be069a70d09c4d9cc5f522bb27c5f8a78b2
|
Uh oh!
There was an error while loading. Please reload this page.
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32507842415 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Fixes#10054
Retires
record:highlightshighlight-fieldiconunder the ADR-0087 flow (ADR-0049 enforce-or-remove; maintainer ruling 2026-08-21, 「其他接受」 accepting option A, executing the 2026-08-20 census verdict: measured dead — zero read points, while advertised on six author-facing surfaces).Route decision (recorded per the playbook)
The object arm is
strictObject, so the route is strict deletion + aguidanceprescription — not aretiredKeytombstone. Why: the playbook's §2 table sends strict shapes down this route; the freshest precedent (data/Metric:filters, PR #10552) records the same reasoning verbatim for astrictObjectshape; and the ruling's Clause-② wording prescribes exactly what this route produces — an authorediconbecomes the arm's own namedunrecognized_keysrefusal carrying the prescription (a tombstone would instead fire as anever-parse error and keep the key in the walked shape). The refusal reaches authors through the zod-4 union collapse viapackages/lint/src/zod-issue-format.ts's arm unpacking (#5583 wiring, untouched).Registered under major 18, not 17: v17.0.0 was cut before this landed, so the removal ships on the 17.x line (launch-window convention: accept-set narrowings ride minor releases — enforced by
check-changeset-no-major) and the prescription lives at the major boundary whereos migrate metausers look (the #8495 / PR #8666 precedent).What changed
packages/spec/src/ui/component.zod.ts—icondeleted from theRecordHighlightsFieldobject arm;guidance.iconprescription added (fully-qualified key, the measured dead-end, "Delete the key — no replacement: the renderer never drew it", theos migrate meta --from 17pointer). Both advertising describes corrected (the union's own andRecordHighlightsProps.fields'). ⛔readonlyuntouched — it is the arm's one enforced key (RecordHighlightsFielddoes not declarereadonly, so the spec silently strips the key the chip gate reads #5176);label/typeuntouched.ui/RecordHighlightsField:icon(entries/retired-keys/18.ui__RecordHighlightsField__icon.ts, registry block regenerated bygen:migration-registry); D2 conversionrecord-highlights-field-icon-removed(stripKeysover the object entries of everyrecord:highlightsfields[], region + slot reach, scoped by component type; bare-string entries and live neighbour keys untouched; fixture disjoint from every other conversion,expectedNotices: 2); wired into the step-18 chain (conversionIds+ rationale fragment).packages/lint/src/zod-issue-format.ts— entry-shape prose corrected (comment only; no behaviour).content/docs/references/ui/component.mdx— regenerated bygen:docs: the union describe, theiconrow (gone), and thefieldsrow.packages/spec/src/ui/component.test.ts) — the old parse-survival pin authoredicon: 'flag'(the one in-repo writer of the key); fixture-triaged as respell: it now pins the surviving surface{name, label?, type?, readonly?}. New pins: a refusal pin digging the arm'sunrecognized_keysout of the union collapse (assertskeyscontainsicon, path['fields', 0], the named surface, therecord:highlightsfieldiconis normalized by the renderer and then drawn by nothing at the pin — a possible #8691-class dead key #10054/ADR-0049 citation, the no-replacement guidance, the migrate pointer); a no-icon positive control; a readonly-untouched pin.@objectstack/specminor per the launch-window convention, with FROM → TO mapping and theadr-0087: registereddisposition marker.packages/spec/liveness/has no per-prop ledger for UI component props (same as thedata/Metric:filtersprecedent). No authorable-surface row moved — the baseline enumeratesRecordHighlightsProps' top-level keys only; nested union-arm keys have no row (verified:authorable-surface/ui.jsonis byte-identical). api-surface byte-identical — key-level narrowing is invisible to it (the crypto.hash 能力声明了、构建期还会自动推断,但沙箱从没实现 —— 调用直接抛(declared ≠ enforced) #4391-side of the ratchet-visibility table; the earlier "stale" verdict was the generator's dist-timing refusal, and the regenerated output produced no diff).Census basis (ruled, not re-adjudicated)
Zero read points: objectui's renderer normalizes the authored object and carries
icon: f?.iconintoHeaderHighlight, whose chip has no icon slot (its onlyiconoccurrence is a buttonsize="icon"); structurally unable to traveluseRegisterHighlightFields(names: string[]); not designer-publishable (Studiofield-listinput typedstring[]); zero in-tree producers (all three authoredrecord:highlightsblocks are bare string arrays — re-verified in this tree:project-detail.page.ts,task-detail.page.ts,sys-user.page.ts). Recorded confidence gap, accepted by the ruling: out-of-tree customer apps cannot be enumerated — the loud refusal is the mitigation.Verification (union re-run at final HEAD
0a58f719ec, post-merge of origin/main)pnpm --filter @objectstack/spec test— 415 files / 11054 tests passed (includes the new pins, the conversion fixture replay + chain replay, and the alias-integrity audit that judges the newguidanceentry). Tree equivalence: the merge changed nothing underpackages/spec,packages/lint,packages/platform-objects,packages/qa,examples,content/docs,skills(two unrelated.changesetfiles only), so suite greens carry to the final tree.record:highlightsfield objects, enumerated by grep):@objectstack/lint80 files / 2251 passed;@objectstack/platform-objects123 files / 884 passed, 3 skipped;@objectstack/dogfood26 files / 426 passed. Typechecks: spec PASS, lint PASS.iconline (mutation proved on disk: grep count 0→1 +git diff1 insertion), the refusal pin went RED (1 failed | 2 passed, vitest exit 1) while both positive controls stayed green;trap-guarded restore proved on disk (count back to 0). No rebuild leg required: spec's own tests import./component.zodrelatively from src — no dist/exports resolution and no alias question in this in-package pin.node scripts/pm/dispatch-gates.mjs(no hand-fed paths; re-derived after the merge with the updated derivation) and re-run at0a58f719ec— all PASS, per-gate exits captured before any pipe, verdicts read from each gate's own output: changeset-gate-self-tests, cross-package-test-inputs (both spellings), doc-anchors, doc-authoring, lint/doc-formula-expressions, docs-audit-scope, docs-redirects, spec empty-state, spec liveness, merge-driver, objectui-changeset, published-readme-links, quick-reference-counts, role-word, slot-lookup, spec-parsed-alias, spec strictness-ledger, test-source-alias, type-source-resolution, spec variant-docs, adr-0087-registration (✓ … registered record-highlights-field-icon-removed (new here)), changeset-no-major, ci-filter-parity, dev-prereqs, doc-frontmatter, empty-changeset, plugin-teardown-shape, docs-audit/check-affected-docs; convention-triggered for the test-file edit: query-options-erasure, type-check-coverage, type-check-debt (--re-measureon the fully built workspace closure), engine-double-contract, where-matcher; plus playbook families spec skill-examples,check:i18n,check:nul-bytes(OK, 6297 files), andpnpm --filter @objectstack/spec check:generatedat final HEAD.pnpm lintis CI-owned): raneslint --no-inline-config --format jsonover the 8 changed files. ① Population per eslint's own config resolution: the 6 TS files are in-population; the 2 md/mdx files are declared out by eslint itself ("File ignored because no matching configuration was supplied"). ② Counts from the JSON: 8 results, errorCount 0, the only 2 warnings are those ignore notices. ③ Invariance for untouched files:eslint.config.mjs(lines 326–329) states type-aware linting is never enabled for any file, so a file's verdict is a function of that file plus the shared config — and this diff edits no config, so no untouched file's verdict can move.Cross-repo
objectui's plugin-detail advertisement (
index.tsx:522input description) and the normalizer's deadicon: f?.iconcarry are out of this repo's surface — filed as objectstack-ai/objectui#5601 (unassigned, dedup-checked, Blocked-by this retirement, proceeds on the next pin bump — the objectui#3829 pattern).Generated by Claude Code
Generated by Claude Code