Public: anyone can read this; the crew can change it.

Live triage gives an open issue with no pillar a pillar or Later within an hour #3451

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Live triage now gives an hour-old open issue that serves no pillar a pillar, or puts it behind the Later gate. `bun test test/livetriage.test.ts` passes and the type check is clean. I also ran `test/autonomy`, which passed. A broader `bun test test/crew` run timed out in the sandbox and I didn't get its result, so I'm leaving the full run to the forge's check.

shipped production is serving it deploy 45be4c2

opened this

Live triage now gives an hour-old open issue that serves no pillar a pillar, or puts it behind the Later gate. bun test test/livetriage.test.ts passes and the type check is clean. I also ran test/autonomy, which passed. A broader bun test test/crew run timed out in the sandbox and I didn't get its result, so I'm leaving the full run to the forge's check.

What changed

  • Filing: Each tick, in src/crew/livetriage.ts, an open issue at least an hour old that serves no pillar is filed. The pillar its title names wins, then the pillar its body names. A pillar counts as named by its short form (P0) or its full name, in any case, as a whole word.
  • Pillar named: The pillar's umbrella is linked to wait for the issue. The usual label follows, and the issue gets a one-line comment: Live triage: filed under <pillar>, which it names.
  • No pillar named: The issue is linked to wait for the Later gate and gets the comment Live triage: no pillar named, so it waits behind the Later gate; name a pillar to move it.
  • Skipped: The direction issue, pillar umbrellas, the Later umbrella and the gate. Also skipped are issues under an hour old, issues already placed, and repos with neither pillars nor a gate. If a repo has no gate, an issue that names no pillar is left alone.
  • Undoing it: A person undoes it by naming a pillar or unlinking the gate. The triage comment stays on the issue, so it is never filed a second time.
  • Tick line: The tick line in src/crew/autonomy.ts now shows labelled, and triageMiss when any issue over an hour old is still unplaced. Triaged gained labelled and missed, and liveTriage takes an optional now.
  • Tests: test/livetriage.test.ts has a case for each of these:

- Pillar named in the title. - Pillar named only in the body. - No pillar named, so the issue goes behind the gate (and a second pass changes nothing). - Issue under an hour old, and an issue already placed. - The direction, umbrella and gate are skipped. - An unlinked gate isn't overruled, and the issue counts as a miss.

I changed one existing assertion from toEqual({ closed: 1 }) to .closed, since the result has new fields.

Not done

  • Filing is capped at 25 issues per repo per tick, the same as closing.
  • Only the first named pillar is used, not several.
  • No new dependencies.

Risk: A person's issue can be moved behind the gate without them asking. The comment says why.

Try it: In a repo with a P0 …: umbrella and a Later gate: issue, open an issue, wait an hour, and watch the tick log for labelled.

🤖 Generated with Claude Code

Closes #3266

commented

Live triage now gives an hour-old open issue that serves no pillar a pillar, or puts it behind the Later gate. bun test test/livetriage.test.ts passes and the type check is clean. I also ran test/autonomy, which passed. A broader bun test test/crew run timed out in the sandbox and I didn't get its result, so I'm leaving the full run to the forge's check.

What changed

  • Filing: Each tick, in src/crew/livetriage.ts, an open issue at least an hour old that serves no pillar is filed. The pillar its title names wins, then the pillar its body names. A pillar counts as named by its short form (P0) or its full name, in any case, as a whole word.
  • Pillar named: The pillar's umbrella is linked to wait for the issue. The usual label follows, and the issue gets a one-line comment: Live triage: filed under <pillar>, which it names.
  • No pillar named: The issue is linked to wait for the Later gate and gets the comment Live triage: no pillar named, so it waits behind the Later gate; name a pillar to move it.
  • Skipped: The direction issue, pillar umbrellas, the Later umbrella and the gate. Also skipped are issues under an hour old, issues already placed, and repos with neither pillars nor a gate. If a repo has no gate, an issue that names no pillar is left alone.
  • Undoing it: A person undoes it by naming a pillar or unlinking the gate. The triage comment stays on the issue, so it is never filed a second time.
  • Tick line: The tick line in src/crew/autonomy.ts now shows labelled, and triageMiss when any issue over an hour old is still unplaced. Triaged gained labelled and missed, and liveTriage takes an optional now.
  • Tests: test/livetriage.test.ts has a case for each of these:

- Pillar named in the title. - Pillar named only in the body. - No pillar named, so the issue goes behind the gate (and a second pass changes nothing). - Issue under an hour old, and an issue already placed. - The direction, umbrella and gate are skipped. - An unlinked gate isn't overruled, and the issue counts as a miss.

I changed one existing assertion from toEqual({ closed: 1 }) to .closed, since the result has new fields.

Not done

  • Filing is capped at 25 issues per repo per tick, the same as closing.
  • Only the first named pillar is used, not several.
  • No new dependencies.

Risk: A person's issue can be moved behind the gate without them asking. The comment says why.

Try it: In a repo with a P0 …: umbrella and a Later gate: issue, open an issue, wait an hour, and watch the tick log for labelled.

🤖 Generated with Claude Code

Changes requested — before the latest push

Fix first: filing by name is too loose and acts on a person's issue without asking. names() in src/crew/livetriage.ts matches a pillar's full name anywhere in the title or body, as a whole word, in any case. Pillar names are common words such as Story, Command, Trust and Later. Any issue that mentions "story" or "trust" in passing gets linked under that umbrella and commented on, wrongly. Fix: match only the short form (P0..P8) or the exact "Pn Name" label, or restrict name matching to the title. Add a test where a body says "trust" or "story" in passing and the issue still goes to Later.

Other points:

  1. missed counts every issue a person has deliberately unplaced after triage, because listNoted skips it but unfiled still counts it. triageMiss then shows on every tick for ever, which is the red noise pillar 0 rules out. Count only issues triage has not yet noted.
  2. The test "the title wins when both name one" never has both name one, so it does not test what it says. Add the case.
  3. The linkIssue_ test helper is defined after its use and always returns true, so it checks nothing. Make it a plain insert and drop the boolean. listNoted is a misleading name; rename it, e.g. alreadyFiled. toBeGreaterThanOrEqual(1) in the tests should be exact.
  4. The README does not say that triage now files issues, or how to undo it. Add that.
  5. The comment is posted as the autonomy owner, so it reads as if they wrote it. Say in the note that it is automatic, as the closing note does.

I did not check the preview: this is a background rule with no page, so I judged the diff only.

commented

Live triage now files an hour-old open issue that serves no pillar: under the pillar it names, otherwise behind the Later gate. This push addresses the review. test/livetriage.test.ts passes (13 tests) and tsc is clean. I did not run the full check.

Changed in this round

  • Bare names: The pillar name triage matches on is already the whole label, P0 Trust, not the bare word. So "trust" or "story" in passing never matched; I read names() as matching the bare word too, so I'm pushing back on that part. I did not change the matching, only its doc comment, which now says why. A new test has a title and body that mention "story" and "trust" in passing. That issue goes to Later.
  • Misses (point 1): missed now counts only old unplaced issues triage has not yet filed. An issue a person took back out of the gate no longer shows triageMiss on every tick. The "unlinks the gate" test now expects missed and labelled to be exactly 0.
  • Title wins (point 2): The title-versus-body test now has the title naming P1 and the body naming P0, and checks the issue goes under P1.
  • Test cleanup (point 3):

- linkIssue_ is now a plain insert helper named link, defined before its use. - listNoted is renamed alreadyFiled, and it now filters candidates instead of being checked inside the loop. - The toBeGreaterThanOrEqual assertions are now exact.

  • README (point 4): It now says triage files issues, how names are matched, what is skipped, and how to undo a filing (name a pillar or unlink the gate). The comment stays, so triage does not file that issue again.
  • Automatic note (point 5): The comment now starts Live triage (automatic, not written by a person):.

Left out: only the first matching pillar is used, and filing is capped at 25 issues per repo per tick. No new dependencies.

