director: fold a startup triage pass (tooling-issue-prioritization) to warm the headless lane before the init gate #397

Closed
opened 2026-07-01 05:35:36 +00:00 by coilysiren · 1 comment
Owner

Problem

The autonomous-drain half of warded director is effectively never used, because the headless lane is always empty. Nothing assigns headless mode labels between sessions, so at launch the init gate ("drain now?", ward#361) surfaces immediately with nothing queued. The surface session then dispatches work directly (warded #N), bypassing the queue, so the lane never fills. Net effect: the budget-governed autonomous drain (the whole point of the heartbeat, ward#351) never runs. The two halves of the director were meant to alternate, but in practice only the surface half is ever exercised.

Root cause

Mode assignment requires a triage pass that never runs on its own. The just-landed tooling-issue-prioritization skill (agentic-os, commit f991872) defines the triage method and explicitly presumes a warded triage run assigns the mode axis:

  • .agents/skills/tooling-issue-prioritization/references/automation-mode-axis.md:25 - "the mode... is a per-issue judgment made during the triage pass (a warded triage run)".
  • automation-mode-axis.md:20-21 - fail-closed default is consult, so unlabeled issues never enter the headless queue. Nothing auto-runs headless until a deliberate, confident promotion.

So the fuel the drain needs (issues promoted to headless) is only ever produced by a triage run that has no trigger.

Ask

Inject a triage pass into director startup, before the init gate, over the scoped backlog. No out-of-band cron - it rides the existing launch flow (the operator's requirement was that it fit the flow, not add a step). The pass applies the tooling-issue-prioritization method:

  • Carve P0 by the content-rule net, then judgment-confirm (assignment-method.md, p0-content-rules.yaml).
  • Score the remainder and percentile-cut into P1-P4 bands.
  • Per-issue mode judgment headless/interactive/consult, fail-closed to consult, only high-confidence headless/interactive promotes out of human-gated (automation-mode-axis.md:20-25).

After the pass the init gate sees a warm lane, so answering "drain now?" yes actually has queued headless work to drain.

Wiring notes

  • There is an existing --triage flag on ward agent director (see agent-director.md:57). Decide whether startup-triage becomes default-on or whether --triage is folded into the pre-init-gate launch sequence. Front-load: read what --triage does today before choosing.
  • The heartbeat's per-tick refresh already reads mode labels (agent-director.md:24). This issue adds the write side (assigning labels) at startup.
  • Mode judgment is a per-issue LLM call. The director already runs host one-shots for its dispatch decision (agent-director.md:25-27) - reuse that path/driver rather than a new harness.
  • Skip re-triage of already-labeled issues unless a staleness rule says otherwise, to keep startup cheap on a large backlog (--limit default 50).
  • Keep the fail-closed posture intact: nothing auto-promotes to headless without a confident call.

Relates

  • agentic-os#246 - the dispatch gate + org-label rollout the mode axis feeds.
  • The tooling-issue-prioritization skill (agentic-os, f991872) - the triage method this invokes.
  • ward#361 (init gate), ward#351 (heartbeat), ward#346 (backlog port).

Mode / tier

headless-eligible. Direction is settled (triage-into-startup, applying the skill). The remaining choices (default-on vs fold --triage, staleness rule) are implementation latitude for the carry, not pending human decisions.

## Problem The autonomous-drain half of `warded director` is effectively never used, because the headless lane is always empty. Nothing assigns `headless` mode labels between sessions, so at launch the init gate ("drain now?", ward#361) surfaces immediately with nothing queued. The surface session then dispatches work **directly** (`warded #N`), bypassing the queue, so the lane never fills. Net effect: the budget-governed autonomous drain (the whole point of the heartbeat, ward#351) never runs. The two halves of the director were meant to alternate, but in practice only the surface half is ever exercised. ## Root cause Mode assignment requires a triage pass that never runs on its own. The just-landed **tooling-issue-prioritization** skill (agentic-os, commit f991872) defines the triage method and **explicitly presumes a `warded` triage run** assigns the mode axis: - `.agents/skills/tooling-issue-prioritization/references/automation-mode-axis.md:25` - "the mode... is a per-issue judgment made during the triage pass (a `warded` triage run)". - `automation-mode-axis.md:20-21` - fail-closed default is `consult`, so unlabeled issues never enter the headless queue. Nothing auto-runs headless until a deliberate, confident promotion. So the fuel the drain needs (issues promoted to `headless`) is only ever produced by a triage run that has no trigger. ## Ask Inject a triage pass into **director startup, before the init gate**, over the scoped backlog. No out-of-band cron - it rides the existing launch flow (the operator's requirement was that it fit the flow, not add a step). The pass applies the tooling-issue-prioritization method: - Carve P0 by the content-rule net, then judgment-confirm (`assignment-method.md`, `p0-content-rules.yaml`). - Score the remainder and percentile-cut into P1-P4 bands. - Per-issue mode judgment `headless`/`interactive`/`consult`, fail-closed to `consult`, only high-confidence `headless`/`interactive` promotes out of human-gated (`automation-mode-axis.md:20-25`). After the pass the init gate sees a **warm** lane, so answering "drain now?" yes actually has queued headless work to drain. ## Wiring notes - There is an existing `--triage` flag on `ward agent director` (see `agent-director.md:57`). Decide whether startup-triage becomes default-on or whether `--triage` is folded into the pre-init-gate launch sequence. Front-load: read what `--triage` does today before choosing. - The heartbeat's per-tick refresh already **reads** mode labels (`agent-director.md:24`). This issue adds the **write** side (assigning labels) at startup. - Mode judgment is a per-issue LLM call. The director already runs host one-shots for its dispatch decision (`agent-director.md:25-27`) - reuse that path/driver rather than a new harness. - Skip re-triage of already-labeled issues unless a staleness rule says otherwise, to keep startup cheap on a large backlog (`--limit` default 50). - Keep the fail-closed posture intact: nothing auto-promotes to headless without a confident call. ## Relates - agentic-os#246 - the dispatch gate + org-label rollout the mode axis feeds. - The `tooling-issue-prioritization` skill (agentic-os, f991872) - the triage method this invokes. - ward#361 (init gate), ward#351 (heartbeat), ward#346 (backlog port). ## Mode / tier headless-eligible. Direction is settled (triage-into-startup, applying the skill). The remaining choices (default-on vs fold `--triage`, staleness rule) are implementation latitude for the carry, not pending human decisions.
Author
Owner

WARD-OUTCOME: done - director now runs a startup triage pass before the init gate that writes tier + automation-mode labels, warming the headless lane.

The core wiring was the easy part: the pass slots into driveBacklog right before backlogRefresh, so the freshly-written headless labels get ranked into the very lane the init gate then sees warm. Reusing the existing host one-shot path meant no new harness, and batching every untriaged issue into one prompt per repo keeps it to ~1 LLM call instead of three-per-issue.

What actually fought back was the doc-size gate, not the code. agent-director.md was already sitting at 3979/4000 chars, so every sentence I added forced a compensating trim - and then ward#398 landed on main mid-flight and rewrote the same sections, so I re-fit the whole file twice under the 80-line/4000-char cap. The code-comments hook (2-line blocks, 90 chars) also bit late, because untracked files get stashed during --files runs so it read clean until the real commit.

Confidence is high on the deterministic half (P0 regex net, percentile bands, fail-closed mode, skip-already-labeled) - all unit-tested. Lower on the LLM prompt itself: the SCORE/MODE/CONF line format is forgiving, but only live runs over a real backlog will calibrate whether claude fills it sensibly.

Rough edges worth filing: the percentile cut runs per-repo over the untiered pool only, so the skill's global distribution isn't strictly enforced across a multi-repo scope (fine for a warm pass, worth a cross-scope cut later); staleness is binary (labeled = skip), no time-based re-triage; and labels must already exist at org scope (agentic-os#246) - a missing one just logs and skips until that rollout lands.

WARD-OUTCOME: done - director now runs a startup triage pass before the init gate that writes tier + automation-mode labels, warming the headless lane. The core wiring was the easy part: the pass slots into `driveBacklog` right before `backlogRefresh`, so the freshly-written headless labels get ranked into the very lane the init gate then sees warm. Reusing the existing host one-shot path meant no new harness, and batching every untriaged issue into one prompt per repo keeps it to ~1 LLM call instead of three-per-issue. What actually fought back was the doc-size gate, not the code. `agent-director.md` was already sitting at 3979/4000 chars, so every sentence I added forced a compensating trim - and then ward#398 landed on main mid-flight and rewrote the same sections, so I re-fit the whole file twice under the 80-line/4000-char cap. The code-comments hook (2-line blocks, 90 chars) also bit late, because untracked files get stashed during `--files` runs so it read clean until the real commit. Confidence is high on the deterministic half (P0 regex net, percentile bands, fail-closed mode, skip-already-labeled) - all unit-tested. Lower on the LLM prompt itself: the SCORE/MODE/CONF line format is forgiving, but only live runs over a real backlog will calibrate whether claude fills it sensibly. Rough edges worth filing: the percentile cut runs per-repo over the untiered pool only, so the skill's global distribution isn't strictly enforced across a multi-repo scope (fine for a warm pass, worth a cross-scope cut later); staleness is binary (labeled = skip), no time-based re-triage; and labels must already exist at org scope (agentic-os#246) - a missing one just logs and skips until that rollout lands.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#397
No description provided.