instar 0.28.49 → 0.28.50

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.
@@ -0,0 +1,104 @@
1
+ # Side-Effects Review — pre-push gate: CI scope fix
2
+
3
+ **Version / slug:** `pre-push-gate-ci-scope`
4
+ **Date:** `2026-04-17`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ Modifies `scripts/pre-push-gate.js` in two ways: (1) wraps section 5 (side-effects artifact check) in `if (!process.env.CI)`, so the check runs only when developers push locally and is skipped in GitHub Actions; (2) adds `2>/dev/null` to the `HEAD~1` stderr fallback in section 3's git diff command, stopping stderr from leaking through the try/catch into the test output in shallow-clone CI environments. No `src/` files are touched — only the gate script itself.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `scripts/pre-push-gate.js` section 5 — **modify** — narrows the scope of the side-effects artifact check from "always" to "not in CI". The check itself is unchanged; only its execution context is restricted.
15
+ - `scripts/pre-push-gate.js` section 3 — **modify** — cosmetic: suppresses stderr noise from a git fallback command. No decision logic involved.
16
+
17
+ ---
18
+
19
+ ## 1. Over-block
20
+
21
+ No block/allow surface for messages or agent actions — not applicable in the traditional sense.
22
+
23
+ Within the gate's own domain: the change *reduces* over-block. Previously the gate would reject any CI run on a contributor branch that was cut before the side-effects artifact for the current version was added to main. That's a false positive — the contributor didn't violate the process, the artifact simply hadn't been added to main yet when they branched. The fix stops those legitimate branches from being blocked.
24
+
25
+ No new rejection surface is introduced.
26
+
27
+ ---
28
+
29
+ ## 2. Under-block
30
+
31
+ The gate now allows CI runs that are missing the side-effects artifact. This is an intentional scope reduction: CI is not the enforcement point. The enforcement points are:
32
+
33
+ 1. The pre-commit hook (`scripts/instar-dev-precommit.js`) — runs per-commit on the developer's machine.
34
+ 2. The pre-push hook (this gate, section 5) — runs on the developer's machine at push time.
35
+
36
+ Both hooks run before code reaches CI. If a developer bypasses them (e.g., `--no-verify`), section 5 in CI would have caught it — and now it won't. This is a real reduction in defense depth for the `--no-verify` bypass case.
37
+
38
+ Mitigation: `--no-verify` bypasses are visible in git history (the commit won't have the artifact). The pre-push gate also re-checks at the release-cut step when NEXT.md is renamed to a versioned file — which does happen locally, not in CI. The net under-block exposure is: a developer who uses `--no-verify` and then somehow gets their branch merged without a local push. This is a narrow path that the review process (PR review, merge gating) is expected to catch.
39
+
40
+ ---
41
+
42
+ ## 3. Level-of-abstraction fit
43
+
44
+ The gate is a structural process-enforcement check, not a message-content gate. Section 5 is explicitly scoped to "push time" in its own comment. CI is not push time — it's post-push. Running a push-time check in CI creates a category mismatch that produces false failures on valid contributor branches.
45
+
46
+ The fix is at the correct layer: the `if (!process.env.CI)` guard is a simple execution-context discriminator applied directly to the check that's miscategorized for CI. No rearchitecting needed.
47
+
48
+ ---
49
+
50
+ ## 4. Signal vs authority compliance
51
+
52
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
53
+
54
+ **Does this change hold blocking authority with brittle logic?**
55
+
56
+ - [x] No — this change has no block/allow surface.
57
+
58
+ The gate operates on developer process compliance (file existence, git metadata), not on message content or agent behavior. The signal-vs-authority principle applies to decision points that evaluate messages or constrain agent information flow. A CI scope guard on a developer process check is outside that domain.
59
+
60
+ The change itself is a pure scope restriction — it *removes* an execution context from an existing check. No new brittle logic is added. No new authority is claimed.
61
+
62
+ ---
63
+
64
+ ## 5. Interactions
65
+
66
+ **Shadowing:** The pre-commit hook and the local pre-push hook both enforce section 5's requirement. This change scopes section 5 to local-only. The pre-commit hook is unchanged — it still runs on every commit. No shadowing occurs.
67
+
68
+ **Double-fire:** Section 5 currently runs both locally (pre-push) and in CI (via the test that invokes the gate script). After this change it only runs locally. No double-fire; in fact we're eliminating the accidental double-enforcement.
69
+
70
+ **Races:** No shared state involved. The check reads filesystem files (upgrade guides, side-effects dir). No concurrent access concern.
71
+
72
+ **Feedback loops:** None. The gate is a one-way exit check with no input to any system that feeds back.
73
+
74
+ ---
75
+
76
+ ## 6. External surfaces
77
+
78
+ - **Other agents:** No effect. The gate runs only in the instar repo's CI and in developer environments.
79
+ - **Install base users:** No effect. This is a developer tooling change, not a runtime change. `instar` as installed by users has no pre-push gate.
80
+ - **External systems:** No effect.
81
+ - **Persistent state:** No effect.
82
+ - **Timing/runtime:** The `CI` env var is set by GitHub Actions automatically for all runs. No timing dependency — it's present or absent at process start.
83
+
84
+ ---
85
+
86
+ ## 7. Rollback cost
87
+
88
+ Pure code change in `scripts/pre-push-gate.js`. Revert and ship a patch. No persistent state, no migration, no agent state repair. The only user-visible effect during the rollback window would be contributor PR CI runs again failing on missing side-effects artifacts — which is the exact condition we're fixing, not a new regression.
89
+
90
+ ---
91
+
92
+ ## Conclusion
93
+
94
+ The change is narrow and correct. It scopes section 5 of the pre-push gate to local developer contexts only, which matches the intent stated in the gate's own comment ("at push time"). The under-block exposure (a developer using `--no-verify` evading CI detection) is real but narrow: it requires bypassing two local enforcement hooks AND getting a PR merged without review catching the missing artifact. The pre-commit hook and PR review process are the remaining guards. The fix is clear to ship.
95
+
96
+ No design changes were made as a result of the review.
97
+
98
+ ---
99
+
100
+ ## Evidence pointers
101
+
102
+ - `tests/unit/pre-push-gate.test.ts` — all 6 tests pass locally after the change.
103
+ - `CI=true node scripts/pre-push-gate.js` — exits 0 on the current branch (which has the 0.28.49 versioned guide with fix/feature language but no fresh side-effects artifact for that version in CI context).
104
+ - Without `CI`, the gate still enforces section 5 (verified by the existing passing local test that runs the gate in a non-CI shell).
@@ -0,0 +1,104 @@
1
+ # Side-Effects Review — default skills: dynamic localhost port
2
+
3
+ **Version / slug:** `skill-port-dynamic-resolution`
4
+ **Date:** `2026-04-17`
5
+ **Author:** `dawn`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ Two source changes. In `src/commands/init.ts`, every `http://localhost:${port}/...` URL inside `installBuiltinSkills` (and adjacent helpers that share the same file) is rewritten to emit `http://localhost:\${INSTAR_PORT:-${port}}/...`, so the generated `.claude/skills/*/SKILL.md` files contain a shell-expandable port reference instead of a number baked in at install time. In `src/core/PostUpdateMigrator.ts`, a new `migrateSkillPortHardcoding()` scans existing default-skill files for bare `http://localhost:NNNN/` URLs and rewrites them to `http://localhost:${INSTAR_PORT:-NNNN}/`, preserving the original port as the fallback default. The migration is scoped to the 14 known-default skill names and is idempotent. Test coverage: `tests/unit/PostUpdateMigrator-skillPortHardcoding.test.ts` — 6 cases.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `src/commands/init.ts` `installBuiltinSkills` — **modify** — replaces hardcoded port templating with runtime-expandable pattern. 93 occurrences, mechanical find/replace, all inside backtick template strings for shell-executed content.
15
+ - `src/core/PostUpdateMigrator.ts` `migrateSkillPortHardcoding` — **add** — new migration method. Called from `migrate()` between `migrateBuiltinSkills` and `migrateSelfKnowledgeTree`. Scoped to a fixed allowlist of 14 default skill names.
16
+ - `tests/unit/PostUpdateMigrator-skillPortHardcoding.test.ts` — **add** — regression coverage for the migration.
17
+
18
+ ---
19
+
20
+ ## 1. Over-block
21
+
22
+ No block/allow surface. The change is runtime port resolution in user-project skill files. No message content or agent action is gated.
23
+
24
+ Within the migration's own domain: the scan matches `/http:\/\/localhost:(\d+)\//g` in the default-skill set. This pattern is narrow enough that it will not false-positive on natural-language references ("localhost:4040" mentioned in prose without the URL form is untouched). Files outside the 14-name allowlist are never read, so custom skills are never modified — a principle the test suite asserts explicitly.
25
+
26
+ ---
27
+
28
+ ## 2. Under-block
29
+
30
+ No block surface existed before this change. The migration adds no new enforcement — it is a one-way content rewrite. There is nothing to under-block.
31
+
32
+ Edge case: if a user had a default-skill file with a mix of the new dynamic pattern and stray hardcoded ports (e.g., partial manual edits), the idempotency guard (`includes('${INSTAR_PORT:-')`) will cause the migration to skip the file entirely rather than finish the rewrite. That is the safe direction — migrating a partially-edited file risks corrupting the user's edits. Users in that state can manually finish the rewrite or delete the file and let `installBuiltinSkills` regenerate it.
33
+
34
+ ---
35
+
36
+ ## 3. Level-of-abstraction fit
37
+
38
+ The change is at the correct layer. The root cause was install-time templating of a value that should have been runtime-resolved. Fixing the template is the direct fix; fixing existing user files via migration is the correct catch-up mechanism. Neither change rearchitects the skill system — skills remain static markdown files, the only change is that a value inside them resolves later.
39
+
40
+ The dynamic pattern `${INSTAR_PORT:-PORT}` uses POSIX shell parameter expansion, the same primitive the rest of the Instar shell surface depends on. It is a recognized idiom inside curl-heavy bash content, not a novel construct the user has to learn.
41
+
42
+ ---
43
+
44
+ ## 4. Signal vs authority compliance
45
+
46
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
47
+
48
+ **Does this change hold blocking authority with brittle logic?**
49
+
50
+ - [x] No — this change has no block/allow surface.
51
+
52
+ The change is a content rewrite inside skill files. It does not evaluate messages, gate agent actions, or constrain information flow. Signal-vs-authority applies to decision points that judge messages or block work. A port-expansion template does neither.
53
+
54
+ ---
55
+
56
+ ## 5. Interactions
57
+
58
+ **Shadowing:** `installBuiltinSkills` and `migrateSkillPortHardcoding` target overlapping surface. Order matters: `migrateBuiltinSkills` runs first (non-destructive, writes only missing files), then `migrateSkillPortHardcoding` runs (rewrites existing files). A skill newly written by `installBuiltinSkills` in the same migration pass already uses the dynamic pattern, so `migrateSkillPortHardcoding` will see the `${INSTAR_PORT:-` marker and no-op. No double-processing.
59
+
60
+ **Double-fire:** `migrateSkillPortHardcoding` is idempotent — once a file contains the dynamic marker, it is skipped. Test case `is idempotent on a second run after migration` covers this explicitly.
61
+
62
+ **Races:** `PostUpdateMigrator.migrate()` is sequential and runs once per `instar` update. No concurrent access to the same skill file is expected. If two updaters ran simultaneously, they would both read the hardcoded content, both rewrite it, and the second write would overwrite the first with identical content — no corruption.
63
+
64
+ **Feedback loops:** None. The migration is a one-shot rewrite; the rewritten content does not feed back into any system.
65
+
66
+ ---
67
+
68
+ ## 6. External surfaces
69
+
70
+ - **Other agents:** Each agent running instar will get the migration on next `instar` upgrade. Agents on non-default ports gain working skills; agents on port 4040 see no behavioral change (the fallback matches their previous hardcoded value).
71
+ - **Install base users:** Users with customized skill files (renamed default skills, heavily edited content) are protected by the allowlist and the dynamic-marker idempotency check. The migration touches only the 14 canonical default-skill files, and only if they still contain the bare-port pattern.
72
+ - **External systems:** None. The URL targets are all `localhost` — no external traffic shape changes.
73
+ - **Persistent state:** Skill files on disk are rewritten in place. No database, no config, no registry is touched. Rollback = `git checkout` of the skill file or `rm` and re-run `installBuiltinSkills`.
74
+ - **Timing/runtime:** The `${INSTAR_PORT:-NNNN}` expansion runs at shell invocation time. An agent with `INSTAR_PORT` unset gets the fallback; with it set, gets the override. Zero-cost at skill-read time; one environment variable lookup per curl.
75
+
76
+ ---
77
+
78
+ ## 7. Rollback cost
79
+
80
+ Low. Revert: `git revert` the two source commits; the emitted skills would return to hardcoded ports, matching pre-fix behavior. Users who already ran the migration would keep their dynamic-pattern skills, which continue to work (the fallback equals the previous hardcoded value). No persistent state to undo, no agent state to repair, no user communication required.
81
+
82
+ Narrow risk: if a user's `INSTAR_PORT` env var is set to an invalid value (e.g., a port the server isn't listening on), curls will fail after this change where they would have succeeded before on the hardcoded default. Mitigation: the variable is only consulted if the user explicitly exported it. The intersection of "exported `INSTAR_PORT`" and "set it wrong" is small and self-inflicted; the fix for that case is `unset INSTAR_PORT` or set it correctly.
83
+
84
+ ---
85
+
86
+ ## Conclusion
87
+
88
+ The change is narrow, well-scoped, and covered by regression tests. The template fix is mechanical and safe. The migration is scoped to a known allowlist, idempotent, and respects user customizations. The under-block surface is zero; the over-block surface is zero. The worst case in rollback is a return to the original bug, which affected only users on non-default ports and is already worked around today by hand-sed. Ship.
89
+
90
+ No design changes were made as a result of the review.
91
+
92
+ ---
93
+
94
+ ## Evidence pointers
95
+
96
+ - `tests/unit/PostUpdateMigrator-skillPortHardcoding.test.ts` — 6 tests pass:
97
+ - rewrites hardcoded ports in a default skill
98
+ - leaves already-dynamic skills untouched (idempotent)
99
+ - does not touch custom (non-default) skills
100
+ - is idempotent on a second run after migration
101
+ - skips when the skill file does not exist
102
+ - preserves the original port number in the fallback
103
+ - Live template verification: `node -e "const {installBuiltinSkills}=require('./dist/commands/init.js'); ..."` against a temp dir shows 13 of 14 default skills emit `localhost:${INSTAR_PORT:-4040}` and zero emit bare `localhost:4040` (the 14th skill, `autonomous`, is a stub that deploys separately and has no localhost URLs).
104
+ - Source-side verification: `grep -c 'localhost:${port}' src/commands/init.ts` = 0 after the rewrite (was 93).