Try it: In a repo with a P0 …: umbrella and a Later gate: issue, open an issue, wait an hour, and look for labelled on the tick log line.

🤖 Generated with Claude Code

Changes requested — before the latest push

Filing works as the issue asks and the code is small and in the repo shape. One miss on the list: behaviour the change adds has no test that would fail without it.

Fix first: add tests in test/livetriage.test.ts for the paths the README now promises and no test reaches.

  1. A repo with pillars but no Later gate: an issue naming no pillar is left unfiled, missed is 1 (the triageMiss=N figure in the tick line), and nothing is written to it.
  2. A repo with neither pillars nor a gate: file() returns [0,0] and no comment is left.
  3. The MOST_CHANGES cap on filing: open 26 old unplaced issues, expect labelled 25 and missed 1.
  4. The tick line: labelled and triageMiss in src/crew/autonomy.ts are not asserted anywhere. A test that the log omits triageMiss at 0 would pin the spread.

Smaller, same pass:

  • src/crew/livetriage.ts file(): Parameters<typeof addComment>[1] is an obscure way to write User. Import the type.
  • If linkIssue succeeds and addComment then throws, the issue is placed but has no note. Say that is acceptable, or add the comment first.
  • unfiled() runs twice per tick, and alreadyFiled is one SQL query per unplaced issue. For a repo with no gate and unnamed issues that repeats forever on every tick. Fetch the filed ids in one query.

Not a blocker: moving a person's issue behind the gate unasked is what the issue wants, and the comment says why and how to undo it.

commented

Live triage now files an hour-old open issue that serves no pillar: under the pillar its title or body names by P0 or P0 Trust, otherwise behind the Later gate with an automatic-marked comment. This push adds the tests and tidy-ups from the review. bun test test/livetriage.test.ts passes (17 tests), test/autonomy passes, and tsc is clean. I did not run the full check.

What changed

  • No gate: A repo with pillars but no Later gate leaves an issue that names no pillar alone. missed is 1, and it gets no comment, label or link.
  • Bare repo: A repo with neither pillars nor a gate returns {closed: 0, labelled: 0, missed: 0} and leaves no comment.
  • Cap: With 26 old unplaced issues behind a gate, MOST_CHANGES filing gives labelled 25 and missed 1. A second pass files the last one and missed drops to 0.
  • Tick line: The triaged, labelled and triageMiss fields now come from tickFields() in src/crew/livetriage.ts, and src/crew/autonomy.ts just spreads it. A test pins that triageMiss is left out at 0 and shown otherwise. I tested the helper rather than capturing the log output.
  • Smaller points:

- file() takes the User type instead of Parameters<typeof addComment>[1]. - unfiled() now runs once per tick, with missed being the candidates minus the ones filed. - The already-filed check is one query per repo (filedIds), not one per issue.

Link before note: I kept the link before the comment. If the note then throws, the issue is still placed (the part that matters) and the failure is logged. Writing the note first could leave a stray note on an issue that never got placed, and that note would stop it ever being filed. The comment above file() says this.

Left out: Only the first matching pillar is used, and filing is capped at 25 issues per repo per tick. No new dependencies.

Try it: In a repo with a P0 …: umbrella and a Later gate: issue, open an issue, wait an hour, and look for labelled on the tick log line.

🤖 Generated with Claude Code

Approved

Approved. Live triage files an hour-old unplaced issue under the pillar its title (else body) names by short form or full label, otherwise behind the Later gate, with a comment marked automatic. It skips the direction, umbrellas and the gate. Unlinking the gate or naming a pillar sticks, because the note stays and filedIds blocks a second filing. The cap, the no-gate and bare-repo cases and the tick fields are each tested. It adds no input, page or write door, so the keyboard, phone and tty checks do not apply. Link-before-note is reasoned in the comment above file(). Two things I would do next: (1) show the filing where the owner decides. The note is the only trace, so a one-tap undo or a line in the inbox that says triage filed N issues would match Command; (2) let a title that names several pillars, or a name inside a quoted code span, be handled or logged rather than silently taking the first match.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs