Skip to content

feat(amplifier): durable session tracking via events.jsonl (two-lane tracker, locator, ledger)#514

Merged
danshapiro merged 4 commits into
mainfrom
feat/amplifier-session-durability
Jul 9, 2026
Merged

feat(amplifier): durable session tracking via events.jsonl (two-lane tracker, locator, ledger)#514
danshapiro merged 4 commits into
mainfrom
feat/amplifier-session-durability

Conversation

@danshapiro

@danshapiro danshapiro commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Problem

Amplifier was the only provider with no durable signals:

  • Turn state was inferred from 2s PTY output-silence plus a 120s deadman timer that fabricated turn.complete events.
  • PTY↔session association relied on a cwd + 30s window + single-candidate heuristic — the same failure class as the opencode ambiguous-ownership RCA.

Approach

Per docs/plans/2026-07-08-amplifier-session-durability-plan.md, which includes settled Phase 0 empirical findings from live CLI experiments:

  • Amplifier's schema-versioned events.jsonl (amplifier.log 1.0.0) drives turn lifecycle — prompt:submit / prompt:complete are the turn boundaries.
  • Deadman repurposed as a WSL2-safe force-read failsafe that never fabricates events.
  • Association driven by Enter↔new-session-dir correlation + session:config cwd confirmation, flowing through the shared bindSession/broadcast paths; claude fast-path widened to amplifier.
  • Single events-driven code path — the legacy output-silence/deadman timing heuristics are deleted. Sessions without events.jsonl (bundles lacking the hooks-logging module) get no busy/turn-complete signal beyond a brief provisional-busy pulse on Enter; signal loss mid-turn reverts the pane to idle with a structured warn.

DRY

  • TurnCompletionLedger extracted from 4 byte-identical tracker duplications.
  • claude/amplifier wiring unified via a shared activity-wiring factory.
  • Locator/controller imitate the opencode controller pattern.
  • No new WS messagesshared/ws-protocol.ts, ws-handler.ts, session-association-coordinator.ts, and all client code untouched.

Hardening

  • 3-agent adversarial review round (fixes A–E documented in the plan doc).
  • Independent post-build gap-analysis review (verdict: MERGE-READY); residual gaps fixed in the final commit — provider test pinning metadata-less orphan-dir exclusion, plan §8 doc fix.

Verification

  • Typecheck (client + server) clean.
  • Server suite: 4515 passed; client suite: 3944 passed.
  • Fixtures derived from live Phase 0 captures (scrubbed).

Upstream issues filed

Upstream asks for microsoft/amplifier-app-cli (plan §12): microsoft/amplifier#314, microsoft/amplifier#315, microsoft/amplifier#316, microsoft/amplifier#317, microsoft/amplifier#318

Generated with Amplifier

codex and others added 3 commits July 8, 2026 13:16
Final plan for durable amplifier session tracking, including Phase 0
empirical findings and the outcomes of adversarial review rounds.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…tracker, locator, ledger)

Replace output-silence heuristics with the amplifier events.jsonl
lifecycle as the source of truth for turn tracking:

- events.jsonl lifecycle drives turn state: prompt:submit /
  prompt:complete are the turn boundaries; the deadman timer is
  repurposed as a force-read failsafe and never fabricates completions
  in the events lane.
- PTY <-> session association via Enter <-> new-session-dir correlation
  with session:config cwd confirmation. New locator + controller flow
  through the shared bindSession/broadcast paths; the coordinator
  slow-path is preserved.
- Catch-up state-sync prevents historical turn replay on attach.
- Claude fast path widened to cover amplifier.
- TurnCompletionLedger extracted from 4 duplicated trackers
  (claude/codex/opencode/amplifier).
- claude/amplifier wiring unified via a shared activity-wiring factory.
- Feature flag FRESHELL_AMPLIFIER_EVENTS_TRACKING, default-on; the
  degraded lane is the prior behavior verbatim.
- Hardening from a 3-agent adversarial review plus red-team
  re-verification: watcher-root containment, serialized attach, tailer
  memory caps, pre-Enter epsilon + stat-anchored rescan, and a grace
  force-read backstop.

WS protocol and client are untouched.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…contradiction

- Provider test: session dirs containing only events.jsonl (kill -9 before
  first prompt:complete, finding E6) are excluded from listSessionFiles()
- Plan doc: remove amplifier-activity-wiring.ts from the Untouched list
  (superseded by Phase 4 wiring unification)

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 62dd6b5b14

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +255 to +257
if (catchUp && (effect.kind === 'turn.began' || effect.kind === 'turn.completed')) {
if (effect.kind === 'turn.began') attachment.catchUpBeganAt = effect.at
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve fast first-turn completions during catch-up

When the locator binds a fresh Amplifier session, it waits for the correlation window to close before calling attachTailer(..., 'start'); if the first turn completes inside that window, the degraded tracker is already busy but its idle debounce has not fired yet. This catch-up branch suppresses the prompt:complete record, and the later catch-up adoption only handles a final busy reducer state, while enableEventsLane has already cleared the degraded debounce timer. In that scenario the terminal silently reverts later via submit-grace with no terminal.turn.complete/chime for the completed turn, so catch-up needs to complete an already-busy tracker when the catch-up reducer ends idle rather than treating that completion as historical.

Useful? React with 👍 / 👎.

Comment on lines +313 to +317
armed.ready = (async () => {
armed.cwdNormalized = await normalizeRealCwd(record.cwd!)
armed.snapshot = await this.snapshotSessionDirs()
})().catch(() => {})
this.armed.set(record.terminalId, armed)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Capture session snapshot before accepting input

The terminal is added to armed before the async pre-spawn snapshot finishes, so an immediate user submit can create the Amplifier session directory before snapshotSessionDirs() resolves. That real session dir is then recorded in armed.snapshot, and tryResolveWindow later excludes snapshot dirs from eligibility, causing the locator to miss the in-flight session until the metadata fallback after completion or never if the process is killed first. The snapshot should be taken before the terminal can open a correlation window, or dirs born after spawnedAt should not be excluded as pre-existing.

Useful? React with 👍 / 👎.

…ingle events-driven path

Maintainer decision: one code path only.

- Delete FRESHELL_AMPLIFIER_EVENTS_TRACKING; locator, controller,
  integration, and the amplifier fast path are unconditional.
- Delete the degraded lane (output-silence debounce, first-output gate,
  deadman completion fabrication) and its tests, including the
  pre-existing timing-heuristic pins.
- Signal loss (tailer degrade/detach, or no events.jsonl because the
  bundle lacks the hooks-logging module) now means idle-and-stop: phase
  reverts to idle with no turn.complete, one structured warn; only
  submit-grace provisional-busy pulses remain for such terminals.
- Docs updated (plan doc §6/§7/Appendix A, ACTIVITY_TRACKING_SPEC).

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
@danshapiro danshapiro merged commit 05c6b1f into main Jul 9, 2026
1 check passed
@danshapiro danshapiro deleted the feat/amplifier-session-durability branch July 9, 2026 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants