instar 1.3.1021 → 1.3.1022

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.1021",
3
+ "version": "1.3.1022",
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",
@@ -149,9 +149,22 @@ function readRegistry() {
149
149
  }
150
150
 
151
151
  function isInRegistry(filepath, registryContent) {
152
- // Strip src/ prefix; the registry uses paths relative to src/.
153
- const stripped = filepath.replace(/^src\//, '');
154
- return registryContent.includes(stripped);
152
+ // The registry's Location column is SECTION-relative, not uniformly relative
153
+ // to src/. Most sections write paths relative to src/, but the provider
154
+ // substrate section ("Provider substrate (`src/providers/`)") writes them
155
+ // relative to src/providers/ — 21 of its 23 rows, measured on main.
156
+ //
157
+ // Stripping only `src/` therefore looked for `providers/adapters/X.ts` while
158
+ // the row said `adapters/X.ts`, so no provider file could ever match. A file
159
+ // listed in three registry rows was still refused for a "missing registry
160
+ // entry", which told the author to add a row that already existed.
161
+ if (registryContent.includes(filepath.replace(/^src\//, ''))) return true;
162
+ // Only widen for genuine provider paths, so no other file gains a match it
163
+ // would not otherwise have had.
164
+ if (filepath.startsWith('src/providers/')) {
165
+ return registryContent.includes(filepath.replace(/^src\/providers\//, ''));
166
+ }
167
+ return false;
155
168
  }
156
169
 
157
170
  function hasMatchingCanary(stagedFiles, filepath) {
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-28T02:53:15.912Z",
5
- "instarVersion": "1.3.1021",
4
+ "generatedAt": "2026-07-28T09:26:52.565Z",
5
+ "instarVersion": "1.3.1022",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,42 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The Rule 3 pre-commit gate's registry lookup could never match a file under `src/providers/`.
9
+
10
+ `isInRegistry()` stripped only `src/`, so it searched the state-detector registry for
11
+ `providers/adapters/foo/Bar.ts` — while the registry's provider section writes its Location column
12
+ relative to `src/providers/`, i.e. `adapters/foo/Bar.ts`. 21 of that section's 23 rows use that
13
+ form. The strings never met.
14
+
15
+ A registered file was therefore still refused, with a message instructing the author to add a
16
+ registry entry that already existed — in one case, one that appears in three separate rows.
17
+
18
+ The lookup now also tries the `src/providers/`-relative form, guarded by
19
+ `filepath.startsWith('src/providers/')` so no other file gains a match it did not already have.
20
+
21
+ ## What to Tell Your User
22
+
23
+ Nothing. This is a contributor-facing pre-commit script — not shipped, not executed at runtime, no
24
+ user-visible behaviour.
25
+
26
+ ## Summary of New Capabilities
27
+
28
+ None. A registry entry still does not exempt a file on its own: `inRegistry && (hasRationale ||
29
+ hasCanary)` is unchanged. This only stops the gate from ignoring a registry row that genuinely
30
+ exists.
31
+
32
+ ## Evidence
33
+
34
+ - Red → green, observed rather than predicted: the provider case failed and the `src/`-relative
35
+ control passed before the fix (1 failed / 23 passed); 24/24 after. The control is what isolates
36
+ the cause to the path form.
37
+ - **Why the branch had no coverage:** `tests/unit/scripts/check-rule3-coverage.test.ts` copied the
38
+ script into its tmp repo but executed the *original*. Since the script resolves its registry from
39
+ `__dirname/../specs/`, it read the real repo's registry while reading staged files from the tmp
40
+ repo — so every registry fixture a test wrote was silently ignored. Fixed by running the copy;
41
+ all 22 pre-existing tests pass unchanged under the corrected harness.
42
+ - Side-effects review: `upgrades/side-effects/rule3-registry-lookup-provider-paths.md`.
@@ -0,0 +1,36 @@
1
+ # ELI16 — the gate told authors to add a registry row that was already there
2
+
3
+ There is a registry listing every place Instar reads state from something it doesn't control.
4
+ A pre-commit gate uses it: if your file is in the registry *and* carries a rationale comment,
5
+ the gate lets it through.
6
+
7
+ For files under `src/providers/`, that lookup could never succeed.
8
+
9
+ **Why.** The gate turned `src/providers/adapters/foo/Bar.ts` into
10
+ `providers/adapters/foo/Bar.ts` and searched the registry for that string. But the registry's
11
+ provider section writes its paths relative to `src/providers/`, so the row actually says
12
+ `adapters/foo/Bar.ts`. The two never matched — 21 of the 23 provider rows are written that way.
13
+
14
+ The result: a file listed in the registry — one of them appears in **three** rows — was still
15
+ refused, with a message telling the author to add a registry entry. Adding the row again would
16
+ not have helped. That is the worst kind of gate message: it is confidently wrong about what
17
+ would fix it.
18
+
19
+ **Why nobody noticed.** The test file for this gate builds a throwaway repo, copies the script
20
+ into it, writes a registry fixture — and then runs the *original* script instead of the copy.
21
+ The script finds its registry relative to its own folder, so it read the real repo's registry
22
+ while reading the staged files from the throwaway one. Every registry fixture a test wrote was
23
+ quietly ignored, so this whole branch had no working test coverage. That is fixed here too, by
24
+ running the copy.
25
+
26
+ **How I know the fix works rather than believing it.** I wrote two tests: the provider case, and
27
+ a control using the ordinary path form that should already have worked. Before the fix the
28
+ provider one failed and the control passed. After, both pass, and the 22 tests that were already
29
+ there still pass.
30
+
31
+ Worth saying: the control failed on my first attempt too, which meant my explanation was wrong.
32
+ Chasing that disagreement is what turned up the harness defect. A control test that fails is
33
+ telling you something.
34
+
35
+ **Scope.** A registry entry still does not exempt a file on its own — a rationale or a canary is
36
+ still required. This only stops the gate from ignoring a registry row that genuinely exists.
@@ -0,0 +1,57 @@
1
+ # Side-effects review — Rule 3 gate registry lookup (provider paths)
2
+
3
+ **Change:** `isInRegistry()` in `scripts/check-rule3-coverage.cjs` gains a second, narrowly-scoped
4
+ path form; `tests/unit/scripts/check-rule3-coverage.test.ts` runs the copied script instead of the
5
+ original and gains 2 tests + a registry-fixture helper.
6
+
7
+ ## Direction of effect — the only question that matters for a gate
8
+
9
+ This makes the gate **strictly more permissive**, so the risk to weigh is a false ACCEPT, never a
10
+ false refusal.
11
+
12
+ | Surface | Effect |
13
+ |---|---|
14
+ | Non-provider files | **None.** The widened form is behind `filepath.startsWith('src/providers/')`, so no other file can gain a match it did not already have. |
15
+ | Provider files, registered, with rationale | Now correctly accepted (was refused). **This is the fix.** |
16
+ | Provider files, registered, no rationale/canary | Still refused — `inRegistry && (hasRationale \|\| hasCanary)` is unchanged. |
17
+ | Provider files, unregistered | Still refused. Containment against a row that does not exist still fails. |
18
+ | Runtime / shipped product | **None.** A pre-commit script; not in `src/`, not bundled, not executed by the server. |
19
+
20
+ ## The false-accept surface, stated plainly
21
+
22
+ Containment is a substring test, so a short row path could in principle match an unintended file.
23
+ That property is **pre-existing** and unchanged in kind — this only adds a second candidate string
24
+ for paths already under `src/providers/`. A file would need to be under `src/providers/` *and* have
25
+ its `src/providers/`-relative path appear verbatim in the registry, which is precisely the
26
+ condition the fix exists to honour.
27
+
28
+ I considered resolving each row against its section heading instead, which would remove the
29
+ guesswork entirely. It is the better long-term shape and a larger change; it is not done here.
30
+
31
+ ## Test-harness change — read this as a coverage change, not a cosmetic one
32
+
33
+ `runCheck` now executes the copy inside the tmp repo. The script resolves the registry from
34
+ `__dirname/../specs/`, so running the original read the **real** repo's registry while reading
35
+ staged files from the tmp repo.
36
+
37
+ Consequence: every registry fixture written by a test was silently ignored, and the
38
+ "already in the registry" branch had **no reachable coverage at all**. `beforeEach` had always
39
+ copied the script in — the copy was simply never run.
40
+
41
+ All 22 pre-existing tests pass unchanged under the corrected harness, which is the evidence that
42
+ this repaired coverage rather than altering what those tests assert.
43
+
44
+ ## Verification
45
+
46
+ - **Red → green, observed:** before the fix, the provider test failed and the `src/`-relative
47
+ control passed (1 failed / 23 passed). After, 24/24.
48
+ - The control is the load-bearing part: it fails if the cause is anything other than the provider
49
+ path form.
50
+ - **A correction this produced:** on my first attempt the control failed *too*, which meant my
51
+ explanation was wrong — a registry entry alone never exempted anything. Following that
52
+ disagreement is what surfaced the harness defect. The earlier claim that 26 files on `main` were
53
+ affected is withdrawn: all 26 lack a rationale and would be refused regardless.
54
+
55
+ ## Rollback
56
+
57
+ `git revert`. Restores the unreachable lookup; no state, no migration, no config.