instar 1.3.1149 → 1.3.1150

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": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
5
- "packageVersion": "1.3.1149",
5
+ "packageVersion": "1.3.1150",
6
6
  "guards": [
7
7
  {
8
8
  "ref": "docs/audits/phase-b/f10-triage.md",
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha256": "1ed8f5bd6959a002ef362c9be5f88a382b0956d4992b16879350851ce3711ac9",
2
+ "sha256": "65b8fa203de000f59bf34d2f1ac5f30e0656f81da112a5f1dde281cf1be35b3c",
3
3
  "registrySha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
4
- "packageVersion": "1.3.1149"
4
+ "packageVersion": "1.3.1150"
5
5
  }
@@ -2,5 +2,5 @@
2
2
  "sha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
3
3
  "articleCount": 88,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1149"
5
+ "packageVersion": "1.3.1150"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.1149",
3
+ "version": "1.3.1150",
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",
@@ -42,14 +42,160 @@ export const UNREACHABLE_OFF_GATE =
42
42
 
43
43
  const SUPPRESS = /lint-allow-messaging-gate\s*:/;
44
44
 
45
+ function stripCommentsPreserveLines(text) {
46
+ let out = '';
47
+ let inBlock = false;
48
+ let quote = null;
49
+
50
+ for (let i = 0; i < text.length; i += 1) {
51
+ const ch = text[i];
52
+ const next = text[i + 1];
53
+
54
+ if (inBlock) {
55
+ if (ch === '*' && next === '/') {
56
+ out += ' ';
57
+ i += 1;
58
+ inBlock = false;
59
+ } else {
60
+ out += ch === '\n' ? '\n' : ' ';
61
+ }
62
+ continue;
63
+ }
64
+
65
+ if (quote) {
66
+ out += ch;
67
+ if (ch === '\\' && i + 1 < text.length) {
68
+ out += text[i + 1];
69
+ i += 1;
70
+ continue;
71
+ }
72
+ if (ch === quote) quote = null;
73
+ continue;
74
+ }
75
+
76
+ if (ch === '/' && next === '/') {
77
+ out += ' ';
78
+ i += 1;
79
+ while (i + 1 < text.length && text[i + 1] !== '\n') {
80
+ out += ' ';
81
+ i += 1;
82
+ }
83
+ continue;
84
+ }
85
+
86
+ if (ch === '/' && next === '*') {
87
+ out += ' ';
88
+ i += 1;
89
+ inBlock = true;
90
+ continue;
91
+ }
92
+
93
+ if (ch === "'" || ch === '"' || ch === '`') quote = ch;
94
+ out += ch;
95
+ }
96
+
97
+ return out;
98
+ }
99
+
100
+ function skipWs(s, i) {
101
+ while (i < s.length && /\s/.test(s[i])) i += 1;
102
+ return i;
103
+ }
104
+
105
+ function parseStringLiteral(s, start) {
106
+ const quote = s[start];
107
+ if (quote !== "'" && quote !== '"' && quote !== '`') return null;
108
+
109
+ let value = '';
110
+ for (let i = start + 1; i < s.length; i += 1) {
111
+ const ch = s[i];
112
+ if (ch === '\\' && i + 1 < s.length) {
113
+ value += s[i + 1];
114
+ i += 1;
115
+ continue;
116
+ }
117
+ if (quote === '`' && ch === '$' && s[i + 1] === '{') return null;
118
+ if (ch === quote) return { value, end: i + 1 };
119
+ value += ch;
120
+ }
121
+ return null;
122
+ }
123
+
124
+ function parseLiteralConcat(s, start) {
125
+ let i = skipWs(s, start);
126
+ let parsed = parseStringLiteral(s, i);
127
+ if (!parsed) return null;
128
+
129
+ let value = parsed.value;
130
+ i = skipWs(s, parsed.end);
131
+ while (s[i] === '+') {
132
+ i = skipWs(s, i + 1);
133
+ parsed = parseStringLiteral(s, i);
134
+ if (!parsed) return null;
135
+ value += parsed.value;
136
+ i = skipWs(s, parsed.end);
137
+ }
138
+
139
+ return { value, end: i };
140
+ }
141
+
142
+ function getCallArgStartAt(s, start) {
143
+ if (!s.startsWith('.get', start)) return null;
144
+ if (/[$_\p{ID_Continue}]/u.test(s[start + 4] ?? '')) return null;
145
+
146
+ let i = skipWs(s, start + 4);
147
+ if (s[i] === '<') {
148
+ const close = s.indexOf('>', i + 1);
149
+ if (close === -1) return null;
150
+ i = skipWs(s, close + 1);
151
+ }
152
+ if (s[i] !== '(') return null;
153
+ return i + 1;
154
+ }
155
+
156
+ function lineHasUnreachableOffGate(line) {
157
+ let quote = null;
158
+ for (let i = 0; i < line.length; i += 1) {
159
+ const ch = line[i];
160
+ if (quote) {
161
+ if (ch === '\\' && i + 1 < line.length) {
162
+ i += 1;
163
+ continue;
164
+ }
165
+ if (ch === quote) quote = null;
166
+ continue;
167
+ }
168
+
169
+ if (ch === "'" || ch === '"' || ch === '`') {
170
+ quote = ch;
171
+ continue;
172
+ }
173
+
174
+ const firstArgStart = getCallArgStartAt(line, i);
175
+ if (firstArgStart === null) continue;
176
+
177
+ const firstArg = parseLiteralConcat(line, firstArgStart);
178
+ if (!firstArg || !firstArg.value.startsWith('messaging.')) continue;
179
+
180
+ let j = skipWs(line, firstArg.end);
181
+ if (line[j] !== ',') continue;
182
+ j = skipWs(line, j + 1);
183
+ if (line.startsWith('false', j) && !/[$_\p{ID_Continue}]/u.test(line[j + 5] ?? '')) {
184
+ return true;
185
+ }
186
+ }
187
+ return false;
188
+ }
189
+
45
190
  /** Scan raw source text; return 1-indexed line numbers of un-suppressed offenders. */
46
191
  export function scanText(text) {
47
- const lines = text.split('\n');
192
+ const lines = stripCommentsPreserveLines(text).split('\n');
193
+ const originalLines = text.split('\n');
48
194
  const hits = [];
49
195
  lines.forEach((line, i) => {
50
- if (!UNREACHABLE_OFF_GATE.test(line)) return;
51
- if (SUPPRESS.test(line)) return;
52
- if (i > 0 && SUPPRESS.test(lines[i - 1])) return;
196
+ if (!lineHasUnreachableOffGate(line)) return;
197
+ if (SUPPRESS.test(originalLines[i])) return;
198
+ if (i > 0 && SUPPRESS.test(originalLines[i - 1])) return;
53
199
  hits.push(i + 1);
54
200
  });
55
201
  return hits;
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-08-15T00:08:31.593Z",
5
- "instarVersion": "1.3.1149",
4
+ "generatedAt": "2026-08-15T00:12:54.107Z",
5
+ "instarVersion": "1.3.1150",
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": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
5
- "packageVersion": "1.3.1149",
5
+ "packageVersion": "1.3.1150",
6
6
  "guards": [
7
7
  {
8
8
  "ref": "docs/audits/phase-b/f10-triage.md",
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha256": "1ed8f5bd6959a002ef362c9be5f88a382b0956d4992b16879350851ce3711ac9",
2
+ "sha256": "65b8fa203de000f59bf34d2f1ac5f30e0656f81da112a5f1dde281cf1be35b3c",
3
3
  "registrySha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
4
- "packageVersion": "1.3.1149"
4
+ "packageVersion": "1.3.1150"
5
5
  }
@@ -2,5 +2,5 @@
2
2
  "sha256": "81b53363a440e832672618965540b3e507ae0d93adcc67ec2b93daf7933b3ab4",
3
3
  "articleCount": 88,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1149"
5
+ "packageVersion": "1.3.1150"
6
6
  }
@@ -0,0 +1,21 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ - Strengthened the unreachable messaging gate lint so it detects default-off `messaging.*` LiveConfig keys built from literal string concatenation.
9
+
10
+ ## What to Tell Your User
11
+
12
+ None — internal change (no user-facing surface).
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ None — internal change (no user-facing surface).
17
+
18
+ ## Evidence
19
+
20
+ - `npx vitest run tests/unit/lint-no-unreachable-messaging-gate.test.ts`
21
+ - `node scripts/lint-no-unreachable-messaging-gate.js`
@@ -0,0 +1,117 @@
1
+ # Side-Effects Review - Split-Key Messaging Gate Lint
2
+
3
+ **Version / slug:** `lint-split-key-messaging-gate`
4
+ **Date:** `2026-08-14`
5
+ **Author:** `Instar-codey`
6
+ **Second-pass reviewer:** `Locke`
7
+
8
+ ## Summary of the change
9
+
10
+ This change strengthens `scripts/lint-no-unreachable-messaging-gate.js` so the existing unreachable default-off `messaging.*` LiveConfig lint also recognizes first-argument string literals joined with `+`, for example `liveConfig.get('messaging.' + 'actionClaim.enabled', false)`. The focused unit test file `tests/unit/lint-no-unreachable-messaging-gate.test.ts` now covers the reproduced split-key miss and the required controls. The release fragment is `upgrades/next/lint-split-key-messaging-gate.md`. Build location was a fresh worktree at `.worktrees/codey-lint-split-key-messaging-gate` on `JKHeadley/instar`, version `1.3.1146`, branched from current `origin/main`.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `scripts/lint-no-unreachable-messaging-gate.js` - modify - build-time decision that flags source lines where `LiveConfig.get` uses a `messaging.*` key with literal `false` default.
15
+ - Release note internal-only classification - pass-through - this is a script/test/docs-only change with no shipped `src/` runtime surface.
16
+
17
+ ---
18
+
19
+ ## 1. Over-block
20
+
21
+ The main legitimate input risk is a dynamic backtick template such as `` liveConfig.get(`messaging.${featureKey}`, false) `` being treated as a constant key. The implementation rejects template expressions during literal parsing, and the unit suite includes that negative control. Second-pass review also found that the first implementation could flag a `.get(...)` example embedded inside another string literal; the scanner now only recognizes `.get` tokens outside ordinary string literal text, and a regression test covers `const example = "liveConfig.get('messaging.' + 'actionClaim.enabled', false)"`. A literal-concat non-messaging key such as `liveConfig.get('monitoring.' + 'burnDetection.enabled', false)` is explicitly covered and remains accepted. A default-true split key remains accepted because the lint is specifically about default-off gates staying unreachable.
22
+
23
+ ---
24
+
25
+ ## 2. Under-block
26
+
27
+ The lint still misses non-literal construction such as `liveConfig.get('messaging.' + featureKey, false)` or helper-returned keys. That is intentional for this change: widening into dataflow or general expression evaluation would raise false-positive risk and would be a different guard. The known reproduced bypass is literal-plus-literal construction, and that class is now covered.
28
+
29
+ ---
30
+
31
+ ## 3. Level-of-abstraction fit
32
+
33
+ This is the right layer for the fix. The problem is a static source spelling that hides an unreachable configuration key. A build lint can catch the enumerable literal shape cheaply before release. A runtime gate would be later, noisier, and would still allow dead code to ship. The implementation uses a narrow scanner rather than general JavaScript evaluation, which fits the lint's existing design.
34
+
35
+ ---
36
+
37
+ ## 4. Signal vs authority compliance
38
+
39
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
40
+
41
+ - [ ] No - this change produces a signal consumed by an existing smart gate.
42
+ - [ ] No - this change has no block/allow surface.
43
+ - [ ] Yes - but the logic is a smart gate with full conversational context (LLM-backed with recent history or equivalent).
44
+ - [x] Yes, but over a hard enumerable source invariant rather than a competing-signals judgment point.
45
+
46
+ This lint has blocking authority in the build, but it is not deciding from brittle runtime context. It enforces a concrete invariant: a literal `messaging.*` config key with literal `false` default is unreachable through the expected top-level config surface. The new part only folds literal string pieces before applying that same invariant.
47
+
48
+ ---
49
+
50
+ ## 4b. Judgment-point check (Judgment Within Floors standard)
51
+
52
+ No new static heuristic at a competing-signals decision point. The domain is enumerable source text: literal string values, `+` separators, and the literal `false` default. There are no live signals such as ownership, urgency, recency, or user intent to arbitrate.
53
+
54
+ ---
55
+
56
+ ## 5. Interactions
57
+
58
+ - **Shadowing:** This replaces the prior single-regex detection path inside the same lint. It does not run before another checker or suppress another result.
59
+ - **Double-fire:** One line produces one hit through `scanText`; the scanner returns line numbers as before.
60
+ - **Races:** No shared runtime state. The script reads the source tree and exits.
61
+ - **Feedback loops:** No feedback loop. The output feeds developer/build action only.
62
+
63
+ ---
64
+
65
+ ## 6. External surfaces
66
+
67
+ No user-facing runtime surface changes. Other agents and users only see the effect when developing Instar: split-literal unreachable messaging gates fail the lint. No external service calls, no persistent state changes, no generated URLs, no timing dependency, and no operator-facing action surface.
68
+
69
+ ---
70
+
71
+ ## 6b. Operator-surface quality (Operator-Surface Quality standard)
72
+
73
+ No operator surface - not applicable.
74
+
75
+ ---
76
+
77
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
78
+
79
+ Machine-local by design: this is a source-tree lint that runs in the checkout performing the build. It holds no durable agent state, emits no user-facing notices, and generates no URLs. Multi-machine coherence is handled by committing the script/tests/release notes to git so every machine receives the same lint behavior after update.
80
+
81
+ ---
82
+
83
+ ## 8. Rollback cost
84
+
85
+ Pure code/test/docs change. Rollback is a hot-fix revert of the lint parser and its tests plus the release fragment. No data migration, no agent state repair, and no user-visible runtime regression during rollback.
86
+
87
+ ---
88
+
89
+ ## Conclusion
90
+
91
+ The review narrowed the implementation to literal-only first-argument folding, added a negative test for template expressions, and resolved second-pass's string-example false-positive concern by scanning for `.get` only outside string literal text. The change is clear to ship with the known caveat that dynamic key construction remains out of scope for this lint.
92
+
93
+ ---
94
+
95
+ ## Second-pass review (if required)
96
+
97
+ **Reviewer:** `Locke`
98
+ **Independent read of the artifact:** `concern, resolved`
99
+
100
+ Initial concern: the first implementation scanned for `.get` across preserved string contents, so a non-executed example string such as `const example = "liveConfig.get('messaging.' + 'actionClaim.enabled', false)"` could be reported. Resolution: `lineHasUnreachableOffGate` now locates `.get` only while outside string literal text, and `tests/unit/lint-no-unreachable-messaging-gate.test.ts` includes the example-string negative control. Dynamic concatenation and template expressions remained out of scope as intended.
101
+
102
+ ---
103
+
104
+ ## Evidence pointers
105
+
106
+ - Shipped-lint reproduction before the fix: split key returned `hits: []`, counted as `failureCount: 1`.
107
+ - After fix direct probe: split key returns `hits: [1]`.
108
+ - Focused suite: `npx vitest run tests/unit/lint-no-unreachable-messaging-gate.test.ts` passed `15/15` after the second-pass fix.
109
+ - Real tree: `node scripts/lint-no-unreachable-messaging-gate.js` exited clean with no existing flags.
110
+ - Full lint: `npm run lint` exited clean.
111
+ - Full push suite: `npm run test:push` ran 44,154 tests; 44,121 passed, 27 skipped, 3 todo, and 3 failed. Two failures were live Gemini e2e tests requiring absent `GEMINI_API_KEY`; the third feedback-drain ordering failure reran green in isolation.
112
+
113
+ ---
114
+
115
+ ## Class-Closure Declaration (display-only mirror)
116
+
117
+ No agent-authored-artifact defect - not applicable. This fixes a source-code lint detection gap and adds direct regression tests for the reproduced shape.