Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
d68cf67
docs(adr): identify the derived daemon registry owners
thymikee Oct 16, 2026
a96f6ee
docs(adr): match guarantee declarations and fixture consumers
thymikee Oct 16, 2026
6bc7426
docs(adr): correct the default lease inactivity period
thymikee Oct 16, 2026
de93147
docs(adr): record the active settle timing detector
thymikee Oct 16, 2026
53b6a2b
docs(adr): include recording consumers of the gesture codec
thymikee Oct 16, 2026
5f891cd
docs(adr): record retired aliases and current client result gaps
thymikee Oct 16, 2026
82f9b50
docs(adr): exclude bridge preparation from the generation circuit
thymikee Oct 16, 2026
3d04ceb
docs(adr): replace deleted migration references in code
thymikee Oct 16, 2026
1866121
docs(adr): identify the current generic-dispatch rejection boundary
thymikee Oct 16, 2026
ef1ad66
docs(adr): remove the dangling historical hard-reject pointer
thymikee Oct 16, 2026
fde65a2
docs(adr): align the proposed durable-resource amendment
thymikee Oct 16, 2026
821e9a7
docs(adr): point exhaustive runtime facts to section 2
thymikee Oct 16, 2026
7e3ac80
docs(adr): cite the withdrawn allocator design for its historical move
thymikee Oct 16, 2026
5fede4d
docs(adr): record the coupling ban and its landing date
thymikee Oct 16, 2026
29c74f8
docs(adr): record the active shape rule and shared test owner
thymikee Oct 16, 2026
b86af9f
docs(adr): correct the direction of the superseded hop comparison
thymikee Oct 16, 2026
9085847
docs(adr): date hinge-stream evidence by toolchain
thymikee Oct 16, 2026
831b62a
docs(adr): describe the permitted capture-only second bind
thymikee Oct 16, 2026
7e572b5
docs(adr): date the completed root-pass move correction
thymikee Oct 16, 2026
f4c77fd
docs(adr): record daemon trait enforcement gaps
thymikee Oct 16, 2026
260a836
docs(adr): describe pending bridge preparation precisely
thymikee Oct 16, 2026
282426b
docs(adr): restore client result migration prerequisites
thymikee Oct 16, 2026
0eee6ee
docs(adr): restore the retained rejection rationale pointer
thymikee Oct 16, 2026
b90d8ac
docs(adr): include replay and publication gesture codec callers
thymikee Oct 16, 2026
047b8dd
docs(adr): trace old-reader guard failures without a codec promise
thymikee Oct 16, 2026
449b595
docs(adr): scope hop counts to their recorded trace
thymikee Oct 16, 2026
d9edbc8
docs(adr): retain the outstanding physical module moves
thymikee Oct 16, 2026
17a25c6
docs(adr): qualify the capture-only second bind
thymikee Oct 16, 2026
b9096c1
docs(adr): state that the ADR 0020 old-reader trace starts after admi…
thymikee Oct 16, 2026
b52f0c8
docs(adr): align ADR 0003 invariants 3 and 4 with the shipped derivation
thymikee Oct 16, 2026
843b7ef
docs(adr): accept existing old-reader errors in ADR 0020
thymikee Oct 16, 2026
2887aad
docs(adr): list the full provider-scenario exclusion buckets in ADR 0001
thymikee Oct 18, 2026
8dfcba8
docs(adr): scope the Android helper rule to instrumentation touch in …
thymikee Oct 18, 2026
978f52e
docs(adr): record the exempt commands and grown allowlist in ADR 0005
thymikee Oct 18, 2026
3ecf51b
docs(adr): state per-fate wire-gate outcomes in ADR 0006
thymikee Oct 18, 2026
4e62f8e
docs(adr): name the platformExecution facet and execute seam in ADR 0008
thymikee Oct 18, 2026
bb6f153
docs(adr): point the visionOS discovery claim at its test file in ADR…
thymikee Oct 18, 2026
a9dd82d
docs(adr): state the remote logPathUnavailable case in ADR 0010
thymikee Oct 18, 2026
1111301
docs(adr): correct the scroll keyboard-probe condition in ADR 0011
thymikee Oct 18, 2026
68bb7e5
docs(adr): scope the linear-schedule sentence to endpoint-hold in ADR…
thymikee Oct 18, 2026
1c3b8ea
docs(adr): name the frame value module and empty-result rule in ADR 0014
thymikee Oct 18, 2026
edb03cf
docs(adr): add the we-are-lenient outcome to ADR 0015
thymikee Oct 18, 2026
4c6bbae
docs(adr): state the session event hides fill text in ADR 0017
thymikee Oct 18, 2026
4db9f74
docs(adr): include translation hops in the collapse rule of ADR 0022
thymikee Oct 18, 2026
a27da08
docs(adr): separate the runner capture path and complete refusal caus…
thymikee Oct 18, 2026
2414d66
docs(adr): scope the novelty fact to verbatim transplants in ADR 0027
thymikee Oct 18, 2026
a3c5418
docs(adr): correct the freshness row and cycle wording in ADR 0033
thymikee Oct 18, 2026
6f62e8c
docs(adr): state the platformExecution execution shapes in ADR 0008
thymikee Oct 18, 2026
f4de629
docs(adr): match the active design to platformExecution in ADR 0009
thymikee Oct 18, 2026
d73610d
docs(adr): scope the diagnostic fields to the request scope in ADR 0010
thymikee Oct 18, 2026
92a59a0
docs(adr): confine frame construction claims to the slot class in ADR…
thymikee Oct 18, 2026
2f6718b
docs(core): state the pinned-generation warning exception in ref-fram…
thymikee Oct 18, 2026
e9f426c
docs(adr): qualify the runner fallback policy and record the panel re…
thymikee Oct 18, 2026
c1c251c
docs(registry): separate app-switcher admission from execution
thymikee Oct 18, 2026
278baaa
test(help): pin the foldable first-screen rule to the merged #3761 co…
thymikee Oct 18, 2026
0d83062
docs(adr): state the attempted flush and field conditions in ADR 0010
thymikee Oct 18, 2026
c190504
docs(adr): scope the primary-panel fallback row to a primary panel in…
thymikee Oct 18, 2026
9edf321
docs(adr): scope the flush owner to the router finalizer in ADR 0010
thymikee Oct 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions docs/adr/0001-provider-first-integration-scenarios.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,20 @@ The script is the source of truth for:

