Skip to content

Commit fbeb56e

Browse files
test(spec): the currency-mode family's enumerating closure pin (#20126) (#20415)
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. - **Rule A.** Every `defaultCurrency` in `skills/**/*.md` and `content/docs/**/*.mdx` sits in a unit that carries `fixed`, or that says it is not the displayed currency (or not read) under `dynamic`. - **Rule B.** The date record's number within five physical lines of `currenc` (any case) counts 0. The matcher reads `ADR-0053`, `ADR 0053` and the `adr/0053-` file link. The roots are `skills/**`, `content/docs/**` and `packages/services/service-analytics/src/**`. Per the family's appended sites 5-10 (ACCEPT `5853407641`, triage `5853734589`), they also include `packages/spec/src/**`, `packages/spec/liveness/**` and `examples/**`: non-code files anywhere, plus `.ts` under each app's `src/`. - **Runtime member.** It is #20091's own pin, `packages/services/service-analytics/src/__tests__/currency-mode-relay.test.ts`, on `main` (`git merge-base --is-ancestor 6780e34 HEAD` exit 0). The closure pin only checks that this file still stands, and ⛔ does not re-assert the resolver. - **Site table.** Each family site (1-10, the three pages #20090 landed, and 11-14) is mapped to the leg that guards it. The test asserts each file's membership in each corpus, so if a site moves out of the radius, the pin goes red. ## 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](https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2304b16 commit fbeb56e

4 files changed

Lines changed: 447 additions & 1 deletion

File tree

0 commit comments

Comments
 (0)