Skip to content

fix(agents): load skills for omitted conditional triggers - #9

Closed
twilwa wants to merge 7 commits into
mainfrom
fm/fm-agents-md-skillify-followup
Closed

twilwa wants to merge 7 commits into
mainfrom
fm/fm-agents-md-skillify-followup

Conversation

@twilwa

@twilwa twilwa commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Follow-up scope and relocation map

The relocation landed in #6.
This follow-up fixes three missing load conditions without moving any more procedures or changing policy.

Original block in AGENTS.md Destination skill Load condition in the skill description
Section 7, Validate: preserve changed requests in intent task-delivery Whenever the captain adds or changes an ask mid-task, including before validation
Section 7, PR ready, landing, and teardown: custom-check safety task-delivery Before writing, registering, changing, or retiring a custom state/<id>.check.sh
Section 14, Relay: startup public follow-up reconciliation fmx-respond When the session-start digest lists a public commitment or an open public loop

AGENTS.md before this follow-up: 305 lines, 33,003 bytes.
AGENTS.md after this follow-up: 305 lines, 33,190 bytes.
The preceding relocation reduced the original 628 lines and 85,533 bytes to 305 lines and 33,003 bytes.

Local checks passed: documentation audience/link validation, both focused documentation and AGENTS.md convention suites, YAML frontmatter validation, compatibility pointers, and whitespace checks.
The supervisor approved proceeding without live skill-load validation because these natural-language loading decisions have no deterministic runtime trace.

Intent

Examine AGENTS.md, find content that only applies in certain circumstances, and transpose it into skills rather than memory, with correct descriptions so each skill gets loaded circumstantially.

What Changed

  • Expand task-delivery triggers to cover mid-task captain request changes and custom check-script lifecycle work.
  • Expand fmx-respond triggers to cover open public loops surfaced in the session-start digest.
  • Keep the skill descriptions and AGENTS.md trigger catalog aligned.

Risk Assessment

✅ Low: The documentation-only change accurately restores required conditional load triggers in both AGENTS.md and the corresponding skill descriptions, without introducing unnecessary behavior or duplication.

Testing

Inspected the complete base-to-target diff, searched for an executable skill-discovery consumer, and confirmed the worktree remained unchanged. No live scenarios were run because the change consists entirely of natural-language instruction and skill-description metadata, and the available runtime exposes no deterministic skill-load telemetry.

  • Live validation: ⚠️ no-surface - 0 of 4 scenarios driven live against the product
