instar 1.3.269 → 1.3.271

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.
Files changed (109) hide show
  1. package/dashboard/index.html +73 -11
  2. package/dist/commands/server.d.ts.map +1 -1
  3. package/dist/commands/server.js +24 -3
  4. package/dist/commands/server.js.map +1 -1
  5. package/dist/coordination/MandateAudit.d.ts +48 -0
  6. package/dist/coordination/MandateAudit.d.ts.map +1 -0
  7. package/dist/coordination/MandateAudit.js +95 -0
  8. package/dist/coordination/MandateAudit.js.map +1 -0
  9. package/dist/coordination/MandateGate.d.ts +48 -0
  10. package/dist/coordination/MandateGate.d.ts.map +1 -0
  11. package/dist/coordination/MandateGate.js +104 -0
  12. package/dist/coordination/MandateGate.js.map +1 -0
  13. package/dist/coordination/MandateStore.d.ts +60 -0
  14. package/dist/coordination/MandateStore.d.ts.map +1 -0
  15. package/dist/coordination/MandateStore.js +106 -0
  16. package/dist/coordination/MandateStore.js.map +1 -0
  17. package/dist/coordination/ReviewExchange.d.ts +135 -0
  18. package/dist/coordination/ReviewExchange.d.ts.map +1 -0
  19. package/dist/coordination/ReviewExchange.js +192 -0
  20. package/dist/coordination/ReviewExchange.js.map +1 -0
  21. package/dist/coordination/conditions.d.ts +32 -0
  22. package/dist/coordination/conditions.d.ts.map +1 -0
  23. package/dist/coordination/conditions.js +54 -0
  24. package/dist/coordination/conditions.js.map +1 -0
  25. package/dist/coordination/types.d.ts +74 -0
  26. package/dist/coordination/types.d.ts.map +1 -0
  27. package/dist/coordination/types.js +17 -0
  28. package/dist/coordination/types.js.map +1 -0
  29. package/dist/core/ApprovalLedger.d.ts +132 -0
  30. package/dist/core/ApprovalLedger.d.ts.map +1 -0
  31. package/dist/core/ApprovalLedger.js +191 -0
  32. package/dist/core/ApprovalLedger.js.map +1 -0
  33. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  34. package/dist/core/PostUpdateMigrator.js +33 -1
  35. package/dist/core/PostUpdateMigrator.js.map +1 -1
  36. package/dist/core/SecretStore.d.ts.map +1 -1
  37. package/dist/core/SecretStore.js +10 -1
  38. package/dist/core/SecretStore.js.map +1 -1
  39. package/dist/core/SessionBuildContextStore.d.ts +33 -0
  40. package/dist/core/SessionBuildContextStore.d.ts.map +1 -0
  41. package/dist/core/SessionBuildContextStore.js +107 -0
  42. package/dist/core/SessionBuildContextStore.js.map +1 -0
  43. package/dist/core/SessionManager.d.ts +4 -0
  44. package/dist/core/SessionManager.d.ts.map +1 -1
  45. package/dist/core/SessionManager.js +44 -3
  46. package/dist/core/SessionManager.js.map +1 -1
  47. package/dist/core/TransferByNickname.d.ts +6 -0
  48. package/dist/core/TransferByNickname.d.ts.map +1 -1
  49. package/dist/core/TransferByNickname.js +18 -6
  50. package/dist/core/TransferByNickname.js.map +1 -1
  51. package/dist/core/seamlessnessConfig.d.ts.map +1 -1
  52. package/dist/core/seamlessnessConfig.js +12 -1
  53. package/dist/core/seamlessnessConfig.js.map +1 -1
  54. package/dist/core/types.d.ts +34 -0
  55. package/dist/core/types.d.ts.map +1 -1
  56. package/dist/core/types.js.map +1 -1
  57. package/dist/feedback-factory/migration/immutableGuard.d.ts +87 -0
  58. package/dist/feedback-factory/migration/immutableGuard.d.ts.map +1 -0
  59. package/dist/feedback-factory/migration/immutableGuard.js +163 -0
  60. package/dist/feedback-factory/migration/immutableGuard.js.map +1 -0
  61. package/dist/feedback-factory/migration/importIntegrity.d.ts +112 -0
  62. package/dist/feedback-factory/migration/importIntegrity.d.ts.map +1 -0
  63. package/dist/feedback-factory/migration/importIntegrity.js +202 -0
  64. package/dist/feedback-factory/migration/importIntegrity.js.map +1 -0
  65. package/dist/feedback-factory/monitor/parityMonitor.d.ts +75 -0
  66. package/dist/feedback-factory/monitor/parityMonitor.d.ts.map +1 -0
  67. package/dist/feedback-factory/monitor/parityMonitor.js +98 -0
  68. package/dist/feedback-factory/monitor/parityMonitor.js.map +1 -0
  69. package/dist/feedback-factory/monitor/parityMonitorStore.d.ts +44 -0
  70. package/dist/feedback-factory/monitor/parityMonitorStore.d.ts.map +1 -0
  71. package/dist/feedback-factory/monitor/parityMonitorStore.js +80 -0
  72. package/dist/feedback-factory/monitor/parityMonitorStore.js.map +1 -0
  73. package/dist/scaffold/templates.d.ts.map +1 -1
  74. package/dist/scaffold/templates.js +19 -1
  75. package/dist/scaffold/templates.js.map +1 -1
  76. package/dist/scheduler/MentorAutonomousGuardian.d.ts.map +1 -1
  77. package/dist/scheduler/MentorAutonomousGuardian.js +1 -0
  78. package/dist/scheduler/MentorAutonomousGuardian.js.map +1 -1
  79. package/dist/server/AgentServer.d.ts +11 -0
  80. package/dist/server/AgentServer.d.ts.map +1 -1
  81. package/dist/server/AgentServer.js +102 -1
  82. package/dist/server/AgentServer.js.map +1 -1
  83. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  84. package/dist/server/CapabilityIndex.js +45 -0
  85. package/dist/server/CapabilityIndex.js.map +1 -1
  86. package/dist/server/routes.d.ts +19 -0
  87. package/dist/server/routes.d.ts.map +1 -1
  88. package/dist/server/routes.js +482 -4
  89. package/dist/server/routes.js.map +1 -1
  90. package/package.json +1 -1
  91. package/src/data/builtin-manifest.json +65 -65
  92. package/src/scaffold/templates.ts +19 -1
  93. package/upgrades/1.3.270.md +106 -0
  94. package/upgrades/1.3.271.md +154 -0
  95. package/upgrades/approval-ledger-phase2.eli16.md +56 -0
  96. package/upgrades/autoloop-gate-compliance.eli16.md +11 -0
  97. package/upgrades/feedback-phase3-monitor.eli16.md +51 -0
  98. package/upgrades/feedback-phase4-integrity.eli16.md +54 -0
  99. package/upgrades/respawn-build-context-reestablishment.eli16.md +5 -0
  100. package/upgrades/side-effects/approval-ledger-phase2.md +82 -0
  101. package/upgrades/side-effects/autoloop-gate-compliance.md +43 -0
  102. package/upgrades/side-effects/coordination-mandate-enforcement.md +86 -0
  103. package/upgrades/side-effects/dashboard-pool-sessions.md +103 -0
  104. package/upgrades/side-effects/feedback-phase3-monitor.md +37 -0
  105. package/upgrades/side-effects/feedback-phase4-integrity.md +35 -0
  106. package/upgrades/side-effects/respawn-build-context-reestablishment.md +81 -0
  107. package/upgrades/side-effects/review-exchange-protocol.md +60 -0
  108. package/upgrades/side-effects/secret-drop-store-first.md +117 -0
  109. package/upgrades/side-effects/transfer-idempotency-exactly-once.md +105 -0
