fix(spec): put the fix before the explanation in the three hand-written unrecognized_keys error maps (#6416) - #6453
Merged
os-project-manager merged 1 commit intoAug 7, 2026
Conversation
`strictVisibilityError` (shared/visibility.ts)、`strictWidgetAnalyticsError` (ui/dashboard.zod.ts)、`strictTenancyError` (data/object.zod.ts) 都是独立的 `$ZodErrorMap`,既不经过 `strictUnknownKeyError`(所以 #5955 的修法够不到), 也不在 #5593 迁移的 44 个直接调用点里。三者都复现了 #5955 针对的形状:一句 不可操作的说明句夹在「哪个键错了」与修复它的处方之间 —— 在多个消费方的单行 渲染上(`os validate` 的 `• where: message`、CI 日志、会主动抹平换行的 `validateFlowTriggerReadiness`),处方被推出作者真正会读的那一段。 现在统一为 PR #6375 为共享模板落地的顺序:前置语(哪个键错了)→ 全部修复 通道(`visibleWhen` 别名指针;ADR-0021 dataset / objectui 隔离 / #5022 drill 三个分支;`tenancy` 的逐键 tombstone bullets)→ 说明句放最后。没有删除任何 文本,也没有让任何句子变成有条件的:七个消息变体在长度与字符多重集上与原拼接 逐字节相同。接受面不动 —— 这些 map 只塑造一个已经失败的 parse 的文本, `visibility.ts` 的别名表原样未改。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ffcE95NaMJcL9XJ9VDYgk
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 112 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-project-manager
marked this pull request as ready for review
August 7, 2026 22:02
os-project-manager
deleted the
claude/issue-6416-handwritten-errmap-reorder
branch
August 7, 2026 22:18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6416
Direction 1 only, per the 2026-08-07T17:54Z triage ruling: three in-place reorders applying the shape PR #6375 landed for the shared template to the three sites that ruling's scope missed. Direction 2 (folding them into
guidancewith a set-keyed form) is not touched — it stays a separate card. The two clean sibling maps named in the issue (ai/tool.zod.tsstrictToolError,object.zod.tsstrictCapabilitiesError) are untouched.Premise re-anchored on fresh
origin/mainRead at
9bc846bff(the issue's anchors were read atbbd2d8d3d, before #6279 / #6423 / #6364 landed). All three hand-written maps are still present and still carry the mid-message sentence; the premise holds in full.bbd2d8d3d9bc846bffpackages/spec/src/shared/visibility.tsstrictVisibilityErrorpackages/spec/src/ui/dashboard.zod.tsstrictWidgetAnalyticsErrorpackages/spec/src/data/object.zod.tsstrictTenancyErrorWhat changed
Every message now emits front matter → every fix channel → the explanatory sentence last, matching
strictUnknownKeyError's emission order exactly:strictVisibilityError— thevisibleWhenalias pointer moves ahead of the "Before ADR-0089 D3a these were dropped silently…" sentence.strictWidgetAnalyticsError— all three prescription branches (the ADR-0021 dataset migration, the objectuicomponent/dataquarantine, thedrillDown是 objectui 读的活能力,却不是 spec 声明的任何键 —— #3752 的迁移处方曾指向它 #5022 drill near-key answer) move ahead of the "Undeclared top-level keys were dropped silently…" sentence.strictTenancyError— the per-key•tombstone bullets move ahead of the two-modes explainer, which is now appended to the last bullet with a single space. This is byte-for-byte the shapestrictUnknownKeyErroruses forhistoryafter its own bullets.Nothing is deleted and nothing becomes conditional. The acceptance surface does not move: these are
$ZodErrorMaps shaping the text of an already-failing parse, andvisibility.ts's alias tables are untouched.Byte parity: measured, not asserted
The ruling asked for ideally byte-identical lengths. All seven message variants are identical in both length and character multiset — a pure permutation, no joiner space gained or lost anywhere:
Pins
13 new order pins, placed next to each surface's existing test conventions:
packages/spec/src/ui/view.test.ts— next toADR-0089 D3a — strict view form schemas, exercised through the realFormFieldSchema/FormSectionSchemadoors.packages/spec/src/ui/dashboard.test.ts— afterDashboardWidgetSchema (dataset-bound), one order pin per prescription branch.packages/spec/src/data/object.test.ts— afterTenancyConfigSchema — #2763 strategy/crossTenantAccess removal.Each asserts all three facts the ruling names: front matter first (
startsWith), every fix channel strictly before the explanatory sentence (indexOf < indexOf), and the sentence still present verbatim at the end (endsWith), plus an "emitted exactly once whatever the key count" pin and a full-messagetoBefor the branch with no fix to offer.Reverse verification
Direction predicted before running: red — restoring the old concatenation must fail exactly the new order pins, while every pre-existing assertion on these three surfaces stays green, because the reorder deletes nothing and those are all
toContainfragment pins.Method: the three source files were reverted to
origin/mainwithgit checkout --while the new tests stayed in place; the patch was re-applied afterwards.Prediction confirmed. The representative failure shows the defect precisely:
Two honest notes on the transcript, rather than a tidier number:
toContainon these three messages. That is the point of the exercise: fragment pins cannot carry an ordering fact, which is exactly why the issue asked for order pins.toBepins on the no-fix branch ofstrictVisibilityError/strictWidgetAnalyticsError: that branch emits front matter + sentence and has no fix channel, so there is genuinely nothing to reorder and the message is byte-identical before and after. Their job is the complementary one — proving the reorder did not perturb the branch it should not touch. The third (still emits the whole alias table after the reorder) is a deliberate presence check guarding against a reorder that quietly drops one of the three alias spellings, which the order assertions alone would not catch. Reported rather than manufactured into a red.After re-applying the patch:
Test Files 5 passed (5) / Tests 555 passed (555).Verification
Gate list enumerated from
.github/workflows/lint.yml(both jobs), run one by one — no from-memory list:pnpm lint, thencheck:slot-lookup,query-options-erasure,nul-bytes,doc-authoring,docs-audit-scope,role-word,quick-reference-counts,adr-anchors,org-identifier,authz-resolver,service-providers,route-envelope,error-code-casing,wildcard-fallthrough,meta-type-normalized,init-service-contract,durability-log-level,startup-registry-verdict,objectui-changeset,release-notes,release-body,node-version,workflow-status-functions,shard-attestation,published-files,engine-double-contract,resume-authority-declared,merge-driver,spec-parsed-alias— all PASS.check:type-check-coverage,check:driver-conformance,check:stall-guard,tsc --noEmit(spec),check:generated --reconcile-only,check:skill-frame-sync,check:skill-compatibility, workspaceturbo build(66/66), workspaceturbo typecheck(120/120),check:type-check-debt, examples typecheck, downstream-contract typecheck,check:api-surface,check:exported-any,check:dual-source-exports,check:skill-examples— all PASS.pnpm --filter @objectstack/spec check:generatedafter a real build: all 10 up to date, nothing regenerated. This confirms the dispatch's mechanism assumption: these strings are not.describe()inputs, socontent/docs/references/**sees zero regen, andauthorable-surface.base.jsonis byte-identical (never hand-edited).@objectstack/spec339 files / 8652 tests pass;@objectstack/lint62 / 1541 pass;@objectstack/cli91 / 928 pass (the two message consumers named in strictObject 的 history 句夹在「哪个键错了」与「该写什么」之间,在单行 error 显示位上把修法推到 222 字符之后(#5762 实测) #5955 —os validate's renderer andvalidateFlowTriggerReadiness).node scripts/check-nul-bytes.mjsOK over 6082 files, plus a widened self-scan (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') over every changed file: clean.content/docs/releases/untouched. File-disjoint from in-lane PR #6447.🤖 Generated with Claude Code
https://claude.ai/code/session_018ffcE95NaMJcL9XJ9VDYgk
Generated by Claude Code