instar 1.3.424 → 1.3.426
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/dist/commands/init.js +5 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/core/ExternalOperationGate.js +1 -1
- package/dist/core/ExternalOperationGate.js.map +1 -1
- package/dist/core/InputGuard.js +1 -1
- package/dist/core/InputGuard.js.map +1 -1
- package/dist/core/IntelligenceRouter.d.ts +14 -0
- package/dist/core/IntelligenceRouter.d.ts.map +1 -1
- package/dist/core/IntelligenceRouter.js +55 -19
- package/dist/core/IntelligenceRouter.js.map +1 -1
- package/dist/core/IntentTestHarness.js +1 -1
- package/dist/core/IntentTestHarness.js.map +1 -1
- package/dist/core/MessageSentinel.js +1 -1
- package/dist/core/MessageSentinel.js.map +1 -1
- package/dist/core/MessagingToneGate.js +1 -1
- package/dist/core/MessagingToneGate.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +7 -1
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/types.d.ts +10 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +20 -20
- package/src/templates/hooks/dangerous-command-guard.sh +9 -2
- package/upgrades/1.3.425.md +23 -0
- package/upgrades/1.3.426.md +20 -0
- package/upgrades/eli16/provider-swap.md +33 -0
- package/upgrades/guard-forcepush-precise.eli16.md +29 -0
- package/upgrades/side-effects/guard-forcepush-precise.md +38 -0
- package/upgrades/side-effects/provider-swap.md +29 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Herd-Aware Provider-Swap — Plain-English Overview
|
|
2
|
+
|
|
3
|
+
> The one-line version: when a safety gate's AI is rate-limited, instead of giving up (and falling back to weak code), it tries your OTHER AI providers first — and only fails closed if every one is down.
|
|
4
|
+
|
|
5
|
+
## The problem in one breath
|
|
6
|
+
|
|
7
|
+
We just made the safety gates fail closed when their AI is down. That's safe, but it means more things pause for approval during a rate-limit. The better answer: don't fail at all if another AI provider is available — swap to it.
|
|
8
|
+
|
|
9
|
+
## What already exists
|
|
10
|
+
|
|
11
|
+
- **One shared AI router** that every gate and sentinel calls. It already routes different components to different AI frameworks (Claude, Codex, Pi) and gives each its own circuit breaker.
|
|
12
|
+
- **The fail-closed gates** (from the previous change) — on an AI failure they require approval / hold, rather than silently proceeding.
|
|
13
|
+
|
|
14
|
+
## What this adds
|
|
15
|
+
|
|
16
|
+
A **failure-swap** at that one router. When a SAFETY-GATING call's AI fails, the router walks a configured ordered list of fallback frameworks, **skips any whose circuit is already open** (so it never piles load onto a provider that's also struggling), and serves the answer from the first healthy one. Only if every provider is down does it fail closed.
|
|
17
|
+
|
|
18
|
+
## The new pieces
|
|
19
|
+
|
|
20
|
+
- **`failureSwap` config** — an ordered list of frameworks to try on a gating call's failure (e.g. Codex, then Pi). Default: empty = today's behavior, nothing changes unless you turn it on.
|
|
21
|
+
- **A `gating` flag** on the call — only safety-gating calls swap. This keeps the "herd" tiny: a rate-limited framework can't dump its whole load onto another, because only the few real gates swap (advisory calls keep degrading as before).
|
|
22
|
+
|
|
23
|
+
## The safeguards
|
|
24
|
+
|
|
25
|
+
**Prevents herding.** The original router deliberately didn't swap, to avoid a rate-limited framework dumping all its traffic onto the fallback at once. This keeps that protection two ways: only gating calls swap (small set), and any fallback whose circuit is already open is skipped instantly.
|
|
26
|
+
|
|
27
|
+
**Fail-closed is still the floor.** If every provider is down, the error re-throws and the gate fails closed — never a silent drop to weak code.
|
|
28
|
+
|
|
29
|
+
**Generalizes to all your providers.** Claude, Codex, Pi, and Copilot-via-Pi are each a separate account/quota, so the same model reachable through multiple paths is redundancy. Composes with the subscription-pool (which manages accounts within a provider).
|
|
30
|
+
|
|
31
|
+
## What ships when
|
|
32
|
+
|
|
33
|
+
This PR is the router swap + the gating flags on the five safety gates. Follow-ups: a model-family-diverse default order, the lint, the iterative re-audit to convergence, and the throwaway-agent test harness.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Guard force-with-lease check — scope it to the actual push command
|
|
2
|
+
|
|
3
|
+
> The one-line version: the safety hook that blocks force-pushes was reading the *whole* command line — including unrelated status text — so it sometimes blocked a perfectly safe branch update by mistake; now it reads only the `git push` part.
|
|
4
|
+
|
|
5
|
+
## The problem in one breath
|
|
6
|
+
|
|
7
|
+
Instar has a safety hook (`dangerous-command-guard`) that stops dangerous git commands. It deliberately *allows* one safe case: `git push --force-with-lease` to your own feature/PR branch (the normal way to update a rebased branch), while still blocking a force-push that targets a protected branch like `main`, `master`, `develop`, or anything starting with `release`. The trouble was *how* it decided "is this targeting a protected branch": it scanned the entire command string for those words. So if the command happened to contain unrelated text — for example a chained status message or log line that mentioned "release cadence" or "main menu" — the guard saw the word "release"/"main" and wrongly concluded you were force-pushing a protected branch. It blocked a legitimate update to a feature branch.
|
|
8
|
+
|
|
9
|
+
## What already exists
|
|
10
|
+
|
|
11
|
+
- **`dangerous-command-guard` hook** — a PreToolUse shell hook that inspects every shell command an agent runs and blocks catastrophic or destructive ones (`rm -rf /`, `git push --force`, etc.). It already had the force-with-lease carve-out; only the protected-branch test inside it was too broad.
|
|
12
|
+
- **The carve-out itself** — the logic that says "force-with-lease to a non-protected branch is fine, force-with-lease to main is not." That intent is correct and unchanged.
|
|
13
|
+
- **Three writers of the guard** — the same guard script is produced in three places: the shipped template (`src/templates/hooks/dangerous-command-guard.sh`), the migration writer that updates existing agents (`PostUpdateMigrator`), and the fresh-install writer (`init.ts`). All three carried the identical bug.
|
|
14
|
+
|
|
15
|
+
## What this adds
|
|
16
|
+
|
|
17
|
+
The fix narrows the protected-branch check so it looks **only at the extracted `git push …` invocation**, not the whole command. Concretely: pull out just the `git push ...` portion of the command, and check *that* for a protected-branch token. Unrelated text elsewhere in the command can no longer flip the decision. The main/master/develop/release block stays exactly as precise as before for the part that actually matters — the push command — so nothing is loosened; force-with-lease to `main` is still blocked.
|
|
18
|
+
|
|
19
|
+
The same one-line change is applied to all three writers, so existing agents get it on their next update and new agents get it at install. A regression test pins the exact false-positive (a force-with-lease to a feature branch with the word "release" in trailing text must be allowed).
|
|
20
|
+
|
|
21
|
+
## The safeguards
|
|
22
|
+
|
|
23
|
+
**Prevents the false-positive without widening the guard.** The check is now scoped to the push invocation, so it is *narrower*, not broader. A force-push to a protected branch is still blocked; plain `--force` / `-f` (no lease) is still blocked; everything the guard caught before, it still catches.
|
|
24
|
+
|
|
25
|
+
**Prevents drift between the three writers.** All three copies are fixed together, and existing tests already assert all three writers contain the carve-out, so a future edit that fixes only one copy would be caught.
|
|
26
|
+
|
|
27
|
+
## What ships when
|
|
28
|
+
|
|
29
|
+
One PR, one release. The migration writer means deployed agents pick the fix up automatically on their next update; no action required from anyone.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Side-Effects Review — scope force-with-lease protected-branch check to the push invocation
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `guard-forcepush-precise`
|
|
4
|
+
**Date:** `2026-06-07`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `self-review under the Tier-1 lite lane; the does-this-widen-the-guard question addressed below`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The `dangerous-command-guard` carve-out that permits `git push --force-with-lease` to a non-protected branch previously decided "is this a protected branch?" by scanning the WHOLE command input (`$INPUT`) for `(main|master|develop|release*)`. Any unrelated text in the command — a chained heredoc status message, a redirect path, a log line mentioning "release cadence" or "main" — false-positived and blocked a legitimate PR-branch force-with-lease update (observed live 2026-06-07, topic 19437: a force-push whose accompanying report text mentioned "release cadence" was blocked). The fix extracts only the `git push …` invocation (`grep -oiE 'git +push[^|;&]*' | head -1`) and scans THAT for the protected-branch token. Applied identically to all three writers (template, PostUpdateMigrator, init.ts) plus a regression test.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
- Protected-branch scan target — modified — `$INPUT` (whole command) → `$PUSH_INVOCATION` (extracted `git push …` segment only). No change to the regex itself.
|
|
15
|
+
- Carve-out semantics — unchanged — force-with-lease to a non-protected branch allowed; to main/master/develop/release* blocked; plain `--force`/`-f` blocked.
|
|
16
|
+
- Writers touched — all three (template `.sh`, `PostUpdateMigrator.getDangerousCommandGuard`, `init.ts` inline copy) — kept byte-consistent.
|
|
17
|
+
|
|
18
|
+
## 1. Direction-of-failure analysis
|
|
19
|
+
|
|
20
|
+
- **Old failure (live):** the guard blocked a SAFE force-with-lease to a feature branch whenever unrelated command text contained a protected-branch word → recurring friction; the agent could not update its own PR branch and resorted to workarounds.
|
|
21
|
+
- **New behavior:** the scan is confined to the push command. `git push --force-with-lease origin echo/feature && echo "release cadence on main"` is now ALLOWED (push targets a feature branch); `git push --force-with-lease origin main` is still BLOCKED. Both pinned by tests.
|
|
22
|
+
- **Trust surface NOT widened:** the change makes the protected-branch check NARROWER (fewer inputs match), never broader. A force-push to a protected branch, and plain `--force`/`-f`, remain blocked exactly as before — verified by the existing "BLOCKS force-with-lease that explicitly targets main/master" and "BLOCKS plain git push --force" tests, which still pass.
|
|
23
|
+
|
|
24
|
+
## 2. Over-permit
|
|
25
|
+
|
|
26
|
+
None. The only behavioral delta is that unrelated text outside the `git push` segment no longer triggers the protected-branch block. No new verbs, no wildcarding, no relaxation of the protected-branch set.
|
|
27
|
+
|
|
28
|
+
## 3. Scope deliberately NOT taken
|
|
29
|
+
|
|
30
|
+
- The broader text-scanning class (a `git commit` whose *message* mentions `git push --force` trips the risky-pattern loop) is a real but separate limitation of the deploy/risky-pattern scan; fixing it requires command-verb parsing across the whole guard and is out of scope for this targeted carve-out fix. Noted for a follow-up.
|
|
31
|
+
|
|
32
|
+
## 4. Migration parity
|
|
33
|
+
|
|
34
|
+
Covered. The migration writer (`PostUpdateMigrator.getDangerousCommandGuard`) is fixed, so existing agents receive the corrected guard on their next update (built-in `instar/` hooks are always-overwritten on migration). New agents get it via `init.ts`. The shipped template is fixed for completeness.
|
|
35
|
+
|
|
36
|
+
## 5. Token/cost impact
|
|
37
|
+
|
|
38
|
+
None.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Side-Effects Review — Herd-aware provider-swap
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `provider-swap` · **Date:** `2026-06-07` · **Author:** `Echo` · **Second-pass:** `not required (Tier-1)`
|
|
4
|
+
|
|
5
|
+
## Summary of the change
|
|
6
|
+
`IntelligenceRouter.evaluate` now, on a RUNTIME provider failure for a SAFETY-GATING call (`attribution.gating: true`), walks `componentFrameworks.failureSwap` (ordered frameworks), skips circuit-open targets, serves from the first healthy one, and re-throws if all are down (caller fails closed). New `failureSwap` config field + `gating` attribution flag. 5 safety-gating callers marked gating (ExternalOperationGate, MessagingToneGate, MessageSentinel, IntentLlmJudge, InputGuard).
|
|
7
|
+
|
|
8
|
+
## Decision-point inventory
|
|
9
|
+
- `IntelligenceRouter.evaluate` failure path — add (swap-on-failure for gating calls)
|
|
10
|
+
- `ComponentFrameworksConfig.failureSwap` — add (opt-in)
|
|
11
|
+
- `IntelligenceOptions.attribution.gating` — add (opt-in marker)
|
|
12
|
+
|
|
13
|
+
## 1. Over-block / Under-block
|
|
14
|
+
No allow/deny surface. The swap only changes WHICH provider answers a gating call on failure; the gate's own verdict logic is unchanged. Non-gating calls and the unconfigured default are byte-identical to before.
|
|
15
|
+
|
|
16
|
+
## 2. Data / state
|
|
17
|
+
None. No files, no schema, no persistence. Pure in-memory routing.
|
|
18
|
+
|
|
19
|
+
## 3. Performance
|
|
20
|
+
On the FAILURE path only, a gating call may make up to N extra provider attempts (N = failureSwap length), each short-circuited by its own breaker if open. The happy path (provider healthy) is unchanged — one call. No hot-path cost added.
|
|
21
|
+
|
|
22
|
+
## 4. Failure modes / herding
|
|
23
|
+
This IS failure-mode handling. Herding is bounded two ways: only gating calls swap (small set), and circuit-open targets are skipped (no load onto a stressed provider). All-down → re-throw → caller fails closed. No infinite loop (finite list, `target===framework` skipped).
|
|
24
|
+
|
|
25
|
+
## 5. Security / auth
|
|
26
|
+
Hardens availability of the safety gates (they get a working provider before failing closed). No new endpoints/capabilities/credentials. The swap reuses already-wired per-framework providers.
|
|
27
|
+
|
|
28
|
+
## 6. Migration / compatibility
|
|
29
|
+
No migration. Default (no `failureSwap`) = unchanged behavior. Opt-in per agent via `componentFrameworks.failureSwap`. `gating` is additive on attribution (ignored by old code paths).
|