# Upgrade Guide — vNEXT

<!-- bump: minor -->
<!-- minor = new capability (ORG-INTENT drift detection — Phase 4, completes the four-phase project). Aggregates fix(heal) from PR #316 too. -->

## What Changed

**feat(org-intent-runtime): periodic drift detection job + analyzer (Phase 4 of 4 — completes the project).**

The per-message Coherence Gate from Phase 1 catches individual constraint violations. The session-start injection from Phase 2 ensures the agent reasons with the contract from message one. The tradeoff helper from Phase 3 lets non-reviewer code paths resolve values collisions deterministically. But none of these catch the slow accumulation pattern — every individual message passes the gate, yet week-over-week the agent has gradually drifted toward optimizing for the wrong objective. That is the Klarna failure mode at action scale, and it is what this phase catches.

Three new surfaces, all signal-only:

- **`src/core/OrgIntentDriftAnalyzer.ts`** — pure function. Given recent Coherence Gate review history + parsed `ORG-INTENT.md`, produces a `DriftAnalysis` with a trend label (`stable` | `rising` | `concerning` | `insufficient-data` | `no-org-intent`), per-reviewer block-rate stats, half-window comparison, and cross-references against ORG-INTENT constraints / goals / values.
- **`GET /intent/org/drift?lookbackDays=N`** — HTTP route exposing the analyzer. Returns 503 when the response review pipeline is not enabled (graceful degradation).
- **Weekly job template** (`src/scaffold/templates/jobs/instar/org-intent-drift-audit.md`) — `enabled: false` by default. Operators with an authored `ORG-INTENT.md` can flip it on; the job runs every Monday at 10:00 local time, calls the route, and sends a Telegram heads-up only when `shouldSurface: true` (trend is rising or concerning). Most weeks stay silent — that means the agent is staying aligned.

Per `feedback_signal_vs_authority`: every surface in this phase is SIGNAL. The Coherence Gate from Phase 1 remains AUTHORITY. Nothing here writes to `ORG-INTENT.md`, modifies the gate's behavior, or blocks anything.

This is the final phase of the four-phase ORG-INTENT runtime project that started with topic 11378 on 2026-05-21. With this release, `ORG-INTENT.md` is fully load-bearing infrastructure: enforced at message review (Phase 1), surfaced at session start (Phase 2), consultable for tradeoffs (Phase 3), and monitored for drift (Phase 4).

Spec: `docs/specs/ORG-INTENT-DRIFT-DETECTION-SPEC.md`. ELI16 companion: `docs/specs/ORG-INTENT-DRIFT-DETECTION-SPEC.eli16.md`. Side-effects review: `upgrades/side-effects/org-intent-drift-detection.md`.

---

**Also included: fix(heal) — better-sqlite3 self-heal now survives Homebrew Node updates that strand `process.execPath`.**

When Homebrew (or any package manager) updates Node while an instar server is running, the brew install swaps the `/opt/homebrew/bin/node` symlink and removes the previous Cellar directory. The server process keeps an open file descriptor to the deleted binary, so it continues executing — but any new `spawnSync(process.execPath, ...)` call returns ENOENT. The native-module self-heal path runs through exactly that kind of spawn, so the heal silently fails. The agent then degrades to legacy-memory fallbacks and stays there across restarts (the next startup hits the same stale execPath).

This was observed live on luna 2026-05-21. The fix adds a `resolveStableNodeBinary()` helper that walks a fallback chain — `process.execPath` → `fs.realpathSync(execPath)` → optional caller-supplied bundled Node → `/opt/homebrew/bin/node` (the stable symlink Homebrew always maintains) → `/usr/local/bin/node` → `/usr/bin/node` → `which node` — and returns the first existing-and-executable path. `ensureSqliteBindings()` in `src/commands/server.ts` and `scripts/fix-better-sqlite3.cjs` both route through the resolver before spawning. Fail-closed semantics preserved: if no Node binary is reachable, the heal does not proceed and a structured DegradationReporter event surfaces.

## What to Tell Your User

If you have an organizational intent file authored AND you opt into the new weekly job, you'll get a Telegram heads-up on Monday mornings when your agent's outbound-message review block rate is rising or concerning. Most weeks stay silent — that means the agent is staying aligned with your organizational intent. The heads-up tells you the trend, what flagged most, and one or two suggestions for where to look. It surfaces patterns; it doesn't fix anything autonomously. The fix is your call.

If you haven't authored an organizational intent file, nothing changes. This is a zero-cost upgrade for those agents.

This is the last of four phases in the ORG-INTENT runtime project. With this release, `ORG-INTENT.md` is fully load-bearing infrastructure: enforced at message review, surfaced at session start, consultable for tradeoffs, and monitored for drift.

A second change in this release (the heal fix): if your agent ever logged "rebuild failed (spawnSync ... ENOENT)" after a Homebrew Node update — most often visible as your knowledge graph or conversation summaries going offline while the agent still appears to be running — this fix lets the agent recover on the next restart without manual help.

## Summary of New Capabilities

- **GET /intent/org/drift** — new HTTP route returning a drift digest derived from recent Coherence Gate review history.
- **`analyzeOrgIntentDrift()` exported function** — pure logic helper for any callsite that wants the same analysis.
- **Weekly drift audit job** — agentmd template, off by default, sends a Telegram heads-up only when drift surfaces.
- **Stable-Node-resolver self-heal** — automatic on next server restart; surfaces a structured DegradationReporter event if no Node binary is reachable.
- **Migration parity** — existing agents' CLAUDE.md gains a Phase 4 curl line automatically.

## Evidence

- Tier 1 unit tests: `tests/unit/OrgIntentDriftAnalyzer.test.ts` (11 new tests, all passing). `tests/unit/PostUpdateMigrator-org-intent-runtime.test.ts` extended with 1 new test for Phase 4 migration (9 total, all passing).
- Tier 2 integration tests: `tests/integration/org-intent-routes.test.ts` extended with 1 new test for the drift route (17 total, all passing).
- Tier 3 E2E lifecycle tests: `tests/e2e/org-intent-drift-lifecycle.test.ts` (4 tests mirroring production wiring through `AgentServer` and `createRoutes` with a real `CoherenceGate` seeded with synthetic history, all passing — including the "feature is alive" 200-not-503 check).
- Heal fix evidence: `tests/integration/heal-execpath-staleness.test.ts` reproduces the luna failure mode (6 scenarios) + 7 unit tests in `tests/unit/resolveNodeBinary.test.ts` covering the resolver fallback chain branch-by-branch. The live fix on luna brought her degradation count from 8 to 1.
- Type-check: `npx tsc --noEmit` clean.
- Lint: clean.
- The full test suite must remain green before merge per Zero-Failure Standard.
