Skip to content

test(spec): the currency-mode family's enumerating closure pin (#20126) - #20415

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20126-currency-family-closure-pin
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20126-currency-family-closure-pin

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #20126
Clause-②: no

Remainder (c) of the currency-mode class-closure card: the family's one enumerating pin. Remainder (b) landed in PR #20217, the skills half (#20196) in PR #20256, and the runtime member (#20091) in PR #20119, so this test-only PR closes the card.

What the pin is

One new test in spec's repo vitest project: packages/spec/src/data/currency-mode-family-closure.pin.test.ts. The maintainer's ruling on #20088 asked for one enumerating pin in the owning package and ⛔ no new check-* gate. packages/spec owns CurrencyConfigSchema, and its repo project already walks skills/** and content/**. The pin enumerates the corpus, not the sites. A new site anywhere in the radius reddens it, as well as a regression of an old one.

Outside the corpus, and why

  • Released entries. This covers every CHANGELOG.md and content/docs/releases/**. The seat ruled sites 11-14 (the released 17.0.0 entries) accepted history, since a released entry records what shipped (claim 5866047669). The two package CHANGELOGs sit outside every root by construction. examples/*/CHANGELOG.md is inside a root and is skipped by name. The test asserts both exclusions, with a live control proving the by-name skip has something to skip.
  • The pin's own file. It quotes both rules and their fabricated controls.

The three design facts (5855122068), each answered in the pin's header

  1. Test titles. Rule A reads published prose only (.md / .mdx), so no test title is judged by it. The field.test.ts title stays outside by corpus, not by exemption. Rule B does read test files inside its roots.
  2. Negation versus citation. Rule B does not try to tell them apart: a negation within the window counts too. Currency text has no reason to name the date record; the pin's message says to cite ADR-0104.
  3. Wrapped keys. Both rules read logical text. A key hyphen-wrapped at a line end (default- / Currency, ADR- / 0053) rejoins after the next line's comment prefix is stripped.

