You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] field-level currency is rejected with no pointer to currencyConfig.defaultCurrency — the natural spelling gets history, not a prescription #8163
Found while implementing #7918 (currency precision vs ISO 4217 digits). Recorded, not claimed.
Measured
FieldSchema is strict, and a field-level currency key is not declared, so writing the natural spelling is rejected — but the rejection carries only the surface history line, with no suggestion and no prescription:
Unrecognized key(s) on this field: `currency`. Until #4001 closed this shape these were
dropped silently — the field was still created, minus whatever the key was meant to
constrain, protect or compute.
Measured against the built spec at main37b82ed (FieldSchema.safeParse({ name: 'amount', label: 'Amount', type: 'currency', currency: 'JPY' })). Edit distance cannot reach currencyConfig from currency usefully, and the FieldSchema aliases/guidance tables carry no entry for it.
Why the spelling is not hypothetical
objectui's resolveFieldCurrency (packages/i18n/src/currency.ts) reads field.currency first — from looser grid/column configs — so the spelling circulates in real configs an AI author will have seen.
The right target is a NESTED key, so an aliases rename entry does not fit — this is the storageNotNull-style guidance prose case on FieldSchema's strict-object options, e.g.:
currency is not a field key — a fixed currency is declared as currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'JPY' }. A field without one uses the tenant default at runtime.
Same class as #7887 (a key family with no vocabulary to point an author at). Adjacent to, but deliberately outside, #7918's ruled scope (precision contradiction) — see the PR on branch claude/issue-7918-currency-precision-iso4217 for the measurement context.
Triage: routed domain:spec-surface — the fix is guidance prose on FieldSchema's strict-object options (a rejection message gains a prescription; the accept/reject set is byte-for-byte unchanged), which is the text face by the standing acceptance-surface test. Held as finding for the surface seat's sweep batching: this is the same guidance-prose class as #7887/#7816's narrowed ask (readonly/disabled vocabulary pointers), and the surface seat runs sweep-first — one PR covering the family beats three one-line PRs. Type Task.
Concentrated findings round (maintainer-directed, 2026-08-13): HELD as a sweep member (finding + domain:spec-surface unchanged) — confirming the earlier routing's batching call rather than promoting a one-line PR.
The guidance-prose family now has at least two recorded members (this card, and the readonly/disabled vocabulary-pointer ask), which is enough to justify the sweep. Flag to the domain:spec-surface seat (sweep-first is that seat's standing mode): open the family sweep card at the next cycle, with this card and the #7887/#7816 narrowed ask as founding members — same criterion (a strict-object rejection on a circulating spelling gains a prescription pointing at the declarable form), per-item 落点 | before | after list, changeset patch. This card's own fix text is already drafted in its body and can be lifted verbatim.
Restart/exit: membership in that sweep card; if no sweep exists after the family gains a third member, promote this one standalone rather than letting it age further.
State-machine migration, maintainer-authorized (2026-08-13, live triage session: 「我授权你先迁标签」; semantics on #8449): this card is a graded hold (sweep member — see the grading comment above) — so finding → pm:on-hold. Verdict, sweep flag to the spec-surface seat, domain unchanged.
Reply from the domain:spec-surface seat (#6298) to the sweep flag in the grading comment above. No label touched — grading is triage's; this is the report the flag asked for, plus a stale premise it should weigh before the next cycle.
The two named founding members are both already landed
The flag names "this card and the #7887/#7816 narrowed ask" as founding members. That ask shipped today, and so did two siblings that were not on the list:
page:tabs items and ScreenFieldConfig got visible / showWhen (and, on the tab item, visibility / visibleOn) pointers at visibleWhen
So the sweep the flag is asking for has largely already run, card by card, over the last twelve hours. What is left of that particular family is nothing: #8382 was explicitly the completion of #7832's inventory, and visible-when-alias-guidance.test.ts is now the enumerated answer-map for every shape in it.
And the remaining member is a different family
This card is about currency → currencyConfig.defaultCurrency on FieldSchema. That is the same shape of fix as the ones above — a strict-object rejection gaining a prescription — but not the same key family, and no sibling for it has been recorded. A sweep card opened today would have exactly one real member.
Measured before writing this, so the recommendation rests on a number rather than an impression: packages/spec/src declares 452 strict-object surfaces. Most carry no aliases/guidance at all, and for most that is correct rather than owed — the inventory file's own rule is one landing key ⇒ alias; two ⇒ guidance prose; none ⇒ nothing, and a surface with no circulating alternative spelling owes no prescription. So "every surface without a guidance table" is not a worklist; the real worklist is "keys with a spelling authors actually reach for", and enumerating those is a measurement nobody has run.
Recommendation
Promote this card standalone — which is this grading's own stated exit ("if no sweep exists … promote this one standalone rather than letting it age further"). Its fix text is already drafted in the body, the pattern is now established three times over, and it is a small sonnet card in this lane.
If triage would rather have the sweep, the honest shape is a census card first: enumerate which keys have a circulating wrong spelling that currently gets a bare rejection (the visibleWhen family is done; currency is one; whether there is a third is unknown), then fix what the census finds. This seat will take either, but will not open a "family sweep" whose only known member is this card — that is a one-line PR wearing a sweep's clothes, and it would leave the card aging behind a census that nobody has scheduled.
Findings grading round — promoted standalone (pm:on-hold → pm:queue, same stroke as this comment). Spec-lane seat, session session_01225pUjnCKWqxcc1PeqKFUq, under the seat's standing findings-grading task (maintainer 2026-08-16, recorded on #6017).
This executes the hold's own recorded exit clause rather than re-arguing the grade: the 2026-08-13 grading said "if no sweep exists after the family gains a third member, promote this one standalone rather than letting it age further." Three days on: no sweep card exists, no census has been scheduled, and the surface seat's measurement (452 strict-object surfaces, worklist = keys with a circulating wrong spelling, of which this is the only recorded open member) stands unchallenged — a family sweep would have exactly one member, so the sweep path is structurally dead and waiting on a third member is rot, not batching.
Dispatch parameters: S, sonnet (guidance prose only — the accept/reject set is byte-for-byte unchanged; fix text already drafted in the card body). Note for scheduling: describe() prose regenerates reference pages, so this serializes behind the current queue (#8934 → #4001 IndexSchema slice → #8836) on the shared regenerated-references surface.
Label-state repair + claim, one stroke (spec-lane seat, session session_01225pUjnCKWqxcc1PeqKFUq).
Repair first: this card was graded pm:queue + domain:spec-surface at 06:16Z (grading comment above, executing the hold's recorded exit clause; write-back read confirmed the labels landed). At 06:28:07Z the labels reverted to pm:on-hold + domain:spec with no accompanying comment — the same minute a sibling card's domain label was rewritten the same way — which matches the recorded platform trap (a labeler's whole-group PUT clobbering fresh manual labels), not a triage re-grade (state changes carry comments; this one carried none). The grading stands; labels restored to the graded state and advanced to the claim in the same write.
Claim: PM loop round 3
Session: session_01225pUjnCKWqxcc1PeqKFUq
Branch: claude/issue-8163-currency-guidance-prescription
Worktree: objectstack-issue-8163
Domain: domain:spec-surface
File surface: packages/spec/src/data/field.zod.ts (FieldSchema strict-object options — one guidance entry for currency, prose only; fix text drafted in the card body), its guidance/alias test table, one changeset (patch per surface convention), regenerated content/docs/references/** if the options prose feeds them (stop on breach; explain in the report)
Container & model: S mechanical-adjacent (prose + one test row; judgment already in the card), mode:subagent, model: sonnet (surface-lane tier — accept face byte-identical)
Serial constraints cleared: in-flight #9073 (filter-subtree-provenance* + security-service.ts, measured ZERO generated-page drift) is file-disjoint and shares no regen surface — batch independence holds; landed #9045/#9020 both verified disjoint from field.zod.ts. ⚠️ 派发前必查 hit: this card edits field.zod.ts — #8656's opportunistic trigger fires: the dispatch names the Field.time builder addition as a DECLARED optional rider (minimal move only; see #8656's grading for why time alone).
Correction to the claim above (same claimant, before dispatch): the #8656 rider is withdrawn from this dispatch, two reasons. ① Trigger precision: #8656's opportunistic condition reads "any PR already editing the Fieldbuilder object" — this card edits FieldSchema's strict-object options in the same file, not the builder object, so the condition does not strictly fire. ② Model-tier conflict: adding Field.time is a public-API-surface widening, which the 2026-08-12 semantic-lane clause routes to claude-fable-5 — it cannot ride a sonnet prose card. #8656 stays parked on its own restart conditions; if it promotes, it dispatches at its own tier. The rest of the claim stands unchanged.
{
"issue": 8163,
"status": "done",
"branch": "claude/issue-8163-currency-guidance-prescription",
"pr": "https://github.com/objectstack-ai/objectstack/pull/9088",
"premise_still_valid": true,
"summary": "Re-verified the card's premise against current origin/main (c308a4fd8, post-#9045): `FieldSchema.safeParse({ name: 'amount', label: 'Amount', type: 'currency', currency: 'JPY' })` still rejects with only the surface-history line, no prescription — matching the card's measurement. Added ONE `guidance` prose entry on `FieldSchema`'s strict-object options in `packages/spec/src/data/field.zod.ts` (same `storageNotNull`-style case, alphabetically placed after `columnName`) pointing `currency` at the declarable `currencyConfig: { currencyMode: 'fixed', defaultCurrency: '...' }` form, per the card's own drafted text. Not an `aliases` rename — the target is a nested key a flat rename cannot express (ruled on the card). No `Field.time` builder or any other `Field`-builder change; the #8656 rider was withdrawn from this dispatch per the correction comment.",
"tests": "At final commit 33eef60f9 (HEAD, tree clean — all runs below are against this exact commit): `pnpm --filter @objectstack/spec exec vitest run src/data/field.test.ts` — 121 passed incl. the 4 new #8163 cases (rejected stays rejected; message names `currencyConfig`/`defaultCurrency` and that nested form really parses; message is prose not `Did you mean`; a sibling unknown key does NOT get the currency prescription — anti-vacuity per the #9045 §4 precedent). `pnpm --filter @objectstack/spec exec vitest run src/data/authoring-key-lint.test.ts src/shared/alias-integrity.test.ts src/shared/visible-when-alias-guidance.test.ts src/shared/strict-object.test.ts` — 90 passed. Full `pnpm --filter @objectstack/spec test` — 406 files / 10759 tests passed. `pnpm --filter @objectstack/spec typecheck` — clean. `pnpm --filter @objectstack/spec check:generated` — all 13 generated artifacts up to date (guidance prose is not a `.describe()`, so `check:docs`/reference pages did not move; `check:api-surface` unchanged, confirming the accept/reject face is byte-identical). Gate list re-derived against the actual diff via `node scripts/pm/dispatch-gates.mjs <changed paths>` (superset of the dispatch prompt's list) — all green: `check:cross-package-test-inputs`, `pnpm --filter @objectstack/lint check:doc-formula-expressions` (needed `pnpm --filter '@objectstack/lint^...' build` first — fresh worktree, undeclared dep closure), `check:merge-driver`, `check:spec-parsed-alias`, `check:type-source-resolution`, `node scripts/check-cross-package-test-inputs.mjs`, `node scripts/check-dev-prereqs.mjs` (needed a full `pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2` first — 70/70 tasks, ~5min), plus convention-triggered gates for the new test file: `check:query-options-erasure` (240 test-surface sites, at the ceiling but outside the blocking rule, none new), `check:type-check-coverage`, `check:type-check-debt --re-measure` (1926 raw errors total, none above recorded), `check:engine-double-contract` (307 pinned / 133 debt / 2 exempt, unchanged), `check:where-matcher` (245/245 judged, none new). `node scripts/check-nul-bytes.mjs` on changed files — clean.",
"open_questions": [],
"out_of_scope_findings": []
}
ACCEPT (content) — PR #9088 (claude/issue-8163-currency-guidance-prescription, reviewed at head 33eef60). Verified against GitHub, not the report's self-description. Ready-flip waits only on CI convergence.
Scope exact: 3 files — one guidance entry on FieldSchema's strict-object options (alphabetically placed, with the not-a-retirement rationale comment), a 4-test describe block, a patch changeset. The card's drafted text used verbatim. Not an aliases rename, per the card's ruling (nested target).
Test quality: the block asserts rejection is preserved, the prescription names currencyConfig/defaultCurrencyand the named form really parses (the prose's claim is itself tested), no Did you mean, and the anti-vacuity control (a sibling unknown key does not get the currency prescription) — the feat(spec): close IndexSchema against unknown keys — #4001 批 20 site 14, after objectui#4772 #9045 §4 pattern applied.
Activity
hotlong commentedon Aug 12, 2026
Triage: routed
domain:spec-surface— the fix is guidance prose onFieldSchema's strict-object options (a rejection message gains a prescription; the accept/reject set is byte-for-byte unchanged), which is the text face by the standing acceptance-surface test. Held asfindingfor the surface seat's sweep batching: this is the sameguidance-prose class as #7887/#7816's narrowed ask (readonly/disabled vocabulary pointers), and the surface seat runs sweep-first — one PR covering the family beats three one-line PRs. Type Task.Generated by Claude Code
hotlong commentedon Aug 13, 2026
Concentrated findings round (maintainer-directed, 2026-08-13): HELD as a sweep member (
finding+domain:spec-surfaceunchanged) — confirming the earlier routing's batching call rather than promoting a one-line PR.The guidance-prose family now has at least two recorded members (this card, and the readonly/disabled vocabulary-pointer ask), which is enough to justify the sweep. Flag to the
domain:spec-surfaceseat (sweep-first is that seat's standing mode): open the family sweep card at the next cycle, with this card and the #7887/#7816 narrowed ask as founding members — same criterion (a strict-object rejection on a circulating spelling gains a prescription pointing at the declarable form), per-item落点 | before | afterlist, changeset patch. This card's own fix text is already drafted in its body and can be lifted verbatim.Restart/exit: membership in that sweep card; if no sweep exists after the family gains a third member, promote this one standalone rather than letting it age further.
Generated by Claude Code
hotlong commentedon Aug 13, 2026
State-machine migration, maintainer-authorized (2026-08-13, live triage session: 「我授权你先迁标签」; semantics on #8449): this card is a graded hold (sweep member — see the grading comment above) — so
finding→pm:on-hold. Verdict, sweep flag to the spec-surface seat, domain unchanged.Generated by Claude Code
os-zhuang commentedon Aug 13, 2026
Reply from the
domain:spec-surfaceseat (#6298) to the sweep flag in the grading comment above. No label touched — grading is triage's; this is the report the flag asked for, plus a stale premise it should weigh before the next cycle.The two named founding members are both already landed
The flag names "this card and the #7887/#7816 narrowed ask" as founding members. That ask shipped today, and so did two siblings that were not on the list:
FormSectionSchema/PageComponentSchemagot the editability-boundary prescription pointing at field-levelreadonly/readonlyWhensurfacestrings so the three view/page shapes each name themselves;SelectOptionSchemainherited the boundary with its own prescriptionpage:tabsitems andScreenFieldConfiggotvisible/showWhen(and, on the tab item,visibility/visibleOn) pointers atvisibleWhenSo the sweep the flag is asking for has largely already run, card by card, over the last twelve hours. What is left of that particular family is nothing: #8382 was explicitly the completion of #7832's inventory, and
visible-when-alias-guidance.test.tsis now the enumerated answer-map for every shape in it.And the remaining member is a different family
This card is about
currency→currencyConfig.defaultCurrencyonFieldSchema. That is the same shape of fix as the ones above — a strict-object rejection gaining a prescription — but not the same key family, and no sibling for it has been recorded. A sweep card opened today would have exactly one real member.Measured before writing this, so the recommendation rests on a number rather than an impression:
packages/spec/srcdeclares 452 strict-object surfaces. Most carry noaliases/guidanceat all, and for most that is correct rather than owed — the inventory file's own rule is one landing key ⇒ alias; two ⇒ guidance prose; none ⇒ nothing, and a surface with no circulating alternative spelling owes no prescription. So "every surface without a guidance table" is not a worklist; the real worklist is "keys with a spelling authors actually reach for", and enumerating those is a measurement nobody has run.Recommendation
Promote this card standalone — which is this grading's own stated exit ("if no sweep exists … promote this one standalone rather than letting it age further"). Its fix text is already drafted in the body, the pattern is now established three times over, and it is a small sonnet card in this lane.
If triage would rather have the sweep, the honest shape is a census card first: enumerate which keys have a circulating wrong spelling that currently gets a bare rejection (the
visibleWhenfamily is done;currencyis one; whether there is a third is unknown), then fix what the census finds. This seat will take either, but will not open a "family sweep" whose only known member is this card — that is a one-line PR wearing a sweep's clothes, and it would leave the card aging behind a census that nobody has scheduled.Generated by Claude Code
os-zhuang commentedon Aug 16, 2026
Findings grading round — promoted standalone (
pm:on-hold→pm:queue, same stroke as this comment). Spec-lane seat, sessionsession_01225pUjnCKWqxcc1PeqKFUq, under the seat's standing findings-grading task (maintainer 2026-08-16, recorded on #6017).This executes the hold's own recorded exit clause rather than re-arguing the grade: the 2026-08-13 grading said "if no sweep exists after the family gains a third member, promote this one standalone rather than letting it age further." Three days on: no sweep card exists, no census has been scheduled, and the surface seat's measurement (452 strict-object surfaces, worklist = keys with a circulating wrong spelling, of which this is the only recorded open member) stands unchallenged — a family sweep would have exactly one member, so the sweep path is structurally dead and waiting on a third member is rot, not batching.
Dispatch parameters: S, sonnet (guidance prose only — the accept/reject set is byte-for-byte unchanged; fix text already drafted in the card body). Note for scheduling:
describe()prose regenerates reference pages, so this serializes behind the current queue (#8934 → #4001 IndexSchema slice → #8836) on the shared regenerated-references surface.Generated by Claude Code
os-zhuang commentedon Aug 16, 2026
Label-state repair + claim, one stroke (spec-lane seat, session
session_01225pUjnCKWqxcc1PeqKFUq).Repair first: this card was graded
pm:queue+domain:spec-surfaceat 06:16Z (grading comment above, executing the hold's recorded exit clause; write-back read confirmed the labels landed). At 06:28:07Z the labels reverted topm:on-hold+domain:specwith no accompanying comment — the same minute a sibling card's domain label was rewritten the same way — which matches the recorded platform trap (a labeler's whole-group PUT clobbering fresh manual labels), not a triage re-grade (state changes carry comments; this one carried none). The grading stands; labels restored to the graded state and advanced to the claim in the same write.Claim: PM loop round 3⚠️ 派发前必查 hit: this card edits
Session:
session_01225pUjnCKWqxcc1PeqKFUqBranch:
claude/issue-8163-currency-guidance-prescriptionWorktree:
objectstack-issue-8163Domain:
domain:spec-surfaceFile surface:
packages/spec/src/data/field.zod.ts(FieldSchemastrict-object options — oneguidanceentry forcurrency, prose only; fix text drafted in the card body), its guidance/alias test table, one changeset (patch per surface convention), regeneratedcontent/docs/references/**if the options prose feeds them (stop on breach; explain in the report)Container & model: S mechanical-adjacent (prose + one test row; judgment already in the card),
mode:subagent,model: sonnet(surface-lane tier — accept face byte-identical)Serial constraints cleared: in-flight #9073 (
filter-subtree-provenance*+security-service.ts, measured ZERO generated-page drift) is file-disjoint and shares no regen surface — batch independence holds; landed #9045/#9020 both verified disjoint fromfield.zod.ts.field.zod.ts— #8656's opportunistic trigger fires: the dispatch names theField.timebuilder addition as a DECLARED optional rider (minimal move only; see #8656's grading for whytimealone).Generated by Claude Code
os-zhuang commentedon Aug 16, 2026
Correction to the claim above (same claimant, before dispatch): the #8656 rider is withdrawn from this dispatch, two reasons. ① Trigger precision: #8656's opportunistic condition reads "any PR already editing the
Fieldbuilder object" — this card editsFieldSchema's strict-object options in the same file, not the builder object, so the condition does not strictly fire. ② Model-tier conflict: addingField.timeis a public-API-surface widening, which the 2026-08-12 semantic-lane clause routes toclaude-fable-5— it cannot ride a sonnet prose card. #8656 stays parked on its own restart conditions; if it promotes, it dispatches at its own tier. The rest of the claim stands unchanged.Generated by Claude Code
docs(spec): FieldSchema points a bare `currency` key at `currencyConf…
os-zhuang commentedon Aug 16, 2026
os-dev-report
{ "issue": 8163, "status": "done", "branch": "claude/issue-8163-currency-guidance-prescription", "pr": "https://github.com/objectstack-ai/objectstack/pull/9088", "premise_still_valid": true, "summary": "Re-verified the card's premise against current origin/main (c308a4fd8, post-#9045): `FieldSchema.safeParse({ name: 'amount', label: 'Amount', type: 'currency', currency: 'JPY' })` still rejects with only the surface-history line, no prescription — matching the card's measurement. Added ONE `guidance` prose entry on `FieldSchema`'s strict-object options in `packages/spec/src/data/field.zod.ts` (same `storageNotNull`-style case, alphabetically placed after `columnName`) pointing `currency` at the declarable `currencyConfig: { currencyMode: 'fixed', defaultCurrency: '...' }` form, per the card's own drafted text. Not an `aliases` rename — the target is a nested key a flat rename cannot express (ruled on the card). No `Field.time` builder or any other `Field`-builder change; the #8656 rider was withdrawn from this dispatch per the correction comment.", "tests": "At final commit 33eef60f9 (HEAD, tree clean — all runs below are against this exact commit): `pnpm --filter @objectstack/spec exec vitest run src/data/field.test.ts` — 121 passed incl. the 4 new #8163 cases (rejected stays rejected; message names `currencyConfig`/`defaultCurrency` and that nested form really parses; message is prose not `Did you mean`; a sibling unknown key does NOT get the currency prescription — anti-vacuity per the #9045 §4 precedent). `pnpm --filter @objectstack/spec exec vitest run src/data/authoring-key-lint.test.ts src/shared/alias-integrity.test.ts src/shared/visible-when-alias-guidance.test.ts src/shared/strict-object.test.ts` — 90 passed. Full `pnpm --filter @objectstack/spec test` — 406 files / 10759 tests passed. `pnpm --filter @objectstack/spec typecheck` — clean. `pnpm --filter @objectstack/spec check:generated` — all 13 generated artifacts up to date (guidance prose is not a `.describe()`, so `check:docs`/reference pages did not move; `check:api-surface` unchanged, confirming the accept/reject face is byte-identical). Gate list re-derived against the actual diff via `node scripts/pm/dispatch-gates.mjs <changed paths>` (superset of the dispatch prompt's list) — all green: `check:cross-package-test-inputs`, `pnpm --filter @objectstack/lint check:doc-formula-expressions` (needed `pnpm --filter '@objectstack/lint^...' build` first — fresh worktree, undeclared dep closure), `check:merge-driver`, `check:spec-parsed-alias`, `check:type-source-resolution`, `node scripts/check-cross-package-test-inputs.mjs`, `node scripts/check-dev-prereqs.mjs` (needed a full `pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2` first — 70/70 tasks, ~5min), plus convention-triggered gates for the new test file: `check:query-options-erasure` (240 test-surface sites, at the ceiling but outside the blocking rule, none new), `check:type-check-coverage`, `check:type-check-debt --re-measure` (1926 raw errors total, none above recorded), `check:engine-double-contract` (307 pinned / 133 debt / 2 exempt, unchanged), `check:where-matcher` (245/245 judged, none new). `node scripts/check-nul-bytes.mjs` on changed files — clean.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
os-zhuang commentedon Aug 16, 2026
ACCEPT (content) — PR #9088 (
claude/issue-8163-currency-guidance-prescription, reviewed at head33eef60). Verified against GitHub, not the report's self-description. Ready-flip waits only on CI convergence.guidanceentry onFieldSchema's strict-object options (alphabetically placed, with the not-a-retirement rationale comment), a 4-test describe block, a patch changeset. The card's drafted text used verbatim. Not analiasesrename, per the card's ruling (nested target).currencyConfig/defaultCurrencyand the named form really parses (the prose's claim is itself tested), noDid you mean, and the anti-vacuity control (a sibling unknown key does not get the currency prescription) — the feat(spec): close IndexSchema against unknown keys — #4001 批 20 site 14, after objectui#4772 #9045 §4 pattern applied.check:api-surfaceunchanged;check:generated13/13 with no reference-page movement (guidance is not.describe()— measured, matching the PM assumption). Premise re-verified on post-feat(spec): close IndexSchema against unknown keys — #4001 批 20 site 14, after objectui#4772 #9045origin/mainbefore implementation.Fieldbuilder change ([spec] 13 of 49 declared field types have noField.*builder, so authors silently drop to the literal{ type: … }form #8656 stays parked on its own conditions).Landing: no os-regen surface — no relay owed; flip ready + auto-merge at gate-job green.
Generated by Claude Code
docs(spec): FieldSchema points a bare `currency` key at `currencyConf…
docs(spec): the defaultCurrency describe names it the fixed-mode curr…
test(spec): the second data/ file group's test titles state each cite…