Skip to content

Integrate upstream/main into fork main - #17

Merged
Bre77 merged 6 commits into
mainfrom
fm/integrate-upstream-j4
Jul 13, 2026
Merged

Bre77 merged 6 commits into
mainfrom
fm/integrate-upstream-j4

Conversation

@Bre77

@Bre77 Bre77 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Intent

  • Integrate upstream/main (kunchenguid/firstmate) into the fork's main via a true merge commit.
    • Picks up upstream's zellij/cmux backend-diagnostics work, fm-gate-refuse-lib.sh, marker-preservation fixes, and related doc/test updates.
    • Resolves the single conflict in bin/fm-bootstrap.sh's install_cmd() case statement: the fork side had added python3 (for the fork-only ClickStack webhook receiver's required-tool check) to the same case arm upstream extended with zellij, alongside upstream's new standalone cmux arm.
    • Both sides' additions are additive and non-conflicting, so the resolution keeps all three: python3 and zellij share the existing brew-install arm, and the new cmux arm is preserved as-is.
  • Fold with a merge commit (not squash) - squashing would drop the upstream merge parent and re-conflict every future upstream integration.
    • The merge parent (fork main tip + upstream/main tip) is what lets git recognize already-integrated upstream history on the next sync; a squash merge discards that parent and the same hunks would conflict again next time.

What changed

  • Merge commit on fm/integrate-upstream-j4, parents: fork main tip (ed872ad) and upstream/main tip (85b7a29).
  • Only manual resolution: bin/fm-bootstrap.sh install_cmd() case statement (see Intent above).
  • Everything else auto-merged cleanly (AGENTS.md, bin/fm-spawn.sh, docs, tests, etc.).