These flags stay in their owning unit/CLI suites:

- Config.
- Remote transport.
- Metro preparation.
- Parser/client-only.
- Report-writing.
- Boot-fallback.

- Config, output, diagnostics, and transport.
- Remote connection and session-lock policy.
- Cloud artifact provider lookup.
- Metro and React Native runtime preparation.
- Apple launch and perf artifact options.
- Parser/client-only command flags.
- Daemon lifecycle control.
- Platform boot fallback without a provider seam.
- Open foreground auto-resolution (RFC prototype).
- Local device contention waiting.
- Apple simulator screenshot, private-AX, and observe-only capture options.
- Daemon screenshot selector crop.

`summarizeProviderScenarioFlagExclusions` in `scripts/integration-progress-model.ts` is the full list.
The report lists these flags as explicit exclusions, so they are not silently missing from the denominator.
Provider pressure separates semantic Apple `simctl`/`devicectl`, macOS helper, and macOS host usage from generic Apple host-tool usage.
It also separates semantic Linux desktop/accessibility/clipboard/screenshot/input usage from generic Linux tool usage.
Expand Down
4 changes: 2 additions & 2 deletions docs/adr/0002-persistent-platform-helper-sessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Accepted
- When startup costs are high and an automation context is reusable, use persistent platform helper sessions.
- The daemon owns helper lifetime policy. Platform modules own helper-manager mechanics.
- Unless a separate cache contract has explicit invalidation, a helper must execute each command against fresh platform state.
- On Android, snapshot capture, gesture viewport resolution, and planned-touch injection share one bundled automation helper.
- On Android, snapshot capture, gesture viewport resolution, and instrumentation-backed planned-touch injection share one bundled automation helper.
- On Android, after a failed session command, retry one-shot only for idempotent reads, and only after the failed session has stopped.
- On Android, return a session gesture failure directly. Do not retry it one-shot.
- For Android snapshots, if the packaged helper is unavailable or invalid, agent-device must fail closed. It must not substitute the legacy `adb uiautomator dump` snapshot engine.
Expand Down Expand Up @@ -87,7 +87,7 @@ If that helper is unavailable or invalid, agent-device must fail closed.
It must not substitute the legacy `adb uiautomator dump` snapshot engine.

Android permits only one reliable instrumentation-owned `UiAutomation` context per device.
Thus, snapshot capture, gesture viewport resolution, and planned-touch injection share one bundled automation helper (amended 2026-07, issue #1275, consistent with ADR 0013).
Thus, snapshot capture, gesture viewport resolution, and instrumentation-backed planned-touch injection share one bundled automation helper (amended 2026-07, issue #1275, consistent with ADR 0013).
A live persistent helper session executes touch commands directly over its session socket.
Without a live persistent session, the same helper runs one-shot.
Before that amendment, touch synthesis shipped as a separate instrumentation helper.
Expand Down
42 changes: 27 additions & 15 deletions docs/adr/0003-daemon-command-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

## Status

Accepted
Accepted. Amended 2026-10-16: invariants 3 and 4 now describe the shipped derivation (#906, #907).

## Rules at a glance

- Keep public command identity in `packages/command-registry/src/catalog.ts` and public input/output contracts in `src/commands/**`.
- Keep daemon route ownership and request-policy traits in the daemon command registry.
- Declare daemon route ownership and request-policy traits in the separately typed `daemon` facet of the descriptor registry.
- Derive the daemon registry from that facet. Expose request-policy predicates only through the daemon registry.
- Request modules consume named predicates from the registry. They do not recreate command string sets.
- Handler modules own execution logic only. They do not export duplicate coverage tables to prove route membership.
- The daemon registry must not define CLI grammar, Node.js client options, MCP schemas, user-facing help, or platform capability support.
- A derived daemon registry is permitted only if it preserves all four invariants in the 2026-06 update.
- Preserve all four invariants in the 2026-06 update.
- Do not derive a public contract from daemon traits. A diagnostic display, such as `command explain`, may read them.
- A command without a `daemon` facet uses the `generic` route with default request policy.

## Context

Expand All @@ -35,7 +38,9 @@ Duplicate command sets required alignment by convention.
Keep public command identity in `packages/command-registry/src/catalog.ts`.
Keep public input/output contracts in `src/commands/**`.

Add `packages/daemon/src/core/daemon-command-registry.ts` as the daemon-side source of truth for command route ownership and request-policy traits.
Declare command route ownership and request-policy traits in the `daemon` facet in `packages/command-registry/src/registry.ts`.
`DaemonCommandDescriptor` in `packages/command-registry/src/daemon-command-descriptor.ts` types that separate facet.
`packages/daemon/src/core/daemon-command-registry.ts` derives its table through `deriveDaemonCommandDescriptors(commandDescriptors)`.
Request modules consume predicate functions from the registry.
They do not recreate command string sets.
Handler modules own execution logic only.
Expand Down Expand Up @@ -64,7 +69,8 @@ The command contract, projection, help, and capability modules retain these resp

## Consequences

When a daemon-handled command is added or moved, its route and request-policy traits require updates in the daemon command registry.
When a daemon-handled command is added or moved, update its `daemon` facet in `packages/command-registry/src/registry.ts`.
The daemon registry derives its table from those declarations.
The registry tests pin the trait decisions.
Provider-backed integration scenarios verify important request-policy behavior through the real daemon request path.

Expand All @@ -79,7 +85,7 @@ Thus, future changes do not require readers to infer the rationale from agent in

## Update (2026-06): single-declaration / derivation model

A later proposal, the `CommandDescriptor` direction in [ADR 0008](0008-command-descriptor-registry.md), unifies a command's declarations at one registration site.
The implemented `CommandDescriptor` direction in [ADR 0008](0008-command-descriptor-registry.md) unifies a command's declarations at one registration site.
It derives these surfaces from that site:

- Public catalog.
Expand All @@ -89,15 +95,16 @@ It derives these surfaces from that site:
- Daemon registry.

Its purpose is to remove the drift between these tables.
Convention keeps several of these surfaces aligned against that drift.
Registry tests pin the derived tables.

**This ADR's decision remains accepted.**
Its boundary concerns ownership and the predicate interface, not the physical file that contains a trait.
“Separate source of truth” means separate ownership and exposure through named predicates.
That property remains true for a projected or derived backing table.
A derived daemon registry is therefore permitted **only if** it preserves all these invariants:

1. **Daemon-owned declaration.** A daemon-owned facet under `packages/daemon/src/` declares route and request-policy traits.
1. **Daemon-owned declaration.** The separately typed `daemon` facet in `packages/command-registry/src/registry.ts` declares route and request-policy traits.
`DaemonCommandDescriptor` in `packages/command-registry/src/daemon-command-descriptor.ts` owns its type.
The registration composes that facet.
The public command contract in `src/commands/**` or `packages/command-registry/src/catalog.ts` must never contain these traits as inline fields.
A registration call may be co-located with public declarations.
Expand All @@ -106,15 +113,20 @@ A derived daemon registry is therefore permitted **only if** it preserves all th
2. **Predicate interface unchanged.** Consumers continue to use named predicates such as `getDaemonCommandRoute`, `isLeaseAdmissionExempt`, and `shouldLockSessionExecution`.
Only the daemon registry exposes these predicates.
Derivation changes table construction, not table access.
3. **No leakage into public projections.** Types must prevent the catalog/CLI/MCP/help/capability projections from reading daemon-only traits.
The daemon registry must still not define CLI grammar, Node.js options, MCP schemas, user-facing help, or capability support.
4. **One declaration per concern, enforced by types.** At the single registration site, a missing or duplicate daemon trait must cause a compile error.
This replaces alignment by convention.
This structural improvement justifies derivation instead of a separate hand-authored table.
3. **No daemon traits in public contracts.** CLI grammar, Node.js client options, MCP schemas, user-facing help, and capability support must not derive from daemon-only traits.
A diagnostic display may read the `daemon` facet. `command explain` in `src/cli/command-explain.ts` displays routes and request-policy traits this way.
4. **One declaration per command.** Each command has at most one `daemon` facet, at its registration in the descriptor registry.
No second table declares the same traits. This replaces alignment by convention, and it justifies derivation instead of a separate hand-authored table.
A command without a `daemon` facet uses the `generic` route with default request policy. The daemon registry tests pin the derived table.

A single flat public descriptor that exposes daemon fields in public views is **not** permitted.
This would combine daemon policy with a public command registry, which this ADR rejects.
Compose facets owned by their domains.
Derive the registry from those facets.
Until that derivation is implemented and the registry tests pin it, the hand-authored `packages/daemon/src/core/daemon-command-registry.ts` remains the source of truth.
Until then, the operating rule in `AGENTS.md` does not change.
PR #906 introduced the descriptor and proved parity.
PR #907 made the derivation live and deleted the hand-authored table.
The daemon registry tests pin route and request-policy decisions.

**Amendment 2026-10-16.** The 2026-06 text required types to stop every public projection from reading daemon traits, and required a compile error for a missing daemon trait.
The shipped derivation does neither: `CommandDescriptorBase.daemon` is optional (`packages/command-registry/src/types.ts`), and a command without a facet gets the `generic` route.
Invariants 3 and 4 now state the property that matters and that the code holds: no public contract derives from daemon traits, and no second table declares them.
7 changes: 5 additions & 2 deletions docs/adr/0004-ios-snapshot-backend-strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Structured snapshot quality verdicts and fallback warnings make degraded or reco

- Route eligible local iOS Simulator snapshots through the host AX bridge. Present them once through the shared TypeScript engine.
- If bridge acquisition or presentation fails, use one typed XCTest fallback.
- After fallback, disable the bridge for that app generation, except for capture-scoped failures. A new app generation enables it again.
- After fallback, disable the bridge for that app generation, except for `preparing` failures and capture-scoped failures.
A new app generation enables it again.
- A refusal that provides evidence about the screen, not the app, has capture scope.
- Keep the regular visible strategy and the raw diagnostic strategy explicit as the two public snapshot strategies.
- The regular visible strategy must not use an arbitrary node-count cutoff.
Expand Down Expand Up @@ -52,7 +53,9 @@ Keep XCTest as the iOS automation runner.
Route eligible local iOS Simulator snapshots through the host AX bridge.
Present them once through the shared TypeScript engine.
If bridge acquisition or presentation fails, use one typed XCTest fallback.
After fallback, disable the bridge for that app generation, subject to the capture-scoped exception below.
After fallback, disable the bridge for that app generation, except for `preparing` failures and the capture-scoped exception below.
A `preparing` failure describes a bridge preparation that is still running, not the app.
It sends only that capture to XCTest.
A new app generation enables it again.
Physical devices, providers, custom-action captures, and interactions remain on their existing owners.

Expand Down
5 changes: 4 additions & 1 deletion docs/adr/0005-ios-runner-interaction-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Accepted
## Rules at a glance

- For iOS/macOS selector taps on an element with a frame, use coordinate-first resolved element activation. tvOS remains focus/remote-driven.
- Before a command to a ready session, send an `uptime` preflight, except for the stated startup, readiness, and recent-mutation cases.
- Before a command to a ready session, send an `uptime` preflight, except for the stated startup, readiness, exempt-command, and recent-mutation cases.
- Keep recent-mutation health only on the `RunnerSession` and only for the stated app, commands, response checks, and 5-second window.
- Never count snapshots or other read-only responses as health signals.
- Future optimization work should reduce the `uptime` preflights only after runner status survives command-induced XCTest teardown and can prove that the session still serves new requests.
Expand Down Expand Up @@ -45,6 +45,7 @@ tvOS remains focus/remote-driven because tvOS does not support normal coordinate
Before command send, ready runner sessions receive a short `uptime` preflight.
Read-only startup commands still skip that preflight because, for a newly launched runner, the first successful command is the readiness proof.
Readiness probe commands skip preflight to avoid recursion.
A ready session also skips the preflight for the preflight-exempt commands `activate`, `terminate`, and `targetReset` (`readinessPreflightExempt` in `RUNNER_COMMAND_TRAITS`).

The daemon may also skip the ready-session `uptime` preflight for an explicit allowlist of mutating interactions:

Expand All @@ -53,6 +54,8 @@ The daemon may also skip the ready-session `uptime` preflight for an explicit al
- `drag`.
- `swipe`.
- `scroll`.
- `desktopScroll`.
- `gesture`.
- `sequence`.

The skip requires that the same session produced a healthy mutating response for the same `appBundleId` within 5 seconds.
Expand Down
4 changes: 3 additions & 1 deletion docs/adr/0006-daemon-rpc-protocol-version.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ Checks enforce the increment rules above, so nobody has to remember them (#1432)
`test/wire-compat/ledger.json` records the hash of each declaration and the protocol version of that hash.
The unit lane fails if the shape of a declaration changes and the ledger does not change with it.
`pnpm check:daemon-wire-compat` compares the ledger with the last released tag.
Drift since that release must carry either a protocol increment or a `compatibleChanges` acknowledgment that invokes the additive list above.
A declaration removed since that release needs a protocol increment; an acknowledgment cannot cover a removal.
A declaration changed since that release needs a protocol increment or a `compatibleChanges` acknowledgment that invokes the additive list above.
Declarations added since that release need neither.
One bullet is only partly digestible: the `/health` and `/rpc` path literals inside `http-server.ts`.
For that gap, the manifest records the gap and its reason instead of implying coverage.
See `test/wire-compat/README.md`.
Expand Down
2 changes: 1 addition & 1 deletion docs/adr/0007-remote-device-leases.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ It stays below daemon device leases and should not be weakened or replaced by th

`open` is the natural point to acquire a device lease because target resolution and session creation meet there.
Commands after `open` must refresh the lease.
After five minutes without activity, the device should become available again.
After the default 60 seconds without activity, the device should become available again.

These operations must run under the same daemon request lock:

Expand Down
Loading
Loading