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.
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 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:
active = someone's current chunk. Only issues carrying active are eligible to be worked./triage, or Aedan clicking a label. Never automatic, and never a side effect of filing.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 /playtestReads all open issues, groups them, and proposes a plan Aedan reacts to in chat rather than clicking through GitHub:
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.
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 | — |
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:
CLAUDE.md. Stable, rarely edited: what a dev session is, what playtest does, that release runs its own queue, that the reviewer is advisory. The table above is the starting content.sid, clone path, started-at, current chunk, status. Sids change on every context reset, so this must not require a PR to update. Sessions register at start and mark themselves wrapped at the end, which slots into #396's wrap-up checklist.session:a / session:b / session:c). Visible and filterable in the GitHub UI, and Aedan can reassign by clicking — which is what makes manual triage possible without running the command at all.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.
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.
active + session:a|b|c, absence-of-label = backlog. Alternative: an explicit backlog label, but that requires labelling every new issue and fails open in the wrong direction./triage — recommend Aedan on demand, not a cron. Automatic triage would re-create the "machine decides what's in scope" problem this is meant to fix.None.
No comments.