Scenario Result Live Evidence
When the captain adds or changes an ask mid-task, the agent conditionally loads task-delivery and applies its intent-update procedure ⏸️ untested no No executable product interface exposes which skill an agent loaded. A deterministic skill-load telemetry or dispatch trace would be needed; source-string assertions and live-model interpretation are…
When managing a custom state check, the agent conditionally loads task-delivery before writing, registering, changing, or retiring it ⏸️ untested no The behavior is solely an instruction-trigger description, with no observable runtime skill-load signal. Provide a deterministic host-level skill-dispatch trace to test it live.
When startup reports a public commitment or open public loop, the agent conditionally loads fmx-respond ⏸️ untested no Startup can expose the underlying public-loop state, but the changed behavior is the model choosing to load a skill from natural-language metadata. No deterministic load telemetry is available, and mo…
In unrelated task and startup contexts, task-delivery and fmx-respond are not eagerly loaded ⏸️ untested no The repository has no public interface that reports negative skill-load decisions. Deterministic host instrumentation recording considered and loaded skills would be required.
  • Outcome: ⚠️ 2 warnings across 1 run (1m24s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

⚠️ **Test** - 2 warnings
  • ⚠️ AGENTS.md:269 - Live validation cannot demonstrate the intended conditional skill loading. The change only edits natural-language AGENTS.md guidance and SKILL.md discovery descriptions; asserting source text would violate the test-quality rule, while agent interpretation is nondeterministic and has no observable skill-load telemetry. Human review or a future deterministic skill-dispatch trace is required.
  • ⚠️ this change has no live-validatable surface; proceed without live validation? (0 of 4 scenarios were driven live against the product); When the captain adds or changes an ask mid-task, the agent conditionally loads task-delivery and applies its intent-update procedure: No executable product interface exposes which skill an agent loaded. A deterministic skill-load telemetry or dispatch trace would be needed; source-string assertions and live-model interpretation are not valid evidence under the test-quality rule.; When managing a custom state check, the agent conditionally loads task-delivery before writing, registering, changing, or retiring it: The behavior is solely an instruction-trigger description, with no observable runtime skill-load signal. Provide a deterministic host-level skill-dispatch trace to test it live.; When startup reports a public commitment or open public loop, the agent conditionally loads fmx-respond: Startup can expose the underlying public-loop state, but the changed behavior is the model choosing to load a skill from natural-language metadata. No deterministic load telemetry is available, and model interpretation cannot serve as live CI evidence.; In unrelated task and startup contexts, task-delivery and fmx-respond are not eagerly loaded: The repository has no public interface that reports negative skill-load decisions. Deterministic host instrumentation recording considered and loaded skills would be required.
  • Live validation: ⚠️ no-surface - 0 of 4 scenarios driven live against the product
Scenario Result Live Evidence
When the captain adds or changes an ask mid-task, the agent conditionally loads task-delivery and applies its intent-update procedure ⏸️ untested no No executable product interface exposes which skill an agent loaded. A deterministic skill-load telemetry or dispatch trace would be needed; source-string assertions and live-model interpretation are…
When managing a custom state check, the agent conditionally loads task-delivery before writing, registering, changing, or retiring it ⏸️ untested no The behavior is solely an instruction-trigger description, with no observable runtime skill-load signal. Provide a deterministic host-level skill-dispatch trace to test it live.
When startup reports a public commitment or open public loop, the agent conditionally loads fmx-respond ⏸️ untested no Startup can expose the underlying public-loop state, but the changed behavior is the model choosing to load a skill from natural-language metadata. No deterministic load telemetry is available, and mo…
In unrelated task and startup contexts, task-delivery and fmx-respond are not eagerly loaded ⏸️ untested no The repository has no public interface that reports negative skill-load decisions. Deterministic host instrumentation recording considered and loaded skills would be required.
  • git diff --no-ext-diff --unified=30 9863806cc4a1c0b7377d77ede1342d386fa50c79..926c43b7ca79f763a84def69e4c192c9032d7d17
  • rg -n "session-start digest lists|custom state/<id>|adds or changes an ask|public commitment|open public loop" tests bin .agents/skills AGENTS.md
  • git show --stat --oneline --decorate=short 926c43b7ca79f763a84def69e4c192c9032d7d17
  • git status --short
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Summary by Sourcery

Align skill metadata and the AGENTS.md trigger catalog so agents load task-delivery and fmx-respond for all required conditional workflows.

Bug Fixes:

  • Restore conditional loading triggers for task-delivery when mid-task asks change or custom state-check lifecycle work occurs.
  • Restore conditional loading of fmx-respond for startup-reported public commitments and open public loops.

Enhancements:

  • Keep the AGENTS.md skill trigger catalog synchronized with the corresponding skill descriptions.

twilwa and others added 7 commits September 20, 2026 01:19
)

* Fix dispatch resolver model and receipts

* no-mistakes(review): Drop model-drift branch, harden receipt lock and brief join

* no-mistakes(review): Scope receipt recording to clear, report failed joins, measure latency

* no-mistakes(review): Narrow dispatch clause and concurrency test, shrink lock budget

* no-mistakes(review): Accept --project on the join, assert drop-or-append concurrency

* no-mistakes(review): Split lock budgets by path, drop receipt size bound

* no-mistakes(review): Record brief_path as spelled, drop abs_path normalization

* no-mistakes(review): Pin model in contract, bound receipt latency, record reason

* no-mistakes(review): Report dropped resolution receipts, project profile agreement, drop dispatch_id

* no-mistakes(review): Enforce append-only cmp, complete join example, govern latency bound

* no-mistakes(review): Keep no-rules exit 0 without jq, dedupe error default

* no-mistakes(review): Refuse symlinked receipts path, drop dead no_rules jq argument

* no-mistakes(document): Document receipt identity, symlink refusal, jq exit narrowing
* fix(bin): refuse an unrecognised fm-send flag instead of sending it as text

fm-send's option loop ended in an unconditional `*) break ;;`, so any token
it did not recognise - including one obviously shaped as a flag - fell out of
the loop and became the positional message body. A steer invoked with a flag
that does not exist was durably written into a live worker's steering inbox as
the literal flag string while fm-send exited 0, so the worker was mis-steered
and the caller got a success code and no diagnostic.

The accepted set is now an allowlist rather than a pattern. --key is a real,
supported flag parsed after this loop and must keep falling through it
untouched, so a blanket "starts with -- and matched no case arm, therefore
refuse" rule would have broken it.

A bare -- ends flag parsing, which is how a message whose text starts with --
is sent. That separator is threaded to the two --key dispatch points so text
after it is text everywhere rather than being re-parsed as a flag. A
single-dash word was never a flag here and still needs no separator.

The refusal exits before anything is marked, recorded, rung, or typed, the
same discipline the header already applies to an empty message.

* no-mistakes(review): drop -- end-of-flags separator, keep pure flag allowlist

* no-mistakes(document): document fm-send's flag allowlist and leading-`--` message limit

* docs(bin): drop the flag-allowlist commentary from fm-send's source

The header block in bin/fm-send.sh is that script's documented contract.
Recording the no-end-of-flags-separator limitation there amends that
contract and turns a deliberate, narrow behaviour change into a
documented guarantee the project would then owe. The rationale comment
above the option loop goes for the same reason: the limitation describes
a decision, which belongs in the pull request, not in the source, where
it reads as a promise.

Removes only those thirteen comment lines. The refusal itself is
unchanged: the option loop remains a pure allowlist, --key still falls
through to its own plane untouched, there is no end-of-flags handling,
the usage line is unmodified, and the tests are untouched.

* fix(bin): refuse trailing arguments after fm-send's --key

The option loop breaks at --key without consuming what follows it, and
the key path reads only the key itself, so every remaining argument was
discarded in silence while the key was still delivered and the command
still exited 0. `fm-send.sh lane --key Enter --not-a-real-flag` sent
Enter and reported success. That is the same silent-delivery shape the
unknown-flag refusal in this change exists to remove, so the key path
contradicted the contract on that one path.

The same ordering bypassed the --fire-and-forget incompatibility:
FIRE_AND_FORGET_ID is only set when the flag precedes --key, so
`--key Enter --fire-and-forget x` passed both existing guards.

The key path now refuses any trailing argument before delivering the
key, naming the offending token in the wording already used for an
unknown flag in flag position, and names --fire-and-forget specifically
so that incompatibility holds on either ordering. Adds regression
coverage for both orderings and for a trailing plain word; both new
tests fail before this commit and pass after it.
* Add head-keyed PR review policy ledger

* Add post-merge browser QA gate

* Fix PR review and post-merge gates

* Close remaining PR review gate gaps

* Harden migration risk and QA evidence parsing

* Close PR review guard bypasses

* Tighten review evidence boundaries

* Bind final review authorization

* Invalidate stale review dispositions

* Harden review evidence validation
* Add keyed decision defer mode

* no-mistakes(review): Fix defer date identity, hold age, parent channel, reporting

* no-mistakes(review): Derive board defer from the option's until alone

* no-mistakes(review): Show the defer date on the board card

* Fix deferred decision lifecycle edges

* no-mistakes(review): Drop fabricated defer hold reason fallback

* no-mistakes(document): Correct stale captain-defer docs for the recorded answer path

* Fix defer intake failure edges

* Require future dates for decision defers

* no-mistakes(review): Narrow UTC day parsing; fix elapsed-defer recovery guidance

* no-mistakes(review): Refuse duplicate board option values; fix defer recovery wording

* Stabilize chat defer hold assertion

* Keep chat defer date stable across midnight

* Refactor defer validation for bounded lint
* fix(brief): forbid validation auto-accept

* no-mistakes(review): restore fleet-wide --yes ban, add ask-user routing sentence

