Skip to content

feat(bin): local ChatGPT return transport, park filter, and packet merge authority - #4344

Closed
brentwarnes-repo wants to merge 3 commits into
kunchenguid:mainfrom
brentwarnes-repo:fm/overnight-local-control-repair
Closed

brentwarnes-repo wants to merge 3 commits into
kunchenguid:mainfrom
brentwarnes-repo:fm/overnight-local-control-repair

Conversation

@brentwarnes-repo

Copy link
Copy Markdown

Intent

Make this Captain's required First Mate behavior independent of parked upstream PR #4315 (kunchenguid/firstmate). PR #4315 itself remains PARKED and must not be resumed, modified, pushed, validated, or chased upstream; its preserved branch (fm/followon-decision-filter at /home/leah/.treehouse/firstmate-7bab20/5/firstmate, head b9d8b97) may be used only as implementation/review evidence or source material.

Implement locally, as three independently testable local controls:

A. Automatic ChatGPT return transport: whenever the primary First Mate produces a return explicitly intended for ChatGPT, the complete return must be atomically written to ~/inbox/FIRST_MATE_TO_CHATGPT.md BEFORE presentation to the Captain. The primary First Mate is the consolidating writer. Do not dump routine internal agent chatter into the transport file. The parked PR's implementation has two known unresolved defects that must be diagnosed and fixed, not copied forward: (1) a dangling-symlink path canonicalization issue, and (2) a repo-identity dedup issue. Test with a small real ChatGPT-bound return.

B. DO IT / DECIDE / REVIEW: implement a local Captain-facing filter with three categories - DO IT (no genuine human judgment remains; execute/resolved AI-side), DECIDE (consequential unresolved human judgment genuinely remains), REVIEW (finished/review-ready artifact needs human judgment/taste/approval). PARK/HOLD is execution state and must NOT automatically surface as a current Captain decision. The parked PR's known defect here - parent-decision resolution behaves incorrectly when parking a live call - must be resolved before this control is considered complete.

C. Packet-scoped merge authority: implement/support the bounded model already proven operationally - an explicitly authorized execution packet may grant packet-scoped merge authority, under which conforming internal implementation PRs may merge without another per-PR Captain word only when: scope remains inside the packet; tests/checks pass; required review completes; substantive findings are repaired/dispositioned; verification passes; no material scope expansion occurs; no reserved human gate appears. This authority expires when the packet closes, does not enable YOLO, and is not global standing merge authority.

D. Ownership: these are Captain/local operating requirements. The Captain's local system must NOT depend on kunchenguid/firstmate accepting an upstream contribution. Use the smallest existing First Mate-local configuration/governance/overlay mechanism that fits; do not invent unnecessary architecture.

Done condition: all three local controls (A, B, C) are independently tested. PR #4315 remains untouched/PARKED throughout.

What Changed

  • Added bin/fm-chatgpt-return.sh, which atomically writes the complete ChatGPT-bound return to ~/inbox/FIRST_MATE_TO_CHATGPT.md before Captain presentation, fixing dangling-symlink path canonicalization and repo-identity dedup issues.
  • Added bin/fm-packet.sh implementing packet-scoped merge authority (scope, tests/checks, review, findings disposition, verification, no scope expansion, no reserved gate), expiring when the packet closes.
  • Extended bin/fm-captain-hold.sh and bin/fm-classify-lib.sh so PARK/HOLD execution state is filtered out of DO IT / DECIDE / REVIEW surfacing and no longer misreports parent-decision resolution when parking a live call.
  • Updated AGENTS.md, docs/architecture.md, docs/captain-hold-lifecycle.md, docs/scripts.md, and the ask-user-authority/captain-hold-lifecycle skills to document the three local controls, plus added test coverage in tests/fm-chatgpt-return.test.sh, tests/fm-captain-hold-park.test.sh, and tests/fm-packet.test.sh.

🤖 Generated with Claude Code

Risk Assessment

⚠️ Medium: Controls A and B are well-diagnosed, correctly fixed (dangling-symlink canonicalization and repo-qualified PR dedup), and thoroughly tested; control C ships only the record/check primitive with no wiring into the actual merge gate (fm-pr-merge.sh), which is an honest disclosure in the script's own header but leaves ambiguous whether the required 'merge without another per-PR Captain word' behavior is actually deliverable yet.

Testing

All three independently-testable local controls (A: ChatGPT return transport, B: DO IT/DECIDE/REVIEW park filter, C: packet-scoped merge authority) have dedicated test suites in this diff and all pass, including regression tests for the two named upstream defects (dangling-symlink canonicalization, cross-repo PR-identity dedup) and the park/parent-decision-resolution defect; a manual end-to-end CLI run additionally confirms the ChatGPT transport file is produced and formatted as intended. No touch to the parked PR #4315 branch was made.

Evidence: Manual CLI transcript: fm-chatgpt-return.sh write end-to-end

Source: Manual CLI transcript: fm-chatgpt-return.sh write end-to-end

$ fm-chatgpt-return.sh write --status complete --return-file body.md --task overnight-local-control-repair --artifact bin/fm-chatgpt-return.sh --blocker "none - all three controls independently tested"
/tmp/tmp.i05WpwA9pW/inbox/FIRST_MATE_TO_CHATGPT.md

--- resulting ~/inbox/FIRST_MATE_TO_CHATGPT.md ---
# First Mate → ChatGPT return

Generated: 2026-09-13T00:00:00Z
Originating task/packet: overnight-local-control-repair
Result/status: complete

## Concise return

The overnight local control repair is complete: ChatGPT return transport, DO IT/DECIDE/REVIEW filter, and packet-scoped merge authority are all locally implemented and independently tested. PR #4315 remains parked and untouched.

## Referenced artifacts

- bin/fm-chatgpt-return.sh

## Blockers and genuine decisions

- none - all three controls independently tested

## Clear safety

CLEAR_SAFE: YES

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 2 issues (1 warning, 1 info)
  • ⚠️ bin/fm-packet.sh:15 - Control C's own header states it 'records and checks the packet only - it does not itself drive or authorize a merge' and 'no such wiring is added by this script' — bin/fm-pr-merge.sh is untouched by this branch and never consults fm-packet.sh check. User intent C requires 'conforming internal implementation PRs may merge without another per-PR Captain word only when [conditions]'; fm-pr-merge.sh's own comments show captain-hold state is the actual mechanical gate that blocks a merge until an answer --release, and that gate is not bypassed for a granted packet anywhere in this change. As shipped, opening/granting a packet changes no actual merge behavior — it only lets code that doesn't exist yet consult it. tests/fm-packet.test.sh (and AGENTS.md's own text) only exercises the record/check lifecycle, not an actual autonomous merge. This may be an intentional MVP scoping consistent with intent's 'implement/support' wording and directive D against inventing unnecessary architecture, but it should be confirmed with the user whether C is meant to be considered complete without the fm-pr-merge.sh wiring, since 'Done condition' calls all three controls independently tested and C's tested surface never actually merges anything without a captain word.
  • ℹ️ bin/fm-packet.sh:137 - open/grant/close/check all do read-then-write of the packet record with no lock (unlike fm-captain-hold.sh's acquire_task_control_lock), so two concurrent invocations (e.g. a duplicate grant vs. close) can race and clobber each other's write. Low likelihood given single-operator usage, but worth a follow-up if packets are ever driven concurrently.
✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-chatgpt-return.test.sh (10/10 pass, includes dangling-symlink and cross-repo dedup regression tests)
  • bash tests/fm-packet.test.sh (5/5 pass, packet-scoped merge authority lifecycle)
  • bash tests/fm-captain-hold-park.test.sh (5/5 pass, includes parent-decision resolution on park regression test)
  • Manual CLI transcript: bin/fm-chatgpt-return.sh write against a scratch HOME, verifying the assembled ~/inbox/FIRST_MATE_TO_CHATGPT.md content end-to-end
  • git status --porcelain (worktree clean after testing)
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

…uthority

Implement three local controls so the captain's required First Mate
behavior no longer depends on the parked upstream PR kunchenguid#4315:

- bin/fm-chatgpt-return.sh: atomically write a ChatGPT-bound captain
  return, diagnosed and fixed independently of the parked branch's copy
  (dangling-symlink canonicalization via realpath -m instead of a
  per-component Cwd::realpath that silently fell back to the literal
  path; PR-identity dedup by repo+number instead of bare number, so two
  different repos' PR kunchenguid#6 no longer collapse into one).
- bin/fm-captain-hold.sh hold --park: records parked/standby execution
  state distinct from a live captain call, excluded from the OPEN
  DECISIONS drain (bin/fm-classify-lib.sh) via a state/<id>.parked
  marker, and fixes the parent-decision resolution defect by resolving
  a task's dangling live hold when it is parked instead of leaving it
  open.
- bin/fm-packet.sh: records and checks bounded packet-scoped merge
  authority (open/grant/check/close) as pure recording/checking
  mechanics, not wired into an autonomous merge path.

PR kunchenguid#4315 and its preserved branch remain untouched throughout.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 13, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-13T05:04:55.918314Z 9f71555 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9f7155542c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/fm-packet.sh
record=$(printf '%s\n' "$record" | sed \
-e "s/^merge_authority=.*/merge_authority=yes/" \
-e "s/^granted=.*/granted=$(now_stamp)/")
write_record_atomic "$slug" "$record"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Serialize packet grant and close updates

When grant and close run concurrently, each reads the old open record and later replaces the entire file without a shared lock or compare-and-swap. If grant writes last, it restores status=open, clears the close timestamp, and leaves merge_authority=yes, so check authorizes merges after the packet was closed. Serialize every read-modify-write operation for a packet so closure cannot be overwritten by a stale grant.

AGENTS.md reference: AGENTS.md:L357-L358

Useful? React with 👍 / 👎.

Comment thread bin/fm-captain-hold.sh Outdated
Comment on lines +931 to +934
if [ "$existing_hold_kind" = captain ] && [ "$existing_held" = yes ]; then
occurrence=$(( $(resolution_record_count "$(show_field "$show" body)") + 1 ))
publish_parent_hold "$id" "$occurrence" resolved parked
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Retry the parent resolution after failed park publication

When parking an existing live hold in a secondmate home and the parent-channel write fails, publish_parent_hold only reports the failure while the backlog still changes to hold_kind=parked. Retrying hold --park after repairing the route then sees existing_hold_kind=parked, skips this conditional, and never republishes the missing resolution, leaving the parent's prior needs-decision open indefinitely. Preserve enough durable transition state to retry the resolution until it reaches the parent. .agents/skills/captain-hold-lifecycle/SKILL.mdL58-L60

Useful? React with 👍 / 👎.

Comment thread bin/fm-chatgpt-return.sh
Comment on lines +145 to +147
if [ -z "$ids" ]; then
return 0
fi

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 Badge Count list items when no PR IDs are present

When a return claims a PR count but lists PRs without numbered identities, collect_pr_ids returns empty and this branch accepts the claim without comparing it to the bullet count. For example, Three PRs landed: followed by two title-only bullets passes verification, so the advertised count/list QA still permits an inaccurate captain-facing return. Treat an empty ID set as zero or count the associated list entries before accepting the claim.

AGENTS.md reference: AGENTS.md:L515-L516

Useful? React with 👍 / 👎.

Comment thread bin/fm-chatgpt-return.sh Outdated
Comment on lines +320 to +324
if [ -n "${FM_TASK_ID:-}" ]; then
default_canonical=$(canonical_path "$DEFAULT_RETURN_PATH") \
|| fail "could not canonicalize the live return path"
if [ "$dest" = "$default_canonical" ]; then
fail "a task worker must not write the live ChatGPT return transport"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Detect task workers without trusting FM_TASK_ID

When a task worker invokes this script through an environment-clearing wrapper or otherwise lacks FM_TASK_ID, the only worker-specific guard is skipped and the process can overwrite the live ChatGPT transport. Because the script is intended to categorically refuse task workers, identify worker scope from non-caller-controlled home/worktree metadata rather than relying solely on an optional environment variable.

AGENTS.md reference: AGENTS.md:L515-L516

Useful? React with 👍 / 👎.

…d#4344

Four ordinary QA/implementation fixes to the local ChatGPT return
transport, park filter, and packet merge authority controls, each with
a dedicated regression test verified to fail before the fix and pass
after it:

- bin/fm-packet.sh: serialize open/grant/close on a per-slug lock
  (fm-wake-lib.sh's fm_lock_acquire_wait) so a concurrent grant and
  close can no longer race each other's read-modify-write and
  resurrect merge authority on a closed packet.
- bin/fm-captain-hold.sh: a park whose parent-channel publish fails
  now leaves a durable state/<id>.park-pending-resolve marker, so a
  later hold --park retries the deferred resolution instead of losing
  it once existing_hold_kind no longer reads "captain".
- bin/fm-chatgpt-return.sh: the PR-count/list QA now falls back to
  counting a claim's own list bullets when no numbered PR identity is
  present, instead of accepting an unchecked claim on no evidence.
- bin/fm-chatgpt-return.sh: the live-path guard now also refuses
  whenever the script's own root is not a genuine primary checkout
  (fm_primary_scope_matches), so an environment-clearing wrapper that
  merely unsets FM_TASK_ID can no longer make a task worker pass as
  the primary.
@devin-ai-integration

Copy link
Copy Markdown

Closed as misaligned with VISION.md — this change takes the project outside the documented scope/contract.

— Kun's Firstmate

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