Skip to content

feat: expand Firstmate supervision and integrations - #5096

Closed
Ivory2024 wants to merge 25 commits into
kunchenguid:mainfrom
Ivory2024:fm/firstmate-nomistakes-jev-review-assist-20260920
Closed

Ivory2024 wants to merge 25 commits into
kunchenguid:mainfrom
Ivory2024:fm/firstmate-nomistakes-jev-review-assist-20260920

Conversation

@Ivory2024

Copy link
Copy Markdown

What Changed

  • Hardened crew supervision and lifecycle handling across backend selection, cleanup, branch/run attribution, session locking, wake/relaunch flows, teardown, and inactive endpoint reaping.
  • Added self-hosted Discord polling/replies, advisory Jev review-assist configuration, and AGY quota/auth-aware dispatch handling.
  • Added and updated skills, documentation, CI/configuration, review evidence, and broad shell/extension test coverage; removed the legacy CLAUDE.md compatibility pointer.

Risk Assessment

🚨 High: The change introduces an unauthenticated Discord-to-agent execution path and documents a Jev configuration that does not actually enable the claimed behavior.

Testing

Inspected the target diff and trusted Herdr lab contract. No lab was started because these scenarios belong to the external no-mistakes review pipeline, which this phase cannot invoke.

  • Live validation: ⚠️ inconclusive - 0 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Operator enables Jev review assist locally while tracked repository configuration remains free of the unsupported global-only opt-in. ⏸️ untested no Requires no-mistakes v1.79.0+, permitted TYPESAFE_API_KEY, and authorized review execution.
Jev provides only an advisory pre-brief while the ordinary cold review remains authoritative. ⏸️ untested no Requires the external no-mistakes review daemon and audit logs.
Missing Jev credentials or call failures fall back to cold review with a recorded reason. ⏸️ untested no Requires external failure injection and no-mistakes review-step logs.
Jev receives only the reviewable diff and path-only candidate list. ⏸️ untested no Requires the external no-mistakes daemon or authorized request capture; no Jev fixture exists here.
  • Outcome: ⚠️ 1 warning across 2 runs (18m22s)

Pipeline

Updates from git push no-mistakes

⏭️ **intent** - skipped

✅ No issues found.

⚠️ **Rebase** - 1 warning

Confirm these commits belong in this PR before approving, or manually separate the intended work onto origin/main before gating.

⚠️ **Review** - 6 issues (4 errors, 2 warnings)
  • 🚨 .no-mistakes.yaml:12 - The tracked jev.review_assist setting at .no-mistakes.yaml:12-13 is not a supported repository-level opt-in for the no-mistakes daemon, so this branch's documented Jev behavior at docs/configuration.md:245-250 is unreachable. The earlier history explicitly removed this key after verifying the setting is global-only. Choose whether the supported fix is operator-local configuration or a new repository configuration path before merging.
  • ⚠️ docs/configuration.md:257 - The claim that gitignored paths can never appear in a git diff is false at docs/configuration.md:257: an ignored file can be force-added or may already be tracked, making its contents eligible for review transmission. Narrow the data-boundary claim to the actual reviewable-file selection behavior instead of asserting an absolute protection.
  • 🚨 bin/fm-discord-poll.js:119 - Self-hosted Discord accepts any non-bot author who mentions the bot, and any non-bot DM when DMs are enabled, at bin/fm-discord-poll.js:119-126. With no explicit channel list it discovers channels across up to five guilds and all DMs at :66-97; author_handle at :146 is only copied into the payload and does not authenticate the sender. The resulting inbox item uses the same x-mention/fmx-respond path as the owner-authorized Relay, so an unrelated server member or DM sender can trigger agent work on the operator machine. The source and configuration docs (docs/configuration.md:695-699) define channel and DM filters but no authorized-user policy. Decide the allowed author/tenant boundary before shipping; the remedy requires an explicit authorization policy or configuration surface.

🔧 Fix applied.
6 issues (4 errors, 2 warnings) still open:

  • 🚨 bin/fm-discord-poll.js:119 - Self-hosted Discord accepts any non-bot author who mentions the bot, and any non-bot DM when DMs are enabled, at bin/fm-discord-poll.js:119-126. With no explicit channel list it discovers channels across up to five guilds and all DMs at :66-97; author_handle at :146 is only copied into the payload and does not authenticate the sender. The resulting inbox item uses the same x-mention/fmx-respond path as the owner-authorized Relay, so an unrelated server member or DM sender can trigger agent work on the operator machine. The source and configuration docs (docs/configuration.md:695-699) define channel and DM filters but no authorized-user policy. Decide the allowed author/tenant boundary before shipping; the remedy requires an explicit authorization policy or configuration surface.
  • 🚨 bin/fm-discord-poll.js:117 - The fix round corrected Jev scope but left the earlier self-hosted Discord authorization bypass. With no channel allowlist, default DM discovery is enabled (bin/fm-discord-lib.sh:63-68, bin/fm-discord-poll.js:67-97); bin/fm-discord-poll.js:117-127 checks only bot status and mention/DM shape, then :143-192 emits the same x-mention consumed by fmx-respond, whose owner-only contract treats the direct author as the captain. Any non-owner who can DM or mention the bot can trigger normal lifecycle work. The remedy requires an explicit allowed-author/role policy or configuration surface.
  • 🚨 bin/fm-bootstrap.sh:1179 - Self-hosted Discord bootstrap publishes state/discord-watch.check.sh at bin/fm-bootstrap.sh:1179 but never creates its required .check-trust binding. The watcher routes this non-x-watch check through custom-check validation at bin/fm-watch.sh:2384-2413, which requires the trust file via bin/fm-check-lib.sh:48-54; therefore a configured self-hosted Discord poll is rejected and never runs. The existing success message at bin/fm-bootstrap.sh:1188 is consequently false.
  • 🚨 bin/fm-discord-poll.sh:32 - Even if the watcher trust issue is repaired, self-hosted-only mode still cannot consume its own wake: bin/fm-discord-poll.sh:32 emits x-mention with only FM_DISCORD_BOT_TOKEN, while .agents/skills/fmx-respond/SKILL.md:21-24 and AGENTS.md:586-601 make the consumer conditional on FMX_PAIRING_TOKEN. The self-hosted configuration documents only the Discord token at docs/configuration.md:692-700, so the intended direct mode produces a wake that the responder is instructed to ignore.
  • ⚠️ bin/fm-bootstrap.sh:1179 - Both self-hosted artifact publications suppress failure at bin/fm-bootstrap.sh:1179 and :1186, then :1188 always reports the mode as armed. A permission, path, or filesystem failure can therefore leave no usable poll shim or cadence while bootstrap claims activation succeeded.
  • ⚠️ bin/fm-discord-poll.js:105 - After the initial cursor, the poller fetches only one limit=100 page at bin/fm-discord-poll.js:103-106 and advances the cursor to that page's newest message at :194-195. If more than 100 messages arrive between polls, older unseen mentions in the burst are skipped permanently on the next poll instead of being paged until exhausted.
⚠️ **Test** - 1 warning
  • ⚠️ docs/configuration.md:233 - Live evidence for Jev review-assist is unavailable in this assigned phase. It requires the external no-mistakes v1.79+ daemon, an approved TYPESAFE_API_KEY, and review-step audit-log access; this phase cannot invoke pipeline controls.
  • ⚠️ live validation verdict: inconclusive (0 of 4 scenarios were driven live against the product); untested: Operator-local Jev configuration is accepted while tracked repository config remains free of the unsupported global-only opt-in., Jev remains advisory while ordinary cold review remains authoritative., Missing Jev credentials or call failures fall back to cold review with a recorded reason., Jev receives only the reviewable diff and path-only candidates; gitignored status alone is not treated as absolute protection.
  • Live validation: ⚠️ inconclusive - 0 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Operator-local Jev configuration is accepted while tracked repository config remains free of the unsupported global-only opt-in. ⏸️ untested no The no-mistakes config consumer is external to this worktree. Provide a v1.79+ daemon e2e run with permission to exercise the local config loader.
Jev remains advisory while ordinary cold review remains authoritative. ⏸️ untested no Requires the external review daemon, approved TYPESAFE_API_KEY, and review-step execution/log access.
Missing Jev credentials or call failures fall back to cold review with a recorded reason. ⏸️ untested no Fallback and audit logging belong to the external daemon. Provide a permitted failure-injection e2e review run.
Jev receives only the reviewable diff and path-only candidates; gitignored status alone is not treated as absolute protection. ⏸️ untested no Requires controlled external-daemon payload capture with tracked, ignored, and force-added fixtures.
  • git show --stat --oneline HEAD
  • git show HEAD -- .no-mistakes.yaml docs/configuration.md
  • sed -n '1,120p' .no-mistakes.yaml
  • sed -n '228,270p' docs/configuration.md
  • command -v no-mistakes
  • git status --short

🔧 Fix applied.
1 warning still open:

  • ⚠️ live validation verdict: inconclusive (0 of 4 scenarios were driven live against the product); untested: Operator enables Jev review assist locally while tracked repository configuration remains free of the unsupported global-only opt-in., Jev provides only an advisory pre-brief while the ordinary cold review remains authoritative., Missing Jev credentials or call failures fall back to cold review with a recorded reason., Jev receives only the reviewable diff and path-only candidate list.
  • Live validation: ⚠️ inconclusive - 0 of 4 scenarios driven live against the product
Scenario Result Live Evidence
Operator enables Jev review assist locally while tracked repository configuration remains free of the unsupported global-only opt-in. ⏸️ untested no Requires no-mistakes v1.79.0+, permitted TYPESAFE_API_KEY, and authorized review execution.
Jev provides only an advisory pre-brief while the ordinary cold review remains authoritative. ⏸️ untested no Requires the external no-mistakes review daemon and audit logs.
Missing Jev credentials or call failures fall back to cold review with a recorded reason. ⏸️ untested no Requires external failure injection and no-mistakes review-step logs.
Jev receives only the reviewable diff and path-only candidate list. ⏸️ untested no Requires the external no-mistakes daemon or authorized request capture; no Jev fixture exists here.
  • git diff 1bb72cc5f88014c86e3d03244efa0bb26c22d001 bcaf6c279915886dbb88588f3e253aff065d306d -- .no-mistakes.yaml docs/configuration.md
  • sed -n '1,240p' docs/herdr-backend.md
  • sed -n '1,180p' bin/fm-herdr-lab.sh
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

irene and others added 25 commits September 19, 2026 08:04
…ate-20260919

