instar 1.3.480 → 1.3.482
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/dashboard/index.html +103 -0
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +6 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +53 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +32 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/BlockerLedger.d.ts +294 -0
- package/dist/monitoring/BlockerLedger.d.ts.map +1 -0
- package/dist/monitoring/BlockerLedger.js +597 -0
- package/dist/monitoring/BlockerLedger.js.map +1 -0
- package/dist/monitoring/blockerSettleAuthority.d.ts +28 -0
- package/dist/monitoring/blockerSettleAuthority.d.ts.map +1 -0
- package/dist/monitoring/blockerSettleAuthority.js +0 -0
- package/dist/monitoring/blockerSettleAuthority.js.map +1 -0
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +9 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +1 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +35 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +15 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +6 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +107 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +64 -64
- package/src/scaffold/templates.ts +9 -0
- package/upgrades/1.3.481.md +38 -0
- package/upgrades/1.3.482.md +26 -0
- package/upgrades/side-effects/blocker-ledger-dev-gate.md +61 -0
- package/upgrades/side-effects/blocker-ledger.md +106 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Side-Effects Review — Blocker Ledger dev-gate registration (PR-1055 follow-up fix)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `blocker-ledger-dev-gate`
|
|
4
|
+
**Date:** `2026-06-10`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required (4-file conformance fix to an enforced standard; no new decision logic)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Registers the Blocker Ledger (merged in PR #1055) under the **developmentAgent dark-feature gate standard** enforced by `lint-dev-agent-dark-gate` (PR #1056). The two PRs merged within minutes of each other from divergent branch points, so PR #1055's hardcoded `monitoring.blockerLedger.enabled: false` default never met the new lint in CI — leaving main latently red (the next branch off main fails `npm run lint`). This fix conforms the feature to the standard: ConfigDefaults **omits** `enabled` (`blockerLedger: {}`), `AgentServer` resolves it via `resolveDevAgentGate(...)` (LIVE on a development agent for dogfooding, DARK on the fleet → routes 503), the config type makes `enabled` optional, and the feature is registered in `DEV_GATED_FEATURES` with the required safety justification (signal-only, no egress, no destructive action; one bounded fail-closed ≤200-token B17 check on the rare settle).
|
|
11
|
+
|
|
12
|
+
Files: `src/config/ConfigDefaults.ts`, `src/server/AgentServer.ts`, `src/core/types.ts`, `src/core/devGatedFeatures.ts`.
|
|
13
|
+
|
|
14
|
+
## Decision-point inventory
|
|
15
|
+
|
|
16
|
+
- `AgentServer` BlockerLedger construction condition — **modify** — from a literal `enabled === true` check to `resolveDevAgentGate(enabled, config)`. The gate's semantics: explicit `true`/`false` wins; absent → live on dev agents, dark on fleet. No other decision point touched.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Over-block
|
|
21
|
+
|
|
22
|
+
No block/allow surface — over-block not applicable. (Fleet behavior is unchanged: absent flag still resolves false on non-dev agents → routes 503 exactly as before.)
|
|
23
|
+
|
|
24
|
+
## 2. Under-block
|
|
25
|
+
|
|
26
|
+
No block/allow surface — under-block not applicable. The one behavior change is intended: development agents now run the ledger live without a config edit (the dogfood-on-dev standard).
|
|
27
|
+
|
|
28
|
+
## 3. Level-of-abstraction fit
|
|
29
|
+
|
|
30
|
+
Correct layer: this moves the feature onto the EXISTING gate primitive (`resolveDevAgentGate`) + registry (`DEV_GATED_FEATURES`) rather than a parallel mechanism. The wiring test (`devGatedFeatures-wiring.test.ts`) auto-covers the new entry with real ConfigDefaults.
|
|
31
|
+
|
|
32
|
+
## 4. Signal vs authority compliance
|
|
33
|
+
|
|
34
|
+
- [x] No — this change has no block/allow surface.
|
|
35
|
+
|
|
36
|
+
The gate resolution is configuration mechanics, not a judgment decision. The ledger's own signal-only posture (PR #1055 artifact) is unchanged.
|
|
37
|
+
|
|
38
|
+
## 5. Interactions
|
|
39
|
+
|
|
40
|
+
- **Shadowing/double-fire/races:** none — same single construction site, same null-→503 path.
|
|
41
|
+
- **Migration interplay:** `applyDefaults` adds only MISSING keys; an existing agent that already received `blockerLedger: { enabled: false }` from PR #1055's default keeps that explicit false (fleet-safe; dev agents that want live can clear it or set true). New installs get the empty object → gate decides. No surprise activation on the fleet.
|
|
42
|
+
|
|
43
|
+
## 6. External surfaces
|
|
44
|
+
|
|
45
|
+
None beyond the intended one: a development agent's `/blockers` routes go live (local Bearer-auth API + dashboard tab). Zero egress; no fleet-visible change.
|
|
46
|
+
|
|
47
|
+
## 7. Rollback cost
|
|
48
|
+
|
|
49
|
+
Trivial: revert restores the literal `enabled: false` default. No persistent state created by the gate itself.
|
|
50
|
+
|
|
51
|
+
## Conclusion
|
|
52
|
+
|
|
53
|
+
A 4-file conformance fix that repairs the PR #1055 × #1056 merge race (latent red main) and lands the feature on the correct dev-gate standard — which also supersedes the manual dogfood config flip on the dev agent. Verified: `lint-dev-agent-dark-gate` clean, `tsc` clean, dev-gate wiring test green (proves live-on-dev/dark-on-fleet with real defaults), Blocker Ledger unit (35) + integration (7) + e2e (4) all green. Clear to ship.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Evidence pointers
|
|
58
|
+
|
|
59
|
+
- `node scripts/lint-dev-agent-dark-gate.js` → clean (was: `[C: unclassified dark default]` on ConfigDefaults.ts:257).
|
|
60
|
+
- `tests/unit/devGatedFeatures-wiring.test.ts` → green including the new `blockerLedger` entry.
|
|
61
|
+
- `tests/unit/BlockerLedger.test.ts` (28) + `tests/unit/blockerSettleAuthority.test.ts` (7) + `tests/integration/blocker-ledger-routes.test.ts` (7) + `tests/e2e/blocker-ledger-lifecycle.test.ts` (4) → green.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Side-Effects Review — Blocker Ledger (Autonomy Principles Enforcement, Piece 1)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `blocker-ledger`
|
|
4
|
+
**Date:** `2026-06-10`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `code-reviewer subagent (see below)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Adds the **Blocker Ledger** — the resolution-workflow + memory layer that COMPLETES Principle 1 of `docs/specs/AUTONOMY-PRINCIPLES-ENFORCEMENT-SPEC.md`. The detection half (deferral-detector hook, B16_UNVERIFIED_WALL, B17_FALSE_BLOCKER) already exists; this is the missing resolution half. A detected false-blocker becomes a gated pipeline (`candidate → authority-checked → access-requested → dry-run → live-run → terminal`) with structural evidence-of-work at every terminal, built so the memory can NEVER become a deferral-laundromat. Ships **DARK** behind `monitoring.blockerLedger.enabled` (default false → routes 503).
|
|
11
|
+
|
|
12
|
+
Files: `src/monitoring/BlockerLedger.ts` (new — store + state machine + CAS + archival + audit), `src/monitoring/blockerSettleAuthority.ts` (new — the Tier-1 B17 settle authority), `src/server/routes.ts` (5 `/blockers*` routes + RouteContext field), `src/server/AgentServer.ts` (gated construction + routeCtx thread), `src/core/PostUpdateMigrator.ts` (deferral-detector auto-open trigger in the always-overwritten built-in hook), `src/config/ConfigDefaults.ts` (dark default), `src/core/types.ts` (config type), `src/scaffold/templates.ts` (CLAUDE.md awareness block). Tests: unit (35) + integration (7) + e2e (4).
|
|
13
|
+
|
|
14
|
+
## Decision-point inventory
|
|
15
|
+
|
|
16
|
+
- `BlockerLedger.advance()` — **add** — gated linear-transition validator (refuses skips). Brittle/structural by design; carries NO message-blocking authority.
|
|
17
|
+
- `BlockerLedger.settle()` (resolved) — **add** — structural evidence validator (confined playbook path, id-reference, successful live-run). Structural, no message authority.
|
|
18
|
+
- `BlockerLedger.settle()` (true-blocker) — **add** — the one JUDGMENT in the feature. The field checks gate the FORM of evidence; the judgment routes to `blockerSettleAuthority` (Tier-1 LLM, B17 pattern). This is the signal-vs-authority crux.
|
|
19
|
+
- `deferral-detector` hook — **modify** — adds a best-effort, non-blocking auto-open POST to `/blockers` on the inability/false-blocker shape. The hook's existing checklist injection is unchanged.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Over-block
|
|
24
|
+
|
|
25
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
26
|
+
|
|
27
|
+
The ledger has **no outbound-message block/allow surface** — it never holds a message. Its only refusals are at its own `/blockers*` API edge (rejecting an advance that skips a state, or a settle whose evidence is incomplete). Those refusals are *intended* and reversible (the caller gathers the missing evidence and retries). A possible over-refusal: the `resolved` confined-path check rejects a legitimate playbook authored outside the configured `confinedPlaybookRoots` (default: `.claude/skills`, `<stateDir>/playbooks`, `.instar/playbooks`). Mitigation: the roots are constructor-configurable; the error message names the constraint. This is a deliberate safety bound (no arbitrary-path write target), not an accidental over-block.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 2. Under-block
|
|
32
|
+
|
|
33
|
+
**What failure modes does this still miss?**
|
|
34
|
+
|
|
35
|
+
The free-text evidence fields (`detectedText`, `rebuttal`, `failedAttempt.detail`) are bounded + enveloped but their *truthfulness* is not verifiable by the ledger — an agent could record a plausible-but-fabricated "vault miss". This is mitigated, not eliminated: the true-blocker settle still routes through the B17 LLM authority, which is prompted to refuse a vague/untried rebuttal, and the self-fetch-first mandate requires the *form* of a failed self-fetch. The ledger's claim is "harder to launder," not "impossible to lie to." The D6 re-walk (re-test on a cadence, require NEW evidence) is the backstop. Noted as an accepted residual.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 3. Level-of-abstraction fit
|
|
40
|
+
|
|
41
|
+
**Is this at the right layer?**
|
|
42
|
+
|
|
43
|
+
Yes. The ledger is a **detector/recorder** (low-level, structural) for everything except the one true-blocker settle judgment, which is correctly delegated UP to an **authority** (the LLM-backed `blockerSettleAuthority`). It does not re-implement the deferral-detector or B16/B17 — it *feeds off* them (the auto-open trigger) and *routes the settle through* B17. The CAS/atomic-write reuses the `CommitmentTracker` pattern; the audit-jsonl reuses the `SessionReaper` pattern; the dark/503 gate reuses the `growthMilestoneAnalyst` pattern. No parallel re-implementation of an existing primitive.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 4. Signal vs authority compliance
|
|
48
|
+
|
|
49
|
+
**Required reference:** docs/signal-vs-authority.md
|
|
50
|
+
|
|
51
|
+
- [x] **No — this change produces a signal consumed by an existing smart gate** (for the message surface: the ledger never blocks a message; B16/B17 keep that authority), **AND** the one judgment it does carry (the true-blocker settle) is a **smart gate with context** (`blockerSettleAuthority`, an LLM authority that fails CLOSED).
|
|
52
|
+
|
|
53
|
+
The brittle field checks in `settle()` gate only the FORM of evidence (taxonomy membership, presence of a failed-attempt record, temporal ordering). They do NOT make the settle decision — that is the LLM authority's. A settle with perfect-form evidence still DENIES if the B17 authority judges it a false blocker. No brittle check owns the judgment. Compliant.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 5. Interactions
|
|
58
|
+
|
|
59
|
+
- **Shadowing:** None. The `/blockers*` routes are new and additive; they do not sit in front of any existing route. The deferral-detector change appends after the existing checklist `process.stdout.write` — it cannot shadow or alter the checklist (verified: checklist is written first, then the fire-and-forget POST).
|
|
60
|
+
- **Double-fire:** The auto-open fires once per inability-match hook invocation. A blocker could be opened multiple times across multiple messages (no dedup in v1) — acceptable; entries are cheap and the list is paginated/archived. Noted as a known v1 characteristic, not a defect.
|
|
61
|
+
- **Races:** All ledger mutations serialize through one in-process chain (`mutate()`), reloading from disk before each apply — a cross-process write is picked up, not clobbered. Concurrent-open test proves 20 parallel opens produce 20 unique ids with no lost increment.
|
|
62
|
+
- **Feedback loops:** The deferral-detector → /blockers auto-open is one-directional; the ledger does not feed back into the hook. The B17 authority consumes ledger free-text only inside the data envelope (no instruction-injection feedback).
|
|
63
|
+
- **Timing:** the deferral-detector hook now holds the process open ~200ms (bounded, global 2000ms safety-net) on inability-matches only, to flush the fire-and-forget POST. Adds bounded latency to that specific hook path; negligible and only on false-blocker framing.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 6. External surfaces
|
|
68
|
+
|
|
69
|
+
- **Other agents / users:** None until `monitoring.blockerLedger.enabled` is set (ships dark → routes 503). Existing agents receive the dark default via `migrateConfig` → `applyDefaults` (idempotent, missing-key-only) and the updated deferral-detector hook via the always-overwrite built-in-hook migration.
|
|
70
|
+
- **External systems:** None. The ledger is purely local file-JSON + the local `/blockers` API + a local-only B17 LLM call through the agent's existing intelligence provider. No network egress beyond the agent's own server.
|
|
71
|
+
- **Persistent state:** Adds `state/blocker-ledger.json`, `state/blocker-ledger-archive.json`, and `logs/blocker-decisions.jsonl`. All created lazily on first write; absent until the feature is enabled AND a blocker is opened.
|
|
72
|
+
- **CLAUDE.md template:** new capability block (agent-awareness). Existing agents get it via the normal template-migration path; it documents the dark default honestly.
|
|
73
|
+
- **Dashboard:** a read-only "Blockers" tab (`dashboard/index.html`) that consumes `GET /blockers`, HTML-escapes all untrusted free-text via the existing `escapeHtml`, renders a true-blocker as a decaying hypothesis ("recheck after <date>", never "settled/stop trying"), and shows a friendly "not turned on yet" message on the 503-dark response. Additive; mirrors the `resources` tab. No mutation controls (advance/settle from the dashboard is a later phase).
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 7. Rollback cost
|
|
78
|
+
|
|
79
|
+
Pure additive code + a dark-by-default flag. Back-out = revert the code and ship a patch; nothing is on by default, so no agent is running it unless explicitly enabled. The only persistent state is the three lazily-created files, which are inert when the feature is off and safe to leave on disk (or delete) on rollback. No migration to undo (the config default is missing-key-only and harmless when present-but-unused). No user-visible regression during the rollback window (nothing user-visible shipped). Estimated rollback: one revert commit, zero downtime.
|
|
80
|
+
|
|
81
|
+
## Conclusion
|
|
82
|
+
|
|
83
|
+
The review produced no signal-vs-authority violation and no message-block surface. The one judgment (true-blocker settle) is correctly an LLM authority that fails closed, with brittle checks confined to evidence-FORM validation. One material build-time discovery (recorded for the user): on current `JKHeadley/main` (v1.3.479), `resolveModelForFramework` **already** handles `gemini-cli`/`pi-cli` with real models, so Piece 3's "broken foundation" premise is already fixed upstream — that is a separate PR's concern and does not affect this one. The design change made *during* this build (vs the converged spec): the true-blocker settle evidence (failedAttempt + accessRequest, each timestamped) is carried in the settle call and validated `accessRequest.at >= failedAttempt.at`, **decoupled** from the linear pipeline's `access-requested` state — because the pipeline orders `access-requested` (state 3) before `dry-run` (state 4), which conflicts with the true-blocker requirement that the ask come AFTER the failed attempt. This is faithful to the spec's *intent* (ask-after-trying) while resolving an ordering contradiction the spec didn't catch. Clear to ship as PR 1.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Second-pass review (if required)
|
|
88
|
+
|
|
89
|
+
**Required** (touches a gate + server lifecycle). An independent reviewer subagent audited the artifact + code adversarially.
|
|
90
|
+
|
|
91
|
+
**Independent read of the artifact: concur.**
|
|
92
|
+
|
|
93
|
+
> Concur with the review. The one judgment (true-blocker settle) routes through the LLM authority (`buildB17SettleAuthority`), which fails closed on no-provider / provider-error / unparseable-verdict; every brittle check gates only the FORM of evidence and holds no settle authority; the message surface is never touched (the deferral-detector hook emits `decision:'approve'` unconditionally before the fire-and-forget auto-open, fully wrapped). Verified: no-skip state machine, `resolved` requires a successful live-run + confined id-referencing playbook, the no-evidence re-settle counter is persisted via `mutate()` BEFORE the throw (survives), single-writer CAS closes the TOCTOU by re-finding inside the final commit after the async authority call, and the feature is ALIVE when enabled / DARK (503) when disabled. `tsc` exit 0; 46 tests pass.
|
|
94
|
+
|
|
95
|
+
Two nice-to-haves the reviewer flagged, both addressed/accepted:
|
|
96
|
+
- The `toLlmSafeEnvelope` close-tag regex was tightened to tolerate whitespace/attributes (`</blocker-ledger-data >`) — **applied** this pass.
|
|
97
|
+
- `escapeHtmlForDashboard` was "exported but unused" at review time — now **wired** by the dashboard "Blockers" tab added this pass (all untrusted text escaped before render).
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Evidence pointers
|
|
102
|
+
|
|
103
|
+
- Unit: `tests/unit/BlockerLedger.test.ts` (28), `tests/unit/blockerSettleAuthority.test.ts` (7) — gated state machine, both terminals, self-fetch-first mandate, anti-laundering re-walk + escalate-after-N, injection-envelope, concurrency, archival, fail-closed authority.
|
|
104
|
+
- Integration: `tests/integration/blocker-ledger-routes.test.ts` (7) — 503-dark, 200-alive, X-Instar-Request 403, full create→advance→settle over HTTP, audit line with origin + gate hash.
|
|
105
|
+
- E2E: `tests/e2e/blocker-ledger-lifecycle.test.ts` (4) — production-path "feature is alive" (200 not 503), dark-by-default, persistence across restart.
|
|
106
|
+
- `npx tsc --noEmit` exit 0.
|