Unit for rule A: not the line. A strict line reading reds on 5 correct, accepted lines in skills/objectstack-data/rules/field-types.md (ACCEPT 5853407641's pin note). Instead, the unit is:

  • in prose, the sentence across wrapped lines;
  • in a table, the row;
  • in a fenced comment, the sentence of its comment run;
  • in fenced code, the innermost object literal holding the key, or the sibling mapping in YAML.

So one fixed field in a fence never vouches for a neighbour's bare defaultCurrency. There is one shape exemption: a parenthesised key list that also names currencyMode, (currencyMode, defaultCurrency). It names keys and teaches no reading; this is field-types.md:55.

Measured on this branch's base dcd3bceaa (assumption 1 holds)

  • Rule A: 445 files in the corpus. 34 defaultCurrency occurrences in 11 files; 0 failing, 1 of them the key-list exemption.
  • Rule B: 2550 files in the corpus, 0 hits. 65 date-record lines remain, all outside the window (date uses).
  • No live text site: no text site was edited in this PR.

Declared radius (AGENTS.md: a test that reads outside its package is spelled so the gate can see it)

Rule B's example-code leg is new radius for @objectstack/spec#test:repo. It is declared in two places:

  • scripts/cross-package-test-inputs.mjs gets examples/*/src/**/*.ts;
  • turbo.json gets the matching $TURBO_ROOT$/... input.

The glob is deliberately ⛔ not examples/**/*.ts. That glob covers the CRM example's smoke test, which is the dispatch-gates self-test's outside-packages specimen. The declaration comment states that the glob reaches the two translation tests inside the todo app's src/. The pin's site table quotes the showcase dataset's path, which holds the glob on the roster. check:cross-package-test-inputs and check:ci-filter-parity are both green.

Verification

All readings are at head 7fc9f86b, the branch's only commit; every build and test ran through scripts/pm/os-verify-lock.sh (VERDICT command-exit 0 each).

  • The pin alone: pnpm --filter @objectstack/spec exec vitest run --project repo --maxWorkers=2 src/data/currency-mode-family-closure.pin.test.ts → Test Files 1 passed (1) / Tests 6 passed (6).
  • Ablation, one leg per rule (from the committed state, scripts/ablation-replace.mjs in wrap mode, under the lock). The expected direction was red, and both legs went red:
    • Leg A drops (only under currencyMode: 'fixed') from skills/objectstack-ui/rules/dashboards.md, site 2's regression. Anchor 1 → 0, blob 570341f3 → 8e0c44f3. Rule A goes red with exactly skills/objectstack-ui/rules/dashboards.md:307: Tests 1 failed / 5 passed. Restored: blob equals HEAD 570341f3, and git diff HEAD is empty.
    • Leg B inserts (ADR-0053) after the key in examples/app-showcase/src/ui/datasets/chart-gallery.dataset.ts, site 10's regression and the newly declared example-code radius. Anchor 1 → 0, blob 31348e15 → 1ca43894. Rule B goes red with exactly examples/app-showcase/src/ui/datasets/chart-gallery.dataset.ts:47: Tests 1 failed / 5 passed. Restored: blob equals HEAD 31348e15.
    • The first leg-B attempt was a no-op and is not a reading: its replacement embedded its own anchor, and the tool refused (anchor 1 → 1) and restored before any test ran. It was re-run with an anchor the replacement does not contain.
    • Restored leg: Tests 6 passed (6). git diff HEAD is 0 bytes and git status --porcelain is empty.
  • spec, both projects:
    • vitest run --project repo: Test Files 36 passed (36) / Tests 640 passed (640).
    • vitest run --project local: Test Files 561 passed (561) / Tests 16517 passed | 1 todo (16518).
    • pnpm --filter @objectstack/spec run typecheck exits 0, and check:test-typecheck is OK. tsc -p tsconfig.test.json --listFilesOnly lists the new file, so the typecheck really reads it.
  • Builds: pnpm --filter @objectstack/spec build exits 0. turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2 gives Tasks: 71 successful, 71 total.
  • Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 96 commands over the 4 changed paths, and every one was run. --ran gives 96 derived, 96 run, 0 NOT-MEASURED, 0 UNRUN. On the first pass, four gates exited 3 because their prerequisite packages were not built. They exited 0 after the full build: check:doc-formula-expressions, check:dual-build-cjs-loads, check:lean-entry-closure and check:type-check-debt.
  • Readers of the edited declaration module: each exits 0.
    • node scripts/pm/dispatch-gates.mjs --self-test: 1976 cases, including "no hint of this gate reaches a test file outside packages/**".
    • node scripts/check-ci-filter-parity.mjs --self-test.
    • node scripts/partition-test-shards.mjs --self-test.
    • node scripts/check-published-list-mirrors.mjs.
    • node scripts/check-examples-live-imports.mjs.
  • Lint, narrowed (CI owns pnpm lint):
    • eslint --no-inline-config --format json on the two lintable changed files gives 2 files / 0 errors / 0 warnings; --print-config gives them 4 and 2 active rules.
    • turbo.json and vitest.repo-tests.json answer "File ignored because no matching configuration", so they are outside eslint's population.
    • eslint.config.mjs sets no parserOptions.project, so there is no type-aware linting, and no untouched file's verdict can move.
  • Ships nothing: spec's files[] is dist, json-schema, liveness, src/**/*.zod.ts and so on. A grep of the published paths for the pin finds 0 files; the control grep for CurrencyConfigSchema in dist finds 30. So the diff takes skip-changeset.
  • Base: the branch is one commit behind origin/main (2c310705). That commit adds two packages/spec/src/data files with no date-record token, so rule B cannot move on the merge. Not merged here.

Acceptance notes (not filed)

  • .changeset/*.md is outside the corpus. It is where released CHANGELOG text originates, so a pending changeset citing the date record for currency would not redden this pin before release. Carrier: none; noted only.
  • The user selectable wording that site 1 corrected is not a rule of the card's pin definition, so it is not guarded here.
  • Example tests (examples/*/test/**, examples/*/e2e/**) are outside rule B's example-code leg, which follows the declared radius above.
  • node scripts/pm/measurement-claim-triage.mjs --self-test (run as a reader of the edited module) is red on the base, naming only scripts/check-dts-references.mjs:74 (UNTRIAGED), a file this PR does not touch. No workflow or package script invokes it. Carrier: none.
  • The objectui pointer in 5855122068 (objectui packages/i18n/src/currency.ts, CurrencyField.tsx) is another repository and is not read here.

Generated by Claude Code

One test in spec's repo project walks the family's corpus and holds two
text rules at zero: every `defaultCurrency` unit in the published skills
and docs carries the `fixed` condition, and the date record is never named
within five lines of currency text. The spec package's declared radius
gains each example app's `src/**/*.ts`, which rule B reads.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/vitest.repo-tests.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/vitest.repo-tests.json) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 40b315b03345e334069dd454aecaf7016adbea4f → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Test Core (6/6) is red on this head, and the cause is not this PR · domain:spec seat 4 · 2026-09-28T10:08Z

domain:spec seat 4 · #18917 · session_01ARcDurZ5j34RdqsGgc4jgH


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

protocol:data size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants