Skip to content

fix(bin): reserve gate-refusal exit code so remote leg cannot report it as delivered - #2894

Open
harmeet-1337 wants to merge 1 commit into
kunchenguid:mainfrom
harmeet-1337:fm/fm-fix-exit3
Open

fix(bin): reserve gate-refusal exit code so remote leg cannot report it as delivered#2894
harmeet-1337 wants to merge 1 commit into
kunchenguid:mainfrom
harmeet-1337:fm/fm-fix-exit3

Conversation

@harmeet-1337

Copy link
Copy Markdown

Summary

Implements accepted simplification-audit finding F-S12-1 (P0).

fm-send exit status 3 was overloaded to mean two contradictory things:

  • a no-mistakes gate-agent refusal ("nothing was sent"), and
  • a delivered-with-unconfirmed-submit ("do not resend").

The remote send leg maps an inner exit 3 to delivered, so a gate refusal inside the remote host's fm-send would be wrongly reported as a delivered steer.

Change

  1. bin/fm-gate-refuse-lib.sh - move FM_GATE_REFUSE_EXIT from 3 to a reserved 77 (outside every lifecycle script's documented status space) and update its header sentence explaining the reservation.
  2. bin/fm-send.sh - document code 77 in the header exit contract as reserved for the gate-agent refusal, never meaning delivered.
  3. tests/fm-gate-refuse.test.sh - assert against the sourced $FM_GATE_REFUSE_EXIT so the value stays owned in one place; degeneralize stale "exit 3" wording.
  4. tests/fm-send-remote-delivery.test.sh - add a negative case where the ssh stub exits the reserved gate code with the gate stderr, asserting the parent fails loudly, discards the undelivered pending-reply expectation, and closes no --resolve-key decision.

Delivered-unconfirmed exit 3 semantics are intentionally unchanged. Grepped bin/ and tests/: no other caller branches on exit 3 from fm-spawn/fm-send/fm-teardown/fm-control as a refusal, matching the audit.

Validation

bin/fm-lint.sh clean (ShellCheck 0.11.0 + actionlint 1.7.12); both affected test suites pass; the remote gate-refusal case was regression-verified (fails when the constant is reverted to 3).

…it as delivered

fm-send exit 3 meant two contradictory things: a no-mistakes gate-agent
refusal (nothing was sent) and a delivered-with-unconfirmed-submit (do not
resend). The remote send leg maps an inner exit 3 to delivered, so a gate
refusal inside the remote host's fm-send would be reported as a delivered
steer.

Move the gate refusal to a reserved code (77) outside every lifecycle
script's documented status space, document the reservation in fm-send's
exit contract, and cover the remote gate-refusal path with a negative test
that asserts a hard failure, a discarded expectation, and no closed
decision. The gate-refuse suite now asserts against the sourced constant so
the value stays owned in one place.
@greptile-apps

greptile-apps Bot commented Aug 23, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

The PR appears safe to merge, with a non-blocking architecture-documentation update needed to reflect the new refusal status.

The production status relay and checked callers correctly treat exit 77 as a hard failure, and the regression test independently protects against collision with delivered-unconfirmed status 3; only the stale documented status remains.

Files Needing Attention: bin/fm-gate-refuse-lib.sh and docs/architecture.md

Reviews (1): Last reviewed commit: "fix(bin): reserve gate-refusal exit code..." | Re-trigger Greptile

Comment thread bin/fm-gate-refuse-lib.sh
# must never collide with fm-send's delivered-unconfirmed exit 3, which the
# remote leg maps to "delivered, do not resend" - a gate refusal wearing exit 3
# would be reported as a delivered steer. Keep this value out of that space.
FM_GATE_REFUSE_EXIT=77

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Gate status documentation remains stale

The refusal status is now 77, but docs/architecture.md still documents status 3 for this guard. That stale contract can lead maintainers or integrations to handle refusals as the delivered-unconfirmed status this change is designed to distinguish.

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