instar 1.3.1078 → 1.3.1079

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "generatedFrom": "source-tree",
4
4
  "registrySha256": "f8a50d91b77caeaeef502ad348a966480db2d4026c42cee2d94d5e0c19438afd",
5
- "packageVersion": "1.3.1078",
5
+ "packageVersion": "1.3.1079",
6
6
  "guards": [
7
7
  {
8
8
  "ref": "docs/canonical-migration-contracts.json",
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha256": "ac5a6b051308426e8a5a16df3560f64c3e913f48eb234dd7b0855e60ba1d3288",
2
+ "sha256": "4db733ce07e33961f4be991c0cb8ea85a1f0f1851567c4952470567030f39933",
3
3
  "registrySha256": "f8a50d91b77caeaeef502ad348a966480db2d4026c42cee2d94d5e0c19438afd",
4
- "packageVersion": "1.3.1078"
4
+ "packageVersion": "1.3.1079"
5
5
  }
@@ -2,5 +2,5 @@
2
2
  "sha256": "f8a50d91b77caeaeef502ad348a966480db2d4026c42cee2d94d5e0c19438afd",
3
3
  "articleCount": 82,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1078"
5
+ "packageVersion": "1.3.1079"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.1078",
3
+ "version": "1.3.1079",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,6 +16,9 @@
16
16
  * - danglingCount = refs a standard names that are NOT on disk — fails the build if
17
17
  * ABOVE ZERO (a guard file removed while a standard still cites it: a broken
18
18
  * guarantee, the loudest signal).
19
+ * - falseClaimCount = standards that name NO guard while their own prose asserts
20
+ * running machinery ("a scheduled audit walks the list daily") — a false
21
+ * all-clear in the constitution, read by humans as protection that exists.
19
22
  *
20
23
  * Self-contained (no dist import) so it runs in CI without a build step — it
21
24
  * re-implements the same deterministic parse → extract → verify the auditor does.
@@ -29,6 +32,10 @@
29
32
  * STANDARDS_ENFORCED_RATIO_FLOOR — min enforced ratio 0..1 (default 0 — starts
30
33
  * loose, ratcheted up as gaps close)
31
34
  * STANDARDS_DANGLING_CEILING — max dangling refs (default 0 — zero tolerance)
35
+ * STANDARDS_FALSE_CLAIM_CEILING — max standards asserting an unnamed guard
36
+ * (default 1 — the measured 2026-07-31 count;
37
+ * ratchet to 0 once Cross-Store Coherence is
38
+ * resolved)
32
39
  */
33
40
  import fs from 'node:fs';
34
41
  import path from 'node:path';
@@ -71,6 +78,14 @@ const FLOORS = {
71
78
  enforcedRatio: numEnv('STANDARDS_ENFORCED_RATIO_FLOOR', 0.64),
72
79
  // Zero tolerance: a standard must NEVER cite a guard that doesn't exist.
73
80
  danglingCeiling: numEnv('STANDARDS_DANGLING_CEILING', 0),
81
+ // A gap that ASSERTS running machinery is a false all-clear, not an honest gap.
82
+ // Set to the measured count on 2026-07-31 (1 — Cross-Store Coherence) rather than
83
+ // 0, following the enforced-ratio precedent of "starts loose": a new check must
84
+ // not fail a build for a pre-existing condition it just became able to see. It
85
+ // already does the load-bearing job at 1 — a NEW standard that claims machinery
86
+ // without naming it fails immediately. RATCHET TO 0 once Cross-Store Coherence
87
+ // either gets its audit built or has the claim amended out of its prose.
88
+ falseClaimCeiling: numEnv('STANDARDS_FALSE_CLAIM_CEILING', 1),
74
89
  };
75
90
 
76
91
  // ── Deterministic parse → extract → verify (mirrors the auditor, self-contained) ──
@@ -123,6 +138,57 @@ function extractRefs(a) {
123
138
  return { files: dedupe(files).sort(), routes: dedupe(routes).sort(), markers: dedupe(markers).sort() };
124
139
  }
125
140
 
141
+ /**
142
+ * ── FALSE-CLAIM DETECTION ────────────────────────────────────────────────────
143
+ * A standard that says "this is how we behave" and names no guard is an HONEST
144
+ * gap. A standard that says "a scheduled audit walks the list daily" is making a
145
+ * claim of FACT — and if it names no resolvable guard, that claim is a false
146
+ * all-clear sitting in the constitution, read by humans as protection that exists.
147
+ *
148
+ * Earned 2026-07-31: of the 24 documented-only standards, exactly three asserted
149
+ * running machinery. Two were true and merely unnamed (now cited). The third —
150
+ * Cross-Store Coherence — claims "A scheduled coherence audit walks the list on
151
+ * every machine daily". No such audit exists; of its three enumerated invariants
152
+ * one has a per-message delivery-time fail-safe and two have no checker at all.
153
+ * It is the standard earned from two identity stores contradicting each other for
154
+ * 19 days with no tripwire — the reactive shield shipped, the tripwire did not.
155
+ *
156
+ * PRECISION OVER RECALL, deliberately, and it is structural rather than a matter
157
+ * of tuning: this runs ONLY over standards already classified `documented-only`.
158
+ * A standard that asserts machinery AND names a resolvable guard is never
159
+ * examined, so the only way to be flagged is to claim a mechanism and cite
160
+ * nothing. Patterns are assertions of a specific mechanism running, never
161
+ * prescriptions ("must refuse", "should block"), which is what the negative
162
+ * lookbehind excludes.
163
+ */
164
+ const CLAIM_PATTERNS = [
165
+ /\ba scheduled\s+[a-z-]*\s*(?:audit|job|check|sweep|pass)\b/i,
166
+ /\bwalks the list\b/i,
167
+ /\b(?:checked|runs|fires|re-?runs)\s+on a cadence\b/i,
168
+ /\bfails the build\b/i,
169
+ /\benforcement is\b/i,
170
+ /\bis enforced by\b/i,
171
+ /\bon every machine\s+daily\b/i,
172
+ /\bdaily\b[^.]{0,40}\baudit\b/i,
173
+ ];
174
+ // Prescriptive framing near a match means the standard is stating a requirement,
175
+ // not asserting an existing mechanism. "must be checked on a cadence" is a rule;
176
+ // "a scheduled audit walks the list" is a claim.
177
+ const PRESCRIPTIVE_NEAR = /\b(?:must|should|shall|needs? to|ought to|is required to)\b[^.]{0,60}$/i;
178
+
179
+ function detectEnforcementClaims(a) {
180
+ const text = `${a.rule ?? ''}\n${a.inPractice ?? ''}\n${a.appliedThrough ?? ''}`;
181
+ const hits = [];
182
+ for (const re of CLAIM_PATTERNS) {
183
+ const m = re.exec(text);
184
+ if (!m) continue;
185
+ const before = text.slice(Math.max(0, m.index - 60), m.index);
186
+ if (PRESCRIPTIVE_NEAR.test(before)) continue;
187
+ hits.push(m[0].trim());
188
+ }
189
+ return dedupe(hits).sort();
190
+ }
191
+
126
192
  const KIND_RANK = { ratchet: 4, gate: 3, lint: 2, 'spec-only': 1 };
127
193
  function classifyFileGuard(ref) {
128
194
  const base = ref.split('/').pop() ?? ref;
@@ -189,7 +255,8 @@ function compute() {
189
255
  generatedAt: new Date().toISOString(),
190
256
  registryFound: false,
191
257
  total: 0, byKind: { ratchet: 0, gate: 0, lint: 0, 'spec-only': 0, 'documented-only': 0 },
192
- enforcedRatio: 1, gaps: [], danglingCount: 0, danglingByStandard: [],
258
+ enforcedRatio: 1, gaps: [], falseClaimCount: 0, falseClaims: [],
259
+ danglingCount: 0, danglingByStandard: [],
193
260
  };
194
261
  }
195
262
 
@@ -202,6 +269,7 @@ function compute() {
202
269
 
203
270
  const byKind = { ratchet: 0, gate: 0, lint: 0, 'spec-only': 0, 'documented-only': 0 };
204
271
  const gaps = [];
272
+ const falseClaims = [];
205
273
  const danglingByStandard = [];
206
274
  let danglingCount = 0;
207
275
 
@@ -224,7 +292,12 @@ function compute() {
224
292
  for (const g of guards) { if (best === null || KIND_RANK[g] > KIND_RANK[best]) best = g; }
225
293
  const kind = best ?? 'documented-only';
226
294
  byKind[kind] += 1;
227
- if (kind === 'documented-only') gaps.push(a.name);
295
+ if (kind === 'documented-only') {
296
+ gaps.push(a.name);
297
+ // A gap that ASSERTS running machinery is a false claim, not an honest gap.
298
+ const claims = detectEnforcementClaims(a);
299
+ if (claims.length > 0) falseClaims.push({ standard: a.name, claims });
300
+ }
228
301
  if (dangling.length > 0) { danglingByStandard.push({ standard: a.name, refs: dangling.sort() }); danglingCount += dangling.length; }
229
302
  }
230
303
 
@@ -234,7 +307,9 @@ function compute() {
234
307
  return {
235
308
  generatedAt: new Date().toISOString(),
236
309
  registryFound: true,
237
- total, byKind, enforcedRatio, gaps, danglingCount, danglingByStandard,
310
+ total, byKind, enforcedRatio, gaps,
311
+ falseClaimCount: falseClaims.length, falseClaims,
312
+ danglingCount, danglingByStandard,
238
313
  };
239
314
  }
240
315
 
@@ -258,8 +333,12 @@ function main() {
258
333
  console.error(`[standards-coverage] registry=${report.registryFound} total=${report.total} ` +
259
334
  `enforced-ratio=${report.enforcedRatio} (ratchet ${report.byKind.ratchet} / gate ${report.byKind.gate} / ` +
260
335
  `lint ${report.byKind.lint} / spec-only ${report.byKind['spec-only']} / gap ${report.byKind['documented-only']}) ` +
336
+ `false-claims=${report.falseClaimCount} ` +
261
337
  `dangling=${report.danglingCount}`);
262
- console.error(`[standards-coverage] floors: enforced-ratio>=${FLOORS.enforcedRatio} dangling<=${FLOORS.danglingCeiling}`);
338
+ console.error(`[standards-coverage] floors: enforced-ratio>=${FLOORS.enforcedRatio} dangling<=${FLOORS.danglingCeiling} false-claims<=${FLOORS.falseClaimCeiling}`);
339
+ for (const fc of report.falseClaims) {
340
+ console.error(`[standards-coverage] FALSE CLAIM — "${fc.standard}" asserts running machinery (${fc.claims.map((c) => `"${c}"`).join(', ')}) but names no resolvable guard.`);
341
+ }
263
342
  }
264
343
 
265
344
  if (CHECK) {
@@ -273,10 +352,14 @@ function main() {
273
352
  ? ` — ${report.danglingByStandard.map((d) => `${d.standard}: [${d.refs.join(', ')}]`).join('; ')}`
274
353
  : ''));
275
354
  }
355
+ if (report.falseClaimCount > FLOORS.falseClaimCeiling) {
356
+ failures.push(`false claims ${report.falseClaimCount} > ceiling ${FLOORS.falseClaimCeiling}` +
357
+ ` — ${report.falseClaims.map((f) => `${f.standard}: asserts [${f.claims.join(', ')}] but names no resolvable guard`).join('; ')}`);
358
+ }
276
359
  if (failures.length > 0) {
277
360
  process.stderr.write('\n❌ standards-coverage check failed:\n');
278
361
  for (const f of failures) process.stderr.write(` - ${f}\n`);
279
- process.stderr.write('\nFix: build a guard for an unguarded standard (raise the ratio), or repair the dangling reference (the cited guard file was renamed/removed).\n');
362
+ process.stderr.write('\nFix: build a guard for an unguarded standard (raise the ratio), repair the dangling reference (the cited guard file was renamed/removed), or resolve a false claim — a standard whose prose asserts running machinery must either NAME the guard that runs it, or stop claiming it.\n');
280
363
  process.exit(1);
281
364
  }
282
365
  if (!QUIET) console.error('✅ standards-coverage check passed.');
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-31T05:00:00.550Z",
5
- "instarVersion": "1.3.1078",
4
+ "generatedAt": "2026-07-31T05:09:09.114Z",
5
+ "instarVersion": "1.3.1079",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "generatedFrom": "source-tree",
4
4
  "registrySha256": "f8a50d91b77caeaeef502ad348a966480db2d4026c42cee2d94d5e0c19438afd",
5
- "packageVersion": "1.3.1078",
5
+ "packageVersion": "1.3.1079",
6
6
  "guards": [
7
7
  {
8
8
  "ref": "docs/canonical-migration-contracts.json",
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha256": "ac5a6b051308426e8a5a16df3560f64c3e913f48eb234dd7b0855e60ba1d3288",
2
+ "sha256": "4db733ce07e33961f4be991c0cb8ea85a1f0f1851567c4952470567030f39933",
3
3
  "registrySha256": "f8a50d91b77caeaeef502ad348a966480db2d4026c42cee2d94d5e0c19438afd",
4
- "packageVersion": "1.3.1078"
4
+ "packageVersion": "1.3.1079"
5
5
  }
@@ -2,5 +2,5 @@
2
2
  "sha256": "f8a50d91b77caeaeef502ad348a966480db2d4026c42cee2d94d5e0c19438afd",
3
3
  "articleCount": 82,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1078"
5
+ "packageVersion": "1.3.1079"
6
6
  }
@@ -0,0 +1,83 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The CI standards-coverage check now distinguishes a standard that is **unguarded** from one that
9
+ **claims a guard it does not name**. Both were previously counted the same way — as
10
+ `documented-only` — which meant a rule could describe running machinery in the present tense while
11
+ nothing existed, and the audit would report it identically to a rule that never claimed anything.
12
+
13
+ `scripts/standards-coverage.mjs` gains `falseClaimCount` + `falseClaims[]`, a per-standard
14
+ `FALSE CLAIM —` line on stderr naming the phrases that triggered it, and a
15
+ `STANDARDS_FALSE_CLAIM_CEILING` floor checked under `--check`.
16
+
17
+ The distinction matters because a human reads the constitution. An honest gap says "nobody is
18
+ watching this." A false claim says "a scheduled audit walks the list on every machine daily" — and
19
+ is read as protection that exists.
20
+
21
+ ## What to Tell Your User
22
+
23
+ Nothing changes in how the agent behaves. This is a build-time check on our own constitution: a
24
+ rule may no longer say "a scheduled check does this daily" unless it names the thing that actually
25
+ does it. One rule currently fails that test — the one written after two of our identity records
26
+ disagreed for nineteen days without anything noticing — and it now says so out loud on every build
27
+ instead of blending in with rules that never made a claim.
28
+
29
+ ## Summary of New Capabilities
30
+
31
+ No new endpoint, route, or operator control. One new environment variable
32
+ (`STANDARDS_FALSE_CLAIM_CEILING`, default `1`) and additional named lines in CI output.
33
+
34
+ ## Evidence
35
+
36
+ - Live run: `total=81 … gap 22 false-claims=1 dangling=0`, with the flagged standard and its matched
37
+ phrases named on stderr.
38
+ - The ceiling **bites** rather than only passing: default `1` → exit 0;
39
+ `STANDARDS_FALSE_CLAIM_CEILING=0` → exit 1 with the standard named in the failure text.
40
+ - Four tests in `tests/unit/standards-coverage-ratchet.test.ts` pin both sides of the boundary —
41
+ a claim with no guard fails; the same claim with a resolvable guard passes; a prescriptive "must"
42
+ passes; an ordinary unguarded standard passes. Verified against the real script on temp fixtures
43
+ (exit 1 / 0 / 0 / 0).
44
+
45
+ ## Why now
46
+
47
+ Measured on 2026-07-31: of the 22 `documented-only` standards, exactly **three** assert running
48
+ machinery. Two were true and had simply never named their guard — both now carry citations. The
49
+ third, **Cross-Store Coherence Is an Invariant**, is false. Of its three enumerated invariants, one
50
+ has a per-message delivery-time fail-safe (`senderValidationGate`), two have no checker at all, and
51
+ the "scheduled coherence audit [that] walks the list on every machine daily" does not exist. It is
52
+ the standard earned from two identity stores contradicting each other for nineteen days with no
53
+ tripwire — the reactive shield shipped, the tripwire did not.
54
+
55
+ ## Precision is structural, not tuned
56
+
57
+ The detector runs **only** over standards the script has already classified `documented-only`. A
58
+ standard that asserts machinery *and* cites a resolvable guard is never examined, so the only way to
59
+ be flagged is to claim a mechanism and point at nothing. Prescriptive framing is excluded — "must be
60
+ checked on a cadence by machinery" is a requirement being stated, not a claim being made.
61
+
62
+ Measured over the live registry: **1 flagged of 22 gaps across 81 standards, zero false positives on
63
+ the other 21.**
64
+
65
+ ## Scope limit, stated plainly
66
+
67
+ This closes a **bookkeeping** gap, not a safety gap. It checks that a standard claiming a guard has
68
+ named one — never that the named guard is sufficient, or that it does its job. A rule can cite a
69
+ real, resolvable, running guard that works badly and this check is satisfied. That is the same limit
70
+ the existing coverage measure carries, restated rather than quietly inherited.
71
+
72
+ ## Default is deliberately loose
73
+
74
+ The ceiling starts at **1**, the currently measured count, following the same "starts loose"
75
+ approach the enforced-ratio floor used: a new check must not fail a build for a pre-existing
76
+ condition it has only just become able to see. It is still load-bearing at that value — a **new**
77
+ standard that claims an unnamed guard fails immediately. Ratchet it to `0` once Cross-Store
78
+ Coherence either gets the audit it describes or has the claim amended out of its prose.
79
+
80
+ ## Rollback
81
+
82
+ `STANDARDS_FALSE_CLAIM_CEILING=<n>` in the environment, with no code change. Reverting the commit
83
+ leaves the two existing floors untouched.
@@ -0,0 +1,156 @@
1
+ # Side-Effects Review — Standards False-Claim Guard
2
+
3
+ **Version / slug:** `standards-false-claim-guard`
4
+ **Date:** `2026-07-31`
5
+ **Author:** `echo`
6
+ **Tier:** `1` (single build script + its unit tests; no runtime surface, no new authority)
7
+ **Second-pass reviewer:** `not required at Tier 1 — the PR is the review surface`
8
+
9
+ ## Summary of the change
10
+
11
+ `scripts/standards-coverage.mjs` already answers "does this standard NAME a resolvable guard?".
12
+ It cannot answer "does this standard CLAIM one?". This adds that second question, scoped to
13
+ standards the script has already classified `documented-only`.
14
+
15
+ - **`detectEnforcementClaims(article)`** — matches assertions of a specific running mechanism
16
+ (`a scheduled <x> audit/job/check`, `walks the list`, `checked/runs/fires on a cadence`,
17
+ `fails the build`, `enforcement is`, `is enforced by`, `on every machine daily`) over the
18
+ Rule / In-practice / Applied-through fields. Prescriptive framing within 60 chars before a match
19
+ (`must`, `should`, `shall`, `needs to`, `ought to`, `is required to`) is excluded.
20
+ - **`falseClaimCount` + `falseClaims[]`** on the report, and a per-standard `FALSE CLAIM —` line on
21
+ stderr naming the matched phrases.
22
+ - **`STANDARDS_FALSE_CLAIM_CEILING`** floor (default **1**, the measured count) checked in
23
+ `--check`.
24
+ - Four tests in `tests/unit/standards-coverage-ratchet.test.ts` pinning both sides of the boundary.
25
+
26
+ Files: `scripts/standards-coverage.mjs`, `tests/unit/standards-coverage-ratchet.test.ts`.
27
+
28
+ ## Decision-point inventory
29
+
30
+ - Claim detection over an article's prose — **add** — read-only classification of a markdown field;
31
+ decides a COUNT, never an action.
32
+ - `falseClaimCeiling` comparison in `--check` — **add** — can fail a CI build. This is the only
33
+ authority the change carries.
34
+
35
+ ---
36
+
37
+ ## 1. Over-block
38
+
39
+ The realistic over-block is a standard flagged for *describing a requirement* rather than asserting
40
+ a fact. Two structural mitigations, neither of them threshold-tuning:
41
+
42
+ - **Scope.** The detector runs ONLY over articles already classified `documented-only`. An article
43
+ that asserts machinery *and* cites a resolvable guard is never examined. There is no
44
+ configuration that widens this — it is a property of where the call sits in the loop.
45
+ - **Prescriptive exclusion.** A negative lookbehind drops a match preceded by `must` / `should` /
46
+ `shall` / `needs to` / `ought to` / `is required to` within 60 characters, which is the shape a
47
+ requirement takes ("must be checked on a cadence by machinery").
48
+
49
+ Measured over the live registry: **1 flagged of 22 gaps / 81 standards.** The one flagged is
50
+ verified false by hand (Cross-Store Coherence — its named daily audit does not exist; of its three
51
+ enumerated invariants, one has a per-message delivery-time fail-safe and two have no checker).
52
+ Zero false positives across the other 21.
53
+
54
+ Blast radius if it over-blocks anyway: a CI failure with a message naming the standard and the
55
+ exact phrases. The fix is a one-word prose edit or a `STANDARDS_FALSE_CLAIM_CEILING` bump. No
56
+ runtime behaviour, no agent action, no user-facing surface.
57
+
58
+ ## 2. Under-block
59
+
60
+ Under-blocking is the expected and accepted state. The pattern list is deliberately narrow —
61
+ precision over recall — so a standard asserting machinery in wording not covered (e.g. "this is
62
+ policed continuously") is missed. That is the safe direction: a missed false claim leaves the
63
+ status quo (an ordinary gap), while a false positive would fail a build for a rule that is honest.
64
+
65
+ The ceiling starting at 1 rather than 0 is also deliberate under-blocking: it accepts the existing
66
+ false claim rather than failing a build for a pre-existing condition the check has only just become
67
+ able to see. It remains load-bearing at 1 — a *new* standard claiming an unnamed guard fails
68
+ immediately.
69
+
70
+ ## 3. Level-of-abstraction fit
71
+
72
+ Correct layer. The question "is this standard's self-description honest?" is a property of the
73
+ standards registry, and the registry parser is the only component that already has each article's
74
+ fields in memory and its guard-resolution verdict. Putting it anywhere else would mean re-parsing
75
+ the constitution.
76
+
77
+ It is deliberately NOT in `StandardsEnforcementAuditor` (the library the `/conformance` route
78
+ serves): that surface is observe-only and non-gating by design, and this needs to fail a build.
79
+ The two implementations already disagree by one article (81 vs 82), recorded rather than averaged;
80
+ adding a gating check to the non-gating side would deepen that.
81
+
82
+ ## 4. Signal vs authority compliance
83
+
84
+ This is a **brittle, low-context filter with build-failing authority**, which is exactly the shape
85
+ *Signal vs. Authority* warns about. Justification for why it is acceptable here rather than a
86
+ signal:
87
+
88
+ - The domain is **not** agent behaviour or message content — it is a fixed, human-authored,
89
+ version-controlled document of 81 articles. The input is bounded and inspectable, not adversarial
90
+ or open-world.
91
+ - The authority is **a CI failure on a docs file**, not a blocked action, message, or session. The
92
+ cost of a wrong verdict is one prose edit; nothing is lost and nothing is delayed for a user.
93
+ - The same file already carries two comparable deterministic gates (the enforced-ratio floor and
94
+ the zero dangling ceiling) with the same shape and authority.
95
+
96
+ Had this needed to judge *meaning* rather than *presence of an assertion pattern*, the correct
97
+ implementation would be an LLM gate per *Intelligent Prompts*. It does not: it reports a phrase
98
+ match to a human, who decides.
99
+
100
+ ## 4b. Judgment-point check (Judgment Within Floors)
101
+
102
+ No judgment point is delegated. The check reports a count and the matched phrases; a human decides
103
+ whether to build the guard or amend the prose. The ceiling is an operator-visible constant with an
104
+ env override.
105
+
106
+ ## 5. Interactions
107
+
108
+ - **Enforced-ratio floor** — independent. A false claim is also counted as a gap, so it already
109
+ depresses the ratio; this adds a *distinct* signal, it does not double-count into the ratio.
110
+ - **Dangling-ref ceiling** — disjoint by construction: dangling means a citation that does not
111
+ resolve; false-claim means no citation at all.
112
+ - **`/conformance/coverage`** — untouched. That route continues to report `documented-only` for the
113
+ same article; the two surfaces will now differ in *detail* (this one names it a false claim),
114
+ which is the intended asymmetry between a gating build check and an observe-only route.
115
+
116
+ ## 6. External surfaces
117
+
118
+ None. No route, no config file, no user-visible message, no network call. The only new surface is
119
+ one env var (`STANDARDS_FALSE_CLAIM_CEILING`) and additional stderr lines in CI output.
120
+
121
+ ## 6b. Operator-surface quality
122
+
123
+ The failure message names the standard, the matched phrases, and the two acceptable resolutions
124
+ ("must either NAME the guard that runs it, or stop claiming it"). It teaches the required shape
125
+ rather than only reporting a number, per the refusal-message convention used elsewhere in the file.
126
+
127
+ ## 7. Multi-machine posture
128
+
129
+ Not applicable. A build-time script over a git-tracked file; no state, no per-machine posture, no
130
+ replication, no lease interaction.
131
+
132
+ ## 8. Rollback cost
133
+
134
+ Near zero, and there are three independent levers:
135
+
136
+ 1. `STANDARDS_FALSE_CLAIM_CEILING=<n>` in the environment — no code change.
137
+ 2. Revert the commit — the two prior floors are untouched by it.
138
+ 3. Delete the `CLAIM_PATTERNS` entries — the check degrades to reporting 0 and passes.
139
+
140
+ No migration, no persisted state, nothing to un-write.
141
+
142
+ ## Conclusion
143
+
144
+ Ship at Tier 1. The change is one build script and its tests; its only authority is a CI failure on
145
+ a documentation file; its precision is structural rather than tuned; and its default ceiling cannot
146
+ fail any build that passes today.
147
+
148
+ ## Evidence pointers
149
+
150
+ - Finding that earned it: `docs/findings/2026-07-31-constitution-asserts-an-audit-that-does-not-exist.md`
151
+ - Live measurement: `total=81 … gap 22 false-claims=1 dangling=0`, with
152
+ `FALSE CLAIM — "Cross-Store Coherence Is an Invariant" asserts running machinery ("A scheduled
153
+ coherence audit", "on every machine daily", "walks the list") but names no resolvable guard.`
154
+ - Boundary verification against the real script on temp fixtures: claim-without-guard → exit 1;
155
+ claim WITH a resolvable guard → exit 0; prescriptive "must" → exit 0; ordinary unguarded standard
156
+ → exit 0.