Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion bin/fm-dod-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,23 @@ There is no pull request, no \`gh-axi\` call, and no forge CI result to report:
EOF
}

# fm_dod_compaction_step sets compaction_step: the pause-for-compaction paragraph
# only when this home has idle-compact enabled (the watcher's own
# fm_idle_compact_threshold_minutes verdict on config/idle-compact, with the
# same FM_HOME/config resolution as bin/fm-idle-compact.sh),
# else a line telling the worker to start validation right after its commit.
fm_dod_compaction_step() {
local home config
home="${FM_HOME:-${FM_ROOT_OVERRIDE:-$FM_ROOT}}"
config="${FM_CONFIG_OVERRIDE:-${CONFIG:-$home/config}}"
# shellcheck source=/dev/null
if ( . "$(d=${BASH_SOURCE[0]%/*}; [ "$d" != "${BASH_SOURCE[0]}" ] || d=.; cd "${d:-/}" && pwd)/fm-idle-compact.sh" && fm_idle_compact_threshold_minutes "$config" ) >/dev/null 2>&1; then
compaction_step="Right after that implementation commit lands, append \`paused [at=<epoch>]: awaiting compaction before validation\` to the status file and stop for this turn - do NOT run \`no-mistakes axi run\` yet. A worker cannot self-trigger compaction (\`/compact\` is a terminal built-in, not a tool you can invoke), so firstmate's idle-compact watcher reads that line - the phrase must START the line, and any detail you want to note (your measured lane size, the commit) may follow it - compacts your context while it is still warm, then rings you with a durable inbox message telling you to start the validation run - resume from that ring instead of waiting on a reply."
else
compaction_step="Right after that implementation commit lands, start validation: measure the lane below, then run \`no-mistakes axi run\`."
fi
}

fm_dod_block() { # <mode> <task-id> [branch] [<forge>]
local mode=$1 id=$2 forge=${4:-none}
local branch=${3:-fm/$id}
Expand Down Expand Up @@ -479,12 +496,13 @@ The configured merge authority approves the ready branch, then firstmate merges
EOF
;;
no-mistakes:*)
fm_dod_compaction_step
cat <<EOF
# Definition of done
Delivery contract: mode=no-mistakes
Ship branch: $branch
The task is complete only when committed on your branch.
Right after that implementation commit lands, append \`paused [at=<epoch>]: awaiting compaction before validation\` to the status file and stop for this turn - do NOT run \`no-mistakes axi run\` yet. A worker cannot self-trigger compaction (\`/compact\` is a terminal built-in, not a tool you can invoke), so firstmate's idle-compact watcher reads that line - the phrase must START the line, and any detail you want to note (your measured lane size, the commit) may follow it - compacts your context while it is still warm, then rings you with a durable inbox message telling you to start the validation run - resume from that ring instead of waiting on a reply.
$compaction_step

Before your FIRST \`no-mistakes axi run\`, measure this lane:
\`bash $FM_ROOT/bin/fm-diff-size-check.sh .\`
Expand Down
3 changes: 2 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,8 @@ Eligibility, checked for every task recorded under `state/*.meta`, is strictly t
- A live safety gate immediately before typing anything: `bin/fm-busy-lib.sh`'s `fm_busy_classify` reports an exact `idle` verdict (never `busy` and never an unproven `unknown`) and `bin/fm-backend.sh`'s `fm_backend_composer_state` reports exactly `empty`, reusing the identical primitives the away-mode daemon's own injection boundary uses.
A busy pane, an unproven verdict, or a non-empty composer defers to the next sweep rather than erroring.

**Declared-state fast path:** a worker cannot self-trigger `/compact` (it is a terminal built-in, not a tool), so a no-mistakes ship brief tells the worker to append the status line `paused: awaiting compaction before validation` right after its implementation commit, then end its turn - before starting `no-mistakes axi run`.
**Declared-state fast path:** a worker cannot self-trigger `/compact` (it is a terminal built-in, not a tool), so, when idle-compact is enabled, a no-mistakes ship brief tells the worker to append the status line `paused: awaiting compaction before validation` right after its implementation commit, then end its turn - before starting `no-mistakes axi run`.
When idle-compact is off (no `config/idle-compact`, or its first content line is not a positive integer) the brief instead tells the worker to start validation right after its commit.
The task's own latest status line is read as declaring that pause when it *starts with* that phrase on a word boundary: the same brief asks the worker to note its measured lane size, so the line that actually lands routinely carries trailing detail, and requiring whole-line equality silently dropped such workers onto the ordinary path.
When the line declares the pause, eligibility ignores the idle-minutes threshold entirely (every other exclusion and the live safety gate still apply), and the episode skips the notes-save turn below and sends `/compact` directly, naming the branch, the brief path, and the delivery contract.
See `bin/fm-idle-compact.sh`'s header comment for the exact mechanics and `bin/fm-dod-lib.sh`'s no-mistakes block for the worker-facing instruction.
Expand Down
39 changes: 38 additions & 1 deletion tests/fm-brief.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -551,10 +551,46 @@ test_ship_briefs_forbid_manual_issue_close_and_board_edits() {
# Quota-efficiency worker rules (captain order 2026-09-04) belong only in the
# no-mistakes DOD: a direct-PR or local-only brief never runs no-mistakes, and
# a scout brief carries no delivery contract at all.
# The compaction pause is only prescribed where idle-compact is enabled; a home
# without config/idle-compact must send the worker straight to validation.
test_no_mistakes_dod_compaction_pause_follows_idle_compact_config() {
local home brief
home="$TMP_ROOT/idle-compact-off-home"
mkdir -p "$home/data" "$home/config"
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" brief-compact-off some-proj --mode no-mistakes >/dev/null 2>&1
brief="$home/data/brief-compact-off/brief.md"
assert_present "$brief" "brief was not scaffolded"
assert_no_grep "awaiting compaction before validation" "$brief" \
"idle-compact off: the DOD must not tell the worker to pause for compaction"
assert_grep "start validation: measure the lane below, then run" "$brief" \
"idle-compact off: the DOD must tell the worker to start validation after its commit"

: > "$home/config/idle-compact"
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" brief-compact-on some-proj --mode no-mistakes >/dev/null 2>&1
brief="$home/data/brief-compact-on/brief.md"
assert_grep "awaiting compaction before validation" "$brief" \
"idle-compact on: the DOD must keep the compaction pause"
assert_no_grep "start validation: measure the lane below" "$brief" \
"idle-compact on: the DOD must not also say to start validation immediately"

local bad
for bad in 0 off; do
printf '%s\n' "$bad" > "$home/config/idle-compact"
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "brief-compact-bad-$bad" some-proj --mode no-mistakes >/dev/null 2>&1
brief="$home/data/brief-compact-bad-$bad/brief.md"
assert_no_grep "awaiting compaction before validation" "$brief" \
"idle-compact '$bad' is disabled for the watcher: the DOD must not tell the worker to pause"
assert_grep "start validation: measure the lane below, then run" "$brief" \
"idle-compact '$bad': the DOD must tell the worker to start validation after its commit"
done
pass "fm-brief.sh: no-mistakes DOD compaction pause follows config/idle-compact"
}

test_no_mistakes_dod_carries_quota_efficiency_rules() {
local home id brief
home="$TMP_ROOT/quota-efficiency-home"
mkdir -p "$home/data"
mkdir -p "$home/data" "$home/config"
: > "$home/config/idle-compact"
id="brief-quota-nm1"
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" some-proj --mode no-mistakes >/dev/null 2>&1
brief="$home/data/$id/brief.md"
Expand Down Expand Up @@ -1511,6 +1547,7 @@ test_ask_user_escalation_format
test_ship_project_memory_wording
test_ship_briefs_forbid_manual_issue_close_and_board_edits
test_no_mistakes_dod_carries_quota_efficiency_rules
test_no_mistakes_dod_compaction_pause_follows_idle_compact_config
test_herdr_lab_contract_is_explicit_and_complete
test_herdr_lab_contract_quotes_foreign_firstmate_path
test_herdr_lab_omission_is_loud_for_ship_and_scout
Expand Down
Loading