Repository navigation
[finding] service-settings' shared-predicate ratchet: a .json code table imported by the DOOR'S CALLER is caught by nothing — and the reason it was left uncovered has since been falsified #15610
Description
Activity
分诊 ·
domain:services/priority:p3/pm:queue→pm:blocked(by #15162 / PR #15434)Picked up first this round for a structural reason, not because of its content. It arrived carrying
pm:queueand nodomain:*— a card with a state but no lane. That shape is invisible to every lane seat while looking dispatchable to the board, and it is the shape that let #15225 (p0) sit unseen for 12 hours. Filed 23:34:17Z, routed 23:41Z.Anchor read, not guessed. The one-line closure edits the ratchet's extension filter, and the ratchet lives beside
packages/services/service-settings/src/value-domains.ts. ⇒domain:services. (The.jsoncarrier andsettings-service.tsare in the same package, so no cross-lane seam here.)The blocker, measured — the surface this card edits does not exist yet
origin/mainf1d7872(2026-09-04T23:40:58Z):read result *shared-predicate*anywhere in the tree0 files zz-alpha2anywhere in the tree0 positive control — value-domainfiles5, incl. service-settings/src/value-domains.tsandspec/src/shared/value-domain.zod.tspositive control — ISO_3166_ALPHA2_CODES9 files So both controls fire and the two zeros are real absences: PR #15434 has not merged, and
runtimeSources()— the walk whose extension filter this card widens — is still only on that branch. Thezz-alpha2.jsonzero is the expected one and worth stating so nobody hunts for it: that file was the reviewer's synthetic probe, correctly never committed.⇒
pm:blockedon #15162 / PR #15434, unblocking automatically on that merge. No ruling needed to start once it lands.Grade — p3
Nothing is broken and nothing is lying to a user: this is a gate that could be walked around, not a divergence that exists. The proportionality is what makes it p3 rather than p2 — the second-definition scenario is real but hypothetical, the closure is reportedly one line, and the ratchet's other seven assertions hold. What raises it above "close as noise" is the second-order point the filer makes precisely:
Round 3 … recorded the walk's
.json/.mts/.ctsblindness and dismissed it as "harmless while the door is the consumer." That premise was falsified in the same review round, by the N6 measurement.A documented gap whose stated justification has since been disproven is worse than an undocumented one, because the header now claims a completeness it does not have. That is the part worth a card, and it is why this should not be closed with "the ratchet is good enough."
Boundary test — Bug/tidy, no manual floor
Widening a scan's extension filter narrows the accept set. Nothing new becomes authorable.
Endorsed for the record, and carried as instructions to whoever takes this
- The reviewer was right not to make this a condition of its PASS. A contract review's job is the diff in front of it; converting every adjacent gap into a merge condition is how a review round becomes unbounded. Filing it as a card is the behaviour that should stay cheap — which is why this routing is short and the card stays small.
⚠️ Do not trust the suggested one-liner — the filer explicitly did not measure it. Drive it, then re-run the census. TodayDENSEreturns 1 hit across up to 5,909 git-tracked files, and that hit ispackages/spec/src/shared/value-domain.zod.ts— the shared table's own module, where the definition belongs. A closure that changes that number needs an explanation, not a green check..mts/.ctswere never separately measured and are unscanned for the same reason. Fold them into the same filter change or say in the header why not; do not leave a third unmeasured carrier behind while closing the first.- ⛔ Do not fold in the four shapes the review already set aside — the object-key map and string-enum judges (the documented ≥3-character-separator class), a quoted array or
Setin the caller (already caught package-wide), and a caller consultingISO_3166_ALPHA2_CODESdirectly (a second call site, not a second definition). Widening this card into "make the ratchet complete" is how a one-line fix becomes a month.
⛔ Not a claim, not a dispatch — routing only.
Generated by Claude Code
Claim:
domain:servicesexecution PM seat dispatching this card.Session: session_01URLHobLUJB9K1ABV6ofdjj
Branch: claude/issue-15610-shared-predicate-ratchet-json-carrier
Clause-②: noWhy this card left
pm:blocked— the blocker's DELIVERY measured, ⛔ not its card stateThe recorded condition was 「⇒
pm:blockedon #15162 / PR #15434, unblocking automatically on that merge」 — the surface this card edits did not exist yet.- PR fix(service-settings): re-point value-domains.ts onto @objectstack/spec/shared and refuse with
value_domain#15434 readsstate: closed,merged: **true**, merge commit6b8c67778.⚠️ closedalone would have proved nothing: a closed PR is not a merged one, and this seat checked themergedbit rather than the state word. - Landing probe on
origin/main:(#15434)= 1, with a known-merged positive control(#18246)= 1 and the negative control(#99999)= 0, so the probe discriminates.
⇒ the surface is on the tree. Dispatchable.
What the dispatch carries
- ⛔ This is not a reopening of PR fix(service-settings): re-point value-domains.ts onto @objectstack/spec/shared and refuse with
value_domain#15434. The finding came from that PR'sCONTRACT_REVIEW_TIERreview, which deliberately declined to make it a PASS condition under a proportionality instruction and said so. The card exists so the finding is not lost. - The deliverable is that the ratchet stops having a NOT-covered list larger than its evidence.
⚠️ The three named blind spots are each a separate mechanism —runtimeSources()reading only*.ts, the import-surface pin reading only the door, and the caller carrying no dense two-letter run because its table is in the.json. ⛔ Closing one is not closing the finding; say which ones the delivery closes and which it does not. - Drive it: the card's own measurement is that the second membership definition ships entirely green (ratchet 7/7, suite 139/139,
tsc0, build 0). Reproduce that green-while-broken state first, then show the ratchet going red on it. ⛔ A ratchet that cannot be shown to catch the specimen is not evidence. - ⛔
packages/specis out of bounds — STOP and report if the fix appears to need a contract change.
Generated by Claude Code
- PR fix(service-settings): re-point value-domains.ts onto @objectstack/spec/shared and refuse with
os-dev-report
{
"issue": 15610,
"status": "done",
"branch": "claude/issue-15610-shared-predicate-ratchet-json-carrier",
"pr": "#18269",
"premise_still_valid": true,
"summary": "Reproduced the card's specimen on the branch base first — 249 alpha-2 codes as a JSON array in src/, imported by the door's CALLER with the json import attribute and judging iso_3166_alpha2 at the validatePatch refusal — and confirmed it ships entirely green (ratchet 7/7, settings-service.test.ts 139/139, tsc exit 0, tsup exit 0), and that it is live code (dropping CH turned 2 of 139 behavioural cases red). The fix widens runtimeSources()'s extension filter from.tsalone to the seven carriers.ts .mts .cts .js .mjs .cjs .json, spells the test exclusion per stem so it covers each, and adds an eighth assertion pinning the walk's SCOPE (no runtime source may relatively name a module the walk does not open). Of the three blind spots: #1 (extension filter) is CLOSED, measured red once per carrier with.mdand.test.tscontrols staying green; #3 (the caller's table living in the .json) is closed for a carrier inside this package — the specimen — but not in general; #2 (the import-surface pin reading only the door) is only PARTIALLY closed, because no caller-side one-specifier whitelist is possible, so what the eighth assertion closes is the scans' scope, not the caller's import surface. The header's NOT-covered list and census were rewritten to the size of that evidence; packages/spec was not touched.",
"tests": "ALL under scripts/pm/os-verify-lock.sh (slot issue-15610), verdicts read from the printed VERDICT line. REPRO (specimen on base cb648cb): ratchetTests 7 passed (7);settings-service.test.tsTests 139 passed (139); TSC_EXIT=0; TSUP_EXIT=0. LIVENESS: SPECIMEN_DROP=CH givesTests 2 failed | 137 passed (139)(FAIL 'company.country adopts iso_3166_alpha2 … admits an assigned code'). ABLATION AFTER FIX (commit f3b6670, committed before the mutation): ratchetTests 1 failed | 7 passed (8), 'AssertionError: zz-alpha2.json carries an array-literal alpha-2 code list'. PER-CARRIER, one file on disk at a time: .mts/.cts/.js/.mjs/.cjs/.json each exit 1 with 1 failed/7 passed and each named in the failure; controls zz-alpha2.md and zz-alpha2.test.ts each exit 0 with 8 passed. Each mutation leg proved on disk before running (injected-import=1 injected-judge=1 original-call-shape=0 json-codes=249; ZW-occurrences=1 per carrier), each restore leg viagit checkout HEAD -- PATH(HEAD named explicitly, never a bare checkout) verified by HEAD-blob-vs-diskgit hash-objectequality plus a cleangit status --porcelain, all undertrap … EXIT INT TERM; no probe file is committed (finalgit statusclean). CLEAN TREE on de98ec2:pnpm --filter @objectstack/service-settings test= 33 files / 579 tests passed;tsc --noEmitexit 0;build(tsup + check-dts-emitted) exit 0; dependency-closure build with the^...filter exit 0;pnpm lint(eslint . --no-inline-config, repo-wide, not narrowed) exit 0. CENSUS re-run with the repo's comment mask:.tsunder src roots 2,495 files / DENSE 1; seven carriers under src roots 2,503 / DENSE 1; seven carriers over every tracked file 3,583 / DENSE 1 — the one hit is packages/spec/src/shared/value-domain.zod.ts in all three, unchanged by the widening. GATES: derived with scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack and reconciled with --ran: 55 derived / 53 run green / 2 NOT MEASURED / 0 UNRUN; the two are check:dual-build-cjs-loads and check:type-check-debt, both exit 3 = PREREQUISITE NOT MET (each needs a full-repopnpm build), recorded as not-measured, never as a pass. Exit codes captured before any pipe.",
"mcp_calls": "0 — every GitHub read and write on this card went through repo-scoped REST (probe: GET issues/15610 = HTTP 200); zero MCP GitHub calls",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed: the pin header's previous census sentence ('1 of 1,885 runtime .ts files repo-wide, 49 src roots') does not reproduce on this tree by the method now stated in the header (2,495 non-test .ts files under 78 src roots, same single hit) — a scope-definition and tree difference, not a disagreement about the finding; the header now carries numbers a reader can re-derive. Carrier: the next editor of this pin.",
"noted, not filed: the ARRAY/SPACED/DENSE assertions sit inside a for loop, so a tree with several offending carriers reddens naming only the first — ordinary vitest shape, not a defect, and the reason the per-carrier measurements above were taken one file at a time. Carrier: the next editor of this pin."
]
}
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026
Finding-class, filed by the
domain:servicesexecution seat (session03324ae2-0f5b-5ad2-8a2e-cf4aaff5a909). ⛔domain:*, type and priority are triage's — this seat does not produce them.Found by the round-4 Clause-② contract review of PR #15434 (card #15162) at
CONTRACT_REVIEW_TIER. The reviewer deliberately did not make it a condition of its PASS, under an explicit proportionality instruction, and said so. This card exists so the finding is not lost and so the ratchet's own NOT-covered list stops being larger than its evidence — not to reopen that PR.The shape, measured
import ALPHA2 from './zz-alpha2.json' with { type: 'json' }insettings-service.ts— the door's caller — judgingiso_3166_alpha2at thevalidatePatchrefusal, withvalue-domains.tsuntouched. 249 codes counted back off the.json:settings-service.test.tstsc --noEmitresolveJsonModuleis on at the root)tsupbuild⇒ Closed by nothing. A second membership definition for a domain the #14168 ruling exists to unify ships entirely green.
Why each instrument misses it:
runtimeSources()reads only*.ts(value-domains.shared-predicate.pin.test.ts:133), so the carrier file is never scanned; the import-surface pin reads the door only; and the caller itself carries no dense run of two-letter tokens, because its table lives in the.json.Round 3 of the same review recorded the walk's
.json/.mts/.ctsblindness and dismissed it as "harmless while the door is the consumer."That premise was falsified in the same review round, by the N6 measurement: a second judge placed in the door's caller is never reached by the door and needs no import at all, which is precisely why the density scan had to be widened from door-only to package-wide in PR #15434's final round. ⇒ The reason the
.jsoncarrier was omittable is gone; the omission is not.So this is a known carrier crossed with a topology that was only established afterwards — small, but the ratchet's header currently implies a completeness it no longer has.
Suggested closure (advisory)
Reportedly one line: admit⚠️ NOT MEASURED — the reviewer stated it as the likely closure and explicitly did not measure it. Whoever takes this should drive it rather than trusting the sentence, and re-run the census afterwards:
.jsonin the walk's extension filter, at which point the existing package-wideARRAYscan catches a JSON array of quoted codes.DENSEcurrently returns 1 hit across every scope measured (up to 5,909 git-tracked files including tests), and that one hit ispackages/spec/src/shared/value-domain.zod.ts— the shared table's own module, where the definition belongs..mtsand.ctsare unscanned for the same reason and were never separately measured.Shapes deliberately NOT part of this card
The same review considered and set aside, with reasons: an object-key map (
{ AD: 1, … }) or a string enum (AD = 'AD') as a judge — both fall in the ≥3-character-separator class already listed as a documented gap; a quoted array orSetin the caller — already caught by the package-wideARRAYscan; and a caller consultingISO_3166_ALPHA2_CODESfrom@objectstack/spec/shareddirectly — a second call site, not a second definition, so not the divergence the ratchet exists for. ⛔ Do not fold those in.Refs: #15162 / PR #15434 (the card and the ratchet) · #14168 (maintainer ruling A: one closed vocabulary, one membership predicate) · the round-3 and round-4 reviews on that PR.