/triage: activate work deliberately, let the backlog stay inert nf-8dwn ← Beads

closed priority 2 task unassigned activesession:b

Twinned from https://github.com/cfsh/ninefold/issues/397 by tools/beads/import_github.py's reconcile pass.

Aedan's framing: filing issues is a good way to remember work, but scope shouldn't grow forever. Three dev sessions (A/B/C) now run in parallel, each with its own clone. Each should hold a concrete couple of issues, work them with focus, and wrap up — rather than keep finding work indefinitely.

The backlog is now mostly machine-authored

28 open issues. 18 are machine-filed (64%), 10 are Aedan's. Of the 18, nine are PR #NNN follow-ups: issues from ninefold-reviewer — one per PR reviewed, generated mechanically.

Rate over the last two days: 08-01 was 15 machine-filed vs 1 from Aedan; 08-02 so far is 7 machine vs 4. #381 documents the reviewer slice: nine residual issues from nine PRs in one day, arrival ≈ 1:1 with PR count, and #375#377 → PR #378#379 shows a follow-up spawning its own follow-up with no natural termination.

The reframe: don't slow the filing, make the backlog inert

The instinct is to file fewer issues. That's the wrong lever — capture is genuinely useful and the individual items are real (#381 makes this case well: "the answer isn't 'file fewer'"). The actual problem is that a filed issue currently reads as *claimable work*, so every one of them enlarges someone's scope.

Split capture from activation:

This resolves the tension directly: keep filing freely, and the backlog stops being a scope-growth engine. It also defuses the reviewer-follow-up volume in #381 — nine inert captured items are fine, so option B there becomes a nice-to-have rather than urgent.

/triage — conversational, like /playtest

Reads all open issues, groups them, and proposes a plan Aedan reacts to in chat rather than clicking through GitHub:

  1. Read every open issue (+ recent comments) and the sessions' current holdings.
  2. Group by subsystem/theme and collapse near-duplicates — the nine reviewer follow-ups cluster naturally by component.
  3. Propose a chunk per session: a couple of concrete issues each, themed so one session owns one area and they don't collide.
  4. Aedan reacts conversationally — swap this, drop that, not now.
  5. Apply: set active + session:x labels, drop active from anything that's gone cold, post CLAIM markers.

Because it reads the whole tracker, /triage should run at session start or in its own session — running it inside a session already at 600k is exactly the expensive case measured in the lifecycle issue.

The team is more than dev sessions

There is no first-class notion of who is on the team. In practice it is already six kinds of actor with different roles:

| Actor | Role | Takes a triage chunk? | |---|---|---| | dev A / B / C | work a claimed chunk of issues to done, then wrap up | yes | | playtest | runs the /playtest ritual with Aedan, routes the braindump | no — Aedan-triggered | | triage | runs /triage, assigns chunks, exits | no — it does the assigning | | release | distribution work off its own queue | no — separate queue | | ninefold-reviewer | automated Tier-0 review, one run per ready-signal | no — event-driven | | *(archived)* tonapse-main | 15-day session on the original clone; wound down under #396 | — |

Session identity on GitHub

Sessions can't see each other — session IDs are app-local and the clones are separate. GitHub is the only shared medium, which CLAUDE.md already establishes for CLAIM/RELEASE.

This is not hypothetical. Session C (sid b8f438b4, clone ninefold-dev/ninefold-c) has been active all day and has *never* posted a CLAIM or RELEASE; a repo-wide search for its sid returns nothing and its tracked-prs.txt is empty. It was identifiable only by listing the filesystem, which works solely because C and B share a machine. From GitHub alone — the channel the sessions actually share — session C does not exist.

Split the registry by how fast each part changes:

Keep CLAIM exactly as-is: label = assignment (intent), CLAIM comment = possession (execution). The claim carries the sid, poll.sh already parses it, and it is load-bearing today. A session picks up work labelled for it, posts its CLAIM, and works. /triage writes labels; sessions write claims. No new channel needed.

/triage should run as its own short-lived session — start, read, propose, apply, exit. It is the one session type that never accumulates context and so never needs #396's wrap-up treatment.

How this closes the cost loop

A session's chunk is now a fixed, finite set at claim time. When it's done, the session wraps up (see the lifecycle issue) and its context can be reset — ready for the next chunk. Triage is what makes "wrapped up" a meaningful state instead of an arbitrary stopping point: without a bounded claimed set there is no definition of done, and without a definition of done there is no safe reset point, so context grows until it hits 1M.

Open questions (recommended defaults, so nothing blocks)

Related: #381 (reviewer follow-up arrival rate), and #396.

Dependencies

None.

Comments

No comments.

Add a comment