Skip to content
Open
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
23 changes: 12 additions & 11 deletions bin/fm-brief.sh
Original file line number Diff line number Diff line change
Expand Up @@ -278,14 +278,15 @@ Report only true captain-relevant outcomes or a declared external wait by append
States: working, needs-decision, blocked, $PAUSED_VERB, done, failed.
Use \`$PAUSED_VERB: {why}\` (distinct from \`blocked:\`) only when your domain is deliberately idling on a known external wait you expect to clear on its own; use \`blocked:\` when you are stuck and need firstmate to act.
Use this only for material phase changes, a captain decision, a real blocker, a failure, or work ready for review.
For a captain decision, append \`needs-decision [key=<slug>]: {summary of options}\`.
This is also how you return the answer to a marked from-firstmate request above.
A marked request requires one correlated answer after the work; it does not require a separate receipt or start acknowledgement.
Never append \`working:\` merely to acknowledge receipt or announce that a marked request has started.
When a routed-work phase has a supervisor-actionable material change worth reporting under the rule above, give that reported phase a stable key.
If its first reportable event is \`working [key=<work-slug>]: {material phase}\`, use the same key on its later \`$PAUSED_VERB\`, \`done\`, \`failed\`, \`needs-decision\`, or \`blocked\` event so the earlier working phase is superseded.
When a keyed phase ends without another reportable state, append \`resolved [key=<work-slug>]: {why it is no longer active}\`.
\`resolved\` separately closes an escalated decision or blocker, and only a \`resolved\` line carrying that decision's exact key closes it: a later \`done\` or \`working\` event never does, even when the answer is what started that work.
The main firstmate's answer normally writes that closing line at answer time; when a blocker or wait clears WITHOUT an answer from the main firstmate, append \`resolved: {how it cleared}\` yourself (keyed with \`[key=<slug>]\` if you opened it with one) as your domain resumes.
\`resolved\` separately closes an escalated decision or blocker, and only a \`resolved\` line carrying that decision's exact key (e.g. \`resolved [key=<slug>]: {how it cleared}\`) closes it: a later \`done\` or \`working\` event never does, even when the answer is what started that work.
The main firstmate's answer normally writes that closing line at answer time; when a blocker or wait clears WITHOUT an answer from the main firstmate, append \`resolved: {how it cleared}\` yourself (key it with \`[key=<slug>]\` if you opened it with one, omit it otherwise) as your domain resumes.
Routine internal supervision, heartbeats, retries, and crewmate churn stay inside your own home and must not touch that status file.

# Definition of done
Expand Down Expand Up @@ -368,9 +369,9 @@ The report is the only thing that survives, so anything worth keeping must be in
treating it as a possible wedge. Use \`blocked:\` when you are stuck and need help.
5. If you hit the same obstacle twice, append \`blocked: {why}\` and stop; firstmate will help.
6. If a decision belongs to a human (product choices, destructive actions),
append \`needs-decision: {summary of options}\` and stop. Firstmate will reply with the decision.
A decision or blocker you opened stays open until a \`resolved\` line carrying its exact key lands; a later \`done:\` or \`working:\` line never closes it, even when the answer is what started that work.
Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append \`resolved: {how it cleared}\` yourself (same \`[key=<slug>]\` if you opened it with one) as you resume.
append \`needs-decision [key=<slug>]: {summary of options}\` and stop. Firstmate will reply with the decision.
A decision or blocker you opened stays open until a \`resolved\` line carrying its exact key lands (e.g. \`resolved [key=<slug>]: {how it cleared}\`); a later \`done:\` or \`working:\` line never closes it, even when the answer is what started that work.
Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append \`resolved: {how it cleared}\` yourself (key it with \`[key=<slug>]\` if you opened it with one, omit it otherwise) as you resume.
7. Never stop, restart, or update the shared \`no-mistakes\` daemon - it is one instance serving
every lane/home, so restarting it kills other lanes' in-flight pipeline runs. On ANY no-mistakes
daemon error, append \`blocked: {the daemon error}\` and stop; only firstmate manages the daemon.
Expand Down Expand Up @@ -456,11 +457,11 @@ land in the generation or the report.
treating it as a possible wedge. Use \`blocked:\` when you are stuck and need help.
5. If you hit the same obstacle twice, append \`blocked: {why}\` and stop; firstmate will help.
6. If a decision belongs above you (product choices, destructive actions, ask-user findings),
append \`needs-decision: {summary of options}\` and stop. Firstmate will apply the configured authority and reply.
A decision or blocker you opened stays open until a \`resolved\` line carrying its exact key lands; a later \`done:\`
append \`needs-decision [key=<slug>]: {summary of options}\` and stop. Firstmate will apply the configured authority and reply.
A decision or blocker you opened stays open until a \`resolved\` line carrying its exact key lands (e.g. \`resolved [key=<slug>]: {how it cleared}\`); a later \`done:\`
or \`working:\` line never closes it, even when the answer is what started that work.
Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply,
append \`resolved: {how it cleared}\` yourself (same \`[key=<slug>]\` if you opened it with one) as you resume.
append \`resolved: {how it cleared}\` yourself (key it with \`[key=<slug>]\` if you opened it with one, omit it otherwise) as you resume.
7. Never stop, restart, or update the shared \`no-mistakes\` daemon - it is one instance serving
every lane/home, so restarting it kills other lanes' in-flight pipeline runs. On ANY no-mistakes
daemon error, append \`blocked: {the daemon error}\` and stop; only firstmate manages the daemon.
Expand Down Expand Up @@ -581,9 +582,9 @@ $RULE1
cadence instead of treating it as a possible wedge. Use \`blocked:\` when you are stuck and need help.
5. If you hit the same obstacle twice, append \`blocked: {why}\` and stop; firstmate will help.
6. If a decision belongs above the implementation worker (product choices, destructive actions, ask-user findings),
append \`needs-decision: {summary of options}\` and stop. Firstmate will apply the configured authority and reply with the decision.
A decision or blocker you opened stays open until a \`resolved\` line carrying its exact key lands; a later \`done:\` or \`working:\` line never closes it, even when the answer is what started that work.
Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append \`resolved: {how it cleared}\` yourself (same \`[key=<slug>]\` if you opened it with one) as you resume.
append \`needs-decision [key=<slug>]: {summary of options}\` and stop. Firstmate will apply the configured authority and reply with the decision.
A decision or blocker you opened stays open until a \`resolved\` line carrying its exact key lands (e.g. \`resolved [key=<slug>]: {how it cleared}\`); a later \`done:\` or \`working:\` line never closes it, even when the answer is what started that work.
Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append \`resolved: {how it cleared}\` yourself (key it with \`[key=<slug>]\` if you opened it with one, omit it otherwise) as you resume.
7. Never stop, restart, or update the shared \`no-mistakes\` daemon - it is one instance serving
every lane/home, so restarting it kills other lanes' in-flight pipeline runs. On ANY no-mistakes
daemon error, append \`blocked: {the daemon error}\` and stop; only firstmate manages the daemon.
Expand Down
39 changes: 39 additions & 0 deletions tests/fm-brief.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,44 @@ test_pause_verb_override_renders_all_brief_scaffolds() {
pass "fm-brief.sh: custom pause verb renders in every scaffold"
}

test_status_protocol_shows_documented_decision_key_placement() {
local home kind id brief
home="$TMP_ROOT/decision-key-home"
mkdir -p "$home/data"

for kind in ship scout dreamer secondmate; do
id="brief-decision-key-$kind"
case "$kind" in
ship)
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" firstmate --mode no-mistakes >/dev/null 2>&1
;;
scout)
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" firstmate --scout >/dev/null 2>&1
;;
dreamer)
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" firstmate --dreamer >/dev/null 2>&1
;;
secondmate)
FM_HOME="$home" "$ROOT/bin/fm-brief.sh" "$id" --secondmate --no-projects >/dev/null 2>&1
;;
esac
brief="$home/data/$id/brief.md"
# shellcheck disable=SC2016 # Literal backticks and braces must remain unexpanded.
assert_grep '`needs-decision [key=<slug>]: {summary of options}`' "$brief" \
"$kind brief did not show the documented before-colon key on needs-decision"
# shellcheck disable=SC2016 # Literal backticks and braces must remain unexpanded.
assert_grep '`resolved [key=<slug>]: {how it cleared}`' "$brief" \
"$kind brief did not show the documented before-colon key on resolved"
# shellcheck disable=SC2016 # Literal backticks and braces must remain unexpanded.
assert_no_grep '`needs-decision: {summary of options}`' "$brief" \
"$kind brief still shows the colon-first needs-decision template"
# shellcheck disable=SC2016 # Literal backticks and braces must remain unexpanded.
assert_grep '`resolved: {how it cleared}` yourself (key it with `[key=<slug>]` if you opened it with one, omit it otherwise)' "$brief" \
"$kind brief did not restore optional-key self-close phrasing"
done
pass "fm-brief.sh: every scaffold shows documented [key=...] placement on needs-decision and resolved"
}

test_scout_and_secondmate_load_decision_hold_policy() {
local home scout charter
home="$TMP_ROOT/decision-policy-home"
Expand Down Expand Up @@ -943,6 +981,7 @@ test_secondmate_no_projects_charter
test_secondmate_marked_request_reporting_contract
test_secondmate_directory_paths_are_absolute_and_output_is_stable
test_pause_verb_override_renders_all_brief_scaffolds
test_status_protocol_shows_documented_decision_key_placement
test_scout_and_secondmate_load_decision_hold_policy
test_scout_and_secondmate_scaffold
test_task_id_reuse_refused_and_preserves_retained_report
Loading