fix(bin): keep the fleet view working past the per-argument cap - #46
Merged
Conversation
fm-fleet-snapshot.sh handed the whole backlog and task inventory to jq as --argjson command-line arguments. Linux caps a single argv entry at MAX_ARG_STRLEN (131072 bytes) independent of the much larger ARG_MAX total, so the snapshot died with "Argument list too long" once the backlog crossed that cap - a size the fleet had already reached. Bulk JSON now travels on stdin: json_envelope assembles the value with shell builtins and pipes it into `jq -n`, whose filter reads it back with `input`. stdin was chosen over a temp file or a process substitution because this command is read-only and must stay that way - there is no file to create, secure, or leave behind when an interrupted read abandons it. Every unbounded --argjson in the file is converted, not only the one that was failing. The more serious half was a fail-open. task_json_lines built one row per task in a loop piped into `jq -s`, so a row that could not be serialized was dropped while `jq -s` slurped the survivors and exited 0 - a task vanished from a snapshot that still reported success, and a supervisor reviewing the fleet would see a task that does not exist. scout_report_lines had the same shape and its caller checked no status at all, and fm-fleet-view.sh rendered a snapshot that produced no output as a healthy empty fleet at exit 0. A genuine failure now exits nonzero and names what failed, while an empty fleet remains a complete snapshot at exit 0. Tests generate the oversized backlog and the oversized task row programmatically, assert both render in full, and assert that neither a failed snapshot nor an empty one is ever reported as success. The macOS stock-Bash job asserts an exact fleet-view test count, so its expected value moves from 15 to 20 in the same commit as the five new tests to keep the guard and the suite from drifting. The sibling Bearings assertion stays at 41: that suite is unchanged.
sbracewell64
force-pushed
the
fork-land/fleet-view
branch
from
August 6, 2026 03:15
1ef77e2 to
eed857d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Repair the structured fleet view, which failed once the backlog grew past a size the fleet had already reached. Defect repair only: the output format and what the view reports are unchanged.
Defect 1 - the per-argument cap.
bin/fm-fleet-snapshot.shhanded the whole backlog and task inventory tojqas--argjsoncommand-line arguments. Linux caps a singleargventry atMAX_ARG_STRLEN(131072 bytes), independent of the much largerARG_MAXtotal (2097152 here, which is why the total-size intuition misleads), so the snapshot died withArgument list too long.Bulk JSON now travels on stdin:
json_envelopeassembles the value with shell builtins and pipes it intojq -n, whose filter reads it back withinput. stdin was chosen over a temp file or a process substitution because this command is read-only and must stay that way - there is no file to create, secure, or leave behind when an interrupted read abandons it, and unlike--slurpfilethe filter receives the value itself rather than a one-element array to unwrap. Every unbounded--argjsonin the file is converted, not only the one that was failing.Defect 2 - the fail-opens.
task_json_linesbuilt one row per task in a loop piped intojq -s, so a row that could not be serialized was dropped whilejq -sslurped the survivors and exited 0. A task vanished from a snapshot that still reported success.scout_report_lineshad the same shape and its caller checked no status at all, andbin/fm-fleet-view.shrendered a snapshot that produced no output as a healthy empty fleet at exit 0. A genuine failure now exits nonzero and names what failed; an empty fleet remains a complete snapshot at exit 0.Relationship to upstream PR 1612
Upstream kunchenguid/firstmate#1612 is open against the same task and its head (
a53f8b4) is untouched by this branch. The two overlap and are not equivalent:json_inputs+ successiveinputreadsjson_envelope+ one envelopereturn 1pipefailbin/fm-fleet-view.shempty-snapshot guardThe distinct contribution here is the renderer: 1612 does not modify
bin/fm-fleet-view.sh, so a snapshot that exits 0 having produced nothing still renders there as a healthy empty fleet. Both approaches to the cap are sound; this is not a claim that 1612's snapshot work is wrong.Delivery and verification status
This is a direct-PR, not a no-mistakes delivery. It carries no no-mistakes attestation marker and did not run that pipeline, so the
Require no-mistakescheck is expected to fail. That red is authorized for this PR and is not evidence of a defect in the change. Nothing here should be read as no-mistakes-verified; the evidence below is what was actually run.Test evidence
Run on this branch at base
aef7a6d(current fork trunk):tests/fm-fleet-snapshot-view.test.sh- 20 assertions, exit 0tests/fm-bearings-snapshot.test.sh- 41 assertions, exit 0tests/fm-secondmate-safety.test.sh- 70 assertions, exit 0shellcheck --norc --external-sourceson both changed scripts - clean at the pinned 0.11.0Negative controls, run against the unfixed code before any change, since this defect is precisely a false success:
Argument list too long, exit 1["small-task"]where two tasks existed, from a snapshot that exited 0The pre-fix code was also confirmed to fail against the real 141848-byte, 126-record backlog; the fixed code renders it at exit 0. Both oversized fixtures are generated programmatically and assert their own size exceeds the cap, so neither can go quietly vacuous.
Disclosed pre-existing failure:
tests/fm-decision-hold-lifecycle.test.shfails locally withfm-decision-hold: compatible tasks-axi is requiredagainst installedtasks-axi0.2.3. This was confirmed to fail identically on unmodified HEAD via a cleangit archivetree, so it is an environment version floor and is not caused by this change.Merge
Do not merge. Raised for review only.