instar 1.3.1012 → 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
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": {
|
|
@@ -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,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.
|