Skip to content

test(spec): give the strictness ledger's older-spelling case an owned fixture - #7238

Merged
os-help merged 1 commit into
mainfrom
claude/issue-6940-owned-strictness-fixture
Aug 10, 2026
Merged

test(spec): give the strictness ledger's older-spelling case an owned fixture#7238
os-help merged 1 commit into
mainfrom
claude/issue-6940-owned-strictness-fixture

Conversation

@os-help

@os-help os-help commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Fixes #6940

Triage's deliverable, quoted so it is not re-derived:

promoted findingpm:queue. The cost is measured, not projected — three fixture evictions in three PRs, and the #4001 campaign guarantees more. Deliverable: give the ledger test an owned .strict() fixture (a synthetic carrier under the test's own control, outside the campaign's conversion surface) so the "older spelling still reads as strict" regression cover stops riding live sites. One PR, no gate changes.

Premise, re-verified on origin/main

Intact. packages/spec/scripts/strictness-ledger.test.ts:164 was still it('reads the OLDER z.object(…).strict() spelling as strict too'), and it still borrowed PerOperationRequiredPermissionsSchema from src/data/object.zod.ts (looked up at :186) to carry its load-bearing assertion. Both that file and scripts/lib/strictness-ledger.ts were last touched by 44d677c93 (#6805 via PR #6935) — the eviction that prompted the finding.

What changed

One file, packages/spec/scripts/strictness-ledger.test.ts. No production code, no gate script, no ledger data.

1. The load-bearing material is now owned. The case analyses a small synthetic source the test writes itself, through a new analyzeSource(source, rel) helper in the same describe block. Four sites, each doing a job:

Site Idiom Posture Why it is there
OwnedClosedSchema z.object strict the campaign-era spelling — shape, error map, closing call
OwnedWrappedClosedSchema z.object strict the same spelling as prettier wraps it, which is how live carriers are actually written
OwnedOpenSchema z.object strip control — a reader that calls every site strict fails here
OwnedHelperSchema strictObject strict control — the idioms must stay distinct

Both readings are pinned as whole maps (toEqual over name → posture and name → idiom), so a missing or extra site fails too. Every counting defect in this campaign has been an omission that a find() would have walked past.

2. The live-site reading is kept — as a population reading, with no site named. This is the part I would flag for review, because it is a shape change rather than a move. The card is explicit that the live reading must not be dropped, and it is not; but keeping it as named sites is what put the fixture on the treadmill in the first place, so the control now reads the whole triaged tree and states population facts:

  • every site the reader reports as z.object + strict lives in a file whose text really contains .strict() — a coarse corroboration that deliberately does not share the AST reader, the same tactic (and the same stated reason) as the coverage-walk case above it;
  • the tree yields more than one distinct idiom and more than one distinct posture — the anti-collapse control, on real material, that the named ObjectCapabilities / TenancyConfigSchema / permission.zod.ts pins used to provide.

Measured on this branch: 437 sites across the five triaged directories, of which 5 are live z.object(…).strict() carriers (ui/view.zod.ts:2093, data/field.zod.ts:503, data/object.zod.ts:615 / :743 / :1075). So the control is not iterating over an empty list today.

3. mutate() and the pre-existing synthetic case at the end of the block now share analyzeSource. Same operation, previously written out three times; no behaviour change.

Does it survive the terminal state?

Yes — stated explicitly because the card asks. When the campaign leaves zero in-repo carriers:

  • the owned fixture is unaffected: it reads no file in the tree;
  • the corroboration loop iterates zero times, which is why it is written as a loop and not as toBeGreaterThan(0) — an empty carrier population is the campaign's declared goal, not a regression;
  • the anti-collapse assertions still hold on the measured data: with the 5 carriers gone, the tree's idiom set is still strictObject / z.strictObject / z.looseObject / z.object and its posture set is still strip / strict / passthrough.

The "move this fixture rather than deleting the assertion" instruction is gone from the case, because there is no longer a site to move.

Reverse verification — anti-vacuity

A test reading its own synthetic fixture can pass while proving nothing, so the reader's older-spelling support was broken two independent ways in scripts/lib/strictness-ledger.ts (reverted after each run via git checkout --, never git stash). Both were expected RED, and both failed on the owned fixture, not on the live control — which is the property that matters:

A. chain walk no longer honours .strict() for z.object (if (m === 'strict' && idiom !== 'z.object')):

× reads the OLDER z.object(….strict() spelling as strict too
AssertionError: expected { OwnedClosedSchema: 'strip', …(3) } to deeply equal { OwnedClosedSchema: 'strict', …(3) }
-   "OwnedClosedSchema": "strict",
+   "OwnedClosedSchema": "strip",
-   "OwnedWrappedClosedSchema": "strict",
+   "OwnedWrappedClosedSchema": "strip",
Tests  3 failed | 13 passed (16)

B. idiomOf stops recognising the idiom (if (e.name.text === 'object') return null;):

AssertionError: expected { OwnedHelperSchema: 'strict' } to deeply equal { OwnedClosedSchema: 'strict', …(3) }
Tests  6 failed | 10 passed (16)

Reader restored and green after both.

Gates

  • pnpm --filter @objectstack/spec check:strictness-ledger — green, all three lines, including docs/audits/2026-07-unknown-key-strictness-ledger.counts.md is current — 437 site(s) measured, 41 authorable strip site(s) left.
  • The os-regen-routed counts artifact did not move: git status --porcelain reports exactly one modified path, the test file. (.gitattributes re-read live rather than trusted from a transcription.)
  • pnpm --filter @objectstack/spec test — 360 files / 9397 tests passed.
  • check:scripts-typecheck and check:test-typecheck — green; eslint on the changed file — clean.
  • node scripts/check-nul-bytes.mjs — OK, plus a wider self-scan of the changed file for other control bytes: no hits.
  • check:generated reports api-surface/ stale, which is the documented fresh-worktree false red (no pnpm --filter @objectstack/spec build has run here); the remaining 10 of 11 artifacts, counts included, are current.

No changeset: test-only, nothing user-visible ships. Labelled skip-changeset.


Generated by Claude Code

… fixture (#6940)

The case "reads the OLDER z.object(....strict() spelling as strict too"
borrowed a live site to carry its assertion, and the #4001 campaign keeps
converting whatever site it lands on: three evictions in three PRs
(#5593, #6619/PR #6804, #6805/PR #6935). The reading under test belongs to
the reader in scripts/lib/strictness-ledger.ts, not to any file in this
tree, so the material now comes from a synthetic fixture the test writes
itself.

The live tree is still read, as a control - but as a POPULATION reading
with no site named, so no conversion wave can evict it and the campaign's
terminal state (zero carriers) stays green.

No gate changes: the reader and every gate verdict are untouched, and the
generated counts artifact does not move.

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

vercel Bot commented Aug 10, 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 10, 2026 3:28am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

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

Labels

skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants