Skip to content

fix: prevent fleet snapshot argv overflows - #1884

Open
Vladykart wants to merge 3 commits into
kunchenguid:mainfrom
Vladykart:fm/fm-fleet-snapshot-argv-fix-p1
Open

fix: prevent fleet snapshot argv overflows#1884
Vladykart wants to merge 3 commits into
kunchenguid:mainfrom
Vladykart:fm/fm-fleet-snapshot-argv-fix-p1

Conversation

@Vladykart

Copy link
Copy Markdown

Intent

Repair Firstmate's fleet snapshot and operator-facing bearings path so large real fleets cannot fail with /usr/bin/jq: Argument list too long, preserving the supplied evidence /root/kun-agent-workspace/bin/fm-fleet-snapshot.sh: line 608: /usr/bin/jq: Argument list too long followed by fm-fleet-snapshot: main inventory summary failed. Establish the earliest failing public path against a proven small fleet and add a deterministic end-to-end reproduction independent of private backlog, clones, or live worker records that separates source input size, shell expansion, the jq exec boundary, and the visible interface result. Make the smallest shared data-transport correction by streaming or file-binding unbounded JSON aggregates into jq rather than argv, while retaining bounded scalar options and reusing one owner for main-home and second-mate summaries. Preserve canonical schema, sorting, null behavior, all required records, existing diagnostics, read-only semantics, per-home isolation, remote second-mate boundaries, no terminal/chat scraping, and bounded output fields; never solve the failure by truncating required records. Safely reject empty, malformed, multi-value, missing, or failed producer output, handle interruption and cleanup without unsafe temporary state, and use private collision-safe non-symlink-following temporary state only if stdin or owned files cannot avoid it. Add executable public-interface regressions for empty/small semantic equivalence, oversized fleet snapshot and bearings output beyond practical argv capacity, and malformed/failed input controls, asserting semantic JSON equivalence and absence of argv failure rather than implementation bytes. Run focused snapshot and bearings tests, the full applicable test runner, the repository lint owner, and documentation audience checks where applicable; safely rerun the formerly failing path with bounded non-private evidence. Preserve and report verified pre-existing suite failures. Do not stop, restart, or update watcher/daemon processes, change backlog semantics, contact project hardware/services, install or update tools, or read project-private data beyond existing snapshot authorization. Validate committed head 90b8311 through every synchronous no-mistakes gate, push and open a PR with current green checks, do not merge, and stop only for a genuine decision or blocker.

What Changed

  • Stream serialized fleet snapshot aggregates into jq through validated stdin framing instead of command-line arguments, preventing oversized fleets from exceeding argv limits.
  • Preserve fleet snapshot, second-mate summary, and bounded bearings semantics while rejecting malformed, multi-value, missing, or failed JSON producer output.
  • Add public-interface regressions covering empty and small semantic equivalence, oversized fleet and bearings output, and producer failure controls.

Risk Assessment

✅ Low: The change is well-bounded and consistently replaces unbounded jq argv bindings with validated stdin transport while preserving schemas, diagnostics, ordering, bounds, and public snapshot/bearings behavior.

Testing

Validated the committed head through focused snapshot and bearings checks, the changed-test runner, and the complete 130-script test runner; direct CLI evidence confirms semantic equivalence, safe producer rejection, and oversized snapshot/bearings success without argv failure, while the full suite preserved 22 unrelated existing/environment-sensitive failures and 16 expected gate skips.

Evidence: Oversized fleet public-interface evidence
ok - empty fleet snapshot, summary, and view use explicit absence markers
ok - small snapshot and secondmate summary preserve canonical JSON semantics
ok - oversized snapshot, secondmate summary, and bearings avoid argv while preserving records
ok - snapshot interfaces reject malformed, extra, and failed JSON producers safely
ok - fixture snapshot covers task rows, backlog rows, pointers, and stable ordering
ok - main_inventory discloses orphan/unstructured and clears when inventory is consistent
ok - backlog normalization preserves strict roles and resolves every blocker compatibly
ok - snapshot event hints follow reconciled current state
ok - durable fold keeps an open decision past a later unrelated event
ok - a live secondmate endpoint preserves unrelated open decisions
ok - durable captain-held transfer closes the duplicate live status decision
ok - durable fold clears a decision only on a keyed resolution
ok - a completed scout's stale decision surfaces as a report pointer, not pending
ok - a scout still parked at a decision stays pending (terminal clear does not over-fire)
ok - snapshot includes durable scout reports after teardown
ok - snapshot parses tasks-axi rows and respects operational overrides
ok - fleet view renders the snapshot without secondmate peek guidance
ok - fleet view renders secondmate agent liveness
Evidence: Focused bearings transcript
ok - Domain Alpha structured state overrides a stale parent Phase 7 event
ok - GNU stat file reads select -c without BSD filesystem-report pollution
ok - parent activity evidence is bounded and disclosed
ok - Bearings excludes a status-only child decision
ok - a structured child captain hold reaches Captain's Call
not ok - bad home outcomes revived stale work or lacked provenance: {
  "schema": "fm-bearings.v1",
  "home": "fm-bearings.cAgRSN/bad-homes",
  "generated": "2026-07-11T18:00:00Z",
  "prs": "not_requested (run: /bearings include PRs)",
  "in_flight": [],
  "secondmates": [
    {
      "id": "invalid",
      "state": "unknown",
      "doing": "invalid home: marked for secondmate someone-else, expected invalid",
      "provenance": "parent-event-fallback",
      "freshness": "historical-event",
      "age_seconds": 0,
      "contradiction": false,
      "reason": "invalid home: marked for secondmate someone-else, expected invalid"
    },
    {
      "id": "malformed",
      "state": "unknown",
      "doing": "structured home state invalid: unstructured current backlog row",
      "provenance": "parent-event-fallback",
      "freshness": "historical-event",
      "age_seconds": 0,
      "contradiction": false,
      "reason": "structured home state invalid: unstructured current backlog row"
    },
    {
      "id": "missing",
      "state": "unknown",
      "doing": "invalid home: not a directory",
      "provenance": "unknown",
      "freshness": "unknown",
      "age_seconds": null,
      "contradiction": false,
      "reason": "invalid home: not a directory"
    },
    {
      "id": "timedout",
      "state": "unknown",
      "doing": "structured home snapshot timed out",
      "provenance": "parent-event-fallback",
      "freshness": "historical-event",
      "age_seconds": 0,
      "contradiction": false,
      "reason": "structured home snapshot timed out"
    },
    {
      "id": "unreadable",
      "state": "no_active_work",
      "doing": "No active child work",
      "provenance": "structured-home",
      "freshness": "fresh",
      "age_seconds": 0,
      "contradiction": true,
      "reason": "-"
    }
  ],
  "decisions_open": [],
  "landed": [],
  "gates": [],
  "reports": [],
  "recorded_prs": [],
  "unhealthy_endpoints": [
    {
      "id": "invalid",
      "backend": "tmux",
      "target": "firstmate:fm-invalid",
      "exists": true,
      "agent": "dead"
    },
    {
      "id": "malformed",
      "backend": "tmux",
      "target": "firstmate:fm-malformed",
      "exists": true,
      "agent": "dead"
    },
    {
      "id": "timedout",
      "backend": "tmux",
      "target": "firstmate:fm-timedout",
      "exists": true,
      "agent": "dead"
    },
    {
      "id": "unreadable",
      "backend": "tmux",
      "target": "firstmate:fm-unreadable",
      "exists": true,
      "agent": "dead"
    }
  ],
  "omitted": [
    {
      "surface": "backlog item bodies",
      "reveal": "--fields bodies"
    },
    {
      "surface": "task paths",
      "reveal": "--fields paths"
    },
    {
      "surface": "watch/steer actions",
      "reveal": "--fields actions"
    },
    {
      "surface": "healthy endpoint detail",
      "reveal": "--fields endpoints"
    },
    {
      "surface": "full scout-report inventory",
      "reveal": "--all-reports"
    },
    {
      "surface": "superseded queued items",
      "reveal": "--all-queued"
    },
    {
      "surface": "secondmate home(s) with unreadable backlog: 4",
      "reveal": "inspect the listed secondmate home backlogs"
    },
    {
      "surface": "live PR discovery + checks",
      "reveal": "--include-prs"
    }
  ]
}
Evidence: Changed-test runner transcript
FM_TEST_BEGIN 2026-08-07T09:17:25Z tests/fm-bearings-snapshot.test.sh family=snapshot-bearings expected_gate_skip=optional-binary
ok - Domain Alpha structured state overrides a stale parent Phase 7 event
ok - GNU stat file reads select -c without BSD filesystem-report pollution
ok - parent activity evidence is bounded and disclosed
ok - Bearings excludes a status-only child decision
ok - a structured child captain hold reaches Captain's Call
not ok - bad home outcomes revived stale work or lacked provenance: {
  "schema": "fm-bearings.v1",
  "home": "fm-bearings.Gr4MVp/bad-homes",
  "generated": "2026-07-11T18:00:00Z",
  "prs": "not_requested (run: /bearings include PRs)",
  "in_flight": [],
  "secondmates": [
    {
      "id": "invalid",
      "state": "unknown",
      "doing": "invalid home: marked for secondmate someone-else, expected invalid",
      "provenance": "parent-event-fallback",
      "freshness": "historical-event",
      "age_seconds": 0,
      "contradiction": false,
      "reason": "invalid home: marked for secondmate someone-else, expected invalid"
    },
    {
      "id": "malformed",
      "state": "unknown",
      "doing": "structured home state invalid: unstructured current backlog row",
      "provenance": "parent-event-fallback",
      "freshness": "historical-event",
      "age_seconds": 0,
      "contradiction": false,
      "reason": "structured home state invalid: unstructured current backlog row"
    },
    {
      "id": "missing",
      "state": "unknown",
      "doing": "invalid home: not a directory",
      "provenance": "unknown",
      "freshness": "unknown",
      "age_seconds": null,
      "contradiction": false,
      "reason": "invalid home: not a directory"
    },
    {
      "id": "timedout",
      "state": "unknown",
      "doing": "structured home snapshot timed out",
      "provenance": "parent-event-fallback",
      "freshness": "historical-event",
      "age_seconds": 0,
      "contradiction": false,
      "reason": "structured home snapshot timed out"
    },
    {
      "id": "unreadable",
      "state": "no_active_work",
      "doing": "No active child work",
      "provenance": "structured-home",
      "freshness": "fresh",
      "age_seconds": 0,
      "contradiction": true,
      "reason": "-"
    }
  ],
  "decisions_open": [],
  "landed": [],
  "gates": [],
  "reports": [],
  "recorded_prs": [],
  "unhealthy_endpoints": [
    {
      "id": "invalid",
      "backend": "tmux",
      "target": "firstmate:fm-invalid",
      "exists": true,
      "agent": "dead"
    },
    {
      "id": "malformed",
      "backend": "tmux",
      "target": "firstmate:fm-malformed",
      "exists": true,
      "agent": "dead"
    },
    {
      "id": "timedout",
      "backend": "tmux",
      "target": "firstmate:fm-timedout",
      "exists": true,
      "agent": "dead"
    },
    {
      "id": "unreadable",
      "backend": "tmux",
      "target": "firstmate:fm-unreadable",
      "exists": true,
      "agent": "dead"
    }
  ],
  "omitted": [
    {
      "surface": "backlog item bodies",
      "reveal": "--fields bodies"
    },
    {
      "surface": "task paths",
      "reveal": "--fields paths"
    },
    {
      "surface": "watch/steer actions",
      "reveal": "--fields actions"
    },
    {
      "surface": "healthy endpoint detail",
      "reveal": "--fields endpoints"
    },
    {
      "surface": "full scout-report inventory",
      "reveal": "--all-reports"
    },
    {
      "surface": "superseded queued items",
      "reveal": "--all-queued"
    },
    {
      "surface": "secondmate home(s) with unreadable backlog: 4",
      "reveal": "inspect the listed secondmate home backlogs"
    },
    {
      "surface": "live PR discovery + checks",
      "reveal": "--include-prs"
    }
  ]
}
FM_TEST_END 2026-08-07T09:17:39Z tests/fm-bearings-snapshot.test.sh exit=1 duration_ms=14300 gate_skip=false
FM_TEST_BEGIN 2026-08-07T09:17:39Z tests/fm-fleet-snapshot-view.test.sh family=snapshot-bearings expected_gate_skip=optional-binary
ok - empty fleet snapshot, summary, and view use explicit absence markers
ok - small snapshot and secondmate summary preserve canonical JSON semantics
ok - oversized snapshot, secondmate summary, and bearings avoid argv while preserving records
ok - snapshot interfaces reject malformed, extra, and failed JSON producers safely
ok - fixture snapshot covers task rows, backlog rows, pointers, and stable ordering
ok - main_inventory discloses orphan/unstructured and clears when inventory is consistent
ok - backlog normalization preserves strict roles and resolves every blocker compatibly
ok - snapshot event hints follow reconciled current state
ok - durable fold keeps an open decision past a later unrelated event
ok - a live secondmate endpoint preserves unrelated open decisions
ok - durable captain-held transfer closes the duplicate live status decision
ok - durable fold clears a decision only on a keyed resolution
ok - a completed scout's stale decision surfaces as a report pointer, not pending
ok - a scout still parked at a decision stays pending (terminal clear does not over-fire)
ok - snapshot includes durable scout reports after teardown
ok - snapshot parses tasks-axi rows and respects operational overrides
ok - fleet view renders the snapshot without secondmate peek guidance
ok - fleet view renders secondmate agent liveness
FM_TEST_END 2026-08-07T09:18:16Z tests/fm-fleet-snapshot-view.test.sh exit=0 duration_ms=37131 gate_skip=false
FM_TEST_SUMMARY total=2 failed=1 skipped_gate=0 duration_ms=51517
FM_TEST_SUMMARY_FAMILY family=snapshot-bearings count=2 duration_ms=51431 failed=1
FM_TEST_SLOWEST rank=1 script=tests/fm-fleet-snapshot-view.test.sh duration_ms=37131
FM_TEST_SLOWEST rank=2 script=tests/fm-bearings-snapshot.test.sh duration_ms=14300
Evidence: Full test-suite transcript
FM_TEST_BEGIN 2026-08-07T09:18:26Z tests/fm-afk-inject-e2e.test.sh family=afk expected_gate_skip=none
ok - Scenario A: partial input defers injection; digest arrives clean after idle
ok - Scenario B: swallowed Enter produces exactly one clean digest
ok - Scenario C: a normal captain status injects exactly one clean single-line sentinel digest
all e2e injection tests passed
FM_TEST_END 2026-08-07T09:19:03Z tests/fm-afk-inject-e2e.test.sh exit=0 duration_ms=36514 gate_skip=false
FM_TEST_BEGIN 2026-08-07T09:19:03Z tests/fm-afk-inject-herdr-e2e.test.sh family=real-herdr-gated expected_gate_skip=herdr
ok - real herdr Scenario A: partial input defers injection; digest arrives clean after idle
ok - real herdr Scenario B: swallowed Enter (via the herdr shim) produces exactly one clean digest
ok - real herdr Scenario C: a normal captain status injects exactly one clean single-line sentinel digest
ok - real herdr Scenario D: a persistently pending composer raises the max-defer wedge alarm, preserves the buffer, and never crashes the daemon
all real-herdr afk injection e2e tests passed
FM_TEST_END 2026-08-07T09:20:07Z tests/fm-afk-inject-herdr-e2e.test.sh exit=0 duration_ms=64126 gate_skip=false
FM_TEST_BEGIN 2026-08-07T09:20:07Z tests/fm-afk-launch.test.sh family=real-herdr-gated expected_gate_skip=herdr
ok - clear-stale: removes escalations buffer, sidecar, and wedge marker
ok - clear-stale: leaves the durable wake-queue intact (no pending work dropped)
ok - launcher paths: relative home and state ignore CDPATH before daemon command construction
ok - launcher paths: absolute symlink spellings are preserved
ok - launcher paths: unresolved relative FM_HOME fails loudly
ok - launcher paths: unresolved relative FM_STATE_OVERRIDE fails loudly
ok - refresh: daemon already alive - stale artifacts preserved (current session's buffer kept)
ok - stop-ordering: daemon SIGTERM'd while .afk still present (flush is not a no-op)
ok - stop-ordering: .afk cleared last
ok - stop-ordering: daemon-terminal record removed
ok - stop identity: stale lock cannot signal an unrelated live process
ok - failed start: away flag and delivery artifacts roll back
ok - concurrent start: one serialized daemon terminal remains tracked
ok - launcher lock: incomplete publication receives initialization grace
ok - launcher signal: TERM exits and releases the lifecycle lock
fm-afk-launch: daemon launched in non-visible herdr workspace ws-partial (pane lab:pane-exact), supervising lab:captain
ok - herdr create: malformed response recovers durable exact ownership
fm-afk-launch: herdr create failed after returning exact ids; closing lab:pane-exact
fm-afk-launch: recorded terminal teardown is unconfirmed; preserving exact id
ok - herdr create error: unconfirmed exact id is persisted for reconciliation
fm-afk-launch: failed to run daemon in herdr pane lab:pane-exact; closing it
fm-afk-launch: recorded terminal teardown is unconfirmed; preserving exact id
ok - herdr run failure: unconfirmed exact id remains reconcilable
fm-afk-launch: failed to persist daemon terminal record; closing tmux:exact-session
ok - record failure: newly created terminal is closed by exact id
fm-afk-launch: daemon did not become ready; closing tmux:exact-session
ok - readiness failure: exact terminal and durable record roll back
fm-afk-launch: daemon did not become ready; closing tmux:exact-session
fm-afk-launch: recorded terminal teardown is unconfirmed; preserving exact id
ok - readiness failure: unconfirmed terminal retains its reconciliation id
ok - tmux absence: clean missing differs from transport probe failure
ok - native lifecycle: launcher owns state with no terminal
ok - native lifecycle: uniform stop clears state without closing a terminal
ok - native entry: launcher-prepared lifecycle state is not rewritten
fm-afk-launch: reconciling leaked daemon terminal tmux:exact-session
fm-afk-launch: recorded terminal teardown is unconfirmed; preserving exact id
ok - teardown failure: exact terminal record is preserved
ok - record publication: failed atomic rename preserves the complete prior record
fm-afk-launch: daemon terminal record is malformed; refusing to act on it
ok - record read: malformed record fails closed without acting on a partial id
fm-afk-launch: daemon terminal record is malformed; refusing to act on it
fm-afk-launch: malformed daemon terminal record; refusing to stop away mode
ok - stop: malformed terminal record preserves away state and fails closed
fm-afk-launch: failed to create detached tmux daemon session 'fm-afk-daemon-3483790959-2407534-254-1786094440'
ok - tmux launch: planned exact target is recorded before creation and removed on failure
fm-afk-launch: failed to create detached tmux daemon session 'fm-afk-daemon-2933635826-2407610-21837-1786094440'
ok - tmux launch: unique names eliminate collision teardown
ok - stop validation: malformed record causes no daemon or state side effects
ok - launcher lock: incomplete metadata fails acquisition and releases lock
fm-afk-launch: failed to clear away-mode flag
fm-afk-launch: away mode stopped; terminal teardown remains recorded for retry
ok - stop state: away-flag removal failure is surfaced
fm-afk-launch: away-mode daemon did not exit after SIGTERM; preserving lifecycle state
ok - stop liveness: captured live daemon preserves lifecycle state after lock release
fm-afk-launch: daemon terminal record is malformed; refusing to act on it
fm-afk-launch: daemon terminal record is malformed; refusing to act on it
ok - refresh record: malformed terminal identity fails closed
fm-afk-launch: failed to clear stale away-mode artifacts
ok - clear failure: native entry aborts and restores prior state
fm-afk-launch: reconciling leaked daemon terminal tmux:exact-session
fm-afk-launch: terminal close command failed, but exact absence was confirmed
ok - confirmed absence: cleanup succeeds and removes the stale record
fm-afk-launch: rollback restoration incomplete; backup retained at /tmp/fm-afk-restore-fail.JnlxZX/state/.afk-launch-backup.oDD3bv
ok - rollback restore: incomplete restoration retains its recovery backup
ok - flag failure: lifecycle aborts without active state
ok - herdr e2e: captain tab pane count unchanged after start (no split)
ok - herdr e2e: daemon launched in a separate non-visible workspace
ok - herdr e2e: daemon pane is NOT in the captain's tab
ok - herdr e2e: daemon terminal scoped to the lab session
ok - herdr e2e: captain tab pane count restored after stop
ok - herdr e2e: daemon workspace removed by exact id on stop
ok - herdr e2e: record + .afk cleared on stop
ok - tmux e2e: captain window pane count unchanged after start (no split-window)
ok - tmux e2e: daemon launched in a separate detached session
ok - tmux e2e: captain window pane count unchanged after stop
ok - tmux e2e: daemon session killed by exact id on stop
ok - tmux e2e: record + .afk cleared on stop
FM_TEST_END 2026-08-07T09:20:42Z tests/fm-afk-launch.test.sh exit=0 duration_ms=34901 gate_skip=false
FM_TEST_BEGIN 2026-08-07T09:20:42Z tests/fm-afk-pi-herdr-return-e2e.test.sh family=live-harness-optin expected_gate_skip=optin-env
skip: set FM_AFK_PI_HERDR_E2E=1 to run the real Pi/Herdr away-return regression
FM_TEST_END 2026-08-07T09:20:42Z tests/fm-afk-pi-herdr-return-e2e.test.sh exit=0 duration_ms=149 gate_skip=true
FM_TEST_BEGIN 2026-08-07T09:20:42Z tests/fm-afk-return.test.sh family=afk expected_gate_skip=none
ok - return catch-up precedes Bearings, owns live blocker remediation, preserves evidence once, and clears idempotently
ok - tmux and Herdr blockers require the same explicit durable reclassification before ordinary work
ok - needs-decision remains reportable without masquerading as a firstmate-actionable blocker
ok - away-mode re-entry fails closed while the prior return catch-up is pending
ok - check retries recorded terminal teardown and keeps catch-up gated until success
FM_TEST_END 2026-08-07T09:20:45Z tests/fm-afk-return.test.sh exit=0 duration_ms=2166 gate_skip=false
FM_TEST_BEGIN 2026-08-07T09:20:45Z tests/fm-arm-pretool-check.test.sh family=pure-contract-unit expected_gate_skip=none
ok - matrix A01: allow through all five entry forms
ok - matrix A02: allo

... [229789 bytes truncated] ...

private guarded artifacts
ok - fmx_split_thread: word-boundary, fence-aware, within-limit, numbered, lossless, capped
ok - fm-x-reply keeps a concise reply as a single unnumbered tweet
ok - fm-x-reply auto-splits a long reply into a numbered thread (texts[])
ok - fm-x-reply uses the Discord inbox platform budget instead of the X tweet budget
ok - fm-x-reply keeps numeric X requests on the X tweet budget
ok - fm-x-reply prefers an explicit relay-provided reply limit
ok - fm-x-reply rejects unsafe inbox context artifacts
ok - fm-x-reply clamps a below-floor max to 50 characters
ok - fm-x-reply posts a thread payload (texts[]) to the relay
ok - fm-x-reply --image posts an image object on answer
ok - fm-x-reply streams large image payloads outside curl argv
ok - fm-x-reply dry-run records compact image metadata for threaded replies
ok - fm-x-reply cleans image and payload temp files
ok - fm-x-reply --image rejects missing and unsupported image paths clearly
ok - fm-x-reply --followup posts to /connector/followup with the same request-bound body
ok - fm-x-reply maps a followup_unavailable follow-up 409 to exit 9
ok - fm-x-reply maps every follow-up 409 to exit 9 even without the marker
ok - fm-x-reply treats answer-endpoint 409 as a generic failure
ok - fm-x-reply --followup --image posts an image object
ok - fm-x-reply --followup is accepted in any position and leaves the answer path default
ok - fm-x-reply --followup dry-run marks the endpoint without changing the answer path
ok - fm-x-reply --followup auto-splits a long follow-up into a marked thread
ok - fm-x-reply followup dry-run keeps endpoint marker and compact image metadata
ok - fm-x-poll records the durable per-request reply context from the relay payload
ok - context registry publishes records only through private guarded artifacts
ok - context registry reads only private single-link artifacts
ok - private artifact publisher is compatible with the system bash path
ok - context registry retention is bounded to the seven-day follow-up window
ok - context registry rewrites preserve the first-seen timestamp
ok - context retention starts only when a live initial answer succeeds
ok - a delayed Discord follow-up stays one message after inbox cleanup via the durable registry
ok - an X follow-up over 280 still splits correctly after inbox cleanup
ok - every unresolved follow-up is refused before posting
ok - a partial registry platform combines with the relay's authoritative budget
ok - concurrent requests each recover their own platform/budget with no cross-overwrite
ok - fm-x-dismiss clears the durable per-request context (a dismissed mention gets no follow-up)
ok - fm-x-dismiss posts a request-bound dismiss and echoes only the request_id
ok - fm-x-dismiss dry-run records the would-be body and never posts
ok - fm-x-dismiss dry-run works without a token
ok - fm-x-dismiss dry-run publishes outbox records only through private guarded artifacts
ok - fm-x-dismiss exits non-zero on a non-2xx relay response
ok - fm-x-dismiss exits non-zero on a transport failure
ok - fm-x-dismiss rejects an unsafe request_id (path-traversal guard)
ok - fm-x-dismiss rejects missing or extra arguments with a usage error
ok - fm-x-link records and refreshes the X-request link without disturbing meta
ok - fm-x-link records Discord platform context so follow-ups keep the Discord budget
ok - fm-x-link resolves the platform by request_id so a post-cleanup link keeps the Discord budget
ok - fm-x-link warns loudly and the follow-up is held (not wrongly split) when the platform is unknown
ok - fm-x-link paired carry flags preserve a prior task's follow-up binding onto a successor
ok - fm-x-link recovery relink preserves Discord platform context after inbox drain
ok - fm-x-link rejects malformed or unpaired carry flags
ok - meta rewrites are independent of TMPDIR
ok - fm-x-link rejects unsafe ids, missing meta, and missing arguments
ok - fm-x-followup --check reports postable / not-linked correctly
ok - fm-x-followup --check prunes a link past the 7-day window
ok - fm-x-followup --check prunes a link that already reached the follow-up cap
ok - fm-x-followup posts a follow-up, increments the counter, and keeps the link under the cap
ok - fm-x-followup --final clears the link after one post regardless of the remaining count
ok - fm-x-followup clears the link once the third follow-up reaches the cap
ok - fm-x-followup --image forwards the attachment through fm-x-reply --followup
ok - fm-x-followup keeps the link and counter when the post fails
ok - fm-x-followup tombstones the link when a post-success counter write fails
ok - fm-x-followup treats a relay cap/window rejection as an already-exhausted link, not a retry
ok - fm-x-followup skips silently and clears the link past the 7-day window
ok - fm-x-followup is a no-op for a task with no X link
ok - fm-x-followup dry-run records the follow-up and increments the counter, keeping the link
ok - fm-x-followup dry-run --final clears the link just as a live post would
ok - fm-x-followup rejects malformed invocations
ok - bootstrap activates X mode from an .env token, idempotently
ok - bootstrap ignores CDPATH when writing absolute FM_HOME into the durable X-mode poll shim
ok - bootstrap reports missing X-mode dependencies before arming
ok - bootstrap does not report X mode on when activation artifacts cannot be written
ok - bootstrap rejects linked X artifacts without touching their targets
ok - bootstrap is inert without a non-empty .env token (non-X users unaffected)
ok - bootstrap cleans up X artifacts on opt-out and is silent once off
ok - bootstrap reports failed X artifact cleanup on opt-out
FM_TEST_END 2026-08-07T10:20:54Z tests/fm-x-mode.test.sh exit=0 duration_ms=69778 gate_skip=false
FM_TEST_SUMMARY total=130 failed=22 skipped_gate=16 duration_ms=3748000
FM_TEST_SUMMARY_FAMILY family=afk count=2 duration_ms=38680 failed=0
FM_TEST_SUMMARY_FAMILY family=backend-dispatch count=12 duration_ms=190959 failed=2
FM_TEST_SUMMARY_FAMILY family=cmux count=2 duration_ms=4876 failed=0
FM_TEST_SUMMARY_FAMILY family=live-harness-optin count=12 duration_ms=518 failed=0
FM_TEST_SUMMARY_FAMILY family=orca count=1 duration_ms=14943 failed=1
FM_TEST_SUMMARY_FAMILY family=pr-forge count=5 duration_ms=785798 failed=1
FM_TEST_SUMMARY_FAMILY family=pure-contract-unit count=29 duration_ms=298945 failed=2
FM_TEST_SUMMARY_FAMILY family=real-herdr-gated count=11 duration_ms=295889 failed=1
FM_TEST_SUMMARY_FAMILY family=secondmate count=16 duration_ms=937086 failed=6
FM_TEST_SUMMARY_FAMILY family=session-bootstrap count=9 duration_ms=257471 failed=4
FM_TEST_SUMMARY_FAMILY family=snapshot-bearings count=2 duration_ms=52630 failed=1
FM_TEST_SUMMARY_FAMILY family=unclassified count=15 duration_ms=367258 failed=1
FM_TEST_SUMMARY_FAMILY family=watcher-wake-lock count=12 duration_ms=490411 failed=2
FM_TEST_SUMMARY_FAMILY family=zellij count=2 duration_ms=6004 failed=1
FM_TEST_SLOWEST rank=1 script=tests/fm-remote-secondmate-lifecycle-e2e.test.sh duration_ms=380235
FM_TEST_SLOWEST rank=2 script=tests/fm-pr-check-security.test.sh duration_ms=373906
FM_TEST_SLOWEST rank=3 script=tests/fm-teardown.test.sh duration_ms=323535
FM_TEST_SLOWEST rank=4 script=tests/fm-secondmate-harness.test.sh duration_ms=236548
FM_TEST_SLOWEST rank=5 script=tests/fm-watch-triage.test.sh duration_ms=180644
FM_TEST_SLOWEST rank=6 script=tests/fm-sessionstart-nudge.test.sh duration_ms=94925
FM_TEST_SLOWEST rank=7 script=tests/fm-public-followup.test.sh duration_ms=93559
FM_TEST_SLOWEST rank=8 script=tests/fm-backend-herdr-presentation-e2e.test.sh duration_ms=87679
FM_TEST_SLOWEST rank=9 script=tests/fm-remote-secondmate-trace-context.test.sh duration_ms=84633
FM_TEST_SLOWEST rank=10 script=tests/fm-watcher-lock.test.sh duration_ms=80275
FM_TEST_SLOWEST rank=11 script=tests/fm-procevent.test.sh duration_ms=70648
FM_TEST_SLOWEST rank=12 script=tests/fm-x-mode.test.sh duration_ms=69778
FM_TEST_SLOWEST rank=13 script=tests/fm-afk-inject-herdr-e2e.test.sh duration_ms=64126
FM_TEST_SLOWEST rank=14 script=tests/fm-remote-reply.test.sh duration_ms=62527
FM_TEST_SLOWEST rank=15 script=tests/fm-claude-stop-autoarm.test.sh duration_ms=61277
- Outcome: ⚠️ 2 warnings across 1 run (1h5m24s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

⚠️ **Test** - 2 warnings
  • ⚠️ The full suite retained 22 failures unrelated to the two changed files. Several are environment-sensitive permission checks running as root; others involve live Herdr/Orca/Zellij, remote fixtures, watcher timing, and existing harness tests. Exact failures and diagnostics are preserved in the full-suite artifact.
  • ⚠️ tests/fm-bearings-snapshot.test.sh - The focused bearings suite's unreadable-home fixture fails under root because chmod cannot make the fixture unreadable. The changed end-to-end regression independently exercised oversized bearings successfully and preserved all generated records.
  • Inspected git diff 70aeba855527f7693082f6dd1bc731e334d0269f..90b83111d48e43858014f0019adbb74e891b6dba
  • /bin/bash tests/fm-fleet-snapshot-view.test.sh
  • /bin/bash tests/fm-bearings-snapshot.test.sh
  • bin/fm-test-run.sh --changed --base 70aeba855527f7693082f6dd1bc731e334d0269f
  • bin/fm-test-run.sh --all
  • git status --short
✅ **Document** - passed

✅ No issues found.

🔧 **Lint** - 1 issue found → auto-fixed ✅
  • ⚠️ linter found issues (exit code 1)

🔧 Fix: Captain, fix fleet snapshot ShellCheck findings
✅ Re-checked - no issues remain.

✅ **Push** - passed

✅ No issues found.

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