Testing

  • bin/fm-lint.sh - shellcheck 0.11.0 (pinned), clean, no findings.
  • Full local test gate: all 74 tests/*.test.sh scripts pass.
Full narrative / original brief

Automated integration of upstream/main into the fork's main stopped on a merge conflict in bin/fm-bootstrap.sh. Both sides had made independent additive changes to the same install_cmd() case arm:

  • Fork (ecf955b, fork-only ClickStack webhook receiver): added python3 to the shared tmux|node|git|gh|curl|jq|orca brew-install arm, since the webhook receiver needs python3 as a required tool.
  • Upstream (547acd7, "fix: make bootstrap diagnostics backend-aware (fix: make bootstrap diagnostics backend-aware kunchenguid/firstmate#519)"): added zellij to the same shared arm, plus a new dedicated cmux) echo "brew install --cask cmux ..." arm.

Neither side's addition depends on or excludes the other, so the resolution merges both: the shared arm now lists tmux|node|git|gh|curl|jq|orca|python3|zellij, and the cmux arm from upstream is kept intact.

kunchenguid and others added 6 commits July 13, 2026 02:01
…uid#518)

* feat: contain no-mistakes gate agents from driving the fleet

Add bin/fm-gate-refuse-lib.sh, sourced at the top of fm-spawn/fm-send/
fm-teardown before any fleet mutation. It fails closed when NO_MISTAKES_GATE
is set, and via an unspoofable git-common-dir backstop when invoked from a
no-mistakes gate worktree (.no-mistakes/repos/*.git) even with the marker
unset. A normal firstmate session has neither signal and is unaffected.

Set disable_project_settings: true in the tracked .no-mistakes.yaml so the
installed pipeline neutralizes gate agents' project instructions for this repo
(trusted-only, honored from the default branch).

firstmate's own suite runs from a gate worktree during validation, so the
shared test helpers set FM_GATE_REFUSE_BYPASS=1 to exempt it; the dedicated
tests/fm-gate-refuse.test.sh strips it to verify real refusal.

* no-mistakes(review): Captain, refuse empty no-mistakes gate markers

* no-mistakes(document): Document no-mistakes gate authority boundary
…uid#505)

* fix: guard secondmate own-home turn ends

Remove the .fm-secondmate-home early-exit in fm-turnend-guard.sh so the
'no turn ends blind' backstop fires in a secondmate's own primary session,
matching the cd-guard's scope: the own home is guarded, child crew/scout
worktrees stay exempt via the retained git-dir/git-common-dir test. This
was pure scoping from the guard's primary-only origin and guarded against
no secondmate-specific hazard.

Add secondmate regression tests (blind-turn block, idle-by-default,
stop_hook_active loop guard, deferred-death recovery loop, child-worktree
exemption) and record the autonomous background-notify re-invoke
measurement (Claude Code 2.1.207, 11s) in docs/turnend-guard.md.

* no-mistakes(document): Correct secondmate guard documentation, captain

* fix: force-include marked secondmate homes in turn-end guard

The prior remove-only form (just deleting the .fm-secondmate-home check)
left the DEFAULT secondmate topology unguarded: a treehouse-leased home is
a linked git worktree (git-dir != git-common-dir), which the retained
git-dir exemption still skipped, so its own primary session could still end
a turn blind. Invert the marker: a genuinely-marked home is force-included
as a guarded primary (treehouse-leased linked OR git-cloned plain), and the
git-dir exemption applies only to UNMARKED child worktrees. Marker
validation (regular non-symlink file, non-empty id-token content) blocks a
stray or empty marker from spoofing inclusion.

Add real linked-worktree regression tests: a treehouse-leased LINKED
secondmate home is guarded, a stray/empty marker stays exempt, and the
unmarked child worktree stays exempt - the topology the plain git-init
fixtures masked. Predicates, in-flight gate, and loop guard untouched.

* fix: force ASCII collation in secondmate marker validation

Add a function-scoped local LC_ALL=C in fm_root_is_secondmate_home so the
[A-Za-z0-9._-] id allowlist matches under C collation, not the ambient
locale - a locale-crafted non-ASCII marker id can no longer slip through
the range match and spoof force-inclusion of a linked child worktree.
Add a regression test proving a non-ASCII marker id is rejected and the
linked worktree stays exempt.

* no-mistakes(test): fix backend baseline gate-refusal dependency

* no-mistakes(document): Correct secondmate turn-end guard documentation
* fix: make bootstrap required-tool detection backend-aware

Bootstrap demanded tmux and treehouse for every backend except orca, so a
herdr/zellij/cmux home with tmux absent was wrongly told MISSING: tmux.

Required tools now follow the resolved backend via the single-owner
fm_backend_required_tools helper (bin/fm-backend.sh): each backend's own
session-provider CLI, jq for the JSON-emitting adapters (herdr/zellij/cmux),
and treehouse for session-provider-only backends (orca owns its worktree).
The treehouse lease-support check is gated to backends that use treehouse.

Adds install hints for herdr/zellij/cmux, regression tests for the full
backend dependency matrix (herdr-without-tmux repro plus each boundary),
and updates the authoritative Toolchain docs.

* no-mistakes(review): Captain, prevent executing Herdr install guidance

* no-mistakes(review): Captain, harden backend-aware bootstrap diagnostics

* no-mistakes(review): Captain, separate manual dependency remediation

* no-mistakes(review): Captain, align bootstrap diagnostic consumers

* no-mistakes(document): Align backend adapter dependency comments
…guid#520)

* fix: recover X/Discord follow-up platform after inbox cleanup

A milestone follow-up posted directly by request_id after the inbox was
drained - and with no task link, because one persistent secondmate's single
x_request slot collides across concurrent requests - resolved platform only
from the local inbox, so a >280 Discord reply silently defaulted to the X
280-char budget and threaded as (1/2).

- fm-x-poll records a durable per-request reply context
  (state/x-context/<rid>.json) at stash time, keyed by request_id so
  concurrent requests never overwrite each other; it survives inbox cleanup
  and restart.
- fm-x-reply resolves platform/budget through registry -> inbox -> relay
  (the relay lookup confined to a live follow-up), recovering the original
  platform independent of task-link availability.
- Fail-safe: a follow-up whose platform/budget cannot be authoritatively
  resolved and that would split is refused (exit 8) and held for retry,
  never wrongly split; fm-x-followup keeps the link on that exit.
- fm-x-dismiss clears the durable context for a dismissed mention.

Refactors reply-context extraction into a single owner and adds regression
coverage for all four cases.

* no-mistakes(review): Captain, fail closed on incomplete follow-up context

* no-mistakes(review): Captain, bound X context registry retention

* no-mistakes(review): Captain, align context retention with answer binding

* no-mistakes(document): Align X follow-up context documentation

* no-mistakes(document): Align durable X follow-up documentation
…id#533)

* fix: preserve secondmate routing markers

* no-mistakes(review): Captain, preserve trailing newlines in marked secondmate sends

* no-mistakes(test): Captain, tolerate bootstrap timeout elapsed drift

* no-mistakes(document): Refresh Herdr marker documentation
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.

2 participants