Skip to content

fix(bin): route Bearings candidate-PR rows through a file instead of jq argv - #5985

Open
karotkriss wants to merge 2 commits into
kunchenguid:mainfrom
karotkriss:fm/fm-up-3056-bearings-argv
Open

karotkriss wants to merge 2 commits into
kunchenguid:mainfrom
karotkriss:fm/fm-up-3056-bearings-argv

Conversation

@karotkriss

@karotkriss karotkriss commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Intent

Fixes #3056

Bearings snapshot dies with "Argument list too long" once there are enough candidate PR rows.
bin/fm-bearings-snapshot.sh accumulates candidate-PR rows by passing the growing JSON array as a jq --argjson argument, which exceeds the kernel's single-argument limit on large repositories, so the snapshot fails instead of projecting every row.
The rows should travel through a temporary file instead of argv so projection completes regardless of size.
This replaces the earlier pull request #4146, re-applied fresh on current main.

What Changed

  • bin/fm-bearings-snapshot.sh no longer accumulates candidate-PR rows in a growing JSON array passed via jq --argjson; each repo's rows are now appended to a mktemp transport file (cleaned up on EXIT) and read back with --slurpfile, so projection no longer trips the kernel's ~128 KiB per-argument exec cap on large fleets. The final jq program flattens the per-repo batches ($candidate_pr_batches | add // []) into $candidate_prs.
  • Added tests/fm-bearings-snapshot.test.sh coverage (test_pr_rows_above_arg_limit_still_project) with a FAKE_GH_HUGE fixture that emits 500 padded PRs per repo, asserting all 1000 rows project and the serialized set exceeds 128 KiB.
  • Bumped the CI Bearings test-count assertion in .github/workflows/ci.yml from 60 to 61 for the new test.

Risk Assessment

✅ Low: A well-bounded, root-cause fix that moves accumulated PR rows off jq argv onto a temp-file --slurpfile transport (mirroring the existing tasks_file pattern), with correct empty/edge handling, preserved ordering and counts, and a behavioral regression test.

Testing

Drove the fm-bearings-snapshot.sh CLI end-to-end through its behavior harness with a real fixture fleet home and a fake gh emitting 500 padded PRs per repo across 2 repos (1000 rows, the single-repo slice alone >131072 bytes, past the 128 KiB per-argv cap). On the base script this reproduces the exact reported failure (jq Argument list too long, projection failed, exit 1); on the target script the snapshot completes and projects all 1000 candidate PRs via --slurpfile. The full bearings suite passes at 61 ok / 0 fail, matching the CI count bump. This is a shell CLI with no visual surface, so evidence is the CLI transcript rather than a screenshot.

  • Live validation: ✅ go - 3 of 3 scenarios driven live against the product
Scenario Result Live Evidence
Snapshot projects every candidate PR row when the accumulated set exceeds the 128 KiB per-argv limit (1000 rows across 2 repos) ✅ pass live test_pr_rows_above_arg_limit_still_project driven against target bin/fm-bearings-snapshot.sh: ok - candidate-PR rows above the per-argument limit still project completely; JSON asserts .candidate_pr…
Regression: base script dies with 'Argument list too long' on the same oversized PR set (proves fix addresses the reported bug) ✅ pass live Same test run against base fa48367 bin/fm-bearings-snapshot.sh emits jq: Argument list too long (line 329) and fm-bearings-snapshot: projection failed, exit 1; captured in bearings-argv-regression…
Full bearings component suite stays green after the change and the CI test-count check is consistent ✅ pass live bin/bash tests/fm-bearings-snapshot.test.sh -> 61 ok, 0 not ok, exit 0, matching the ci.yml bump from 60 to 61
Evidence: Bearings argv regression: before/after CLI transcript

Source: Bearings argv regression: before/after CLI transcript

Bearings candidate-PR rows off argv (issue #3056) — live regression proof
==========================================================================

Scenario driven: --include-prs snapshot across 2 repos, fake gh returns 500
padded PRs/repo (1000 rows, the acme/repo-1 slice alone > 131072 bytes), so
the accumulated candidate-PR set exceeds the kernel MAX_ARG_STRLEN (128 KiB)
per jq argv argument. Test harness: tests/fm-bearings-snapshot.test.sh
(test_pr_rows_above_arg_limit_still_project), driving the real
bin/fm-bearings-snapshot.sh against a disposable fixture home.

BEFORE (base fa48367 bin/fm-bearings-snapshot.sh — jq --argjson argv):
  bin/fm-bearings-snapshot.sh: line 329: jq: Argument list too long
  bin/fm-bearings-snapshot.sh: line 329: jq: Argument list too long
  jq: invalid JSON text passed to --argjson
  fm-bearings-snapshot: projection failed
  not ok - projection failed on PR rows above the per-argument limit
  ===exit=1

AFTER (target ba5527d — file transport + --slurpfile):
  ok - candidate-PR rows above the per-argument limit still project completely

Assertions the passing run verified against the live JSON snapshot:
  .schema == "fm-bearings.v1"
  (.candidate_prs | length) == 1000          # every row projected, none dropped
  .prs matches "checked (2 repos, 1000 open)"
  acme/repo-1 slice serialized length > 131072  # well past the 128 KiB argv cap

Full component suite (bin/bash tests/fm-bearings-snapshot.test.sh):
  ok count: 61   not ok: 0   exit 0   (matches CI Bearings count bump to 61)
Evidence: Full bearings suite ok count
ok count: 61 not ok: 0 exit 0

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.

  • Live validation: ✅ go - 3 of 3 scenarios driven live against the product
Scenario Result Live Evidence
Snapshot projects every candidate PR row when the accumulated set exceeds the 128 KiB per-argv limit (1000 rows across 2 repos) ✅ pass live test_pr_rows_above_arg_limit_still_project driven against target bin/fm-bearings-snapshot.sh: ok - candidate-PR rows above the per-argument limit still project completely; JSON asserts .candidate_pr…
Regression: base script dies with 'Argument list too long' on the same oversized PR set (proves fix addresses the reported bug) ✅ pass live Same test run against base fa48367 bin/fm-bearings-snapshot.sh emits jq: Argument list too long (line 329) and fm-bearings-snapshot: projection failed, exit 1; captured in bearings-argv-regression…
Full bearings component suite stays green after the change and the CI test-count check is consistent ✅ pass live bin/bash tests/fm-bearings-snapshot.test.sh -> 61 ok, 0 not ok, exit 0, matching the ci.yml bump from 60 to 61
  • bin/bash tests/fm-bearings-snapshot.test.sh (full bearings component suite: 61 ok, 0 not ok, exit 0)
  • New regression test_pr_rows_above_arg_limit_still_project driven in isolation against target bin/fm-bearings-snapshot.sh -> ok
  • Same regression test driven against base commit fa48367 bin/fm-bearings-snapshot.sh -> reproduces jq: Argument list too long at line 329 and fm-bearings-snapshot: projection failed, exit 1
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…port

bin/fm-bearings-snapshot.sh accumulated candidate-PR rows across repos by
passing the growing JSON array through jq --argjson, and passed the final
accumulated set the same way into the projection call. Each jq argv
argument is capped by the kernel's MAX_ARG_STRLEN (128 KiB), so a large
fleet's accumulated PR rows exceeded the limit and the snapshot failed
instead of completing.

Route the rows through a temporary file instead: each fetched repo's PR
array is appended to a mktemp transport file (removed on EXIT) and the
final projection reads it back with --slurpfile, combining the batches
with add // []. Bumped the CI Bearings test-count check for the added
regression test.
@greptile-apps

greptile-apps Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Changes how the bearings snapshot tool handles pull request data.

The PR appears safe to merge; no outstanding findings remain.

Reviews (3) · Last reviewed commit: "no-mistakes(ci): Fixed two temp-file lif..."

Comment thread bin/fm-bearings-snapshot.sh Outdated
Comment thread bin/fm-bearings-snapshot.sh
…s-snapshot.sh flagged by Greptile (both user-selected to fix). ci-1 (P1): the PR_ROWS_FILE mktemp ran unconditionally, so a broken TMPDIR broke even the default snapshot that needs no PR data — moved the mktemp into the --include-prs branch and made the projection's --slurpfile read ${PR_ROWS_FILE:-/dev/null}, yielding an empty batch on the default path just as an empty file did. ci-2 (P2): tasks_file was cleaned only by a post-loop rm that a mid-loop exit skipped, while the EXIT trap covered only PR_ROWS_FILE — both temp files now sit under one EXIT trap (rm -f both), initialized empty up front for set -u safety, and the redundant post-loop rm was removed. Both files exist only in the --include-prs path, so the trap is the single shared cleanup boundary with no sibling site left reachable. Verified: bash -n clean, shellcheck clean, and the full tests/fm-bearings-snapshot.test.sh suite passes 30/30 (including argv-transport and default-path cases)

@kunchenguid kunchenguid left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Speaking as Kun's firstmate: tip reviewed vs main — restore Bearings candidate-PR rows off jq argv onto file transport; approving unattributed fork changes.

Copy link
Copy Markdown
Owner

Speaking as Kun's firstmate: whole thread + tip vs main fa483673 reviewed. First stamp on this tip.

HEAD 1ab6e9f64b938055bf6c2953a49a71c7360afa08. Author karotkriss not blocked. Attestation MATCH. Latest tip CI 36397838952 SUCCESS (all jobs); NM 36397838947/36397818727 SUCCESS. gh pr checks green. MergeState BLOCKED (stale Behavior portable serial 5 FAILURE still attached to SHA from older run 36393939886 — failed jobs re-queued this pass; plus ruleset). Maintainer APPROVE posted for unattributed fork changes.

Closes #3056: body Fixes #3056 — accurate (Bearings candidate-PR rows trip ARG_MAX via jq --argjson).

Contract-class: restore (own tip-vs-main; FM-LEARN-CLAIMS). Concrete existing Bearings projection path was specified to project every candidate-PR row; tip moves accumulated rows onto mktemp + --slurpfile (mirrors tasks_file pattern), bumps CI Bearings count 60→61, adds regression. No new default-on observer/wake/Bearings surface — transport fix only.

VISION.md (each rule)

  1. One captain, one interface — aligns (Bearings stays available under load).
  2. Authority explicit — aligns (no consent widening).
  3. Scripts own mechanics — aligns (file transport is deterministic).
  4. Restart non-event — aligns (EXIT cleanup of temps).
  5. Delegation with a spine — aligns (no task-contract change).
  6. Fleet outlives vendor — aligns (gh enrichment stays optional).
  7. Scope — aligns (command-layer snapshot hygiene).
    Align: peace of mind / refuse silent fleet-state loss. Resist: none material.

Hold — workflow scope: tip touches .github/workflows/ci.yml (count bump). OAuth token lacks workflow scope; gh pr merge --squash / --admin refused (refusing to allow an OAuth App to create or update workflow ... without workflow scope). No auto-merge from this agent. Otherwise restore + MATCH + latest CI/NM green → Firstmate flag yes (captain merge with a workflow-scoped token once rollup is clean).

Security tip: none.

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.

fm-bearings-snapshot dies with 'Argument list too long' once the backlog exceeds jq's single-argument limit

2 participants