instar 1.3.1048 → 1.3.1049
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.
- package/dist/data/standards-registry.meta.json +1 -1
- package/package.json +1 -1
- package/scripts/instar-dev-precommit.js +9 -3
- package/scripts/lib/markdown-code-identifier.mjs +130 -0
- package/src/data/builtin-manifest.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/upgrades/1.3.1049.md +28 -0
- package/upgrades/eli16/keyword-gate-authorial-context.md +37 -0
- package/upgrades/side-effects/keyword-gate-authorial-context.md +157 -0
package/package.json
CHANGED
|
@@ -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
|
|
|
@@ -843,9 +844,13 @@ if (staged.includes(spec) && !staged.includes(eli16Rel)) {
|
|
|
843
844
|
// `deferrals-tracked` field). Override via INSTAR_DEV_ALLOW_ORPHAN_DEFERRALS=1
|
|
844
845
|
// (logged for visibility).
|
|
845
846
|
//
|
|
846
|
-
// Detector patterns intentionally conservative
|
|
847
|
-
//
|
|
848
|
-
//
|
|
847
|
+
// Detector patterns intentionally remain conservative over the complete
|
|
848
|
+
// document: headings, callouts, indented text, and standalone inline-code words
|
|
849
|
+
// can all carry real scope decisions. The one structural exclusion is a
|
|
850
|
+
// reference list for the shipped MigrationPerEntryAction CLOSED ENUM. A lone
|
|
851
|
+
// `deferred-in-flight` remains visible; the exemption requires another known
|
|
852
|
+
// enum member on the same line. This validates structured input rather than
|
|
853
|
+
// inferring meaning from Markdown or identifier shape.
|
|
849
854
|
// Patterns: { regex, requireUnnegated } — when requireUnnegated is true,
|
|
850
855
|
// we skip the match if the immediately-preceding chars contain "no ", "non-",
|
|
851
856
|
// "non ", "non", or "un" (so "no deferrals" / "non-deferred" / "undeferred"
|
|
@@ -883,6 +888,7 @@ function findOrphanDeferrals(content) {
|
|
|
883
888
|
let m;
|
|
884
889
|
while ((m = regex.exec(content)) !== null) {
|
|
885
890
|
const start = m.index;
|
|
891
|
+
if (isKnownInlineCodeEnumReference(content, start, start + m[0].length)) continue;
|
|
886
892
|
if (requireUnnegated) {
|
|
887
893
|
// Look at up to 8 chars immediately before the match. Treat
|
|
888
894
|
// matches preceded by "no ", "non-", "non ", "un" as legitimate
|
|
@@ -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-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-07-29T10:16:28.309Z",
|
|
5
|
+
"instarVersion": "1.3.1049",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -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,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,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.
|