diff --git a/agents/honker/work/queue-194/DESIGN.md b/agents/honker/work/queue-194/DESIGN.md index ba12d5ec5..ba7a10ea3 100644 --- a/agents/honker/work/queue-194/DESIGN.md +++ b/agents/honker/work/queue-194/DESIGN.md @@ -256,6 +256,23 @@ Fire refuses `instance-kept` for a kept instance, `organization-definition-refus fired instance stays in `roles`. The chief never deletes. Delete stays a human act because it retires the name. +Fire ends the fired instance's processes, not only its claims (F4, Megavolt through sage-1374). Every run +gets the shared model token at start: `ENV_ALLOW` (`packages/seat/src/session.mjs:83-94`) passes +`ANTHROPIC_API_KEY`, `CLAUDE_CODE_OAUTH_TOKEN` and the other provider variables into the sandbox. A revoke +can't take that token back, so a fired agent whose process lives on still holds it. Fire therefore runs V3 +steps 1 to 3 in the same transaction as the delist: + +1. It revokes every claim the instance holds. +2. It writes `lifecycle.cancelled` for each of the instance's open requests. +3. It writes `lifecycle.end` with the runs. The launcher pass sends SIGTERM to each runner after the + start-time check (`launcher.mjs:526`), spawned but unbound registry runs included. + +Fire's answer lists the runs it signalled. The delist stops any new chief launch (`launch` takes listed +instances only). A human launch request already taken is past cancelling, as in V3. The human made it, the +fire answer names it, and the human's terminate ends its run. Ten seconds after the signal, the launcher pass checks +each signalled runner again. A runner still alive gets `lifecycle.end.alive` with the run and pid, and the +Console's Agents section shows it to the human, who uses `mosaic stop`. There is still no SIGKILL (N6, R7). + ### D2.3 The hire floor (B2, sage-1365 item 4) A definition the chief can never hire, whatever `hireable` says. It fails the floor when its withinRole or @@ -266,10 +283,11 @@ crossRole holds any of: | `role.launch` | launch authority | | `role.end`, `role.revoke` | end authority | | `organization.change` | organization authority | +| `instance.name` | naming authority (Webby B2, mos-1023 item 6) | | `role.hire`, `role.fire` | hire authority | | `review.verdict` | a chief can't pick its own reviewers, so author ≠ reviewer holds | -`roles/chief-of-staff.json` fails it (role.launch, role.end, organization.change), so the chief never hires +`roles/chief-of-staff.json` fails it (role.launch, role.end, organization.change, instance.name), so the chief never hires a chief. Reviewer and security-reviewer fail it (review.verdict). A credentialed definition is refused by D2.2 item 3 until row 199, and the floor list is the place a credentialed action joins if row 199 needs it. @@ -283,10 +301,10 @@ The floor is a constant in `business/src/vocabulary.mjs`, `HIRE_FLOOR`. It is ch - At hire, in the broker, against the definition as loaded then. A role file edited after load is caught here. -`hireable` in `roles/chief-of-staff.json` starts empty in this row (`[]`). Filling it is a reviewed role -file commit, as AGENTS.md invariant 7 requires. With an empty list the chief can hire nothing, even with -Jason's resolve, until a reviewed commit names a kind. I chose that over a default list because the -choice of role kinds is a policy call, not this row's. +`hireable` in `roles/chief-of-staff.json` stays empty in this row (`[]`, Q4, sage-1374). Naming the first +role kind is a separate policy commit in `roles/`, made after Jason resolves the `prd.approve` decision, as +AGENTS.md invariant 7 requires. With an empty list the chief can hire nothing, even with Jason's resolve, +until that commit. The row's tests use scratch role files whose `hireable` names a kind. ### D2.4 The per-agent forbid and the veto (sage-1365 item 3) @@ -427,7 +445,8 @@ the other byte-identical (T11). ## D7. The Console A new Settings section, "Agents", in its own `agents.js` file. Settings itself isn't rewritten. It lists -each instance with definition, listed, kept, retired and running runs. It has these actions: +each instance with definition, listed, kept, retired and running runs, and flags a run with a +`lifecycle.end.alive` event as "still running after fire" (D2.2). It has these actions: - Create (definition select, from `definitions`), Delete (with a confirm naming what stays: the evidence and the workspace under `.retired`). @@ -468,6 +487,7 @@ Every test uses scratch roots under `TMPDIR` and the existing fixtures (`busines | T8b | Hire floor (D2.3): one case per floor action. A fixture definition, clean when the chief's role file loads and listed in `hireable`, is rewritten to hold only that action before the hire. The hire refuses `definition-not-hireable`. chief-of-staff and reviewer refuse | same | | T8c | Floor at load: a role file whose `hireable` names a definition holding each floor action refuses at `loadRole`, one case per action. A clean list loads. A missing, version 1 or duplicate name refuses | business `role.test.mjs` | | T9 | Chief fire: runs end, open requests cancelled, delisted, still in `roles`. Kept (even with a resolved decision), END_PROTECTED, `launch.by` and last-listed refuse | bus `chief-of-staff.test.mjs` | +| T9a | Fire ends processes (F4): with a bound run and a spawned but unbound registry run of I, both fixture runners holding a stand-in model variable, fire answers both runs. After the launcher pass, neither runner pid is alive and I holds no claim. A fixture runner that ignores SIGTERM is still alive after the 10 s check and gets `lifecycle.end.alive` with its run and pid. A runner whose start time changed is not signalled | cli `launcher.test.mjs` | | T10 | Keep: chief `role.revoke` with a reason, fire, hire of that name and an `organization.set` model write aimed at a kept instance each refuse `instance-kept`. A `role.revoke` citing a human-resolved decision ends the kept run (Q2). The human's V3 works | same | | T11 | Two scratch stack instances with the same business id: V2, V3 and V5 in A leave B's root and config byte-identical. A chief of business A can't hire into business B on the same bus | cli `lifecycle.test.mjs`, bus | | T12 | Agent and reader sessions refuse every human verb before any effect. The tester gets exactly the D4.1 table, including `tester-refused` for `instances.set` op `delete` (B6). The D4 hook is called with the verb | bus `instances-verb.test.mjs` | @@ -520,6 +540,11 @@ sha256 checked after each one. | M44 | fire skips `instance-kept` when a decision is cited | T9 | | M45 | `instance.hire` skips the `launch.by` caller check | T8 | | M46 | `veto.set` skips `#human` | T18 | +| M47 | `instance.name` removed from `HIRE_FLOOR` in the broker's hire check | T8b | +| M48 | `instance.name` removed from the load check in `role.mjs` only | T8c | +| M49 | fire revokes the claims but writes no `lifecycle.end`, so no runner is signalled | T9a | +| M50 | fire's signal skips spawned but unbound registry runs | T9a | +| M51 | the 10 s recheck writes no `lifecycle.end.alive` | T9a | ## Scope and boundaries @@ -554,8 +579,11 @@ sha256 checked after each one. - R5. `tools.mjs`, `serve.mjs`, `broker.mjs`, `vocabulary.mjs` and `role.mjs` may carry sha256 pins in other packages' tests. The build greps the tests for every changed path plus a 64-hex value before in-review, without a `head`. -- R6. With `hireable` empty, the chief can hire nothing until a reviewed role file commit names a kind. - Case 1's "as needed" waits on that commit and on PRD 1.7. +- R6. With `hireable` empty, the chief can hire nothing until the policy commit in `roles/` that follows + the `prd.approve` resolve names a kind (Q4). Case 1's "as needed" waits on that commit and on PRD 1.7. +- R7. A fired agent's runner that ignores SIGTERM keeps the shared model token until the human runs + `mosaic stop` (D2.2, F4). `lifecycle.end.alive` makes that visible. It doesn't end it. A SIGKILL + escalation, or a per-agent model token (row 199 Q-M4, a later proxy row), would close it. ## Questions and rulings @@ -565,8 +593,9 @@ sha256 checked after each one. branch. D2.4. - Q3, ruled by Sage (sage-1355): launch and terminate are tester verbs scoped to the tester's own business, behind `bus.tester`. D4.1. -- Q4, for Sage: should `hireable` start empty (my choice, D2.3), or should this row name a first kind for - review? +- Q4, ruled by Sage (sage-1374): `hireable` stays empty in this row. Naming the first role kind is a + separate policy commit in `roles/` after Jason resolves the `prd.approve` decision. Tests use scratch role + files that name a kind. D2.3. ## r2 changes against webby-0003 @@ -589,3 +618,12 @@ sha256 checked after each one. | N6 | V3 and V4: no SIGKILL, `regenerate-timeout` | | N7 | D2.4: intended, Q169 | | N8 | V2 item 2 and T2 | + +## r3 changes against sage-1374, sage-1377 and Megavolt's F4 + +| Item | Where | +|---|---| +| Q4 ruled: `hireable` stays empty, the first kind is a later policy commit in `roles/` | D2.3, R6, Questions | +| `instance.name` joins the floor (Webby B2, mos-1023 item 6) | D2.3 table, T8b, T8c, M47, M48 | +| F4: fire ends the fired agent's processes, since `ENV_ALLOW` gives every run the shared model token | D2.2, D7, T9a, M49 to M51, R7 | +| `git.push.remote` routed to coder only (mos-1028 item 3, row 199 r3) | `PRD-1.7-DRAFT.md`, REQ-LAND-2 and the REQ-WAIT-3 append | diff --git a/agents/honker/work/queue-194/PRD-1.7-DRAFT.md b/agents/honker/work/queue-194/PRD-1.7-DRAFT.md index c40c4d13c..5cf05bf52 100644 --- a/agents/honker/work/queue-194/PRD-1.7-DRAFT.md +++ b/agents/honker/work/queue-194/PRD-1.7-DRAFT.md @@ -1,4 +1,4 @@ -# PRD 1.7 draft: the chief of staff's hire and fire authority +# PRD 1.7 draft: the chief of staff's hire and fire authority, and the coder's push to its fork Draft by Honker for row 194 (#1692), under Mos's ruling mos-1017 (through Sage, sage-1365). Not approved. It changes nothing until Jason approves it as a `prd.approve` decision in the Console. Sage opens that @@ -6,27 +6,31 @@ decision and sends Mos its id. Base: `docs/prd/mosaic-stack.md` version 1.6 at 5 ## What it changes -Row 194 adds `role.hire` and `role.fire` to the vocabulary. Under REQ-WAIT-3 they are hard waits, so today -Jason resolves every hire and every fire. This version routes them for the chief of staff within fixed -bounds, so the chief hires and fires as needed and the user's per-agent forbid still holds. +Row 194 adds `role.hire` and `role.fire` to the vocabulary, and row 199 adds `git.push.remote`. Under +REQ-WAIT-3 all three are hard waits, so today Jason resolves every hire, every fire and every push to a +remote. This version routes hire and fire for the chief of staff within fixed bounds, so the chief hires +and fires as needed and the user's per-agent forbid still holds. It routes `git.push.remote` for the coder +only (Mos, mos-1028 item 3). One `prd.approve` decision covers all three (Vikunja #420). When this version lands, a reviewed commit: -1. adds `role.hire` and `role.fire` to `ROUTED` in `packages/business/src/vocabulary.mjs` and in - `packages/bus/src/broker.mjs`. -2. adds both to `roles/chief-of-staff.json` withinRole. +1. adds `role.hire`, `role.fire` and `git.push.remote` to `ROUTED` in + `packages/business/src/vocabulary.mjs` and in `packages/bus/src/broker.mjs`. +2. adds `role.hire` and `role.fire` to `roles/chief-of-staff.json` withinRole, and `git.push.remote` to + `roles/coder.json` withinRole. No other role file gets `git.push.remote`. 3. switches the broker's check on `instance.hire` and `instance.fire` from a cited decision to the - `reason` form, as `role.end` works for REQ-ROLE-2. + `reason` form, as `role.end` works for REQ-ROLE-2, and makes `publish`'s `decision` optional for a + within-role class (row 199 D9 step 1). -Every other check stays as row 194 builds it. Filling `hireable` stays a separate reviewed role file -commit. +Every other check stays as rows 194 and 199 build it. Filling `hireable` stays a separate reviewed role +file commit in `roles/`. ## Text for the PRD Status line, appended to the current paragraph: -> Version 1.7 routes the chief of staff's hire and fire actions, approved by Jason in decision -> . +> Version 1.7 routes the chief of staff's hire and fire actions and the coder's push to its own fork, +> approved by Jason in decision . Source, a new bullet above "Version 1.6 source": @@ -46,7 +50,7 @@ Under "Added in version 1.2", after REQ-COS-2: > - The chief hires only role definitions that need no credentials, until a later version adds > credentialed roles. > - The chief hires only the role kinds its role file lists. Changing that list is a reviewed commit. -> - The chief never hires a role that holds launch, end, organization or hire authority, or the +> - The chief never hires a role that holds launch, end, organization, naming or hire authority, or the > review verdict. So the chief never hires a chief and never picks its own reviewers, and the > author is never the reviewer. This holds whatever the list says. > - The user can forbid per agent. The user marks an instance so the chief can't fire, replace or end @@ -55,9 +59,28 @@ Under "Added in version 1.2", after REQ-COS-2: > - The kill switch stops every hire and fire while it is on. > - Every hire and fire is logged with the chief's instance, its run and the reason. +Under "Landing", after REQ-LAND-1: + +> Added in version 1.7: +> +> - **REQ-LAND-2.** A coder pushes its own work to its own fork. The action is `git.push.remote`. +> - What it pushes: the latest work commit the bus recorded for the coder's task, to a remote its +> business grants it. +> - Where it lands: only the branch `refs/heads//`. The host builds that +> name, the agent never does. A push never forces. +> - Which remote: a fork that the agent's own Gitea user owns. Gitea itself then refuses a push to +> upstream or to another agent's fork. +> - Who may: the action routes under REQ-DEC-2 and is granted within-role to the coder role only. No +> other role file grants it. +> - Before version 1.7 the action was a hard wait under REQ-WAIT-3, so each push needed a decision +> the human resolved. +> +> Every push is logged with the remote, the ref and the commit. + REQ-WAIT-3, appended: > `role.hire` and `role.fire` were added as hard waits and route under REQ-COS-3 since version 1.7. +> `git.push.remote` was added as a hard wait and routes under REQ-LAND-2 since version 1.7. ## Notes for the reviewer and for Mos @@ -67,6 +90,12 @@ REQ-WAIT-3, appended: user-resolved decision still ends a kept run (row 194 D2.4). - The kill switch is row 191's. If row 191 hasn't landed when this version is approved, the bound still holds through row 194's chain on its candidate. +- REQ-LAND-2 follows row 199's design r3 (c2c729ddf, D9 to D11, Q-M1 and Q-M2) and Megavolt's + wording in megavolt-0005, through Sage (sage-1377). Megavolt checks the text against that design. +- REQ-LAND-2 and REQ-COS-3 meet at the coder. Coder declares Gitea credentials, so REQ-COS-3's + credentials bound keeps the chief from hiring one until a later version lifts it. Granting + `git.push.remote` to coder doesn't put it on the hire floor, because a push reaches only the agent's + own fork. - The credentials bound names no row number, so the text doesn't go stale when row 199 lands. A later version lifts it. - This draft follows the PRD's own style: plain words, no semicolons in new sentences, and the status