mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
62001cf210
* refactor(record): derive session recording from the publication lifecycle `SessionState.recordSession` stored an answer the script-publication aggregate already contained. Every writer set both, but nothing made them agree, and #1533 was the consequence: a `--save-script` ingress re-armed the flag behind an ABORTED status, and a bare `close` published a recording the caller had been told was aborted. That fix routed every write through one rule, which made the two agree without making disagreement unrepresentable. The field remained a second source of truth, and its doc comments had to carry the invariant that a type could enforce. Remove the field and derive the answer. `isRecordingPublication` reads recording off the lifecycle: ordinary authoring records only while ARMED; a repair transaction records for its whole lifetime, terminal statuses included. That last clause is deliberately exact rather than merely safe — `armRepairStep` armed the old flag and neither `abortRepair` nor `commitRepair` ever cleared it, so narrowing it would silently stop evidence capture for a committed repair. Whether it should is a real question, and a behavior change, so it is left alone here. What this buys, beyond one less field: - `buildNextOpenSession` and `finalizeOrdinaryCloseScript` make no recording decision at all now, so no surface can arm recording without moving the lifecycle that authorizes it. - The writer's publication gate is answered entirely by the aggregate. Its separate ABORTED check is gone: a terminal authoring lifecycle is already not recording, so one question replaces two that could disagree. - The R7 ownership ratchet drops from 23 writer-owned fields / 29 owner claims to 22 / 26, and the layering manifest loses the entry whose comment documented the smell ("deliberately set on its own by paths that record without arming a publication"). Behavior-preserving: the derivation reproduces what the flag held at every transition. The test fixtures that armed `recordSession` with no publication state described a shape production stopped producing at #1478; they now carry the lifecycle that causes recording. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFW9gJqz1wEHoowkdd1nFW * test(close-script): flush queued event-log writes before removing the tmp root CI failed the Coverage lane with ENOTEMPTY removing the test's tmp root, in `afterEach` rather than in an assertion. `SessionStore.recordAction` QUEUES its event-log append (`queueEventLogWrite`) instead of writing it, and every close path in this file records an action. Nothing awaited that write, so `fs.rmSync(root, {recursive: true})` could race it: the pending append recreates `<root>/sessions/<name>/` while rmSync is walking, and the final rmdir fails ENOTEMPTY. It needs CI's parallel load to lose the race — the file passes 12/12 in isolation locally. Await `flushSessionEventLogWrites()` before removing. The hazard is latent in any test that records actions and then removes its tmp root; this fixes the file that failed rather than sweeping the pattern, which deserves its own change. Not added to the #1419 contention-retry list: that list requires a concrete spawn/wait mechanism named per entry, and this file has none. The race was a real teardown bug, not lane contention. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFW9gJqz1wEHoowkdd1nFW * docs: correct ADR 0016 on recording vs publication for repair Review caught a real overstatement. The amendment claimed evidence capture and publication authorization are "the same question asked of the same state". That holds for ordinary authoring — ARMED both records and publishes, ABORTED and PUBLISHED do neither — but not for repair: `isRecordingPublication` is true for every repair status including `committed` and `aborted`, while the writer additionally applies `isRepairArmedWriteBlocked`, refusing a committed transaction and one that is not yet committable. State it as it is: both decisions derive from the same aggregate, but they remain distinct predicates, and collapsing them would republish a committed repair or commit an incomplete prefix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PFW9gJqz1wEHoowkdd1nFW --------- Co-authored-by: Claude <noreply@anthropic.com>
ADR index — read this when…
| ADR | Read when you touch… |
|---|---|
| 0001 Provider-First Integration Scenarios | integration testing strategy, provider transcripts, the scenario harness |
| 0002 Persistent Platform Helper Sessions | helper process lifecycle, keep-alive semantics |
| 0003 Daemon Command Registry | daemon routing, request-policy traits |
| 0004 iOS Snapshot Backend Strategy | snapshot capture plans, backend fallbacks, quality verdicts |
| 0005 iOS Runner Interaction Lifecycle | XCTest runner sessions, leases, adoption, idle-stop |
| 0006 Daemon RPC Protocol Version | remote daemon HTTP/JSON-RPC compatibility |
| 0007 Remote Device Leases | leases, tenancy, provider-owned devices |
| 0008 Command Descriptor Registry | adding/changing a command, any surface projection (CLI/MCP/client/batch), timeout policy |
| 0009 Apple Platform Consolidation | Apple platform family, apple/appleOs axes, the apple-leak guard |
| 0010 Error system conventions | error codes, hints, normalizeError, typed error signals |
| 0011 Interaction Guarantee Contract | interaction dispatch paths, fast paths, guards, the guarantee matrix, parity tables |
| 0012 Interactive Replay | replay healing/--update, diagnostic resolution disclosure, bounded .ad target-binding evidence, bounded divergence wire/error handling, plan-bound replay-only --from semantics, and agent-supervised re-record repair ("heal-by-doing") |
| 0013 Unified Gesture Plans | gesture API/routing, contact topology, multi-touch geometry, native pointer injection, two-finger pan |
| 0014 Session Ref-Frame Lifetime | ref authorization epochs, complete/partial issuance, pre-side-effect expiration, replay/batch compatibility, and cross-platform stale-mutation policy |
| 0015 Direct Maestro Compatibility Engine | Maestro YAML parsing/execution, compatibility observation policy, conformance, performance gates, gesture integration |
| 0016 Active-Session Script Publication | publishing an armed open-to-destination .ad script without closing its live session |
| 0017 Parameterized Recorded Inputs | safely authoring sensitive fill inputs as ${VAR} placeholders across recording, replay, and repair |
| 0018 Unified Request Event Journal (Proposed) | event/diagnostic vocabulary, journal scopes and sinks, progress-channel separation, observability-only state |
| 0019 Request-Bound Platform Runtime | platform-package boundaries/composition, device discovery, runtime facts/facets, request binding, provider ownership, platform-shaped session resources, durable reattachment, daemon-handler migration |
ADRs record why; the registries and gates they describe are the living source of truth — when prose and a registry disagree, the registry wins and the ADR needs a follow-up.
Shape conventions, so consulting an ADR stays cheap:
- Normative rules first, terse. Status, then a "Rules at a glance" summary a reader can stop after; full contracts and rationale below it.
- Rationale and refuted alternatives stay in the ADR — they are what stops re-litigating settled ideas — but below the fold.
- Process history is deleted once complete, not archived in-file. Migration plans, per-step landing tables, and point-in-time status change-logs go to git history; the Status section keeps one line saying so plus any accepted, still-relevant waiver or evidence gap.
- Once a rule is gate-enforced, the ADR keeps the why and points at the gate rather than restating the rule's details.