Skip to content

feat: merge the completed 30-commit upstream sync with local main - #11

Merged
kirangathani merged 35 commits into
mainfrom
fm/fm-upstream-sync-b3
Aug 2, 2026
Merged

kirangathani merged 35 commits into
mainfrom
fm/fm-upstream-sync-b3

Conversation

@kirangathani

Copy link
Copy Markdown
Owner

Intent

Bring the fork's parked upstream-sync branch up to date with local main so the completed upstream sync (30 upstream commits merged at a3b15b4 by a previous worker) can ship without losing any local work. This merge commit (db46bda) merges main (4bf2e94, PRs #5-#10) into the sync branch, deliberately a merge rather than a rebase to avoid rewriting shared history. Key constraint honored: PR #5's kernel-start-ticks process identity in bin/fm-wake-lib.sh (Linux /proc//stat field 22 parsed after the final paren in comm, proc-starttime: prefix, ps lstart kept only as macOS fallback and legacy-lock compatibility) had to survive against the upstream side's older lstart-based code; the merged file has zero deletions vs main, only the branch's ~157 added watcher-health lines. Conflict resolutions: AGENTS.md keeps the upstream restructure (section bodies moved into skills) and folds in main's only semantic additions - the /handoff skill load trigger and PR #9's exec-gate sentence; .claude/settings.json keeps BOTH SessionStart hooks (upstream's matcher-scoped fm-sessionstart-nudge.sh plus main's fm-handoff.sh pickup) and the branch's third PreToolUse hook; docs/scripts.md keeps both sides' new script rows, with main's richer fm-assert-tests-kept.sh description (matches the #6/#9-enhanced script the branch did not touch). Two deliberate test edits are part of the merge, not drive-by changes: tests/fm-pr-merge.test.sh's stub helper now mirrors all bin/.sh into its shim dir because the branch's fm-pr-merge.sh sources SCRIPT_DIR/fm-pr-lib.sh (with transitive deps) which the old two-symlink shim lacked, and tests/fm-sessionstart-nudge.test.sh now asserts the nudge SessionStart entry is registered exactly once with matcher startup|resume|clear instead of asserting SessionStart has exactly one entry total, because main's handoff pickup hook is a legitimate second entry (its registration is asserted by tests/fm-handoff.test.sh). The .github/workflows/ci.yml diff vs main (test-count assertions 12->13 and 30->36) is inherited byte-identical from upstream and required: the merged tree really has 13 fleet-snapshot/view and 36 bearings tests, verified by running them. Note: the branch was pushed to origin over SSH out-of-band because the pipeline's HTTPS OAuth token lacks workflow scope and cannot push the ci.yml change; the remote branch already matches HEAD, so the push step should be a no-op. Validation before commit: bin/fm-lint.sh clean and all 86 tests/.test.sh files pass.

What Changed

  • Brings the parked upstream-sync branch (a3b15b4, 30 upstream commits) together with local main via a merge commit, deliberately not a rebase. The upstream side adds durable captain decision holds, native session-start nudges, secondmate shared-captain inheritance, wake-signal status enrichment, watcher/x-mode/supervision fixes, PR-check hardening (bin/fm-pr-lib.sh, bin/fm-pr-check-migrate.sh), and the AGENTS.md restructure that moves section bodies into skills.
  • Conflict resolutions preserve all local work: PR fix(watcher): identify processes by kernel start ticks, not drifting lstart #5's kernel-start-ticks process identity in bin/fm-wake-lib.sh survives with zero deletions vs main (only the branch's watcher-health additions), .claude/settings.json keeps both SessionStart hooks (upstream's matcher-scoped nudge plus main's handoff pickup) and the branch's third PreToolUse hook, and the restructured AGENTS.md and docs/scripts.md fold in main's semantic additions (the /handoff load trigger, PR feat(bin): execute Python base tests at the kept-tests merge gate #9's exec-gate sentence, the richer fm-assert-tests-kept.sh description).
  • Two deliberate test edits support the merge: tests/fm-pr-merge.test.sh's stub helper now mirrors all bin/*.sh into its shim dir (fm-pr-merge.sh now sources fm-pr-lib.sh with transitive deps), and tests/fm-sessionstart-nudge.test.sh asserts the nudge SessionStart entry is registered exactly once with matcher startup|resume|clear instead of asserting a single entry total. The ci.yml test-count bumps (12→13, 30→36) are inherited byte-identical from upstream and match the merged tree; all 86 test files pass.

Risk Assessment

✅ Low: Every intent constraint verified against both parents (wake-lib zero deletions with kernel-ticks identity intact, ci.yml byte-identical to upstream with statically confirmed test counts of 13 and 36, both SessionStart hooks plus the third PreToolUse hook, both AGENTS.md semantic additions, both scripts.md row sets), the only hand-edits beyond mechanical resolution are the two declared test-seam repairs which are demonstrably necessary, and no duplicate definitions, dropped test invocations, or syntax issues exist in any both-sides-merged file.</risk_rationale>
["git diff --numstat 4bf2e94..db46bda -- bin/fm-wake-lib.sh (165 insertions, 0 deletions) and grep for proc-starttime/lstart identity helpers", "git diff 9ae91ac..db46bda -- .github/workflows/ci.yml (empty: byte-identical to sync parent)", "static pass-assertion counts: 13 in fm-fleet-snapshot-view.test.sh, 36 in fm-bearings-snapshot.test.sh, matching ci.yml", "jq parse of .claude/settings.json and presence of both SessionStart hooks plus third PreToolUse hook", "isolation of merge-resolution edits: every test hunk vs main traced to the sync parent except the two declared edits", "duplicate-function and defined-but-uninvoked test-function sweeps over all both-sides-merged bash files", "bash -n on fm-pr-merge.sh, fm-wake-lib.sh, and merged test files", "SCRIPT_DIR transitive-dependency check confirming the bin/.sh shim mirror is required (fm-pr-check-migrate.sh sources five sibling scripts)", "git ls-remote: origin fm/fm-upstream-sync-b3 already at db46bda; 86 tests/.test.sh files present"]

Testing

Baseline run of all 86 shell test files passed; I then re-ran the merge-critical tests (fm-pr-merge, fm-sessionstart-nudge, fm-handoff, fm-watcher-lock, fm-wake-queue, fm-fleet-snapshot-view, fm-bearings-snapshot) and verified each intent constraint directly: zero deletions in fm-wake-lib.sh vs main with proc-starttime identity intact, ci.yml diff limited to the inherited count bumps whose values (13, 36) match live test output, both SessionStart hooks plus the three-command PreToolUse hook registered, both deliberate test edits present as described, and the remote branch already at HEAD. No linter was run per task rules. No visual artifacts because this is a shell/CLI project with no rendered UI surface; CLI transcripts serve as the product-level evidence.

Evidence: Merge intent verification transcript (diffs, live counts, hooks, remote check)
== Merge db46bda: intent verification transcript (2026-07-31) ==

-- 1. PR #5 survival: bin/fm-wake-lib.sh vs main (4bf2e94) has zero deletions --
 bin/fm-wake-lib.sh | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 165 insertions(+)
deleted lines: 0
proc-starttime prefix present: 1 occurrence(s)

-- 2. ci.yml diff vs main is exactly the inherited count bumps --
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d95944d..bdfa76b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -81,16 +81,16 @@ jobs:
           snapshot_output=$(/bin/bash tests/fm-fleet-snapshot-view.test.sh)
           printf '%s\n' "$snapshot_output"
           snapshot_count=$(printf '%s\n' "$snapshot_output" | grep -c '^ok - ')
-          [ "$snapshot_count" -eq 12 ] || {
-            echo "::error::expected 12 snapshot/fleet-view tests, got $snapshot_count"
+          [ "$snapshot_count" -eq 13 ] || {
+            echo "::error::expected 13 snapshot/fleet-view tests, got $snapshot_count"
             exit 1
           }
 
           bearings_output=$(/bin/bash tests/fm-bearings-snapshot.test.sh)
           printf '%s\n' "$bearings_output"
           bearings_count=$(printf '%s\n' "$bearings_output" | grep -c '^ok - ')
-          [ "$bearings_count" -eq 30 ] || {
-            echo "::error::expected 30 Bearings tests, got $bearings_count"
+          [ "$bearings_count" -eq 36 ] || {
+            echo "::error::expected 36 Bearings tests, got $bearings_count"
             exit 1
           }
 

-- 3. Live test counts match the ci.yml assertions --
fm-fleet-snapshot-view ok-count: 13 (ci.yml asserts 13)
fm-bearings-snapshot ok-count: 36 (ci.yml asserts 36)

-- 4. .claude/settings.json keeps BOTH SessionStart hooks + 3-command PreToolUse --
SessionStart matcher='startup|resume|clear' cmds=['"$CLAUDE_PROJECT_DIR"/bin/fm-sessionstart-nudge.sh']
SessionStart matcher=None cmds=['"$CLAUDE_PROJECT_DIR"/bin/fm-handoff.sh pickup']
PreToolUse matcher='Bash' cmds=['"$CLAUDE_PROJECT_DIR"/bin/fm-arm-pretool-check.sh --claude', '"$CLAUDE_PROJECT_DIR"/bin/fm-cd-pretool-check.sh --claude', '"$CLAUDE_PROJECT_DIR"/bin/fm-continuity-pretool-check.sh']

-- 5. Deliberate test edits --
fm-pr-merge stub shim now mirrors all bin/*.sh:
  # Mirror every real bin script into the shim dir so SCRIPT_DIR-relative
  # sourcing (fm-pr-lib.sh and its transitive deps) resolves, then shadow only
  # the detector with the stub written below.
  local binfile
  for binfile in "$ROOT/bin/"*.sh; do
    ln -s "$binfile" "$shimbin/$(basename "$binfile")"
  done
  rm -f "$shimbin/fm-assert-tests-kept.sh"

fm-sessionstart-nudge registration assertion (nudge-entry-scoped, not length==1):
11:NUDGE="$ROOT/bin/fm-sessionstart-nudge.sh"
109:  cp "$ROOT/bin/fm-sessionstart-nudge.sh" "$ROOT/bin/fm-primary-scope-lib.sh" \
111:  chmod +x "$root/bin/fm-sessionstart-nudge.sh"
147:  jq -e '[.hooks.SessionStart[] | select(any(.hooks[]?; .command | contains("fm-sessionstart-nudge.sh")))] | length == 1' \

-- 6. Remote branch already matches HEAD (push step is a no-op) --
db46bda0c418c45aa5fbff5f13bb24a0df4491fb	refs/heads/fm/fm-upstream-sync-b3
local HEAD: db46bda0c418c45aa5fbff5f13bb24a0df4491fb
Evidence: fm-fleet-snapshot-view test output (13 ok lines)
ok - empty fleet snapshot and view use explicit absence markers
ok - fixture snapshot covers task rows, backlog rows, pointers, and stable ordering
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: fm-bearings-snapshot test output (36 ok lines)
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
ok - missing, invalid, unreadable, malformed, and timed-out homes stay explicit unknowns
ok - secondmate and per-home child counts are bounded, disclosed, and explicitly expandable
ok - parent decisions remain untrusted contradiction evidence
ok - parent evidence reconciliation distinguishes matching holds, blocks, and decisions
ok - nonprogressing child states are explicit and inconsistent terminal rows invalidate
ok - registry unavailability and bounded truncation remain explicit
ok - repeated snapshots keep the same current landed baseline and ignore prior reports
ok - default output is bounded, local-only, and marks omitted surfaces
ok - TOON and JSON are parity representations of the same model
ok - landed includes secondmate-managed merges alongside main-home merges
ok - default landed selection balances one dominant home with sparse homes
ok - landed selection refills capacity after sparse homes exhaust
ok - landed selection uses deterministic home order when homes exceed the cap
ok - landed selection preserves deterministic home and internal tie ordering
ok - landed selection handles no landed items
ok - --all-landed keeps the complete global landed output
ok - landed stays bounded with per-home + overall caps and omitted[] disclosure
ok - Bearings keeps a live blocker in structured live state and never converts it to Charted Next queue work
ok - action-free items (working/done/queued/landed) do not leak into Captain's Call
ok - the /bearings skill states the four-section chat contract in order, with empty-states and the At Anchor exclusion
ok - a completed scout with decision-like report prose is a pointer, not pending
ok - an authoritative captain hold surfaces end-to-end
ok - current report pointers surface
ok - superseded queued items are dropped by default and restored with --all-queued
ok - --include-prs is the only path that fetches, and it enriches correctly
ok - a partial GitHub failure degrades gracefully
ok - Perl fallback bounds stalled GitHub calls without coreutils timeout
ok - all fleet-sized sections are capped with counted opt-in expansion
ok - live PR enrichment caps repositories with counted expansion
ok - per-repository open-PR caps are disclosed with an expansion knob
ok - projection and TOON rendering failures exit nonzero with diagnostics
Evidence: Merge-critical test runs (pr-merge, sessionstart-nudge, handoff)
== tests/fm-pr-merge.test.sh ==
ok - fm-pr-merge records pr= and pr_head= before invoking gh-axi pr merge
ok - fm-pr-merge propagates a real merge failure without silently succeeding
ok - fm-pr-merge forwards extra flags to gh-axi pr merge after the -- separator
ok - fm-pr-merge refuses before merging when task meta is missing
ok - fm-pr-merge refuses malformed PR URLs before calling gh-axi
ok - fm-pr-merge refuses unsafe PR URL segments before recording state
ok - fm-pr-merge refuses repo override args before recording state
ok - fm-pr-merge does not add default --squash when the caller passes an explicit merge method
ok - fm-pr-merge respects --method=<value> as an explicit merge method
ok - fm-pr-merge refuses to merge when a base test identifier is missing from the branch
ok - fm-pr-merge refuses a kept-name rewritten assertion (check 2) before calling gh-axi
ok - a clean branch whose base tests execute green merges normally
ok - a failing base assertion with a valid captain supersession entry merges normally
ok - a supersession entry missing a required field is not honored
ok - fm-pr-merge parses a GitHub PR URL into gh-axi number and --repo arguments
ok - an unexecuted finding is informational and non-blocking when the project has no exec-gate marker
ok - an unexecuted finding refuses the merge once the project's exec-gate marker exists
ok - missing and failing findings refuse the merge whether or not the exec-gate marker exists
ok - an excused missing finding does not let a gated unexecuted finding through
ok - a legacy single-id supersession entry excuses exactly its own identifier and nothing else
ok - an ids: glob batch entry excuses every identifier it matches
ok - an ids: glob batch entry does not excuse an identifier outside its glob
ok - kind: restricts a batch entry to its own finding class, never excusing a deleted assertion
ok - an ids: * entry with no kind excuses every finding class, as the back-compat contract documents
ok - a supersession entry naming an invalid kind is warned about and never honored
ok - a supersession entry with a field written after reason is warned about and never honored
ok - a field written after reason with no space after its colon is warned about and never honored
ok - a supersession entry repeating kind: is warned about and never honored
ok - a supersession entry repeating ids: is warned about and never honored
ok - a supersession entry carrying both id: and ids: is warned about and never honored
ok - a supersession entry with an unparseable or unrecognized field is warned about and never honored
ok - a supersession entry carrying neither id: nor ids: is warned about and ignored
ok - a findings exit whose output has no parseable finding line refuses as unverified
ok - an unverifiable gate exit still refuses the merge
PASS tests/fm-pr-merge.test.sh
== tests/fm-sessionstart-nudge.test.sh ==
ok - fm-sessionstart-nudge: a genuine primary gets exactly one instruction line
ok - fm-sessionstart-nudge: NO_MISTAKES_GATE is silent
ok - fm-sessionstart-nudge: .no-mistakes gate common-dir is silent
ok - fm-sessionstart-nudge: an unmarked linked task worktree is silent
ok - fm-sessionstart-nudge: a marked linked secondmate home is a primary
ok - fm-sessionstart-nudge: a checkout without state is silent
ok - fm-sessionstart-nudge: a lock holder in process ancestry is already run
ok - OpenCode session.created delivers the exact wrapper nudge once per session
ok - all five verified harnesses register the shared session-start nudge
PASS tests/fm-sessionstart-nudge.test.sh
== tests/fm-handoff.test.sh ==
ok - the /handoff skill keeps its /clear and /stow-delegation contract
ok - fm-handoff path allocates a dated handoff name and never overwrites an existing one
ok - fm-handoff arm refuses missing, empty, and non-private handoff targets
ok - fm-handoff pickup stays a silent no-op with no handoff and in a crewmate worktree
ok - fm-handoff pickup points a fresh session at the exact armed handoff
ok - fm-handoff consume marks a handoff read exactly once and stops it re-announcing
ok - fm-handoff consume refuses to clear a marker pointing at a different handoff
ok - fm-handoff pickup self-heals a marker pointing at a deleted handoff
ok - fm-handoff status reports whether a handoff is pending
ok - the SessionStart pickup hook is registered in tracked settings.json
PASS tests/fm-handoff.test.sh
Evidence: Watcher process-identity test runs (watcher-lock, wake-queue)
== tests/fm-watcher-lock.test.sh ==
ok - simultaneous watcher starts leave exactly one live process
ok - fm_pid_identity is locale-invariant across LC_ALL/LC_TIME
ok - fm_pid_identity is stable across repeated reads of one live pid
ok - fm_pid_parse_start_ticks handles comm containing spaces and parentheses
ok - fm_pid_identity parses a real process whose comm holds a space and a paren
ok - fm_pid_identity falls back to the lstart form when /proc/<pid>/stat is unreadable
ok - fm_pid_identity_matches accepts a live pid's legacy record and rejects a foreign one
ok - fm_pid_identity_matches still rejects dead, recycled, and start-marker-mismatched pids
ok - killed watcher stale lock is reclaimed
ok - live watcher lock with stale heartbeat is actionable
ok - guard banner leads when down with pending wakes (repair-after-drain) and stays silent when fresh
ok - concurrent fm_lock_try_acquire yields exactly one winner
ok - dead-pid stale lock is reclaimed by a single acquirer
ok - concurrent stale-lock steal yields exactly one winner
ok - live steal mutex is not reclaimed
ok - live-held lock is not stolen
ok - empty mid-acquire lock keeps a minimum grace
ok - late original claimant cannot claim a recreated lock
ok - paused mid-acquire claimant backs off to active stealer
ok - watch restart refuses to signal a reused pid
ok - watch restart attaches to a verified healthy peer and later surfaces a successor gap
ok - watcher self-evicts when the lock pid no longer names it
ok - arm turns clean self-eviction without a successor into a typed failure
ok - arm attaches to a live fresh watcher and fails loudly when that cycle has no successor
ok - attached arm signals record a classified lifecycle entry
ok - arm starts+confirms a fresh watcher on a clean lock and self-heals a dead-pid lock (never healthy off a dead pid)
ok - arm cleans child watcher and temp output on HUP
ok - arm propagates an immediate watcher wake before confirmation
ok - arm attaches to a peer watcher after child stands down and surfaces a missing successor
watcher: lock held by live pid 3214364 but heartbeat is stale for 838821161s (>300s); inspect or stop that watcher before re-arming.
ok - arm reports FAILED and exits non-zero when no fresh watcher can be confirmed
ok - cycle-exit ledger links a verified successor and remains size-capped
ok - SIGSTOP distinguishes live PID from stale beacon and termination records the exit class
PASS tests/fm-watcher-lock.test.sh
== tests/fm-wake-queue.test.sh ==
ok - concurrent append plus drain preserves queue records
ok - signal written while no watcher runs is caught on next run
ok - stale wake is queued before suppressor state is advanced
ok - a not-provably-working stale wake is queued before its suppressor is advanced
ok - registered custom check output is queued before cadence suppression
ok - two atomic drains cannot consume the same records twice
ok - drain collapses obvious duplicate heartbeat and signal records
ok - drain asserts watcher liveness: warns on a lapse, stays silent right after a fire
ok - structural signal enrichment is separate, deduped, home-local, and tier-zero for other wakes
ok - bounded reads and per-item/global caps fail open with explicit truncation and omission markers
ok - slow annotation releases the append lock and a deleted status file fails open
ok - interruptions restore before commitment and never replay after raw commitment
PASS tests/fm-wake-queue.test.sh

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 info
  • ℹ️ tests/fm-handoff.test.sh:243 - tests/fm-handoff.test.sh's no-matcher assertion (jq '.hooks.SessionStart[] | has("matcher")' output contains 'false') became imprecise once the merge added a second, matcher-scoped SessionStart entry: it passes if any entry lacks a matcher, rather than asserting the pickup entry specifically is unmatchered. The nudge test was tightened to entry-scoped jq selects during this merge; the handoff test was not given the symmetric treatment. It still guards correctly today since pickup is the only unmatchered entry, but a future third unmatchered SessionStart entry would let a narrowed pickup slip past this assertion.
✅ **Test** - passed

✅ No issues found.

  • command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"
  • Baseline (pre-run): for t in tests/*.test.sh; do bash &#34;$t&#34;; done - all 86 test files passed
  • bash tests/fm-fleet-snapshot-view.test.sh - exit 0 with exactly 13 ok - lines, matching the new ci.yml assertion
  • bash tests/fm-bearings-snapshot.test.sh - exit 0 with exactly 36 ok - lines, matching the new ci.yml assertion
  • bash tests/fm-pr-merge.test.sh, bash tests/fm-sessionstart-nudge.test.sh, bash tests/fm-handoff.test.sh - all pass, covering the two deliberate test edits and the dual SessionStart hook registration
  • bash tests/fm-watcher-lock.test.sh, bash tests/fm-wake-queue.test.sh - pass, exercising the preserved proc-starttime process identity from PR #5
  • git diff --stat 4bf2e94 HEAD -- bin/fm-wake-lib.sh - 165 insertions, 0 deletions; grep confirms proc-starttime prefix and lstart-fallback code intact
  • git diff 4bf2e94 HEAD -- .github/workflows/ci.yml - diff vs main is exactly the 12->13 and 30->36 count changes
  • Inspected .claude/settings.json hooks: nudge SessionStart entry with matcher startup|resume|clear, handoff pickup SessionStart entry, and the three-command PreToolUse Bash hook
  • Inspected AGENTS.md (handoff skill load trigger, exec-gate sentence) and docs/scripts.md (both sides' script rows, main's richer fm-assert-tests-kept.sh description)
  • git ls-remote origin fm/fm-upstream-sync-b3 - remote tip db46bda equals local HEAD, so the pipeline push is a no-op
⚠️ **Document** - 1 info
  • ℹ️ docs/scripts.md - Pre-existing docs/scripts.md coverage gap, not caused by this merge: bin/fm-cd-pretool-check.sh and bin/fm-cd-command-policy.mjs are unlisted while their sibling PreToolUse hooks (fm-arm-* and fm-continuity-*) have rows, and fm-lint.sh, fm-lint-plan.awk, fm-install-shellcheck.sh, and fm-transition-lib.sh are also unlisted. All were equally absent at base 4bf2e94, so this is a follow-up candidate for a session that owns scripts.md coverage, not part of this change.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

kunchenguid and others added 30 commits July 15, 2026 16:13
* Add instruction owners foundation

* no-mistakes(document): Refresh project-management owner pointers
…kunchenguid#626)

* docs: compress firstmate operating contract

* docs: make delivery rigor single-owner

PR B already removed personal and stacked review requirements, but it did not explicitly assign rigor to the selected delivery path or forbid risk-based manual clean gates. That gap still permitted the Hi Bit inversion.

* no-mistakes(review): Honor configured merge authority across faster delivery paths

* no-mistakes(document): Align docs with compressed operating contract
* Add durable captain decision holds

* no-mistakes(review): Validate decision hold retries and origin paths

* no-mistakes(review): Enforce durable decision lifecycle boundaries

* no-mistakes(review): Harden decision display and partial retry recovery

* no-mistakes(test): Update scout teardown fixtures for decision inventory

* no-mistakes(document): Align decision lifecycle and scout teardown documentation

* no-mistakes: apply CI fixes

* no-mistakes(review): Reconcile terminal decision holds

* no-mistakes(document): Align captain decision-hold documentation
* fix: harden PR check artifacts

* fix: close PR check migration gaps

* fix: close PR check retry gaps

* fix: clarify migration outcomes and ESM boundary

* fix: keep failed migrations authoritative

* test: use inert PR validation fixtures

* no-mistakes(review): Reserve noncanonical PR quarantine namespace

* no-mistakes(review): Prevalidate final PR-check teardown artifacts

* no-mistakes(review): Preserve X metadata and validate teardown IDs

* no-mistakes(review): Initialize migration state before watcher exclusion

* no-mistakes(review): Isolate failed poll migrations from bootstrap recovery

* no-mistakes(review): Allow safe polling during incomplete private repairs

* no-mistakes(review): Authenticate watcher checks at execution time

* no-mistakes(review): Preserve custom checks with hash-bound registration

* no-mistakes(review): Clean custom check snapshots on watcher signals

* no-mistakes(review): Stop watcher checks promptly on signals

* no-mistakes(review): Terminate watcher check groups before cleanup

* no-mistakes(document): Correct stale X-mode watcher documentation

* fix: drain returned watcher check groups

* no-mistakes(review): Harden quarantine links and recover validated replacement polls

* no-mistakes(review): Preserve X mode across shim version transitions

* no-mistakes(review): Refresh legacy X shims before marker short-circuits

* no-mistakes(document): Correct persisted PR-check artifact documentation

* no-mistakes(document): Correct stale PR-check documentation

* fix: bind PR poll repair provenance

* no-mistakes(review): Enforce single-link ownership for custom check artifacts

* no-mistakes(review): Preserve private checks, X polling, and lifecycle IDs

* no-mistakes(review): Separate task creation and legacy teardown validation

* no-mistakes(review): Restore safe legacy operations and teardown validation

* no-mistakes(review): Disambiguate migration obligations and preserve legacy retries

* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence

* no-mistakes(review): Reconcile legacy migration retries and teardown collisions

* no-mistakes(review): Force legacy namespace reconciliation before marker short-circuits

* no-mistakes(document): Document private poll artifact safety contracts

* no-mistakes(lint): Suppress intentional literal-dollar lint finding

* fix: migrate historical X poll identity

* fix: harden PR check artifacts

* no-mistakes(review): Preserve fail-closed diagnostics and legacy quarantine evidence

* no-mistakes(review): Reconcile legacy migration retries and teardown collisions

* fix: migrate historical X poll identity

* no-mistakes(review): Harden X-mode artifact publication against symlink corruption

* no-mistakes(review): Guard X artifact publication

* no-mistakes(review): Enforce private X artifact reads

* no-mistakes(test): Fix backend compatibility fixture dependencies

* no-mistakes(document): Refresh PR-check documentation

* no-mistakes(lint): Remove unused x-mode test locals

* no-mistakes: apply CI fixes
* fix: compact session-start backlog digest

* no-mistakes(test): Fix legacy backend fixture helper

* no-mistakes(test): Fix watcher exit wait helper

* no-mistakes(document): Document compact backlog digest
* fix: dedupe stale watcher guard banner

* no-mistakes(review): Keep read-only guard state nonmutating

* no-mistakes(document): Clarify stale watcher docs
* fix: balance bearings landed defaults

* no-mistakes(document): Document balanced landed baseline

* no-mistakes: apply CI fixes
* docs: clarify captain-facing translation contract

* no-mistakes(review): Restore runtime fallback mandate

* no-mistakes(document): Align Bearings translation wording
…#646)

* fix: make bootstrap nudges deterministic

* no-mistakes(review): Honor state override for bootstrap nudges

* no-mistakes(review): Update benign bootstrap documentation labels

* no-mistakes(review): Validate bootstrap nudge retry markers

* no-mistakes(document): Align bootstrap nudge documentation

* no-mistakes: apply CI fixes
…nchenguid#649)

* Clarify concise secondmate registry contract

* no-mistakes(review): Expand secondmate registry boilerplate coverage

* no-mistakes(document): Point route docs to owner
…kunchenguid#654)

* fix(bin): strip quotes on blocked_by in decision-hold resolve

tasks-axi quotes multi-entry blocked_by as "a,b,c", so the comma-boundary
membership test only matched middle elements. Strip surrounding quotes
before matching so first and last hold ids resolve correctly.

* no-mistakes(document): Refresh decision-hold regression evidence
* feat(secondmate): inherit shared captain preferences

* no-mistakes(review): Honor shared captain data overrides

* no-mistakes(review): Honor bootstrap data override registry

* no-mistakes(document): Refresh shared inheritance docs

* no-mistakes(document): Clarify inherited local-material docs
* feat(spawn): gate local agent secret injection

* fix(spawn): align final Keychain slot

* no-mistakes: apply CI fixes
* test: isolate herdr autodetect smoke session

* no-mistakes(review): Restored autodetect smoke gate bypass

* no-mistakes(test): Harden Herdr lab provisioning

* no-mistakes(document): Refresh Herdr lab docs
* fix(pi): distinguish stale locks when arming watcher

* no-mistakes(test): Stabilize watcher extension async waits

* no-mistakes(document): Document Pi lock recovery
* fix: accept secondmate as house vocabulary

* no-mistakes(test): Update captain vocabulary contract test

* no-mistakes(document): Align secondmate documentation vocabulary
…uid#686)

* fix: parse secondmate home after pre-field parentheses

Registry summaries often include parentheticals before the structured
(home: ...) field. Match that field with a greedy prefix so handoff
no longer reports "has no home" for those entries.

* no-mistakes(document): Refresh handoff test comments
* feat: add native session-start nudges

* no-mistakes(document): Document nudge script inventory
…nguid#688)

Relabel absent-captain and related domain defaults wording so it names
the firstmate repo rather than treating "template" as this domain's
identity label. Keep the design-tenet "shared template" statements and
unrelated launch/PR-poll template uses unchanged.
…nsion (kunchenguid#205)

* fix(bin): use set -u-safe empty-array expansion in pr-merge and spawn

Expanding "${arr[@]}" on an empty array under set -u fails on bash < 4.4
(notably macOS bash 3.2). Quote the portable "${arr[@]+"${arr[@]}"}" idiom
in fm-pr-merge and fm-spawn batch dispatch so empty arrays expand to nothing.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(brief): harden fm-brief regression coverage for parse and scaffolds

Tighten bash -n checking, pin literal backtick rendering in the no-mistakes
DOD wording assertion, and keep a scout/secondmate scaffold smoke test so the

Co-authored-by: Cursor <cursoragent@cursor.com>
kunchenguid#166 apostrophe regression cannot return unnoticed.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…nchenguid#693)

* fix: make watcher supervision continuous

* no-mistakes(review): Bound watcher retries and log attached signals

* no-mistakes(review): Add bounded successor-recovery wake fallbacks

* no-mistakes(review): Prevent overlapping successor-arm retries

* no-mistakes(review): Resume supervision after late arm closes

* no-mistakes(review): Bind OpenCode recovery to attempted arm

* no-mistakes(test): Synchronize peer beacon regression fixture

* no-mistakes(test): Synchronize Pi and OpenCode late-close lifecycle fixtures

* no-mistakes(document): Captain: document watcher successor protocol behavior

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes
* fix: always fetch PR head for review diffs

Prefer a freshly fetched refs/pull/<n>/head over a reachable recorded
pr_head= so reviewers never hold a merge over a "missing" fix that already
landed on the remote PR. Recorded SHA is offline fallback only; local branch
is last resort with a warning. Store the tip under refs/fm-review/ so a later
base-branch fetch cannot clobber the compare tip via FETCH_HEAD.

* no-mistakes(test): Isolate session-start nudge tests from gate state

* no-mistakes(document): Correct review-diff documentation
…and skills (kunchenguid#736)

* docs: resolve five contract contradictions

* no-mistakes(test): align owner-pointer assertions with reworded docs; skip absent shellcheck
* docs(harness): reverify grok exit command

* no-mistakes(test): Correct Grok exit resume attribution
* fix(watcher): bound stale wakes for exited paused crew

* no-mistakes(review): Gate pause suppression on confirmed agent death

* no-mistakes(test): Fixed stale pause cadence

* no-mistakes(document): Document dead-agent hold cadence
…id#744)

* fix(supervision): distinguish ordinary wakes from repair

* no-mistakes(review): Make passive guard follow-ups recovery-only

* no-mistakes(document): Clarify recovery-only turn-end guard documentation
* fix(x-mode): dedupe pending mention wakes

* no-mistakes(review): fix x-poll claim error deduplication

* no-mistakes(review): separate claim diagnostics from relay recovery

* no-mistakes(document): Document X-mode once-only mention wakes
…enguid#747)

* feat(wake): enrich drained signal context

* no-mistakes(review): Bound wake enrichment reads

* no-mistakes(document): Document wake-drain annotations

* docs(wake): explain at-least-once drain boundary

* no-mistakes(review): Prevent symlink races in wake annotations

* no-mistakes(review): Exercise wake symlink race regression

* test: document intentional AFK marker subprocesses

* fix(wake): isolate annotation marker state
Brings the fork up to date with upstream (b2bf95f..4ab61fa reached upstream
between dispatch and fetch, so 30 commits landed rather than the 24 counted
at dispatch). All 6 local commits survive; verification below.

What upstream brings, grouped:
- Instruction ownership restructure (kunchenguid#619, kunchenguid#626, kunchenguid#644, kunchenguid#649, kunchenguid#666, kunchenguid#685,
  kunchenguid#688, kunchenguid#736): AGENTS.md compressed 958 -> 479 lines, contracts moved to
  single owners in docs/ and new skills (project-management,
  decision-hold-lifecycle, diagnostic-reasoning), enforced by the new
  tests/fm-instruction-owners.test.sh.
- PR-check security hardening (kunchenguid#556): new fm-pr-lib.sh canonical task-ID and
  PR-URL validation, byte-static fm-pr-poll.sh sidecars, fm-check-register.sh
  and fm-check-lib.sh for custom checks, fm-pr-check-migrate.sh quarantine,
  plus the large tests/fm-pr-check-security.test.sh matrix.
- Watcher and supervision fixes: continuous supervision across child cycles
  (kunchenguid#693), bounded stale wakes for parked crew (kunchenguid#743), recovery vs ordinary
  wake distinction (kunchenguid#744), enriched drained signals (kunchenguid#747), deduped stale
  guard banners (kunchenguid#637), pi stale-lock arming (kunchenguid#681).
- Secondmate: shared captain preferences via data/captain-shared.md (kunchenguid#656),
  handoff-home parsing after registry parentheticals (kunchenguid#686), durable captain
  decision holds (kunchenguid#593) and their quoted blocked_by fix (kunchenguid#654).
- Session start: native session-start nudges (kunchenguid#687), compact backlog digest
  (kunchenguid#636), deterministic bootstrap output (kunchenguid#646), balanced bearings baseline
  (kunchenguid#640).
- Review diffs fetch the current PR head (kunchenguid#722); fm-brief.sh parse and set -u
  hardening (kunchenguid#205); X-mode pending-mention wake dedupe (kunchenguid#745); Herdr smoke
  test isolation (kunchenguid#662); Grok exit-guidance docs (kunchenguid#742); secret-injection
  gate added (kunchenguid#658) and reverted (kunchenguid#668).

Conflicts and resolutions (3 files):
- AGENTS.md: upstream compressed the delivery/yolo section that local commit
  a6d71e7 had extended. Took upstream's compact block and re-added the local
  test-keep-gate stub in the same style: the fm-assert-tests-kept.sh hard
  refusal and the captain-approved data/supersessions/<project>.md routing.
  The local data/supersessions layout line auto-merged. The dropped verbose
  HEAD-side text (Supervise, review-diff, evidence commits) was verified
  relocated by upstream into docs/ and skills, not lost.
- bin/fm-pr-merge.sh: upstream rewrote entry validation around fm-pr-lib.sh
  (canonical ID/URL parsing, symlink-refusing META check); local commits had
  added the test-keep gate and supersession honor logic. Kept upstream's
  validation and structure, reinserted the local gate between pr= recording
  and the gh-axi merge call, and merged both header docs. The gate execution
  block itself auto-merged.
- docs/scripts.md: combined upstream's new script table rows (fm-pr-lib,
  fm-pr-poll, fm-check-register, fm-check-lib, fm-pr-check-migrate) with the
  local fm-assert-tests-kept.sh row; the fm-pr-merge.sh row now names both
  the gate and the canonical-URL contract.

Local work survival, commit by commit:
- 40fa488 (treehouse pool config + reset-accounts skill): treehouse.toml and
  .agents/skills/reset-accounts/SKILL.md present and byte-identical
  (git diff 40fa488..HEAD on both paths is empty).
- eec0f70 (assert a rebase never reduces main's test assertions):
  bin/fm-assert-tests-kept.sh present and untouched by upstream;
  bin/fm-pr-merge.sh still invokes it; docs/architecture.md and
  docs/scripts.md references intact; tests/fm-assert-tests-kept.test.sh all
  green post-merge.
- a6d71e7 (check 2 + captain-approved supersessions): check-2 baseline-run
  logic present in fm-assert-tests-kept.sh; supersession_approved and its
  refusal guidance present in fm-pr-merge.sh; AGENTS.md keeps the
  data/supersessions layout line and the yolo-section gate stub; all 15
  tests/fm-pr-merge.test.sh cases green post-merge, including the gate and
  supersession cases.
- cb6a599, 3b060d5, c55b29a (PR merge commits): reachable unchanged from
  HEAD; a merge was used precisely so no local history was rewritten.

Validation: bin/fm-lint.sh passes; fm-pr-merge, fm-assert-tests-kept,
fm-review-diff, fm-instruction-owners, and fm-pr-check-security suites pass
(the security suite needed a follow-up fixture commit teaching its
merge-success cases to satisfy the local test-keep gate).
fm-pr-merge.sh gates merges on fm-assert-tests-kept.sh, which resolves a real
project repo and task worktree from the task meta. The upstream security
fixtures predate the gate and used bare or missing paths, so every
expected-successful merge was refused with 'could not verify'. Add
write_gate_project and scope the legacy-loop gate worktree to the merge step
so both teardown invocations still exercise the missing-worktree path.
test_output_ordering_diagnostics_lead and test_composition_invokes_real_scripts
forced a MISSING: node diagnostic only by deleting the fakebin node stub, which
silently assumed node is absent from the fallback BASE_PATH
(/usr/bin:/bin:/usr/sbin:/sbin). That holds on GitHub runners but breaks on any
host where apt/nodesource installed /usr/bin/node: command -v node succeeds,
bootstrap correctly reports nothing missing, and both assertions fail.

Reuse the existing tmux masking idiom from
test_herdr_backend_diagnostics_follow_real_session_start: a shared
write_node_mask helper emits a BASH_ENV file overriding command -v node to
fail regardless of PATH, and both tests pass it on their run_session_start
call while keeping the fakebin removal. The assertions themselves are
unchanged; only how node is made to look absent is.
Conflicts resolved by keeping the upstream restructure and folding in
main's semantic additions: the /handoff trigger and exec-gate sentences
in AGENTS.md, both SessionStart hooks (nudge + handoff pickup) in
.claude/settings.json, and both sides' new script rows in docs/scripts.md.
Test seams repaired: the pr-merge stub dir now mirrors bin/*.sh so
SCRIPT_DIR-relative sourcing of fm-pr-lib.sh resolves, and the nudge
test asserts its own SessionStart entry instead of sole registration.
bin/fm-wake-lib.sh merged with zero deletions vs main, preserving the
kernel-start-ticks process identity from PR #5.
tests/fm-pr-check-security.test.sh's write_gate_project and
tests/fm-continuity-pretool-check.test.sh's primary-checkout fixture both
ran bare git commit without fm_git_identity or an inline -c identity, so
they passed on any machine with a global git config and failed exit 128
(empty ident) on a clean CI runner. Call fm_git_identity after sourcing
lib.sh, matching the convention the other nineteen callers use. Audited
all 86 test files for the same latent defect; these two were the only
instances. Full suite passes under a neutralized-identity environment
(GIT_CONFIG_GLOBAL=/dev/null, identity vars unset) and normally.
@kirangathani
kirangathani merged commit 1852b34 into main Aug 2, 2026
5 checks passed
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.

4 participants