Skip to content

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 into
mainfrom
claude/issue-6416-handwritten-errmap-reorder
Aug 7, 2026
Merged

fix(spec): put the fix before the explanation in the three hand-written unrecognized_keys error maps (#6416)#6453
os-project-manager merged 1 commit into
mainfrom
claude/issue-6416-handwritten-errmap-reorder

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

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 guidance with a set-keyed form) is not touched — it stays a separate card. The two clean sibling maps named in the issue (ai/tool.zod.ts strictToolError, object.zod.ts strictCapabilitiesError) are untouched.

Premise re-anchored on fresh origin/main

Read at 9bc846bff (the issue's anchors were read at bbd2d8d3d, 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.

site symbol anchor at bbd2d8d3d anchor at 9bc846bff
packages/spec/src/shared/visibility.ts strictVisibilityError 94-112 94-111 (unchanged text)
packages/spec/src/ui/dashboard.zod.ts strictWidgetAnalyticsError 145-190 145-190 (unchanged text)
packages/spec/src/data/object.zod.ts strictTenancyError 428-438 425-438 (unchanged text; #6423 edited a different stanza)

What changed

Every message now emits front matter → every fix channel → the explanatory sentence last, matching strictUnknownKeyError's emission order exactly:

  • strictVisibilityError — the visibleWhen alias 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 objectui component/data quarantine, the drillDown 是 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 shape strictUnknownKeyError uses for history after 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, and visibility.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:

OK   visibility  alias branch:     old=386 new=386 delta=0 multiset-identical=true
OK   visibility  no-fix branch:    old=189 new=189 delta=0 multiset-identical=true
OK   dashboard   legacy branch:    old=467 new=467 delta=0 multiset-identical=true
OK   dashboard   quarantine branch:old=353 new=353 delta=0 multiset-identical=true
OK   dashboard   drill branch:     old=817 new=817 delta=0 multiset-identical=true
OK   dashboard   no-fix branch:    old=215 new=215 delta=0 multiset-identical=true
OK   tenancy     multi-key:        old=648 new=648 delta=0 multiset-identical=true

Pins

13 new order pins, placed next to each surface's existing test conventions:

  • packages/spec/src/ui/view.test.ts — next to ADR-0089 D3a — strict view form schemas, exercised through the real FormFieldSchema / FormSectionSchema doors.
  • packages/spec/src/ui/dashboard.test.ts — after DashboardWidgetSchema (dataset-bound), one order pin per prescription branch.
  • packages/spec/src/data/object.test.ts — after TenancyConfigSchema — #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-message toBe for 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 toContain fragment pins.

Method: the three source files were reverted to origin/main with git checkout -- while the new tests stayed in place; the patch was re-applied afterwards.

$ git checkout -- packages/spec/src/shared/visibility.ts \
                  packages/spec/src/ui/dashboard.zod.ts \
                  packages/spec/src/data/object.zod.ts
$ npx vitest run --maxWorkers=2 src/ui/view.test.ts src/ui/dashboard.test.ts \
      src/data/object.test.ts src/ui/page.test.ts src/ui/chart.test.ts

 × src/ui/dashboard.test.ts > strictWidgetAnalyticsError message order … > legacy inline-analytics branch: the ADR-0021 dataset prescription comes first
 × src/ui/dashboard.test.ts > strictWidgetAnalyticsError message order … > quarantine branch: the objectui-internal verdict comes first
 × src/ui/dashboard.test.ts > strictWidgetAnalyticsError message order … > drill branch (#5022): the "AUTOMATIC" answer comes first
 × src/ui/dashboard.test.ts > strictWidgetAnalyticsError message order … > keeps the whole drill answer ahead of the history, not just its opening
 × src/ui/dashboard.test.ts > strictWidgetAnalyticsError message order … > emits the history exactly once, whatever the key count
 × src/data/object.test.ts  > strictTenancyError message order … > names the wrong key first, then the tombstone bullet, then the explainer
 × src/data/object.test.ts  > strictTenancyError message order … > keeps EVERY per-key bullet ahead of the explainer, not just the first
 × src/data/object.test.ts  > strictTenancyError message order … > is a full-message pin for the plain unknown-key case
 × src/ui/view.test.ts      > strictVisibilityError message order … > names the wrong key first, then the alias pointer, then the history
 × src/ui/view.test.ts      > strictVisibilityError message order … > emits the history exactly once, whatever the key count

 Test Files  3 failed | 2 passed (5)
      Tests  10 failed | 545 passed (555)

Prediction confirmed. The representative failure shows the defect precisely:

AssertionError: expected 'Unrecognized key(s) on this view/page…' to contain '`visibleWhenn`. If this is the condit…'
Received: "Unrecognized key(s) on this view/page schema: `visibleWhenn`. Before ADR-0089 D3a
these were dropped silently, shipping inert metadata; a mis-layered or stale key is now
a loud parse error. If this is the conditional-visibility predicate, the canonical key is
`visibleWhen` (ADR-0089) — …"

Two honest notes on the transcript, rather than a tidier number:

  1. 545 pre-existing tests stayed green under the old order — including every toContain on 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.
  2. 3 of the 13 new pins are green in BOTH directions, by design, and I did not "fix" them to go red. Two are full-message toBe pins on the no-fix branch of strictVisibilityError / 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:

  • ESLint job (30 steps)pnpm lint, then check: 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-aliasall PASS.
  • TypeScript Type Check jobcheck:type-check-coverage, check:driver-conformance, check:stall-guard, tsc --noEmit (spec), check:generated --reconcile-only, check:skill-frame-sync, check:skill-compatibility, workspace turbo build (66/66), workspace turbo typecheck (120/120), check:type-check-debt, examples typecheck, downstream-contract typecheck, check:api-surface, check:exported-any, check:dual-source-exports, check:skill-examplesall PASS.
  • Generated artifactspnpm --filter @objectstack/spec check:generated after a real build: all 10 up to date, nothing regenerated. This confirms the dispatch's mechanism assumption: these strings are not .describe() inputs, so content/docs/references/** sees zero regen, and authorable-surface.base.json is byte-identical (never hand-edited).
  • Tests@objectstack/spec 339 files / 8652 tests pass; @objectstack/lint 62 / 1541 pass; @objectstack/cli 91 / 928 pass (the two message consumers named in strictObject 的 history 句夹在「哪个键错了」与「该写什么」之间,在单行 error 显示位上把修法推到 222 字符之后(#5762 实测) #5955os validate's renderer and validateFlowTriggerReadiness).
  • Byte disciplinenode scripts/check-nul-bytes.mjs OK 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

`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
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 7, 2026 9:44pm

Request Review

@github-actions github-actions Bot added the size/m label Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

112 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests protocol:ui tooling labels Aug 7, 2026
@os-project-manager
os-project-manager marked this pull request as ready for review August 7, 2026 22:02
@os-project-manager
os-project-manager added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit bf0ae99 Aug 7, 2026
26 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-6416-handwritten-errmap-reorder branch August 7, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants