feat(amplifier): durable session tracking via events.jsonl (two-lane tracker, locator, ledger)#514
Conversation
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>
There was a problem hiding this comment.
💡 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".
| if (catchUp && (effect.kind === 'turn.began' || effect.kind === 'turn.completed')) { | ||
| if (effect.kind === 'turn.began') attachment.catchUpBeganAt = effect.at | ||
| continue |
There was a problem hiding this comment.
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 👍 / 👎.
| armed.ready = (async () => { | ||
| armed.cwdNormalized = await normalizeRealCwd(record.cwd!) | ||
| armed.snapshot = await this.snapshotSessionDirs() | ||
| })().catch(() => {}) | ||
| this.armed.set(record.terminalId, armed) |
There was a problem hiding this comment.
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>
Problem
Amplifier was the only provider with no durable signals:
turn.completeevents.Approach
Per docs/plans/2026-07-08-amplifier-session-durability-plan.md, which includes settled Phase 0 empirical findings from live CLI experiments:
events.jsonl(amplifier.log1.0.0) drives turn lifecycle —prompt:submit/prompt:completeare the turn boundaries.session:configcwd confirmation, flowing through the sharedbindSession/broadcast paths; claude fast-path widened to amplifier.DRY
TurnCompletionLedgerextracted from 4 byte-identical tracker duplications.shared/ws-protocol.ts,ws-handler.ts,session-association-coordinator.ts, and all client code untouched.Hardening
Verification
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#318Generated with Amplifier