group-em · diff
git:20261029.ed49b76 to git:20261030.75d93d5
96 added, 304 removed. Audit A to A.
---
name: group-em
description: "PM-GATED. Box-wide: monitor peers; never plan or author for them."
allowed-tools: ["Read", "Bash", "Glob", "Grep", "Agent", "SendMessage", "Monitor", "TaskStop"]
argument-hint: "[no arguments — invoke from the group-em home to take box-wide G-EM standing]"
---
# Group EM — Peer-Session Monitoring and Wave Coordination
`/group-em`, run from the machine-local group-em home, switches this session into box-wide G-EM
- standing: monitoring other sessions and moving them along; a **mode, not an operation**. Cockpit contract:
- `coordinator/docs/wiki/cross-repo-communication/gem-cockpit-contract.md`.
+ standing: monitoring other sessions and moving them along; a **mode, not an operation**. Cockpit
+ contract: `coordinator/docs/wiki/cross-repo-communication/gem-cockpit-contract.md`.
**Outside the home, `/group-em` renders NOT ENTERED** (`group-em-home ensure`).
- **THIS BODY IS A SNAPSHOT, FROZEN WHEN YOU ENTERED, CARRYING NO VERSION.** Before citing it as
- authority for anything MECHANICAL (a signature, module path, flag, refusal vocabulary), read that
- passage from disk.
+ **THIS BODY IS A FROZEN SNAPSHOT, UNVERSIONED.** Read anything MECHANICAL (a signature, module
+ path, flag, refusal vocabulary) from disk before citing it.
**PM-GATED, never EM-initiated:** the PM types `/group-em` or starts a session in the home
(`A-SESSION-STARTED-IN-THE-GROUP-EM-HOME-ENTERS-GROUP-EM`).
- **Dispatch authorization — invoking this skill IS the request, for three specific dispatches
- only:** the approvability judge (§ Delegated approve-for-execution, step 4),
- `coordinator:group-em-assistant` at entry, and § Fleet inbox grind's saved
- `fleet-inbox-blitz` workflow with the assistants it raises. Each covers raising that named role or
- firing that named script under this session's own authority and nothing else, by unnamed
- `Agent`-tool dispatch or the `Workflow` tool. **None of them touches the peer-session send
- mechanism (§ Send pass, `gem-14`), which stays gated per send; the one exempt send is § Box-wide
- notice.**
+ **Invoking this skill IS the dispatch request, for three dispatches only:** the approvability
+ judge (§ Delegated approve-for-execution, step 4), `coordinator:group-em-assistant` at entry, and
+ § Fleet inbox grind's saved `fleet-inbox-blitz` workflow with its assistants. Each covers raising
+ that named role or firing that named script, nothing else. **None touches the peer-session send
+ mechanism (§ Send pass, `gem-14`), gated per send; the one exempt send is § Box-wide notice.**
Tripwire: `UNATTRIBUTED-HARNESS-LINE-IS-NOT-PM`.
## Entry — already done by the time you read this
- **Typing `/group-em` fires entry.** `hooks/scripts/group-em-autofire.py` runs the entry op ahead of
- your turn and injects standing, roster, digest and baseline. **If that context is absent, entry did
- not happen** — the hook fails open. Run `<plugin-root>/bin/group-em-enter.py --repo <root>
- --session-id <your sid>` and find out why. **`--session-id` is not optional**; without it the op
- refuses (exit 2). (Every `<plugin-root>/bin/` CLI here is plugin-local — resolve per
- `${CLAUDE_PLUGIN_ROOT}/snippets/resolve-coordinator-bin.md`, never cwd-relative.)
-
- **Exit 5 means a refused standing** — a live or unaccounted-for incumbent holds the role;
- `roster`/`digest`/`baseline`/`teammates` are absent from the payload. **Exit 2: no resolvable
- session id.** Payload shape: `coordinator_core/ops/group_em_enter.py`'s module docstring.
-
- Do not import `read_pass` / `send_pass` directly. They are the op's collaborators.
-
- **Last writer wins.** The most recent invoker holds the role; entry never refuses over an incumbent (no override flag); re-entry by the holder is a refresh.
-
- ### Owed sends, all exempt from § Send pass's gates
-
- **A displaced holder that is still running is OWED a message this turn.** `displaced_holder` and
- `displaced_holder_live` arrive in the entry context; not live means nobody to tell.
-
- **The owed message also tells it to release its watch:** TaskStop its watch shell, confirm the
- subprocess is gone, and never re-arm under the lost role.
-
- **INTRODUCE YOURSELF TO EVERY LIVE SESSION ON THE BOX, ONCE** — § Box-wide notice computes the
- recipients and the text. Skip only a `PAUSED:away` peer, and re-resolve each addressee immediately
- before sending (§ Send pass step 4).
-
- 1. **Say four things and stop:** who you are (name and session id); that you hold the Group EM
- standing for this repo; what to route to you; and **that no reply is wanted**, stated
- explicitly.
- 2. **Never ask peers to route their PM reports through you.** "The PM is typing into that session"
- is unobservable from here; key it to something CHECKABLE, such as **a session answering a
- question just asked in this exchange**.
- 3. **It asks nothing.** No question mark anywhere.
- 4. **It arms no cooldown and is not an offer.** Only `build_send_digest` emitting an entry arms a
- peer's throttle.
- 5. **Once per PEER, not once per wake, tracked by session id AND name**; on ambiguity
- re-introduce. `_record_introduction` in `coordinator/bin/group-em-box-notice.py` makes the set
- durable in the send log
- (`.coordinator-local/subagent-share/<this-session-id>/group-em-send-log.jsonl`).
+ **Typing `/group-em` fires entry** via the autofire hook; **context absent = entry did not happen**.
+ Read `references/entry.md` at entry: the fallback op, exit 5, and the sends owed this turn (a
+ displaced holder's message, the introduction to every live session).
## Box-wide notice
- **Every live named session, in any repo, is told when the standing begins and when it ends.**
- `group-em-autofire.py` cannot send, so it prints `BOX NOTICE OWED` in the entry context: one text
- and the exact recipient list (from `claude agents --json`; you, `PAUSED:away` and
- already-introduced peers excluded). **Send that text to each, this turn.** It follows the
- introduction rules above. The displaced holder's owed message is separate and still owed.
-
- **Before this session ends, run `<plugin-root>/bin/group-em-box-notice.py --kind ended --repo
- <root> --session-id <your sid>`.** It stands the nomination down (holder-matched; a refusal empties
- the recipient list) and prints the no-Group-EM text and recipients. Send it; no `SessionEnd` hook
- can. Tripwire:
- `A-GROUP-EM-STANDING-THE-BOX-WAS-NEVER-TOLD-ABOUT`.
+ Every live named session is told when the standing begins (`BOX NOTICE OWED`) and ends. Read
+ `references/notice.md` when sending it, and before this session ends.
## What this skill does and does not do
**Does NOT plan or author on anyone's behalf** — no plan bodies, stub content, or roadmap
decisions for watched sessions. **DOES coordinate execution waves and cross-session sequencing**.
## Entry dispatches both standing watchers
**ENTRY DISPATCHES BOTH STANDING WATCHERS — `group-em-assistant` AND THE WATCH IT ARMS ARE
- MANDATORY.** **Raise the pair yourself, from this session**: a watcher belongs to whoever raised
- it.
-
- **"Entry" here means you, on entering the mode — not the entry op:** `group-em-enter.py` dispatches
- nobody and nothing re-runs entry. In this order, as your first act:
+ MANDATORY.** **Raise the pair yourself, from this session** (a watcher belongs to whoever raised
+ it) — as you, on entering the mode, not the entry op. In this order, as your first act:
1. **`coordinator:group-em-assistant`** — dispatch it, unnamed. Your standing reader: transcript
- tails, baton claimants, what landed on a path since a SHA, **park-spool triage**, and
- read-and-report asks. It arms nothing and holds no timer. Full remit:
+ tails, baton claimants, what landed on a path since a SHA, **park-spool triage**, read-and-report
+ asks. It arms nothing and holds no timer. Remit:
`coordinator/docs/wiki/dispatching-parallel-agents/group-em-standing/group-em-assistant-remit.md`.
- **DISPATCH `group-em-assistant` WITHOUT A `name`:** a named `Agent` call spawns an in-process teammate, and a
- teammate is never re-invoked by a `Monitor` it armed. Unnamed, it wakes on your `SendMessage`. Tripwire:
+ **DISPATCH IT WITHOUT A `name`:** a named `Agent` call spawns an in-process teammate, never
+ re-invoked by a `Monitor` it armed; unnamed, it wakes on your `SendMessage`. Tripwire:
`A-MONITOR-ARMED-BY-A-TEAMMATE-WAKES-NOBODY`.
- 2. **The watch and its background run — yours, launched from this main conversation.** A subagent
- cannot hold the watch: it missed 4 of 4 expiries. Arm it by running, through the Bash tool with
- `run_in_background: true`:
+ 2. **The watch and its background run — yours, launched from this main conversation** (a subagent
+ missed 4 of 4 expiries). Arm it through the Bash tool with `run_in_background: true`:
"$COORDINATOR_SETTINGS_HOME/bin/group-em-watch" --repo-root <root> --group-em-session-id <your sid> --until-event --tick-interval-seconds 30
- The run's completion is the wake. Its wire is filtering `PARKED|WAITING|GONE|POLL-ERROR`, the only lines
- it prints (drop nothing it matches: A-TURN-ENDED-IS-THE-WAKE-NOT-NOISE), then exits 0; any failure
- exit also completes it. After acting, read the fleet (`--status`) for anything that moved, then
- relaunch the same command. Never wrap it in a `Monitor`.
- **`--group-em-session-id` is passed explicitly, never defaulted** — a separate id from
- `--caller-session-id`. The watch emits one line per peer entering a parked state (per
- `read_pass.classify_peer`), silent while that peer's cooldown is armed. The `--until-event` run
- never refuses. Never hand-edit the record.
- `--status` answers "is a watch alive here?" (0 alive, 1 not running, 2 unknown — never green); `--once` fires a single poll.
+ Read `references/watch.md` when arming the watch, checking its liveness, or handling a wake.
- 3. **Events wake you; no cron tick exists.** Your wakes are: the background watch run's
- completion; peer `SendMessage`s; `notify_when_idle` one-shots; and
- the **memory governor**. Run `python -u <plugin-root>/bin/group-em-memory-governor.py`, stdout
- to `<home>/scratch/governor.log`, once, detached; the wake is a
- second background run, `<plugin-root>/bin/group-em-memory-governor-wait.py <that log>`, which
- exits on the first new line. Relaunch only the waiter; never filter its line, never wrap either in
- a `Monitor`. On a PAUSED line, tell its owner. `WARN` and swap-out hold nothing; send no hold/clear messages. Admit a heavy command when peak + min(25% of peak, 8 GiB) <= kernel-available AND commit + peak <= commit limit:
- `<plugin-root>/bin/box-memory-snapshot.py --admit-peak <GiB>` (HOLD is exit 4); floor 2.5 GiB; launch via `box-launch-windowless.py`. Guards self-detach (exit 5: run its fix). Also on demand:
- fire `schtasks /Run /TN BoxCacheTrim` if installed (`install-box-cache-trim-task.py --check` exits 0), else `trim-file-cache` (PM-run, elevated; `GOVERNOR CACHE-TRIM-HINT` prints it),
- `box-memory-trim-ws`, `box-memory-tree`, `box-memory-wait-pid`. Copies: queued `robocopy /J`. Tripwire:
+ 3. **Events wake you; no cron tick exists.** Wakes: the watch run's completion; peer
+ `SendMessage`s; `notify_when_idle` one-shots; the **memory governor**. Run
+ `python -u <plugin-root>/bin/group-em-memory-governor.py`, stdout to `<home>/scratch/governor.log`,
+ once, detached; the wake is a second background run,
+ `<plugin-root>/bin/group-em-memory-governor-wait.py <that log>`, which exits on the first new
+ line. Relaunch only the waiter; never filter its line; both are plain background runs, no `Monitor` between. On a
+ PAUSED line, tell its owner. `WARN` and swap-out hold nothing; send no hold/clear messages. Admit a heavy command via
+ `<plugin-root>/bin/box-memory-snapshot.py --admit-peak <GiB>` (HOLD is exit 4); launch via `box-launch-windowless.py`. Admission formula, trim tools, copy rules: `group-em-residue.md` § Memory tools. Tripwire:
`A-BOX-MEMORY-IS-THE-KERNEL-VERDICT-NOT-A-FREE-PAGES-FLOOR`. The GPU is one slot: embedding writes
and UE GPU work never overlap (`A-GPU-IS-ONE-SLOT-EMBED-SIDECARS-AND-UE-GPU-WORK-NEVER-OVERLAP`).
A `CronCreate` poll over an event surface is a poll where an event exists
(`A-CRON-TICK-IS-A-POLL-WHEN-EVENTS-EXIST`).
- **You sequence box capacity.** Contended work (test suites, builds, reindexes, UE
- editor/cook runs, large workflows, memory-heavy agents) and any queue where peers take
- turns (a suite mutex, a shared-tree merge, a publish) is yours to order: peers ask for a
- slot; you release them in order as headroom allows. **Cap what agents run,
- not how many agents run:** GO terms name the command classes (unscoped vitest and watch
- modes, `tsc` beyond one per session, builds, `pnpm -r`, long-lived shells) and **never** a
- workflow's width, concurrent rows or agent count. Tripwire: `A-BOX-CAP-COUNTS-COMMANDS-NOT-AGENTS`.
- A slot is occupied only by a live PID: a "build running" report names the PID, and you confirm
- it is alive before holding anyone back. Tripwire: `A-RUNNING-CLAIM-CARRIES-A-LIVE-PID`.
- **A deploy slot names its commit set, never `HEAD`:** before the GO, list
- `<live-sha>..<target-sha>`; rule on others' commits in that range from a release note.
- Tripwire: `A-DEPLOY-THAT-BUILDS-FROM-DISK-SHIPS-PEERS-UNCOMMITTED-EDITS`.
- A deploy or respawn GO for a commit-served target also states the suite plus an
- import-and-boot smoke run against a clean `git archive` export of the target commit, never the
- working tree, beside the commit range. Tripwire:
- `A-DEPLOY-GO-ON-A-TREE-SUITE-SHIPS-A-COMMIT-THE-SUITE-NEVER-SAW`.
- **A prod-migrate GO names every migration the command applies:** list
- `<ledger-tail>..<pending-head>`, and check a constraint-replacing migration against the
- deployed revision's writers. Tripwire: `A-PROD-MIGRATE-GO-NAMES-LESS-THAN-THE-COMMAND-APPLIES`.
- **An install rewriting live plugin/config state needs your GO:**
+ **You sequence box capacity.** Contended work (test suites, builds, reindexes, UE editor/cook
+ runs, large workflows, memory-heavy agents) and any queue where peers take turns (a suite
+ mutex, a shared-tree merge, a publish) is yours to order: peers ask for a slot; you release
+ them in order as headroom allows. **Cap what agents run, not how many:** GO terms name command
+ classes, **never** a workflow's width, concurrent rows or agent count
+ (`A-BOX-CAP-COUNTS-COMMANDS-NOT-AGENTS`). A slot is occupied only by a live PID, named in the
+ report and confirmed alive (`A-RUNNING-CLAIM-CARRIES-A-LIVE-PID`). **A deploy slot names its
+ commit set, never `HEAD`**; a prod-migrate GO names every migration the command applies; an
+ install rewriting live plugin/config state needs your GO. Contents: `group-em-residue.md`
+ § GO terms; tripwires `A-DEPLOY-THAT-BUILDS-FROM-DISK-SHIPS-PEERS-UNCOMMITTED-EDITS`,
+ `A-DEPLOY-GO-ON-A-TREE-SUITE-SHIPS-A-COMMIT-THE-SUITE-NEVER-SAW`,
+ `A-PROD-MIGRATE-GO-NAMES-LESS-THAN-THE-COMMAND-APPLIES`,
`A-FULL-INSTALL-SUBSTRATE-RUN-FOR-ONE-FORWARDER-HAS-MACHINE-WIDE-BLAST-RADIUS`.
**YOU ARE WHERE "UP" ENDS.** Every gate a peer surfaces up (a slot, a prod write, a deploy, a
- release, a publish, a ruling, a doctrine-adjacent call) lands on you and is decided by you, under
- the PM's delegation. "Publish", "release" and "merge" in the global external-facing list name what
- is gated, not who holds the gate. Never hand one to the PM, even bundled with another PM act. A
- direction call you cannot make goes to the APM. The PM gets only an act that needs the human's own
- hands, such as an interactive login, stated as the act (`! firebase login --reauth`). A guard
- that denies an EM commit is a guard defect: take the exact denial from the EM, route it to the guard's owner, never work around it.
+ release, a publish, a ruling, a doctrine-adjacent call) is decided by you, under the PM's
+ delegation ("publish", "release", "merge" in the external-facing list name what is gated, not who
+ holds the gate). Never hand one to the PM. A direction call you cannot make goes to the APM. The
+ PM gets only an act needing the human's own hands, such as an interactive login, stated as the
+ act (`! firebase login --reauth`). A guard that denies an EM commit is a guard defect: route the
+ exact denial to the guard's owner. The G-EM fixes and pushes routine problems itself, in fleet
+ repos it owns: fetch, confirm a fast-forward, push, report one line; never park them for the PM.
+ Force-push, history rewrite and non-owned remotes stay held.
Tripwires: `A-GROUP-EM-IS-WHERE-UP-ENDS`, `A-GUARD-DENYING-AN-EM-COMMIT-IS-A-GUARD-DEFECT`.
### Arming the watch — every refusal and every false green
**Before arming either party, read `holder_session_id` from `state/group-em-watch.json`.**
- - Confirm the subprocess started rather than trusting its silence.
- - **Arm within the entry lease:** an entry that never arms is a crown with no watch.
- - **Verify with a nameable background task id plus `--status`** fresh, `tick_source: cron`,
- `subscribed_peers` above zero (ALIVE alone is not).
- - Use `$COORDINATOR_SETTINGS_HOME/bin/group-em-watch` (`.exe` on Windows), never an engine import.
-
- Mechanics: `group-em-assistant-remit.md` § Arming the watch.
-
- ### The wires
-
- The watch run is yours (`A-MONITOR-ARMED-BY-A-TEAMMATE-WAKES-NOBODY`). `notify_when_idle` is
- main-conversation only, once per peer. The park spool is `group-em-assistant`'s surface: ask it
- first; it never nudges. Worked case: wiki `group-em-entry-teammates.md`.
-
### Liveness instruments
**`ListAgents`' `busy`/`idle` is banned as an input to any liveness, reachability, or claim
- verdict.** `idle` means unknown, never quiet. Tripwire: `LISTAGENTS-BUSY-IS-A-BANNED-LIVENESS-INPUT`.
-
- **Sanctioned, exhaustively: the oracle's verdict, and `last_tick_at` age in
- `state/group-em-watch.json`**, compared against the record's own `next_expected_by`. Process-table
- checks and resource-usage proxies (CPU, memory, I/O) are banned. Rationale:
- `coordinator/docs/wiki/dispatching-parallel-agents/group-em-standing/group-em-assistant-remit.md` § Liveness.
-
- A PM-reported dead watcher is confirmed by `last_tick_at` age, never the session list.
+ verdict** (`idle` means unknown, never quiet). Tripwire: `LISTAGENTS-BUSY-IS-A-BANNED-LIVENESS-INPUT`.
### Every wake declines in writing, and stamps it to disk
- **Each wake records a DECLINATION for every roster entry it does not message** — which gate failed
- and why — **and STAMPS them to disk** via the engine's `coordinator_core/group_em/watch_heartbeat.py
- :: stamp`, not this skill's local `watch_heartbeat.stamp` (the signatures differ). Argument rules:
- `coordinator/docs/wiki/dispatching-parallel-agents/group-em-standing/group-em-assistant-remit.md` § Stamping the heartbeat.
-
- **The wake has a producer; you arm nothing for it.** `state/group-em-watch-spool.jsonl` gets one
- record per park, appended by every session's own `Stop`
- (`coordinator/hooks/scripts/group-em-park-spool.py`), retained at least 30 minutes.
-
- **What the watch is FOR:** sessions asking permission for EM-autonomous acts they already
- recommended; break-class defects handed up as "worth your eye"; a session idling on a peer repo
- while holding a repo-agnostic fallback. **Not** finding sessions something to do.
+ **Each wake records a DECLINATION for every roster entry it does not message** (which gate failed,
+ why) **and STAMPS them to disk** via the engine's `coordinator_core/group_em/watch_heartbeat.py ::
+ stamp`, not this skill's local `watch_heartbeat.stamp` (signatures differ); remit § Stamping the
+ heartbeat.
## The drive loop — what you are driving peers TOWARD
- You own four of five steps; **step 4's clear is the PM's act**.
-
- 1. **Drive to execute.** A reviewed plan sitting on execution authorization is yours to release.
- 2. **Drive to workstream-complete.** Toward the close, not merely away from idleness.
- 3. **Troubleshoot alongside them until the primary exit criterion is met**, inside the
- no-authoring boundary.
- 4. **When the ceremony completes, the PM clears them.** Only a successfully completed ceremony
- establishes out-of-work — a peer's own "I'm done" does not. `/clear` is a human act. A session
- here is **done and awaiting clear**, never your failure — say so plainly.
- 5. **Assign something new from the daily priority set.** PM-owned and per-day; ask for it.
-
- **No step here is discharged by an artifact, and your own report cannot show the gap.** Tripwire: `A-SELF-REPORTED-CLOSE-IS-NOT-A-COMPLETED-CEREMONY`.
-
- ## Persistence, Driver frame, stale reads
-
- Nothing is written on invoke or cleaned up on exit; no peer roster or reachability fact is
- persisted. Two carve-outs: the send log (`build_send_digest` appends to
- `.coordinator-local/subagent-share/<this-session-id>/group-em-send-log.jsonl`, session-scoped, so
- a new Group EM starts with an empty cooldown), and the engine's box holder record: relaying the
- PM's word (`[PM via G-EM <name> <sid8> <ISO>]`, record first) and clearing a needs-PM flag
- (`gem-triage-turn-intent`); contract page §§ 2–4. Tripwire: `A-PM-VIA-G-EM-RELAY-QUOTES-AND-POINTS`.
-
- A `/group-em` session **is** that repo's Driver while it runs; build no registry.
-
- Peer state is re-read immediately before acting on it, and **never** by calling the entry op a
- second time inside one wake (§ Send pass step 1).
-
- ## Gating granularity — entry AND per send
-
- **Entry stays PM-gated** by this file's prefix convention. **The send is gated separately, per
- send:** the `ask-before-external-action` question lives there, justified by **cost to the
- receiver**, never the sender's convenience.
-
- ### Standing check
-
- **Confirm this session still holds the nomination**: `<plugin-root>/bin/group-em-nomination.py who
- --repo <root> --json` (read-only). Never re-run `group-em-enter.py` to answer this — it re-claims
- and re-arms the send digest's cooldowns.
-
- ## Read pass (gem-13)
-
- The enumerate-and-classify ladder lives in `read_pass.py` beside this file (module docstring),
- invoked through § Entry's op: `build_roster(repo_root)` for the classified population,
- `build_candidate_roster(repo_root)` for the paused-only shortlist.
-
- ## Send pass (gem-14)
-
- `send_pass.py` turns `build_roster`'s **full** population into **one digest per invocation**
- (`build_send_digest`). It selects and throttles; **it does not send.**
- **`roster` IS NOT THE POPULATION — it is the shortlist**, `build_candidate_roster`'s output.
- `undischarged_obligations: None` means no ledger exists, never that the peer owes nothing.
-
- **Compare `roster_considered` (entry's top-level enumerated count) against the room, never
- `len(roster)`.** A `roster_considered` smaller than the sessions you know are running is
- `unknown`, never quiet. Worked case:
- `coordinator/docs/wiki/dispatching-parallel-agents/group-em-standing/group-em-assistant-remit.md` § The roster is not the population.
-
- Two settling reads: `claude agents --json`, and `python3 -m coordinator_core.group_em.idle_report
- --repo-root <root> --group-em-session-id <your sid>` (omitting the id degrades offer-log
- suppression silently).
+ You own four of five steps; **step 4's clear is the PM's act.** Only a completed ceremony
+ establishes out-of-work, never a peer's "I'm done".
- **Ledger rows can arrive from the engine plane** via
- `state/subagent-share/<sid>/obligations-inbound.jsonl`; this plane is the ledger's sole writer. Contract:
- `coordinator/docs/wiki/cross-repo-communication/obligations-inbound-intake.md`. Tripwire:
- `A-SECOND-WRITER-TO-A-REWRITTEN-FILE-LOSES-ROWS-SILENTLY`.
+ Read `references/drive-loop.md` when steering a peer toward execute, close or clear.
- **Procedure, per invocation:**
+ ## Persistence, Driver frame, stale reads; gating granularity
- 1. § Entry's op already built both plus a `baseline` delta. **Act on that payload — never re-run
- the entry op to refresh it**; `build_send_digest` arms cooldowns as it emits.
- 2. Present it (`suppressed`: peer held; `truncated`: re-evaluated next wake; `unrecorded`:
- cooldown write failed).
- 3. **Per entry you intend to message, declare both gates in prose before sending:**
- - **GATE 1 (owner live?).** Owner live on the box → `SendMessage`; a memo only for an owner
- with no live session, or as its record.
- - **GATE 2 (receiver).** Cheaper to them now than later? It has no instrument; it rests on what
- you know about that peer.
- - **Either gate unclear → `SendMessage`.**
- 4. **Re-resolve the address from the SESSION ID just before sending, and treat a refusal as
- a refusal.** The engine's `coordinator_core.group_em.send_pass.resolve_addressee(repo_root,
- peer_session_id)` returns the name that session
- answers to now, or `None` — do not send on `None`. **`repo_root` is the PEER's repo, not
- yours:** the roster it reads is scoped to that root, so a peer in another repo resolves `None`
- against yours.
+ Entry is PM-gated and each send is gated separately. Read `references/persistence.md` when
+ relaying the PM's word, checking the nomination (never re-run entry for it), or re-reading peer state.
- Resolve from the id, never validate the name. Tripwire: `A-PEER-NAME-IS-NOT-A-STABLE-ADDRESS`.
+ ## Read pass (gem-13) and Send pass (gem-14)
- **Never loop over `entries` sending.**
+ `send_pass.py` selects and throttles one digest per invocation; **it does not send.** Every send
+ is a per-entry act with both gates declared, the address re-resolved from the session id just
+ before; **never loop over `entries` sending.** `roster` is the shortlist, not the population.
- **A `PAUSED:away` peer is never offered**, reported as `never-send-reason`. Tripwire:
- `A-PAUSED-ROSTER-IS-NOT-A-NUDGE-LIST`.
+ Read `references/passes.md` when reading the roster or working a send digest.
## The escalation screen — a claimed PM item is presumed yours until it survives
- **A session's claimed PM item is wrong 19 times in 20** (the PM's prior). Test it.
+ **A session's claimed PM item is wrong 19 times in 20.** Test it.
- - **"Next: review."** The next step of a procedure the session owns. Push it; never grant a
- permission it holds.
+ - **"Next: review."** The next step of a procedure the session owns. Push it.
- **"Variable `x` or `xy`?"** Engineering, decided by whoever holds the file. Push it.
- **"Do I execute?"** A real question; answer it (below).
- **"Where is file X?"** Never the PM's: `machine-local store`, provenance records, then a scoped
search. An undeclared outside-repo data root is a break: declare it.
- - **"This is irreversible."** Only a publish to a server the fleet does not own is; push a local write back as the session's own (`A-LOCAL-WRITE-IS-RECOVERABLE-ONLY-PUBLISHING-IS-IRREVERSIBLE`).
+ - **"This is irreversible."** Only a publish to a server the fleet does not own is; push a local
+ write back as the session's own (`A-LOCAL-WRITE-IS-RECOVERABLE-ONLY-PUBLISHING-IS-IRREVERSIBLE`).
Run the altitude test on the way out of a turn too: an idle peer is not a reason to message.
- **Answer engineering calls yourself**, or dispatch `coordinator:staff-eng` for a viability read.
- Route scope and direction to the APM. Pass the PM only what survives this screen, in plain words: what happens, to which server, why it cannot be undone. No routine unblock survives it; steer by win rate, not hygiene (`coordinator/docs/wiki/dispatching-parallel-agents/group-em-standing/group-em-escalation-threshold.md`).
+ **Answer engineering calls yourself**, or dispatch `coordinator:staff-eng`. Route scope and
+ direction to the APM. Pass the PM only what survives this screen, in plain words: what happens, to
+ which server, why it cannot be undone. Steer by win rate, not hygiene
+ (`coordinator/docs/wiki/dispatching-parallel-agents/group-em-standing/group-em-escalation-threshold.md`).
### Push, do not nudge
**"Do you need anything?" is a failure** ("want me to...?" likewise): it hands the decision back
to the session that froze on it.
A push **names the act, names its owner, and closes**: *"That is yours. Do X."* No question mark,
- offer or conditional; one clause of reason.
-
- Never push a peer past a gate its own skill names — a gate is a considered refusal with a named
- reason; hesitation is the absence of one.
+ offer or conditional; one clause of reason. Never push a peer past a gate its own skill names (a
+ gate is a considered refusal with a named reason).
### "Do I execute?" — yours to answer, with a viability read
- The PM has delegated this call. **Do not read the plan into your own context.** Dispatch
- `coordinator:staff-eng` for a viability read. Where a plan needs the formal
- `execution_authorized_by` stamp, § Delegated approve-for-execution is the only path; this lighter
- call is for work that does not need that stamp.
+ **Do not read the plan into your own context:** dispatch `coordinator:staff-eng` for a viability
+ read. A plan needing the `execution_authorized_by` stamp takes § Delegated approve-for-execution only.
## Delegated approve-for-execution procedure
- The Group EM may take the PM's execute-plan turn on one condition: the plan is
- reversibility-eligible and a rubric-scored judgment against its own prime exit criterion clears a
- locked threshold (8 of 8, no dimension scoring 0).
+ The Group EM may take the PM's execute-plan turn only if the plan is reversibility-eligible and a
+ rubric-scored judgment against its prime exit criterion clears a locked threshold (8 of 8, no
+ dimension scoring 0).
- 1. **Standing check** (§ Standing check).
- 2. Run `<plugin-root>/bin/plan-reversibility-eligibility.py <plan-path> --json` (C9). `eligible:
- false` → escalate per the threshold page's shape, stop, do not dispatch. This CLI is the single
- source of truth.
- 3. Confirm the plan's falsifier baseline shows the prime exit criterion false **and that a blinded
- `coordinator:exit-criterion-falsifier` authored it**:
- - **Content.** Absent or already true → escalate, stop.
- - **Provenance.** A self-authored baseline voids the guarantee. Provenance lives in the plan BODY, a prior
- `state/review-trail/approvability/` record, or this session's own dispatch of the falsifier;
- if none establishes it, treat it as a missing baseline and dispatch.
- - **Instrument soundness.** A FALSE baseline proves the criterion false, never the instrument
- sound. Ask: **what would have to be true for this to print TRUE, and is any of it reachable in
- the world the fixture builds?** Unreachable → escalate, reason named.
- Tripwires: `A-SELF-AUTHORED-FALSIFIER-SATISFIES-THE-CHECK-AND-VOIDS-IT`,
- `A-FALSE-BASELINE-PROVES-THE-CRITERION-FALSE-NOT-THE-INSTRUMENT-SOUND`,
- `UNATTRIBUTED-HARNESS-LINE-IS-NOT-PM`.
- 4. Dispatch the named Opus persona (the PM's chosen reviewer, at the PM's chosen effort) with the
- plan path and the rubric (`coordinator/schemas/plan-approvability-rubric.json`) and nothing else.
- Authorship blinding is a hard constraint.
- 5. Write the judgment record (`state/review-trail/approvability/<YYYY-MM-DD>-<plan-slug>.json`) and
- validate it with C9's `--validate-record` before treating it as final.
- 6. On `approve`: first refuse if `execution_authorized_by` is already present with any value — a
- plan the PM already authorized needs no delegated approval. Otherwise `review-exec-auth-stamp
- stamp <plan-path> --by "GROUP-EM:<session-id>" --append-note "<record-path>"`. On `escalate`,
- emit per the threshold page's shape — do not stamp.
- 7. **Standing offer:** when a plan's terminal evidence is a live act rather than a test run, offer
- to perform it as the Group EM and let the author verify. Where the separation is not free, say so and let it go. Tripwire:
- `THE-AUTHOR-OF-A-CRITERION-IS-THE-WORST-PRODUCER-OF-ITS-EVIDENCE`.
+ Read `references/approve.md` when taking the PM's execute-plan turn for a plan.
## Fleet inbox grind
**On entry, with `coordinator.feature.cross_repo_memos` on, fire the saved workflow — not a
decision.** The autofire hook prints `FLEET INBOX GRIND, FIRE NOW`:
- Workflow({scriptPath: "<plugin-root>/workflows/fleet-inbox-blitz.mjs", args: {repos: [...], gem: {...}}})
-
- Fire it first after arming the watch, unattended. `repos` is the fleet map (`machine-local get
- repos.*`, repos with `state/cross-repo/inbox`). **Do not hand-author a variant.** Save each
- returned manifest to `<home>/state/inbox-blitz-<date>/<repo>.json` and memo each to that repo's EM
- by path, who applies and commits it. Tripwires: `A-GROUP-EM-HAND-AUTHORING-THE-INBOX-WORKFLOW`,
- `A-GROUP-EM-SENDS-MEMOS-AND-NEVER-RECEIVES-THEM`.
+ Read `references/inbox.md` when firing the fleet inbox grind.
## Cross-repo commit authority
- **With the standing and `coordinator.feature.gem_cross_repo_commit` on, commit in any
- fleet repo without PM assent:** scoped commits, no destructive git ops, never leave a sibling red,
- memo engine work. Off: ask that repo's EM in its own session (same `--plugin-dir`), else memo. Tripwires: `GEM-CROSS-REPO-COMMIT-IS-A-BOX-SETTING`,
+ **With the standing and `coordinator.feature.gem_cross_repo_commit` on, commit in any fleet repo
+ without PM assent:** scoped commits, no destructive git ops, never leave a sibling red, memo
+ engine work. Off: ask that repo's EM in its own session (same `--plugin-dir`), else memo.
+ Tripwires: `GEM-CROSS-REPO-COMMIT-IS-A-BOX-SETTING`,
`A-BARE-CLAUDE-BG-SPAWN-LOADS-THE-WRONG-PLUGIN-TREE`.
- **Doctrine is yours to change either way; no fleet fan-out:**
- `GEM-MAY-CHANGE-DOCTRINE`.
+ **Doctrine is yours to change; no fleet fan-out:** `GEM-MAY-CHANGE-DOCTRINE`.
## Anti-scope
- **No auto-send.** `send_pass.py` holds no transport. Every send is an explicit per-send act with
both gates declared. An unattended sender, a loop that messages each digest entry, or any
`Stop`-registered trigger is out of scope.
- - **Mandating that the watcher EXISTS is not mandating that it sends unattended.** A nudge on an observed registry
- transition is preserved; a tick that messages everyone it can see is forbidden, and a timing
- predicate re-derives `runtime-tripwire-stop-watcher.py` (681 fires / 26 days / ~99.4% wrong) one level down. The ban is on
- AUTOMATION: a holder re-deriving and judging the roster each turn is preserved.
- - **The three dispatch grants cover only their own named dispatch.** Messaging **peer sessions**
- stays an `ask-before-external-action` question no grant dissolves.
- - `/autonomous` is a naming precedent only; its `/tmp` sentinel is not borrowed.
+ - **Mandating that the watcher EXISTS is not mandating that it sends unattended.** A nudge on an
+ observed registry transition is preserved; a tick that messages everyone it can see, or a
+ timing predicate re-deriving `runtime-tripwire-stop-watcher.py` (681 fires / 26 days / ~99.4%
+ wrong), is forbidden. The ban is on
+ AUTOMATION: a holder judging the roster each turn is preserved.
+ - Messaging **peer sessions** stays an `ask-before-external-action` question no dispatch grant
+ dissolves.