instar 1.3.1011 → 1.3.1013
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 +1 -1
- package/scripts/pre-push-gate.js +36 -23
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/{1.3.1011.md → 1.3.1012.md} +42 -0
- package/upgrades/1.3.1013.md +55 -0
- package/upgrades/side-effects/mutual-ssh-evidence-ref.md +45 -0
- package/upgrades/side-effects/prepush-gate-frozen-guide.md +78 -0
package/package.json
CHANGED
package/scripts/pre-push-gate.js
CHANGED
|
@@ -345,44 +345,57 @@ if (!process.env.CI) {
|
|
|
345
345
|
// isn't what this PR is changing. Falls back to the versioned guide when no
|
|
346
346
|
// fragment / NEXT.md is staged (post-release-cut state).
|
|
347
347
|
const inFlight = assembledContent !== null;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
348
|
+
|
|
349
|
+
// This check is a RELEASE-LEVEL re-check on the notes THIS PUSH is shipping —
|
|
350
|
+
// which means it only has a subject when in-flight notes exist. It deliberately
|
|
351
|
+
// does NOT fall back to the versioned guide.
|
|
352
|
+
//
|
|
353
|
+
// Why (three recurrences, 2026: v1.3.492, v1.3.802, v1.3.1009): the release cut
|
|
354
|
+
// renames upgrades/next/*.md into upgrades/<version>.md and bumps package.json,
|
|
355
|
+
// but side-effects artifacts are named per CHANGE SLUG, never per version — so
|
|
356
|
+
// upgrades/side-effects/<version>.md is a file the release flow never creates.
|
|
357
|
+
// Falling back to the frozen guide therefore demanded a filename that cannot
|
|
358
|
+
// exist, on EVERY push from a clean post-release tree, for a release that had
|
|
359
|
+
// already shipped and already been reviewed.
|
|
360
|
+
//
|
|
361
|
+
// The damage was not the refusal, it was the REMEDY the message named: three
|
|
362
|
+
// separate times someone hand-wrote a placeholder upgrades/side-effects/<version>.md
|
|
363
|
+
// to get past it (see 1.3.492.md and 1.3.802.md, both of which say so in their
|
|
364
|
+
// own text). A gate whose advice is unfollowable teaches people to write junk
|
|
365
|
+
// that satisfies it.
|
|
366
|
+
//
|
|
367
|
+
// Nothing is weakened. Per-change enforcement lives in the pre-COMMIT gate
|
|
368
|
+
// (scripts/instar-dev-precommit.js — refuses in-scope staged files without an
|
|
369
|
+
// ELI16 + side-effects artifact), and check 3b above already refuses a
|
|
370
|
+
// release-relevant push that ships no fragment, with an actionable remedy.
|
|
371
|
+
if (inFlight) {
|
|
352
372
|
// Extract "## What Changed" section
|
|
353
|
-
const whatChangedMatch =
|
|
373
|
+
const whatChangedMatch = assembledContent.match(/## What Changed\s*([\s\S]*?)(?=\n##\s|$)/);
|
|
354
374
|
const whatChanged = whatChangedMatch ? whatChangedMatch[1] : '';
|
|
355
375
|
|
|
356
376
|
const qualifies = FIX_PATTERNS.some((p) => p.test(whatChanged));
|
|
357
377
|
|
|
358
378
|
if (qualifies) {
|
|
359
379
|
const sideEffectsDir = path.join(ROOT, 'upgrades', 'side-effects');
|
|
360
|
-
// When in-flight notes (fragments/NEXT.md) drive the push, any fresh
|
|
361
|
-
// artifact (last 24h) counts — the versioned-filename requirement only
|
|
362
|
-
// applies when a versioned guide is being validated without in-flight notes.
|
|
363
|
-
const artifactName = (!inFlight && versionedGuideExists) ? `${version}.md` : null;
|
|
364
380
|
let artifactFound = false;
|
|
365
381
|
|
|
366
382
|
if (fs.existsSync(sideEffectsDir)) {
|
|
367
383
|
const files = fs.readdirSync(sideEffectsDir).filter((f) => f.endsWith('.md'));
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
return Date.now() - stat.mtimeMs < 24 * 60 * 60 * 1000;
|
|
377
|
-
});
|
|
378
|
-
artifactFound = recent.length > 0;
|
|
379
|
-
}
|
|
384
|
+
// Any fresh artifact from the last 24h counts — the in-flight notes name
|
|
385
|
+
// the change, the artifact reviews it, and the two are paired by the PR
|
|
386
|
+
// rather than by filename.
|
|
387
|
+
const recent = files.filter((f) => {
|
|
388
|
+
const stat = fs.statSync(path.join(sideEffectsDir, f));
|
|
389
|
+
return Date.now() - stat.mtimeMs < 24 * 60 * 60 * 1000;
|
|
390
|
+
});
|
|
391
|
+
artifactFound = recent.length > 0;
|
|
380
392
|
}
|
|
381
393
|
|
|
382
394
|
if (!artifactFound) {
|
|
383
395
|
errors.push(
|
|
384
|
-
`
|
|
385
|
-
`
|
|
396
|
+
`Your release-note fragment claims a fix/feature but no side-effects review artifact was written in the last 24h. ` +
|
|
397
|
+
`Add upgrades/side-effects/<slug>.md for this change (produced via the /instar-dev skill) — ` +
|
|
398
|
+
`do NOT create a version-named file to satisfy this check. ` +
|
|
386
399
|
`See skills/instar-dev/SKILL.md and docs/signal-vs-authority.md.`
|
|
387
400
|
);
|
|
388
401
|
}
|
|
@@ -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-27T20:30:23.365Z",
|
|
5
|
+
"instarVersion": "1.3.1013",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
|
|
6
6
|
## What Changed
|
|
7
7
|
|
|
8
|
+
Corrects the `rollout-evidence-ref` in `docs/specs/mutual-ssh-autobootstrap.md`. It named
|
|
9
|
+
`/multi-machine/mutual-ssh` — a path with no route anywhere in `src/`. The rollout has been marked
|
|
10
|
+
active and unmeasurable since the feature merged on 2026-07-21.
|
|
11
|
+
|
|
12
|
+
The readout was never missing. It is `GET /machines/ssh-health`, wired the whole time, and it
|
|
13
|
+
returns real data right now. The spec simply named the wrong address.
|
|
14
|
+
|
|
15
|
+
Spec frontmatter only. No runtime surface, no route added, no behaviour change.
|
|
16
|
+
|
|
8
17
|
Memory recall now retrieves semantically. Keyword matching becomes the fallback it was always
|
|
9
18
|
meant to be.
|
|
10
19
|
|
|
@@ -41,6 +50,16 @@ the fallback.
|
|
|
41
50
|
|
|
42
51
|
## What to Tell Your User
|
|
43
52
|
|
|
53
|
+
Some features are released carefully: switched on quietly first, and only turned up once there is
|
|
54
|
+
evidence they work. Each one's plan names the readout you check to see that evidence.
|
|
55
|
+
|
|
56
|
+
This feature's plan named a readout that does not exist — so there was no way to tell whether it was
|
|
57
|
+
working, and it would have sat in its cautious first stage forever. The readout it should have named
|
|
58
|
+
does exist and has all along.
|
|
59
|
+
|
|
60
|
+
Nothing about the feature changed. What changed is that its progress can now be read, and right now
|
|
61
|
+
it honestly reports that it is not ready yet — which is a much better answer than silence.
|
|
62
|
+
|
|
44
63
|
Your agent has two ways to search its own memory: one that matches on meaning, and one that
|
|
45
64
|
matches on words. The good one was built, fully switched on, and never called.
|
|
46
65
|
|
|
@@ -62,6 +81,9 @@ lookup, quietly, and everything after is fast.
|
|
|
62
81
|
|
|
63
82
|
## Summary of New Capabilities
|
|
64
83
|
|
|
84
|
+
- The mutual-SSH feature's graduation evidence is readable at `GET /machines/ssh-health` instead of
|
|
85
|
+
pointing at a path that returns nothing.
|
|
86
|
+
|
|
65
87
|
- Memory recall retrieves by meaning rather than keyword, using the embedding index that was
|
|
66
88
|
already built and populated but never called.
|
|
67
89
|
- Each recall reports which strategy served it, so running on the keyword fallback is
|
|
@@ -73,6 +95,26 @@ lookup, quietly, and everything after is fast.
|
|
|
73
95
|
|
|
74
96
|
## Evidence
|
|
75
97
|
|
|
98
|
+
Both paths probed live against the running server:
|
|
99
|
+
|
|
100
|
+
| path | result |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `/multi-machine/mutual-ssh` (the ref as written) | **404** |
|
|
103
|
+
| `/machines/ssh-health` (the real readout) | **200** — `enrollmentState: ssh-bootstrap-blocked`, `pairs[0].mutual: false`, `standingKeyInstalled: false` |
|
|
104
|
+
|
|
105
|
+
So the graduation criterion — at least one peer pair with bidirectional readiness proof and no
|
|
106
|
+
blocking reason — is now evaluable, and currently, correctly, **not met**. Before this change,
|
|
107
|
+
"not met" and "not measurable" were the same 404.
|
|
108
|
+
|
|
109
|
+
The route is served from `src/server/routes.ts` (`router.get('/machines/ssh-health')`) reading
|
|
110
|
+
`MutualSshRuntime.status()`, so the corrected ref also satisfies the rollout-evidence lint.
|
|
111
|
+
|
|
112
|
+
**A correction to my own earlier diagnosis, recorded because it is the more useful finding.** I
|
|
113
|
+
first read the 404 and concluded the endpoint had never landed with the feature, and filed an action
|
|
114
|
+
to build it. It had landed, under a different name. Concluding absence from a single lookup, without
|
|
115
|
+
checking whether the thing exists elsewhere, is the same error this whole sweep is about — and I
|
|
116
|
+
made it while running the sweep.
|
|
117
|
+
|
|
76
118
|
New tests run against **unmodified source first**:
|
|
77
119
|
|
|
78
120
|
| run | result |
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Fixes the pre-push gate's side-effects-artifact check, which refused **every push from a clean
|
|
9
|
+
post-release tree** and named an impossible remedy when it did.
|
|
10
|
+
|
|
11
|
+
After a release cut there are no in-flight release-note fragments, so the check fell back to
|
|
12
|
+
`upgrades/<version>.md` — the guide for the version that already shipped — and demanded
|
|
13
|
+
`upgrades/side-effects/<version>.md`. Side-effects artifacts are named per change slug; the release
|
|
14
|
+
flow has never produced a version-named one, so the demand could not be satisfied.
|
|
15
|
+
|
|
16
|
+
The check is now scoped to the notes the push is actually shipping. With no notes in flight there is
|
|
17
|
+
nothing to check and it stays silent. With notes in flight it fires exactly as before.
|
|
18
|
+
|
|
19
|
+
## What to Tell Your User
|
|
20
|
+
|
|
21
|
+
None — internal change (no user-facing surface).
|
|
22
|
+
|
|
23
|
+
## Summary of New Capabilities
|
|
24
|
+
|
|
25
|
+
None — internal change (no user-facing surface).
|
|
26
|
+
|
|
27
|
+
## Evidence
|
|
28
|
+
|
|
29
|
+
**Three observed recurrences, self-documented in the repo.** `upgrades/side-effects/1.3.492.md` and
|
|
30
|
+
`1.3.802.md` are hand-written placeholders whose own text says they exist only to satisfy this
|
|
31
|
+
check; the second calls itself "its second observed recurrence". Today (v1.3.1009) was the third,
|
|
32
|
+
and it refused a sibling branch before diagnosis.
|
|
33
|
+
|
|
34
|
+
Both placeholders claim the gap "remains logged in the framework-issues ledger under dedupKey
|
|
35
|
+
`pre-push-gate-versioned-artifact-fallback`". It is not. Queried four ways — unfiltered,
|
|
36
|
+
`?status=fixed`, `?bucket=instar-integration-gap`, `?framework=instar` — the ledger holds 163 issues
|
|
37
|
+
and zero matches, with no dedupKey containing `release`, `artifact`, or `push`. Declared tracked,
|
|
38
|
+
never tracked, recurred. It is registered for real with this change.
|
|
39
|
+
|
|
40
|
+
**Verified by reverting, because a passing test proves nothing:**
|
|
41
|
+
|
|
42
|
+
| gate | result |
|
|
43
|
+
|---|---|
|
|
44
|
+
| OLD code, new tests | **3 failed** \| 16 passed (19) |
|
|
45
|
+
| NEW code | **19 passed** (19) |
|
|
46
|
+
|
|
47
|
+
Plus a live run against the real repo in its actual post-cut state: errors before, warnings only
|
|
48
|
+
after.
|
|
49
|
+
|
|
50
|
+
**Nothing is weakened, and this was the load-bearing question.** Per-change enforcement still lives
|
|
51
|
+
in the pre-COMMIT gate (which refuses in-scope staged files lacking an ELI16 + side-effects artifact,
|
|
52
|
+
and blocked this very change twice while it was being written); check 3b still refuses a
|
|
53
|
+
release-relevant push with no fragment; and check 5 still fires when in-flight notes claim a fix with
|
|
54
|
+
no fresh artifact — asserted by a dedicated negative-control test, since the easy mistake here is
|
|
55
|
+
trading a false positive for a false negative.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Side-effects review — mutual-ssh rollout-evidence-ref correction
|
|
2
|
+
|
|
3
|
+
**Change:** one frontmatter line in `docs/specs/mutual-ssh-autobootstrap.md` —
|
|
4
|
+
`rollout-evidence-ref: /multi-machine/mutual-ssh` → `/machines/ssh-health`.
|
|
5
|
+
|
|
6
|
+
**Tier:** 0–1. Spec frontmatter only. No `src/` surface, no route, no config key, no persisted
|
|
7
|
+
state, no migration. Rollback is reverting one line.
|
|
8
|
+
|
|
9
|
+
## What reads this field
|
|
10
|
+
|
|
11
|
+
`scripts/lint-rollout-evidence-resolvable.js` (string-matches the ref against `src/`) and any
|
|
12
|
+
future rollout-graduation reader. Nothing at runtime dereferences it — the field is documentation
|
|
13
|
+
of where a human or a check should look, so a wrong value cannot cause a runtime fault. Its failure
|
|
14
|
+
mode is exactly what happened: silence.
|
|
15
|
+
|
|
16
|
+
## Blast radius
|
|
17
|
+
|
|
18
|
+
None at runtime. The one behavioural consequence is intended and desirable: the mutual-ssh rollout
|
|
19
|
+
becomes *measurable*, and the first honest measurement says **not ready** (`enrollmentState:
|
|
20
|
+
ssh-bootstrap-blocked`, `pairs[0].mutual: false`). A feature that previously could not be assessed
|
|
21
|
+
now reports a negative. That is the point; it is not a regression.
|
|
22
|
+
|
|
23
|
+
## Why not build `/multi-machine/mutual-ssh` instead
|
|
24
|
+
|
|
25
|
+
That was the first plan, and it was wrong. Adding an alias route to satisfy a spec that named a
|
|
26
|
+
non-existent path would have created a second address for one readout — two places to look, two
|
|
27
|
+
things to keep in sync, and a permanent invitation to the same confusion. The spec was wrong; the
|
|
28
|
+
spec was corrected.
|
|
29
|
+
|
|
30
|
+
## Verification
|
|
31
|
+
|
|
32
|
+
- `curl /multi-machine/mutual-ssh` → 404 (before and after — nothing was added).
|
|
33
|
+
- `curl /machines/ssh-health` → 200 with live pair state.
|
|
34
|
+
- `node scripts/lint-rollout-evidence-resolvable.js` → the corrected ref resolves.
|
|
35
|
+
|
|
36
|
+
## Rollback
|
|
37
|
+
|
|
38
|
+
`git revert` the one-line commit. The rollout returns to being unmeasurable, which is the state it
|
|
39
|
+
has been in since 2026-07-21.
|
|
40
|
+
|
|
41
|
+
## Known limitation, stated rather than hidden
|
|
42
|
+
|
|
43
|
+
The lint that guards this field is a **string match against `src/`**. A route that is written but
|
|
44
|
+
never mounted would still satisfy it. That limitation is documented in the lint's own header; the
|
|
45
|
+
live probe above is what actually establishes that this particular ref resolves.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Side-effects review — pre-push gate stops validating the frozen versioned guide
|
|
2
|
+
|
|
3
|
+
**Change:** `scripts/pre-push-gate.js` check 5 (side-effects-artifact requirement) is scoped to
|
|
4
|
+
in-flight release notes. It no longer falls back to `upgrades/<version>.md` — the guide for the
|
|
5
|
+
version that already shipped.
|
|
6
|
+
|
|
7
|
+
**Tier:** 1. One local developer gate. No `src/` surface, no route, no config, no persisted state,
|
|
8
|
+
no migration. Not run in CI (`if (!process.env.CI)`), so it cannot change what merges — only what a
|
|
9
|
+
developer can push from their own machine.
|
|
10
|
+
|
|
11
|
+
## The defect, with its recurrence record
|
|
12
|
+
|
|
13
|
+
Post-release-cut the tree has `upgrades/<version>.md` (frozen), no fragments, and no
|
|
14
|
+
`upgrades/side-effects/<version>.md`. That last file is one the release flow never creates: artifacts
|
|
15
|
+
are named per change slug. The fallback demanded it anyway, so **every push from a clean
|
|
16
|
+
post-release tree was refused**.
|
|
17
|
+
|
|
18
|
+
Three observed recurrences, all self-documented in the repo:
|
|
19
|
+
|
|
20
|
+
| version | evidence |
|
|
21
|
+
|---|---|
|
|
22
|
+
| v1.3.492 | `upgrades/side-effects/1.3.492.md` — a hand-written placeholder that says so |
|
|
23
|
+
| v1.3.802 | `upgrades/side-effects/1.3.802.md` — same, and calls itself "its second observed recurrence" |
|
|
24
|
+
| v1.3.1009 | today; refused this branch's sibling PR before diagnosis |
|
|
25
|
+
|
|
26
|
+
Both placeholders state the gap "remains logged in the framework-issues ledger under dedupKey
|
|
27
|
+
`pre-push-gate-versioned-artifact-fallback`". **It is not.** Queried four ways
|
|
28
|
+
(`GET /framework-issues` unfiltered, `?status=fixed`, `?bucket=instar-integration-gap`,
|
|
29
|
+
`?framework=instar`): 163 issues, zero matches, and no dedupKey in the store containing `release`,
|
|
30
|
+
`artifact`, or `push`. The tracking claim was hollow, which is why it recurred a third time. The
|
|
31
|
+
issue is registered for real as part of this change.
|
|
32
|
+
|
|
33
|
+
## What is NOT weakened — the load-bearing question
|
|
34
|
+
|
|
35
|
+
Removing a check is the risky half of this. Three separate enforcement points remain:
|
|
36
|
+
|
|
37
|
+
1. **`scripts/instar-dev-precommit.js` — untouched.** This is the real per-change enforcement: it
|
|
38
|
+
refuses a COMMIT whose in-scope staged files lack an ELI16 doc and a side-effects artifact, and
|
|
39
|
+
it verifies the artifact's sha against the decision trace. It blocked this very change twice
|
|
40
|
+
while it was being written.
|
|
41
|
+
2. **Check 3b — untouched.** A push with release-relevant files and no fragment is still refused,
|
|
42
|
+
with an actionable remedy (`add upgrades/next/<slug>.md`).
|
|
43
|
+
3. **Check 5 itself — still fires, scoped.** With in-flight notes claiming a fix and no fresh
|
|
44
|
+
artifact, it refuses exactly as before. Test:
|
|
45
|
+
`STILL refuses an in-flight fix-claiming fragment with no fresh side-effects artifact`.
|
|
46
|
+
|
|
47
|
+
The narrowed case — "no in-flight notes, frozen guide claims a fix, no version-named artifact" — was
|
|
48
|
+
never a real signal. It fired on a release that had already shipped and already been reviewed.
|
|
49
|
+
|
|
50
|
+
## Blast radius
|
|
51
|
+
|
|
52
|
+
A developer can now push from a clean post-release tree without hand-writing a placeholder. That is
|
|
53
|
+
the entire behavioural change. Nothing in CI, publishing, or runtime reads this script.
|
|
54
|
+
|
|
55
|
+
**Residual risk:** if the release process ever DID start producing version-named artifacts and
|
|
56
|
+
someone relied on this check to enforce that, this would silently stop enforcing it. Judged
|
|
57
|
+
acceptable: no such producer exists, and the 37 version-named artifacts already in the repo are
|
|
58
|
+
release rollups and placeholders, not a maintained convention.
|
|
59
|
+
|
|
60
|
+
## Verification
|
|
61
|
+
|
|
62
|
+
Verified by REVERTING, because a passing test proves nothing:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
against the OLD gate: 3 failed | 16 passed (19)
|
|
66
|
+
× ACCEPTS a post-release-cut tree with no fragment and no version-named artifact
|
|
67
|
+
× does not demand a version-named side-effects artifact even when one has never existed
|
|
68
|
+
× STILL refuses an in-flight fix-claiming fragment with no fresh side-effects artifact
|
|
69
|
+
against the NEW gate: 19 passed (19)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Plus a live run against the real repo in its actual post-cut state (v1.3.1009, no fragments): errors
|
|
73
|
+
before, warnings only after.
|
|
74
|
+
|
|
75
|
+
## Rollback
|
|
76
|
+
|
|
77
|
+
`git revert`. The gate returns to refusing every clean post-release push, and the next person writes
|
|
78
|
+
`upgrades/side-effects/<version>.md` by hand for the fourth time.
|