instar 1.3.1031 → 1.3.1032

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.1031",
3
+ "version": "1.3.1032",
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",
@@ -212,12 +212,32 @@ function isInRegistry(filepath, registryContent) {
212
212
 
213
213
  function hasMatchingCanary(stagedFiles, filepath) {
214
214
  // A matching canary is any file in the same adapter's canary/ directory,
215
- // or a file named *Canary*.ts adjacent to the source file.
215
+ // or a file named *Canary*.ts ADJACENT to the source file.
216
+ //
217
+ // "Adjacent" used to be unimplemented: the second clause tested
218
+ // `/canary/i.test(path.basename(f))` against every staged file without ever
219
+ // referencing `filepath`. That made it a property of the COMMIT, not a
220
+ // relationship — stage one canary-named file anywhere and every other file in
221
+ // the change was credited with having a canary. src/ carries 11 such files, so
222
+ // any broad commit touching one satisfied the canary half of Rule 3 wholesale.
223
+ //
224
+ // It failed in the QUIET direction (weakening the gate rather than blocking
225
+ // wrongly), which is why nothing ever complained about it.
226
+ // TWO canary/ locations, because sources sit at two depths. A source one
227
+ // level below the adapter root (adapters/X/observability/foo.ts) has its
228
+ // canary at adapters/X/canary/; a source AT the adapter root
229
+ // (adapters/X/foo.ts) has it at adapters/X/canary/ too — but that is
230
+ // `<dir>/canary`, not `<parent>/canary`. The original computed only the
231
+ // parent form, so the directory clause silently missed the second layout and
232
+ // the global fallback above was covering for it. Removing the fallback
233
+ // without fixing this would have turned a too-weak check into a wrong one.
216
234
  const dir = path.dirname(filepath);
217
235
  const adapterRoot = dir.split('/').slice(0, -1).join('/');
218
- const canaryDir = path.join(adapterRoot, 'canary');
236
+ const canaryDirs = [path.join(dir, 'canary'), path.join(adapterRoot, 'canary')];
219
237
  return stagedFiles.some(
220
- (f) => f.startsWith(canaryDir + '/') || /canary/i.test(path.basename(f)),
238
+ (f) =>
239
+ canaryDirs.some((cd) => f.startsWith(cd + '/')) ||
240
+ (path.dirname(f) === dir && /canary/i.test(path.basename(f))),
221
241
  );
222
242
  }
223
243
 
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-28T13:03:59.365Z",
5
- "instarVersion": "1.3.1031",
4
+ "generatedAt": "2026-07-28T13:11:52.917Z",
5
+ "instarVersion": "1.3.1032",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,36 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The Rule 3 gate's canary check credited a file if **any** staged file had a canary-ish basename — it
9
+ never referenced the file under test, so it was a property of the commit rather than a relationship.
10
+ `src/` holds 11 canary-named files, so any broad commit touching one satisfied the canary half of Rule 3
11
+ for everything else in the change. It failed in the permissive direction, which is why it went unnoticed.
12
+
13
+ Underneath it, the canary-directory probe computed `<parent-of-dir>/canary` only, missing a source that
14
+ sits directly in an adapter root. The permissive fallback was masking that — so removing the fallback
15
+ alone would have turned a too-weak check into a wrong one.
16
+
17
+ Both fixed: the fallback now requires the canary to be in the file's own directory, and the probe covers
18
+ both layouts.
19
+
20
+ ## What to Tell Your User
21
+
22
+ Nothing — a contributor-facing pre-commit script.
23
+
24
+ ## Summary of New Capabilities
25
+
26
+ None. The gate is stricter: it stops granting canary credit that was never earned. A file carrying a
27
+ Rule 3.1 rationale is unaffected.
28
+
29
+ ## Evidence
30
+
31
+ - Red → green: the new unrelated-canary test fails without the change (1 failed / 26 passed), passes with
32
+ it (27/27).
33
+ - The **second** bug was found because an existing test failed when I tightened the first. I assumed the
34
+ test was wrong; it was describing a real directory layout the probe could not see.
35
+ - Held deliberately until #1701 landed — tightening this earlier would have surfaced main's latent Rule 3
36
+ violations on every merge. Verified `mergeHeadIfMerging` is on `main` before proceeding.
@@ -0,0 +1,26 @@
1
+ # ELI16 — one file with the right name let a whole commit off the hook
2
+
3
+ Rule 3 says code that reads outside state must ship with either a written justification or a "canary" —
4
+ a small file that proves the reading still works. The check looked for a canary next to your file.
5
+
6
+ Except it didn't check "next to". It asked: *is any file in this commit called something-canary?* If
7
+ yes, **every** file in the commit was treated as having one. There are eleven canary-named files in the
8
+ source tree, so any broad change touching one of them satisfied that half of the rule for everything
9
+ else it contained.
10
+
11
+ It failed silently in the permissive direction — it let things through rather than blocking them — so
12
+ nobody ever hit it and complained.
13
+
14
+ **A second bug was hiding underneath.** The check *did* have a proper "look in the canary folder next to
15
+ this file" rule, but it looked one directory too high. It worked for files nested inside an adapter and
16
+ missed files sitting directly in one. The sloppy catch-all was quietly covering for it — so removing
17
+ the catch-all on its own would have turned a too-weak check into a plainly wrong one.
18
+
19
+ I only found that because an existing test failed when I tightened the first rule. I had assumed the
20
+ test was wrong. It wasn't; it was describing a real folder layout the check couldn't see.
21
+
22
+ **Both are fixed:** the catch-all now requires the canary to actually be beside the file, and the folder
23
+ rule checks both layouts.
24
+
25
+ The check is now stricter than it was yesterday. That's the point — it was passing things it should
26
+ have refused.
@@ -0,0 +1,45 @@
1
+ # Side-effects review — Rule 3 canary adjacency
2
+
3
+ **Change:** `hasMatchingCanary` in `scripts/check-rule3-coverage.cjs` — the basename fallback is scoped
4
+ to the file's own directory, and the canary-directory probe now covers both layouts. One new test.
5
+
6
+ ## Direction of effect
7
+
8
+ **Stricter**, so the risk to weigh is a false REFUSAL blocking legitimate work.
9
+
10
+ | situation | before | after |
11
+ |---|---|---|
12
+ | canary in `<dir>/canary/` | **missed** (only `<parent>/canary` was computed) | matched |
13
+ | canary in `<parent>/canary/` | matched | matched |
14
+ | canary-named file **beside** the source | matched | matched |
15
+ | canary-named file **anywhere else in the commit** | matched ❌ | **not matched** — the fix |
16
+ | no canary, but a rationale comment | passes | passes (unchanged) |
17
+
18
+ Rule 3 is satisfied by `inRegistry && (rationale || canary)` **or** `rationale && canary`, so a file
19
+ with a rationale is unaffected either way. This only removes credit that was never earned.
20
+
21
+ ## The interaction that made this worth care
22
+
23
+ Removing the global fallback alone would have **broken** the check: the directory probe computed
24
+ `<parent-of-dir>/canary`, which misses a source sitting directly in an adapter root. The fallback was
25
+ masking it. An existing test caught this immediately — I had assumed the test was wrong, and it was
26
+ describing a real layout.
27
+
28
+ ## Sequencing — why now and not earlier
29
+
30
+ Filed as ACT-1472 and deliberately held: making this stricter **before** #1701 (judge the author's
31
+ contribution, not the merge index) would have surfaced all of main's latent Rule 3 violations on every
32
+ merge. #1701 is now on `main` (verified: `mergeHeadIfMerging` present), so a merge evaluates only the
33
+ committer's own files and this cannot cascade.
34
+
35
+ ## Blast radius
36
+
37
+ Pre-commit script only — not in `src/`, not shipped, not executed at runtime. `git revert` restores
38
+ both the permissive fallback and the layout blind spot.
39
+
40
+ ## Verification
41
+
42
+ - Red → green: the new unrelated-canary test fails without the change (1 failed / 26 passed) and passes
43
+ with it (27/27).
44
+ - The pre-existing "canary staged alongside" test passes, which is what demonstrates the layout fix —
45
+ it was the failure that revealed the second bug.