Skip to content

fix(bin): keep fleet-sized snapshot documents out of jq's argv - #2777

Open
x45dev wants to merge 2 commits into
kunchenguid:mainfrom
x45dev:fm/fm-snapshot-argv-overflow
Open

fix(bin): keep fleet-sized snapshot documents out of jq's argv#2777
x45dev wants to merge 2 commits into
kunchenguid:mainfrom
x45dev:fm/fm-snapshot-argv-overflow

Conversation

@x45dev

@x45dev x45dev commented Aug 22, 2026

Copy link
Copy Markdown

Intent

Fix bin/fm-bearings-snapshot.sh failing outright with "jq: Argument list too long" / "fm-fleet-snapshot: main inventory summary failed".

Root cause: bin/fm-fleet-snapshot.sh's main_inventory_json() passed whole JSON documents to jq on the command line via --argjson backlog "$1" and --argjson tasks "$2". With 67 backlog records the serialized document exceeds the kernel's argv limit, so execve refuses before jq ever runs. It is a hard size ceiling, not a jq bug, and it only worsens as the backlog grows.

Required fix: stop passing JSON documents through argv. Feed them to jq through files or stdin - --slurpfile/--rawfile against a temp file, or piping one document in and reading the other with --slurpfile, whichever reads more naturally in the surrounding code. Keep the function's signature and its output contract byte-identical so every caller is unaffected.

Required audit: audit the rest of the file in the same change. main_inventory_json is where it surfaced, but any other --argjson carrying a document that grows with the fleet has the same latent ceiling. Fix every instance found; leave --argjson alone where the value is genuinely small and bounded (a flag, a count, a single id).

Required test: ship a test that fails without this change - construct a backlog document large enough to exceed getconf ARG_MAX on the host, run the snapshot, and assert it produces valid output rather than erroring. Follow whatever test convention this repo already uses; do not invent a new harness.

Required verification: run bin/fm-bearings-snapshot.sh against the real home and confirm it returns a complete snapshot.

Decisions and tradeoffs made while doing the work, which a reviewer reading only the diff would not know:

  • Chose process substitution with --slurpfile (--slurpfile <name> <(printf '%s' "$doc"), read back as ($<name>[0]) as $<binding>) over staging a temp file. Deliberate: nothing is staged on disk, so no signal trap is needed, and the bounded, routinely killed cross-home reads elsewhere in this script still die promptly and leave nothing behind. The binding form was chosen specifically so every jq filter body stays identical to the --argjson form it replaced, keeping the output contract byte-identical.
  • Converted every document that grows with the fleet: main_inventory_json, secondmate_home_summary_json, parent_evidence_reconciliation_json, secondmate_current_json (including its per-record accumulator, which previously rebuilt the whole array through argv on every iteration), secondmate_landed_from_current_json, and the top-level snapshot assembly.
  • Deliberately left --argjson in place where the value is bounded by something other than fleet size: flags, counts, a single id, one task's own state or paths, and surfaces an FM_SNAPSHOT_* cap already truncates. This is the brief's explicit instruction, not an oversight. Per-task open_decisions is bounded by that one task's own distinct open keys, not by fleet size, so it stays on --argjson too.
  • Added a require_json_docs guard because the failure modes differ: --argjson rejected an empty document outright, but through a pipe an empty document slurps to [] and binds null, which would silently reshape the output instead of failing. Keeping that a hard failure is intentional.
  • The regression test sizes its fixture from the ceiling the host actually enforces (probing for the smallest refused single-argument size) rather than a hardcoded guess, and then asserts the resulting document really did clear that ceiling - so the test is neither needlessly slow on this host nor silently vacuous on a platform with a different cap. It covers both the canonical --json mode and the --secondmate-home-summary mode, which carries the same two documents into a different jq call.
  • Also added a test for the newly documented "stages nothing on disk" contract (a run under a private TMPDIR must leave it empty). This replaced an earlier test of mine that asserted cleanup of a scratch directory - that test was left over from a temp-file design I abandoned for the pipe design, so it named a mechanism that no longer exists and could never fail.

Constraints: this is firstmate's own shared tracked material, so firstmate-coding-guidelines applies - bin/*.sh must pass shellcheck and bin/fm-lint.sh, tests stay colocated in tests/ extending the existing tests/fm-fleet-snapshot-view.test.sh rather than adding a runner, one sentence per line in tracked markdown, plain dash never an em dash, and no agent co-author on the commit.

