Skip to content

Commit e77a8bc

Browse files
authored
feat(tooling): simplify agent workflows and validation (#3705)
* feat(tooling): serialize validation and emit compact execution receipts * docs(agents): route tasks and clarify validation boundaries * fix(tooling): fingerprint untracked nested Git repositories * fix(tooling): bound individual failure excerpt lines * chore(gates): tighten agent context budgets and register validation entry * fix(tooling): address validation review findings * test(android): verify the final fill sample without a capture quota * fix(tooling): limit serialized validation to supported hosts
1 parent b7c93e3 commit e77a8bc

36 files changed

Lines changed: 1776 additions & 581 deletions

‎.fallowrc.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"entry": [
44
"tsdown.config.ts",
55
"scripts/check-provider-plugin.mjs",
6+
"scripts/check-affected/command.ts",
67
"packages/provider-testmu/test/package-smoke.mjs",
78
"packages/provider-testmu/tsdown.config.ts",
89
"packages/provider-testmu/src/plugin.ts",

‎AGENTS.md‎

Lines changed: 39 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,146 +1,61 @@
11
# AGENTS.md
22

3-
`agent-device` is a CLI and daemon for automating Apple, Android, HarmonyOS, Vega, Linux, and web
4-
targets. A long-lived daemon owns sessions; registry-derived commands route to platform runtimes.
3+
`agent-device` is a CLI and daemon for automating devices and web targets.
4+
The daemon owns sessions. Registry declarations route commands to platform runtimes.
55

66
## Task routing
77

8-
Load only the procedures relevant to the task:
8+
Read only the row for your current task. Follow further links only when they apply.
99

1010
| When the task involves | Read |
1111
| --- | --- |
1212
| Domain vocabulary | `CONTEXT.md`, `docs/agents/domain.md` |
1313
| Architecture decisions | `docs/adr/README.md` |
14-
| Tests or gate selection | `docs/agents/testing.md` |
15-
| Writing, auditing, or sweeping tests; dispatching test-audit subagents | `docs/agents/test-audit.md` |
16-
| Selector capture, polling, or interaction fast paths | `docs/agents/selector-capture.md` |
14+
| Source changes, package boundaries, routing, diagnostics | `docs/agents/code-ownership.md` |
15+
| Running checks or diagnosing a failed gate | `docs/agents/testing.md` |
16+
| Writing or changing tests | `docs/agents/test-authoring.md` |
17+
| Auditing or deleting tests | `docs/agents/test-audit.md` |
18+
| Mutation experiments or base comparisons | `docs/agents/test-experiments.md` |
19+
| Changing gate selection, fuzzing, or mutation harnesses | `docs/agents/gates.md` |
20+
| Selector capture, polling, interaction fast paths, replay | `docs/agents/selector-capture.md` |
1721
| Adding or changing a CLI flag | `docs/agents/cli-flags.md` |
18-
| Opening or reviewing a PR | `docs/agents/pull-requests.md` |
19-
| Apple runner changes or manual device verification | `docs/agents/device-verification.md` |
22+
| Opening or updating a PR | `docs/agents/pull-requests.md` |
23+
| Reviewing a change | `docs/agents/review.md` |
24+
| Device-facing changes or manual device verification | `docs/agents/device-verification.md` |
2025
| Writing issues or PRDs, and triage labels | `docs/agents/issue-tracker.md`, `docs/agents/triage-labels.md` |
2126
| Web backend setup or diagnostics | `docs/agents/web-backend.md` |
2227

23-
Versioned CLI help owns command semantics. Read the relevant topic when behavior is unclear;
24-
normal app-driving startup follows the skill's routing card.
28+
Device-facing changes affect live device behavior: dispatch, capture, interaction, app lifecycle, or native execution.
29+
A daemon edit that changes none of these needs no device run.
2530

26-
## Incident-derived principles
31+
Versioned CLI help owns command semantics. For app-driving startup, use the skill's routing card.
2732

28-
- Classify interaction dispatch paths in `packages/contracts/src/interaction-guarantees.ts` and
29-
verify each claim against the native implementation.
30-
- Delegation on error proves no success-path parity. A fast path may succeed on a candidate the
31-
shared rules would refuse.
32-
- Prove both paths are reachable before measuring a fast path against its baseline.
33-
- Repair recurring failures at the owning type, registry, or construction path; do not add guards
34-
that reconstruct another source of truth.
35-
- Keep control-flow narration and review history out of implementation comments. Encode invariants
36-
in names, types, boundaries, and tests; reserve comments for public API docs, tool directives,
37-
and non-obvious constraints that cannot be encoded.
38-
- Key behavior on typed reasons and details, never error text; do not copy existing message sniffs.
39-
- A claim about a platform family in code, help, or docs holds for every backend in it (Appium as
40-
well as ADB on Android), or names the backends it covers.
41-
- Keep metadata at response level when it applies to the whole snapshot. Append warnings through
42-
the shared response builder; never replace prior warnings.
43-
- Before preserving a compatibility shape, run `git tag --contains <commit>`. Unreleased API has no
44-
external compatibility obligation.
33+
## Working rules
4534

46-
## Declaration sites and enforcement
35+
- Keep edits within the requested command family or module group. Inspect other platforms only when the task requires it.
36+
- Fix recurring failures at the owning type, registry, or construction path. Do not reconstruct another owner's state.
37+
- Use typed reasons and details for behavior. Never match error text.
38+
- Add compatibility or fallback behavior only when explicitly requested or approved. Remove superseded paths during migrations.
39+
- Encode invariants in names, types, and boundaries. Comments explain public APIs, tool directives, or constraints code cannot express.
40+
- Resolve gate failures at the reported invariant. Do not suppress them or add an allowlist to get a pass.
41+
- Use `@agent-device/selectors` for selector parsing and matching. See `docs/agents/code-ownership.md` for other shared owners.
42+
- Keep skills as routing cards. Keep `CONTEXT.md` glossary-only. Update owning help and user docs when behavior changes.
4743

48-
Read the declaration rather than maintaining a prose copy:
44+
## Worktree setup
4945

50-
- commands and their surface, runtime-use, batch, and timeout traits:
51-
`packages/command-registry/src/registry.ts`
52-
- daemon route ownership and request-policy traits: `packages/daemon/src/core/daemon-command-registry.ts`
53-
- interaction paths and guarantees: `packages/contracts/src/interaction-guarantees.ts`
54-
- canonical command names: `packages/command-registry/src/catalog.ts`
55-
- device runtime-use declarations and fact admission:
56-
`packages/command-registry/src/registry.ts`, `packages/daemon/src/core/runtime-admission.ts`, and
57-
`src/platform-runtime-gateway.ts`
58-
- common command input fields, and which surface may write an input key (model, operator, retired):
59-
`src/commands/common-input-fields.ts` and `src/commands/input-audience.ts`
46+
- Use `pnpm`. Use OXC for lint and format. Run `pnpm format` repository-wide.
47+
- In a fresh worktree, run `pnpm install --frozen-lockfile && pnpm build` before testing.
48+
- Preserve other worktrees, devices, sessions, dirty files, and experiments.
49+
- Never copy `.env` into a worktree. For host credentials, source the main checkout's file by absolute path.
50+
- Give parallel workers disjoint files and distinct devices. `pnpm check:affected --run` and `pnpm check` serialize automatically.
51+
- The layering scan reads tracked files. Stage new modules before trusting its result.
52+
- Move a path's Fallow baseline entry when renaming its file. Do not regenerate unrelated baselines.
6053

61-
Shared selector parsing and matching belongs in `@agent-device/selectors`; daemon-side request
62-
cancellation and progress in `@agent-device/host-kit/request`, and the caller's per-call abort guard
63-
beside the transports it serves in `src/daemon-client/daemon-client-transport.ts`; cross-layer
64-
contracts in `packages/contracts/src`; CLI flags in `src/commands/cli-grammar`; cross-surface schema
65-
composition in `src/commands/schema`.
54+
The validation lock reclaims provably dead owners automatically. Unknown owners remain blocking.
55+
If waiting times out, report the printed owner and lock state; do not remove it by hand.
6656

67-
Resolve registry completeness failures at the missing declaration. Diagnose other gate failures
68-
at their reported invariant; do not suppress them or add an allowlist to get a pass. Build interaction
69-
responses through `buildInteractionResponseData`; change cross-language rules through golden tables
70-
under `contracts/fixtures/`.
57+
## Agent docs
7158

72-
## Hard repository rules
73-
74-
- Plain `.mjs` packaging fixtures that cannot import TypeScript execution helpers keep child-process
75-
use local and prefer `execFile`.
76-
- Apple target changes keep the kernel device model, runtime-fact admission, dispatch resolution,
77-
Apple discovery, and xctestrun preparation in sync.
78-
- iOS simulator-set scoping must never hide the host macOS desktop target.
79-
- Skills stay minimal routing cards.
80-
- Add compatibility or fallback behavior only when explicitly requested or approved. Otherwise,
81-
complete the migration and remove superseded paths.
82-
- Keep changes within one command family or module group unless the task explicitly crosses a
83-
boundary. Platform-neutral work does not license inspecting every platform implementation.
84-
85-
## Module and test topology
86-
87-
- Name modules for the domain question they answer and colocate machine-readable claims with their
88-
enforcement. Internal barrels are legacy; add barrels only at package boundaries.
89-
- Files past 1,000 lines are architecture debt; split them before adding behavior, unless they
90-
are generated or fixture data.
91-
- Tests mirror source topology one-to-one. Split a source module and its test together; do not add to
92-
the legacy `interaction.test.ts` or platform `index.test.ts` aggregations. Pure moves carry their
93-
tests unchanged; rename-only hunks owe no new coverage.
94-
- A test sits beside the module it is named for: `<module>.test.ts` or `<module>-<aspect>.test.ts`
95-
(R84). Cross-module package tests are `index-<aspect>.test.ts` beside `index.ts`; repo-level guards on
96-
Swift sources, manifests, docs or scripts live in `test/repo-guards/`.
97-
- Add no package `exports` entry that points at test support; R83 only lets the legacy count fall. A
98-
fixture one package uses stays inside it, imported relatively; helpers shared across packages live only in `@agent-device/test-kit`, a
99-
`devDependency` production source never imports and that never depends on `platform-*`,
100-
`provider-*`, the daemon or root.
101-
102-
## Toolchain and worktree traps
103-
104-
- Use `pnpm`; never add `package-lock.json`. OXC owns lint and format. Run `pnpm format`
105-
repository-wide, not path-scoped.
106-
- A fresh worktree requires `pnpm install --frozen-lockfile && pnpm build`. Until then package and
107-
optional-peer resolution may point at another checkout and produce false failures.
108-
- Worktrees never receive `.env`; no repo code reads it. When a command needs a host credential,
109-
source the main checkout's copy by absolute path (`set -a && . /path/to/main/checkout/.env && set +a`)
110-
instead of copying it in or writing it into the worktree.
111-
- Parallel work needs disjoint edit ownership and distinct devices. Run one full gate per host;
112-
concurrent subprocess-backed suites can produce contention timeouts.
113-
- The layering scan reads tracked files only. Stage a new module before trusting its result.
114-
- Fallow baselines are path-keyed. Move the matching baseline entry when renaming a file; never bulk
115-
regenerate baselines to accept unrelated findings.
116-
117-
## Runtime and diagnostics seams
118-
119-
Diagnostics use `@agent-device/host-kit/diagnostics`. Request diagnostics belong in the session request log;
120-
session artifact paths come from `packages/daemon-contracts/src/session-artifact-paths.ts`. App/device logs remain in `app.log`;
121-
Apple runner and xcodebuild output remains in `runner.log`.
122-
123-
Normalize failures with `normalizeError` and preserve `hint`, `diagnosticId`, `logPath`, and typed
124-
`details`. An interaction taking five seconds or more is a daemon-log question: inspect runner
125-
restart, stale-session recovery, accessibility failure, transport retry, and timeout evidence.
126-
127-
Optional probes and caches are best-effort only when the feature contract says so. Their budgets
128-
must be shorter than the required operation they precede.
129-
130-
## Selector and replay invariants
131-
132-
Element interactions support selector and `@ref`, then record a selector chain after resolution.
133-
Replay failures may re-resolve that chain only to produce a ranked divergence suggestion; ADR 0012
134-
retired silent script rewriting.
135-
136-
Selector keys stay centralized in `@agent-device/selectors`; `is` predicates use
137-
`evaluateIsPredicate`. On macOS, snapshot rectangles are absolute in window space and point actions
138-
translate through the interaction root frame. Prefer selector or ref tests over raw coordinates.
139-
140-
## Documentation ownership
141-
142-
Keep this file to repository traps and routing. Put task procedures in `docs/agents/`, decisions in
143-
ADRs, and command semantics in versioned help. Link to executable registries instead of duplicating
144-
their rules. `CONTEXT.md` is glossary-only: no implementation paths, decisions, or migration status.
145-
146-
Behavior changes update owning help/metadata and user docs. Report docs or skill changes when relevant.
59+
Write short instructions with one action per sentence. Put the condition before its action.
60+
Use the same term for the same concept. Keep commands and domain terms exact.
61+
Route specialized rules to their task document. Delete duplicate or enforced rules before adding reminders.

‎CONTRIBUTING.md‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,11 @@ For broad refactors or when explicitly requested, run the deterministic core agg
217217
pnpm check
218218
```
219219

220-
`pnpm check` covers formatting, lint, typechecking, layering, dependency-graph parity, production
220+
Serialized validation (`pnpm check` and `check:affected --run`) requires macOS or Linux.
221+
On Windows, use the affected plan and direct focused checks.
222+
223+
`pnpm check` takes the same host lock as `check:affected --run`, prints a receipt path, and writes
224+
logs under `.tmp/validation`. It covers formatting, lint, typechecking, layering, dependency-graph parity, production
221225
exports, MCP metadata, the distributable build, bundle ownership, Fallow, unit tests, and local smoke
222226
tests. It is intentionally not a simulation of every CI job: coverage, provider integration,
223227
history-backed compatibility, specialized toolchains, and live device/browser lanes remain separate.
@@ -238,8 +242,8 @@ Useful direct entry points:
238242
- `pnpm fallow:all` — full-tree audit, including grandfathered baseline findings
239243
- `pnpm fallow:baseline` — intentionally regenerate the reviewed Fallow health baseline
240244

241-
See [`docs/agents/testing.md`](docs/agents/testing.md) for gate ownership, shared test utilities,
242-
mutation/fuzz lanes, contention policy, and test-speed rules. For real devices, follow
245+
See [`docs/agents/testing.md`](docs/agents/testing.md) for check selection and blocked validation; see
246+
[`test authoring`](docs/agents/test-authoring.md) for shared test utilities and test-speed rules. See [gate maintenance](docs/agents/gates.md) for mutation and fuzz harnesses. For real devices, follow
243247
[`docs/agents/device-verification.md`](docs/agents/device-verification.md); a fixture-backed test does
244248
not prove that a native path was active.
245249

‎docs/agents/code-ownership.md‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Code ownership
2+
3+
Read this for shared contracts, package boundaries, request routing, or diagnostics.
4+
Before editing a high-fan-in module, run `pnpm depgraph affected <path>` to scope callers and guarantees.
5+
6+
## Declarations
7+
8+
Read the owner. Do not copy its policy into consumers.
9+
10+
| Question | Owner |
11+
| --- | --- |
12+
| Command names | `packages/command-registry/src/catalog.ts` |
13+
| Surface, runtime, batch, timeout traits | `packages/command-registry/src/registry.ts` |
14+
| Daemon routes and request policy | `packages/daemon/src/core/daemon-command-registry.ts` |
15+
| Interaction guarantees | `packages/contracts/src/interaction-guarantees.ts` |
16+
| Runtime-fact admission | `packages/daemon/src/core/runtime-admission.ts`, `src/platform-runtime-gateway.ts` |
17+
| Input fields and audiences | `src/commands/common-input-fields.ts`, `src/commands/input-audience.ts` |
18+
19+
Shared selectors belong in `@agent-device/selectors`. Request cancellation and progress belong in
20+
`@agent-device/host-kit/request`. Per-call abort guards belong beside transports in
21+
`src/daemon-client/daemon-client-transport.ts`. Cross-layer contracts belong in `packages/contracts/src`.
22+
CLI flags belong in `src/commands/cli-grammar`; schema composition belongs in `src/commands/schema`.
23+
Build interaction data through `buildInteractionResponseData`. Change cross-language rules through `contracts/fixtures/` golden tables.
24+
25+
## Modules and tests
26+
27+
Name modules for the domain question they answer. Colocate claims with their enforcement.
28+
Use barrels only at package boundaries. Split files over 1,000 lines before adding behavior, except generated or fixture data.
29+
Split a source module and its tests together. Do not extend legacy interaction or platform index test aggregations.
30+
Keep tests beside their named module. Put repository artifact guards in `test/repo-guards/`.
31+
Keep a single-package fixture local. Shared helpers belong in `@agent-device/test-kit`, a devDependency.
32+
Production code never imports test-kit. Test-kit never depends on platforms, providers, the daemon, or root.
33+
Do not export test support from production packages.
34+
35+
## Diagnostics
36+
37+
Use `@agent-device/host-kit/diagnostics`. Keep request diagnostics in the session request log.
38+
Get session artifact paths from `packages/daemon-contracts/src/session-artifact-paths.ts`.
39+
Keep app/device output in `app.log`; keep Apple runner and xcodebuild output in `runner.log`.
40+
Normalize errors with `normalizeError`. Preserve `hint`, `diagnosticId`, `logPath`, and typed `details`.
41+
For interactions taking at least five seconds, inspect daemon and runner recovery, retries, accessibility failures, and timeouts.
42+
Use best-effort probes or caches only when the feature contract permits them. Keep their budgets below the required operation's budget.

‎docs/agents/device-foldable.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Foldable Apple verification
2+
3+
Read ADR 0025 before changing capture behavior on a multi-panel device. The iOS 27.1 runtime ships
4+
only with the Xcode that carries it, and `xcode-select` may point at an older one, so pin the
5+
toolchain per command:
6+
`DEVELOPER_DIR=<Xcode-27.1>/Contents/Developer xcrun devicectl device info displays --device <udid>`.
7+
8+
- Panels: that command lists each integrated panel with `backlightState`. Only the lit panel is
9+
capturable — a capture of the dark panel exits 0 and writes an all-black PNG.
10+
- Input routing: verify a fresh control after each pose change. A successful synthesis acknowledgement
11+
does not prove a hit. Inspect the runner and simulator `testmanagerd`/BackBoard logs for display
12+
identity and delivery; the resolved app window owns gesture coordinates and its target screen.
13+
- Pose: `agent-device fold closed|half-open|open` sends private HID inside the simulator and reads
14+
the hinge back through `devicectl device motion hinge-angle`. Device Hub and host Accessibility
15+
permission are not required. Re-snapshot afterwards: refs and coordinates do not survive folds.
16+
Verify locally with Device Hub stopped and the simulator booted through `simctl boot`; test all
17+
three poses, active panel capture, and an app interaction. Duo coverage remains local until GHA
18+
supports the runtime. To inspect the angle independently:
19+
`DEVELOPER_DIR=<Xcode-27.1>/Contents/Developer xcrun devicectl device motion hinge-angle --device <udid> --session-timeout 1 --timeout 5`.
20+
- Touch overlays export at the captured track size. The compositor checks its output (size,
21+
non-black) against the raw capture; on failure `record stop` keeps the raw file and reports
22+
`overlayWarning`. `record start --hide-touches` is only for the fastest raw capture.
23+
- iOS 27 SDK apps need UIScene lifecycle to launch on iOS 27.0/27.1.
24+
- The 27.1 beta accepts only the iPhone Duo device type; use another runtime for a non-foldable control.

0 commit comments

Comments
 (0)