instar 1.2.42 → 1.2.43
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
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// safe-git-allow: pre-commit-bootstrap — read-only `git diff --cached` to scan staged file list; runs before TS compile so cannot use SafeGitExecutor funnel.
|
|
3
|
+
/**
|
|
4
|
+
* E2E-pairing gate — pre-commit check.
|
|
5
|
+
*
|
|
6
|
+
* Cherry-pick from the GSD-Instar integration spike. The spike's Tier-3
|
|
7
|
+
* "feature is alive" finding: features that ship with API routes but no
|
|
8
|
+
* E2E lifecycle test silently return 503 in production. CLAUDE.md calls
|
|
9
|
+
* the Tier-3 test "the single most important test for any feature with
|
|
10
|
+
* API routes" — but nothing structurally enforced its presence.
|
|
11
|
+
*
|
|
12
|
+
* This gate: if a commit stages a non-test `src/server/*.ts` file, it must
|
|
13
|
+
* also stage at least one `tests/e2e/*.test.ts` file. Otherwise the commit
|
|
14
|
+
* is blocked with a remediation message.
|
|
15
|
+
*
|
|
16
|
+
* This is a SIGNAL with commit-time authority — it errs toward false
|
|
17
|
+
* positives (a server refactor that genuinely needs no new e2e test is
|
|
18
|
+
* rarer than a feature shipped without one). Two escape hatches keep it
|
|
19
|
+
* from being tyrannical:
|
|
20
|
+
* 1. Env bypass: INSTAR_SKIP_E2E_PAIRING=1 git commit ...
|
|
21
|
+
* 2. Marker: include "E2E-PAIRING: EXEMPT — <reason>" in any staged
|
|
22
|
+
* server file (for genuine refactors / type-only / comment changes).
|
|
23
|
+
*
|
|
24
|
+
* Exit codes:
|
|
25
|
+
* 0 — pass (no server change, or e2e test paired, or exempt)
|
|
26
|
+
* 1 — block (server change with no paired e2e test and no exemption)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const { execSync } = require('node:child_process');
|
|
30
|
+
|
|
31
|
+
if (process.env.INSTAR_SKIP_E2E_PAIRING === '1') {
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function stagedFiles() {
|
|
36
|
+
try {
|
|
37
|
+
const out = execSync('git diff --cached --name-only --diff-filter=ACMR', { encoding: 'utf-8' });
|
|
38
|
+
return out.split('\n').map(s => s.trim()).filter(Boolean);
|
|
39
|
+
} catch {
|
|
40
|
+
// If we can't read the index, don't block the commit.
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function stagedContent(file) {
|
|
46
|
+
try {
|
|
47
|
+
return execSync(`git show :${file}`, { encoding: 'utf-8' });
|
|
48
|
+
} catch {
|
|
49
|
+
return '';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const files = stagedFiles();
|
|
54
|
+
|
|
55
|
+
// Server source files (excluding tests + type-declaration files).
|
|
56
|
+
const serverChanges = files.filter(f =>
|
|
57
|
+
/^src\/server\/.*\.ts$/.test(f) &&
|
|
58
|
+
!/\.test\.ts$/.test(f) &&
|
|
59
|
+
!/\.d\.ts$/.test(f)
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (serverChanges.length === 0) {
|
|
63
|
+
process.exit(0); // No server change — nothing to enforce.
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Paired E2E test staged in the same commit?
|
|
67
|
+
const hasE2e = files.some(f => /^tests\/e2e\/.*\.test\.ts$/.test(f));
|
|
68
|
+
if (hasE2e) {
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Exemption marker in any staged server file?
|
|
73
|
+
const exemptMarker = /E2E-PAIRING:\s*EXEMPT\s*[—-]/;
|
|
74
|
+
for (const f of serverChanges) {
|
|
75
|
+
if (exemptMarker.test(stagedContent(f))) {
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Block.
|
|
81
|
+
console.error('');
|
|
82
|
+
console.error('╔════════════════════════════════════════════════════════════════════╗');
|
|
83
|
+
console.error('║ E2E-PAIRING GATE — server change without a paired E2E test ║');
|
|
84
|
+
console.error('╚════════════════════════════════════════════════════════════════════╝');
|
|
85
|
+
console.error('');
|
|
86
|
+
console.error(' Staged server source files:');
|
|
87
|
+
for (const f of serverChanges) console.error(` ${f}`);
|
|
88
|
+
console.error('');
|
|
89
|
+
console.error(' No tests/e2e/*.test.ts file is staged in this commit.');
|
|
90
|
+
console.error('');
|
|
91
|
+
console.error(' CLAUDE.md: the Tier-3 "feature is alive" E2E test is the single most');
|
|
92
|
+
console.error(' important test for any feature with API routes. Features that ship');
|
|
93
|
+
console.error(' with routes but no E2E lifecycle test silently return 503 in prod.');
|
|
94
|
+
console.error('');
|
|
95
|
+
console.error(' Fix one of:');
|
|
96
|
+
console.error(' 1. Add/modify a tests/e2e/*.test.ts that boots the real server path');
|
|
97
|
+
console.error(' and hits the route, then stage it.');
|
|
98
|
+
console.error(' 2. Genuine refactor / type-only / comment change? Add a comment');
|
|
99
|
+
console.error(' "E2E-PAIRING: EXEMPT — <reason>" to a staged server file.');
|
|
100
|
+
console.error(' 3. One-off bypass: INSTAR_SKIP_E2E_PAIRING=1 git commit ...');
|
|
101
|
+
console.error('');
|
|
102
|
+
process.exit(1);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-05-23T03:
|
|
5
|
-
"instarVersion": "1.2.
|
|
4
|
+
"generatedAt": "2026-05-23T03:49:24.867Z",
|
|
5
|
+
"instarVersion": "1.2.43",
|
|
6
6
|
"entryCount": 191,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**feat(dev): e2e-pairing pre-commit gate — GSD cherry-pick.**
|
|
8
|
+
|
|
9
|
+
New pre-commit gate (`scripts/check-e2e-pairing.cjs`, wired into `.husky/pre-commit`) that blocks any commit changing a non-test `src/server/*.ts` file unless it also stages at least one `tests/e2e/*.test.ts`. Structurally enforces the Tier-3 "feature is alive" discipline that CLAUDE.md calls the single most important test for any feature with API routes.
|
|
10
|
+
|
|
11
|
+
From the GSD-Instar spike, where the gsd-planner methodology surfaced that the Topic Intent Layer's Tier-3 lifecycle test would have been forgotten under ad-hoc planning. This gate makes "ship a route without an e2e test" structurally hard rather than discipline-dependent.
|
|
12
|
+
|
|
13
|
+
Two escape hatches keep it from being tyrannical: env bypass (`INSTAR_SKIP_E2E_PAIRING=1`) and an `E2E-PAIRING: EXEMPT — <reason>` marker in a staged server file (for genuine refactors / type-only / comment changes).
|
|
14
|
+
|
|
15
|
+
This governs instar's OWN development commits (it's in instar's `.husky/`), not agent-installed files — so no migration parity needed.
|
|
16
|
+
|
|
17
|
+
## Evidence
|
|
18
|
+
|
|
19
|
+
8 unit tests, all green (tmp-git-repo harness): passes with no server files, blocks server-without-e2e, passes server-with-e2e, ignores server test files + .d.ts, respects env bypass + EXEMPT marker, blocks when only an unrelated unit test is staged. TypeScript clean.
|
|
20
|
+
|
|
21
|
+
Verified the gate does not block this very PR (this PR changes scripts/ + .husky/ + tests/, not src/server/).
|
|
22
|
+
|
|
23
|
+
Side-effects review: `upgrades/side-effects/e2e-pairing-gate.md`.
|
|
24
|
+
|
|
25
|
+
## What to Tell Your User
|
|
26
|
+
|
|
27
|
+
Nothing user-visible. Internal dev-discipline gate for instar contributors.
|
|
28
|
+
|
|
29
|
+
## Summary of New Capabilities
|
|
30
|
+
|
|
31
|
+
One new pre-commit gate script + one line in .husky/pre-commit. Signal-with-commit-authority (blocks), with two escape hatches. Errs toward false positives because a route shipped without an e2e test is the corruption-class failure being defended against.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Side-Effects Review — E2E-Pairing Pre-Commit Gate
|
|
2
|
+
|
|
3
|
+
**Source:** Cherry-pick from GSD-Instar spike (Tier-3 "feature is alive" finding)
|
|
4
|
+
**Author:** Echo · autonomous run · 2026-05-23
|
|
5
|
+
|
|
6
|
+
## 1. Over-block
|
|
7
|
+
Could block legitimate server refactors / type-only changes that genuinely need no new e2e test. Mitigations: (a) `E2E-PAIRING: EXEMPT — <reason>` marker, (b) `INSTAR_SKIP_E2E_PAIRING=1` env bypass. Both are documented in the block message itself.
|
|
8
|
+
|
|
9
|
+
## 2. Under-block
|
|
10
|
+
Could pass a commit that stages a trivial/empty e2e test just to satisfy the gate. Accepted: the gate enforces PRESENCE, not quality. Quality is the reviewer's job + the existing CI E2E run. Presence-enforcement alone closes the "forgot the e2e test entirely" gap, which is the actual failure mode.
|
|
11
|
+
|
|
12
|
+
## 3. Level-of-abstraction fit
|
|
13
|
+
Pre-commit gate alongside check-rule3-coverage.cjs, protect-migration-guarantee.js, instar-dev-precommit.js. Same layer (instar dev discipline), same .husky/pre-commit wiring, same read-only-staged-diff pattern.
|
|
14
|
+
|
|
15
|
+
## 4. Signal-vs-authority compliance
|
|
16
|
+
This is a SIGNAL with commit-time authority (it blocks). Per signal-vs-authority: brittle low-context filters should only block when the defended-against failure is corruption-class and the false-positive cost is low. A route shipped without an e2e test silently 503s in prod (corruption-class); the false-positive cost is one comment marker or one env var (low). The two escape hatches keep the human/agent as the final authority. Compliant.
|
|
17
|
+
|
|
18
|
+
## 5. Cross-feature interactions
|
|
19
|
+
- Runs last in .husky/pre-commit, after lint + instar-dev-precommit + rule3 + migration-guarantee. Independent — reads staged diff, no shared state.
|
|
20
|
+
- Does not interact with CI (CI runs the actual E2E suite; this gate just enforces a test FILE is staged).
|
|
21
|
+
- Edge: a commit that splits a feature across two commits (server in commit 1, e2e test in commit 2) would block commit 1. Mitigation: the EXEMPT marker or env bypass for the intermediate commit; or stage both together. This is a deliberate nudge toward atomic feature commits.
|
|
22
|
+
|
|
23
|
+
## 6. Rollback cost
|
|
24
|
+
Trivial. One script + one line in .husky/pre-commit + one test file. Revert the commit; the gate stops running.
|
|
25
|
+
|
|
26
|
+
## 7. Migration parity
|
|
27
|
+
N/A — this is an instar-dev-repo gate (`.husky/pre-commit`), NOT an agent-installed file. It ships with the source repo and governs instar contributors' commits. Agents never receive `.husky/` hooks. No PostUpdateMigrator entry needed.
|
|
28
|
+
|
|
29
|
+
## Conclusion
|
|
30
|
+
Ship. Structurally enforces the Tier-3 discipline the spike identified as most-forgotten. Two escape hatches prevent tyranny. Trivial rollback. Seven-dimension review clean.
|