Skip to content

fix: enforce Discord decision buttons and recommendations - #290

Merged
dnth merged 3 commits into
mainfrom
fm/fm-ext-needs-you-buttons
Nov 6, 2026
Merged

dnth merged 3 commits into
mainfrom
fm/fm-ext-needs-you-buttons

Conversation

@dnth

@dnth dnth commented Nov 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

Every Discord decision now has to arrive as buttons, and every choice of two or more options has to name a recommendation.

emit(kind, state, decision_file, no_buttons)
  if state == needs-you and kind != ack
    refuse unless decision_file or no_buttons

ask(options, recommended, no_recommendation)
  if len(options) >= 2
    refuse unless recommended or no_recommendation
 bin/
   fm-ext-emit.sh   # + needs-you rule, + --no-recommendation (record only)
   fm-ext-ask.sh    # + recommendation rule, forwards the recorded reason
   fm-ext-open.sh   # + --decision-file / --no-buttons passthrough
   fm-ext-lib.sh    # payload schema accepts no_recommendation_reason
 docs/configuration.md          # Decision buttons rule + Topic threads pointer
 .agents/skills/ext-respond/SKILL.md  # two sentences
 tests/
   fm-ext-needs-you-buttons.test.sh   # new: AC1-AC3
   fm-ext-ask.test.sh                 # fixtures mark a recommendation
   fm-ext-topic-threads.test.sh       # needs-you status posts record a reason

Evidence

  • Before: bin/fm-ext-emit.sh --kind answer --thread-state needs-you with no buttons published a plain post; three such choice posts reached the captain on 2026-11-06 because the text-shape guard only matched numbered or coded option lines.
    After: the same command exits 2 and publishes nothing:

    fm-ext-emit: a needs-you answer must carry decision buttons; post the choice with bin/fm-ext-ask.sh (or --decision-file), or pass --no-buttons "<reason>" when it asks no choice
    

    With the escape it publishes an ordinary payload: {"thread_state":"needs-you","no_buttons_reason":"status reminder, no choice asked"}.

  • Before: bin/fm-ext-ask.sh --option North --option South posted a two-option choice with no starred option.
    After: it exits 2 before touching the hold:

    fm-ext-ask: a post of 2 options must mark one --recommended, or pass --no-recommendation "<reason>" when no option is genuinely better
    

    With --no-recommendation 'both routes cost the same' the payload carries the record: {"no_recommendation_reason":"both routes cost the same","labels":["North","South"]}.

  • Tests: env -u FM_TASK_ID bash tests/fm-ext-needs-you-buttons.test.sh passes all 4 cases; all 12 tests/fm-ext-*.test.sh suites exit 0. FM_TASK_ID is unset only because a worker environment deliberately makes the watcher and drain suites refuse.

  • Lint: bin/fm-lint.sh clean at pinned ShellCheck 0.11.0.

Merge Danger

Door: two-way

The rule is validation only: no data migration, no payload field is required, and reverting restores the previous posting behavior.

Blast Radius: bridge

Any home running this commit must pass buttons or --no-buttons "<reason>" on a needs-you reply, and a starred recommendation on a choice of two or more options; the emit and ask headers, docs/configuration.md, and the ext-respond skill say so.

Pipeline

Updates from git push no-mistakes

✅ **Intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 6 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Local emit refuses needs-you answers, followups, and finals—including bold-bullet choices—without changing persisted state ✅ pass live Live CLI transcript; state snapshots asserted by live-cli-driver.py
Local emit accepts decision buttons or a recorded no-buttons reason for each needs-you reply kind ✅ pass live Live CLI transcript; actual generated outbox payloads
Done, none, unstated followups, and exempt acknowledgements retain their behavior while the existing choice guard remains effective ✅ pass live Live CLI transcript; actual generated outbox payloads
Local ask rejects unstarred choices, records explained ties, stars recommended choices, and accepts single-option asks ✅ pass live Live CLI transcript; actual generated outbox payloads; persisted captain holds
Ask and emit reject contradictory recommendations; ask rejects malformed reasons before creating a hold ✅ pass live Live CLI transcript; state and backlog snapshots asserted by live-cli-driver.py
Local open refuses an unbuttoned needs-you post and accepts buttons or a no-buttons reason ✅ pass live Live CLI transcript; actual generated outbox payloads
  • python3 .test-validation/live.py — real intake, emit, ask, hold, open, and lookup commands against an isolated FM_HOME
  • for suite in tests/fm-ext-*.test.sh; do TMPDIR=&#34;$PWD/.test-validation/tmp&#34; bash &#34;$suite&#34;; done — all twelve suites exited successfully
  • bin/fm-ext-emit.sh --help, bin/fm-ext-ask.sh --help, and bin/fm-ext-open.sh --help
  • Manually reviewed documentation changes and the skill's two added sentences
🔧 **Document** - 1 issue found → auto-fixed ✅
  • ⚠️ .agents/skills/ext-respond/SKILL.md:70 - The new sentence says emit refuses any needs-you reply, but ack is exempt. Narrow it to answer/followup/final. Left unchanged because this phase forbids rewording runtime-loaded prompts.

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

dnth added 3 commits November 6, 2026 15:39
…d option on choices

fm-ext-emit.sh now refuses an answer, followup, or final marked needs-you
unless it carries --decision-file or --no-buttons "<reason>", so a thread
asking the captain to act always carries the buttons for that choice.
fm-ext-ask.sh refuses a post of two or more options that stars none of them
unless --no-recommendation records the genuine tie, and the reason lands in
the outbox payload as no_recommendation_reason. fm-ext-open.sh passes both
decision flags through to its first message.

Headers, help, docs/configuration.md, and the ext-respond skill carry the rule.
@dnth
dnth merged commit 7c71cfb into main Nov 6, 2026
19 checks passed
@dnth
dnth deleted the fm/fm-ext-needs-you-buttons branch November 6, 2026 09:13
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