instar 1.3.607 → 1.3.609
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/server.d.ts.map +1 -1
- package/dist/commands/server.js +298 -31
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +22 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/coordination/AccountFollowMeMandateBridge.d.ts +56 -0
- package/dist/coordination/AccountFollowMeMandateBridge.d.ts.map +1 -0
- package/dist/coordination/AccountFollowMeMandateBridge.js +56 -0
- package/dist/coordination/AccountFollowMeMandateBridge.js.map +1 -0
- package/dist/core/AccountFollowMeDetector.d.ts +53 -0
- package/dist/core/AccountFollowMeDetector.d.ts.map +1 -0
- package/dist/core/AccountFollowMeDetector.js +56 -0
- package/dist/core/AccountFollowMeDetector.js.map +1 -0
- package/dist/core/AccountFollowMeEmailGate.d.ts +51 -0
- package/dist/core/AccountFollowMeEmailGate.d.ts.map +1 -0
- package/dist/core/AccountFollowMeEmailGate.js +50 -0
- package/dist/core/AccountFollowMeEmailGate.js.map +1 -0
- package/dist/core/AccountFollowMeOrchestrator.d.ts +98 -0
- package/dist/core/AccountFollowMeOrchestrator.d.ts.map +1 -0
- package/dist/core/AccountFollowMeOrchestrator.js +76 -0
- package/dist/core/AccountFollowMeOrchestrator.js.map +1 -0
- package/dist/core/AccountFollowMeService.d.ts +84 -0
- package/dist/core/AccountFollowMeService.d.ts.map +1 -0
- package/dist/core/AccountFollowMeService.js +105 -0
- package/dist/core/AccountFollowMeService.js.map +1 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +18 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/accountFollowMeDepth.d.ts +40 -0
- package/dist/core/accountFollowMeDepth.d.ts.map +1 -0
- package/dist/core/accountFollowMeDepth.js +47 -0
- package/dist/core/accountFollowMeDepth.js.map +1 -0
- 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/fetchPeerSubscriptionViews.d.ts +46 -0
- package/dist/core/fetchPeerSubscriptionViews.d.ts.map +1 -0
- package/dist/core/fetchPeerSubscriptionViews.js +70 -0
- package/dist/core/fetchPeerSubscriptionViews.js.map +1 -0
- package/dist/core/types.d.ts +37 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/AutonomousLivenessReconciler.d.ts +278 -0
- package/dist/monitoring/AutonomousLivenessReconciler.d.ts.map +1 -0
- package/dist/monitoring/AutonomousLivenessReconciler.js +660 -0
- package/dist/monitoring/AutonomousLivenessReconciler.js.map +1 -0
- package/dist/monitoring/ResumeQueue.d.ts +10 -0
- package/dist/monitoring/ResumeQueue.d.ts.map +1 -1
- package/dist/monitoring/ResumeQueue.js +12 -0
- package/dist/monitoring/ResumeQueue.js.map +1 -1
- package/dist/monitoring/guardManifest.d.ts.map +1 -1
- package/dist/monitoring/guardManifest.js +1 -0
- package/dist/monitoring/guardManifest.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +4 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +7 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +7 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +59 -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 +4 -0
- package/upgrades/1.3.608.md +29 -0
- package/upgrades/1.3.609.md +24 -0
- package/upgrades/side-effects/autonomous-liveness-reconciler.md +39 -0
- package/upgrades/side-effects/ws52-account-follow-me-pr2.md +59 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Side-Effects Review — AutonomousLivenessReconciler (self-heal a run marked active but with no live session)
|
|
2
|
+
|
|
3
|
+
**Spec:** docs/specs/autonomous-liveness-reconciler.md. **Constitutional principle served:** Structure > Willpower + "An autonomous run must outlive its session" — a level-triggered control loop replaces an edge-triggered heuristic that had a single-instant failure window.
|
|
4
|
+
**Ships DARK on the fleet** behind `monitoring.autonomousLivenessReconciler.enabled` (OMITTED in defaults → the dev-agent gate resolves it live-on-dev / dark-on-fleet) **and dryRun-first** (the component code-defaults `dryRun:true`). On the fleet the routes 503 and the loop never constructs/acts. On a dev agent the loop + route are live but only LOG "would respawn" until a deliberate `dryRun:false` flip.
|
|
5
|
+
**Files:** src/monitoring/AutonomousLivenessReconciler.ts (new), src/core/devGatedFeatures.ts, plus (pending in this branch) src/commands/server.ts, src/server/routes.ts, src/server/AgentServer.ts, src/config/ConfigDefaults.ts, src/core/PostUpdateMigrator.ts, src/scaffold/templates.ts, and the integration/e2e tests.
|
|
6
|
+
|
|
7
|
+
## What changed
|
|
8
|
+
|
|
9
|
+
1. **AutonomousLivenessReconciler.ts (new):** the level-triggered reconcile loop. Per tick it reads the active autonomous runs (reusing `activeAutonomousJobs` + `autonomousRunRemainingForTopic`), and for each evaluates 7 candidate criteria — active+remaining, NOT paused, NOT operator-stopped, NOT mid-machine-move, owned by THIS machine, NO live session, NOT already in the resume queue. A candidate must persist N consecutive ticks across a debounce window before action. Action = a respawn through the SAME spawn-with-resume primitive the ResumeQueueDrainer uses, bounded by a per-topic rolling-window cap (P19 loop brake) that gives up LOUDLY (one coalesced attention item) and posts one honest self-heal line.
|
|
10
|
+
2. **devGatedFeatures.ts:** registers `autonomousLivenessReconciler` (configPath `monitoring.autonomousLivenessReconciler.enabled`) so the dev-agent gate resolves it live-on-dev / dark-fleet.
|
|
11
|
+
3. **(pending) server.ts / AgentServer / routes.ts / ConfigDefaults / migrator / templates:** construct the loop behind the gate reusing the drainer's in-scope dep closures (`liveSessionForTopic`, `topicOwnerElsewhere`, `operatorStopSince`, quota), the `GET /autonomous/liveness` status route, the config block, and the migration + CLAUDE.md awareness.
|
|
12
|
+
|
|
13
|
+
## Blast radius
|
|
14
|
+
|
|
15
|
+
- **Config-gated + dryRun-first.** Fleet: `enabled` resolves false → the loop is never constructed, the route 503s, zero behavior change. Dev: `enabled` resolves true but `dryRun:true` → the loop runs and LOGS "would respawn" without spawning anything. Only a deliberate `dryRun:false` makes it actuate.
|
|
16
|
+
- **No new outbound path of its own.** A respawn reuses the existing spawn-with-resume primitive; the self-heal notice + the give-up attention item reuse the existing send/aggregated-attention plumbing.
|
|
17
|
+
- **Coordinates with, never races, the ResumeQueue.** Criterion 7 (not-already-queued) + the multi-machine ownership criterion ensure the edge-triggered queue stays first responder; the reconciler only catches what the queue missed, and only on the owning machine.
|
|
18
|
+
- **Cost is O(active runs) per tick** (reads run-state files + a tmux-liveness check), same class as the reaper. No whole-tree walk.
|
|
19
|
+
|
|
20
|
+
## Risk + mitigation
|
|
21
|
+
|
|
22
|
+
- **Risk:** the reconciler fights the reaper (respawns what was just deliberately killed). **Mitigation:** it acts ONLY when the run-state file still says active+remaining AND no operator-stop/pause is in effect — a deliberate stop sets those, excluding the run. Proven by the operator-stopped / paused unit cases.
|
|
23
|
+
- **Risk:** an infinite respawn loop on a run that keeps dying. **Mitigation:** the per-topic rolling-window cap (default 3/6h, durable across restarts) stops auto-respawn and raises ONE attention item. Proven by the loop-brake unit case.
|
|
24
|
+
- **Risk:** two machines both respawn the same run. **Mitigation:** the ownership criterion (only the owner reconciles) + the debounce window absorbing lease-move lag + the post-transfer closeout. Proven by the owner-elsewhere unit case.
|
|
25
|
+
- **Risk:** a transient gap (mid-recycle) triggers a needless respawn. **Mitigation:** the N-tick debounce across a window + criterion 7 (queue already handling it). Proven by the debounce-reset unit case.
|
|
26
|
+
- **Risk:** spawning under quota pressure. **Mitigation:** a per-respawn quota gate (skip + retry next tick). Proven by the quota unit case.
|
|
27
|
+
- **Direction of failure:** every dep read fails toward NOT acting (err toward "alive" / "owned elsewhere" / "stopped" / "queued"), so an uncertain read suppresses a respawn — the strictly-safe direction (a missed respawn is the status quo; a false respawn is bounded by the cap).
|
|
28
|
+
|
|
29
|
+
## Migration parity
|
|
30
|
+
|
|
31
|
+
- (pending) `migrateConfig` adds the `monitoring.autonomousLivenessReconciler` block (existence-checked); the CLAUDE.md template gains the awareness section + proactive trigger ("user asks why a run died / didn't come back"). devGatedFeatures registration is in. No hook/skill/settings change.
|
|
32
|
+
|
|
33
|
+
## Dark-gate line-map
|
|
34
|
+
|
|
35
|
+
- (pending) `ConfigDefaults.ts` adds the `monitoring.autonomousLivenessReconciler` block with `enabled` OMITTED (resolved by the dev-agent gate). `node scripts/lint-dev-agent-dark-gate.js` must stay clean (no hardcoded `enabled:false`); the golden-map drift-canary test will be updated for the new `enabled:`-free block's line shift.
|
|
36
|
+
|
|
37
|
+
## Rollback
|
|
38
|
+
|
|
39
|
+
- Revert the PR, or set `monitoring.autonomousLivenessReconciler.enabled:false` (or leave dryRun:true). The loop never constructs / never actuates; the durable cap-state file is inert. Byte-identical to pre-PR behavior when off.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Side-Effects Review — WS5.2 Account Follow-Me, PR2 (Mechanism B enroll-drive)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `ws52-account-follow-me-pr2`
|
|
4
|
+
**Date:** `2026-06-17`
|
|
5
|
+
**Author:** Echo (autonomous)
|
|
6
|
+
**Second-pass reviewer:** REQUIRED (high-risk: credentials, mandate authorization, cross-machine mesh delivery) — to be appended.
|
|
7
|
+
**Spec:** `docs/specs/ws52-account-follow-me-security.md` (converged 2026-06-13, approved)
|
|
8
|
+
**Status:** READY — the detection→consent flow is built, production-wired, and tested (37 tests: 35 unit across 7 modules + 2 Tier-2 integration over the real HTTP pipeline; tsc clean). PR2 ships the detection/consent/offer surface; the email-gate-at-completion (S7) wiring + the router `locallyExecutable` gate are PR3 (selection-safety) <!-- tracked: CMT-1620 --> (the email-gate LOGIC is already built + unit-tested here; only its completion-flow wiring is PR3). Revocation is PR4 <!-- tracked: CMT-1620 -->.
|
|
9
|
+
|
|
10
|
+
## Summary of the change
|
|
11
|
+
|
|
12
|
+
PR2 builds Mechanism B (re-mint per machine) account enrollment — the "one approval per machine, ToS-safe" flow. Per OQ6 (resolved per the spec's lean + the 2-machine topology) the transport is **per-server operator-side selection**, not a new credential-adjacent mesh verb. PR2 ships the decision/orchestration logic (built, unit-tested) + the server-shell wiring (pending).
|
|
13
|
+
|
|
14
|
+
Files added (all unit-tested, dark behind `multiMachine.accountFollowMe`):
|
|
15
|
+
- `src/core/AccountFollowMeOrchestrator.ts` — §5.2 request-never-self-authorize: depth-zero → MandateGate.evaluate(`account-follow-me`) → deny/no-mandate ⇒ phone-first consent (never proceed/CLI); allow ⇒ proceed.
|
|
16
|
+
- `src/core/AccountFollowMeEmailGate.ts` — §5.3/S7 email-validation-before-selectable (fail-closed; HIGH attention item on mismatch).
|
|
17
|
+
- `src/core/AccountFollowMeDetector.ts` — depth-zero offer detection, R7-bounded (per-account max-follow cap, one-per-(account,target), in-flight dedup).
|
|
18
|
+
- `src/coordination/AccountFollowMeMandateBridge.ts` — R4a cross-machine mandate package/accept via PR1's Ed25519 signMandateIssuance/verifyMandateIssuance.
|
|
19
|
+
- `src/core/AccountFollowMeService.ts` — composes the above: `scanAndOffer()` (one aggregated consent, enrolls nothing) + `onMandateDelivered()` (verify → allow → enroll-drive instruction).
|
|
20
|
+
- `src/core/accountFollowMeDepth.ts` — pure adapter: per-machine pool views → detector input (usable = locallyHeld + active/warming; meta-only ⇒ depth-zero).
|
|
21
|
+
- `src/core/fetchPeerSubscriptionViews.ts` — extracts the `?scope=pool` fan-out into a tolerant, injectable peer-views fetcher (dark peers skipped, never throws).
|
|
22
|
+
- `src/server/routes.ts` — `POST /subscription-pool/follow-me/scan` (dark→503; enabled→detect depth-zero peers→ONE aggregated consent attention item, enrolls nothing) + an optional `accountFollowMePeerViews` RouteContext field.
|
|
23
|
+
- `src/server/AgentServer.ts` + `src/commands/server.ts` — thread + construct the real peer-views fetcher (listPoolMachines + fetchPeerSubscriptionViews, authToken).
|
|
24
|
+
- `tests/integration/account-follow-me-scan-route.test.ts` — Tier-2 over the real HTTP pipeline (dark→503; enabled→detect+one-consent).
|
|
25
|
+
- 37 tests total (35 unit across 7 modules + 2 Tier-2).
|
|
26
|
+
|
|
27
|
+
## The eight side-effect questions (for the built decision logic)
|
|
28
|
+
|
|
29
|
+
1. **Over-block** — The detector only offers to DEPTH-ZERO machines and caps per account; a machine that already serves is never offered, and the cap can suppress a legitimate offer past N machines (intended R7 bound, operator-tunable). No legitimate enrollment is silently lost — it's surfaced as consent or capped-by-policy.
|
|
30
|
+
2. **Under-block** — PR2 logic does not itself perform the credential write (the server-shell does, pending); the at-rest residual / revocation (R10/R12) is PR4, tracked. The orchestrator denies by default, so the under-block risk (enrolling without authorization) is structurally closed at the decision layer.
|
|
31
|
+
3. **Level-of-abstraction fit** — Decision logic is pure + injectable (no I/O), mirroring PR1's primitives; side effects (attention item, EnrollmentWizard drive, SubscriptionPool.add) are injected so the server-shell owns I/O. Correct layering.
|
|
32
|
+
4. **Signal vs authority** — The orchestrator + bridge are AUTHORITIES (they gate a credential enrollment) but are NOT brittle: authorization delegates to the existing PIN-gated MandateGate + the R4a asymmetric signature, and every path FAILS CLOSED. No brittle check holds blocking authority; deny-by-default throughout.
|
|
33
|
+
5. **Interactions** — Reuses PR1's CrossMachineMandate (no duplication) + the existing MandateGate (action-agnostic, no change needed) + the existing EnrollmentWizard/enroll routes (no fork). The `account-follow-me` action is a new string in the existing gate — no schema change.
|
|
34
|
+
6. **External surfaces** — Dark on fleet. The consent surface is a phone-first dashboard deep-link, never a CLI instruction. The aggregated consent is ONE attention item (P17), never per-machine spam. No credential or token is in any surface the logic produces.
|
|
35
|
+
7. **Multi-machine posture** — This IS the multi-machine feature. Mandate authority crosses via the R4a asymmetric signature (verified-operator binding); the credential is re-minted per machine (never replicated). Operator-rooted, not peer-quorum. Single-machine = no-op (no depth-zero peers).
|
|
36
|
+
8. **Rollback cost** — Low. Dark behind `multiMachine.accountFollowMe`; revert the PR. No data migration (no live credential written by PR2's logic layer). The server-shell increment carries its own rollback once added.
|
|
37
|
+
|
|
38
|
+
## Wired-surface notes (questions 2/6/8 for the shipped detection surface)
|
|
39
|
+
|
|
40
|
+
- **Under-block (2):** the scan route only SURFACES consent (enrolls nothing); the credential write stays in the existing operator-driven enroll route. The email-gate (S7) validating a completed enrollment is PR3 <!-- tracked: CMT-1620 --> — until then a follow-me enrollment relies on the operator approving on the target's own dashboard (the existing, already-shipped enroll flow). No new credential path is opened by PR2.
|
|
41
|
+
- **External surfaces (6):** the scan route fetches peers' PLAIN `/subscription-pool` (Bearer `config.authToken`, 4s timeout, dark-peer-tolerant) — same auth + tolerance posture as the existing `?scope=pool` / `/guards` fan-out. It surfaces ONE aggregated attention item (category `account-follow-me`), never per-machine spam. Dark on fleet (resolveDevAgentGate → 503).
|
|
42
|
+
- **Rollback (8):** dark behind `multiMachine.accountFollowMe`; revert the PR. No data migration; no credential written by the detection surface. The `accountFollowMePeerViews` ctx field + server wiring are additive/optional.
|
|
43
|
+
|
|
44
|
+
## Pending for PR3/PR4 (tracked)
|
|
45
|
+
|
|
46
|
+
- PR3 <!-- tracked: CMT-1620 -->: wire the email-gate at enrollment completion (S7) + the router `locallyExecutable` gate (§6.2).
|
|
47
|
+
- PR4 <!-- tracked: CMT-1620 -->: revocation (R12).
|
|
48
|
+
|
|
49
|
+
## Second-pass review
|
|
50
|
+
|
|
51
|
+
**Verdict: Concur with the review.** (Independent reviewer subagent, 2026-06-17; ran 35 unit + 2 integration tests green + `tsc --noEmit` clean.)
|
|
52
|
+
|
|
53
|
+
Verified the four focus areas:
|
|
54
|
+
- **(a) No self-authorization path** — `requestEnrollment` short-circuits to consent BEFORE the gate when no mandateId; only returns proceed on an explicit gate `allow`. `scanAndOffer` never passes a mandateId (structurally consent-only). `onMandateDelivered` requires the R4a asymmetric verify AND the real MandateGate (authorship/expiry/revocation/named-party/bounds). Deny-by-default holds.
|
|
55
|
+
- **(b) No credential leak** — the peer fetch hits each peer's PLAIN `/subscription-pool` (no scope=pool recursion), projects only id/email/status, discards configHome; SubscriptionAccount structurally cannot carry a token; consent/attention surfaces are metadata-only.
|
|
56
|
+
- **(c) Dark-default genuinely inert** — scan route 503s on the fleet via resolveDevAgentGate; integration test asserts it.
|
|
57
|
+
- **(d) No fail-open bugs** — meta-only never counts usable; a dark peer can't make a held machine read depth-zero; email-gate + mandate-verify fail closed; the R7 cap is order-independent.
|
|
58
|
+
|
|
59
|
+
Two non-blocking notes for the PR3+ author (NOT PR2 defects — PR2 never reaches these): the route wires `agentFp` to `ctx.config.projectName ?? 'self'`, which must match the named agent party once the real mandate-delivered flow lands in PR3; and the plain `/subscription-pool` route serializes `configHome` (a path, never a token; pre-existing, Bearer-gated) which the PR2 fetcher correctly discards.
|