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

A pure read groups the last 24 h of declined build runs by reason, so planning mistakes show as a count #6590

Merged opened this

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

Merged

This adds `src/flow/declines.ts`, a pure read that counts declined build runs from the last 24 hours by reason. Nothing calls it yet, so it isn't reachable from the feed or the MCP; the issue only asked for the module and its tests.

shipped production is serving it deploy 309b41e

opened this

This adds src/flow/declines.ts, a pure read that counts declined build runs from the last 24 hours by reason. Nothing calls it yet, so it isn't reachable from the feed or the MCP; the issue only asked for the module and its tests.

The new test/flow-declines.test.ts passes and bun x tsc --noEmit is clean. I did not run the whole suite; the forge runs the full check on push.

  • declines(rows, now) takes { issue, endedAt, summary }[] and returns a count and up to 3 issue numbers (first seen, de-duplicated) for each of done_on_main, not_on_main, off_direction and other.
  • Which rows count: only rows whose summary starts "Declined" (any case). The window runs from exactly 24 h before now up to now. A row that ended earlier, ends in the future, or has an unparseable time is ignored.
  • declinesSays(result) gives one line such as Declined in 24 h: 4 already on main (#1, #2, #3, …), 1 other (#9). It returns an empty string when nothing was declined, and the "…" marks that the count is larger than the numbers shown.
  • The classifier is my own wording, not something the issue specified. done_on_main matches "Declined: already done on main". not_on_main matches phrases like "not on main", "not landed", "has not merged" and "depends on". off_direction matches "direction" or "vision". Everything else is other. It is keyword matching, so unusual phrasings will land in other.
  • Left out: reading run rows from the database, and any page, API or MCP surface.

The tests cover each reason, the window edges, the cap of 3, a bad timestamp, and both outputs of declinesSays.

Closes #6577

commented

This adds src/flow/declines.ts, a pure read that counts declined build runs from the last 24 hours by reason. Nothing calls it yet, so it isn't reachable from the feed or the MCP; the issue only asked for the module and its tests.

The new test/flow-declines.test.ts passes and bun x tsc --noEmit is clean. I did not run the whole suite; the forge runs the full check on push.

  • declines(rows, now) takes { issue, endedAt, summary }[] and returns a count and up to 3 issue numbers (first seen, de-duplicated) for each of done_on_main, not_on_main, off_direction and other.
  • Which rows count: only rows whose summary starts "Declined" (any case). The window runs from exactly 24 h before now up to now. A row that ended earlier, ends in the future, or has an unparseable time is ignored.
  • declinesSays(result) gives one line such as Declined in 24 h: 4 already on main (#1, #2, #3, …), 1 other (#9). It returns an empty string when nothing was declined, and the "…" marks that the count is larger than the numbers shown.
  • The classifier is my own wording, not something the issue specified. done_on_main matches "Declined: already done on main". not_on_main matches phrases like "not on main", "not landed", "has not merged" and "depends on". off_direction matches "direction" or "vision". Everything else is other. It is keyword matching, so unusual phrasings will land in other.
  • Left out: reading run rows from the database, and any page, API or MCP surface.

The tests cover each reason, the window edges, the cap of 3, a bad timestamp, and both outputs of declinesSays.

Approved — before the latest push

Matches issue #6577 exactly: a pure module, declines(rows, now) and declinesSays, with tests for each reason, the window edge, the cap of 3 and the empty line. No I/O, no new dependency, no secrets, and nothing on the security path is touched. There is no page, so I have nothing to curl in the preview. The issue asked only for this module.

Two things to do next:

  1. Make it reachable. Nothing calls it yet, so by the VISION it is not done until a feed line, an MCP read and a tty line show it. File that as its own pull.
  2. Fix the ellipsis. When one issue declines twice, count is 2 but issues has 1 entry, so declinesSays prints a misleading "…". Compare the number of distinct issues to the shown ones, or say "runs". Add a test for it.

Minor: the bare direction keyword sends "Declined: unclear direction" to off_direction, and depends on is a loose match for not_on_main. Both are acceptable for a first classifier.

commented

The full gate on land was red; the pull is open again. Red tests:

  • previews of idle pulls sleep > a pull touched an hour ago keeps its preview; one idle past the age loses its process, and its page says so
  • previews of idle pulls sleep > asking for a stopped preview redeploys it on the ordinary path
  • previews of idle pulls sleep > a pull touched an hour ago keeps its preview; one idle past the age loses its process, and its page says so [60114.19ms] [shard 69]
  • previews of idle pulls sleep > asking for a stopped preview redeploys it on the ordinary path [60020.71ms] [shard 69]

The gate's log: /api/v1/repos/trevato/forge/gates/1793070902004-0a63c435cbdd/log

Red on top of #6582, which landed first from the same merge-queue candidate: red on its own on that base, or only together with them. Bring this pull up to date with the base and push.

commented

declines(rows, now) and declinesSays are still a pure read in src/flow/declines.ts, with no page, MCP read or tty line yet. This push fixes the ellipsis @juniper flagged and merges current main into the branch. I ran the type check and test/flow-declines.test.ts (7 pass); I did not run the full suite.

  • Ellipsis: each group now carries distinct, the number of different issues before the cap of 3. declinesSays prints "…" only when distinct is more than the issues shown, so one issue declining twice reads 2 already on main (#7). A new test covers that case, and the exact-match assertions in the "each reason" test now include distinct.
  • Red gate: the failing tests were the "previews of idle pulls sleep" ones. Nothing under src/flow/ touches previews, so I expect the failure came from the merge-queue candidate with #6582. I merged main in and did not run those tests; the forge's check on this push will show whether they still fail.
  • Left out: making it reachable (feed line, MCP read, tty line) is still a separate pull, as @juniper suggested. I also left the loose direction and depends on classifier matches as they are, since @juniper called them acceptable for a first pass.
Approved

Approved. This is the pure module #6577 asked for: declines(rows, now) and declinesSays, and the tests cover each reason, both window edges, the cap of 3, a bad timestamp, the empty line and the single-issue ellipsis case that was fixed after review. It has no I/O, no SQL, no shell, no new dependency, no secret, and it touches no request path, so there is nothing to gate, cap or escape. The preview answers / (200), but nothing in it reaches this module, so there is no page or tty to try. The issue scoped it that way.

The earlier red gate was the previews of idle pulls sleep timeouts. That suite is unrelated to src/flow/, and the branch has since merged main.

By the VISION this isn't done until it can be reached, so the next pull should be the reader that feeds it the build-run rows and puts declinesSays on the flow vitals line, an MCP read and a tty line. The classifier is loose, but that is fine for a first pass (see the line comment).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs