ace-hitl 0.16.0 → 0.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +160 -0
  3. data/README.md +60 -69
  4. data/docs/usage.md +237 -421
  5. data/handbook/workflow-instructions/hitl.wf.md +55 -6
  6. data/lib/ace/hitl/adapters/registry.rb +65 -0
  7. data/lib/ace/hitl/adapters/terminal.rb +75 -0
  8. data/lib/ace/hitl/adapters.rb +80 -0
  9. data/lib/ace/hitl/atoms/hitl_address.rb +88 -0
  10. data/lib/ace/hitl/atoms/hitl_event_text.rb +54 -0
  11. data/lib/ace/hitl/cli/commands/create.rb +81 -12
  12. data/lib/ace/hitl/cli/commands/lifecycle_command.rb +1 -7
  13. data/lib/ace/hitl/cli/commands/list.rb +22 -1
  14. data/lib/ace/hitl/cli/commands/operator_question.rb +27 -0
  15. data/lib/ace/hitl/cli/commands/read.rb +22 -0
  16. data/lib/ace/hitl/cli/commands/send.rb +85 -0
  17. data/lib/ace/hitl/cli/commands/serve.rb +28 -37
  18. data/lib/ace/hitl/cli/commands/show.rb +23 -3
  19. data/lib/ace/hitl/cli/commands/update.rb +4 -0
  20. data/lib/ace/hitl/cli/commands/wait.rb +5 -0
  21. data/lib/ace/hitl/cli.rb +14 -18
  22. data/lib/ace/hitl/lifecycle/binding.rb +13 -0
  23. data/lib/ace/hitl/lifecycle/frame_serving.rb +2 -16
  24. data/lib/ace/hitl/lifecycle/kinds.rb +1 -1
  25. data/lib/ace/hitl/lifecycle/lifecycle_requests.rb +2 -34
  26. data/lib/ace/hitl/lifecycle/operator_questions.rb +84 -0
  27. data/lib/ace/hitl/lifecycle/policy.rb +12 -41
  28. data/lib/ace/hitl/lifecycle/protocol.rb +1 -2
  29. data/lib/ace/hitl/lifecycle/service.rb +2 -3
  30. data/lib/ace/hitl/lifecycle/store.rb +72 -77
  31. data/lib/ace/hitl/lifecycle/tls_access_policy.rb +2 -12
  32. data/lib/ace/hitl/lifecycle/tls_project_scope.rb +0 -15
  33. data/lib/ace/hitl/lifecycle/tls_service.rb +2 -3
  34. data/lib/ace/hitl/lifecycle.rb +2 -4
  35. data/lib/ace/hitl/live_client.rb +11 -87
  36. data/lib/ace/hitl/models/hitl_event.rb +35 -0
  37. data/lib/ace/hitl/molecules/hitl_address_resolver.rb +80 -0
  38. data/lib/ace/hitl/molecules/hitl_config_loader.rb +22 -1
  39. data/lib/ace/hitl/molecules/hitl_creator.rb +126 -27
  40. data/lib/ace/hitl/molecules/hitl_delivery_state.rb +58 -0
  41. data/lib/ace/hitl/molecules/hitl_display_formatter.rb +3 -2
  42. data/lib/ace/hitl/molecules/hitl_loader.rb +19 -2
  43. data/lib/ace/hitl/molecules/hitl_route_loader.rb +78 -0
  44. data/lib/ace/hitl/organisms/hitl_manager.rb +51 -5
  45. data/lib/ace/hitl/organisms/hitl_sender.rb +147 -0
  46. data/lib/ace/hitl/providers/lab.rb +15 -129
  47. data/lib/ace/hitl/version.rb +1 -1
  48. data/lib/ace/hitl.rb +8 -1
  49. metadata +17 -45
  50. data/lib/ace/hitl/cli/commands/ask.rb +0 -136
  51. data/lib/ace/hitl/cli/commands/overseer_ack.rb +0 -30
  52. data/lib/ace/hitl/cli/commands/overseer_pending.rb +0 -28
  53. data/lib/ace/hitl/cli/commands/overseer_send.rb +0 -35
  54. data/lib/ace/hitl/cli/commands/proposal.rb +0 -75
  55. data/lib/ace/hitl/lifecycle/overseer.rb +0 -111
  56. data/lib/ace/hitl/lifecycle/proposals.rb +0 -297
  57. data/lib/ace/hitl/lifecycle/service_publication_binding.rb +0 -97
  58. data/lib/ace/hitl/proposals/evaluator.rb +0 -29
  59. data/lib/ace/hitl/proposals/policy.rb +0 -126
  60. data/lib/ace/hitl/providers/lab/assignment_binding.rb +0 -126
  61. data/lib/ace/hitl/providers/lab/protected_assignment_binding.rb +0 -75
  62. data/lib/ace/hitl/providers/providers.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d2bae48cdaf02e617f52c254eb78f5a8dae316be06a8787d4282041c01eacc3
4
- data.tar.gz: 81410404b3ad0e07900497a9f62594aba56aaf987ed2d816d208bcab112b096c
3
+ metadata.gz: a9186e91db61d509bafd0c44d8ad023ed208614ad8cbfe749d3b49b0bbf10772
4
+ data.tar.gz: 151a5ad5cda6dc92256a7f2f604249858c04666c23a5a6ce85c9347dbf4640f4
5
5
  SHA512:
6
- metadata.gz: e5ad8fad6083826ca4f1fb6220d7bf87bd302482bbbe946cc93778bf83279d3cf728898e9f2c9bb286ebac9e98a278b5129ab3914d1ee7b354c2befd07400129
7
- data.tar.gz: 1b0bae700322c0fae15a9f6ab81a7efd5faad863db9f729115909c95e66087be26b2217ad037e5e21ea3a7e7dc7bd418afa3dd1b01654f8f5fcda36007fd5b3d
6
+ metadata.gz: 8f6a6ef440d4404df3868ddc1e416032a09a1b59eb36e9d9a9317f214939677a5c58a724ec8cebd10bf88a7d5d1f412671f724be0957dd54c938b54cf06a1c44
7
+ data.tar.gz: 6dd4dae6d026e1167dcb7225188f7b5e73fd9fbfc4fde1625e1988daf4fb4922b2e8a477e5f142c68aad6032a806512fc6506ab0ad05eb71aed144627965e137
data/CHANGELOG.md CHANGED
@@ -7,6 +7,166 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.23.1] - 2026-10-18
11
+
12
+ ### Fixed
13
+
14
+ - Terminal routes are machine-scoped (round-9 review H1): the adapter now
15
+ reads the route's `machine` (defaults to `hitl.machine`) and refuses a
16
+ panel recipient on a different machine instead of delivering to a
17
+ local pane that merely shares the panel name and reporting a false
18
+ `delivered`. The refusal mirrors the hermes adapter, so both shipped
19
+ adapters apply the same address check.
20
+
21
+ ### Changed
22
+
23
+ - Docs only: `docs/usage.md` now documents that route delivery requires
24
+ a panel-form recipient (folder-form recipients have no shipped delivery
25
+ route and are refused per-route), the per-route refusal semantics of
26
+ both shipped adapters, per-route `unavailable` retention for unknown
27
+ adapters, dotted route-name rejection, and the absolute `reply_to`
28
+ folder. `HitlConfigLoader.normalize` notes that mixing flat/shaped
29
+ config documents across tiers can invert cascade precedence.
30
+
31
+ ## [0.23.0] - 2026-10-18
32
+
33
+ ### Fixed
34
+
35
+ - Adapters deliver to the event's recipient, not just the route's own
36
+ destination (PR #383 audit F1): the terminal adapter sends to the
37
+ recipient's `panel` (the route `pane` remains the fallback only for
38
+ legacy recipient-less events) and explicitly refuses a folder-form
39
+ recipient it cannot serve — never a silent send to the route pane.
40
+ Flat hitl config documents are no longer silently dropped (F11):
41
+ `.ace/hitl/config.yml` without the `hitl:` key now merges over the
42
+ shipped defaults instead of being shadowed by them. The default reply
43
+ address is built from the resolved sender folder (F6): an absolute
44
+ path that identifies the originating worktree, so two worktrees on
45
+ one machine never share a reply address (the relative `root_dir`
46
+ setting stays relative in config). Route names containing a dot
47
+ (e.g. `captain.telegram`) are rejected before any delivery attempt
48
+ (F10): delivery retention keys route names literally and a dot would
49
+ nest frontmatter keys, breaking retry/skip — `send` now fails closed
50
+ with `InvalidRouteError` naming the route.
51
+
52
+ ### Changed
53
+
54
+ - An unknown adapter on one route no longer aborts the whole send
55
+ (PR #383 audit F5): the route is retained as `unavailable` with the
56
+ resolution error as its reason (never a bare `in_flight` marker), the
57
+ remaining routes still deliver, and the send still reports overall
58
+ delivery failure.
59
+
60
+ ## [0.22.0] - 2026-10-18
61
+
62
+ ### Added
63
+
64
+ - Retention and redelivery of undelivered messages (8xg.t.sbz.1.3 / L2.4):
65
+ `send` now persists each route's last outcome, failure reason, and attempt
66
+ timestamp on the event's own file (`delivery.<route>` frontmatter — the
67
+ single state owner per ADR-034; no journal or queue). Default `send`
68
+ retries only undelivered or unknown-result routes and skips confirmed
69
+ delivered ones; `--force` redelivers every route and `--dry-run` reports
70
+ the retry/skip decisions without delivering. A `in_flight` marker written
71
+ before each attempt means a crashed send leaves an unknown result that the
72
+ next `send` retries — at-least-once semantics: a retry may duplicate, and
73
+ every rendering carries the same `(case <ID>)` + task binding so
74
+ recipients dedup by ID (exactly-once is not promised). Redelivery retries
75
+ the delivery, never the assignment. `list --delivery undelivered|delivered`
76
+ discovers retained events; `show` prints a per-route `Delivery:` block
77
+ with the retained failure reason. Redelivering an all-delivered event is a
78
+ no-op success (`nothing to retry (use --force to redeliver)`).
79
+
80
+ ## [0.21.0] - 2026-10-18
81
+
82
+ ### Added
83
+
84
+ - Configurable adapter delivery routes (8xg.t.sbz.1.2 / L2.3): `ace-hitl
85
+ send <ref>` delivers a persisted event through the routes configured under
86
+ `hitl.adapters.routes` — the sender interface is adapter-independent, so
87
+ switching transports is pure configuration (no assignment or coworker
88
+ change). Every route reports its own result line; one route's success never
89
+ hides another's failure and an unavailable adapter never silently reroutes
90
+ (per-route isolation, fail-closed unknown-adapter/no-route errors).
91
+ Built-in `terminal` adapter pushes the shared event text to a pane via any
92
+ `ace-runtime` terminal (tmux/herdr); `ace-hitl-hermes` 0.8.0 ships the
93
+ `hermes` adapter entrypoint (publishes the shared rendering to the channel
94
+ folder; identical resend is idempotent, different-bytes collision fails
95
+ without overwrite, missing folder is `unavailable`). New adapters register
96
+ through the duck-typed `Ace::Hitl::Adapters` registry
97
+ (`lib/ace/hitl/adapters/<name>.rb` entrypoint — a future Nervus adapter
98
+ needs no ace-hitl change). Shared rendering (`Atoms::HitlEventText`):
99
+ `[HITL question]`/`[HITL report <result>]` prefix, `Reply-To:` on questions
100
+ only, task/assignment/step context. Delivery results are reported, not
101
+ persisted — retention and redelivery of undelivered messages is
102
+ 8xg.t.sbz.1.3.
103
+
104
+ ## [0.20.0] - 2026-10-18
105
+
106
+ ### Added
107
+
108
+ - Recipient addressing and Reply binding (8xg.t.sbz.1.1 / L2.2): `ace-hitl
109
+ create ... --to <name>` resolves a configured recipient into an explicit
110
+ address — machine + events folder + case ID (folder form, ID stamped from
111
+ the new event) or machine + panel — read from the `hitl` cascade
112
+ (`machine`, `default_recipient`, `recipients:<name>:{machine,folder|panel}`).
113
+ Questions record a `reply_to` address (sender machine + events folder + own
114
+ case ID) so answers bind to the original case and the right agent;
115
+ task/assignment/step stay context, never an ID substitute. Local Reply is
116
+ unchanged: `update <ref> --answer` bound by exact ID with strict ambiguity
117
+ and explicit not-found — no write to a foreign event. Unknown recipient
118
+ names, malformed configured addresses, and a missing `hitl.machine` fail
119
+ closed before anything is written. `show`/create output print
120
+ `Recipient:`/`Reply-To:`; `HitlEvent#recipient`/`#reply_to` expose the
121
+ address hashes for adapters (delivery itself lands in 8xg.t.sbz.1.2/.1.3;
122
+ local write is not delivery).
123
+
124
+ ## [0.19.0] - 2026-10-18
125
+
126
+ ### Fixed (review PR #383, round 3)
127
+
128
+ - Report events carry no `kind` (loader returns nil), so question-oriented
129
+ `list --kind` filters never mix reports into a clarification list.
130
+
131
+ ### Added
132
+
133
+ - Report events: the same `ace-hitl` file interface now records work-done/error notifications alongside questions. `ace-hitl create "..." --type report --result success|error [--body line]... [--task REF]` writes an event with status `recorded`, a `## Report` body, task/assignment/step references, and its own ID. Reports never await an answer: `wait`, `update --answer`, and `update --resume` on a report fail fast with an explicit error (exit 1); generic `--set/--add/--remove/--move-to` still work so an overseer can archive processed reports.
134
+ - `--type question` is now written explicitly on new question events (loader defaults keep existing files without `type` valid questions); `--task` is accepted for both types; `list --type question|report` filters by type; `show` prints `Type:`/`Result:` and list gains the `recorded` status symbol.
135
+ - Library guards: `HitlManager#update(answer:)` raises `NotAnswerableError` on reports before any file mutation; `wait_for_answer` and `dispatch_resume` return `{status: :report}` without sleeping.
136
+
137
+ ### Notes
138
+
139
+ - Local write is not delivery: `recorded` means the report is persisted in `.ace-local/hitl/`, not that it reached the overseer. Remote addressing, reply routing, and configurable adapters land in 8xg.t.sbz.1.1–.1.3.
140
+
141
+ ## [0.18.0] - 2026-10-18
142
+
143
+ ### Removed
144
+
145
+ - Remove the installed Lab provider and its attempt-bound managed HITL path: `Providers::Lab::AssignmentBinding`, `ProtectedAssignmentBinding`, the provider `ask`/native-delivery methods, the `ask` CLI command, and the Herdr-native delivery client in `LiveClient` (the old ace-assign `AttemptCoordinator`/journal identity).
146
+ - Remove the second-commander proposal surface: the `proposal` CLI command, `Lifecycle::Proposals`, the proposal policy/evaluator, proposal frames, and the publication HITL binding tied to the removed publication authority.
147
+ - Remove managed and TLS `serve` modes: `serve` requires `--operator-only` and fails clearly otherwise.
148
+ - Remove the unused old-lab Root Overseer reverse-address channel: `Lifecycle::Overseer`, the `overseer-send`/`overseer-pending`/`overseer-ack` CLI commands, the default `mo` responder, the `ACE_HITL_OVERSEER_CHANNEL_ROOT`/`/lab/state/overseer-channel` default, and the `[decyzja]`/`[pytanie]`/`[info]` response policy. Generic HITL transport and the ready lifecycle surface are unchanged; there is no replacement queue or relay for this role policy.
149
+ - Remove the now-dead `LifecycleCommand::STDIN_READER` constant (`deliver` reads stdin inline) and add a Duty projection regression test covering the answer-delivered pending state and mixed effect visibility.
150
+
151
+ ### Changed
152
+
153
+ - `LiveClient` keeps the requester-side authenticated boundary operations (`wait`, `status`, `pending`); the lifecycle/relay transport (`Lifecycle::*`) remains for `ace-hitl-hermes`.
154
+ - Drop the now-unused `ace-assign` and `ace-herdr` runtime dependencies (the managed attempt binding required them); re-lock the workspace Gemfile.lock locally.
155
+
156
+ ## [0.17.0] - 2026-10-16
157
+
158
+ ### Added
159
+
160
+ - Add explicit unassigned operator questions with kernel requester UID, exact installed project grants, stable retries and existing request/terminal recovery. Expose public client/CLI creation/read and an operator-only service binding that refuses managed execution, secrets and effects.
161
+
162
+ ### Changed
163
+
164
+ - Require the ace-hitl-contract 0.3 operator-question envelope for the tagged request union.
165
+
166
+ ### Fixed
167
+
168
+ - Require a reconciliation checkpoint to name the canonical proposal project before silence can authorize its effect.
169
+
10
170
  ## [0.16.0] - 2026-10-16
11
171
 
12
172
  ### Added
data/README.md CHANGED
@@ -1,89 +1,80 @@
1
1
  # ace-hitl
2
2
 
3
- `ace-hitl` manages ACE human-in-the-loop (HITL) events in `.ace-local/hitl/`.
3
+ Human-in-the-loop (HITL) event files for ACE agents and operators.
4
+
5
+ > **State owner:** `.ace-local/hitl/` -- HITL event markdown files owned by
6
+ > `ace-hitl`. Other tools must not write there directly. The agent event
7
+ > history is local and untracked. The canonical flow is
8
+ > [docs/lab-flow.md](../docs/lab-flow.md).
4
9
 
5
10
  Canonical workflow and skill for agents:
6
11
 
7
12
  - Workflow: `wfi://hitl`
8
13
  - Skill: `as-hitl`
9
14
 
10
- ## Commands
11
-
12
- - `ace-hitl create` creates a HITL event
13
- - `ace-hitl ask` asks a human via HITL and forwards the request through a provider adapter (`--provider`, default `lab`); ONE operation: local event + relay request through the authenticated boundary (`--assignment/--attempt/--project` managed binding, effect callback flags)
14
- - `ace-hitl list` lists HITL events with filters (`--scope current|all`, all statuses by default)
15
- - `ace-hitl show` renders event details, path, or raw content (`--scope current|all`)
16
- - `ace-hitl update` updates frontmatter, answer content, and folder location
17
- - `ace-hitl wait` polls a specific HITL event until answered (`--poll-every`, `--timeout`)
18
- - `ace-hitl deliver` answers a pending relay request from stdin (configured transport operation through the boundary); executes the declared effect callback (non-OTP kinds)
19
- - `ace-hitl consume` consumes one own relay request's answer (indefinite by default; `--timeout` bounds only the local wait)
20
- - `ace-hitl cancel` cancels with an audited reason (the only way to abandon a request)
21
- - `ace-hitl pending` / `ace-hitl states` / `ace-hitl duty` transport projections (pending, public lifecycle records, pending + escalated)
22
- - `ace-hitl serve` runs the authenticated store boundary service (peer-credential UNIX socket; trusted grants authorize the transport)
23
-
24
- Multi-user HITL state (spec 8wq.t.34i) is the PRIVATE state of the
25
- `ace-hitl serve` boundary: identity comes from kernel peer
26
- credentials, transport authority from the trusted grants document,
27
- and OTP secrets are held in service memory only — never in files,
28
- logs, or projections.
29
- - `ace-hitl overseer-send` / `ace-hitl overseer-pending` / `ace-hitl overseer-ack` the Overseer reverse-address response channel
30
-
31
- `ace-hitl` is a blocker-resolution tool, not a global dashboard:
32
-
33
- - linked worktree default: local (`--scope current`)
34
- - main checkout default: operator view (`--scope all`)
35
-
36
- Use `ace-overseer status` for a global worktree dashboard.
37
-
38
- ## Provider adapters
39
-
40
- `ace-hitl ask --question ... --assignment ... --attempt ...` creates a scoped
41
- request through authenticated IPC. The managed coordinator verifies the exact
42
- active native owner and reverse address; caller environment variables cannot
43
- supply authority. No Lab daemon or Work binding is used.
44
-
45
- `Ace::Hitl::LiveClient` provides explicit in-process `deliver`, `watch`, `wait`,
46
- `status`, `pending`, and signed `reconcile`. `watch` returns a thread owned by
47
- its calling agent. Native delivery commits an incarnation-bound event through
48
- Herdr Inbox and registers it through Assign. Queue acceptance and wake do not
49
- prove consumption. Only an event-bound signed native observation verified by
50
- Herdr and journaled by Assign completes delivery. Business callbacks have
51
- separate authorization and receipts and are never rerun by native retries.
52
-
53
- Pane-less `wait --request ID` consumes an existing authorized request over IPC;
54
- it neither creates a native target nor proves a business effect. OTP answers
55
- use that protected path with their authorized operation; no OTP bytes or OTP
56
- hash enter the shared envelope, folder or native inbox.
15
+ ## What exists today
16
+
17
+ `ace-hitl` manages HITL events stored as markdown files under `.ace-local/hitl/`.
18
+ An event records a question or decision, its context (assignment/step), its
19
+ status, and the answer — or a report (work done / error) that never awaits an
20
+ answer. This is the local, file-based path; it needs no
21
+ listener, daemon, or database.
22
+
23
+ | Command | Purpose |
24
+ |---------|---------|
25
+ | `ace-hitl create` | Create a question event (kind, questions, assignment/step context, resume instructions) or a report event (`--type report --result success\|error --body ... --task ...`) |
26
+ | `ace-hitl list` | List events with status/kind/type/tag/folder/scope filters |
27
+ | `ace-hitl show` | Render event details, path, or raw markdown |
28
+ | `ace-hitl update` | Update frontmatter, write an answer, or move the event |
29
+ | `ace-hitl wait` | Poll one question event until it is answered (reports are rejected) |
30
+ | `ace-hitl send` | Deliver an event through the configured adapter routes; per-route results retained on the event, redelivery retries undelivered/unknown routes |
31
+
32
+ `ace-hitl` is a blocker-resolution tool, not a global dashboard: in a linked
33
+ worktree it defaults to local (`--scope current`); in the main checkout it uses
34
+ the operator view (`--scope all`). Use `ace-overseer status` for a worktree
35
+ dashboard.
57
36
 
58
37
  ## Examples
59
38
 
60
39
  ```bash
61
- ace-hitl list
62
- ace-hitl list --scope all
63
- ace-hitl create "Which auth strategy?" --kind decision --question "JWT or sessions?"
64
- ace-hitl ask --question "Proceed with deploy?" --assignment assign685 --attempt attempt685 --effect-arg /bin/false --effect-cwd /tmp
65
- ace-hitl ask --question "Proceed with deploy?" --provider lab --assignment assign685 --attempt attempt685
40
+ ace-hitl create "Which auth strategy?" --kind decision \
41
+ --question "JWT or sessions?" --assignment abc123 --step 020
42
+ ace-hitl create "Work done" --type report --result success \
43
+ --body "Implemented JWT login" --task 8xg.t.sbz.1.0
44
+ ace-hitl list --status pending
45
+ ace-hitl list --type report
66
46
  ace-hitl show abc123 --content
67
- ace-hitl show abc123 --scope current
68
47
  ace-hitl update abc123 --answer "Use JWT with server-side refresh tokens."
69
- ace-hitl wait abc123
70
- ace-hitl update abc123 --answer "Use JWT with server-side refresh tokens." --resume
48
+ ace-hitl update abc123 --move-to archive
49
+ ace-hitl wait abc123 --poll-every 600 --timeout 14400
71
50
  ```
72
51
 
73
- ## Testing
74
-
75
- This package has deterministic fast and scoped integration tests.
52
+ ## Transport boundary
53
+
54
+ > The installed Lab provider and the attempt-bound managed HITL path (`ask`,
55
+ > provider assignment binding, native Herdr delivery, managed/TLS `serve`) were
56
+ > removed with the old authority model. The local file-based HITL events above
57
+ > remain the active path. The lifecycle/relay transport (`Lifecycle::*`) and
58
+ > its commands remain for `ace-hitl-hermes` and other adapters; `serve` supports
59
+ > `--operator-only` only. Second-commander proposals are removed as well.
60
+ >
61
+ > **L2 status:** report/question distinction, recipient addressing
62
+ > (`--to`, `reply_to`), adapter-route delivery (`send` with the built-in
63
+ > terminal adapter and `ace-hitl-hermes` as the hermes adapter), and
64
+ > retention/redelivery of undelivered messages (per-route records on the
65
+ > event; `send` retries undelivered/unknown routes, `--force` redelivers
66
+ > with the same case ID) are available. `ace-hitl-hermes` remains an
67
+ > adapter package; tmux/Herdr remain transports.
76
68
 
77
- - Deterministic test coverage lives under `test/fast/`.
78
- - This migration does not introduce `test/feat/` or `test/e2e/` for this package.
79
-
80
- Verification commands:
81
-
82
- - `ace-test ace-hitl`
83
- - `ace-test ace-hitl all`
69
+ ## Testing
84
70
 
85
- ## Ownership Boundary
71
+ ```bash
72
+ bin/ace-test ace-hitl
73
+ bin/ace-test ace-hitl all
74
+ ```
86
75
 
87
- `ace-hitl` owns HITL-specific event semantics and markdown contract.
76
+ ## Ownership boundary
88
77
 
89
- `ace-support-items` remains generic support infrastructure and should not absorb HITL-specific domain behavior.
78
+ `ace-hitl` owns HITL event semantics and the markdown contract.
79
+ `ace-support-items` remains generic support infrastructure and does not absorb
80
+ HITL-specific behaviour.