instar 1.3.339 → 1.3.340

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 (54) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +166 -10
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +17 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/AutonomousSessions.d.ts +17 -2
  8. package/dist/core/AutonomousSessions.d.ts.map +1 -1
  9. package/dist/core/AutonomousSessions.js +30 -4
  10. package/dist/core/AutonomousSessions.js.map +1 -1
  11. package/dist/core/CoherenceJournal.d.ts +326 -0
  12. package/dist/core/CoherenceJournal.d.ts.map +1 -0
  13. package/dist/core/CoherenceJournal.js +999 -0
  14. package/dist/core/CoherenceJournal.js.map +1 -0
  15. package/dist/core/CoherenceJournalReader.d.ts +158 -0
  16. package/dist/core/CoherenceJournalReader.d.ts.map +1 -0
  17. package/dist/core/CoherenceJournalReader.js +450 -0
  18. package/dist/core/CoherenceJournalReader.js.map +1 -0
  19. package/dist/core/JournalSyncApplier.d.ts +272 -0
  20. package/dist/core/JournalSyncApplier.d.ts.map +1 -0
  21. package/dist/core/JournalSyncApplier.js +835 -0
  22. package/dist/core/JournalSyncApplier.js.map +1 -0
  23. package/dist/core/StateManager.d.ts +41 -0
  24. package/dist/core/StateManager.d.ts.map +1 -1
  25. package/dist/core/StateManager.js +100 -0
  26. package/dist/core/StateManager.js.map +1 -1
  27. package/dist/core/types.d.ts +35 -0
  28. package/dist/core/types.d.ts.map +1 -1
  29. package/dist/core/types.js.map +1 -1
  30. package/dist/messaging/TelegramAdapter.d.ts +14 -0
  31. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  32. package/dist/messaging/TelegramAdapter.js +16 -1
  33. package/dist/messaging/TelegramAdapter.js.map +1 -1
  34. package/dist/scaffold/templates.d.ts.map +1 -1
  35. package/dist/scaffold/templates.js +7 -0
  36. package/dist/scaffold/templates.js.map +1 -1
  37. package/dist/server/routes.d.ts.map +1 -1
  38. package/dist/server/routes.js +54 -3
  39. package/dist/server/routes.js.map +1 -1
  40. package/package.json +2 -2
  41. package/scripts/lint-cas-emit-placement.js +87 -0
  42. package/scripts/lint-journal-actuation-ban.js +63 -0
  43. package/scripts/lint-state-registry.js +313 -0
  44. package/src/data/builtin-manifest.json +46 -46
  45. package/src/data/state-coherence-registry.json +880 -0
  46. package/src/scaffold/templates.ts +7 -0
  47. package/upgrades/1.3.340.md +132 -0
  48. package/upgrades/coherence-journal-p1-1.eli16.md +11 -0
  49. package/upgrades/coherence-journal-p1-2.eli16.md +11 -0
  50. package/upgrades/coherence-journal-p1-3.eli16.md +13 -0
  51. package/upgrades/side-effects/coherence-journal-p1-1.md +68 -0
  52. package/upgrades/side-effects/coherence-journal-p1-2.md +54 -0
  53. package/upgrades/side-effects/coherence-journal-p1-3.md +49 -0
  54. package/upgrades/1.3.339.md +0 -48
@@ -419,6 +419,12 @@ This routes feedback to the Instar maintainers automatically. Valid types: \`bug
419
419
  - Also: when a session is autonomously shut down, you get a "your session was shut down — <reason>" notice (recovery-bounces and your own operator kills stay silent). Turn the notice off with \`{"monitoring": {"reapNotify": {"enabled": false}}}\`.
420
420
  - Proactive: user asks "where did my session go?" / "why did X disappear?" / "did something get killed?" → GET /sessions/reap-log and explain the most recent reaped/skipped entries for that session.
421
421
 
422
+ **Coherence Journal** — The durable "what happened where, and where are the files?" answer for a multi-machine agent. Every machine writes append-only event streams (topic placement + why it moved, session open/close/reap, autonomous runs + their artifact paths); the read API serves a merged view so you answer placement/artifact questions from local disk instead of grepping rotating logs on the right machine.
423
+ - Read it: \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/coherence/journal?topic=N&kind=topic-placement&limit=50"\` → \`{ entries: [...], streams: {...}, skippedCorrupt }\` (+ a partial-result flag when a read bound was hit). Filters: \`topic\`, \`kind\` (\`topic-placement\`|\`session-lifecycle\`|\`autonomous-run\`), \`machine\`, \`limit\`, \`cursor\`. Read-only; 503 when the journal is not enabled on this agent.
424
+ - TRUST NOTE: entries tagged \`source: "replica"\` are another machine's copied history — always a little stale (\`stalenessMs\` says how much). NEVER make a kill/spawn/move decision off journal data; it answers questions, the live systems decide.
425
+ - Degraded mode: the streams are plain JSONL under \`state/coherence-journal/\` — readable directly when HTTP is starved.
426
+ - Proactive: user asks "which machine was topic N on?" / "why did this conversation move?" / "where are the overnight run's files?" / "did the old machine close its session after the move?" → GET /coherence/journal with the topic filter and answer from the entries.
427
+
422
428
  **🩺 Agent Health lane (calm self-health notices)** — Routine notices about MY OWN internal state (a session that looks stuck, a peer I can't reach) land in ONE calm, named "🩺 Agent Health" Telegram topic — never topic-after-topic. Each is normal-priority (not a user-critical alert), names the topic in plain language (e.g. "the 'EXO 3.0' session", never \`topic-19077\`), ends with a next step you can just reply to, and same-session re-escalations are de-duped so the lane stays quiet. Ships **default-on, no config** (it's a delivery-shaper in code — it never gates or drops anything; every notice is still in the attention store). Tune via \`messaging[].config.agentHealthLane\` = \`{ "enabled": true, "topicName": "🩺 Agent Health", "dedupWindowMs": 1800000 }\` (set \`enabled:false\` for the old per-item-topic behavior). Proactive: user asks "what's this Agent Health topic?" / "why are my stale-session notices grouped?" → explain the calm lane (the StaleSessionBackstop now routes its "looks stuck" heads-up here at normal priority instead of spawning a topic each time).
423
429
 
424
430
  **Applying config & hook changes to running sessions** — A running session keeps the config it was *spawned* with. Claude Code loads \`.claude/settings.json\` (hooks, model) **once, at session start** — so a config change (default model, a disabled feature) or a newly-added hook does NOT reach an already-running session. It only takes effect on the next session, OR when you restart the existing one. (This is why a UserPromptSubmit hook added mid-session never fires for that live session — the session was launched before the hook existed.)
@@ -843,6 +849,7 @@ I maintain registries that are the source of truth for specific categories. Thes
843
849
  | What have I learned? | \`.instar/MEMORY.md\` |
844
850
  | What jobs do I have? | \`.instar/jobs.json\` or \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/jobs\` |
845
851
  | Who have I interacted with? | \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/relationships\` |
852
+ | Which machine was topic N on / where are a run's artifacts? | \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/coherence/journal?topic=N"\` (multi-machine placement + artifact history; 503 = journal not enabled) |
846
853
  | My configuration? | \`.instar/config.json\` |
847
854
  | My identity/principles? | \`.instar/AGENT.md\` |
848
855
  | My past learnings about X? | \`curl -H "Authorization: Bearer $AUTH" "http://localhost:${port}/memory/search?q=X"\` |
@@ -0,0 +1,132 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ **Coherence Journal P1.1** (COHERENCE-JOURNAL-SPEC, converged + approved):
9
+ every machine now writes per-kind append-only event streams under
10
+ `state/coherence-journal/` — `topic-placement` (emitted at all 8
11
+ ownership-CAS sites with caller-known reasons, paired by a new CI lint),
12
+ `session-lifecycle` (derived at the saveSession funnel; `reaped` emitted
13
+ beside the reap-log), `autonomous-run` (60s observer + stop-funnel seam —
14
+ no phantom-live runs). Writer is non-blocking (memory enqueue + 250ms
15
+ flusher; zero sync I/O in caller stacks), crash-safe (repair-counted
16
+ truncation, incarnation-fenced restore detection), single-process-locked,
17
+ schema-typed with artifactPath jail. Plus: the State-Coherence Registry is
18
+ now machine-readable (`src/data/state-coherence-registry.json`, 66
19
+ categories) with `lint-state-registry` failing CI on undeclared durable
20
+ stores. Dark-ship: `multiMachine.coherenceJournal.enabled ?? developmentAgent`.
21
+
22
+ **Coherence Journal P1.2** — the read API. `GET /coherence/journal` serves
23
+ the merged placement / session-lifecycle / autonomous-run history from
24
+ local disk: skew-proof `(epoch,ts)` ordering for placement, replica entries
25
+ labeled with `source:"replica"` + `stalenessMs`, `(topic,epoch)` dedupe,
26
+ bounded reverse-tail reads (byte ceiling + archive caps; placement stays
27
+ answer-complete), opaque keyset cursors, corrupt lines skipped + counted.
28
+ New `lint-journal-actuation-ban` build-enforces §3.9 (actuators may not
29
+ import the reader). CLAUDE.md template teaches every agent the capability.
30
+ TelegramAdapter emergency-stop now reports its journal line instantly.
31
+
32
+ **Coherence Journal P1.3 (apply/serve engine)** — `JournalSyncApplier`,
33
+ the pure mesh-independent receive+serve engine for journal replication
34
+ (COHERENCE-JOURNAL-SPEC §3.4): first-hop sender binding, schema-validated
35
+ apply with suspect-self-clear, incarnation-fenced restore detection with
36
+ bounded quarantine, truncation gap signals, ack-after-fdatasync on receive,
37
+ and durably-flushed-only own-stream serve. The `journal-sync` mesh verb +
38
+ session-status advert + the live two-machine proof are the closing wiring
39
+ step (the engine ships ahead of the network exposure, fully tested).
40
+
41
+ Adds a **learning-velocity metric** — Salim Ismail's EXO 3.0 KPI inversion (from
42
+ *Your KPI System Is Training You to Miss the Future*). Backward-looking
43
+ operational KPIs (throughput, utilization, efficiency) reward the existing model
44
+ and suppress the weak signals where the future shows up. The EXO 3.0 answer is to
45
+ measure how fast you're **learning** — adaptability, experimentation, capability
46
+ creation.
47
+
48
+ Instar already emits the raw learning events (registered learnings, captured
49
+ corrections, evolution actions); this turns them into a signal:
50
+
51
+ - `GET /metrics/learning-velocity?windowDays=30` → `{ totalEvents, eventsPerDay,
52
+ byType, typeDiversity, trend, adaptabilityScore, reason }`.
53
+ - `trend` is `accelerating` | `steady` | `declining` | `insufficient-data`
54
+ (first-half vs second-half of the window).
55
+ - `adaptabilityScore` (0–100) blends velocity (saturating) with category
56
+ diversity.
57
+
58
+ Read-only + advisory — it never gates anything. A flat or declining trend is the
59
+ EXO 3.0 warning sign that the org is optimizing the old model instead of learning.
60
+
61
+ ## What to Tell Your User
62
+
63
+ Nothing user-visible yet — this is the foundation layer. Your agent's
64
+ machines have started keeping reliable local "diaries" of where
65
+ conversations live, when sessions open/close, and where autonomous runs
66
+ put their files. The pieces that let you ASK about that history from any
67
+ machine arrive in the next two updates (the query API, then
68
+ machine-to-machine sync).
69
+
70
+ If your agent runs on more than one machine, you can now ask it "which
71
+ machine was this conversation on last night, and why did it move?" or
72
+ "where did the overnight run put its files?" — and it answers from a
73
+ durable history instead of guessing. (Multi-machine sync of those
74
+ histories lands in the next update; today each machine answers from what
75
+ it holds.)
76
+
77
+ Nothing user-visible changes yet — this is the engine that will let your
78
+ agent's machines safely exchange their diaries. Once the final wiring lands,
79
+ asking ANY machine "where did this conversation live / where are the
80
+ overnight files?" will answer from a synced history. Today the engine is in
81
+ place and proven; the cross-machine exchange turns on with the next step.
82
+
83
+ Your agent can now answer "are we actually learning, or just running?" with real numbers. Ask it for its learning velocity and you get a trend — accelerating, steady, or declining — built from its genuine learning events (lessons it recorded, corrections it absorbed, capabilities it grew) instead of backward-looking activity stats. The EXO 3.0 idea behind it: traditional KPIs measure how well the OLD model runs; learning velocity measures whether you're building the next one. A flat or declining trend is your early warning that things are coasting.
84
+
85
+ ## Summary of New Capabilities
86
+
87
+ - None user-invocable yet (P1.2 ships `GET /coherence/journal` + the
88
+ agent-facing docs). Internal: `CoherenceJournal` writer,
89
+ `StateManager.guardJournalWrite`, machine-readable state registry, two
90
+ new CI lints.
91
+
92
+ - `GET /coherence/journal?topic=N&kind=...&machine=...&limit=...&cursor=...`
93
+ — merged journal view; read-only; 503 when the journal is not enabled.
94
+ - Agents proactively reach for it on "where did topic N live / where are
95
+ the artifacts?" questions (CLAUDE.md template entry ships in this
96
+ release).
97
+
98
+ - None user-invocable yet (the engine is internal; the `journal-sync`
99
+ transport that drives it is the closing wiring step). Internal:
100
+ `JournalSyncApplier` (receive+serve engine for §3.4 replication).
101
+
102
+ - `GET /metrics/learning-velocity?windowDays=30` — `{ totalEvents, eventsPerDay, byType, typeDiversity, trend, adaptabilityScore (0-100), reason }`, computed from registered learnings, corrections, and evolution actions. Read-only + advisory — never gates.
103
+ - PROACTIVE trigger: "are we learning/adapting?" → read this metric and contrast it with operational throughput.
104
+
105
+ ## Evidence
106
+
107
+ - 56 new tests (writer 33 incl. fault-injected non-blocking emit +
108
+ kill-9-window re-mint precision; wiring 9 with independent oracles;
109
+ guard 7; registry lint 7); 357 tests green across the affected surface;
110
+ both lints clean on the real tree; tsc clean.
111
+ - The cas-pairing lint caught a real unpaired site (POST /pool/transfer
112
+ release) during development — the structural guard works.
113
+
114
+ - 22 new reader/route tests + Tier-3 e2e lifecycle (feature-alive, 503
115
+ when dark); actuation-ban lint clean over 8 actuator modules; tsc + full
116
+ lint chain clean.
117
+
118
+ - 26 new tests covering every §3.4 rule (seq-gating, forged-entry reject,
119
+ suspect→self-clear, incarnation quarantine bounds + reset-flapping,
120
+ truncation fast-forward, ack-after-fsync ordering via injected spy,
121
+ guardWrite refusal). tsc + full lint chain clean.
122
+
123
+ Three-tier coverage, all green, `tsc --noEmit` clean:
124
+
125
+ - Unit — `LearningVelocityScorer.test.ts` (6): empty, window exclusion,
126
+ accelerating, declining, insufficient-data, and byType/diversity/adaptability.
127
+ - Integration — `learning-velocity-routes.test.ts` (3): the route reads a real
128
+ `learning-registry.json` + corrections over HTTP and computes.
129
+ - E2E — `learning-velocity-lifecycle.test.ts` (1): a real server on a real port,
130
+ feature alive end-to-end (200, not 404/503).
131
+
132
+ CLAUDE.md scaffold template documents the endpoint.
@@ -0,0 +1,11 @@
1
+ # The diary starts writing (P1.1 of the coherence journal)
2
+
3
+ This is the build half of the spec you approved tonight: every machine now actually KEEPS the diary. Three kinds of entries get written automatically — "this conversation was placed/moved here (and why)", "a work session opened/closed/was reaped", and "an autonomous run started/stopped here, its files are at these paths". Nothing reads them across machines yet (that's the next two PRs: the question-answering API, then machine-to-machine swapping) — this PR is the foundation that makes those possible: reliable, cheap, tamper-resistant local diaries.
4
+
5
+ The seatbelts from the review are all real code now, each with a named test: writing a diary line never touches the disk in the hot path (it's an instant memory hand-off; a background helper saves batches four times a second — a fault-injection test wedges the disk and proves the hand-off still returns instantly). A crash can only lose the last quarter-second, and a half-written line is repaired and COUNTED on restart. Restore-from-backup is detected precisely (the "edition number" mechanism — an ordinary crash can never false-trigger it, proven by a test that kills the writer at the exact worst moment). Only one process on a machine may write (a second one locks out, loudly — visible in status, not silently). Every line must match a strict template; free text, secrets, oversized entries, and path-escape tricks are rejected at the door.
6
+
7
+ Three things make the wiring trustworthy rather than hopeful: (1) session open/close events are derived at the ONE place every status change already passes through, so no future code can forget to record one; (2) every one of the 8 places that can change "which machine owns this conversation" is paired with its diary write, and a NEW build-time check fails CI if anyone ever adds a 9th without the pairing — it caught a site I'd missed within seconds of existing; (3) autonomous runs are watched by a small once-a-minute observer, so even a run that dies by crash or reboot gets its "stopped" line — no phantom forever-running jobs.
8
+
9
+ Also in this PR: the census from P0 becomes machine-readable (all 66 state categories) with its own CI check — new code that writes durable state without declaring it in the registry fails the build. That's the "nothing becomes invisible-machine-local by accident again" guarantee, live.
10
+
11
+ Ships dark on the fleet, live on me. Existing agents get the config automatically on update. One honest note: a stop issued through the Telegram path gets its diary line from the observer (up to a minute late) rather than instantly — the direct hookup there needs a wider change that rides the next PR.
@@ -0,0 +1,11 @@
1
+ # The diary becomes answerable (P1.2 of the coherence journal)
2
+
3
+ P1.1 made every machine KEEP the diaries; this makes them ANSWERABLE. One new read endpoint serves the question this project was born from: "which machine was conversation X on last night, why did it move, and where did the overnight run put its files?" — answered from local disk, merged across every diary the machine holds.
4
+
5
+ The answers are engineered not to lie. Cross-machine ordering uses the placement epoch (a counter that can't disagree between machines) instead of wall-clocks, so two machines with slightly different clocks can't make history look like a conversation was in two places at once — the exact confusion you'd be diagnosing. Copied diaries from other machines are labeled as copies with their staleness in milliseconds, so nothing ever mistakes a replica for live truth. Duplicate move records (from operation retries) collapse to one. A corrupted line degrades the answer and says so — it never crashes the query.
6
+
7
+ The reads can't hurt a loaded box: newest-first with hard ceilings on bytes scanned, an honest "partial result" flag when a bound is hit, and the one exemption the review demanded — placement history (tiny, kept forever) is always answer-complete, so old history doesn't become unreachable just because it's old.
8
+
9
+ Two structural guards ride along. First, the reader is a deliberately separate module from the writer, and a new CI lint BANS every session-killing/spawning/moving module from importing it — "the diary never drives actions" is now build-enforced, not promised. Second, every agent's own documentation teaches the new endpoint (capability awareness rule): the moment this ships, agents know to reach for it when you ask "where did this conversation live?"
10
+
11
+ Also closed: the one stop-path from P1.1 that relied on the once-a-minute observer (emergency stops via Telegram) now reports instantly. Tier-3 boot test proves the feature is genuinely alive in a production-shaped server, not just in unit tests.
@@ -0,0 +1,13 @@
1
+ # The diaries start syncing between machines (P1.3 — the apply engine)
2
+
3
+ This is the piece that finally answers your EXO question from EITHER machine. P1.1 made each machine keep its diaries; P1.2 made them readable; P1.3 lets machines safely exchange copies — so when you ask the Laptop "where did the Mini's overnight run put its files?", the Laptop actually knows, because it holds a copy of the Mini's diary.
4
+
5
+ The hard part of syncing isn't the copying — it's not getting fooled. This is the receive-and-serve ENGINE, built with every defense the review demanded as real, tested code:
6
+
7
+ - **A machine can only hand over ITS OWN diary.** Every incoming line must be signed (at the transport layer) by the same machine it claims to be from; a machine trying to pass off a third machine's history is rejected and counted. So one confused or compromised machine cannot rewrite everyone's records.
8
+ - **Every line is checked before it's saved** — right size, right sequence number (exactly the next one expected), valid shape. A corrupted line marks that one peer's stream "suspect" and stops there; it self-clears once the peer sends 20 clean lines in a row. A torn line from one peer can never poison the whole picture.
9
+ - **Restore-from-backup is caught.** If a machine comes back from an old backup with its diary rewound, the "edition number" changes, the old copy is set aside (at most two kept, so a flapping machine can't fill the disk), and it's flagged loudly — instead of silently swallowing the machine's real new history forever.
10
+ - **Gone-history is honest.** If a machine asks for diary lines that have aged out, it gets told "those were pruned" and records a visible gap, rather than asking forever for something that no longer exists.
11
+ - **A copy isn't trusted until it's truly on disk.** The receiver saves and force-flushes a batch BEFORE it reports success — so a crash mid-sync can never leave a machine believing it has lines it actually lost.
12
+
13
+ This PR is the engine and its 26 tests; the last wiring step — actually carrying the little "I'm at line N" notes on the existing 30-second machine check-in and pulling deltas — plus the live two-machine proof on your Laptop+Mini, is the closing step. The engine is deliberately built to be driven by that wiring without knowing anything about the network: pure, testable, and impossible to make the mistakes the review caught on paper.
@@ -0,0 +1,68 @@
1
+ # Side-Effects Review — Coherence Journal P1.1 (writer core + emission wiring + registry lint)
2
+
3
+ **Version / slug:** `coherence-journal-p1-1`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required as a PR-time pass — the DESIGN went through 4-round multi-reviewer convergence (security/scalability/adversarial/integration/lessons + codex-cli:gpt-5.5 external, report at docs/specs/reports/coherence-journal-convergence.md) and this implementation tracks that converged spec section-by-section; deviations are enumerated below`
7
+
8
+ ## Summary of the change
9
+
10
+ Implements P1.1 of `docs/specs/COHERENCE-JOURNAL-SPEC.md` (converged, `approved: true`, Justin 2026-06-05): `CoherenceJournal` writer class (non-blocking enqueue-assigned seq, 250ms flusher, advisory lock, typed per-kind schemas, artifactPath jail, restart-proof op-key dedupe, incarnation + crash-safe highWaterSeq, per-kind rotation incl. rotate-never-delete); emission wiring — `StateManager.saveSession` status-diff funnel (session-lifecycle), `emitPlacement` paired at all 8 ownership-CAS call sites (server.ts ownAction ×4, router place/claim, transfer-planner release, POST /pool/transfer release), reaper `reaped` emit beside the reap-log append, autonomous-run scanner (60s) + stop-funnel seam; `StateManager.guardJournalWrite` (standby-safe, prefix-allowlisted); `src/data/state-coherence-registry.json` (66 census categories) + `scripts/lint-state-registry.js` and `scripts/lint-cas-emit-placement.js`, both chained in `package.json` lint; ConfigDefaults + types (dark-ship: `enabled ?? !!developmentAgent`).
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `StateManager.guardJournalWrite` — ADD — permits journal-prefix writes on a read-only standby (independent of `_sessionPoolActive`); REFUSES paths escaping the canonicalized journal prefix. Spec §3.1; 7 tests.
15
+ - `lint-state-registry` / `lint-cas-emit-placement` — ADD — CI-time guardrails (build fails, never runtime).
16
+ - The journal writer itself holds NO runtime decision authority: emits are observational, never gate the observed operation (§3.9), and every emit path is wrapped so a journal failure cannot throw into or slow its caller.
17
+
18
+ ## 1. Over-block
19
+
20
+ `guardJournalWrite` could over-block only by mis-canonicalizing a legitimate journal path — covered by tests (own streams, peers/, meta/lock sidecars all permitted; sibling-prefix dirs refused). The CI lints can over-block future PRs on false positives: `lint-state-registry` accepts the `/* state-registry: <category> */` inline annotation as the documented escape; `lint-cas-emit-placement` pairs per-token within ±12 lines (calibrated against all 8 real sites). No runtime over-block surface.
21
+
22
+ ## 2. Under-block
23
+
24
+ The lints are guardrails, not proofs (stated in their headers + the spec): wrapper-hidden writes/CAS calls can evade the pattern sweep. The declared duty ("new store registers itself"; "every ownership mutation pairs an emit") remains the authority. Accepted per the converged spec §3.3/§3.6.
25
+
26
+ ## 3. Level-of-abstraction fit
27
+
28
+ One refinement over the spec letter, at a STRONGER layer: §3.3 prescribed a `recordLifecycle(sessionId, status)` funnel that the (eleven) SessionManager status-transition sites call. Implemented instead INSIDE `StateManager.saveSession` as a status-diff (prev-on-disk vs next): every transition already passes through saveSession, so no call site exists to forget — the exact drift the spec's own convergence flagged about "naming three sites". The spec's intent (single funnel, no per-site wiring, per-transition wiring tests) is preserved and strengthened; the letter (a SessionManager method) is deviated from, recorded here.
29
+
30
+ ## 4. Signal vs authority compliance
31
+
32
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
33
+
34
+ - [x] No — this change has no runtime block/allow surface (the journal is signal-only by spec §3.9; the lints act at CI, the documented place for structural guards).
35
+
36
+ ## 5. Interactions
37
+
38
+ - **saveSession funnel:** adds one small read-before-write per save (non-hot path); a journal emit failure is swallowed (tested: throwing journal, saveSession still persists). No emit on metadata-only saves (status unchanged) — tested.
39
+ - **Double-fire:** scanner observed-stopped + funnel-stop emit for the same run collapse via the shared `(topic, runId, action)` op key and the shared `autonomousRunId()` formula (exported, single source). placement emit retries collapse via `(topic, epoch)`.
40
+ - **Races:** two server processes — the advisory lock makes the second writer a surfaced no-op (tested: no torn lines, no forked seq). Reaper + funnel both touching a session: 'reaped' is emitted ONLY at the reap event (funnel maps killed/completed/failed), no double-status.
41
+ - **Shadowing:** `guardJournalWrite` is additive; the existing private `guardWrite` and its `sessionScoped` semantics are untouched.
42
+ - **Feedback loops:** the journal subsystem emits nothing about itself (writer excluded; scanner reads `.local.md` files only).
43
+
44
+ ## 6. External surfaces
45
+
46
+ - **Other agents/fleet:** dark-ship — `enabled ?? !!developmentAgent`; fleet agents get inert config via `migrateConfig`'s applyDefaults backfill (Migration Parity §3.8). The two lints run for every CONTRIBUTOR build (CI-time, not agent-runtime).
47
+ - **Persistent state:** new files only under `state/coherence-journal/` (registered as the registry's first entry). Stored session records unchanged.
48
+ - **Spec deviations recorded:** (1) funnel-at-saveSession (above, stronger); (2) journal SessionStatus enum gains `'failed'` — Session records carry a real terminal `failed` the spec's §3.2 enum missed; recording it as killed/completed would misstate history (additive; readers ignore unknowns); (3) TelegramAdapter's emergency-stop `stopAutonomousTopic` call site is NOT directly seamed (the adapter holds no StateManager) — covered by the scanner's observed-stopped within ≤60s per the spec's own defense-in-depth; direct seam rides P1.2 when the adapter is touched anyway <!-- tracked: multimachine-coherence-topic-placement-history-api -->; (4) Agent-Awareness CLAUDE.md template entry ships with the READ API in P1.2 per spec §3.8 (no route exists yet to document).
49
+ - **The cas-pairing lint caught a real miss during development:** the `POST /pool/transfer` release half had no emit until the lint flagged it — the structural guard demonstrably works.
50
+
51
+ ## 7. Rollback cost
52
+
53
+ Code revert + patch release. Journal files left on disk are inert and plain-JSONL readable (spec §3.7 rollback semantics). Lint + registry JSON revert together (same PR, same revert). No data migration; no agent state repair.
54
+
55
+ ## Conclusion
56
+
57
+ Implementation tracks the converged spec with four recorded, rationale-carrying deviations (none weakening a safety property; two strengthening). The riskiest surface — hot-path cost — is structurally bounded (memory-only emit, fault-injection tested). 56 new tests green + 357 across the affected surface; both new lints clean on the real tree; tsc clean. Clear to ship dark.
58
+
59
+ ## Second-pass review (if required)
60
+
61
+ **Reviewer:** design-level convergence panel (4 rounds, 5 perspectives + external cross-model)
62
+ **Independent read of the artifact:** the convergence report stands as the design review; PR CI + operator spot-check per Tier-2 process.
63
+
64
+ ## Evidence pointers
65
+
66
+ - `tests/unit/CoherenceJournal.test.ts` (33), `coherence-journal-wiring.test.ts` (9, independent oracles), `state-manager-guard-journal-write.test.ts` (7), `lint-state-registry.test.ts` (7)
67
+ - `node scripts/lint-state-registry.js` → clean (66 categories); `node scripts/lint-cas-emit-placement.js` → clean (8 sites)
68
+ - Affected surface: 29 files / 357 tests green; `tsc --noEmit` clean
@@ -0,0 +1,54 @@
1
+ # Side-Effects Review — Coherence Journal P1.2 (read API + awareness + actuation-ban lint)
2
+
3
+ **Version / slug:** `coherence-journal-p1-2`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required as a PR-time pass — design converged in the 4-round spec review (docs/specs/reports/coherence-journal-convergence.md); implementation tracks §3.5/§3.8/§3.9`
7
+
8
+ ## Summary of the change
9
+
10
+ P1.2 of the approved COHERENCE-JOURNAL-SPEC: `CoherenceJournalReader` (standalone module; bounded merged reads per §3.5 — reverse-tail via the writer's shared tolerant reader, 4MB per-query byte ceiling, 8-archive generic cap with the topic-placement answer-complete exemption, `(epoch,ts)` placement ordering vs `(ts,machineId,seq)` otherwise, opaque keyset cursor matching the query's order key, `(topic,epoch)` first-seen collapse, replica/staleness tagging, param-hygiene by enumeration); `GET /coherence/journal` route (Bearer, 503-when-dark, 400 on malformed cursor); `lint-journal-actuation-ban` (§3.9 — actuator modules may not import the reader; chained in `lint`); CLAUDE.md template Capabilities entry + Registry-First row + proactive triggers (Agent Awareness); site docs coverage; TelegramAdapter emergency-stop seam (closing the P1.1 deviation); Tier-3 e2e lifecycle test.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `GET /coherence/journal` — ADD — read-only; 503 when dark; no actuation surface.
15
+ - `lint-journal-actuation-ban` — ADD — CI-time guard (build fails; never runtime).
16
+ - No runtime block/allow decisions added or modified.
17
+
18
+ ## 1. Over-block
19
+ Read path: a malformed cursor returns a clean 400 (tested); traversal-shaped `machine`/`kind` filters match nothing rather than erroring (tested). The actuation-ban lint could over-block a legitimate future consumer inside an actuator file — that is the DESIGN (the consumer should read the live store; §3.9), and the lint message says so.
20
+
21
+ ## 2. Under-block
22
+ The lint bans imports of the reader module in an enumerated actuator list — a new actuator file or a hand-rolled JSONL read evades it (stated guardrail framing; the §3.9 duty is the authority). The enumerated-list shape is deliberate: growable, reviewable.
23
+
24
+ ## 3. Level-of-abstraction fit
25
+ Reader as a separate module (not writer methods) exists precisely so the import-ban lint has a clean target; route is a thin adapter over it. Right layers.
26
+
27
+ ## 4. Signal vs authority compliance
28
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
29
+ - [x] No — this change has no runtime block/allow surface. (The journal remains signal-only; this PR adds the structural enforcement OF that.)
30
+
31
+ ## 5. Interactions
32
+ - Reads share `readTailTolerant` with the writer (single tolerant-parse implementation, no drift).
33
+ - `recvTs` for replicas uses replica-file mtime as best-effort until P1.3's apply path stamps real receipt times — recorded limitation, surfaced in the field's semantics, not hidden.
34
+ - Stream `status` is `current` for all streams in P1.2; the replication states (`behind/gapped/suspect/reset/writer-locked-out`) arrive with P1.3's apply machinery. The shape is already in the response so consumers build against it now.
35
+ - The TelegramAdapter seam is injection-only (setter); absent → previous behavior (scanner coverage within ≤60s).
36
+
37
+ ## 6. External surfaces
38
+ - New GET route behind the standard Bearer middleware; 503 when dark — fleet agents (dark) expose a clean "not enabled" rather than a 404 that reads as "wrong version".
39
+ - CLAUDE.md template + migrateClaudeMd: existing agents' docs gain the capability block on update (Agent Awareness + Migration Parity).
40
+ - No persistent-state changes beyond reads.
41
+
42
+ ## 7. Rollback cost
43
+ Code revert + patch. No state, no migration. Template section removal rides the same revert.
44
+
45
+ ## Conclusion
46
+ Read-side honesty (staleness labels, partial-result flags, skew-proof ordering) implemented exactly as converged; the §3.9 ban is now structural. Clear to ship dark.
47
+
48
+ ## Second-pass review (if required)
49
+ **Reviewer:** convergence panel (design-time)
50
+ **Independent read of the artifact:** PR CI + operator spot-check per process.
51
+
52
+ ## Evidence pointers
53
+ - `tests/unit/CoherenceJournalReader.test.ts` (15) + `tests/integration/coherence-journal-route.test.ts` (7) green; e2e lifecycle test (agent-built, see PR); writer/wiring/guard suites unaffected (46 adjacent tests green).
54
+ - `node scripts/lint-journal-actuation-ban.js` → clean (8 actuator modules).
@@ -0,0 +1,49 @@
1
+ # Side-Effects Review — Coherence Journal P1.3 (replication apply/serve engine)
2
+
3
+ **Version / slug:** `coherence-journal-p1-3`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required as a PR-time pass — design converged in the 4-round spec review; this is the §3.4 engine, mesh-independent and pure`
7
+
8
+ ## Summary of the change
9
+
10
+ `JournalSyncApplier` — the RECEIVE + own-stream SERVE engine for journal replication, implementing COHERENCE-JOURNAL-SPEC §3.4 rules 1-4 as a pure module (no mesh/server dependency; the mesh wiring is the closing step). `apply(senderMachineId, batch)`: first-hop sender binding (entry.machine===sender or reject+count; replica path derived from sender, never payload), schema-validated apply (size/seq/ts/kind/typed-data; failure→suspect+stop, self-clear after K=20), incarnation fencing (new incarnation→quarantine ≤2 + coalesced divergence signal + reset-flapping past 3), truncation signals (oldestRetainedSeq→gap sentinel+fast-forward+gapped). `buildServeBatch`: own-stream, durably-flushed-only (reads the file), byte-capped, oldestRetainedSeq after rotation. Ack-after-fdatasync on the receive side (§4.1). Plus `getAdvertState`/`getStreamStatus`/`getDegradation`.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - The applier is pure logic with NO runtime actuation surface — it appends replica files and reports status. It makes no kill/spawn/place/transfer decision. Per §3.9, replica data it writes is read-only signal; the actuation-ban lint (shipped P1.2) guarantees no actuator imports the reader that serves it.
15
+
16
+ ## 1. Over-block
17
+ The validation can reject a legitimate entry only if it genuinely violates seq-order/schema/sender-binding — each is the spec's required gate, and a rejection is counted + surfaced (suspect/forgedEntries), never silent.
18
+
19
+ ## 2. Under-block
20
+ First-hop-only means a 3rd machine's genuine history that arrives via a relay is rejected — accepted P1 limitation (transitive relay needs per-entry signatures, explicitly out of P1). Documented.
21
+
22
+ ## 3. Level-of-abstraction fit
23
+ Pure engine, mesh-injected by the caller — the right seam: it is unit-testable without a two-machine setup (26 tests prove every §3.4 rule deterministically), and the network layer can't smuggle logic past it.
24
+
25
+ ## 4. Signal vs authority compliance
26
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
27
+ - [x] No — the applier writes signal data (replica streams); it holds no block/allow authority. The §3.9 actuation ban (lint, P1.2) keeps it signal-only structurally.
28
+
29
+ ## 5. Interactions
30
+ - Writes replica files + `peers/<machine>.meta.json` that `CoherenceJournalReader` already reads (incarnation top-level, per-kind lastHeldSeq/status) — verified shape-compatible.
31
+ - Quarantine eviction routes through `SafeFsExecutor.safeRmSync` (destructive-fs funnel) — not raw unlink.
32
+ - Ack-after-fsync: an fsync failure reports 0 applied and does NOT advance lastHeldSeq (no false-durable claim that could desync a peer).
33
+ - guardWrite refusal (standby/prefix) → batch skipped + counted, never thrown.
34
+
35
+ ## 6. External surfaces
36
+ - No route, no mesh verb yet (this is the engine; the `journal-sync` verb + session-status advert ride the closing wiring step). No external surface change in THIS PR beyond new replica files under `state/coherence-journal/peers/` when the engine is eventually driven.
37
+
38
+ ## 7. Rollback cost
39
+ Pure code revert + patch. Replica files are inert plain JSONL. No migration.
40
+
41
+ ## Conclusion
42
+ The §3.4 trust model — the load-bearing reason replication can't become a new incoherence source — is implemented as deterministic, fault-injected-tested code ahead of any network exposure. Recorded deviations: forged entries reject+count without marking suspect (rule 1 = trust violation, distinct from rule 2 torn-write); buildServeBatch takes explicit ownMachineId (keeps the module symmetric/pure); incarnation is a per-stream-set token (reconciles the prompt phrasing to the spec). Clear to ship as the engine; the wiring + live two-machine proof is the closing step.
43
+
44
+ ## Second-pass review (if required)
45
+ **Reviewer:** convergence panel (design-time §3.4)
46
+ **Independent read of the artifact:** PR CI + the live two-machine proof (approved) as the closing verification.
47
+
48
+ ## Evidence pointers
49
+ - `tests/unit/JournalSyncApplier.test.ts` (26) — every §3.4 rule incl. ack-after-fsync ordering (injected fs spy), guardWrite refusal, quarantine bounds.
@@ -1,48 +0,0 @@
1
- # Upgrade Guide — vNEXT
2
-
3
- <!-- assembled-by: assemble-next-md -->
4
- <!-- bump: minor -->
5
-
6
- ## What Changed
7
-
8
- Adds a **learning-velocity metric** — Salim Ismail's EXO 3.0 KPI inversion (from
9
- *Your KPI System Is Training You to Miss the Future*). Backward-looking
10
- operational KPIs (throughput, utilization, efficiency) reward the existing model
11
- and suppress the weak signals where the future shows up. The EXO 3.0 answer is to
12
- measure how fast you're **learning** — adaptability, experimentation, capability
13
- creation.
14
-
15
- Instar already emits the raw learning events (registered learnings, captured
16
- corrections, evolution actions); this turns them into a signal:
17
-
18
- - `GET /metrics/learning-velocity?windowDays=30` → `{ totalEvents, eventsPerDay,
19
- byType, typeDiversity, trend, adaptabilityScore, reason }`.
20
- - `trend` is `accelerating` | `steady` | `declining` | `insufficient-data`
21
- (first-half vs second-half of the window).
22
- - `adaptabilityScore` (0–100) blends velocity (saturating) with category
23
- diversity.
24
-
25
- Read-only + advisory — it never gates anything. A flat or declining trend is the
26
- EXO 3.0 warning sign that the org is optimizing the old model instead of learning.
27
-
28
- ## What to Tell Your User
29
-
30
- Your agent can now answer "are we actually learning, or just running?" with real numbers. Ask it for its learning velocity and you get a trend — accelerating, steady, or declining — built from its genuine learning events (lessons it recorded, corrections it absorbed, capabilities it grew) instead of backward-looking activity stats. The EXO 3.0 idea behind it: traditional KPIs measure how well the OLD model runs; learning velocity measures whether you're building the next one. A flat or declining trend is your early warning that things are coasting.
31
-
32
- ## Summary of New Capabilities
33
-
34
- - `GET /metrics/learning-velocity?windowDays=30` — `{ totalEvents, eventsPerDay, byType, typeDiversity, trend, adaptabilityScore (0-100), reason }`, computed from registered learnings, corrections, and evolution actions. Read-only + advisory — never gates.
35
- - PROACTIVE trigger: "are we learning/adapting?" → read this metric and contrast it with operational throughput.
36
-
37
- ## Evidence
38
-
39
- Three-tier coverage, all green, `tsc --noEmit` clean:
40
-
41
- - Unit — `LearningVelocityScorer.test.ts` (6): empty, window exclusion,
42
- accelerating, declining, insufficient-data, and byType/diversity/adaptability.
43
- - Integration — `learning-velocity-routes.test.ts` (3): the route reads a real
44
- `learning-registry.json` + corrections over HTTP and computes.
45
- - E2E — `learning-velocity-lifecycle.test.ts` (1): a real server on a real port,
46
- feature alive end-to-end (200, not 404/503).
47
-
48
- CLAUDE.md scaffold template documents the endpoint.