instar 1.3.1048 → 1.3.1050

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,5 +2,5 @@
2
2
  "sha256": "b75c147afd1f5a9843ca4eac372159f3623f24731fe63b2f59e48043ae488af9",
3
3
  "articleCount": 82,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1048"
5
+ "packageVersion": "1.3.1050"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.1048",
3
+ "version": "1.3.1050",
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",
@@ -34,6 +34,7 @@ import { classifyTier, decideRequirementSet } from './lib/classify-tier.mjs';
34
34
  import { recognizeConvergence } from './lib/convergence-recognition.mjs';
35
35
  import { isOperatorSurfaceFile, artifactAddressesOperatorSurfaceQuality, isAuthorizationSurfaceFile, artifactAddressesAgentProposesApproves, operatorSurfaceRequiresRawInput } from './lib/operator-surface.mjs';
36
36
  import { selfActionDeclarationVerdict } from './lib/self-action-detect.mjs';
37
+ import { isKnownInlineCodeEnumReference } from './lib/markdown-code-identifier.mjs';
37
38
  import { validateAuditReport, parseFrontmatter } from './write-audit-convergence.mjs';
38
39
  import { scanForSecrets } from './audit-secret-patterns.mjs';
39
40
 
@@ -251,14 +252,14 @@ if (bootstrapTrigger) {
251
252
 
252
253
  let tierSignal = { suggestedTier: 2, sizeTier: 2, riskFloor: 1, reasons: [] };
253
254
  let totalChangedLoc = 0;
255
+ let addedLines = 0;
256
+ let deletedLines = 0;
254
257
  // Hoisted to module scope (docs/specs/self-action-convergence.md → E3 impl
255
258
  // note): addedDiffText is computed in the Step-3.5 block but consumed later by
256
259
  // assertSelfActionDeclared at BOTH the enforceTier1 and Tier-2 pass-through call
257
260
  // sites. It must outlive the block.
258
261
  let addedDiffText = '';
259
262
  {
260
- let addedLines = 0;
261
- let deletedLines = 0;
262
263
  try {
263
264
  const numstat = execSync(
264
265
  `git diff --cached --numstat -- ${inScopeFiles.map((f) => JSON.stringify(f)).join(' ')}`,
@@ -440,6 +441,9 @@ const decisionEntryPath = writeDecisionAudit({
440
441
  belowFloor,
441
442
  files: inScopeFiles.length,
442
443
  loc: totalChangedLoc,
444
+ scopeFiles: inScopeFiles,
445
+ addedLines,
446
+ deletedLines,
443
447
  causalAutopsy,
444
448
  classClosure: (freshestTrace && typeof freshestTrace.classClosure === 'object' && freshestTrace.classClosure) || null,
445
449
  });
@@ -843,9 +847,13 @@ if (staged.includes(spec) && !staged.includes(eli16Rel)) {
843
847
  // `deferrals-tracked` field). Override via INSTAR_DEV_ALLOW_ORPHAN_DEFERRALS=1
844
848
  // (logged for visibility).
845
849
  //
846
- // Detector patterns intentionally conservative false-positives are cheaper
847
- // than false-negatives here. The author can either link a tracker or rephrase
848
- // the sentence to not promise a deferral.
850
+ // Detector patterns intentionally remain conservative over the complete
851
+ // document: headings, callouts, indented text, and standalone inline-code words
852
+ // can all carry real scope decisions. The one structural exclusion is a
853
+ // reference list for the shipped MigrationPerEntryAction CLOSED ENUM. A lone
854
+ // `deferred-in-flight` remains visible; the exemption requires another known
855
+ // enum member on the same line. This validates structured input rather than
856
+ // inferring meaning from Markdown or identifier shape.
849
857
  // Patterns: { regex, requireUnnegated } — when requireUnnegated is true,
850
858
  // we skip the match if the immediately-preceding chars contain "no ", "non-",
851
859
  // "non ", "non", or "un" (so "no deferrals" / "non-deferred" / "undeferred"
@@ -883,6 +891,7 @@ function findOrphanDeferrals(content) {
883
891
  let m;
884
892
  while ((m = regex.exec(content)) !== null) {
885
893
  const start = m.index;
894
+ if (isKnownInlineCodeEnumReference(content, start, start + m[0].length)) continue;
886
895
  if (requireUnnegated) {
887
896
  // Look at up to 8 chars immediately before the match. Treat
888
897
  // matches preceded by "no ", "non-", "non ", "un" as legitimate
@@ -1350,7 +1359,7 @@ function blockCommit(files, reason) {
1350
1359
  // fire, the line just evaporated with the worktree). If the commit is later
1351
1360
  // blocked by the gate, the staged line simply rides the retry commit — both
1352
1361
  // lines describe real gate evaluations.
1353
- function writeDecisionAudit({ slug, suggestedTier, declaredTier, riskFloor, riskFloorReasons, belowFloor, files, loc, causalAutopsy = null, classClosure = null }) {
1362
+ function writeDecisionAudit({ slug, suggestedTier, declaredTier, riskFloor, riskFloorReasons, belowFloor, files, loc, scopeFiles, addedLines, deletedLines, causalAutopsy = null, classClosure = null }) {
1354
1363
  try {
1355
1364
  fs.mkdirSync(DECISIONS_DIR, { recursive: true });
1356
1365
  const ts = new Date().toISOString();
@@ -1376,6 +1385,12 @@ function writeDecisionAudit({ slug, suggestedTier, declaredTier, riskFloor, risk
1376
1385
  belowFloor,
1377
1386
  files,
1378
1387
  loc,
1388
+ scope: {
1389
+ basis: 'staged-in-scope-additions-plus-deletions',
1390
+ files: scopeFiles,
1391
+ addedLines,
1392
+ deletedLines,
1393
+ },
1379
1394
  // Causal autopsy (directive 2026-06-05): what caused the issue this
1380
1395
  // commit fixes — prior-pr / environment-shift / new-code / latent /
1381
1396
  // unknown, with linked PRs. null = not declared (advisory in slice 1).
@@ -0,0 +1,130 @@
1
+ /** The shipped MigrationPerEntryAction closed enum from MigrationLedger.ts. */
2
+ export const MIGRATION_LEDGER_ACTION_VALUES = Object.freeze([
3
+ 'migrated',
4
+ 'forked',
5
+ 'renamed',
6
+ 'skipped',
7
+ 'failed',
8
+ 'deferred-in-flight',
9
+ ]);
10
+
11
+ /**
12
+ * Return true only when a candidate range is a reference to the shipped
13
+ * MigrationPerEntryAction enum: it must sit inside an inline-code span whose
14
+ * complete value is in the closed enum, and the same line must enumerate at
15
+ * least one other closed-enum member in its own inline-code span.
16
+ *
17
+ * A lone `deferred-in-flight` may still be an authorial disposition and remains
18
+ * visible to the caller. Fenced blocks, headings, blockquotes, indented text,
19
+ * standalone inline-code words, escaped backticks, and unknown identifiers also
20
+ * remain visible. This validates already-structured input against a fixed enum;
21
+ * it does not infer intent from identifier shape.
22
+ */
23
+ export function isKnownInlineCodeEnumReference(markdown, candidateStart, candidateEnd) {
24
+ if (
25
+ typeof markdown !== 'string'
26
+ || !Number.isInteger(candidateStart)
27
+ || !Number.isInteger(candidateEnd)
28
+ || candidateStart < 0
29
+ || candidateEnd <= candidateStart
30
+ || candidateEnd > markdown.length
31
+ ) {
32
+ return false;
33
+ }
34
+
35
+ const isEscaped = (index) => {
36
+ let slashes = 0;
37
+ for (let i = index - 1; i >= 0 && markdown[i] === '\\'; i -= 1) slashes += 1;
38
+ return slashes % 2 === 1;
39
+ };
40
+
41
+ const fencedRanges = [];
42
+ let fence = null;
43
+ let lineStart = 0;
44
+ while (lineStart < markdown.length) {
45
+ const newline = markdown.indexOf('\n', lineStart);
46
+ const lineEnd = newline >= 0 ? newline + 1 : markdown.length;
47
+ const line = markdown.slice(lineStart, newline >= 0 ? newline : markdown.length).replace(/\r$/, '');
48
+ let fenceLine = line;
49
+ // CommonMark permits fences inside blockquote and list containers. Strip
50
+ // only the structural prefix used to introduce a fence; the recorded byte
51
+ // range still covers the untouched source.
52
+ for (;;) {
53
+ const quote = fenceLine.match(/^ {0,3}>[ \t]?/);
54
+ if (quote) {
55
+ fenceLine = fenceLine.slice(quote[0].length);
56
+ continue;
57
+ }
58
+ const list = fenceLine.match(/^ {0,3}(?:[-+*]|\d{1,9}[.)])[ \t]+/);
59
+ if (list) {
60
+ fenceLine = fenceLine.slice(list[0].length);
61
+ continue;
62
+ }
63
+ break;
64
+ }
65
+ if (!fence) {
66
+ const open = fenceLine.match(/^ {0,3}(`{3,}|~{3,})/);
67
+ if (open) fence = { char: open[1][0], length: open[1].length, start: lineStart };
68
+ } else {
69
+ const close = fenceLine.match(/^ {0,3}(`+|~+)[ \t]*$/);
70
+ if (close && close[1][0] === fence.char && close[1].length >= fence.length) {
71
+ fencedRanges.push({ start: fence.start, end: lineEnd });
72
+ fence = null;
73
+ }
74
+ }
75
+ lineStart = lineEnd;
76
+ }
77
+ if (fence) fencedRanges.push({ start: fence.start, end: markdown.length });
78
+
79
+ const spans = [];
80
+ for (let i = 0; i < markdown.length;) {
81
+ const fenced = fencedRanges.find((range) => i >= range.start && i < range.end);
82
+ if (fenced) {
83
+ i = fenced.end;
84
+ continue;
85
+ }
86
+ if (markdown[i] !== '`' || isEscaped(i)) {
87
+ i += 1;
88
+ continue;
89
+ }
90
+
91
+ let runLength = 1;
92
+ while (markdown[i + runLength] === '`') runLength += 1;
93
+ const lineStart = markdown.lastIndexOf('\n', i - 1) + 1;
94
+
95
+ const contentStart = i + runLength;
96
+ let close = contentStart;
97
+ while (close < markdown.length) {
98
+ if (markdown[close] !== '`' || isEscaped(close)) {
99
+ close += 1;
100
+ continue;
101
+ }
102
+ let closeLength = 1;
103
+ while (markdown[close + closeLength] === '`') closeLength += 1;
104
+ if (closeLength === runLength) break;
105
+ close += closeLength;
106
+ }
107
+
108
+ if (close >= markdown.length) break;
109
+ const lineEndIndex = markdown.indexOf('\n', close);
110
+ spans.push({
111
+ start: contentStart,
112
+ end: close,
113
+ value: markdown.slice(contentStart, close).trim(),
114
+ lineStart,
115
+ lineEnd: lineEndIndex >= 0 ? lineEndIndex : markdown.length,
116
+ });
117
+ i = close + runLength;
118
+ }
119
+
120
+ const target = spans.find((span) => candidateStart >= span.start && candidateEnd <= span.end);
121
+ if (!target || !MIGRATION_LEDGER_ACTION_VALUES.includes(target.value)) return false;
122
+
123
+ const referencedValues = new Set(
124
+ spans
125
+ .filter((span) => span.lineStart === target.lineStart && span.lineEnd === target.lineEnd)
126
+ .map((span) => span.value)
127
+ .filter((value) => MIGRATION_LEDGER_ACTION_VALUES.includes(value)),
128
+ );
129
+ return referencedValues.size >= 2;
130
+ }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-29T09:19:22.136Z",
5
- "instarVersion": "1.3.1048",
4
+ "generatedAt": "2026-07-29T10:34:17.724Z",
5
+ "instarVersion": "1.3.1050",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -2,5 +2,5 @@
2
2
  "sha256": "b75c147afd1f5a9843ca4eac372159f3623f24731fe63b2f59e48043ae488af9",
3
3
  "articleCount": 82,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1048"
5
+ "packageVersion": "1.3.1050"
6
6
  }
@@ -0,0 +1,28 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The development specification check now recognizes a reference list for a
9
+ shipped, closed telemetry enum instead of reading one member as postponed work.
10
+ Headings, callouts, fenced blocks, lone values, and standalone status words
11
+ remain checked.
12
+
13
+ ## What to Tell Your User
14
+
15
+ Technical state names in specifications no longer trigger an irrelevant
16
+ unfinished-work warning, while real scope decisions are still checked.
17
+
18
+ ## Summary of New Capabilities
19
+
20
+ - Closed-enum reference recognition in the development specification gate.
21
+
22
+ ## Evidence
23
+
24
+ - The live telemetry-enum regression now passes without an override.
25
+ - Real scope-decision forms and fenced examples remain blocked.
26
+ - The recognized value list is pinned to the shipped enum declaration.
27
+ - Removing the enum-list distinction makes the regression test fail.
28
+ - Focused tests and the repository typecheck pass.
@@ -0,0 +1,25 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Development decision records now retain the exact staged source files and
9
+ added/deleted-line counts behind their compact file and line totals.
10
+
11
+ ## What to Tell Your User
12
+
13
+ Internal development audit records now explain exactly what their size
14
+ counters measured.
15
+
16
+ ## Summary of New Capabilities
17
+
18
+ - Self-describing scope evidence for development decisions.
19
+
20
+ ## Evidence
21
+
22
+ - The focused hook integration test verifies the persisted counting basis,
23
+ file list, additions, and deletions.
24
+ - Existing compact `files` and `loc` fields remain unchanged for compatible
25
+ readers.
@@ -0,0 +1,23 @@
1
+ # Decision records now explain what their counters measured
2
+
3
+ The development commit gate already records two compact numbers for each
4
+ reviewed source change: how many source files were in scope and how many lines
5
+ changed. Those numbers are useful, but the record did not retain the concrete
6
+ file list or say whether the line count represented additions, deletions, or a
7
+ different basis. A later reader could see “three files, eighteen lines” without
8
+ being able to tell which files produced that result.
9
+
10
+ The gate now stores an additional `scope` object beside the existing counters.
11
+ It names the counting basis, lists the exact staged source files included, and
12
+ records added and deleted lines separately. The old `files` and `loc` fields
13
+ remain unchanged, so existing readers continue to work.
14
+
15
+ The new values come from the same staged-diff calculation the gate already
16
+ uses for tier signaling. There is no second calculation that can disagree with
17
+ the original counters. If that existing calculation cannot run, the gate keeps
18
+ its current fail-open behavior and records the same zero counts explicitly.
19
+
20
+ This changes evidence only. It does not change which files require review,
21
+ which tier is suggested, which trace is selected, or whether a commit passes.
22
+ A focused integration test runs the real hook in a temporary repository and
23
+ asserts the emitted record’s basis, file list, additions, and deletions.
@@ -0,0 +1,37 @@
1
+ # Keyword gates now distinguish an enum value from a prose decision
2
+
3
+ The development gate that checks technical specifications for unfinished work
4
+ used to read every occurrence of the word “deferred” as a decision to postpone
5
+ something. That is usually a useful warning, but it also caught a telemetry
6
+ value such as `deferred-in-flight`. The value names a state in software; it does
7
+ not say that implementation work is being postponed. Because the check blocks a
8
+ commit, the only escape was an audited override even though there was no work to
9
+ track.
10
+
11
+ This change adds one deliberately narrow distinction. It knows the actual
12
+ closed list of migration telemetry outcomes shipped by the code. A match is
13
+ treated as an enum reference only when the complete inline-code value belongs
14
+ to that list and at least one other member of the same closed list appears in
15
+ inline code on the same line. A lone `deferred-in-flight` still triggers the
16
+ gate because it could be an authorial status. The exact same words in ordinary
17
+ prose also trigger it, as do headings, blockquotes, callouts, indented list
18
+ text, fenced blocks, standalone `deferred`, unknown identifiers, and escaped
19
+ backticks. Those places can all carry genuine scope decisions, so the
20
+ implementation does not infer intent from Markdown or hyphen count.
21
+
22
+ The new parser preserves the existing tracker lookup, diagnostics, override,
23
+ and block behavior. It supports matching single- or multi-backtick inline-code
24
+ spans, refuses fenced blocks and malformed ranges, and has a parity test that
25
+ pins its local closed set to the shipped type declaration. Tests prove both
26
+ sides: the telemetry enum list passes, while real scope-decision forms remain
27
+ blocked. A mutation test removed the new distinction and the enum regression
28
+ failed immediately.
29
+
30
+ The same investigation also records the broader failure class in the defect
31
+ registry: a literal keyword is given authority without enough context to know
32
+ what it means. That class remains unconfirmed and open because the other named
33
+ systems do not share one safe mechanical fix. The outbound convergence check is
34
+ separately tracked for removal from blocking authority; the recall change is
35
+ owned elsewhere; and raw shell-input safety needs enforcement at the relay
36
+ boundary, not another text carve-out. This PR therefore fixes the live enum
37
+ false positive without pretending it closes those different problems.
@@ -0,0 +1,73 @@
1
+ # Side-Effects Review — development decision audit scope
2
+
3
+ **Version / slug:** `decision-audit-scope`
4
+ **Date:** 2026-07-29
5
+ **Author:** Instar Agent (instar-codey)
6
+
7
+ ## Summary
8
+
9
+ The development pre-commit gate now persists the exact in-scope staged file
10
+ list, added-line count, deleted-line count, and named counting basis beside
11
+ each decision record’s existing compact `files` and `loc` counters.
12
+
13
+ ## Decision-point inventory
14
+
15
+ This changes evidence emitted by an existing gate, not its authority. Tier
16
+ classification, trace selection, refusal conditions, and verdict finalization
17
+ remain unchanged.
18
+
19
+ ## 1. Over-block
20
+
21
+ No new refusal is introduced. Audit writing remains best-effort and fail-open,
22
+ as before. The additive fields cannot prevent a commit.
23
+
24
+ ## 2. Under-block
25
+
26
+ The record still reflects only files covered by the gate’s existing `inScope`
27
+ predicate, not every file in the pull request. That boundary is now explicit
28
+ in the `staged-in-scope-additions-plus-deletions` basis and concrete file list,
29
+ rather than hidden behind a compact count. Removing the emitted object made the
30
+ focused assertion fail before the implementation was restored, proving the
31
+ test does not merely restate its own derivation.
32
+
33
+ ## 3. Level-of-abstraction fit
34
+
35
+ The audit writer is the correct owner because it already receives the tier
36
+ signal and writes the durable decision record. The added values reuse the
37
+ same staged `numstat` calculation rather than asking downstream consumers to
38
+ reconstruct a vanished diff.
39
+
40
+ ## 4. Signal vs authority compliance
41
+
42
+ Compliant with `docs/signal-vs-authority.md`. The scope fields are evidence
43
+ only. They add no detector, filter, or blocking authority and do not alter the
44
+ gate’s verdict.
45
+
46
+ ## 5. Interactions
47
+
48
+ Existing consumers retain the unchanged `files` and `loc` fields. New
49
+ consumers can inspect `scope`. The values are captured before any gate exit and
50
+ therefore accompany both passing and blocked decision records through the
51
+ existing verdict-finalization path.
52
+
53
+ ## 6. External surfaces
54
+
55
+ Internal decision JSON gains one additive object. No runtime API, user-facing
56
+ message, configuration, credential, or operator action changes.
57
+
58
+ ## 7. Multi-machine posture
59
+
60
+ Repository-replicated evidence. Decision records already ride the commit as
61
+ distinct files, so the new fields follow the same Git replication path and do
62
+ not introduce machine-local state or cross-machine authority.
63
+
64
+ ## 8. Rollback cost
65
+
66
+ A direct revert removes the additive fields. Records already written with
67
+ `scope` remain readable by older consumers because they ignore unknown keys.
68
+ No migration or state repair is required.
69
+
70
+ ## Conclusion
71
+
72
+ The change makes existing gate evidence interpretable without changing what
73
+ the gate decides.
@@ -0,0 +1,157 @@
1
+ # Side-Effects Review — Keyword-gate authorial context
2
+
3
+ **Version / slug:** `keyword-gate-authorial-context`
4
+ **Date:** `2026-07-29`
5
+ **Author:** `instar-codey`
6
+ **Second-pass reviewer:** `Euler`
7
+
8
+ ## Summary of the change
9
+
10
+ The instar-dev orphan-deferral blocker now excludes only a reference list for
11
+ the shipped MigrationPerEntryAction closed enum. The matched inline-code value
12
+ must belong to that enum and share a line with another enum member. It does not
13
+ remove headings, quotations, callouts, indented text, fenced content, lone enum
14
+ values, unknown identifiers, or standalone inline-code words from inspection.
15
+ A new pure helper owns the parse, and refusal-first tests cover the live enum
16
+ regression plus genuine decision shapes. The broader failure class is recorded
17
+ as an unconfirmed registry entry. ACT-1519 owns its confirmation/refinement;
18
+ ACT-1520 owns enforcement at the relay boundary.
19
+
20
+ ## Decision-point inventory
21
+
22
+ - `findOrphanDeferrals` — modified — skips one structurally qualified artifact
23
+ reference before applying the unchanged negation/tracker/block policy.
24
+ - `isKnownInlineCodeEnumReference` — added — validates equal-backtick
25
+ inline-code spans against the real closed enum and requires a same-line
26
+ sibling member; it has no authority outside the existing caller.
27
+ - Orphan-deferral commit block — pass-through — patterns, nearby-tracker
28
+ requirement, override, diagnostics, and exit behavior are unchanged.
29
+ - Defect-class registry — modified — names the broader cross-gate class as
30
+ unconfirmed; it grants no runtime authority.
31
+
32
+ ## 1. Over-block
33
+
34
+ Enum values shown alone, values rendered outside inline code, and unknown
35
+ identifier values still reach the existing blocker. This is intentional
36
+ conservatism: a lone `deferred-in-flight` may itself be an authorial
37
+ disposition. Historical quotations and fenced examples also still require a
38
+ tracker or the existing audited override.
39
+
40
+ The reported heading `## §8 — Out of scope (deliberate)` already passes current
41
+ main because none of the configured phrases matches it. A test pins that fact;
42
+ this change does not claim a heading fix that the current source cannot
43
+ reproduce.
44
+
45
+ ## 2. Under-block
46
+
47
+ An author could place a genuine decision inside a line that also enumerates
48
+ multiple real migration outcomes. That is the remaining narrow ambiguity.
49
+ Lone enum values, unknown multi-segment identifiers, standalone
50
+ `` `deferred` ``, headings, blockquotes/callouts, indented prose, fenced blocks,
51
+ escaped backticks, and the same enum token in prose all remain blocked and are
52
+ refusal-tested.
53
+
54
+ The broader keyword-authority class is not closed here. ACT-1519 already tracks
55
+ the Signal-vs-Authority correction and class refinement. ACT-1520 is the
56
+ tracked enforcement gap: move outbound checks to the relay/send boundary, where
57
+ quoting, variables, aliases, and wrappers do not decide what gets inspected.
58
+
59
+ ## 3. Level-of-abstraction fit
60
+
61
+ The helper answers a structured question at the structured boundary: “is this
62
+ match one member of the shipped closed enum being listed beside another
63
+ member?” It does not infer meaning from identifier shape or decide whether a
64
+ whole heading, quotation, code block, or paragraph is authorial. Two broader
65
+ implementations attempted those shortcuts; the required independent review
66
+ rejected them, and both designs were removed completely.
67
+
68
+ The other named gates are not forced through this helper. ACT-1519 owns moving
69
+ the outbound convergence regex out of blocking authority; recall has a
70
+ semantic-index design owned elsewhere; dangerous shell input needs
71
+ command-boundary enforcement.
72
+
73
+ ## 4. Signal vs authority compliance
74
+
75
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
76
+
77
+ This change adds no new blocking authority and does not promote a new keyword.
78
+ It narrows the evidence entering an existing blocker by validating an actual
79
+ closed enum reference. The existing blocker still uses literal language with commit authority,
80
+ so the broader constitutional concern is recorded honestly rather than called
81
+ closed: `brittle-keyword-authority`, unconfirmed, with `closure: gap` tied to
82
+ ACT-1520. ACT-1519 separately owns confirmation/refinement of the class.
83
+
84
+ ## 4b. Judgment-point check
85
+
86
+ No new static heuristic chooses among competing live signals. The helper
87
+ validates already-structured input against the shipped closed enum, with a
88
+ source-parity test. It cannot turn a non-match into a block; it can only remove
89
+ the demonstrated enum-list false positive from an existing candidate list.
90
+
91
+ ## 5. Interactions
92
+
93
+ - **Shadowing:** The identifier check runs before existing negation and nearby
94
+ tracker checks only for that candidate. All other candidates follow the
95
+ byte-identical path.
96
+ - **Double-fire:** None. The helper returns one boolean to the existing single
97
+ scan.
98
+ - **Races:** None. Parsing is pure and local to one staged document.
99
+ - **Feedback loops:** Fewer invalid blocks should reduce override use. The
100
+ override log and decision audit are otherwise unchanged.
101
+
102
+ ## 6. External surfaces
103
+
104
+ Instar contributors can commit specs that reference the closed telemetry enum
105
+ as a list without an audited override. Real unfinished-work language still receives the
106
+ same blocking diagnostic. No APIs, user messages, persistent runtime state,
107
+ external services, timing assumptions, or operator-facing actions change.
108
+
109
+ ## 6b. Operator-surface quality
110
+
111
+ No operator surface — not applicable.
112
+
113
+ ## 7. Multi-machine posture
114
+
115
+ Git-replicated source behavior. Every machine running the same source revision
116
+ gets the same pure classification; no machine-local state is added. The change
117
+ emits no user notice, holds no durable state, and generates no URLs.
118
+
119
+ ## 8. Rollback cost
120
+
121
+ Pure code and registry rollback. Reverting the helper import and exclusion
122
+ restores the previous over-block immediately. No data migration or agent-state
123
+ repair is required.
124
+
125
+ ## Conclusion
126
+
127
+ Clear to ship after the independent re-review. Two overly broad syntax
128
+ heuristics were rejected and removed; the final change binds only to the real
129
+ shipped enum, proves the nearby under-block boundaries, and records the larger
130
+ class without claiming to have solved unrelated gates.
131
+
132
+ ## Second-pass review
133
+
134
+ **Reviewer:** Euler
135
+ **Independent read of the artifact: approved after three blocking passes.**
136
+ The first two designs exempted broad Markdown/identifier shapes and were
137
+ removed. The final pass verified closed-enum parity, lone/prose/status refusal,
138
+ and top-level, blockquoted, and list-nested fenced ranges. It also verified that
139
+ ACT-1519 owns class refinement and ACT-1520 owns relay-boundary enforcement.
140
+ There are no remaining blocking findings.
141
+
142
+ ## Evidence pointers
143
+
144
+ - `tests/unit/instar-dev-precommit-deferrals.test.ts`
145
+ - `tests/unit/markdown-code-identifier.test.ts`
146
+ - `tests/unit/class-closure-registry.test.ts`
147
+ - Mutation proof: removing the identifier exclusion makes the enum test fail.
148
+ - `npx tsc --noEmit`
149
+ - `git diff --check`
150
+
151
+ ## Class-Closure Declaration (display-only mirror)
152
+
153
+ `defectClass: brittle-keyword-authority`, `closure: gap`, `gapItem: ACT-1520`.
154
+ The class is new and unconfirmed; the current PR closes the reproduced enum
155
+ instance but does not claim that a local lexical exclusion ends the broader
156
+ raw-input and natural-language authority class. ACT-1519 owns class
157
+ confirmation/refinement; ACT-1520 owns the missing relay-boundary enforcement.