feat: gate fresh CLAUDE.md pointer creation on Claude Code version >= 2.1.277
…tage 2) (#2)

* feat(bin): complete stage 2 CLAUDE.md pointer removal

* no-mistakes(review): Restore column-0 heredoc regression fixture with generic content

* no-mistakes(review): Remove stale CLAUDE.md pointer claim from updatefirstmate skill

---------

Co-authored-by: irene <irene@ireneui-MacBookPro.local>
Prior commits on this branch regressed past stage2, restoring the
unconditional CLAUDE.md pointer-write logic stage2 removed. Reset to
fork/main (stage2's merged head) and redo stage3 correctly: delete the
now-dead fm_version_at_least/claude_supports_native_agents_md functions
and their header-comment reference, and drop the now-vestigial
with_mock_claude/with_no_claude test helpers (the script no longer
reads claude --version at all).

Co-authored-by: irene <irene@ireneui-MacBookPro.local>
…eering skills (#4)

* feat: add lazy specialist tool routing

Expose ECC, paperthin, and ultrawork as captain-approved specialist paths while keeping Firstmate intake and lifecycle authority. Load only the selected skill or mode and keep ECC hooks, MCP, and legacy sync opt-in.

* docs(agents): recover firstmate-layout and task-steering skills

These two skills existed only on an orphaned local branch, never pushed.
firstmate-layout is re-extracted from AGENTS.md section 2's current
(much larger) layout tree rather than reusing the stale 2026-09-14
snapshot. task-steering's underlying AGENTS.md paragraph was byte-identical
to the 2026-09-14 extraction, so it is reused as-is. Both get a one-line
trigger in section 13 and a documentation-audiences.json entry, matching
how specialist-tools (recovered earlier on this branch) is registered.

---------

Co-authored-by: irene <irene@ireneui-MacBookPro.local>
Co-authored-by: irene <irene@ireneui-MacBookPro.local>
.treehouse/ holds only runtime pool bookkeeping (treehouse-state.json,
treehouse-state.lock), never captain work, but its absence from
.gitignore makes it show up as an untracked dirty-tree blocker for
bin/fm-update.sh's self-update fast-forward check.

Co-authored-by: irene <irene@ireneui-MacBookPro.local>
* fix(dispatch): expose AGY auth-required quota cause

* no-mistakes(review): Guarded auth-required AGY ranking with regression coverage

* no-mistakes(document): Document AGY auth-required resolver behavior

* no-mistakes(review): Normalize auth errors; preserve unranked AGY dispatch safety

* no-mistakes(review): Guard auth-required AGY from stale quota wake classification

* no-mistakes(review): Guard auth-required AGY ranking and surface exact cause

* no-mistakes(review): Preserve auth-required AGY floors as unverifiable

* no-mistakes(document): Document AGY auth-required quota behavior

* test(quota): keep unknown-row fixture malformed

* no-mistakes(review): Remove unreachable AGY and unused auth-cause code

* no-mistakes(document): Updated documentation for quota and terminal cleanup

* no-mistakes(review): Remove stale AGY chooser documentation claim

* no-mistakes(review): Restored migration trigger and terminal ledger reaping

* no-mistakes(review): Removed stale memory path and redacted local evidence paths

* no-mistakes(review): Updated stale chooser evidence and verified legacy migration

---------

Co-authored-by: irene <irene@ireneui-MacBookPro.local>
#9)

* fix(bin): preserve Claude lock ownership after helper recycling (kunchenguid#4894)

* fix(bin): let a background Claude session keep owning its session lock

Session-lock ownership was decided by process ancestry alone. Under an
unattended Claude session the model loop runs in a transient bg-spare
bridged to the front-end by a shared daemon; when that bridge is
recycled the contiguous claude-named ancestry from a hook to the
recorded owner breaks while the owner pid stays alive, so the Stop
auto-arm stood down as a foreign live owner, the turn-end guard ended
every turn with its read-only diagnostic, and fm-lock.sh refused - a
self-sustaining outage until restart.

Ownership is now ancestry membership OR a trusted same-session id,
never id-first:

- fm-session-lock-lib.sh accepts CLAUDE_CODE_SESSION_ID only when
  CLAUDE_PID is a Claude-shaped member of the current contiguous run,
  compares it against the id recorded in state/.lock-session, and
  requires the recorded pid to still be a live harness. No id, no
  sidecar, an untrusted id, a different id, or a dead recorded pid
  leaves the ancestry verdict unchanged. Ids are never read from ps
  argv.
- fm-lock.sh accepts a same-session holder at both refusal sites,
  writes, refreshes, and clears the sidecar only under its claim lock
  (including the early already-mine exit, skipped only while the
  deferred startup sweep leases that lock), keeps it byte-identical
  across a same-session confirmation, records CLAUDE_PID on lock line 1
  for a session with a trusted id so a shared daemon or front-end that
  outlives the session never keeps a dead session's lock alive, never
  rewrites a live line 1 on a same-session confirmation, and names the
  recorded id in the live-owner refusal.
- The .lock line-1 format is unchanged, so every reader that takes the
  whole first line as the pid keeps working; the guard's foreign-owner
  exit is unchanged and inherits the fix through the shared predicate.

Tests: the ancestry suite drives the ancestry and id signals apart in a
deterministic process table (asserting the divergence) and runs a real
orphaned front-end/daemon/pty-host/spare tree through six phases with
the real lock, auto-arm, and guard scripts; the foreign-owner repro
keeps its negative control and adds a same-id positive control.

Disclosure: no live unattended Claude background session ran on the
verifying machine. The topology is documented by the real process
listings in kunchenguid#3902, kunchenguid#2314, kunchenguid#3398, and kunchenguid#4066; coverage is the structural
predicate plus the executable fixtures, not a live pass.

Residual: bin/fm-sessionstart-nudge.sh keeps its own private ancestry
walk (it only decides whether to print a nudge) and may nudge on a
resume in the recycled case.

Out of scope, deliberately: no structured lock format, no guard budget
changes, no daemon-identity rejection, no fork lineage.

* no-mistakes(review): Wait for claim lock; revert failed sidecars

* no-mistakes(review): Revalidate ownership after wait; restore sidecars

* no-mistakes(review): Roll back sidecar by publication phase

* no-mistakes(review): Restore sidecar only if lock line is unchanged

* no-mistakes(review): Trust session ids without a spelling allowlist

* no-mistakes(review): Disarm sidecar rollback before backup cleanup

* no-mistakes(document): Updated session-lock ownership documentation

* feat: park main under the away posture on Pi (kunchenguid#4889)

* feat: park main under the away posture on Pi

While the away-posture record exists on a Pi primary, the supervision branch
takes every actionable wake, no processing turn opens on main, captain rows
accumulate for the return brief, and main's standing authority relocates to
the branch through the existing guarded scripts.

- lib/fm-branch-dispatch.ts: read the record at every routing decision; while
  it exists claim check, decision-owned, and heartbeat rows too, keeping the
  two broken-queue vetoes; expose checkSeqs so a claimed check row lifts task
  scoping.
- fm-primary-pi-watch.ts: offer every actionable row under the record; a
  declined wake and every watcher-failure alarm still reach main.
- fm-branch-supervision.ts: drop the legacy .afk decline; append a fixed
  POSTURE: AWAY tail carrying the record's read-back verbatim per wake; open no
  processing request while the record exists, re-checked immediately before a
  request would open and at every run boundary; present the accumulated rows
  at the first run boundary after archive.
- fm-lease-lib.sh: fm_lease_forbid_branch passes the branch for opted-in
  actions only while fm-afk-contract.sh validate succeeds on a confirmed live
  record; PR merge, fresh spawn, and decision answer opt in, local landing
  never does.
- fm-send.sh: a --resolve-key naming an open needs-decision or captain-held
  task is a decision answer and meets the partition; blocked: keys stay
  steering.
- fm-spawn.sh: enforce the record's spend cap for a fresh ordinary spawn by
  either actor; relaunches and secondmates exempt.
- fm-branch-prompt.sh: fixed Postures section and the verbatim
  ask-user-authority policy; the prefix stays byte-stable.
- fm-afk-return.sh: count what the away session handled from the store.
- docs, afk skill, AGENTS.md stub: main parked on Pi, green merge gate
  absolute while away.
- tests: watcher and branch extension suites, fleet-record, merge, and
  decision-answer suites cover the relocation, the vetoes, the tail, the
  parked processing turn, the cancellation, the re-presentation, and the
  spend cap; dated live-guard evidence recorded.

* no-mistakes(review): Refuse branch merge after preflight archive race

* no-mistakes(review): Fix away wake, spawn, and processing races

* no-mistakes(review): Suppress parked processing; narrow away-only rejection

* no-mistakes(review): Abort dedicated processing; gate branch spawn once

* no-mistakes(review): Stamp away-only on the dispatch offer

* no-mistakes(review): Treat invalid away records as spend-cap absence

* no-mistakes(review): Drop spawn test hook; abort processing-opened runs

* no-mistakes(review): Bind abort to opening prompt; cap-read absence

* no-mistakes(review): Limit away branch spawn to queued work only

* no-mistakes(document): Correct AFK posture documentation

* ci: standardize workflow timeouts into three tiers (kunchenguid#4910)

* ci: simplify CI job timeouts to a three-tier policy

Replace the scattered per-job timeout values (10m parallel, 25m lint, 30m
serial, 10m macOS) with three readable tiers, each a hang tripwire with
headroom rather than a packing estimate:

- fast (5m): coverage guard, repo invariants, timing aggregate
- normal (30m, one shared budget): lint partitions, portable parallel
  shards, portable serial shards, macOS stock Bash
- heavy (Herdr only): 20m step tripwire on the family run so always()
  cleanup still runs, under a 75m job-level last-resort backstop

The workflow's header comment states the policy and points at
docs/fm-test-portable-shards.md "Timeouts", which now owns it, and each
job names its tier beside timeout-minutes. tests/fm-ci-workflow.test.sh
asserts the policy against the parsed workflow instead of the old
per-job minute values: every job joins exactly one tier, exactly three
distinct job-level values exist, the fast tier stays within 5-10
minutes, the normal budget stays at least double the modeled parallel
lane sum reported by fm-test-run.sh --check-coverage, and the Herdr step
tripwire stays below its job backstop with an always() cleanup after it.

Concurrency supersession, shard counts, lane membership, and fail-fast
settings are unchanged.

* no-mistakes(review): Decouple the normal timeout from packing estimates

* no-mistakes(review): Assert Herdr teardown follows the family run

* no-mistakes(review): Pin Herdr family-run timeout to 20 minutes

* no-mistakes(review): Ignore comments when identifying Herdr steps

* no-mistakes(review): Identify Herdr steps by declarative ids

* no-mistakes(document): Clarify authoritative three-tier timeout policy

* fix(guard): allow root x-mode config paths

* fix(tests): resolve timing race in remote backlog handoff test

* no-mistakes(review): Fix conflict marker and Orca reaping; unrelated focused test failure

* no-mistakes(review): Fix validated reaping, PR fallback, and config test mappings

* no-mistakes(review): Restore active-home-only x-mode approval

* no-mistakes(document): Correct layout reference ownership label

---------

Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com>
Co-authored-by: irene <irene@ireneui-MacBookPro.local>
* fix(bin): preserve Claude lock ownership after helper recycling (kunchenguid#4894)

* fix(bin): let a background Claude session keep owning its session lock

Session-lock ownership was decided by process ancestry alone. Under an
unattended Claude session the model loop runs in a transient bg-spare
bridged to the front-end by a shared daemon; when that bridge is
recycled the contiguous claude-named ancestry from a hook to the
recorded owner breaks while the owner pid stays alive, so the Stop
auto-arm stood down as a foreign live owner, the turn-end guard ended
every turn with its read-only diagnostic, and fm-lock.sh refused - a
self-sustaining outage until restart.

Ownership is now ancestry membership OR a trusted same-session id,
never id-first:

- fm-session-lock-lib.sh accepts CLAUDE_CODE_SESSION_ID only when
  CLAUDE_PID is a Claude-shaped member of the current contiguous run,
  compares it against the id recorded in state/.lock-session, and
  requires the recorded pid to still be a live harness. No id, no
  sidecar, an untrusted id, a different id, or a dead recorded pid
  leaves the ancestry verdict unchanged. Ids are never read from ps
  argv.
- fm-lock.sh accepts a same-session holder at both refusal sites,
  writes, refreshes, and clears the sidecar only under its claim lock
  (including the early already-mine exit, skipped only while the
  deferred startup sweep leases that lock), keeps it byte-identical
  across a same-session confirmation, records CLAUDE_PID on lock line 1
  for a session with a trusted id so a shared daemon or front-end that
  outlives the session never keeps a dead session's lock alive, never
  rewrites a live line 1 on a same-session confirmation, and names the
  recorded id in the live-owner refusal.
- The .lock line-1 format is unchanged, so every reader that takes the
  whole first line as the pid keeps working; the guard's foreign-owner
  exit is unchanged and inherits the fix through the shared predicate.

Tests: the ancestry suite drives the ancestry and id signals apart in a
deterministic process table (asserting the divergence) and runs a real
orphaned front-end/daemon/pty-host/spare tree through six phases with
the real lock, auto-arm, and guard scripts; the foreign-owner repro
keeps its negative control and adds a same-id positive control.

Disclosure: no live unattended Claude background session ran on the
verifying machine. The topology is documented by the real process
listings in kunchenguid#3902, kunchenguid#2314, kunchenguid#3398, and kunchenguid#4066; coverage is the structural
predicate plus the executable fixtures, not a live pass.

Residual: bin/fm-sessionstart-nudge.sh keeps its own private ancestry
walk (it only decides whether to print a nudge) and may nudge on a
resume in the recycled case.

Out of scope, deliberately: no structured lock format, no guard budget
changes, no daemon-identity rejection, no fork lineage.

* no-mistakes(review): Wait for claim lock; revert failed sidecars

* no-mistakes(review): Revalidate ownership after wait; restore sidecars

* no-mistakes(review): Roll back sidecar by publication phase

* no-mistakes(review): Restore sidecar only if lock line is unchanged

* no-mistakes(review): Trust session ids without a spelling allowlist

* no-mistakes(review): Disarm sidecar rollback before backup cleanup

* no-mistakes(document): Updated session-lock ownership documentation

* feat: park main under the away posture on Pi (kunchenguid#4889)

* feat: park main under the away posture on Pi

While the away-posture record exists on a Pi primary, the supervision branch
takes every actionable wake, no processing turn opens on main, captain rows
accumulate for the return brief, and main's standing authority relocates to
the branch through the existing guarded scripts.

- lib/fm-branch-dispatch.ts: read the record at every routing decision; while
  it exists claim check, decision-owned, and heartbeat rows too, keeping the
  two broken-queue vetoes; expose checkSeqs so a claimed check row lifts task
  scoping.
- fm-primary-pi-watch.ts: offer every actionable row under the record; a
  declined wake and every watcher-failure alarm still reach main.
- fm-branch-supervision.ts: drop the legacy .afk decline; append a fixed
  POSTURE: AWAY tail carrying the record's read-back verbatim per wake; open no
  processing request while the record exists, re-checked immediately before a
  request would open and at every run boundary; present the accumulated rows
  at the first run boundary after archive.
- fm-lease-lib.sh: fm_lease_forbid_branch passes the branch for opted-in
  actions only while fm-afk-contract.sh validate succeeds on a confirmed live
  record; PR merge, fresh spawn, and decision answer opt in, local landing
  never does.
- fm-send.sh: a --resolve-key naming an open needs-decision or captain-held
  task is a decision answer and meets the partition; blocked: keys stay
  steering.
- fm-spawn.sh: enforce the record's spend cap for a fresh ordinary spawn by
  either actor; relaunches and secondmates exempt.
- fm-branch-prompt.sh: fixed Postures section and the verbatim
  ask-user-authority policy; the prefix stays byte-stable.
- fm-afk-return.sh: count what the away session handled from the store.
- docs, afk skill, AGENTS.md stub: main parked on Pi, green merge gate
  absolute while away.
- tests: watcher and branch extension suites, fleet-record, merge, and
  decision-answer suites cover the relocation, the vetoes, the tail, the
  parked processing turn, the cancellation, the re-presentation, and the
  spend cap; dated live-guard evidence recorded.

* no-mistakes(review): Refuse branch merge after preflight archive race

* no-mistakes(review): Fix away wake, spawn, and processing races

* no-mistakes(review): Suppress parked processing; narrow away-only rejection

* no-mistakes(review): Abort dedicated processing; gate branch spawn once

* no-mistakes(review): Stamp away-only on the dispatch offer

* no-mistakes(review): Treat invalid away records as spend-cap absence

* no-mistakes(review): Drop spawn test hook; abort processing-opened runs

* no-mistakes(review): Bind abort to opening prompt; cap-read absence

* no-mistakes(review): Limit away branch spawn to queued work only

* no-mistakes(document): Correct AFK posture documentation

* ci: standardize workflow timeouts into three tiers (kunchenguid#4910)

* ci: simplify CI job timeouts to a three-tier policy

Replace the scattered per-job timeout values (10m parallel, 25m lint, 30m
serial, 10m macOS) with three readable tiers, each a hang tripwire with
headroom rather than a packing estimate:

- fast (5m): coverage guard, repo invariants, timing aggregate
- normal (30m, one shared budget): lint partitions, portable parallel
  shards, portable serial shards, macOS stock Bash
- heavy (Herdr only): 20m step tripwire on the family run so always()
  cleanup still runs, under a 75m job-level last-resort backstop

The workflow's header comment states the policy and points at
docs/fm-test-portable-shards.md "Timeouts", which now owns it, and each
job names its tier beside timeout-minutes. tests/fm-ci-workflow.test.sh
asserts the policy against the parsed workflow instead of the old
per-job minute values: every job joins exactly one tier, exactly three
distinct job-level values exist, the fast tier stays within 5-10
minutes, the normal budget stays at least double the modeled parallel
lane sum reported by fm-test-run.sh --check-coverage, and the Herdr step
tripwire stays below its job backstop with an always() cleanup after it.

Concurrency supersession, shard counts, lane membership, and fail-fast
settings are unchanged.

* no-mistakes(review): Decouple the normal timeout from packing estimates

* no-mistakes(review): Assert Herdr teardown follows the family run

* no-mistakes(review): Pin Herdr family-run timeout to 20 minutes

* no-mistakes(review): Ignore comments when identifying Herdr steps

* no-mistakes(review): Identify Herdr steps by declarative ids

* no-mistakes(document): Clarify authoritative three-tier timeout policy

* fix(bin): keep supervisor status closes from waking the same home (kunchenguid#4895)

* fix(bin): keep supervisor status closes from waking the same home

A drain that already folded OPEN DECISIONS has presented those bytes even
when the watcher has no matching seen marker. Treat that fold, and the
presentation cursor, as known so the bookkeeping close stays quiet while
later worker lines still signal.

* no-mistakes(review): Keep folded worker failures waking past supervisor closes

* no-mistakes(review): Wake on unlisted folded worker lines; batch multi-key closes

* no-mistakes(review): Stop folded worker resolved lines from counting as already read

* no-mistakes(document): Correct self-announced close marker contract in docs

* fix(bin): stop labeling Herdr as experimental (kunchenguid#4972)

* Stop steering operators away from Herdr

* no-mistakes(review): Neutralize remaining Herdr opt-out documentation wording

* fix(bin): treat a live no-mistakes run as current after rebase (kunchenguid#4973)

* fix(bin): treat a live no-mistakes run as current after rebase

A running run on the task's branch is authoritative regardless of head.
Matching only the local head made a rebased in-flight run look failed.

* no-mistakes(review): restrict coarse live-any-head to foreign-branch answers

* no-mistakes(review): reject gate-parked runs from the executing predicate

* no-mistakes(review): hoist gate-marker patterns into single run-lib owner

* no-mistakes(review): require live daemon for head-free run binding

* no-mistakes(review): require answered daemon-down before unbinding live runs

* no-mistakes(review): extend daemon guard to anchored continuation routes

* no-mistakes(review): delete live-any-head; restore dead-daemon verdict

* no-mistakes(review): keep parked gates parked; name dead daemon everywhere

* no-mistakes(review): set dead-daemon verdict instead of emitting early

* no-mistakes(review): align selected route with legacy dead-daemon handling

* no-mistakes(review): drop unproven-record binds; narrow coarse gate reading

* no-mistakes(review): narrow header, drop vestigial guard, retarget tests

* no-mistakes(review): revert coarse gate override; require answered-down probe

* no-mistakes(review): cache one daemon probe; stop duplicating run id

* no-mistakes(review): restrict coarse dead-daemon verdict to moved-off rows

* no-mistakes(review): delete coarse dead-daemon extension and gate note

* no-mistakes(review): delete remaining coarse dead-daemon block and stale docs

* no-mistakes(document): document rebase-safe live-run bind and unverified-record verdict

* fix(bin): prevent long worker launch command truncation (kunchenguid#4994)

* fix(bin): stage the launch command in a private file and type a short source line

A long launch line typed while the fresh pane shell is still busy waits in the
terminal's canonical line buffer, which drops input past about 1,024 bytes on
macOS, so the pane was left at an unfinished command with no agent running.
fm-spawn now writes the assembled command to the task's own temp root under
umask 077 and types only a short line that sources it.

Refs kunchenguid#4559

* fix(bin): keep the per-task temp root private before staging the launch command

The root lives at a predictable path under /tmp and now holds the whole launch
command. Create it with mode 0700, refuse one that already exists as anything but
a directory owned by this user that nobody else can write, and tighten an owned
one, so no other local user can plant or swap the staged file.

Refs kunchenguid#4559

* fix(bin): enforce private staged launch file mode

* test(spawn): cover long staged Claude launches

* no-mistakes(review): Namespace launch files and prove truncation staging

* no-mistakes(review): Use immutable per-spawn launch filenames

* no-mistakes(document): Document staged launch delivery safeguards

* no-mistakes(ci): Updated eight behavior tests/fakes to execute or inspect immutable staged launch files instead of expecting inline launch commands. This restores Muse, secondmate lifecycle/restart, remote trace/parent binding, compact-adviser, and Orca coverage. All affected tests, dispatch-profile regression, fixture tests, syntax checks, ShellCheck, and git diff checks pass

---------

Co-authored-by: Vytautas Stankus <svycka@gmail.com>

* test: authorize isolated Herdr lab validation (kunchenguid#4998)

* Add isolated Herdr runbook to test instructions

* no-mistakes(review): Drop substring matching from test.instructions contract

* no-mistakes(review): Assert commands.test key absence in YAML

* Drop unit-first sentence and instructions contract test

Captain-scoped follow-up on the Herdr-lab test.instructions ship:
keep the lab safety runbook only, and leave the no-mistakes contract
test focused on commands.test absence.

* docs(vision): accept vendor-semantics and 9k AGENTS ceiling (kunchenguid#4873) (kunchenguid#5001)

* docs(vision): accept vendor-semantics and 9k contract-ceiling amendments (kunchenguid#4873)

Replace the pixels-of-today's-UI rule with a quarantined, version-pinned
surface-adapter exception recorded as standing debt. Cap the always-loaded
contract at 9,000 words and require prune-or-trigger before a crossing change
lands.

Co-authored-by: Kun Chen <kunchenguid@users.noreply.github.com>

* docs(vision): restore accepted three-sentence vendor-semantics form (kunchenguid#4873)

Replace the compressed paraphrase with the issue's accepted wording:
a named quarantined version-pinned adapter, expected to break, recorded
as standing debt that never hardens into a shared contract.

Co-authored-by: Kun Chen <kunchenguid@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Kun Chen <kunchenguid@users.noreply.github.com>

* feat(bin): defer the wedge escalation for a lane parked at a supervisor-owed gate (kunchenguid#4974)

* fix(watch): recheck a gate awaiting a human instead of wedge-escalating it

A lane whose validation run is parked at a gate waiting on a human
decision is correctly quiet, but nothing in its status line says so: the
evidence is the pipeline's own gate state rather than anything the worker
wrote. The wedge timer read that silence as a suspected wedge and climbed
the escalation ladder for as long as the wait lasted, and each escalation
cost a supervising turn. The landed declared-wait consult does not reach
it, because a live ordinary crewmate never reports a declared pause, and
raising FM_STALE_ESCALATE_SECS would delay genuine wedge detection for
every lane by the same amount.

The threshold now reads a second, independent record when the status line
accounts for nothing: whether the crew's current state is a gate whose
answer is owed by a human. That is minted only from the gate's own
findings table, by a row whose `action` column is exactly `ask-user`,
located by position out of the table header the way nm_gate_step_row
already reads its row - never searched for over the run payload, where a
finding's free-text description or a branch name satisfies a search just
as well. A gate awaiting the CREWMATE's own answer keeps the unchanged
escalation schedule, reason and demand-deep-inspection wording, because a
crewmate that goes quiet before answering its own gate is exactly the
wedge the ladder exists to catch.

Each kind of wait now carries the human it is on, the action that clears
it, and whether that human is the captain as data alongside the verdict,
rather than as wording chosen per branch where the recheck is written, so
the deferral cannot word one kind of wait as another and a new kind
cannot ship without deciding all of them. A parked gate has no written
record of when its wait began, so its recheck publishes no wait age at
all rather than one read from the quiet window this deferral resets on
every pass, which would report the same small number for a gate of any
age. Like every other captain-facing recheck here it is absorbed in
silence while the away-posture record exists, arming no throttle, so the
recheck is owed in full the moment the record is archived.

The consult runs only in the at-threshold branch that was about to
escalate, beside the worktree walk already there, and only for lanes
whose status line explained nothing.

Closes kunchenguid#3055

* no-mistakes(review): require an unanswered decision before deferring a parked gate

* no-mistakes(review): reset the away-silenced timer, fail-safe findings parse, US-joined wait records

* test(watch): pass the pane hash wedge_timer_check now takes

Upstream gave wedge_timer_check a sixth <pane-hash> argument for its
dead-record probe. The malformed-wait-record rounds drive the real function
directly, so they pass one, and stub fm_backend_agent_state to a live agent so
the probe that runs after a refused deferral keeps the unchanged ladder rather
than reading a backend the child shell has none of.

* no-mistakes(review): Bind parked-gate wait to its run, owe it firstmate

* no-mistakes(document): correct wait-kind count, crew-state reader scope, gate-key coupling

* feat(watch): make the parked-gate wait deferral opt-in

The wedge timer deferring a lane parked at a validation gate is new
supervision behaviour rather than a restored one, and it decides which
lanes give up the escalation ladder, so it now ships as a default-off
per-home option instead of changing every home on upgrade.

config/wedge-defer-parked-gate arms it. The flag is read before the
decision fold, so an unconfigured home spends no fold or current-state
read, writes no record, and keeps the unchanged escalation schedule,
reasons and demand-deep-inspection wording; a test counts the reader
calls in both directions to pin that.

It is not inherited by secondmate homes: each home supervises its own
crew and owns that trade separately, the same reason
config/turnend-churn-absorb is home-local.

The away-posture absorb returns to leaving the idle timer alone, which
it had restarted only because the costly consult could reach it. A
parked-gate wait is owed to the supervisor rather than the captain, so
it never enters that branch, and the recheck owed on return is again
owed in full the moment the record is archived.

* test(watch): pin that the away-silenced hold leaves the idle timer alone

The absorb no longer restarts the timer, so the recheck owed on return is
owed in full rather than a cadence into the return. Nothing asserted
that, so a restart could be reintroduced silently.

* no-mistakes(review): document away-silence rationale, pin captured gate component

* no-mistakes(test): anchor gate row scan to the braced findings header

* no-mistakes(document): pin same-block gate row invariant in crew-state comment

* fix(bin): reclaim a task whose herdr endpoint was destroyed (kunchenguid#5007)

* fix(control): let the owning seat reclaim a task whose endpoint is gone

A destroyed pane or workspace made `missing` a terminal state. Relaunch
accepted only `dead` and said to stop the agent first; exit refused
`missing` and said to reconcile the task first; there is no reconcile
verb. Each command named the other as its prerequisite, so a task whose
terminal went away could not be reclaimed by anything, and a no-mistakes
approval it was parked on had no seat left to answer it.

`missing` is agent-free a fortiori: there is no endpoint, so there is no
agent in it. Widen the existing guards rather than add a verb.

- fm-spawn --relaunch accepts a positively proven `missing` and creates
  one fresh endpoint in the recorded worktree; the record it already
  republishes rebinds the task to it. A `dead` endpoint is still adopted
  in place.
- fm-control exit reports `endpoint-gone` instead of dying, so the
  relaunch transaction's stop step no longer dead-ends, and re-resolves
  the endpoint from the record before verifying the replacement.

The duplicate-agent refusal is untouched: both verdicts come from the
same recovery-grade classifier, which claims `missing` only from positive
absence, so `alive`, `ambiguous`, and `unreadable` all still refuse. The
backends' own create paths refuse a live same-labeled endpoint as a
second independent guard. The worktree, its branch, commits, uncommitted
changes, armed poll and registration, record rows, and status log are all
untouched - a reclaim is a recovery, never a teardown.

A secondmate is excluded: its gone-endpoint recovery already has one
owner in the session-start liveness sweep, so relaunch refuses and names
it rather than becoming a second path to the same outcome.

Tests reproduce both halves of the deadlock, the reclaim succeeding,
unlanded work surviving it, and the refusals that still hold.

* no-mistakes(review): prove endpoint absence per backend before reclaim rebinds

* no-mistakes(review): give exit and relaunch one absence proof; pin herdr rebind session

* no-mistakes(review): narrow endpoint reclaim to herdr; tmux refuses honestly

* no-mistakes(review): stop refusals and docs asserting unestablished causes

* no-mistakes(review): stop herdr fixture helper losing tmp-root registration

* no-mistakes(review): document workspace drift and absence-probe server residue

* no-mistakes(review): correct rebind limitation to its one reachable case

* no-mistakes(review): stop claiming reclaim leaves instructions untouched

* no-mistakes(document): scope fm-control-lib purity claim, note reclaim coverage

* no-mistakes(rebase): read the staged launch file in the herdr fixture

Rebasing onto main picked up kunchenguid#4994, which stages a long worker launch
command into a script and delivers the short `. '<path>'` line instead of
the literal command. The tmux fake and tests/fixtures.sh were updated for
that; the herdr fake this branch adds was written before it and still
keyed "an agent now exists on this pane" off the literal
`encode launch-brief` text, so after the rebase it never marked the
rebound pane live and the reclaim's alive-wait read `dead`.

Dereference the staged file first, exactly as the tmux fake above does.
Test-fixture only; no production path changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* no-mistakes(document): note reclaim placement in herdr and scripts inventories

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(bin): stamp status events with their emission time (kunchenguid#3764)

* test(status): reproduce missing event emission time

* wip(status): preserve optional event emission time

* test(status): document indirect clock stub invocation

* no-mistakes(review): Preserve historical status bytes during reply recovery

* no-mistakes(test): Fix timestamped status assertions and remote fixture dependencies

* no-mistakes(review): Preserve captain regex overrides for timestamped status events

* no-mistakes(document): Clarify status event timing and publication contracts

* no-mistakes(lint): Quote literal done to satisfy ShellCheck

* no-mistakes(ci): Captain, updated .github/workflows/ci.yml to expect 19 snapshot tests instead of 18, matching the PR’s added regression. Reproduced the failure before the fix. Stock Bash 3.2.57 verification passed: parse sweep, 19 snapshot tests, 53 Bearings tests, and the public-followup regression. Workflow lint and diff checks passed

* no-mistakes(test): Preserve terminal notifications with malformed timestamp tags

* no-mistakes(test): Stamp Rovo spawn failures with emission time

* no-mistakes(document): Verify status event documentation

* no-mistakes(lint): Fix ShellCheck quoting in status emission-time tests

* no-mistakes(ci): Captain, fixed four lifecycle assertions to accept emission timestamps while preserving publication and retry checks. Reproduced the CI failure before the fix. The lifecycle suite now passes with six Beads capability skips; syntax, targeted ShellCheck, and diff checks passed

* no-mistakes(ci): Captain, fixed malformed timestamp colons hiding actionable events using shared normalization. Original bytes and unknown ages are preserved. Regression reproduced before the fix; classifier and remote-reply suites, targeted lint, syntax, and diff checks passed

* no-mistakes(review): Stamp remote escalations at call sites, drop new flag

* no-mistakes(review): Accept stamped escalation and close lines in test assertions

* no-mistakes(review): Restore reserved-key answered-note guard for stamped closes

* test(status): accept optional emission time in PR-provenance assertions

The kunchenguid#4148 provenance test landed on main with exact unstamped greps.
Parent-channel lines from this branch carry [at=<epoch>], so strip only
that tag before the same exact match. No production change.

* no-mistakes(review): Accept stamped ready signal in PR fallback scrape

* no-mistakes(review): Drop relay flag, stamp parent events at call sites

* no-mistakes(review): Stamp worker terminal-signal instructions, revert fm-on fixture

* no-mistakes(review): Accept optional stamp in live cmux drift guard

* no-mistakes(review): Restore original test invocation order in two suites

* no-mistakes(review): Strip only well-formed numeric status time tags

* no-mistakes(document): Drop stale unstamped PR-ready line spelling from channel doc

* no-mistakes(review): Stamp agy spawn-failure status lines with event time

* fix(bin): normalize status event times in-shell and freeze the budget test clock

Two paths made a status event's emission time cost more than it should.

The captain-relevance fallback piped every line through awk to drop a
well-formed `[at=<epoch>]` tag before matching, so a supervisor sweep paid a
fork per line just to prepare a regex match. Shell parameter expansion does the
same strip with no fork, and the retry-dedup scan now reuses that one helper
instead of carrying a second copy of the rule in awk. The copies had already
drifted: the shell side stripped tags from lines with no colon, which the awk
rule left whole, so a colonless line could be mistaken for one already
recorded. One definition, checked against the awk rule it replaces over the
edge cases and a 4000-line fuzz.

tests/fm-contributions.test.sh froze its fixture clock only in exhaust mode. In
hang mode the poll set DEADLINE to the real now plus a one-second budget, and
when the second ticked before the first forge call the loop broke without ever
calling gh: forge/calls was never written and the assertion failed reading a
missing file. Freezing the clock in both modes removes the dependence on wall
time; the bounded call is still cut by the real timeout, so the observation the
test asserts still starts.

Emission time stays optional on new status records, and legacy or malformed
lines keep an unknown age.

* no-mistakes(review): Stamp ask-user escalation line and fix Kimi status assertion

* no-mistakes(document): Drop stale unstamped done-line spelling from watcher docs

* test: fold emission-time snapshot coverage into the fixture case

Drop the incidental ci.yml 18-to-19 count hunk so the PR no longer
touches workflows. Keep every emission-time assertion by folding it
into test_fixture_snapshot_json.

* no-mistakes(review): replace brief date substitution with epoch placeholder; drop emitted_at_epoch

* no-mistakes(review): align untimed normalizer with epoch parser; tolerate placeholder stamp in PR scrape

* no-mistakes(review): strip undelimited at-tags; correct brief stamp header

* no-mistakes(review): normalize stamps at both captain-regex sites; restore mtime freshness

* no-mistakes(review): strip colon-bearing stamps for relevance; fix headers and test oracles

* no-mistakes(review): narrow escalation match to stamp tolerance; pin note verb

* no-mistakes(review): read note and key past colon-bearing stamps

* test(status): keep inactive reconcile assertions stamp-tolerant

These two oracles were made stamp-tolerant while resolving one of the
branch's merges from main. The rebase drops merge commits, so that
adaptation was lost and both assertions went back to matching an exact
substring that a stamped line no longer contains: the tag lands before
the colon, so "failed [key=k]: ..." is now "failed [key=k] [at=N]: ...".
Strip a well-formed tag before matching, as the branch's other oracles do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* no-mistakes(review): unstamp fold colon tests; reserve stamp width in cap

* no-mistakes(document): correct stale unstamped status-line spellings in docs

* no-mistakes(document): quote brief-test literals for lint; correct stamp-helper contract comments

* no-mistakes(ci): rename subshell-local epoch in delivery-race stub

The serialization test overrides fm_pending_reply_mark_delivered inside a
(..) subshell. Its `epoch` local collided with the same name in
status_line_at_epoch/status_stamp_line, which this branch added and this
suite now calls at top level, so ShellCheck 0.11.0 reported SC2030 and
failed Lint 2. The stub already prefixes its other locals with `pending_`
for the same reason; `epoch` was the leftover.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(discord): add self-hosted Discord connector ingestion and reply path

* fix(discord): enforce DM flag, add poll cursor, add reply send progress

- FM_DISCORD_ALLOW_DMS was exported but never checked in fm-discord-poll.js;
  DMs were ingested unconditionally. Now skipped when the flag is false.
- The poller fetched only the newest 10 messages with no cursor, so a burst
  of 11+ messages between polls could permanently skip an older mention.
  Now persists a per-channel last-seen message id and polls with after=.
- Multi-chunk replies in fm-discord-reply.js had no per-chunk progress, so a
  retry after a partial failure would repost already-delivered chunks. Now
  persists send progress per request id and resumes from the first
  unsent chunk, clearing the record on full completion.

* no-mistakes(review): Fix Discord cursor, endpoint ownership, and poller regression coverage

* no-mistakes(review): Pass expected labels through backend reaper kill dispatch

* no-mistakes(review): Pass validated Zellij tab IDs through inactive reaper

* no-mistakes(review): Add default Discord DM channel discovery

* no-mistakes(review): Guard terminal reaping against endpoint reuse

* fix(discord): silence SC2034 on cross-file token global, drop leaked .omo evidence files

.omo/evidence/*.md were pipeline review artifacts accidentally committed;
add .omo/ to .gitignore to stop recurrence.

* fix(test): pin dismiss call to the scenario's mocked clock in fm-x-mode

fm-x-dismiss.sh now sources fm-discord-lib.sh and calls
fm_discord_is_selfhosted_request, which reads the context registry and
triggers fmx_context_registry_prune as a side effect. The dismiss call
in this test had no FMX_NOW_OVERRIDE, so prune ran against the real
wall clock, saw the offer marker's FMX_NOW_OVERRIDE-stamped recorded_at
as ~2.8 years old, and deleted it, causing a spurious re-offer. Give the
dismiss call the same mocked clock as the surrounding poll calls.

---------

Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com>
Co-authored-by: Tiago <tiagop@hey.com>
Co-authored-by: rovermike <mike@rovertown.com>
Co-authored-by: Vytautas Stankus <svycka@gmail.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Kun Chen <kunchenguid@users.noreply.github.com>
Co-authored-by: Amin Roudaki <roudaky@gmail.com>
Co-authored-by: Jon Roosevelt <rooseveltadvisors@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: irene <irene@ireneui-MacBookPro.local>
Verified against no-mistakes v1.79.0's own e2e tests and upstream PR kunchenguid#1120:
jev.review_assist is global-only and has no effect when set in a repo's
tracked .no-mistakes.yaml. Revert that no-op change and document the real
activation path, data sent, and data-boundary guidance instead.
@Ivory2024

Copy link
Copy Markdown
Author

잘못된 대상(upstream) — fork(Ivory2024/firstmate) 대상으로 재작업합니다. 실수로 열림, 원작자 관여 요청 없음.

@Ivory2024 Ivory2024 closed this Sep 21, 2026
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