Skip to content

feat(spec): reject a declared currency precision contradicting the currency's ISO 4217 fraction digits (#7918) - #8232

Merged
huangyiirene merged 4 commits into
mainfrom
claude/issue-7918-currency-precision-iso4217
Aug 12, 2026
Merged

huangyiirene merged 4 commits into
mainfrom
claude/issue-7918-currency-precision-iso4217

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #7918

Implements the maintainer's Option-A ruling (issue comment, 2026-08-12, provenance 「7918 A,7917 ②,7900 收敛两扇门,7929 来源标记」): publish-time validation rejects a declared currency precision that contradicts the currency's ISO 4217 / CLDR fraction digits, when the currency is statically known.

What changed

Two anchors, one shared verdict (currencyPrecisionContradiction in the new packages/spec/src/data/currency-fraction-digits.ts):

  1. CurrencyConfigSchema.precision — checked in a superRefine before the default materializes. The ruling's design trap governs the shape: the property carried .default(2), which bakes in at parse, so authored-vs-defaulted is indistinguishable post-parse. Measured anchor choice: the .default(2) moved off the property into a post-check .overwrite(), so the refinement sees undefined for an unauthored precision (authored-only firing), and the parse OUTPUT stays byte-identical to the .default(2) era — measured on origin/main (37b82ed) before the change and pinned in tests: {"precision":2,"currencyMode":"fixed","defaultCurrency":"JPY"} for an untouched fixed-JPY config, same shape order, same materialized default. .overwrite() rather than .transform() per the measured finding: FormViewSchema.groups is declared as "alias to sections" but nothing folds it — every consumer reads only sections #6926 precedent in view.zod.ts (a pipe has no .extend and breaks shape introspection); its one accepted cost, same as there: CurrencyConfigParsed now infers precision? at the type level while the runtime value is always a number (ADR-0122 forbids hand-narrowing the alias).
  2. Field-level precision — checked in FieldSchema's existing superRefine chain (the same anchoring as the sibling storage.notNull × requiredWhen rule, so every publish door inherits it). This key has no schema default, so authored-vs-absent needed no relocation.

