The fleet view draws every live worker, not only ship tasks - #61
Conversation
The fleet pipeline view filtered every non-ship live worker into an out_of_scope list rendered as a single dim count, so a captain watching a running scout saw "0 agents ... 1 running no pipeline" over "no agents in flight" and read the view as broken. Liveness is now the whole membership test and kind decides only the shape of the row. A worker with no pipeline gets a compact three-row block - id, kind, window, and the state read through bin/fm-crew-state.sh - and never gets pipeline boxes it does not have. A secondmate reading unknown, which bin/fm-crew-state.sh produces by construction for a quiet one, renders as dim "idle" rather than as an alarm. Blocks now come in two heights, so scrollWindow() solves the window start and the block count together instead of dividing available rows by one constant. Schema bumped to fm-flow-snapshot.v2: agents changed meaning and out_of_scope is removed.
The snapshot suite gains a live scout, a live second mate and a DEAD scout in one fixture fleet, so the live ones must be drawn and the dead one must still be held back - a fix that only asserts the live direction would let a finished worker back onto the screen. The two compact workers get real state/<id>.meta records over real directories so their state is bin/fm-crew-state.sh's actual bytes rather than a hand-written approximation, and the read-only hash is taken again over the home that reader touches. The renderer suite asserts the drawn rows, the absence of pipeline boxes for a worker that has none, that the empty-fleet line prints only when nothing is live, that a quiet second mate uses no alarm colour while a blocked one keeps its own, and that a fleet of both block heights still fits its terminal at every size swept.
A fleet of pipeline-less workers narrowed to 80 columns still carried "stages 1-6 of 9" from the horizontal layout, describing cells that were not on screen.
…changed Three assertions were renamed for no reason beyond wording, which reads to the kept-tests gate as the base losing them. The behaviour each asserts is unchanged, so the base's own names are restored and the cases this branch adds sit alongside them rather than replacing them.
|
| assertion | why it cannot survive |
|---|---|
ships with a live endpoint become agents; scouts and dead endpoints do not |
the task is to make a live scout an agent |
a live worker with no pipeline is named rather than silently absent |
it is now drawn, not named in out_of_scope |
emits the fm-flow-snapshot.v1 schema id |
the schema is v2 |
60 failing: — every single one is in the base's own copies of tests/fm-flow-snapshot.test.sh and tests/fm-flow-tui.test.sh. None is a behaviour regression. Two mechanical causes:
- The base's renderer fixtures build
fm-flow-snapshot.v1documents; this branch's renderer refuses any other schema id, so every one of them exits 1. tests/lib.sh'sfailexits the file. So the base's file dies at its first mismatch and every assertion after that point is recorded as lost — including ones with nothing to do with this change, e.g.every tracked bin/*.mjs passes node --check.
The whole branch's own suite is green (bin/fm-test.sh: 108 of 108 files), and the two rewritten files cover everything the base's covered plus the new behaviour.
The supersession is unavoidable, whatever is decided about the schema
Worth being explicit, because the obvious escape does not exist. This base assertion:
[ "$got" = "arm-lock-gate-q4,eager-dispatch-e2,no-run-yet-n1" ] || fail "unexpected agent set: $got"
pass "ships with a live endpoint become agents; scouts and dead endpoints do not"runs against a fixture containing a live scout. Making that scout an agent is the whole task, so this assertion falls under any version of this change. Reverting the schema bump would shrink the failing count but cannot reach zero, and it would cost an honest wire format: out_of_scope would have to stay as an always-empty field whose emptiness means the opposite of what it used to.
Options
- Approve a supersession entry in
data/supersessions/firstmate.mdfor the three named assertions (entry format inbin/fm-pr-merge.sh's header), and merge. Recommended: the supersession is exactly the behaviour change that was asked for, the branch's own suite is green, and the wire format stays honest. - Keep
fm-flow-snapshot.v1and carryout_of_scopeas an always-empty compatibility field. Fewerfailing:entries, still at least onemissing:, and a wire format that lies about what an emptyout_of_scopemeans. I do not recommend it. - Something else — I will implement whichever is chosen.
Nothing further is pushed until this is decided.
Merged
|
The defect
The fleet pipeline view drew only ship tasks. Every other live worker was filtered into an
out_of_scopelist the renderer showed as a single dim count, so the captain saw0 agents ... 1 running no pipelinewithno agents in flightbeneath it while a scout was demonstrably alive, and read the view as broken.It was not broken. It was telling the truth about a set it had defined too narrowly, and a view whose body is empty while workers are running is indistinguishable from one that has failed.
The change
Liveness is now the whole membership test. Kind decides only the shape of the row.
pipeline: truepipeline: falsestateobjectThe original concern is kept honest: a worker with no pipeline gets no pipeline boxes. Nine permanently empty boxes over a scout would be an invented journey, which is a worse lie than the omission was.
pipelineis a field the snapshot states rather than a kind string the renderer matches on, so a kind the renderer has never heard of still lands on the right side of the question.The compact row's state is read, not derived:
bin/fm-crew-state.shalready owns reconciling a crew's current state out of its run step, its pane, and its append-only status log, so the collector calls it and passes its answer through split into its stated fields. A read that fails reportsok:falseand the row saysstate not read; it never falls back to the status log's last line, which is a wake event and not a current state.A quiet second mate is healthy and is not painted as a fault.
AGENTS.mdsection 8 says its idle endpoint is normal, andbin/fm-crew-state.shencodes the same rule by skipping the pane busy-check forkind=secondmate- so a quiet one readsunknownby construction.unknownis magenta everywhere else in this view, which is right where it means nobody could find out and wrong here where it means there is nothing to report. It renders dimidle, with the detail dropped. Every other state a second mate can report keeps its own colour, because those come from its status log and are real.Blocks now come in two heights, so
visibleRows()+resolveTop()are replaced by onescrollWindow(heights, avail, top, sel): how many blocks fit depends on which is first, and dividing available rows by a single constant would answer for a frame that is not being drawn. The captain's scroll rule is unchanged and is the three clauses in that function.Schema bump, deliberately
fm-flow-snapshot.v1->v2. This is a genuine break in both directions, not an additive change:agentschanged meaning - it was the live ship tasks and is now every live worker - so av1consumer reading av2document would draw pipeline boxes over workers that have none.out_of_scopeis removed, not emitted empty. It existed to name the live workersagentsexcluded, andagentsnow excludes none, so an empty array left in place would be a field whose emptiness meant the opposite of what it used to.omittednow covers dead records of any kind and carries each one's kind. A dead scout previously appeared in neither list and was dropped silently.bin/fm-flow-tui.mjsrefuses any other schema id outright, so the two ship together or neither runs.docs/flow-tui.mdis updated to match; the:482-487comment justifying the old filter is replaced by one describing the new behaviour.Verification
Regression tests cover both directions, as required - a fix that only asserts the live worker is drawn would put a finished worker back on screen beside running ones.
tests/fm-flow-snapshot.test.sh(31 assertions): the fixture fleet gains a live scout, a live second mate, and a dead scout. The live ones must be agents; the dead one must still be held back inomittedwith its kind. The two compact workers get realstate/<id>.metarecords over real directories, so what is asserted isbin/fm-crew-state.sh's actual bytes rather than a hand-written approximation of them. The read-only hash is taken again over the home that reader touches, because the compact path calls a whole second script per worker.tests/fm-flow-tui.test.sh(51 assertions): the scout and second mate appear in the body;3 agentscounts them;no agents in flightprints only when nothing is live; a pipeline-less worker gets no stage labels and no box borders; a quiet second mate's row uses none of the three alarm colour slots while a blocked one keeps yellow; av1document is refused; and a fleet of both block heights fits its terminal at every size swept, 40 to 200 columns.bin/fm-lint.shclean.bin/fm-test.sh: 108 assigned, 108 run, 108 passed, 0 failed.fm-supersession: v1 flow-show-all-workers-n8 4480c77 aWQJYW55CXRlc3RzL2ZtLWZsb3ctc25hcHNob3QudGVzdC5zaDo6c2hpcHMgd2l0aCBhIGxpdmUgZW5kcG9pbnQgYmVjb21lIGFnZW50czsgc2NvdXRzIGFuZCBkZWFkIGVuZHBvaW50cyBkbyBub3QKaWQJYW55CXRlc3RzL2ZtLWZsb3ctc25hcHNob3QudGVzdC5zaDo6YSBsaXZlIHdvcmtlciB3aXRoIG5vIHBpcGVsaW5lIGlzIG5hbWVkIHJhdGhlciB0aGFuIHNpbGVudGx5IGFic2VudAppZAlhbnkJdGVzdHMvZm0tZmxvdy1zbmFwc2hvdC50ZXN0LnNoOjplbWl0cyB0aGUgZm0tZmxvdy1zbmFwc2hvdC52MSBzY2hlbWEgaWQKaWRzCWZhaWxpbmcJdGVzdHMvZm0tZmxvdy1zbmFwc2hvdC50ZXN0LnNoOjoqCmlkcwlmYWlsaW5nCXRlc3RzL2ZtLWZsb3ctdHVpLnRlc3Quc2g6OioK 1b53efdf173662522823fe18503f5e75140204396f8e8b655bd84c5f855ea8b0