Verified before this run: the new test fails without the fix with the exact reported error ("jq: Argument list too long", 258 records over this host's 131072-byte ceiling); the full tests/fm-fleet-snapshot-view.test.sh suite is 17/17 green with it; bin/fm-lint.sh passes (ShellCheck 0.11.0, actionlint 1.7.12); and bin/fm-bearings-snapshot.sh against the real home returns rc=0 with a complete snapshot (64 backlog records, 8 tasks, 2 secondmates, main_inventory.valid true).

Known and deliberately out of scope: tests/fm-bearings-snapshot.test.sh fails on this machine under load, with its bounded cross-home reads reporting "structured home snapshot timed out" at a load average around 19. That failure reproduces at HEAD without this change and the failing test moves between runs, so it is a pre-existing load-sensitive flake, not a regression from this work, and it is deliberately not fixed here.

What Changed

  • In bin/fm-fleet-snapshot.sh, replaced --argjson with --slurpfile <name> <(printf '%s' "$doc") (bound back via ($<name>[0]) as $<binding>) for every JSON document whose size grows with the fleet, so large documents reach jq through a pipe instead of argv and stop tripping the kernel's per-argument execve limit: main_inventory_json, secondmate_home_summary_json, parent_evidence_reconciliation_json, secondmate_current_json (including its per-record accumulator, previously rebuilt through argv on every loop iteration), secondmate_landed_from_current_json, and the top-level snapshot assembly.
  • Left --argjson in place for values bounded independently of fleet size (flags, counts, a single id, one task's own state, an already-truncated FM_SNAPSHOT_* surface).
  • Added a require_json_docs guard so an empty document still hard-fails as it did under --argjson, instead of silently slurping to []/null and reshaping output.
  • Added tests/fm-fleet-snapshot-view.test.sh coverage: a regression test sized from the host's actual ARG_MAX ceiling for both --json and --secondmate-home-summary modes, plus a test asserting the snapshot stages nothing on disk under a private TMPDIR.

Risk Assessment

✅ Low: The change mechanically replaces --argjson with guarded --slurpfile/process-substitution at every site that carries a fleet-sized document (verified via grep that all --slurpfile call sites have a matching require_json_docs guard, and that all remaining --argjson uses carry genuinely bounded scalars/single-record values, matching the stated audit scope), preserves each jq filter body unchanged apart from the added binding preamble, adds a require_json_docs guard with correct empty-vs-null semantics, and ships a regression test that sizes its fixture from the host's actual argv ceiling and asserts both output validity and that the fixture genuinely exceeds the ceiling; no risky, ambiguous, or unverified behavior was found.

Testing

All 17 tests in tests/fm-fleet-snapshot-view.test.sh pass against the fix, the two new regression tests were confirmed to fail with the exact pre-fix error against the base commit's script, and manual end-to-end runs of both bin/fm-fleet-snapshot.sh --json and its bin/fm-bearings-snapshot.sh wrapper against a 300-record synthetic backlog completed successfully (rc=0, valid output) - the author's real firstmate home referenced in the intent's verification note is not reachable from this isolated test worktree, so a synthetic large-backlog home was substituted to demonstrate the same end-to-end path.

Evidence: Pre-fix regression test output (confirms failure without the change)
/tmp/fm-base-check/bin/fm-fleet-snapshot.sh: line 635: /home/dev/.local/share/mise/installs/jq/1.8.2/jq: Argument list too long
fm-fleet-snapshot: main inventory summary failed
not ok - snapshot must survive a backlog document larger than one argv string (258 records)
Evidence: Manual fm-bearings-snapshot.sh run against a small synthetic home
schema: fm-bearings.v1
home: tmp/fm-manual-home
generated: "2026-08-22T04:00:32Z"
prs: "not_requested (run: /bearings include PRs)"
in_flight: []
secondmates: []
decisions_open: []
landed[1]{id,what,artifact,owner}:
  done-task-1,Done Task One,"-",(main)
gates[2]{id,title,blocked_by,reason,owner}:
  queued-task-1,Queued Task One,"-","-",(main)
  queued-task-2,Queued Task Two,"-","-",(main)
reports: []
recorded_prs: []
omitted[7]{surface,reveal}:
  backlog item bodies,"--fields bodies"
  task paths,"--fields paths"
  watch/steer actions,"--fields actions"
  healthy endpoint detail,"--fields endpoints"
  full scout-report inventory,"--all-reports"
  superseded or prose-deferred queued items,"--all-queued"
  live PR discovery + checks,"--include-prs"
Evidence: Manual fm-bearings-snapshot.sh run against a 300-record oversize backlog
schema: fm-bearings.v1
home: tmp/fm-manual-home-big
generated: "2026-08-22T04:00:48Z"
prs: "not_requested (run: /bearings include PRs)"
in_flight: []
secondmates: []
decisions_open: []
landed: []
gates[20]{id,title,blocked_by,reason,owner}:
  argv-task-00001,Queued task 00001 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00002,Queued task 00002 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00003,Queued task 00003 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00004,Queued task 00004 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00005,Queued task 00005 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00006,Queued task 00006 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00007,Queued task 00007 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00008,Queued task 00008 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00009,Queued task 00009 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00010,Queued task 00010 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00011,Queued task 00011 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00012,Queued task 00012 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00013,Queued task 00013 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00014,Queued task 00014 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00015,Queued task 00015 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00016,Queued task 00016 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00017,Queued task 00017 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00018,Queued task 00018 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00019,Queued task 00019 with a title long enough to give every rec…,"-","-",(main)
  argv-task-00020,Queued task 00020 with a title long enough to give every rec…,"-","-",(main)
reports: []
recorded_prs: []
omitted[8]{surface,reveal}:
  backlog item bodies,"--fields bodies"
  task paths,"--fields paths"
  watch/steer actions,"--fields actions"
  healthy endpoint detail,"--fields endpoints"
  full scout-report inventory,"--all-reports"
  superseded or prose-deferred queued items,"--all-queued"
  gates showing 20 of 300,"--all-queued"
  live PR discovery + checks,"--include-prs"
Evidence: fm-fleet-snapshot.sh --json output over a 300-record oversize backlog
{
  "schema": "fm-fleet-snapshot.v1",
  "generated": "2026-08-22T04:00:40Z",
  "fm_home": "/tmp/fm-manual-home-big",
  "roots": {
    "fm_root": "/home/dev/.no-mistakes/worktrees/5480956096ee/01M0KSNFGXYTFWK5WPCYR15JFJ",
    "state": "/tmp/fm-manual-home-big/state",
    "data": "/tmp/fm-manual-home-big/data",
    "config": "/tmp/fm-manual-home-big/config",
    "projects": "/tmp/fm-manual-home-big/projects"
  },
  "backlog": {
    "path": "/tmp/fm-manual-home-big/data/backlog.md",
    "present": true,
    "records": [
      {
        "order": 1,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00001",
        "checked": false,
        "title": "Queued task 00001 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00001 - Queued task 00001 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 2,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00002",
        "checked": false,
        "title": "Queued task 00002 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00002 - Queued task 00002 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 3,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00003",
        "checked": false,
        "title": "Queued task 00003 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00003 - Queued task 00003 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 4,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00004",
        "checked": false,
        "title": "Queued task 00004 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00004 - Queued task 00004 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 5,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00005",
        "checked": false,
        "title": "Queued task 00005 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00005 - Queued task 00005 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 6,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00006",
        "checked": false,
        "title": "Queued task 00006 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00006 - Queued task 00006 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 7,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00007",
        "checked": false,
        "title": "Queued task 00007 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
     

... [341884 bytes truncated] ...

d": "argv-task-00295",
        "checked": false,
        "title": "Queued task 00295 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00295 - Queued task 00295 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 296,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00296",
        "checked": false,
        "title": "Queued task 00296 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00296 - Queued task 00296 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 297,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00297",
        "checked": false,
        "title": "Queued task 00297 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00297 - Queued task 00297 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 298,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00298",
        "checked": false,
        "title": "Queued task 00298 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00298 - Queued task 00298 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 299,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00299",
        "checked": false,
        "title": "Queued task 00299 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00299 - Queued task 00299 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      },
      {
        "order": 300,
        "state": "queued",
        "structured": true,
        "id": "argv-task-00300",
        "checked": false,
        "title": "Queued task 00300 with a title long enough to give every record real weight",
        "repo": "alpha",
        "kind": "ship",
        "priority": null,
        "hold_reason": null,
        "hold_kind": null,
        "hold_until": null,
        "blocked_by": null,
        "blocked_by_ids": [],
        "blocked_reason": null,
        "since": "2026-07-08",
        "merged": null,
        "reported": null,
        "done": null,
        "completion": {
          "verb": null,
          "date": null
        },
        "links": [],
        "pr_url": null,
        "report_path": null,
        "local_note": null,
        "raw": "- [ ] argv-task-00300 - Queued task 00300 with a title long enough to give every record real weight (repo: alpha) (kind: ship) (since 2026-07-08)",
        "body_lines": [],
        "body_excerpt": null,
        "unresolved_blocker_ids": [],
        "current_role": "queued",
        "requires_child_metadata": false,
        "captain_actionable": false,
        "deferred_marker": false
      }
    ]
  },
  "tasks": [],
  "main_inventory": {
    "valid": true,
    "reason": null,
    "orphan_in_flight": [],
    "unstructured_current_count": 0
  },
  "scout_reports": [],
  "secondmate_current": {
    "registry": {
      "present": false,
      "available": true,
      "complete": true,
      "reason": null,
      "provenance": "registered-table",
      "path": "/tmp/fm-manual-home-big/data/secondmates.md",
      "freshness": {
        "status": "fresh",
        "observed_at": "2026-08-22T04:00:40Z"
      },
      "records": [],
      "input_truncated": false,
      "records_truncated": false,
      "reasons": [],
      "lines_in_window": 0,
      "records_in_window": 0
    },
    "records": [],
    "total_registered": 0,
    "total": 0,
    "shown": 0,
    "truncated": 0
  },
  "secondmate_landed": {
    "records": [],
    "truncated": [],
    "unreadable": [],
    "partial": []
  },
  "secondmate_guidance": {
    "note": "For kind=secondmate, bearings selects validated structured state from that registered home; parent events and bounded terminal evidence are fallback-only supplements and never current-state authority."
  }
}

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-fleet-snapshot-view.test.sh on the fix (db3ab48) - all 17 tests pass, including test_backlog_larger_than_one_argv_string (258 records over a 131072-byte ceiling) and test_snapshot_stages_nothing_on_disk
  • Same two new tests run in isolation against the pre-fix bin/fm-fleet-snapshot.sh (base dc0172c) via a scratch copy - fails with the exact reported error: 'jq: Argument list too long' / 'fm-fleet-snapshot: main inventory summary failed'
  • Manual end-to-end run: FM_HOME=&lt;synthetic-home&gt; bin/fm-fleet-snapshot.sh --json against a 300-record queued backlog - rc=0, valid JSON, backlog.records length 300, main_inventory.valid true
  • Manual end-to-end run: FM_HOME=&lt;synthetic-home&gt; bin/fm-bearings-snapshot.sh against the same 300-record backlog - rc=0, complete TOON snapshot with 20-row gates table shown (bounded by default fields)
  • Manual smoke run: FM_HOME=&lt;small-synthetic-home&gt; bin/fm-bearings-snapshot.sh against a 3-record backlog (queued/done mix) - rc=0, complete snapshot
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

The fleet snapshot passed whole JSON documents to jq on the command line
with --argjson. execve caps a single argument string far below the total
ARG_MAX (MAX_ARG_STRLEN is 128 KiB on Linux), so once a home's backlog
document crossed that ceiling every snapshot aborted with "Argument list
too long" before jq ran. It is a hard size ceiling, not a jq bug, and it
only worsens as a home grows.

Every document that grows with the fleet - the backlog, the task
inventory, a home summary, the aggregated secondmate records and their
accumulator - now reaches jq through a pipe via
`--slurpfile <name> <(printf '%s' "$doc")`, read back as
`($<name>[0]) as $<binding>` so each filter body is unchanged and every
caller's output contract stays byte-identical. Nothing is staged on
disk, so no signal trap is needed and the bounded, routinely killed
cross-home reads still die promptly leaving nothing behind. An empty
document keeps the hard failure --argjson raised, since through a pipe
it would otherwise bind null and silently reshape the output.

--argjson stays where the value is bounded by something other than fleet
size: a flag, a count, a single id, one task's own state or paths, or a
surface an FM_SNAPSHOT_* cap already truncates.

Tests size their fixture from the ceiling the host actually enforces and
assert the document really cleared it, so the regression is neither slow
here nor vacuous elsewhere; both the canonical and home-summary modes are
covered, plus the "stages nothing on disk" contract.
@greptile-apps

greptile-apps Bot commented Aug 22, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Reviews (2): Last reviewed commit: "no-mistakes: apply CI fixes" | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant