@staix/agent-hub 0.23.1 → 0.25.0
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.
- package/CHANGELOG.md +24 -0
- package/README.md +32 -5
- package/docs/agent-notes/adapters.md +5 -2
- package/docs/agent-notes/bus.md +1 -0
- package/docs/agent-notes/daemon.md +16 -2
- package/docs/agent-notes/tasks.md +9 -2
- package/docs/agent-notes/tests.md +3 -0
- package/docs/dogfood.md +16 -2
- package/docs/memory.md +1 -1
- package/docs/operations.md +198 -5
- package/docs/profiles.md +2 -0
- package/docs/quickstart.md +19 -4
- package/docs/security.md +225 -8
- package/docs/specs/2026-09-19-agent-hub-design.md +54 -1
- package/docs/specs/2026-09-19-multi-project-design.md +12 -1
- package/docs/specs/2026-11-01-research-campaigns-design.md +351 -0
- package/docs/verification/2026-10-31-0.24.0.md +63 -0
- package/docs/verification/2026-10-31-claude-implementer-2.1.316.md +65 -0
- package/docs/verification/2026-11-01-0.25.0.md +91 -0
- package/docs/verification/claude-shell-wrapper-native.py +1 -1
- package/docs/verified.json +31 -15
- package/package.json +4 -3
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +5120 -4710
- package/src/adapters/claude-channel.ts +29 -6
- package/src/adapters/compat.ts +3 -3
- package/src/adapters/definitions/native-cli-claude-setup.ts +4 -0
- package/src/adapters/definitions/native-cli-doctor.ts +30 -0
- package/src/adapters/jcode.ts +3 -0
- package/src/adapters/registry.ts +1 -1
- package/src/cli/acon-register.ts +29 -0
- package/src/cli/autonomy-homes.ts +33 -0
- package/src/cli/autonomy-offline.ts +75 -0
- package/src/cli/autonomy-projects.ts +103 -0
- package/src/cli/autonomy.ts +44 -0
- package/src/cli/claude-homes.ts +123 -0
- package/src/cli/claude-profile-hook.ts +130 -0
- package/src/cli/handoff-args.ts +27 -0
- package/src/cli/handoff-output.ts +25 -0
- package/src/cli/help.ts +8 -4
- package/src/cli/identity.ts +8 -1
- package/src/cli/main.ts +174 -33
- package/src/cli/output.ts +8 -5
- package/src/cli/schedule-output.ts +8 -4
- package/src/cli/setup-homes.ts +46 -0
- package/src/cli/setup.ts +1 -1
- package/src/cli/study-output.ts +71 -0
- package/src/cli/study.ts +58 -0
- package/src/cli/task-output.ts +1 -0
- package/src/hub/action-class.ts +203 -14
- package/src/hub/action-enforce.ts +8 -6
- package/src/hub/action-policy.ts +95 -9
- package/src/hub/autonomy-consent.ts +173 -0
- package/src/hub/autonomy-defaults.ts +58 -0
- package/src/hub/autonomy.ts +232 -0
- package/src/hub/board.ts +871 -2
- package/src/hub/channel-project.ts +61 -0
- package/src/hub/config-apply.ts +3 -2
- package/src/hub/confirmation-matrix.ts +202 -0
- package/src/hub/control-client.ts +10 -1
- package/src/hub/daemon.ts +546 -27
- package/src/hub/envelope.ts +2 -0
- package/src/hub/events.ts +4 -1
- package/src/hub/execution-budget.ts +12 -0
- package/src/hub/handoff.ts +126 -0
- package/src/hub/hub-tools.ts +12 -2
- package/src/hub/manager.ts +64 -57
- package/src/hub/no-writes.ts +1 -1
- package/src/hub/path-policy.ts +12 -8
- package/src/hub/project.ts +14 -5
- package/src/hub/provenance.ts +30 -0
- package/src/hub/research-campaign.ts +265 -0
- package/src/hub/research-experiments.ts +445 -0
- package/src/hub/restart.ts +26 -0
- package/src/hub/schedules.ts +210 -9
- package/src/hub/session-identity.ts +49 -0
- package/src/hub/settings.ts +105 -8
- package/src/hub/task-repository.ts +11 -6
- package/src/hub/tasks.ts +894 -22
- package/src/hub/ui.ts +15 -6
- package/src/memory/capture.ts +2 -2
- package/src/ui/index.html +5 -3
- package/src/ui/office-space.ts +118 -0
- package/src/ui/plugin.ts +293 -0
- package/templates/AGENTS.block.md +1 -0
- package/templates/presets/autonomous.json +161 -0
- package/templates/presets/confirmation-matrix.json +943 -0
- package/templates/profiles/general.json +1 -1
- package/templates/profiles/research.json +4 -4
- package/templates/profiles/writing.json +1 -1
- package/templates/roles/research/analyst.md +1 -0
- package/templates/roles/research/fact-checker.md +1 -0
- package/templates/roles/research/research-lead.md +1 -0
- package/templates/roles/research/researcher.md +1 -0
- package/templates/roles/research/statistician.md +1 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Research campaigns, experiment receipts and runner attestation
|
|
3
|
+
date: 2026-11-01
|
|
4
|
+
project: agent-hub
|
|
5
|
+
status: frozen for implementation (task #595); slices #596 to #602
|
|
6
|
+
issue: 930, 932, 1018
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Research campaigns, experiment receipts and runner attestation
|
|
10
|
+
|
|
11
|
+
This document freezes the implementation contract for #929 R1 (#930, research campaigns), #929 R3 (#932, experiment protocols and attempt receipts) and #1018 (registered external runner). The issues hold the decisions and acceptance criteria; this spec fixes the wire names, schemas, bounds, storage and the delivery slices, so implementation does not have to invent them. Where it narrows or departs from an issue, the departure is listed in "Departures from the issues". #931 (evidence links) is out of scope.
|
|
12
|
+
|
|
13
|
+
The person directed on 2026-11-01 that #932 be implemented together with #1018. #932 depends on #930, so all three are in scope.
|
|
14
|
+
|
|
15
|
+
## Common rules
|
|
16
|
+
|
|
17
|
+
### Authority and paths
|
|
18
|
+
|
|
19
|
+
- Every board write goes through `Tasks` (AGENTS.md "Board writes"). New Tasks methods throw `PreEffectToolRefusal` before any effect, follow the existing validate, then `withholds`, then re-check order, and write history only through `board.update` or `board.plan`.
|
|
20
|
+
- Research roles stay catalog guidance. A unit's `purpose` grants no authority; dispatch, ownership and review use the existing routing and role admission.
|
|
21
|
+
- Activation, revision approval, scope or ceiling enlargement, attestation and runner registration are person only. A planner may draft and propose a revision; it cannot approve one.
|
|
22
|
+
- No model call and no filesystem read inside a database transaction. Screening, source lookups and file hashing run first; the transaction then re-checks revisions and writes.
|
|
23
|
+
|
|
24
|
+
### Provenance levels
|
|
25
|
+
|
|
26
|
+
A field that can be evidenced carries `{ value, provenance, evidence? }`:
|
|
27
|
+
|
|
28
|
+
| Level | Meaning | Set by |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `declared` | An agent or a person wrote it | any record call; the default |
|
|
31
|
+
| `host-observed` | The hub measured it itself | a check-runner receipt the hub reads from `stateDir/checks/<run>.json`, or a deliverable hash from `hashDeliverables` |
|
|
32
|
+
| `runner-attested` | A registered external runner signed it | a verified #1018 receipt |
|
|
33
|
+
| `person-attested` | The person attested it | console-only `ahub study attest` |
|
|
34
|
+
|
|
35
|
+
- No path converts one level into another. A higher level is a new evidence row with its own source, never an update of a declared value.
|
|
36
|
+
- Projections show the level next to every evidenced field. `runner-attested` never renders as `host-observed`. A missing field is `unknown`, not `declared`.
|
|
37
|
+
- None of the levels states scientific correctness.
|
|
38
|
+
|
|
39
|
+
### Bounds
|
|
40
|
+
|
|
41
|
+
Every text field is UTF-8 and bounded. A record above its bounds refuses whole, with the field named. Shared limits: an id matches `^[a-z0-9][a-z0-9_-]{0,63}$`; a short text is at most 512 bytes and a long text at most 4 KiB; a list is at most its stated count; a whole stored body is at most 64 KiB.
|
|
42
|
+
|
|
43
|
+
### Privacy
|
|
44
|
+
|
|
45
|
+
- A campaign whose parent task is PII, or that names a private source (`SourceMeta.private`), is private. So is an attempt whose task or protocol inputs are private.
|
|
46
|
+
- Public views of private records keep ids, counts, states and provenance levels, and stub every question, scope, text, path, excerpt and metric name as `[pii]` (the `publicView` rule). Raw source text is never stored in a campaign, a handoff or an attempt; they reference source ids.
|
|
47
|
+
- Nothing from a private campaign or attempt goes to claude-mem or any cloud observer. Handoffs and attempt notes are screened through the existing public and private delivery paths.
|
|
48
|
+
|
|
49
|
+
### Recovery and features
|
|
50
|
+
|
|
51
|
+
- New daemon feature `research_records` in `DAEMON_FEATURES`. `incompatibleRecoveryTarget` refuses a target without it while `board.hasResearchState()` finds any campaign, protocol, attempt or runner-receipt row, or `research.runners` is set in config.
|
|
52
|
+
- The recovery `integrity()` digest gains the row counts and the latest revision of the research tables.
|
|
53
|
+
|
|
54
|
+
## T1 implementation boundary (#596)
|
|
55
|
+
|
|
56
|
+
T1 provides the bounded parser, Board storage and host Tasks methods, with no public study CLI or hub tool until #601. A write receipt carries only generated campaign ids, revision, status and unit counts; the full unit/task mapping is returned only by person-only approval. No raw contract or close reason enters parent Task history or outcome memory.
|
|
57
|
+
|
|
58
|
+
A stable unit id retains its task across approved revisions and restart, including a unit omitted from an intervening revision. T1 retains only an identical work-bearing unit definition, including its dependencies; changed work uses a fresh unit id. Existing intake or retained tasks keep their owner, reviewer, state, detail and dependencies. Incompatible dependencies or retaining a public task in a private campaign refuse whole rather than changing that task's authority. Approved omissions are recorded as counts in the parent history and remain inspectable through the immutable contracts. A replay creates nothing; it may only tighten the campaign's privacy metadata without changing body, approval time, mapping or Task history.
|
|
59
|
+
|
|
60
|
+
The #597 dispatch slice adds handoff-backed round advancement and budget-id-specific hard-cap admission. Until then, T1 refuses new follow-up rounds and hard-cap activation instead of silently running them without those checks. Drafts may still describe structurally valid limits. Study writes recheck recovery, shutdown and storage holds before commit; shutdown fences late screens and drains admissions within the existing bounded host-writer stop window.
|
|
61
|
+
|
|
62
|
+
The base `research_records` floor protects T1 stored state and raw runner-key compatibility. Later slices that introduce additional dispatch, wire or configuration requirements add their own recovery floors before exposing them; advertising base storage support alone is not proof of those later capabilities.
|
|
63
|
+
|
|
64
|
+
## Campaigns (#930)
|
|
65
|
+
|
|
66
|
+
### ResearchCampaignV1
|
|
67
|
+
|
|
68
|
+
| Field | Type and bound |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `id` | hub-issued `rc-<12 hex>`; stable across revisions |
|
|
71
|
+
| `parentTaskId` | existing task id in this project; at most one active campaign per parent |
|
|
72
|
+
| `revision` | integer from 1; each revision is immutable once stored |
|
|
73
|
+
| `status` | `draft`, `approved`, `superseded`, `closed` |
|
|
74
|
+
| `question` | long text |
|
|
75
|
+
| `scope` | long text |
|
|
76
|
+
| `exclusions` | at most 32 short texts |
|
|
77
|
+
| `sourceIds` | at most 64 `src:<16 hex>` ids, each known to `SourceRegistry` |
|
|
78
|
+
| `units` | 1 to 32 units |
|
|
79
|
+
| `deliverableSections` | at most 32 `{ id, title, ownerUnitId }`; each owner names one unit with purpose `synthesis` |
|
|
80
|
+
| `stopPolicy` | `{ maxUnits (1..32), maxFollowUpRounds (0..5), deadline (ISO time, at most 90 days after approval) }` |
|
|
81
|
+
| `budget` | optional `{ id (an existing ExecutionBudget id), hardCap: resources to enforce, possibly empty }`; reference ids retain the ledger's exact 1..200-character spelling rather than the new-id grammar; see "Budget support map" |
|
|
82
|
+
|
|
83
|
+
A unit: `{ id, round (integer, 0 for the initial round), question (long text), perspective (short), requiredOutput (short), sourceIds (subset of the campaign's, at most 16), dependsOn (unit ids, at most 16, acyclic, never a later round), purpose: "discovery" | "independent_check" | "analysis" | "synthesis", adoptTaskId?, taskId? }`. `adoptTaskId` names an approved intake child to bind. `taskId` is bound by the hub on activation, never supplied by a contract.
|
|
84
|
+
|
|
85
|
+
Rounds: a follow-up round is a set of units with `round = n + 1`, added only by a revision. Validation refuses a revision that adds round n+1 units while any round-n discovery unit has neither a complete handoff nor an `insufficientEvidence` reason, and refuses a round above `stopPolicy.maxFollowUpRounds`. A unit's round is stored in `research_units.round`, so the dispatch gate and restart read it rather than recompute it.
|
|
86
|
+
|
|
87
|
+
### Lifecycle
|
|
88
|
+
|
|
89
|
+
1. Draft: `Tasks.studyDraft(by, { parentTaskId, contract })` by the person (CLI `ahub study draft`) or a configured planner (`hub_study_draft`, checked with `planningAuthority`). It validates the whole contract and stores revision 1 as `draft`. A draft creates no task and dispatches nothing.
|
|
90
|
+
2. Revise: `Tasks.studyRevise(by, { id, revision, contract })` (`ahub study revise` or `hub_study_revise`, same authority as draft) stores revision n+1 as `draft`; `revision` must equal the latest, or it refuses as stale. A revision may enlarge scope, units or the stop policy only as a draft; only approval activates it.
|
|
91
|
+
3. Approve: `Tasks.studyApprove(by, { id, revision })`, person only (console role). It runs in three phases.
|
|
92
|
+
- Prepare (async, outside any transaction). Validate and screen the revision's units with the same `withholds` path `Tasks.propose` uses. Resolve every source, intake child, task and dependency ref, and build one child spec per unbound unit (title, detail with a `Study: <campaign id> unit <unit id>` line, class, refs, deps). No write happens here.
|
|
93
|
+
- Commit (one synchronous `board.activateCampaign(id, revision, prepared)` inside `board.atomic`, the `board.splitBacklog` precedent). It re-checks the revision is still the latest `draft` and that retained or adopted tasks still have their captured flow revisions. Previously bound stable units reuse their task ids. An intake child may be adopted only if unbound to another campaign/unit; its task is not rewritten. Only unbound person-authored units create new children with synchronous `Board.propose` as `backlog: true` cards, with deps from `dependsOn` mapped to task ids. It writes the unit-to-task mapping rows and the revision's `approved` status, and marks the previous approved revision `superseded`, all in the same transaction. If anything has changed since Prepare, it throws and nothing is written.
|
|
94
|
+
- Publish (after commit). The board's ordinary post-commit change notifications go out. The new children are offered through the existing planner pull path; the campaign does not assign owners itself.
|
|
95
|
+
Re-running approve on an approved revision returns the stored mapping and creates nothing. A crash between commit and publish loses nothing: the mapping and the backlog cards are committed, and the ordinary planner pull picks the cards up after restart. Restart never re-creates children.
|
|
96
|
+
4. Close: `Tasks.studyClose(by, { id, revision, reason })`, person or the campaign's planner. A closed campaign dispatches nothing more; its tasks keep their own states.
|
|
97
|
+
|
|
98
|
+
A person-approved revision may drop a dependency or a unit. The omission is recorded in that revision's history note. Task approval stays the only event that releases a dependent; a campaign never approves a task.
|
|
99
|
+
|
|
100
|
+
### Dispatch gate
|
|
101
|
+
|
|
102
|
+
Before the hub offers, assigns or pulls a task that is bound to a campaign unit, `Tasks` synchronously re-reads the campaign. It holds the task with a reason, and does not dispatch it, when:
|
|
103
|
+
- the bound revision is not `approved` (superseded, closed or revoked);
|
|
104
|
+
- the deadline has passed;
|
|
105
|
+
- the unit's stored `round` exceeds `maxFollowUpRounds`, or the approved revision's unit count exceeds `maxUnits` (both re-read from the tables, never from the request).
|
|
106
|
+
|
|
107
|
+
The check runs after any asynchronous screening, immediately before the dispatch write. Holding a task never kills a native turn already running.
|
|
108
|
+
|
|
109
|
+
### Coverage and stop projection
|
|
110
|
+
|
|
111
|
+
`studyProjection(campaign)` is pure and computes, per unit:
|
|
112
|
+
- its bound task's state, and whether its handoff is present and complete;
|
|
113
|
+
- the sources it covers, and any source assigned to more than one `discovery` unit (shown as a duplicate assignment);
|
|
114
|
+
- `independent_check` units, labeled as intentional independent review, never as duplicates.
|
|
115
|
+
|
|
116
|
+
Closing a discovery round needs every discovery unit to have a complete handoff, or a recorded `insufficientEvidence` reason on that unit. A model's statement that it is done is not coverage.
|
|
117
|
+
|
|
118
|
+
### Handoffs
|
|
119
|
+
|
|
120
|
+
`ResearchHandoffV1`: `{ campaignId, revision, unitId, taskId, evidence: [{ sourceId, locator (short) }] (at most 64), unresolved (at most 16 short), contradictions (at most 16 { sourceIds, note (short) }), limitations (at most 16 short), insufficientEvidence? (short) }`. It is recorded by the bound task's current owner with `hub_study_handoff` while that task is in progress. The latest handoff per unit is kept, and earlier ones stay in history. Validation reports every missing required field at once.
|
|
121
|
+
|
|
122
|
+
### Budget support map
|
|
123
|
+
|
|
124
|
+
A campaign with a `budget` shows, per unit and per resource (`model_calls`, `tool_calls`, `elapsed_ms`, `tokens`), one label:
|
|
125
|
+
- `enforceable` only when every condition is proven from current state:
|
|
126
|
+
- the budget exists and is enabled;
|
|
127
|
+
- the unit's task has an owner;
|
|
128
|
+
- that owner is in the budget's `peers` and is instrumented (today `pi` and `local`);
|
|
129
|
+
- the resource has a limit;
|
|
130
|
+
- the scope covers the task: a `kind: "run"` budget covers every task of its peers, and a `kind: "task"` budget covers only its `taskId`. `ExecutionBudget.applies([taskId], owner)` is the proof.
|
|
131
|
+
- `unknown` when the unit has no owner yet, or the budget cannot be read.
|
|
132
|
+
- `advisory` when the scope or peer does not cover the unit; usage is shown for attribution only.
|
|
133
|
+
- `unavailable` for `tokens` (the ledger denies them as `unknown_usage`) and for an uninstrumented owner.
|
|
134
|
+
|
|
135
|
+
Display is not enforcement. A contract that wants enforcement says so with `budget: { id, hardCap: [resources] }` in place of the bare `executionBudgetId`. `hardCap` lists the resources that must be enforced for every unit, as stored intent, and it may be empty for an advisory-only budget. With a non-empty `hardCap`:
|
|
136
|
+
- Activation refuses unless all of these hold:
|
|
137
|
+
- budget `id` exists and is enabled;
|
|
138
|
+
- every `hardCap` resource has a limit and is not `tokens`;
|
|
139
|
+
- the budget's `peers`, intersected with instrumented peers, is not empty.
|
|
140
|
+
That intersection is the campaign's eligible owner set, stored with the revision.
|
|
141
|
+
- The dispatch gate and every owner change for a campaign-bound task make the same id-specific check immediately before the write: the offer, the assignment, a planner pull, a sweep reassignment, `hub_task_assign` and an owner handoff. The chosen owner must be in the stored eligible set, and `ExecutionBudget.applies([taskId], owner)` must include this budget `id`, with every `hardCap` resource still limited. If any part fails or cannot be read, the task is held with the reason, or the assignment is refused, and nothing is offered to an uncovered owner. A budget that is disabled or removed after activation holds every not-yet-started unit the same way.
|
|
142
|
+
- A unit already running when the budget changes keeps running; the hold applies from its next dispatch or owner change.
|
|
143
|
+
|
|
144
|
+
V1 uses the existing ledger as is. A `kind: "run"` budget is peer-wide, so unrelated work by those peers spends the same budget, and the projection says so. Two campaigns that name one budget share it, and neither resets it. Activation refuses a requested hard cap on an `unavailable` cell, and refuses a campaign-exclusive hard cap entirely, until the ledger gains task membership in a separate reviewed change. Stop and budget limits block new dispatch only.
|
|
145
|
+
|
|
146
|
+
## Experiments (#932)
|
|
147
|
+
|
|
148
|
+
### ExperimentProtocolV1
|
|
149
|
+
|
|
150
|
+
Stored by content: `protocolHash = sha256(canonical JSON of the body)`.
|
|
151
|
+
|
|
152
|
+
| Field | Type and bound |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `campaignId`, `campaignRevision` | an approved campaign revision in this project |
|
|
155
|
+
| `claimIds` | at most 32 ids (free ids until #931 defines claims) |
|
|
156
|
+
| `inputs` | at most 64 `{ sourceId, sha256 }`; the hash must equal the registry's |
|
|
157
|
+
| `code` | `{ commit: 40 hex }` or `{ deliverable: { id, sha256 } }` |
|
|
158
|
+
| `environment` | `{ descriptor (long text), hash? (64 hex) }`; variable names allowed, values refused |
|
|
159
|
+
| `method` | long text |
|
|
160
|
+
| `parameters` | at most 64 keys; values are scalars or lists of at most 64 scalars |
|
|
161
|
+
| `seeds` | at most 256 integers |
|
|
162
|
+
| `evaluator` | `{ id, version, hash? }` |
|
|
163
|
+
| `metrics` | at most 32 `{ name, unit, direction: "higher" | "lower" }` |
|
|
164
|
+
| `role` | `baseline` or `variant`, with `variantOf?` (a protocol hash) |
|
|
165
|
+
| `splits` | at most 16 short ids |
|
|
166
|
+
| `resourceLimits` | at most 16 `{ name, value, unit }` |
|
|
167
|
+
| `sealed` | `declared` boolean; verified only by a runner receipt (below) |
|
|
168
|
+
|
|
169
|
+
Every protocol also carries `lineage` (a short id, stable across revisions of one experiment) and `supersedes?` (the previous protocol hash in that lineage). A protocol is immutable, so a change is a new protocol with a new hash.
|
|
170
|
+
|
|
171
|
+
Protocol approval:
|
|
172
|
+
- `ahub study approve-protocol <hash>` is person only (console role). It writes one `research_protocol_approvals` row: `(protocol_hash, evaluator_hash, approved_by, at)`.
|
|
173
|
+
- An approval applies to exactly that protocol hash, and to that evaluator identity hash (sha256 of the canonical `evaluator` object).
|
|
174
|
+
- A changed protocol has a new hash and so no approval. Nothing copies an approval forward.
|
|
175
|
+
- Consumers:
|
|
176
|
+
- The comparison projection marks a pair `approved` only when both protocols have approvals.
|
|
177
|
+
- `hub_experiment_show` shows each attempt's protocol as `approved` or `unapproved`.
|
|
178
|
+
- Recording against an unapproved protocol is allowed, and shown as such.
|
|
179
|
+
|
|
180
|
+
### Comparison plan
|
|
181
|
+
|
|
182
|
+
`ComparisonPlanV1`, also stored by hash: `{ campaignId, fixed: { inputs, splits, evaluator, metrics }, varying: subset of ["code", "parameters", "seeds", "role"], rule: { kind: "tolerance", value } | { kind: "test", name (short), alpha } }`. Two attempts compare under a plan only when their protocols match every `fixed` field exactly and differ only in `varying` fields. Otherwise the projection names the first differing field and marks the pair incompatible; it still shows both. The hub never declares a best result.
|
|
183
|
+
|
|
184
|
+
### ExperimentAttemptV1
|
|
185
|
+
|
|
186
|
+
- `attemptId`: hub-issued `ra-<12 hex>`. `idempotencyKey`: caller-supplied, at most 64 bytes, unique per project. A second record call with the same key and the same body returns the existing attempt; the same key with a different body refuses.
|
|
187
|
+
- `protocolHash`, `taskId` (an existing task in this project), and optional `retryOf` or `reproducesAttemptId`. A retry is always a new attempt linked by `retryOf`; `reproducesAttemptId` is declared and never set by the hub.
|
|
188
|
+
- Every attempt has `phase: "development" | "final"`, set when it is created and never changed. A `final` attempt is the evaluation of record for its protocol.
|
|
189
|
+
- Each event carries `{ seq, kind, provenance, body, at }`, where `at` is the hub's time of recording. The kinds:
|
|
190
|
+
- `start`: `{ startedAt? }`, declared unless host evidence supplies it.
|
|
191
|
+
- `end`: `{ status: "succeeded" | "failed" | "cancelled", exitStatus?, reason? (short), run? (a check-runner run id) }`. At most one per attempt; a second `end` refuses.
|
|
192
|
+
- `metric`: `{ name, value }`. The name must exist in the protocol's `metrics`.
|
|
193
|
+
- `output`: deliverable claims. If the hub hashes them through `hashDeliverables`, they are `host-observed`; declared hashes stay `declared`. An inaccessible file is `unknown`.
|
|
194
|
+
- `note`: short text.
|
|
195
|
+
- `attestation`: a verified runner receipt or a person attestation.
|
|
196
|
+
- Status is a pure fold over the events:
|
|
197
|
+
- `declared` with no `start` and no `end`;
|
|
198
|
+
- `running` after `start` and before `end`;
|
|
199
|
+
- the `end` status once there is an `end`;
|
|
200
|
+
- `unknown` when there is no `end` and the attempt's task is approved, cancelled or closed.
|
|
201
|
+
- Post-hoc: a protocol is marked `post-hoc` when, at its recording time, its lineage already has a `final` attempt with an `end` event. That is, it was written after a final evaluation of an earlier protocol in the same lineage. The projection reads only `seq` and the recording order, so the fold is deterministic.
|
|
202
|
+
- Failed, cancelled and unknown attempts stay in every all-attempt count. Task approval and experiment success are separate fields.
|
|
203
|
+
|
|
204
|
+
### Host evidence
|
|
205
|
+
|
|
206
|
+
- A check-runner receipt (#793) supplies `host-observed` exit status (`exit`), `timedOut`, `cancelled`, duration (`duration_ms`) and receipt creation time (`createdAt`, from `created`) when an `end` event names its `run`. The hub reads `stateDir/checks/<run>.json` itself, and requires `status: "finished"`, the same task, and a `sha` equal to the protocol's `code.commit`. The receipt records no separate start or end time, so `startedAt` and `endedAt` stay `unknown` (or declared) for such an attempt. Extending the run receipt with timestamps is a separate change.
|
|
207
|
+
- Output hashes are host-observed only when the hub hashed the file.
|
|
208
|
+
- An agent-supplied hash is never host evidence.
|
|
209
|
+
|
|
210
|
+
## Runner attestation (#1018)
|
|
211
|
+
|
|
212
|
+
### Registration
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
"research": { "runners": { "<name>": { "publicKey": "<base64 Ed25519 SPKI DER>", "projects": ["<projectId>", ...], "revoked": false } } }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
- This block lives only in the untracked `.agenthub/config.local.json`. A tracked or shared file naming it throws at load, the `checks.remote` precedent.
|
|
219
|
+
- It is added to `ALL_MACHINE_LOCAL` and is a structural tier-2 key for `ahub settings edit`. Its writes are person only.
|
|
220
|
+
- `name` follows the id rule. At most 16 runners.
|
|
221
|
+
- Revocation sets `revoked: true`. The key is kept, so old receipts still show who signed them, but a revoked key verifies nothing new.
|
|
222
|
+
- The hub stores no private key.
|
|
223
|
+
|
|
224
|
+
### AttemptReceiptV1
|
|
225
|
+
|
|
226
|
+
The runner signs `"agent-hub.runner-receipt/v1\0" + canonical JSON of the receipt body` with Ed25519. The hub verifies with `node:crypto`.
|
|
227
|
+
|
|
228
|
+
The body is `{ receiptId, runner, projectId, attemptId, protocolHash, codeCommit, imageDigest, containers: [{ id, role: "candidate" | "evaluator" | "other" }], mounts: [{ container, path, readOnly }], network: "none" | "restricted" | "open", resourceLimits, startedAt, endedAt, exitStatus, outputs: [{ name, sha256 }], metricsFile?: { name, sha256 } }`.
|
|
229
|
+
|
|
230
|
+
Verification refuses before any write when any of these holds:
|
|
231
|
+
- the runner is unknown or revoked;
|
|
232
|
+
- `projectId` is not in the runner's `projects`;
|
|
233
|
+
- the signature fails;
|
|
234
|
+
- the attempt is missing, in another project, or bound to a different `protocolHash`;
|
|
235
|
+
- the receipt is over its bounds.
|
|
236
|
+
|
|
237
|
+
Each mount also carries `purpose: "evaluator-code" | "evaluator-data" | "candidate-output" | "other"`.
|
|
238
|
+
|
|
239
|
+
A verified receipt appends one `attestation` event, and its fields are `runner-attested`. `sealed` becomes verified only when every condition holds:
|
|
240
|
+
- at least one container has role `candidate` and at least one has role `evaluator`, and their ids are disjoint and unique;
|
|
241
|
+
- every mount's `container` names a listed container;
|
|
242
|
+
- at least one mount has purpose `evaluator-code` or `evaluator-data` and is on an evaluator container;
|
|
243
|
+
- every `evaluator-code` and `evaluator-data` mount is `readOnly`, and none of them is on a candidate container.
|
|
244
|
+
|
|
245
|
+
Missing, empty or inconsistent isolation evidence leaves `sealed` declared or unverified, never verified.
|
|
246
|
+
|
|
247
|
+
A receipt with a known `receiptId` and identical bytes is a no-op. The same `receiptId` with different bytes refuses.
|
|
248
|
+
|
|
249
|
+
### Delivery
|
|
250
|
+
|
|
251
|
+
- Agents relay receipts with `hub_experiment_record { kind: "receipt", receipt, signature }`. The signature, not the caller, is the authority, so any task owner may relay.
|
|
252
|
+
- The person may also run `ahub study receipt <file>`.
|
|
253
|
+
- The hub never contacts the runner.
|
|
254
|
+
|
|
255
|
+
## Storage
|
|
256
|
+
|
|
257
|
+
All new tables live in `hub.db`, created in the `Board` constructor with `CREATE TABLE IF NOT EXISTS`. Writes use `board.atomic`.
|
|
258
|
+
|
|
259
|
+
| Table | Key | Content |
|
|
260
|
+
|---|---|---|
|
|
261
|
+
| `research_campaigns` | `(id, revision)` | status, parent task id, body JSON, body sha256, approved_by, approved_at |
|
|
262
|
+
| `research_units` | `(campaign_id, revision, unit_id)` | round, task id, purpose, adopted (boolean) |
|
|
263
|
+
| `research_protocol_approvals` | `(protocol_hash)` | evaluator hash, approved_by, at |
|
|
264
|
+
| `research_handoffs` | `(campaign_id, unit_id, seq)` | task id, body JSON, by, at |
|
|
265
|
+
| `research_protocols` | `hash` | campaign id and revision, body JSON, by, at |
|
|
266
|
+
| `research_plans` | `hash` | campaign id, body JSON, by, at |
|
|
267
|
+
| `research_attempts` | `attempt_id`, unique `(project, idempotency_key)` | protocol hash, task id, phase, retry_of, reproduces, by, at |
|
|
268
|
+
| `research_attempt_events` | `(attempt_id, seq)`, unique `receipt_id` when present | kind, provenance, body JSON, at |
|
|
269
|
+
|
|
270
|
+
`board.hasResearchState()` reports whether any row exists. Readback is paginated: at most 50 rows per call, with a cursor.
|
|
271
|
+
|
|
272
|
+
## Wire names
|
|
273
|
+
|
|
274
|
+
| Surface | Name | Who |
|
|
275
|
+
|---|---|---|
|
|
276
|
+
| CLI | `ahub study draft <parent> <contract.json>`, `study revise <id> <revision> <contract.json>`, `study approve <id> <revision>`, `study close <id> <revision> --reason`, `study show [<id> | --after <id>] [--json]`, `study experiments [--campaign <id>] [--json]`, `study attest <attempt> <field> <value>`, `study receipt <file>` | approve, attest and receipt are person only; draft and revise are person or planner; show is anyone |
|
|
277
|
+
| Hub tools | `hub_study_draft` and `hub_study_revise` (configured planner only, through `planningAuthority`; they store drafts and never approve), `hub_study_show` (read-only; no id lists this project's campaigns as receipts, one page of at most 50 as `{ campaigns, next? }`, and `after` continues from the `next` of the previous page), `hub_study_handoff` (bound task owner), `hub_experiment_record` (`kind`: `protocol`, `plan`, `attempt`, `event` or `receipt`; task owner), `hub_experiment_show` (read-only) | none of them approves or attests |
|
|
278
|
+
| CLI (person only) | `ahub study approve-protocol <hash>` | person |
|
|
279
|
+
| Control | `study` (console role, CLI only) | person |
|
|
280
|
+
| Feature | `research_records` | recovery gate |
|
|
281
|
+
| Config | `research.runners` | untracked config.local.json only |
|
|
282
|
+
|
|
283
|
+
`ahub research`, the opt-in telemetry command, is unchanged.
|
|
284
|
+
|
|
285
|
+
## Delivery slices
|
|
286
|
+
|
|
287
|
+
Each slice amends this spec in its own PR if it must differ, and updates `docs/dogfood.md`. All of them touch `tasks.ts` or `board.ts`, so they run one at a time on those files.
|
|
288
|
+
|
|
289
|
+
| Task | Issue and ACs | Scope |
|
|
290
|
+
|---|---|---|
|
|
291
|
+
| #596 | #930 T1, AC1 and AC2 | the `research-campaign.ts` schema and validation (rounds included); the campaign and unit tables; `studyDraft`, `studyRevise`, the three-phase `studyApprove` with `board.activateCampaign`, and `studyClose`; intake adoption; the replay, crash-between-commit-and-publish and restart tests; the `research_records` feature gate |
|
|
292
|
+
| #597 | #930 T2, AC3 and AC4 | the dispatch gate on stored rounds; round advancement validation; the coverage and stop projection; the budget support map with its `applies` proof; the stored `hardCap` intent and eligible owner set, with refusal at activation and the id-specific check at every dispatch and owner change (offer, assign, pull, sweep reassign, handoff); the two-campaign shared-ledger fixture |
|
|
293
|
+
| #598 | #932 T1, AC1 and AC2 | the `research-experiments.ts` protocol (with lineage), attempt (with phase) and event schemas; the status fold; the provenance levels; the protocol, attempt and event tables; `hub_experiment_record` for protocol, attempt and event; host evidence from check receipts (exit, duration and receipt creation time only) and deliverable hashes |
|
|
294
|
+
| #599 | #932 T2, AC3 and AC4 | comparison plans and compatibility; the protocol approval table and `ahub study approve-protocol` with its consumers; idempotency and retry linkage; the post-hoc marking by lineage |
|
|
295
|
+
| #600 | #1018, AC1 to AC5 | the `research.runners` config; `research-runner.ts` receipt verification; receipt delivery; the sealing rule with its negative cases (no evaluator, empty mounts, a dangling container ref, an evaluator mount on a candidate); fixtures with a test key pair |
|
|
296
|
+
| #601 | #930 T3, AC5 and AC6 | `ahub study` draft, revise, approve, close and show; `hub_study_draft`, `hub_study_revise`, `hub_study_show` and `hub_study_handoff`; the privacy stubs; role guidance in `templates/`; the three-source, two-peer example |
|
|
297
|
+
| #602 | #932 T3, AC5 and AC6 | `ahub study experiments`, `attest` and `receipt`; `hub_experiment_show`; the synthetic CPU-only fixture; the rerun checklist in `docs/profiles.md` |
|
|
298
|
+
|
|
299
|
+
## Departures from the issues
|
|
300
|
+
|
|
301
|
+
- Runner registration is person only in V1. #1018 proposed "the person or conductor". A public key is a trust root, so the conductor path is deferred until a reviewed change gives it the same confirmation as other trust settings.
|
|
302
|
+
- Claim ids in a protocol are free ids until #931 defines claims; they are not validated against a claim store.
|
|
303
|
+
- `ahub study attest` covers `person-attested` fields. #932 names a "person attestation" without a command.
|
|
304
|
+
- The #601 list is paged at the Board query (`LIMIT`, at most 50 rows, id-ordered cursor), as the readback bound requires, so its reply is `{ campaigns, next? }` rather than a bare array; the feature is unreleased, so no caller depends on the array. `ahub study show --after <id>` continues a list. `--live-test` refuses every `study` form but `show`.
|
|
305
|
+
- `hub_study_handoff`, `hub_study_draft` and `hub_study_revise` are new tools. #930 lists only `hub_study_show`, but a handoff needs a write path that is not a task completion, and a planner needs a draft route that is not the person-only CLI.
|
|
306
|
+
- Protocol approval is the person-only `ahub study approve-protocol`; #932 asks for approvals bound to hashes without naming the operation.
|
|
307
|
+
- The budget support map adds an `unknown` label for a unit with no owner yet, since enforceability depends on the owner peer.
|
|
308
|
+
- Host evidence from a check run covers exit status, duration and receipt creation time only; the run receipt has no start or end timestamp.
|
|
309
|
+
|
|
310
|
+
## Out of scope
|
|
311
|
+
|
|
312
|
+
#931 evidence links and claim judgment; executing, scheduling or provisioning experiments; a campaign-exclusive budget ledger; holiday calendars; new search, crawling or source providers; any third-party dependency.
|
|
313
|
+
|
|
314
|
+
## T2 dispatch and coverage implementation boundary (#597)
|
|
315
|
+
|
|
316
|
+
- `research_dispatch` is an additive recovery floor. Any stored campaign already carries stop policy intent, including a campaign activated before this slice. A target without the feature refuses while any campaign, dispatch activation or handoff exists. The base `research_records` floor remains required too. Dispatch metadata and handoff content have their own integrity digest when present.
|
|
317
|
+
- The latest stored revision controls every offer, planner pull, owner change and acceptance. A newer draft holds older bound work until that draft is approved; a closed or omitted unit remains held. This gate never interrupts a native turn already running. A revision cannot reauthorize a changed unit definition without a new unit id.
|
|
318
|
+
- Approval stores the instrumented eligible owner set for the named budget. Immediately before dispatch or an owner change, current membership, task scope and each required limit must still be proven for that same budget id. Another budget covering the task proves nothing. The existing peer-wide ledger is shared, never reset by campaign activation. Exhausted requested cells hold dispatch. A model-call cap alongside a token ceiling is unavailable because the existing meter cannot prove token usage; activation refuses it.
|
|
319
|
+
- A complete handoff covers every source assigned to the unit; all required structural fields remain mandatory. `insufficientEvidence` is a separate way to settle a discovery unit. New round n+1 units require stored round-n discovery bindings and complete or insufficient-evidence handoffs for each. A proposed contract cannot supply its own completion evidence.
|
|
320
|
+
- A study-held owner offer is persisted and re-offered after approval (#603). When a hold makes the bus discard a queued owner offer, `Tasks.relevant` writes a `research_dropped_offers` row; approving a revision re-offers each retained, still-proposed unit task through `sendTask` and clears the row once the offer is published. `research_dropped_offers` is its own additive recovery label: a target that lacks it refuses while any row exists, and a row no longer raises only the `research_dispatch` floor. The row joins the dispatch integrity digest only when rows exist.
|
|
321
|
+
- `Tasks.studyHandoff` accepts only the current in-progress bound owner and screens outside the transaction; stored ownership, revision, sources and flow are rechecked at the write. `Tasks.studyShow` exposes the pure projection and removes source identifiers from private views. Public tool and CLI wiring remains in #601.
|
|
322
|
+
|
|
323
|
+
## Experiment T1 implementation boundary (#598)
|
|
324
|
+
|
|
325
|
+
- The record envelope for a protocol is `{ kind: "protocol", taskId, protocol }`; `recordedForTaskId` is immutable metadata outside the protocol's content hash. A writer must be that task's current owner while it is `in_progress`. Attempt and event writes use the attempt task's current owner under the same condition. No console override is introduced by this slice.
|
|
326
|
+
- Both the recording task and every attempt task must be unit tasks of the protocol's same current approved campaign revision, resolved by `Board.researchDispatchBinding`. Different units in that campaign may share a protocol. Removed units, a pending draft, foreign project references and a protocol from an earlier revision refuse before effects. New attempts and events against an older revision's protocol remain refused; the upgrade is an explicit membership+source fence. Historical comparison reads and person approvals are allowed as described in the T2 boundary.
|
|
327
|
+
- Protocol inputs are a subset of the campaign revision's source ids, not only the unit's source ids, and every registry hash must match exactly. A code deliverable reference must name a matching host record on the recording task. Privacy follows the task, protocol inputs and the current campaign; missing privacy evidence fails closed. All asynchronous screens, receipt reads and file hashes are followed by fresh authority, source and campaign checks; the transaction rechecks the task flow and campaign binding.
|
|
328
|
+
- Environment descriptors and their optional text-hash claims are always `declared`. The lexical screen rejects assignment forms, Bearer credentials and known secret shapes before writing; flagged text is refused, never stored redacted. It detects those forms only and never proves secret absence. The upgrade path is structured key/version fields or #1018 runner evidence. The hash labels the declared descriptor text; it is not a measured host environment hash.
|
|
329
|
+
- Output `{ id, sha256? }` is a declaration. Output `{ path, format, version? }` requests host hashing through the existing #509 reader and all its path, file-identity, deny and byte bounds. A missing, unreadable or refused path leaves the hash unknown, with no declared fallback. Output path privacy is classified independently of measurement using the #509 PII, deny and hub-state policies on both declared and resolved names. A protected path, or an unavailable classification, makes the event and whole attempt private even if hashing fails. The classification is retained across the asynchronous read. Experiment classification opts into fail-closed handling of an exhausted bounded alias-discovery budget; ordinary path-policy callers and the discovery ceiling stay unchanged. Neither record ingestion nor readback executes a command.
|
|
330
|
+
- Host measurements occupy separate immutable `research_attempt_observations` rows keyed by `(attempt_id, event_seq)` and linked to the declared end's run id or the output hash request's derived deliverable id. The declared event is never rewritten and no second end is created. Readback puts declared and measured values side by side with their own provenance. A check receipt must be finished and match the task and protocol commit; only exit status, timeout/cancellation, duration and its receipt creation timestamp (`createdAt`) are measured. Start/end timestamps remain unknown unless declared. The original check output and tail are not stored.
|
|
331
|
+
- Attempt idempotency keys are unique within the project. Event idempotency keys are likewise project-wide, bind the attempt and exact declared body, and return the original immutable event and measurements on replay. A different body refuses. Retries and reproduction links remain declared associations, never independent-reproduction claims. The all-attempt denominator includes failed, cancelled and unknown rows. Pages carry at most 50 records; the event cursor and completeness flag identify partial evidence pages.
|
|
332
|
+
- A private event makes the whole attempt private across every page. Public readback retains ids, counts, state and provenance while stubbing protocol text, metric names, paths and event bodies. Raw research text never enters task history, notices or memory.
|
|
333
|
+
- `research_experiments` is additive to `research_records` and `research_dispatch`. A target lacking it refuses while any protocol, attempt, event or observation exists. A separate content-sensitive experiment integrity digest is present only when experiment state exists. No new public tool or CLI surface, comparison/approval projection (#599), runner trust (#600) or execution engine is added here.
|
|
334
|
+
|
|
335
|
+
## Experiment T2 comparison identity and approval binding (#599)
|
|
336
|
+
|
|
337
|
+
- Both protocols in a pair must have the comparison plan's `campaignId`. Only `campaignRevision`, `lineage` and `supersedes` are identity/order metadata excluded from structural compatibility. They remain part of each immutable protocol body and its content hash.
|
|
338
|
+
- The only predeclarable varying groups are `code` (commit or deliverable), `parameters`, `seeds`, and `role` together with `variantOf`. A difference in an undeclared varying group is incompatible.
|
|
339
|
+
- `inputs`, `splits`, `evaluator` and `metrics` (name, unit and direction) must match the plan's fixed values on both sides. Every other experimental field stays exact: `environment` (descriptor and hash), `method`, `claimIds`, `resourceLimits` and `sealed`. These fields cannot be declared as varying.
|
|
340
|
+
- The projection retains both members, names the deterministic first differing field when incompatible, and never ranks them or evaluates the declared tolerance/statistical test. Each compared attempt shows its own exact protocol hash and `campaignRevision`, with an explicit note that exclusion from compatibility does not hide its identity.
|
|
341
|
+
- Any changed protocol hash requires a fresh person approval, even if the new protocol is structurally compatible. Approval binds to that exact full protocol hash and the canonical evaluator identity hash; it never carries through a changed revision, lineage, supersession or variant link.
|
|
342
|
+
|
|
343
|
+
## T2 comparison implementation boundary (#599)
|
|
344
|
+
|
|
345
|
+
- `Tasks.experimentRecord` accepts `{ kind: "plan", taskId, plan }` only from the current in-progress owner of a unit in the current approved campaign. Fixed input source ids and hashes must resolve in that campaign. An identical hash replays only for its original recording task; changing the recording task refuses rather than rebinding it. Plans remain immutable and paginated in Board storage.
|
|
346
|
+
- `Tasks.experimentShow` accepts `{ planHash, baselineAttemptId, variantAttemptId, eventAfter?, limit? }` for a pair, keeping each attempt and the all-attempt campaign denominator. The projection names incompatibility and exact protocol hashes/revisions, never ranks results or sets a best result. A private plan or attempt withholds the comparison body too.
|
|
347
|
+
- `ahub study approve-protocol <hash>` uses the console-only `study_approve_protocol` operation. The person may approve a current or historical immutable protocol. A changed hash is always unapproved until its own explicit approval; compatibility does not carry approval. Each attempt shows `approval`, declared retry/reproduction links, and `independentlyReproduced: false`.
|
|
348
|
+
- New protocol insertion captures `research_protocol_context` in the same Board transaction: either no earlier ended final attempt in its lineage, or that attempt id and terminal seq. This is a statement of recording order only. Replaying a protocol never restamps it after a later evaluation. Older protocols without the row remain `unknown`; timestamps never infer missing order evidence.
|
|
349
|
+
- `research_comparisons` is a separate additive recovery floor for any comparison plan, protocol approval or protocol-context row. Its conditional integrity digest covers all three tables. The older experiment and dispatch guards and integrity fields remain unchanged. No command or model runs during these writes.
|
|
350
|
+
|
|
351
|
+
New attempts and events may be recorded only against a protocol of the current approved campaign revision. Historical immutable protocols remain available for comparison reads and the person's explicit exact-hash approvals. New recording against older protocols is deferred until an explicit membership+source fence is implemented.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# 0.24.0 release verification
|
|
2
|
+
|
|
3
|
+
This record covers release preparation and source review. It claims no installation, no running-hub upgrade to 0.24.0 and no live TUI launch.
|
|
4
|
+
|
|
5
|
+
## Candidate
|
|
6
|
+
|
|
7
|
+
Version 0.24.0, prepared from main 266689ff (8 commits since v0.23.1, 4 of them `feat`; bump rule: minor). The release commits carry the version, the CHANGELOG section, the bundle and the documentation stamps.
|
|
8
|
+
|
|
9
|
+
## Reviews
|
|
10
|
+
|
|
11
|
+
Pull requests named by the commits since v0.23.1: #1015, #1013, #1014, #1010, #1011, #1007, #1009, #1005.
|
|
12
|
+
|
|
13
|
+
Each merged with its exact-head `check` run green and no unresolved review thread. The claude[bot] review on each is the "extra usage unavailable" notice, not a review.
|
|
14
|
+
|
|
15
|
+
- #1005 (task 580, #999 T0): codex approved 1dc17ce0, the merged head (check run 41173483116).
|
|
16
|
+
- #1009 (task 581, #999 T1): claude approved 3a032a4a, the merged head (check run 41186813039). There were two earlier rounds: a help-text contradiction of the off semantics, and a codex-connector P2 for reviewer variants without hub-managed permissions.
|
|
17
|
+
- #1007 (task 582, #999 T3): codex approved f89a8567, the merged head, as a step (check run 41193006018). Its two remaining Important findings (file-writing `find` primaries, and `gh` option values skipping the opaque/glob checks) moved to task 585.
|
|
18
|
+
- #1011 (task 585, #999 T3b): codex approved 7b5580b6, the merged head, after an administrative rebind from the pre-rebase head 15629fe0 with an identical tree (check run 41195375968). Both moved findings are fixed.
|
|
19
|
+
- #1010 (task 583, #999 T2): claude approved a8870249, the merged head (check run 41196952390). There were two earlier rounds: `ahub setup` had stopped running doctor, and a fresh-install regression caught by the unchanged `test/cli.test.ts`.
|
|
20
|
+
- #1013 (task 586): codex approved abba220c, the merged head (check run 41201125644), after two documentation findings and an administrative rebind.
|
|
21
|
+
- #1014 (Claude Code 2.1.316 receipt) was opened and merged by another Claude session at b7f41224 (check run 41200874878). No hub task or review record for it is visible from this release session; its review is not established here.
|
|
22
|
+
- #1015 (amem 0.15.0 pin) has no hub task: the person asked for it directly. codex reviewed it read-only and approved f3dc5f92 with no finding. The merged head c6f77939 is the rebase onto main after #1014, with the CHANGELOG conflict resolved and the bundle rebuilt identically. That is an approval at an earlier head, and the content delta is the conflict resolution only (check run 41203990883).
|
|
23
|
+
|
|
24
|
+
## Native acceptance receipts
|
|
25
|
+
|
|
26
|
+
Receipts added under `docs/verification/` since v0.23.1: none, per release-prepare. `git diff --diff-filter=A --name-only v0.23.1..HEAD -- docs/verification` also lists `docs/verification/2026-10-31-claude-implementer-2.1.316.md` (#1014), a model-free compatibility receipt, not a native acceptance receipt.
|
|
27
|
+
|
|
28
|
+
This list is read from the repository, never written by hand. Native acceptance and the person's release consent are separate records: consent is `ahub sdlc authorize-release 0.24.0`, person only, and is not recorded in this file. The tag run refuses without it.
|
|
29
|
+
|
|
30
|
+
## Document review
|
|
31
|
+
|
|
32
|
+
`node scripts/check-docs.mjs --require-fresh` reported 12 stale documents, stamped at 5b63fa38 or ce8da3ec. Read-only reviewers in four groups read each one against its source commits since that stamp (#1005, #1009, #1007, #1011, #1010, #1013, #1014, #1015 and the release-prepare commit), and their proposed edits were checked against the code before they were applied. All 12 were restamped at 9af51bfd.
|
|
33
|
+
|
|
34
|
+
- README.md: the Status line (release-prepare) and the report link name 0.24.0; the guard-rails bullet now states the opt-in floor, and the operations bullet names `ahub autonomy`.
|
|
35
|
+
- docs/quickstart.md: the install pin is v0.24.0, the setup comment names the Claude homes and the hook, and a new "Upgrading to 0.24.0" section covers the preset, the machine default, the floor, the older-target refusal, Claude homes, amem 0.15.0 and Claude Code 2.1.316. Older upgrade sections are unchanged.
|
|
36
|
+
- docs/operations.md: the T1 subsection no longer calls T2 future work. On a running hub, consent comes from the `on` confirmation or from a trusted machine opt-in at startup. Stopped projects use the offline writer with or without `--all-projects`, and offline writes have no undo witness. Stopped-hub status is described, the preset key list names `action_policy.floor`, and the setup and floor sentences now cover Claude homes and the preset.
|
|
37
|
+
- docs/security.md: never-ask now also holds under retained autonomy consent (three places). A new paragraph covers who can turn autonomy on or off, what the preset writes, where consent is created and what can never create it, and that under the machine opt-in a preset-matching never-ask written to `config.local.json` by any process is consented at the next start. The floor paragraph names `ahub autonomy`, the profile hook appears in the enforceability list, and the implementer receipts include 2.1.316.
|
|
38
|
+
- src/cli/help.ts: `init` names machine-default inheritance, and the autonomy row says undo restores a live-hub write. No command or flag mismatch against main.ts and launch.ts.
|
|
39
|
+
- docs/agent-notes/adapters.md: config never-ask is qualified by retained consent, and adding a native peer now also requires its row in `templates/presets/autonomous.json`.
|
|
40
|
+
- docs/agent-notes/daemon.md: the recovery feature list names `project_autonomy`, and a new rule says where retained consent may be created and that `_autonomy` is inert.
|
|
41
|
+
- docs/agent-notes/tests.md: tests that reach Claude-home discovery isolate `HOME` and `CLAUDE_CONFIG_DIR`, and an amem pin raise moves the version literal in four named tests.
|
|
42
|
+
- docs/agent-notes/README.md, budget.md, bus.md and tasks.md: no statement changed (their files were untouched, or only refactored in `task-repository.ts`).
|
|
43
|
+
- The CHANGELOG gained the #999 entries (T0 to T3b), which those PRs had not added.
|
|
44
|
+
|
|
45
|
+
## Checks
|
|
46
|
+
|
|
47
|
+
On the Mac at 86382336 (the release branch after the restamp) with the worktree's own frozen install (Bun 1.4.2 install; `@staix/agent-mem` 0.15.0):
|
|
48
|
+
- `node scripts/check-docs.mjs --require-fresh` printed `docs: OK (0 stale documents)`.
|
|
49
|
+
- `bun x tsc --noEmit` was clean.
|
|
50
|
+
- `bun scripts/build.mjs --check` exited 0.
|
|
51
|
+
- `node scripts/check-package.mjs` printed `package: OK (695 files, @staix/agent-hub@0.24.0)`.
|
|
52
|
+
- `bun test test/help.test.ts test/autonomy-cli.test.ts`: 24 pass, 0 fail.
|
|
53
|
+
|
|
54
|
+
The release PR's exact-head CI is the full gate on both OSes.
|
|
55
|
+
|
|
56
|
+
## Known gaps, not blocking
|
|
57
|
+
|
|
58
|
+
- No live receipt for #999. The T4 receipt (task 584: one command on under Orca, one standard task with zero person prompts, a force push and `gh release create` still asking) needs this release installed and the person present. It is the next step, not part of this record.
|
|
59
|
+
- No full local `scripts/check.sh`. Every #999 PR's local or remote `--changed` run that grew into the full suite was stopped by the default 960 s total watchdog, with no failure observed before the stop. The full-suite evidence is each PR's exact-head CI on both OSes, and this release PR's.
|
|
60
|
+
- #1014's review is not established from this session (see Reviews). #1015's approval was given at f3dc5f92, before its rebase.
|
|
61
|
+
- The 2.1.316 receipt is model-free; a real account, model and person interaction remains a separate leg.
|
|
62
|
+
- `scripts/lib/release-plan.ts` drops any receipt whose file name ends in a version number (the release-report filter `-\d+\.\d+\.\d+\.md$`), so release-prepare printed no receipts. The receipt line above was corrected by hand from the `git diff` query; the script fix is a separate change.
|
|
63
|
+
- The running hub on this machine has not been upgraded to 0.24.0.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Claude Code 2.1.316 headless implementer receipt
|
|
2
|
+
|
|
3
|
+
Date: 2026-10-31. Scope: #888 (claude-implementer row). This repeats the procedures of the [2.1.314 receipt](2026-10-31-claude-implementer-2.1.314.md) on the installed Claude Code 2.1.316, with 2.1.314 run through the same producers as the control: the permission transport (Write, production-name Bash, Bash `updatedInput` rewrite) and the host shell wrapper. Source head: `65d4a4fe`. Platform: macOS arm64, host Bun 1.4.3.
|
|
4
|
+
|
|
5
|
+
Result: every case passed on both binaries. `2.1.316` is added to `COMPAT["claude-implementer"].verified`. 2.1.315 is published on npm but was not run and is not verified by this receipt.
|
|
6
|
+
|
|
7
|
+
| Native version | Binary SHA-256 |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Claude Code 2.1.314 (control) | `21d6e7b9a6f07b4cfcb7df13760b3b72aa25e084e13a5354413382987ba832ed` |
|
|
10
|
+
| Claude Code 2.1.316 | `64c327e92b2c5e0f78c0a980c5a518121e1f0d140ca771ca5dd4488d1a2dcb3f` |
|
|
11
|
+
|
|
12
|
+
The 2.1.314 hash matches the 2.1.314 receipt, so the control is the binary it certified.
|
|
13
|
+
|
|
14
|
+
## Upstream changes since 2.1.314
|
|
15
|
+
|
|
16
|
+
Read from the upstream [CHANGELOG](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md); it has no 2.1.315 entry. Items in 2.1.316 that touch permissions, MCP, hooks, settings sources, process lifetime or the Bash tool:
|
|
17
|
+
|
|
18
|
+
- **Shell commands left running when Claude Code exits by itself**: fixed on macOS and Linux. The producers already require every native child's process group to be empty afterwards; this tightens cleanup and loosens nothing.
|
|
19
|
+
- **Bash tool shell: multi-line alias values, dash-named functions and an exported `SHELLOPTS`** no longer garble the shell or stop scripts after their first command. The hub's implementer child gets an isolated HOME without the person's rc files, and the wrapper's persistent-cwd control below still passes on 2.1.316.
|
|
20
|
+
- **Managed `autoMode.allow` without `"$defaults"` regaining built-in exceptions from a host app's `--settings`**: fixed. The hub passes `--settings` with permission rules only, runs in `default` permission mode and does not use auto mode.
|
|
21
|
+
- **Server-managed settings for Team and Enterprise logins apply without an approval prompt**: these come from an account login, which the model-free runs do not have. As before, managed settings from a real account are outside this receipt.
|
|
22
|
+
- **`--restricted` uploads and plugin MCP `headersHelper` environment**: the hub uses neither `--restricted` nor plugin MCP servers in the implementer child (`--strict-mcp-config`).
|
|
23
|
+
|
|
24
|
+
Nothing in these entries changes `--permission-prompts host`, `--permission-prompt-tool`, `--strict-mcp-config`, `--setting-sources` or the `updatedInput` reply contract. This reading is of the changelog text, not the binary's source, which is not public.
|
|
25
|
+
|
|
26
|
+
## Runs
|
|
27
|
+
|
|
28
|
+
Each producer ran both binaries sequentially with an isolated HOME and `CLAUDE_CONFIG_DIR`, a fixture MCP server, a deterministic loopback provider and the literal API key `synthetic-probe-not-a-credential`. No account, provider request or model inference was involved. Every native child's process group was confirmed empty afterwards and every binary hash was unchanged.
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
python3 docs/verification/claude-permission-transport-native.py OUT/write --claude 2.1.314 --claude 2.1.316
|
|
32
|
+
python3 docs/verification/claude-permission-transport-native.py OUT/bash --tool Bash --server-name agent-hub --permission-tool hub_permission_request --require-tool-use-id --claude ... --claude ...
|
|
33
|
+
python3 docs/verification/claude-permission-transport-native.py OUT/rewrite --tool Bash --rewrite-bash --server-name agent-hub --permission-tool hub_permission_request --require-tool-use-id --claude ... --claude ...
|
|
34
|
+
python3 docs/verification/claude-shell-wrapper-native.py OUT/wrapper --bun ABSOLUTE_BUN --claude ... --claude ...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
(binary arguments are the absolute installed paths). `--bun` must be the absolute path of the Bun executable. A first wrapper run here was given an empty path, because `command -v bun` names a shell function in an interactive zsh, and failed the `normalized` case on both binaries with `PermissionError`; the rerun with the Homebrew Bun 1.4.3 path is the result below.
|
|
38
|
+
|
|
39
|
+
| Producer | Cases per binary | 2.1.314 | 2.1.316 |
|
|
40
|
+
| --- | --- | --- | --- |
|
|
41
|
+
| Write transport (allow, deny, missing tool, hook deny/allow, MCP error, disconnect, pending, deadline) | 9 | 9 pass | 9 pass |
|
|
42
|
+
| Bash transport, production server and tool names, `tool_use_id` required | 9 | 9 pass | 9 pass |
|
|
43
|
+
| Bash `updatedInput` command replacement (allow, deny) | 2 | 2 pass | 2 pass |
|
|
44
|
+
| Host shell wrapper (persistent-cwd control, fixed-wrapper rewrite with replay refusal) | 2 | 2 pass | 2 pass |
|
|
45
|
+
|
|
46
|
+
Per-case shapes on 2.1.316 match the control: pending stopped externally at the 25-second deadline; wrapper control 3 requests and 2 permission calls, wrapper rewrite 4 requests and 3 permission calls with the effect counter at exactly 1 after replay.
|
|
47
|
+
|
|
48
|
+
The only producer change is the version allow-list in `claude-shell-wrapper-native.py`, which now admits `2.1.316`.
|
|
49
|
+
|
|
50
|
+
| Artifact | SHA-256 |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| Permission producer (unchanged) | `8f8885f7153b3a236f3b3f8ce49a344b908f2af3b3aba8b064762d82d1ecf12a` |
|
|
53
|
+
| Wrapper producer (this change) | `92dde3d32d290ee4e64447957e2c760726467e3597f5a436b960f7dbe71f9219` |
|
|
54
|
+
| Wrapper host fixture | `616e6711e392f0eee7e3fa1c7bdc47a537dfa86bcc8ffb30e549ca94e5a71cef` |
|
|
55
|
+
| Fixed CLI wrapper | `8ff56514a6e3f25bce0784775d396df199b58b1b93f55ad0e8747bbc729d2fd8` |
|
|
56
|
+
| Write receipt JSON | `1eb6c30ad7c18258f204610e37c61a5b2fff128ba98017c74d59686cd9646c37` |
|
|
57
|
+
| Bash receipt JSON | `6a4e5a478e751a6040383eb0d7a520ebe0b89ad693ebe76eab0353dcde4d8eed` |
|
|
58
|
+
| Rewrite receipt JSON | `ac5b574115d9afe0f93f9c1f7ed63df155cdc3ec5cc991ebf0c9b6b14a98f73a` |
|
|
59
|
+
| Wrapper receipt JSON | `1e8d280ce6dbe66b30184b9abd68b9947057d9d87dfd3fb42e352edc136a6a50` |
|
|
60
|
+
|
|
61
|
+
The receipt JSON files stay in the local diagnostic directory; they carry local paths and are not committed.
|
|
62
|
+
|
|
63
|
+
## Evidence boundaries
|
|
64
|
+
|
|
65
|
+
Unchanged from the earlier receipts: no real provider authentication, model tool selection, person approval interaction, task-session resume or production-daemon task binding is proved, and this is not a runtime receipt gate. Native version admission and binary fencing remain required. The Monitor tool is still an unrewritten prompt-tool path. Exact-head package gate and CI are recorded on the PR.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# 0.25.0 release verification
|
|
2
|
+
|
|
3
|
+
This record covers release preparation and source review. It claims no installation, no running-hub upgrade to 0.25.0 and no live TUI launch.
|
|
4
|
+
|
|
5
|
+
## Candidate
|
|
6
|
+
|
|
7
|
+
Version 0.25.0, prepared from main b3303e3c (16 commits since v0.24.0, 9 of them `feat`; bump rule: minor). Main then gained #1037 and #1043, merged into the release branch at 70f3a56f, so the release carries 18 commits since v0.24.0. The release commits carry the version, the CHANGELOG section, the bundle and the documentation stamps.
|
|
8
|
+
|
|
9
|
+
## Reviews
|
|
10
|
+
|
|
11
|
+
Pull requests named by the commits since v0.24.0: #1042, #1041, #1031, #1012, #1033, #935, #1032, #1035, #1028, #1029, #1027, #1025, #1024, #1022, #1020, #1023, #1021, #1019.
|
|
12
|
+
|
|
13
|
+
#1012 and #935 are the issues behind #1033 and #1032, not pull requests.
|
|
14
|
+
|
|
15
|
+
Each of the 16 pull requests merged with its exact-head `check` workflow green on ubuntu-latest and macos-latest (all four shards each), and none has an unresolved review thread. The claude[bot] review on each is the "extra usage unavailable" notice, not a review. The release session runs on a different hub from the agent-hub project board and an agent shell cannot run `ahub task list`, so for the PRs below that were not reviewed in this session, the hub review record is not read here. Their reviews are stated as the PR bodies and GitHub reviews record them.
|
|
16
|
+
|
|
17
|
+
Reviewed in this release session:
|
|
18
|
+
|
|
19
|
+
- #1032 (task 12, #935): claude approved 71df8835 with `hub_review`, and Codex found no major issues at 71df8835. A follow-up commit 0076d986 makes inbox links carry the project and selects it in the panel (Codex: no major issues at 0076d986). The merged head 8f88eb48 is the rebase of 0076d986 onto main with a CHANGELOG conflict resolved by keeping both lines (check run 41252842704). That is an approval at an earlier head; the content delta is the conflict resolution only.
|
|
20
|
+
- #1033 (task 13, #1012 Part 2): claude approved e990bc7 with `hub_review`. Codex then left threads at 73fc8aa0, bb59e518, b0d5c3be and 9700c060, and Copilot at 74bcfffd: card attribution, broadcast arcs, cap integrity, arc expiry, a stalled project blocking the scene, and the dogfood row. Each was fixed with a test and its thread answered and resolved. Codex found no major issues at the merged head 89108375 (check run 41260946811). The `hub_review` approval is at an earlier head; the later commits are those review fixes, read by claude before merge.
|
|
21
|
+
- #1035 (agent-mem 0.17.0 pin): prepared by claude for the coordinated release the person approved on 2026-11-01. The Codex code review completed at the merged head eecd7631 with no findings; there is no separate hub review (check run 41249599153).
|
|
22
|
+
|
|
23
|
+
Merged by other sessions, as recorded on the PRs:
|
|
24
|
+
|
|
25
|
+
- #1037 (task 606, #1036, distinguishable sessions and sender provenance): Codex, Copilot and claude[bot] reviewed 872c757c; their threads were answered and resolved at 4dbea3f3. Merged head b65c4504 (check run 41273051923), after the release branch point.
|
|
26
|
+
- #1043 (task 604, #1030, cross-project task handoff): Codex, Copilot and claude[bot] reviewed ce62908b; their threads were answered and resolved at 2b28fded. Merged head c3cc372e (check run 41275467577), after the release branch point.
|
|
27
|
+
|
|
28
|
+
- #1019 (native version-named receipts): read-only OCR delegation, no finding; merged head bb04e335 (check run 41214600952).
|
|
29
|
+
- #1020 (research campaign spec, hub task 595): reviewer codex per its body; merged head 1e62fb5e (check run 41216881998).
|
|
30
|
+
- #1021 (owner review delivery refresh): independent read-only review and OCR delegation, no defect; merged head 93201d56 (check run 41216437395).
|
|
31
|
+
- #1022 (calendar schedules, task 592): Codex threads at b86fc7ed were resolved; merged head a1134856 (check run 41221438344).
|
|
32
|
+
- #1023 (security sentence on generation review): read-only manual review of a one-sentence documentation change; merged head 0c57e9aa (check run 41217077321).
|
|
33
|
+
- #1024 (versioned campaign persistence): independent review found two defects, both fixed with regression tests; merged head dbd487f6 (check run 41225669180).
|
|
34
|
+
- #1025 (doctor memory readiness, task 591): merged head 96303c2a (check run 41226139512).
|
|
35
|
+
- #1027 (campaign dispatch gate): Codex threads at c0caf0a8 were resolved; merged head 1cdfd888 (check run 41236820463).
|
|
36
|
+
- #1028 (experiment records): independent Bugs/Security/Compliance review, no remaining blocker; merged head 2ec771c9 (check run 41243986451).
|
|
37
|
+
- #1029 (study-dropped owner offers): Codex threads at cda2ac34 were resolved; merged head 15acb90c (check run 41242811388).
|
|
38
|
+
- #1031 (`ahub study`, hub_study tools): Codex threads at e47fea8b and Copilot at 115c6af6 were resolved; merged head 77b1992f (check run 41260046135).
|
|
39
|
+
- #1041 (exact protocol approvals): independent code review, no Important finding; Copilot reviewed the merged head a05342e6 (check run 41270130168).
|
|
40
|
+
- #1042 (agent-mem 0.18.0 pin, board task 609): independent review of all 11 non-generated paths, no Important finding; merged head 42aefad3 (check run 41271493781).
|
|
41
|
+
|
|
42
|
+
## Native acceptance receipts
|
|
43
|
+
|
|
44
|
+
Receipts added under `docs/verification/` since v0.24.0: none.
|
|
45
|
+
|
|
46
|
+
This list is read from the repository, never written by hand. Native acceptance and the person's release consent are separate records: consent is `ahub sdlc authorize-release 0.25.0`, person only, and is not recorded in this file. The tag run refuses without it.
|
|
47
|
+
|
|
48
|
+
## Document review
|
|
49
|
+
|
|
50
|
+
`node scripts/check-docs.mjs --require-fresh` reported 13 stale documents after release preparation. Each was read against the source commits since its stamp (9af51bfd; ce8da3ec for local-worker.md), corrected where needed in 92282ae3, and restamped at 92282ae3 with `bun scripts/release-prepare.ts restamp <document>... --reviewed`.
|
|
51
|
+
|
|
52
|
+
- `src/cli/help.ts`, corrected: `ahub setup` names the acon plugin registration (#1032), and `ahub doctor` names the memory capture rows read from `amem setup <tool> --json` (#1025). The `study` entries already matched `src/cli/study.ts`, and the `schedule` usage is unchanged by #1022. `launch.ts` and the native entries are unchanged in the range. `test/help.test.ts`, `test/completion.test.ts` and `test/schedule-cli.test.ts` pass.
|
|
53
|
+
- `README.md`, corrected: a research campaigns bullet, `cron`/`tz` schedules in Operations, and the release report link now points to this file. The acon plugin and Space paragraphs from #1032/#1033 match `src/ui/plugin.ts`; the README states no agent-mem pin.
|
|
54
|
+
- `docs/quickstart.md`, corrected: a new "Upgrading to 0.25.0" note covers the acon plugin and Space, the agent-mem 0.18.0 pin with the rule that every amem writer on one memory home must run 0.16.0 or later, doctor's memory capture rows, research campaigns, cron schedules, the owner re-file at a new head, and running `ahub setup` again after an upgrade (acon marks a changed module stale). The install line names v0.25.0.
|
|
55
|
+
- `docs/operations.md`, corrected: new sections "acon console plugin" and "Research campaigns: `ahub study`"; `ahub study show` in the authority table; doctor's unknown outcome; the owner re-file during review; and the `calendar_schedules` recovery gate. The confirmation list, the seven views, the Space caps (32/200/64) and the 3 s budget were checked against `src/ui/plugin.ts`, `src/hub/ui.ts` and `src/ui/office-space.ts`.
|
|
56
|
+
- `docs/security.md`, corrected: new sections on the acon plugin (no credential of its own, registration hash, confirm fingerprint is a request binding and not authentication, deny-only Pi/local approvals, #264-allowlisted Space) and on research campaigns (console-only approval, rechecks at the write, provenance never upgraded, privacy stubs, recovery refusal). The schedules trust boundary covers `cron` and `tz`.
|
|
57
|
+
- `docs/agent-notes/daemon.md`, corrected: scope lists the acon and `ahub study` files; the recovery floor lists the five `research_*` features; the acon bullet covers registration and the Space timing rules; a doctor memory capture bullet.
|
|
58
|
+
- `docs/agent-notes/tasks.md`, corrected: scope lists `research-campaign.ts` and `research-experiments.ts`; new campaign storage and experiments bullets; `study_approve_protocol` among the person ops.
|
|
59
|
+
- `docs/agent-notes/tests.md`, corrected: a test that runs `ahub doctor` through the CLI also sets `CODEX_HOME` and puts a fake `amem` first on PATH (#1025).
|
|
60
|
+
- `docs/agent-notes/README.md`, `adapters.md`, `budget.md`, `bus.md`, `local-worker.md`: unchanged. Their sources changed only through files whose rules live in daemon.md and tasks.md (study forms in `identity.ts`, `STUDY_TOOLS` in `capture.ts`, research integrity fields in `restart.ts`).
|
|
61
|
+
|
|
62
|
+
After #1037 and #1043 were merged into the release branch (70f3a56f), the same 13 documents were stale again and were reviewed for those two PRs only, then restamped:
|
|
63
|
+
|
|
64
|
+
- `src/cli/help.ts`, corrected: `ahub task handoff` gains `[--color=auto|always|never]`, and its description says state changes show in `ahub board --handoffs` (only an agent requester gets task messages; `Tasks.handoffEvent` skips the person). #1037 changed no CLI entry.
|
|
65
|
+
- `README.md`, corrected: one sentence each for cross-project handoff and for distinguishable sessions as provenance, not authentication.
|
|
66
|
+
- `docs/operations.md`, corrected: the handoff section now says the person gets no follow-back message, that `ahub task handoff` is Console, that a target in recovery or shutdown refuses, and that the target's PII patterns apply.
|
|
67
|
+
- `docs/security.md`, corrected: a new "Cross-project task handoff" section (same-user console connection, who may hand off, what crosses each way, the origin applies no PII patterns of its own and refuses private turns and `[pii]` tasks, recovery label) and a paragraph on what session identity and sender provenance do and do not guarantee.
|
|
68
|
+
- `docs/quickstart.md`, corrected: the 0.25.0 note gains a sentence each for #1043 and #1037.
|
|
69
|
+
- `docs/agent-notes/daemon.md` (scope, channel plugin project, sender provenance, the handoff recovery fence), `tasks.md` (scope and handoff invariants), `adapters.md` (launch ids read by shape for labels only), `bus.md` (`Envelope.session`) and `tests.md` (fixtures that run the real plugin set `cwd` to the realPath'd hub root), corrected. `README.md`, `budget.md` and `local-worker.md` of agent-notes, unchanged.
|
|
70
|
+
|
|
71
|
+
The AGENTS.md path map and the daemon.md and tasks.md entries in `docs/verified.json` now include the new files `src/ui/plugin.ts`, `src/ui/office-space.ts`, `src/cli/acon-register.ts`, `src/cli/study.ts`, `src/cli/study-output.ts`, `src/hub/research-campaign.ts` and `src/hub/research-experiments.ts`, plus the earlier unmapped `src/hub/schedules.ts` and `src/hub/folder-trigger.ts`, and from #1037/#1043 `src/hub/session-identity.ts`, `src/hub/provenance.ts`, `src/hub/channel-project.ts`, `src/hub/project.ts`, `src/hub/handoff.ts`, `src/cli/handoff-args.ts` and `src/cli/handoff-output.ts`. The CHANGELOG 0.25.0 section gained the entries that #1021, #1022, #1025, #1037, #1043 and the research PRs had not added.
|
|
72
|
+
|
|
73
|
+
## Checks
|
|
74
|
+
|
|
75
|
+
On the Mac at 96b09c59 (the release branch after the second restamp, with #1037 and #1043 merged in), with the worktree's own frozen install (Bun 1.4.2; `@staix/agent-mem` 0.18.0):
|
|
76
|
+
- `node scripts/check-docs.mjs --require-fresh` printed `docs: OK (0 stale documents)`.
|
|
77
|
+
- `bun x tsc --noEmit` was clean.
|
|
78
|
+
- `bun scripts/build.mjs --check` exited 0.
|
|
79
|
+
- `node scripts/check-package.mjs` printed `package: OK (710 files, @staix/agent-hub@0.25.0)`.
|
|
80
|
+
- `bun test test/help.test.ts test/completion.test.ts test/schedule-cli.test.ts`: 55 pass, 0 fail (before the merge-in); `bun test test/help.test.ts test/completion.test.ts`: 24 pass, 0 fail (after).
|
|
81
|
+
|
|
82
|
+
The unsharded full `scripts/check.sh` at 0b198f46 (before the merge-in) in a fresh dgx02 container checkout (`remote_dev.py verify`) reached 6661 passing tests and no failure, then hang-watch stopped it at its 960 s total bound (`cause=total`, quiet for 1 s), so it did not finish and is not claimed as a pass. The release PR's exact-head CI, sharded on both OSes, is the full gate.
|
|
83
|
+
|
|
84
|
+
## Known gaps, not blocking
|
|
85
|
+
|
|
86
|
+
- Release preparation was done by claude, not jcode: board task 14 was assigned to jcode, who accepted it but had not started when the person asked to proceed. The board could not move the task (reassignment needs the conductor role); jcode was told to stand down.
|
|
87
|
+
- The hub review record of the PRs merged by other sessions is not read here (see Reviews).
|
|
88
|
+
- No installation, running-hub upgrade or live acon check of 0.25.0 is claimed. The person's Mac acon node is checked after the publish and the coordinated upgrade.
|
|
89
|
+
- `src/hub/execution-budget.ts` and `src/hub/path-policy.ts` remain without a named agent note in the AGENTS.md map; they predate this range.
|
|
90
|
+
- `cliCommandLabel` labels `ahub study approve-protocol` as a bare `study` in the audit; harmless (no text leaks), left as a follow-up.
|
|
91
|
+
- The experiment surfaces in the research campaigns spec (`hub_experiment_record`, `hub_experiment_show`, `ahub study attest|receipt`, `research.runners`) are not shipped; the docs and CHANGELOG say so.
|