Statically known means currencyConfig.currencyMode: 'fixed'. One premise refinement against the ruling's parenthetical "(field-level currency, …)": the spec's strict FieldSchema declares no field-level currency key — that spelling is an objectui-side read of looser column configs, and writing it on a spec field is already an unrecognized-key rejection (filed the missing-guidance gap as #8163). The only statically-known-currency form the spec can express is fixed-mode currencyConfig, and both precision keys are judged against it. In authored-fixed mode the check also fires when defaultCurrency itself was defaulted (CNY): the fixed currency is statically known either way, and the precision was authored — pinned in tests.

Deliberately partial, by design (do not "improve"): dynamic currencyMode has no single currency to check against and is untouched; codes outside CLDR currencyData (crypto/custom, e.g. the existing BTC-precision-8 test) fail open — refusing unknown codes is a different rule nobody ruled.

Error message names both numbers, per the ruling: "currency JPY has 0 fraction digits; precision: 2 contradicts it — …", plus the prescription (declare the currency's own count, or omit precision).

Alias funnel: CurrencyConfigSchema's decimals/scale aliases are strict-rejection-with-suggestion (not renames), so an alias spelling cannot carry a contradicting width past the check — the author is pointed at precision, where the check waits. Pinned.

The digit table

Static, checked-in snapshot of CLDR 48.0 currencyData (ICU 78.2, node v22.22.2 full-icu), 162 codes, generated locale-free via Intl.NumberFormat(...).resolvedOptions().maximumFractionDigits — provenance and regeneration snippet in the module header. Checked-in rather than probed at validation time so the verdict is deterministic (a small-icu host answers 2 for everything) and the validation path takes no Intl dependency. Renderers keep deriving from live Intl (objectui#4361); both read CLDR, so they agree. The card's measured anchors (0: JPY/KRW/CLP/ISK/VND; 2: USD/EUR/CNY/GBP; 3: KWD/BHD/OMR/TND) are pinned against the table.

In-repo census (PM assumption #3)

Three currencyConfig declarations repo-wide (examples/app-showcase: field-zoo, semantic-zoo, account), all fixed + USD + precision: 2 — agreeing. Zero contradictions to fix; no field-level precision on any in-repo currency field. Census clean, as expected.

Bump: minor, per the #3746 precedent

Acceptance narrowing in the #3746 shape (strict-closing family, shipped as Minor Changes in the 17.0.0-rc line): every newly-rejected input is a contradiction no consumer could honor — renderers already derive the width from the currency when precision is absent, and the rejected combinations rendered money with digits the currency does not have. Not major (check:changeset-no-major also refuses majors); the changeset argues the same and records the one type-level visible change.

Verification

  • @objectstack/spec: full pnpm test — 386 files / 10216 tests passed; pnpm typecheck green; check:generatedall 13 artifacts up to date after regenerating the one it proved stale (content/docs/references/**, a 1-line optionality rendering for currencyConfig.precision; rides in this PR). Re-verified after the final origin/main merge (fa48973 side: spec contracts/* moved — rebuilt, all 13 still green).
  • Both directions pinned (21 new tests): JPY+2 and KWD+2 refused at both anchors (issue code custom, path precision / currencyConfig.precision, message naming both digit counts); USD+2, JPY+0, KWD+3, absent-precision, dynamic-mode (authored and defaulted), unknown-code (BTC+8) accepted — the agreeing combos byte-identically (stringified parse outputs measured on origin/main 37b82ed before the change, pinned as literals).
  • Reverse verification, directions declared before running. A (type-level): const n: number = cfg.precision against the rebuilt dist .d.ts → red (TS2322) exactly as predicted, number | undefined control clean — proves the declaration change is real and rebuilt, not cached. B (anchor choice): temporarily restoring .default(2) on the property predicted 3 reds; observed 4 — the three predicted (noisy-shape guard, its byte-identity row, the field-level agreeing-acceptance test) plus the field-level JPY+2 rejection test, which failed on issue ORDER: the config-level check over-fires on the baked default and its currencyConfig.precision issue displaces the field-level issue as first. One more red than predicted, same mechanism — the baked-default over-firing shape the relocation exists to prevent, proven live from the committed state, then restored via git checkout.
  • Downstream (consumer direction): @objectstack/metadata-protocol 75 files / 1094 tests passed; @objectstack/platform-objects 16 files / 347 tests passed (both after building their dependency closures — the first lap's exit-1 was the fresh-worktree unbuilt-closure false red, not a regression); objectstack validate green in all three example apps (showcase / crm / todo).
  • Spec gate farm locally, all green: adr-anchors, changeset-gate-self-tests, cross-package-test-inputs, doc-formula-expressions, docs-audit-scope, i18n + i18n-coverage (12/12 configs measured), merge-driver, release-body, spec-parsed-alias, nul-bytes.

Docs: content/docs/data-modeling/field-types.mdx currency section states the rule, its partiality, and the authored-only firing.


Generated by Claude Code

claude added 4 commits August 12, 2026 18:22
…rrency's ISO 4217 fraction digits (#7918)

Maintainer ruling 2026-08-12, Option A. Two anchors, one shared verdict:
the field-level precision key (no default — checked in FieldSchema's
superRefine) and CurrencyConfigSchema.precision (default(2) relocated into
a post-check .overwrite() so the superRefine sees authored-vs-absent;
parse output stays byte-identical). Fires only when the currency is
statically known (currencyConfig fixed mode); dynamic mode and non-CLDR
codes fail open by design. Digit table is a checked-in CLDR 48.0 snapshot
with provenance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
…ion optionality (#7918)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
@vercel

vercel Bot commented Aug 12, 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 12, 2026 9:31pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

106 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/permissions/system-context.mdx (via packages/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/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)

7 release-owned page(s) also reference the affected code. These are read-only:

  • 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/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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 size/m documentation Improvements or additions to documentation protocol:data tests tooling labels Aug 12, 2026
@huangyiirene
huangyiirene marked this pull request as ready for review August 12, 2026 22:18
@huangyiirene
huangyiirene added this pull request to the merge queue Aug 12, 2026
Merged via the queue into main with commit e5bd2f6 Aug 12, 2026
27 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-7918-currency-precision-iso4217 branch August 12, 2026 22:35
huangyiirene pushed a commit that referenced this pull request Aug 12, 2026
…tree (#7872 relay lap over #8230/#8232)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
huangyiirene pushed a commit that referenced this pull request Aug 13, 2026
os-regen merge lap for landing: merge origin/main (committed first, per
scripts/pm/os-regen-merge.sh), then wholesale regen of the os-regen'd
references/api pages from the merged tree. Sibling assertions on the
regenerated tree: #8230 retirement state (def names only in retirement
prose + migration entry), #8232 currency fraction-digit guard, #8234's
13 comparand-door exports in api-surface/data.json, #8236's groupBy
union row all survive; MONGODB_MULTI_TENANT_UNSUPPORTED stays absent
from the ledger and the references ErrorCode union reads main-minus-one
(+265 -> +264; the union grew by 2 on main since the previous lap).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
huangyiirene pushed a commit that referenced this pull request Aug 13, 2026
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
… enforced once at the shared compile face for all five drivers (objectstack-ai#7872) (objectstack-ai#8234)

* feat(spec): comparand-type door — accepted literal comparand set enforced at the shared compile face (objectstack-ai#7872)

The measured superset string | number | bigint | boolean | null | Date is
defined in packages/spec (filter-comparand-type.ts), enforced by
parseFilterAST on everything it returns and by the engine's lowering seam on
the object form; everything else is refused with the INVALID_FILTER / 400
envelope naming the accepted set. bigint is narrowed copy-on-write to its
exact number (refused beyond 2^53), which kills the driver-memory mingo
crash cell without touching the frozen driver; the mongo silent-edit cell
({qty: undefined} wiring to {} = match everything) becomes a refusal at the
door. SQL-family allowlists source their set membership and wording from the
door instead of local copies. FILTER_COMPARAND_TYPE_CASES conformance table
added and consumed by all five driver suites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* chore(spec): regenerate api-surface + export-origins for the comparand-type door exports (objectstack-ai#7872)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* test(objectql): re-judge the deep-equality operator-map pin under the objectstack-ai#7872 door

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* chore(spec): regenerate api-surface + export-origins from the merged tree (objectstack-ai#7872 relay lap over objectstack-ai#8230/objectstack-ai#8232)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* test(objectql): pay the two farm reds — registerObject arity, and un-erased engine option bags (objectstack-ai#7872)

The door suite's registerObject(deal) call was missing the required
packageId (the +1 over objectql's frozen TEST_DEBT 355); and its option
bags used bare 'as any', which the query-options-erasure ratchet counts
(240 -> 245). The bags now type-check uncast — FilterCondition's index
signature admits the deliberately off-contract comparands, which is the
point of the door — except the one FilterArray case, which carries the
sanctioned 'as unknown as EngineQueryOptions' naming the contract it
bypasses (not counted).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

---------

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ger — a boot refusal never reaches a wire envelope (objectstack-ai#8035) (objectstack-ai#8239)

* fix(spec): MONGODB_MULTI_TENANT_UNSUPPORTED leaves the error-code ledger (objectstack-ai#8035)

The code was registered under @objectstack/driver-mongodb (objectstack-ai#3724) but no
response envelope can carry it: the CLI boot handler rethrows the tenancy
refusal pre-HTTP and aborts, and the one request-reachable trigger
(assertObjectsNotTenantScoped via syncObjectSchema inside the metadata
protocol's ensureObjectStorage) is swallowed by a documented best-effort
catch. Registered-but-unemittable is the class the ledger header names;
precedent OVERLAY_PERSISTENCE_FAILED / objectstack-ai#5783 — this instance is the sister
shape (never had a wire path, rather than lost it), now documented in the
header.

The boot refusal stays untouched: MULTI_TENANT_UNSUPPORTED_CODE, the error
class, its message, and the CLI's duck-typed literal match. A new
driver-mongodb test pins the code literal (with the ledger row gone it is
the only cross-package guard on the literal serve.ts matches); the ledger
test now asserts the wire vocabulary refuses the retired string. Reference
docs regenerated (ErrorCode enum 264 -> 263).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* docs(spec): regenerate references from the merged tree (objectstack-ai#8035)

os-regen merge lap for landing: merge origin/main (committed first, per
scripts/pm/os-regen-merge.sh), then wholesale regen of the os-regen'd
references/api pages from the merged tree. Sibling assertions on the
regenerated tree: objectstack-ai#8230 retirement state (def names only in retirement
prose + migration entry), objectstack-ai#8232 currency fraction-digit guard, objectstack-ai#8234's
13 comparand-door exports in api-surface/data.json, objectstack-ai#8236's groupBy
union row all survive; MONGODB_MULTI_TENANT_UNSUPPORTED stays absent
from the ledger and the references ErrorCode union reads main-minus-one
(+265 -> +264; the union grew by 2 on main since the previous lap).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

---------

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ered/virtualScroll (ADR-0049, objectstack-ai#7176) (objectstack-ai#8252)

* refactor(spec)!: retire pass-through-only list-view keys striped/bordered/virtualScroll (ADR-0049, objectstack-ai#7176)

Maintainer ruling 2026-08-10: every measured reader copies the key forward
and ObjectGrid, where the chains end, never applies any of the three —
copy-without-apply is dead in effect. retiredKey() tombstones on
ListViewSchema (radiating into ObjectListViewSchema), ADR-0087 D2 conversion
view-list-passthrough-keys-removed + D3 chain step + six
RETIRED_KEYS_BY_MAJOR[17] entries, ledger rows flipped to dead with the
retirement note, form inputs pruned, docs updated, changeset with FROM->TO.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* test(spec): match the striped prescription's actual casing in the pin test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* merge origin/main (os-regen artifacts taken from main; regeneration follows)

* chore(spec): regenerate artifacts after merging origin/main (4dc1c7d relay: objectstack-ai#8230/objectstack-ai#8232/objectstack-ai#8234/objectstack-ai#8236/objectstack-ai#8239)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Contract question: should publish-time validation reject a declared currency precision that contradicts the currency's ISO 4217 digits?

2 participants