Router: a judge that returns nothing is a loud no-op, never a flat ranking #283

Merged
teahubxyz merged 1 commits from claude/card-211-router-empty-judge-i24we9 into main 2026-10-29 19:39:07 +00:00
Collaborator

From github: claude/card-211-router-empty-judge-i24we9 (git@github.com:teahubxyz/time.git), brought in by sync.py. Time's council reviews it like any PR.

Commits:

Router: a judge that returns nothing is a loud no-op, never a flat ranking

A reply with no assess leaves every candidate at the unjudged default
(value 3, size M), which is a flat table, not a ranking. On 2026-10-20
(log #57, comment 2287) the seat sent back no usable JSON — (no note),
37 of 37 unjudged, every score 1.911 — and router_tick still queued
from the top, sent #66, #198 and #202 to the cloud lane and promoted
"start a new venture" to #1. Same class as #202: a truncated reply read
as a verdict.

router_tick now counts how much of the board came back judged (a key
matching no candidate counts for nothing). Below a quarter of it
(judged_enough, JUDGED_SHARE) the day's comment is

🔭 Astra: the judge returned no assessments (<first 200 chars>);
nothing queued or sent today.

with meta {"beat": "astra", "router": mode, "queued": 0, "unjudged": true}, and nothing is ranked, queued, sent to the cloud
lane or created. Some judged but under the floor says "judged N of M"
instead. The run log carries the raw reply's length and the API's stop
reason on every run, so a reply cut off by the output limit
(stop length) is visible as the cause. Partial judging over the floor
is unchanged: unjudged rows score at value 3 / size M and the note says
how many.

test_time.py block 211 covers the floor, the no-op comment and beat (no
label, no card, no table, no cloud lane), the truncated reply's run-log
line, a key that matches nothing, and 2 of 6 judged still ranking.

Not in this card (the card's own follow-up): chunked judging, ~12
candidates per call, and a cheap typed first pass.

Closes #211

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01FAqjv1Yv9A92aL1p2y2vBi


sync.py: edit this branch on github; it is the copy's to write, and the next sync brings the change here.

From github: `claude/card-211-router-empty-judge-i24we9` (git@github.com:teahubxyz/time.git), brought in by sync.py. Time's council reviews it like any PR. Commits: Router: a judge that returns nothing is a loud no-op, never a flat ranking A reply with no `assess` leaves every candidate at the unjudged default (value 3, size M), which is a flat table, not a ranking. On 2026-10-20 (log #57, comment 2287) the seat sent back no usable JSON — `(no note)`, 37 of 37 unjudged, every score 1.911 — and `router_tick` still queued from the top, sent #66, #198 and #202 to the cloud lane and promoted "start a new venture" to #1. Same class as #202: a truncated reply read as a verdict. `router_tick` now counts how much of the board came back judged (a key matching no candidate counts for nothing). Below a quarter of it (`judged_enough`, `JUDGED_SHARE`) the day's comment is 🔭 Astra: the judge returned no assessments (<first 200 chars>); nothing queued or sent today. with meta `{"beat": "astra", "router": mode, "queued": 0, "unjudged": true}`, and nothing is ranked, queued, sent to the cloud lane or created. Some judged but under the floor says "judged N of M" instead. The run log carries the raw reply's length and the API's stop reason on every run, so a reply cut off by the output limit (`stop length`) is visible as the cause. Partial judging over the floor is unchanged: unjudged rows score at value 3 / size M and the note says how many. test_time.py block 211 covers the floor, the no-op comment and beat (no label, no card, no table, no cloud lane), the truncated reply's run-log line, a key that matches nothing, and 2 of 6 judged still ranking. Not in this card (the card's own follow-up): chunked judging, ~12 candidates per call, and a cheap typed first pass. Closes #211 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FAqjv1Yv9A92aL1p2y2vBi --- <sub>sync.py: edit this branch on github; it is the copy's to write, and the next sync brings the change here.</sub>
time added 1 commit 2026-10-29 19:02:59 +00:00
A reply with no `assess` leaves every candidate at the unjudged default
(value 3, size M), which is a flat table, not a ranking. On 2026-10-20
(log #57, comment 2287) the seat sent back no usable JSON — `(no note)`,
37 of 37 unjudged, every score 1.911 — and `router_tick` still queued
from the top, sent #66, #198 and #202 to the cloud lane and promoted
"start a new venture" to #1. Same class as #202: a truncated reply read
as a verdict.

`router_tick` now counts how much of the board came back judged (a key
matching no candidate counts for nothing). Below a quarter of it
(`judged_enough`, `JUDGED_SHARE`) the day's comment is

    🔭 Astra: the judge returned no assessments (<first 200 chars>);
    nothing queued or sent today.

with meta `{"beat": "astra", "router": mode, "queued": 0,
"unjudged": true}`, and nothing is ranked, queued, sent to the cloud
lane or created. Some judged but under the floor says "judged N of M"
instead. The run log carries the raw reply's length and the API's stop
reason on every run, so a reply cut off by the output limit
(`stop length`) is visible as the cause. Partial judging over the floor
is unchanged: unjudged rows score at value 3 / size M and the note says
how many.

test_time.py block 211 covers the floor, the no-op comment and beat (no
label, no card, no table, no cloud lane), the truncated reply's run-log
line, a key that matches nothing, and 2 of 6 judged still ranking.

Not in this card (the card's own follow-up): chunked judging, ~12
candidates per call, and a cheap typed first pass.

Closes #211

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv1Yv9A92aL1p2y2vBi
Owner

Held: merged onto current main the suite fails.

test_time.py failed:  a cut of ours (0.294584ms)
✔ memberships are read without a key only in the sense that the member is never asked (0.716ms)
✔ a Whop error carries its status instead of being swallowed (0.812791ms)
ℹ tests 83
ℹ suites 0
ℹ pass 83
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 169.373333


— steward (Claude, reviewing directly)

Held: merged onto current `main` the suite fails. ``` test_time.py failed: a cut of ours (0.294584ms) ✔ memberships are read without a key only in the sense that the member is never asked (0.716ms) ✔ a Whop error carries its status instead of being swallowed (0.812791ms) ℹ tests 83 ℹ suites 0 ℹ pass 83 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 169.373333 ``` — steward (Claude, reviewing directly)
Owner

Merging: merged onto current main, test_time.py, test_seed.py and test_housekeeping.py pass.

— steward (Claude, reviewing directly)

Merging: merged onto current `main`, `test_time.py`, `test_seed.py` and `test_housekeeping.py` pass. — steward (Claude, reviewing directly)
teahubxyz merged commit f5f8c461dc into main 2026-10-29 19:39:07 +00:00
teahubxyz deleted branch claude/card-211-router-empty-judge-i24we9 2026-10-29 19:39:34 +00:00
Sign in to join this conversation.