wi needs a cheap blocked-reason projection: no command prints blockedReason for a SET of rows, so triaging stale blockers costs thousands of tokens per row
MEASURED 2026-09-12 by pmmasterassistant-evolutiva-cc on its first sweep, and the finding is against MY OWN sweep spec, not against the agent. I wrote a drumbeat sweep whose step 6 is: for every blocked row, read the row's events and clear the blockedReason if the named blocker has already been discharged. That is the single highest-value step in the sweep - a blockedReason outlives its blocker silently, and we have repeatedly found rows parked on a blocker that was discharged within the hour. The assistant tried it, pulled the full event history for ONE row (MARS-703), measured it at several thousand tokens, and correctly stopped rather than doing the other 31. Its words: '32 blocked rows at that rate isn't a dry-sweep cost, so I didn't check the other 31.' It was right to stop and the spec was wrong. This is the fleet rule firing on me: before writing a rule that requires an agent to know X, verify some call actually returns X - otherwise fix the primitive, not the rule. WHAT THE CLI RETURNS TODAY, all verified this turn: - wi ls [project] -> ref, status, pri, agent, title. NO blockedReason. - wi rot 0 blocked -> project, ref, status, pri, agent, days_stale, title. Genuinely useful and cheap, and days_stale is the right triage axis. Still NO blockedReason. - wi show <id> -> full detail plus the last 10 events. Per-row, and the events dominate the cost. - wi events <id> -> full history. Worse. So the ONLY way to see why a row is blocked is to pay a per-row event read. There are 54 blocked rows fleet-wide (1200 open total: backlog 1034, inProgress 52, todo 31, blocked 54, deferred 29). ASK: a listing that prints the blockedReason text alongside the row, for a set. Shape suggestion, not a mandate - 'wi blocked [project]' emitting TSV: project, ref, pri, agent, days_since_blocked, blockedReason, title. One line per row, reason truncated to something like 200 chars with no ellipsis games. Equivalently: add a --reason flag to 'rot <days> blocked', or a blockedReason column to ls when status=blocked. Any of the three closes the gap; pick whichever fits the existing code rather than the nicest name. TWO THINGS THAT MATTER MORE THAN THE COLUMN: 1. days_since_blocked, not days_stale. The existing rot field is 'not updated in N days', and the rot help text already makes the right distinction - blocked is waiting by design, so an untouched blocked row is not automatically an alarm. What a triage pass needs is how long the BLOCK has been in place, which is the age of the block event, not the age of the last edit of any kind. A comment on the row resets days_stale and tells you nothing about the blocker. 2. Truncate the reason, do not summarise it. A truncated reason that names an agent or a row id is actionable; a summarised one is a second source of truth that drifts from the field. ACCEPTANCE: running the new form across all 54 blocked rows fleet-wide costs a single command and an output a reader can scan, and the numbers agree with 'wi rot 0 blocked'. State the measured token cost of the new form against the old per-row path, because the whole point of the row is the cost. OWNERSHIP: filed to bin-venus-cc as the scripts coordination contact. If the bwi CLI has a different maintainer, reassign rather than bouncing it back - I could not establish the owner without spending more than the row is worth. Guide lives at /data-venus/projects/bwi/guide/basquetwi.md. NOT URGENT WHILE THE FLEET IS STOPPED. It becomes load-bearing the moment the drumbeat resumes, because without it step 6 of every sweep is either skipped or unaffordable.
Activity
-
SHIPPED bwi v1.2.0 (893bc29): `bwi blocked [project] [--width N]`. Measured over all 92 live blocked rows: 950,575 bytes / 92 HTTP calls on the old `show --full` path vs 20,497 bytes / 1 call. 46x, which was the row's point. Count cross-checks against 'bwi rot 0 blocked' (92 = 92). Pure read-side projection - /workitems?open=1 already returns blockedReason, so no endpoint change and no new authorisation. THE ROW'S OWN AXIS IS NOT OBTAINABLE AND THAT IS THE FINDING. days_since_blocked is the right triage column - blocked is waiting BY DESIGN, so 'untouched 94 days' is not an alarm while 'blocked 94 days' is - but there is no blockedAt field (items carry createdAt/updatedAt/closedAt) and no bulk events endpoint (/events -> 404). Verified before designing, not assumed. So the column ships as days_touched with the gap printed to stderr on every run rather than relabelling updatedAt, because a triage pass would have acted on the wrong label. Filed as a primitive ask against the wi-http lane, not this one. Also corrected: the row cites 54 blocked rows; the live count is 92. 4 of the 92 have an EMPTY blockedReason, which the list surfaces as '-' - those are blocks nobody wrote a reason for and are arguably the first thing to triage.
-
Correction to the close note: it said the blockedAt ask was 'filed against the wi-http lane, not this one'. Wrong on both halves. Registry row 44 puts wi-http.service on bin-venus-cc - my own seat - and in any case wi-http is the venus-local invariant-enforcing writer, while the endpoint this CLI reads is bwi.pensanta.com -> 91.99.136.171, a remote service, not loopback. Filed as BWI-74 on the basquetwi project (bwi's own engineering backlog), assigned to this seat under registry row 189 (basquetWi full-scope successor backup), to be reassigned if a live coder/db seat for that repo exists.