* no-mistakes(ci): Fixed a flaky test that failed the "Behavior portable serial 4" shard. Failure: tests/fm-pi-branch-extension.test.sh -> test_captain_outcome_processing_turn_is_sequence_keyed_and_re_presented, with "Error: supervision branch prompt settled but produced no durable outcome for its claimed wake rows" (thrown at .pi/extensions/fm-branch-supervision.ts:1548). Nothing in this PR's diff (the --yes DoD line, the harness-adapters sentence, three brief assertions) touches that extension or test; the other two check runs on the same head commit (99a0187) passed. It is a pre-existing race that surfaces on a slow/loaded runner. Root cause: in fm-branch-supervision.ts a wake builds the branch session (ensureBranch), then runs several awaited subprocesses (flushMirror, actingAsOwner, scopeForUnreadWake, writeEligibleRowsSnapshot, away-posture read-back) and only then snapshots reportRevisionBeforePrompt immediately before session.prompt(...); after the prompt settles it requires that revision to have advanced. The test synchronized on the wrong point: `settle(() => __fmSessions.length === 2, "replacement branch session")`. Session creation precedes that snapshot, so when the extension's pre-prompt work is slower than the test's report append, report2's durable append lands before the snapshot and the wake rejects its own settled prompt as outcome-less. The routine wake earlier in the same test already waits on __fmPrompts.length === 1 and is unaffected. Fix (tests/fm-pi-branch-extension.test.sh:1377, 9 insertions / 1 deletion): wait for the wake prompt as well as the replacement session, matching the routine wake's own idiom, with a comment naming why the built session is not the synchronization point. No production code changed; no new machinery. Verification: reproduced the exact CI error deterministically by temporarily injecting a delay ahead of reportRevisionBeforePrompt (delays 100/200/300/400/500/700 ms all failed with the identical message); that injection was reverted (git status shows only the test file modified). With the fix the test passes under injected delays of 100, 400 and 1500 ms. Full file run: exit 0, 45 tests passing. 24 parallel runs of the target test: 24/24 pass. shellcheck -x on the changed file is clean, and this PR's own tests (tests/fm-brief.test.sh, tests/fm-ask-user-authority.test.sh) still pass. The change is left uncommitted in the worktree, since prior rounds' commits on this branch were made by the executor rather than this phase
* docs: audit AGENTS.md size and ownership

* docs: slim always-loaded Firstmate contract

* no-mistakes(review): drop audit doc, dedupe skill triggers, fix stale pointers

* no-mistakes(review): fix yolo brief split, state guard, and stale pointers

* no-mistakes(review): restore backstop wake duty, dedupe trigger, repoint pointers

* no-mistakes(document): Repoint stale brief guidance comment

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @twilwa, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 2 days and 20 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Sep 24, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This documentation-only change restores omitted conditional skill-loading triggers and keeps the AGENTS.md catalog synchronized with the task-delivery and fmx-respond skill descriptions. Review the exact trigger wording and consistency across both metadata locations; runtime loading was not live-validated because the repository exposes no deterministic skill-dispatch telemetry.

File-Level Changes

Change Details Files
Expanded conditional discovery triggers for task-delivery to cover mid-task requirement changes and custom check-script lifecycle operations.
  • Added loading when the captain adds or changes an ask mid-task, including before validation.
  • Added loading before writing, registering, changing, or retiring custom state check scripts.
  • Mirrored the trigger wording in the skill description and the AGENTS.md catalog.
.agents/skills/task-delivery/SKILL.md
AGENTS.md
Expanded fmx-respond discovery triggers for public work surfaced during session startup.
  • Added loading when the startup digest lists a public commitment or open public loop.
  • Kept the Relay-only constraint and synchronized the skill description with the AGENTS.md catalog.
.agents/skills/fmx-respond/SKILL.md
AGENTS.md
Validated the documentation-only trigger synchronization without runtime behavior tests.
  • Reviewed the complete base-to-target diff and searched for related trigger references and skill-discovery consumers.
  • Confirmed lint, documentation, push, and worktree checks passed; live conditional-load scenarios remain untestable because no skill-dispatch telemetry or executable surface is available.
.agents/skills/fmx-respond/SKILL.md
.agents/skills/task-delivery/SKILL.md
AGENTS.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-24T07:03:25.174107Z 926c43b PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@twilwa

twilwa commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #16 (merged).

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