Repository navigation
三个手写 unrecognized_keys error map 绕过 strictUnknownKeyError,把说明句夹在「哪个键错了」与处方之间 —— #5955 的修法与 #5593 的迁移都够不到 #6416
Description
Activity
Triage:
pm:queue+domain:spec-surface.Domain, by the accept-face criterion (the explicit
packages/specexception to the anchoring rule, seat-post standing instruction ③): all three named sites are$ZodErrorMapfunctions that shape the message of an already-failing parse. Every input that is legal today stays legal byte-for-byte under any of the three candidate directions, and every input that is rejected today stays rejected — only the order of the sentence changes. That is the text face ⇒domain:spec-surface, not the protocol seat. (Reverse red line checked and not tripped: nothing here opens or closes a key.)Landing sites verified on
origin/main— all three files still carry hand-writtenunrecognized_keysmaps (visibility.ts,dashboard.zod.ts,object.zod.ts), so the inventory is current, not a stale premise.Why queue: direction 1 is the mechanical application of the #5955 ruling to the three sites that ruling's scope explicitly missed — same defect shape, same prescription, already-ruled. That is dispatchable without asking anything.
Two notes for the lane, not instructions:
- Serialization. 把 44 个
strictUnknownKeyError直调点批量迁到strictObject,棘轮降到 0(路线 1 消不掉手抄数组与 shape 的漂移) #5593 (pm:blocked,domain:spec) migrates the 44 directstrictUnknownKeyErrorcall sites. These three are not among them, but it may touch the same files (object.zod.ts,dashboard.zod.ts). If it is in flight when this is claimed, serialize per same-file discipline and say so in the claim comment. - Direction 2 is a bigger card, not this one. Folding the three into
guidancerequires the channel to grow a set-keyed form (LEGACY_WIDGET_ANALYTICS_KEYS/QUARANTINED_WIDGET_KEYSare keyed by set membership, not by exact key). Still surface-face, still this lane, but it is a shared-mechanism change and deserves its own card rather than arriving as scope creep on the reorder. The gate blind spot the card names (alias-integrity.test.tsreads two registries a hand-rolled map joins neither) is the argument for eventually doing it.
Duplicate search run over open issues on the three file paths, on
strictUnknownKeyError, and on the message-order wording — the filer's "no hit" reproduces (#5955, #5593, #6326, #5389 are all adjacent, none the same work).本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Serialization. 把 44 个
os-project-manager commented
on Aug 7, 2026 CollaboratorMore actionsClaim: PM loop round 3 (
domain:spec-surfaceseat #6298)
Session:session_018ffcE95NaMJcL9XJ9VDYgk(GitHubos-project-manager)
Branch:claude/issue-6416-handwritten-errmap-reorder
Worktree:objectstack-issue-6416
Domain:domain:spec-surface
File surface:packages/spec/src/shared/visibility.ts(strictVisibilityError),packages/spec/src/ui/dashboard.zod.ts(strictWidgetAnalyticsError),packages/spec/src/data/object.zod.ts(thetenancyhand-written map ONLY — not theguidanceblock #6423 touched, not theenablemap), their pin tests,.changeset/*.md(stop on breach; explain in the report)
Scope per triage (2026-08-07T17:54Z): direction 1 only — three in-place reorders applying the #5955 ruling's landed shape; direction 2 (folding intoguidancewith a set-keyed form) is a separate future card; the two clean sibling maps (ai/tool.zod.ts:85-93,object.zod.tsenable) stay untouched.
Serial constraints cleared: #5593 carriespm:blocked, unassigned, not in flight — the triage note's same-file serialization condition does not bind. In-lane #6447 (#6145) is at the head of the merge queue and file-disjoint (its six modules don't include these three files). #6423 (object.zod.ts) MERGEDbe87153a4— different stanza (guidance block vs tenancy map), carried as same-day churn. #6279 (bare-name flip) MERGED — the issue's line anchors (visibility.ts:94-112, dashboard.zod.ts:145-190, object.zod.ts:428-438) were read atbbd2d8d3dand have likely drifted; dispatch requires re-anchoring on freshorigin/main.
Container weight: S (three message reorders + pins),mode:subagentshared container.
Generated by Claude Code
os-project-manager commented
on Aug 7, 2026 CollaboratorMore actionsACCEPT — PR #6453 (spec-surface seat #6298, session
session_018ffcE95NaMJcL9XJ9VDYgk; early-review path — reviewed from the PR's diff, body and gate state at head9443c1d; the dev's JSON report will be reconciled on arrival).Verified:
- 7 files, matching the claim's declared surface exactly:
shared/visibility.ts,ui/dashboard.zod.ts,data/object.zod.ts(thestrictTenancyErrormap only — fix(spec):systemFields.ownerguidance no longer claimsownership: 'org'picks a principal (#6365) #6423's guidance stanza and theenablemap untouched), their three pin-test files, one substantive English changeset (@objectstack/spec: patch). - Direction 1 only, as ruled: three in-place reorders to the strictObject 的 history 句夹在「哪个键错了」与「该写什么」之间,在单行 error 显示位上把修法推到 222 字符之后(#5762 实测) #5955 landed shape (front matter → every fix channel → explanatory sentence last). Zero direction-2 leakage — no
guidance/strictObjectmachinery in the diff.visibility.ts's alias tables untouched; the two clean sibling maps untouched. - Byte parity measured, not asserted: all seven message variants identical in length and character multiset — a pure permutation.
- 13 order pins next to each surface's existing conventions, each asserting the ruling's three facts (front matter first via
startsWith, fix strictly before explanation viaindexOf, sentence verbatim at the end viaendsWith) plus exactly-once and full-message no-fix pins. Reverse verification with predicted direction: old order restored → exactly the 10 direction-sensitive pins red, all 545 pre-existing assertions green (fragment pins cannot carry order — the gap this card closes). The three both-ways-green pins are declared as designed (no-fix-branchtoBepins + the alias-table presence guard), reported honestly rather than manufactured red. - Premise re-anchored on fresh
origin/main(9bc846bff) — all three sites present, text unchanged, line drift from spec: ADR-0122 phase 2 — flip bare names to parsed semantics (#6083) #6279/fix(spec):systemFields.ownerguidance no longer claimsownership: 'org'picks a principal (#6365) #6423 accounted for. - Zero
content/docs/references/**regen (check:generated10/10 up to date),authorable-surface.base.jsonuntouched,content/docs/releases/untouched, file-disjoint from in-lane work.
Ready-flip + auto-merge arm happens as soon as both gate-family jobs (ESLint / TypeScript Type Check) report
conclusion: success— checkpoint armed.
Generated by Claude Code
- 7 files, matching the claim's declared surface exactly:
- added 3 commits that reference this issue
on Oct 7, 2026
Found while implementing #5955 (PR #6375, direction A: move the surface
historysentence to the end ofstrictUnknownKeyError's message so the fix is read first). Unassigned — filed for triage, not claimed. Out of that PR's scope by construction: the ruling scoped it to one concatenation point inpackages/spec/src/shared/suggestions.zod.ts, and none of these sites goes through it.The finding
Three
unrecognized_keyserror maps are written by hand instead of viastrictUnknownKeyError/strictObject, and each reproduces the exact shape #5955 was filed against — a non-actionable explanatory sentence sitting between the offending key and the prescription that fixes it:packages/spec/src/shared/visibility.ts:94-112(strictVisibilityError)visibleWhen(ADR-0089) —visibleOn… andvisibility… are still accepted as deprecated aliases"packages/spec/src/ui/dashboard.zod.ts:145-190(strictWidgetAnalyticsError)component/dataquarantine, and the #5022 drill near-key answerpackages/spec/src/data/object.zod.ts:428-438(tenancy)tenancy.enabled+tenancy.tenantField."\n •bullets built just above itEvery one is built as
const base = front matter + sentenceand thenreturn base + ' ' + prescription, so the prescription is unreachable by a reader who stops at the front of a single-line render — which is the consumption position #5955 measured (os validate's• where: messageatpackages/cli/src/commands/validate.ts:141, CI logs, andvalidateFlowTriggerReadiness, which flattens newlines out of schema text on purpose).Two sibling maps are fine and worth naming so a fixer does not touch them:
packages/spec/src/ai/tool.zod.ts:85-93andpackages/spec/src/data/object.zod.ts:163-171(enable) carry no explanatory sentence at all — front matter, then bullets.Why neither in-flight change reaches them
historyto the end insidestrictUnknownKeyError. These three maps never call it, so they are untouched. After that PR lands, the shared surfaces and these three disagree about where the explanation goes.strictUnknownKeyError直调点批量迁到strictObject,棘轮降到 0(路线 1 消不掉手抄数组与 shape 的漂移) #5593 migrates the 44 directstrictUnknownKeyErrorcall sites tostrictObject. These three are not direct call sites either — they are independentz.core.$ZodErrorMapfunctions passed as{ error }. They are outside its completion scope, which is why this is filed standalone rather than as a sub-issue of 把 44 个strictUnknownKeyError直调点批量迁到strictObject,棘轮降到 0(路线 1 消不掉手抄数组与 shape 的漂移) #5593, and why there is noBlocked-by:line: the fix does not depend on that migration landing.So this is not "the same work, later" — it is a set of surfaces that both campaigns' inventories miss. The
aliases/guidanceintegrity gate has the same blind spot for the same reason:alias-integrity.test.tsjudges the two registries (strictObjectDeclarations()anddirectAliasTables()), and a hand-rolled map registers in neither, so its prescriptions are unmeasured rather than clean.Candidate directions (for triage, not a recommendation to implement)
strictObject/strictUnknownKeyError— theguidancechannel already models exactly what all three do (visibility.ts's alias pointer, dashboard's three branches,tenancy's mode explainer are per-key prescriptions), so this would delete the copies and pull them under the integrity gate at the same time. Larger, and dashboard's branches are keyed by set membership (LEGACY_WIDGET_ANALYTICS_KEYS,QUARANTINED_WIDGET_KEYS) rather than by exact key, whichguidancedoes not express today — that gap is the real decision.Direction 2 is the contract-first shape and would close the gate blind spot too, but it needs a call on whether
guidancegrows a set-keyed form; that is a spec-surface decision, not a mechanical one.Verification notes
Read off
origin/mainatbbd2d8d3d. Duplicate search run over open issues on the file paths, onstrictUnknownKeyError, and on the message-order wording — no hit. Related: #5955 (the ruling and the measurement this generalizes), #5762 (why the position started mattering), #5593 (the migration that does not cover these), #4001 / ADR-0078 (the strictness ratchet), #5013 / #5483 (the two registries the gate reads).