@@ -0,0 +1,106 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ Implemented Phase 2 of the approved Approval-as-Data design: the **approval ledger**.
9
+ Every operator approval is now recorded as durable, signed data — classified as
10
+ approved-as-is, approved-with-change (with the reason for each change), or rejected — and
11
+ the system computes a per-class agreement ratio and streak from those records. The ledger
12
+ tracks approvals wherever they occur: an official spec sign-off, a decision approved in
13
+ chat, or any other surface. New endpoints record a decision, list the records, and return
14
+ the agreement summary with a breakdown by surface. The ledger is signed, append-only, and
15
+ read-only with respect to all other behavior — it never gates, blocks, or changes anything.
16
+ The authoritative source of whether an approval was as-is or changed is always the
17
+ operator; the agent never self-classifies intent, and any record is operator-correctable.
18
+
19
+ Implemented the Coordination Mandate enforcement engine (the design the operator
20
+ signed off as A/A/B): a deny-by-default authority gate for autonomous agent-to-agent
21
+ actions. The operator writes one bounded, expiring, revocable "permission slip"
22
+ delegating specific authorities to a specific pair of agents; the slip — not the agent
23
+ — is what authorizes each action, preserving the rule that the one asking is never the
24
+ one authorizing. Issuance and revocation require the operator's dashboard PIN, so an
25
+ agent's API access alone is structurally unable to create or widen a mandate. A signed
26
+ store verifies authorship on every check (a forged or edited mandate fails), risky
27
+ authorities can be tied to objective real-state conditions the agent cannot fake, and
28
+ every decision — allowed and denied alike — lands in a tamper-evident, hash-chained
29
+ audit log. With no mandate issued, the gate denies everything, so this ships inert and
30
+ changes no behavior until the operator issues the first mandate.
31
+
32
+ Added the Phase-3 invariant-parity monitor for the feedback-factory migration: a
33
+ windowing layer over parity results that computes the objective
34
+ parity-zero-divergence condition (a sustained run of clean passes over a minimum
35
+ real-traffic window) which the future cutover step reads as its go signal. Includes
36
+ a durable, restart-surviving variant (append-only pass journal, torn-line tolerant).
37
+ Internal migration tooling — not yet wired to any live behavior.
38
+
39
+ Added the Phase-4 data-migration integrity tooling for the feedback-factory
40
+ migration: import-as-is preservation of every curated field, per-row checksums
41
+ (in vs out), fingerprint-uniqueness scanning, auto-increment sequence reset,
42
+ schema-equivalence assertion, and the structural never-re-derive guard (the
43
+ processor refuses to mutate any cluster created before the cutover timestamp or
44
+ carrying governance notes). Internal migration tooling — not yet wired to any
45
+ live behavior.
46
+
47
+ SessionManager now samples the live tmux pane cwd for enabled development-agent sessions and stores it in a crash-safe sidecar. Resume spawns prepend a restore note only for fresh, existing `.worktrees` paths; home-only sessions remain a no-op.
48
+
49
+ ## What to Tell Your User
50
+
51
+ Your agent now remembers your approvals instead of forgetting them the moment they happen.
52
+ Each time you approve something — a full spec, or just a choice you make in chat — it can
53
+ record whether you took its recommendation as-is or changed it, and why. Over time this
54
+ builds a simple picture of where the agent already proposes what you would have picked, and
55
+ where it still needs to close the gap. You stay the source of truth: the agent only records
56
+ what you explicitly say, and you can correct any entry. This is an internal, read-only
57
+ record — it never changes what the agent does, it just helps it learn your preferences.
58
+
59
+ You can now hand your agent a bounded permission slip instead of approving every step
60
+ of a multi-agent project. You write the slip once from your dashboard with your PIN:
61
+ exactly which actions are allowed, within which limits, for which two agents, until
62
+ when. Your agent can act inside those lines without pinging you, and nothing outside
63
+ them — and you can tear the slip up at any moment. Everything done under a slip is
64
+ written to a tamper-evident log you can review. Until you issue a slip, nothing changes
65
+ at all: the system refuses every delegated action by default.
66
+
67
+ Nothing changes for you. This is internal plumbing for the feedback-system handover:
68
+ a safety meter that has to read "clean for a sustained window" before the one-way
69
+ switch can ever be considered. It ships dormant.
70
+
71
+ Nothing changes for you. This is internal plumbing for the feedback-system
72
+ handover: the checks that guarantee curated history is copied perfectly and can
73
+ never be silently rewritten afterward. It ships dormant.
74
+
75
+ Developer-agent respawns can now re-surface the worktree checkout they were building in before the restart. Normal home-only conversations are unchanged.
76
+
77
+ ## Summary of New Capabilities
78
+
79
+ - Record an approval decision through the new approvals endpoint, tagged as approved-as-is,
80
+ approved-with-change, or rejected, with the reason for any change.
81
+ - Read a per-class agreement summary (total, approved-as-is count, ratio, streak, and a
82
+ breakdown by where the approval happened) plus a list of recorded decisions.
83
+ - Maturity: stable for the recording and summary surface; the later auto-approval pilot
84
+ remains a separate, operator-gated phase that is not part of this change.
85
+
86
+ - Issue or revoke a coordination mandate from the dashboard surface with your PIN —
87
+ agent credentials alone cannot do either.
88
+ - Agents check intended agent-to-agent actions against the mandate and get an
89
+ allow-or-deny answer with the reason; denials are the default with no mandate.
90
+ - Review every mandate decision in a chained, tamper-evident audit trail, including
91
+ whether each entry's chain verifies.
92
+ - Maturity: stable for the gate, store, and audit; conditioned authorities (objective
93
+ real-state gates for riskier actions) ship deny-safe and unused by the first mandate.
94
+
95
+ - Internal: order-independent parity windowing (per-report fingerprint,
96
+ terminal-status, recurrence/cycling counts) with a conservative
97
+ cleared-or-blocked gate verdict; survives restarts.
98
+ - Maturity: internal migration tooling, dormant until the dual-forward phase.
99
+
100
+ - Internal: integrity-safe import core + a guarded store wrapper that makes
101
+ pre-cutover and governance-noted clusters structurally immutable.
102
+ - Maturity: internal migration tooling, dormant until the import phase.
103
+
104
+ - SessionManager can record the live pane working directory for running sessions when the development-agent-gated feature is enabled.
105
+ - A resumed respawn receives a `[BUILD-CONTEXT RESTORE]` continuation note only when the prior cwd was a fresh, existing agent worktree.
106
+ - The sidecar state write is crash-safe through the state layer's temp-file plus rename path.
@@ -0,0 +1,154 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ One additive line in the mentor autoloop prompt (`src/scheduler/MentorAutonomousGuardian.ts`), locked by three new unit-test assertions. Earned from PR #792's no-silent-fallbacks CI failure, where a spec's "best-effort, never throws" wording invited the swallowed catch the ratchet counts.
9
+
10
+ The dashboard sessions list now shows EVERY session across ALL machines in the
11
+ multi-machine pool, and every session row states which machine it runs on
12
+ (a machine-nickname badge). Sessions on the machine you're viewing stay fully
13
+ interactive (live terminal, close button); sessions on other machines appear
14
+ as informational rows with a tooltip pointing at the owning machine's
15
+ dashboard.
16
+
17
+ Under the hood: `GET /sessions` self-tags sessions with `machineId` /
18
+ `machineNickname` when the pool is wired, and a new `GET /sessions?scope=pool`
19
+ aggregates every reachable peer's session list (existing cross-machine Bearer
20
+ auth, 5s timeout per peer). A dead or slow peer degrades to a `pool.failed`
21
+ entry — the page never breaks. The plain `/sessions` route keeps its
22
+ back-compatible array shape.
23
+
24
+ Added the ReviewExchange protocol — the structured way two mandate-named agents complete
25
+ a mutual code-review sign-off without the operator relaying messages between them. One
26
+ exchange tracks one review package (content-addressed by checksum, fixed at creation)
27
+ through a strict linear lifecycle: proposed, delivered, verdict recorded, complete — or
28
+ changes-requested, which is terminal so a stale approval can never be replayed onto
29
+ reworked code. Both sign-offs — the reviewing peer's authenticated approval and the
30
+ owner's countersignature — are checked against the operator's coordination mandate
31
+ before acceptance, and every accepted signature stores the audit reference of the gate
32
+ decision that authorized it. With no mandate issued, every sign-off refuses: the
33
+ protocol inherits deny-by-default and ships inert.
34
+
35
+ A submitted Secret Drop is now persisted store-first to the durable
36
+ AES-256-GCM encrypted SecretStore the instant it is received, instead of
37
+ living only in the server's in-memory `received` map. The retrieve route
38
+ transparently falls back to the durable copy when the in-memory one is gone
39
+ (server restart, compaction, cross-machine handoff), and a successful consume
40
+ deletes both copies — one-time semantics are preserved. Opt out with
41
+ `secrets.persistDrops: false` in `.instar/config.json`.
42
+
43
+ This closes the recurring "the user dropped a secret and the agent lost it"
44
+ failure: with the fleet shipping many releases a day, every release restarted
45
+ the server and evaporated any un-consumed submission.
46
+
47
+ Also: the SecretStore master-key manager now forces file-key mode during test
48
+ runs (`VITEST` / `NODE_ENV=test`). The OS keychain entry is machine-global —
49
+ a test constructing a SecretStore against a fresh stateDir used to generate a
50
+ new master key and silently overwrite that shared entry, making every real
51
+ agent vault on the machine undecryptable for keychain-resolving readers. No
52
+ test can touch the real keychain anymore. A `secrets.forceFileKey` config
53
+ plumb is also available for operators who want to pin the key source.
54
+
55
+ The CLAUDE.md template's Secret Drop "Security" bullet is rewritten (the old
56
+ "in-memory only, never written to disk" claim is no longer true), and an
57
+ idempotent migration updates existing agents' CLAUDE.md in place.
58
+
59
+ Two fixes for the 2026-06-05 "move this to the laptop" noise incident, where
60
+ one user message produced contradictory "Moving to Laptop" / "I can't move
61
+ this right now (rate-limited)" replies and executed multiple times.
62
+
63
+ 1. **Idempotent topic transfer.** The transfer planner now recognizes a move
64
+ request targeting the machine the topic is already on — or already pinned
65
+ to — BEFORE the rate limit. Duplicates of an already-satisfied move answer
66
+ "This conversation is already running on X — nothing to move" instead of a
67
+ rate-limit rejection. The rate limit keeps its real job: damping rapid
68
+ flip-flops between DIFFERENT machines.
69
+
70
+ 2. **Exactly-once ingress turns on with the pool.** The exactly-once inbound
71
+ message gate (the dedupe ledger that stops retried/replayed messages from
72
+ re-executing commands) shipped default-OFF — even on machines whose
73
+ multi-machine session pool was live. The default is now stage-aware: a pool
74
+ at `live-transfer` or `rebalance` gets `exactlyOnceIngress` ON
75
+ automatically. An explicit `multiMachine.exactlyOnceIngress: false` still
76
+ wins.
77
+
78
+ ## What to Tell Your User
79
+
80
+ Nothing user-visible. The autonomous mentor loop's instructions now include how to satisfy the repo's ratchet CI gates, so mentor-driven fixes stop tripping no-silent-fallbacks.
81
+
82
+ Open the dashboard on any of your machines and you'll see all your sessions in
83
+ one list — each with a badge saying which machine it's running on. No more
84
+ opening one dashboard per machine to find a session.
85
+
86
+ Your agent can now run a real code review with a partner agent under the permission
87
+ slip you issue — no more relaying review messages between them yourself. The agents
88
+ deliver the code package, record the reviewer's verdict, and counter-sign, and every
89
+ step is checked against your permission slip and written to the same tamper-evident
90
+ log. If you revoke the slip mid-review, the review stops on the spot. Until you issue
91
+ a slip, nothing changes — every review step refuses by default.
92
+
93
+ If you hand me a secret through a drop link, it now survives my server
94
+ restarting, updating, or the conversation moving between machines. You should
95
+ never have to re-send a secret because "I lost it" again. Secrets are stored
96
+ encrypted and are deleted as soon as they're consumed.
97
+
98
+ Asking me to move a conversation to a machine it's already on (or repeating
99
+ the request) now gets a calm "already running there" instead of a confusing
100
+ "rate-limited" error. And if my internals retry a message under load, the
101
+ command runs once — not four times.
102
+
103
+ ## Summary of New Capabilities
104
+
105
+ - `buildAutoloopGoal` includes a gate-compliance paragraph: intentional fail-open catches must report via DegradationReporter or carry an inline `@silent-fallback-ok` justification — never a ratchet baseline bump.
106
+ - The mentor is instructed to spell out these gate notes in any task brief or spec it authors for another agent.
107
+
108
+ - Dashboard sessions list shows every session across the pool with a machine badge per row.
109
+ - `GET /sessions?scope=pool` → `{ sessions, pool: { peersOk, failed, ... } }` (agents can answer "what's running across my machines?").
110
+ - `GET /sessions` sessions carry `machineId`/`machineNickname` on pooled installs.
111
+ - CLAUDE.md template bullet + idempotent migration so existing agents learn the capability.
112
+
113
+ - Create a review exchange for an artifact under a mandate, content-addressed so the
114
+ signatures bind to exactly the code that was reviewed.
115
+ - Record delivery, the peer's authenticated verdict, and the owner's countersignature —
116
+ with both sign-offs evaluated through the mandate gate and refused on any deny.
117
+ - Inspect exchanges and their signatures, each carrying the audit reference of the
118
+ gate decision that authorized it.
119
+ - Maturity: stable engine and routes; ships inert (deny-by-default) until the operator
120
+ issues a mandate with the sign-code-review authority.
121
+
122
+ - Secret Drop submissions persist store-first to the encrypted SecretStore and survive server churn.
123
+ - Retrieval transparently falls back to the durable copy; consume deletes both copies.
124
+ - `secrets.persistDrops: false` opts out (default ON).
125
+ - Tests can never pollute the machine-global SecretStore keychain entry (structural guard).
126
+ - `secrets.forceFileKey` pins the master-key source to the per-agent file key.
127
+
128
+ - Duplicate "move to X" requests no-op as "already there" — never "rate-limited."
129
+ - The transfer planner accepts an optional `currentPinOf` hook (pin-aware idempotency).
130
+ - `exactlyOnceIngress` defaults ON whenever the session pool routes real traffic.
131
+
132
+ ## Evidence
133
+
134
+ Three tiers green: `tests/unit/dashboard-sessionMachineBadge.test.ts` (8),
135
+ `tests/unit/PostUpdateMigrator-poolSessionsVisibility.test.ts` (3),
136
+ `tests/integration/sessions-pool-scope.test.ts` (5 — including a REAL second
137
+ HTTP server as the peer and a dead-peer degradation case), and
138
+ `tests/e2e/sessions-pool-scope-lifecycle.test.ts` (3 — real AgentServer,
139
+ feature alive single-machine). tsc + lint clean.
140
+
141
+ `tests/integration/secret-drop-store-first.test.ts` (5 route-level tests, both
142
+ sides of every boundary), `tests/unit/secret-store.test.ts` (keychain
143
+ pollution guard), `tests/unit/PostUpdateMigrator-secretDropHardenedRetrieve.test.ts`
144
+ (+3 migration tests), and the Tier-3 e2e
145
+ `tests/e2e/secret-drop-store-first-lifecycle.test.ts` — which boots two REAL
146
+ AgentServers on one stateDir and proves a secret submitted to process 1 is
147
+ retrievable from process 2 after a true restart. tsc + lint clean.
148
+
149
+ `tests/unit/TransferByNickname.test.ts` (+5, including the verbatim incident
150
+ case: already-on-target inside the rate window → noop) and
151
+ `tests/unit/seamlessnessConfig.test.ts` (+4, stage coupling both ways +
152
+ explicit-override both ways). tsc + lint clean. Production logs
153
+ (2026-06-05T04:20Z double pin, zero `exactly-once` lines on a live-transfer
154
+ pool) are the incident evidence.
@@ -0,0 +1,56 @@
1
+ # Approval-as-Data — the approval ledger (Phase 2), explained simply
2
+
3
+ ## What this is
4
+
5
+ Until now, when Justin approved something, that approval vanished the moment it
6
+ happened. "Approved" — and no memory of it. So the agent could never learn the
7
+ pattern of *when Justin agrees with its recommendation as-is* versus *when he changes
8
+ it*, and could never get better at recommending the thing he'd have picked anyway.
9
+
10
+ This change builds the **approval ledger**: every approval becomes a durable, signed
11
+ record. Each one is tagged as one of three things:
12
+
13
+ - **approved-as-is** — Justin took the recommendation exactly.
14
+ - **approved-with-change** — Justin approved, but changed something (and we record
15
+ *why* — the single most useful bit).
16
+ - **rejected** — Justin said no (also with the why).
17
+
18
+ From those records, the system computes a simple score per *kind* of decision: out of
19
+ all the decisions of this kind, what fraction did Justin take as-is? That fraction (the
20
+ "agreement ratio"), plus a "current streak" of consecutive as-is approvals, is the
21
+ signal that — much later, and only if Justin opts in — could let a class of low-risk
22
+ decisions auto-approve. That auto-approval part is NOT in this change; this is just the
23
+ memory + the scoreboard.
24
+
25
+ ## The restaurant analogy
26
+
27
+ Think of the agent as a sous-chef proposing dishes to the head chef (Justin). Today,
28
+ each "yes" or "change the sauce" is said out loud and then forgotten. The ledger is a
29
+ notebook where the sous-chef writes down every proposal and what the head chef did with
30
+ it — took it as-is, tweaked it (and the tweak), or sent it back. Over weeks, the notebook
31
+ reveals: "For pasta dishes he almost always takes my call; for desserts he usually
32
+ adjusts the sweetness." That's how the sous-chef learns to propose what the chef would
33
+ pick — and which calls the chef trusts him to just make.
34
+
35
+ ## The one rule that keeps it honest
36
+
37
+ The agent must **never decide for Justin** whether he agreed. Only Justin's *explicit*
38
+ words count: "go with your picks" = as-is; "change X because Y" = a change with that
39
+ reason. If Justin is silent or vague, nothing is recorded. And Justin can correct any
40
+ entry later (a correction is a new signed line, never a quiet edit). This is what stops
41
+ the agent from flattering itself by marking everything "approved-as-is."
42
+
43
+ ## What Justin asked for, and what changed mid-build
44
+
45
+ Justin asked for this, then made one correction while it was being built: the original
46
+ written design only tracked *official spec sign-offs*, but most of his approvals (like
47
+ picking A/A/B in chat) happen in conversation. So the ledger was generalized to track
48
+ approvals **wherever they occur** — a spec, a chat, anywhere — each tagged with where it
49
+ happened. Fittingly, that very correction became the ledger's first recorded
50
+ "change" entry: the first real data point is the feedback that shaped the feature.
51
+
52
+ ## What's safe about it
53
+
54
+ It only *reads and records* — it never blocks or changes any behavior. If the agent has
55
+ nowhere to store state, the feature simply isn't there (the API politely says
56
+ "unavailable") rather than breaking anything. Every record is signed so tampering shows.
@@ -0,0 +1,11 @@
1
+ # Mentor autoloop prompt: gate-compliance line
2
+
3
+ Instar has an automated "mentor loop" — a prompt that tells a developer agent how to run one cycle of dogfooding a mentee agent: check its health, assign it a real task, observe, and fix what breaks as a proper PR.
4
+
5
+ That prompt already teaches the ship discipline (three test tiers, the dev gate, verify-before-claim). But it said nothing about the repo's *ratchet gates* — CI checks like no-silent-fallbacks that count known-bad patterns and fail if the count ever goes UP.
6
+
7
+ We learned why that matters the hard way: a spec told the builder a helper should be "best-effort, never throws." The builder did exactly that — wrapped it in a catch that swallowed the error — and CI went red, because a swallowed catch is exactly what the no-silent-fallbacks ratchet counts. The spec's own wording invited the failure.
8
+
9
+ This change adds one paragraph to the mentor-loop prompt: an intentional fail-open catch must either report the failure (through DegradationReporter) or carry an inline `@silent-fallback-ok` justification — and you never bump a ratchet baseline just to get CI green. It also tells the mentor to spell these notes out whenever it authors a task brief or spec for another agent, so the next builder doesn't get trapped by well-meaning "never throws" guidance.
10
+
11
+ One prompt paragraph, three new test assertions locking it in. No behavior change anywhere else.
@@ -0,0 +1,51 @@
1
+ # ELI16 — Phase-3 parity monitor + cutover gate
2
+
3
+ ## What problem does this solve?
4
+
5
+ Before we flip the feedback system from Dawn's Portal to Instar (the "cutover" — a one-way
6
+ door), we run both processors side by side over real traffic for a while and check they
7
+ agree. That side-by-side check ("the parity comparison") already exists. What was missing is
8
+ the part that watches it *over time* and decides when it's genuinely safe to flip.
9
+
10
+ You can't trust a single green check. Traffic is bursty; one quiet minute proves nothing. We
11
+ need to see a real, sustained window where the two systems agreed on every report — and only
12
+ *then* allow the cutover. And crucially, the decision to flip must not come from an agent
13
+ "feeling confident" — it must come from an objective gate that an agent cannot fake.
14
+
15
+ ## What this change adds
16
+
17
+ A small, pure `ParityMonitor`:
18
+
19
+ - You feed it each comparison pass (how many clusters were compared, how many divergences).
20
+ - It tracks the current **zero-divergence streak**. The moment any pass diverges, the streak
21
+ resets to zero — so a single disagreement, even after a long clean run, sends us back to
22
+ the start. No "mostly agreed" hand-waving.
23
+ - It exposes one method, `gate(now)`, that returns **cleared** or **blocked** with a reason.
24
+ It clears only when the trailing run of passes is (a) all clean, (b) at least N passes
25
+ long, (c) spanning at least a real time window (default one hour), and (d) covering enough
26
+ clusters to be a meaningful sample. All four must hold.
27
+
28
+ That `cleared` boolean is the objective `parity-zero-divergence` condition. It's exactly what
29
+ the Coordination Mandate's "execute-cutover" authority reads: the agents can only flip the
30
+ one-way door when this gate — not their judgment — says the window is satisfied.
31
+
32
+ ## Why it's safe
33
+
34
+ Pure logic, no database, no network, no boot wiring. It only ever *reads* comparison results
35
+ and *computes* a yes/no; it changes nothing and triggers nothing on its own. It's the
36
+ building block the cutover executor will consult. 9 unit tests cover every gate boundary:
37
+ too-few passes, too-short window, too-few clusters, the satisfied window, and the streak
38
+ reset on any divergence (including re-clearing only after a fresh full clean window).
39
+
40
+ ## Plain-language risk
41
+
42
+ Near-zero, and the failure mode is conservative: if the policy is too strict, the gate just
43
+ stays *blocked* longer (cutover waits) — never the dangerous direction of clearing early.
44
+
45
+ ## Durability note
46
+
47
+ The "they agreed" window can take hours to build up. If we kept it only in memory, restarting
48
+ the server in the middle would silently wipe the streak and we'd have to start over (or worse,
49
+ mis-measure the window across the restart). So each check result is appended to a small log file
50
+ and reloaded when the monitor starts — the window survives restarts. A half-written final line
51
+ from a crash is skipped cleanly, so one bad line never corrupts the rest of the history.
@@ -0,0 +1,54 @@
1
+ # ELI16 — Phase-4 feedback-migration integrity tooling
2
+
3
+ ## What problem does this solve?
4
+
5
+ We're moving the "feedback factory" (the thing that catches user bug reports, groups
6
+ duplicates into clusters, and tracks each cluster's lifecycle) from Dawn's Portal over to
7
+ Instar. The cluster records aren't just data — they hold human and AI *judgment*: which
8
+ bug is which, what was already triaged, what was shipped. That curated judgment is
9
+ irreplaceable. If the move corrupts it, or if the new processor later overwrites it, we
10
+ lose work nobody can recreate.
11
+
12
+ Two specific dangers:
13
+
14
+ 1. **A silent bad copy.** "The row counts match" is far too weak a check — a single
15
+ cluster could come across with its status flipped or its governance note dropped and a
16
+ count check would never notice. We need to prove *every curated field of every row*
17
+ survived the move byte-for-byte.
18
+
19
+ 2. **A wrong-date backfill overwriting curated history.** After cutover, the processor is
20
+ only supposed to touch *new* reports. But if someone ever re-runs it over old data, it
21
+ would happily "re-cluster" the curated history and discard every triage decision.
22
+
23
+ ## What this change adds
24
+
25
+ Two small, pure, well-tested building blocks (no database, no network — just logic, so
26
+ they're fully unit-testable):
27
+
28
+ - **`importIntegrity.ts`** — the import gate. It computes a per-row checksum over every
29
+ curated field and compares source-vs-imported (catching silent corruption), scans the
30
+ source for two clusters sharing a fingerprint *before* importing (which would otherwise
31
+ abort the transaction or silently merge them), asserts the two schemas accept the same
32
+ status values and field types, checks that no feedback row points at a missing cluster
33
+ (referential integrity), and computes the auto-increment sequence reset so the next new
34
+ insert can't collide. `runIntegrityGate()` rolls all of that into one pass/fail.
35
+
36
+ - **`immutableGuard.ts`** — the structural "never re-derive" guard. Instead of *trusting*
37
+ the processor to only run over new traffic, we wrap the store: a cluster that predates
38
+ cutover, or that carries any governance note, is **immutable**, and any attempt to merge
39
+ into it, reopen it, or upsert over it is physically refused and recorded. A wrong-date
40
+ backfill therefore *cannot* overwrite curated state — the write simply does not happen.
41
+
42
+ ## Why it's safe
43
+
44
+ Both modules are pure functions plus one store decorator. The guard only ever *refuses*
45
+ writes (it never invents or changes data), and reads pass straight through. Nothing is
46
+ wired into the running server yet — these are the building blocks the Phase-4 cutover will
47
+ use. 36 new unit tests cover both sides of every boundary, including the processor running
48
+ over a guarded store and leaving a curated cluster's count, status, and note untouched.
49
+
50
+ ## Plain-language risk
51
+
52
+ Near-zero. Worst case if the guard is mis-tuned: a *legitimate* post-cutover merge is
53
+ refused and shows up in the violations list (loud, not silent) — far better than the
54
+ alternative of silently overwriting curated judgment.
@@ -0,0 +1,5 @@
1
+ # Respawn build-context restore
2
+
3
+ Developer agents can now remember the build checkout they were using before a respawn. When the feature is enabled and a resumed session had been working inside an agent worktree, the resumed conversation starts with a `[BUILD-CONTEXT RESTORE]` note pointing back to that worktree.
4
+
5
+ This is meant for fleet PR build sessions that die or restart mid-task. It does not move the tmux session's home directory, and it does nothing for normal home-only conversations. Stale or removed worktrees are skipped.
@@ -0,0 +1,82 @@
1
+ # Side-effects review — Approval-as-Data ledger (Phase 2)
2
+
3
+ Spec: `docs/specs/AUTONOMOUS-OPERATION-JUDGMENT-AND-APPROVAL-AS-DATA-SPEC.md` (Part B).
4
+ Change: new `src/core/ApprovalLedger.ts` + `POST/GET /approvals`, `GET /approvals/summary`
5
+ wired through `AgentServer` → `RouteContext`; Agent-Awareness blurb in the CLAUDE.md template.
6
+
7
+ ## 1. Blast radius
8
+ Additive only. A new module, three new route handlers, one new always-constructed field
9
+ on `AgentServer`, one new `RouteContext` field, one template blurb. No existing route,
10
+ store, sentinel, or gate is modified. The ledger never gates, blocks, throttles, or
11
+ mutates any other state — read paths are pure reads; the one write path appends to its
12
+ own JSONL file.
13
+
14
+ ## 2. State / data
15
+ New on-disk file `.instar/state/approval-ledger.jsonl` (append-only, signed). No schema
16
+ migration — the file is created on first write and absent until then. No existing file is
17
+ touched. Torn-trailing-line tolerant on read. Rows are HMAC-signed over `authToken`; an
18
+ empty/missing file yields an empty summary (no crash).
19
+
20
+ ## 3. Interactions
21
+ - `RouteContext` gains a REQUIRED `approvalLedger` field. The only production assembler is
22
+ `AgentServer` (updated). Route tests build `ctx: any` partials, so they are unaffected
23
+ (tsc confirms the whole tree compiles).
24
+ - Construction rides the existing `stateDir` availability (like `tokenLedger`); own
25
+ try/catch so an init failure can never cascade into the other ledgers.
26
+ - Shares no lock, queue, or budget with any other component.
27
+
28
+ ## 4. Failure modes
29
+ - No `authToken` → falls back to a fixed dev key for signing (integrity-only; documented).
30
+ Signing is never load-bearing for correctness — the operator-authoritative-source rule is.
31
+ - `stateDir` absent → `approvalLedger` is null → routes 503 (handled + tested).
32
+ - Inconsistent row (as-is WITH a divergence, or a change WITHOUT one) → `recordApproval`
33
+ throws → the route returns 400, not 500 (tested). Bad data cannot pollute ratios.
34
+ - Disk-full / write error on append → throws to the caller (route 400/500); no partial
35
+ corrupt state (single `appendFileSync`).
36
+
37
+ ## 5. Security / authority
38
+ - The load-bearing invariant is **operator-authoritative `mode` + `divergences`**: the
39
+ agent must not self-classify intent. Enforced by documentation + the design (the route
40
+ records what the caller passes; the caller must pass an explicit operator statement) and
41
+ backstopped by operator-correctable rows. HMAC signing gives integrity, NOT correctness —
42
+ it stops tampering, not ratio inflation; the authority rule stops inflation.
43
+ - All routes are Bearer-gated (standard middleware). Read routes never gate behavior.
44
+
45
+ ## 6. Performance
46
+ - O(rows) summary computation over a small append-only file read on each summary call.
47
+ At realistic volumes (tens to low-hundreds of approvals) this is negligible. No polling,
48
+ no background work, no LLM calls. Phase-3 (auto-approval, digest) is out of scope here.
49
+
50
+ ## 7. Migration parity
51
+ - No `.claude/settings.json` hook, `.instar/config.json` default, or hook-script change →
52
+ no `PostUpdateMigrator` entry required. The feature is server-side code that activates on
53
+ the next server start after update; existing agents get it by updating, with no on-disk
54
+ migration. Agent-Awareness IS satisfied: the CLAUDE.md template gained an Approval-as-Data
55
+ blurb (`generateClaudeMd`).
56
+ - Always-on when `stateDir` exists (read-only, low-cost) — no enable flag to migrate.
57
+
58
+ ## Tests
59
+ - Unit (`tests/unit/ApprovalLedger.test.ts`, 18): record/read/verify, tamper-reject, every
60
+ consistency-guard throw + its passing counterpart, ratio + streak (reset on change/reject),
61
+ auto-eligibility threshold edges, surface generality, corrections, torn-line tolerance.
62
+ - Integration (`tests/integration/approvals-routes.test.ts`, 6): full HTTP round-trip over a
63
+ real ledger; summary + surface breakdown; the 400 + 503 paths.
64
+ - E2E (`tests/e2e/approval-ledger-lifecycle.test.ts`, 5): real AgentServer boot, alive
65
+ (200 not 503), record→summary→list lifecycle, Bearer-gate, and a WIRING-INTEGRITY proof
66
+ that the production HMAC signer is real (persisted row verifies; a tamper fails).
67
+
68
+ ## Post-review amendments (same PR, pre-merge)
69
+
70
+ - **State-path fix:** the ledger file follows the `.instar/state/` convention —
71
+ `config.stateDir` IS `.instar`, durable state lives under `state/`
72
+ (`.instar/state/approval-ledger.jsonl`, matching the spec's stated path). The e2e
73
+ wiring-integrity test proves the corrected path end-to-end.
74
+ - **Ratchet exemptions:** the three deny-safe/default-empty catches carry
75
+ `@silent-fallback-ok` markers INSIDE the catch blocks (missing-file → empty
76
+ history; malformed signature → verifies false; init failure → reported via
77
+ console.warn + ledger null → routes 503).
78
+ - **Docs coverage:** the three `/approvals` routes are documented in
79
+ `site/src/content/docs/reference/api.md` (route-floor gate).
80
+ - **Discoverability:** the `/approvals` prefix is classified in
81
+ `CapabilityIndex.ts` (CAPABILITY_INDEX → surfaced in `/capabilities` with its
82
+ three endpoints), satisfying the capabilities-discoverability gate.
@@ -0,0 +1,43 @@
1
+ # Side-Effects Review — Mentor autoloop gate-compliance line
2
+
3
+ **Version / slug:** `autoloop-gate-compliance`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `echo second-pass checklist`
7
+
8
+ ## Summary of the change
9
+
10
+ Adds one static paragraph to `buildAutoloopGoal()` in `src/scheduler/MentorAutonomousGuardian.ts` — the deterministic prompt assembled for the autonomous mentor dogfooding loop. The paragraph teaches ratchet-gate compliance: intentional fail-open catches must report via DegradationReporter or carry an inline `@silent-fallback-ok` justification (never a baseline bump), and task briefs/specs authored for other agents must spell these notes out explicitly. Earned from PR #792's no-silent-fallbacks CI failure, where the spec's "best-effort, never throws" guidance invited the exact swallowed catch the ratchet counts.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `buildAutoloopGoal` — modified — one additional template line appended to the returned prompt string. Pure string assembly; no new branches, no I/O, no config.
15
+ - `tests/unit/MentorAutonomousGuardian.test.ts` — modified — three new content assertions on the assembled prompt.
16
+
17
+ ## 1. Over-block
18
+
19
+ None possible. The function returns a string; nothing is gated, blocked, or filtered. The added text instructs the *consuming agent*; it cannot prevent any operation by itself.
20
+
21
+ ## 2. Over-permit
22
+
23
+ None. No permission surface is touched.
24
+
25
+ ## 3. Token/cost impact
26
+
27
+ The prompt grows by ~430 characters, sent once per autonomous-fix guardian cycle (budget- and min-interval-gated, single-instance). Negligible.
28
+
29
+ ## 4. Behavior change for existing consumers
30
+
31
+ The only consumer is `MentorAutonomousGuardian` → spawned loop session goal text. Existing assertions on the prompt (cycle steps, discipline line, topics) are unchanged and still pass — the new line is purely additive. The `degrades gracefully when topics are unset` test still passes (the added text contains no topic interpolation).
32
+
33
+ ## 5. Failure modes
34
+
35
+ A string literal cannot throw at runtime. The TypeScript build verifies the template syntax. If the guidance itself were wrong, the blast radius is advisory-only (an agent following it would still produce gate-passing code — DegradationReporter and `@silent-fallback-ok` are both legitimate, documented paths in `tests/unit/no-silent-fallbacks.test.ts`).
36
+
37
+ ## 6. Migration parity
38
+
39
+ None required: the prompt is assembled at runtime from shipped code; every agent gets it on its next update through the normal release path. No installed files, hooks, config defaults, or templates change.
40
+
41
+ ## 7. Rollback
42
+
43
+ Revert the commit. No persisted state references the new text.