feat(bin): publish real work outcomes into herdr as signal + metadata - #3
Merged
Conversation
added 4 commits
August 7, 2026 14:48
…metadata Adds bin/fm-herdr-outcome-publish.sh, a reusable decoration-only publisher that maps a firstmate outcome onto herdr's four existing WorkspaceSignalKind values and writes both a momentary report-signal and a durable report-metadata patch, targeting the workspace recorded in the task's own state/<id>.meta. Herdr cannot derive outcomes itself (only firstmate talks to GitHub with identity and intent), and the two-call split matches data/herdr-event-channel-research/report.md section D's recommendation to keep the momentary and durable channels decoupled. Wires it into the two real outcome-learning moments in firstmate's own lifecycle: a PR merge (fm-pr-merge.sh, after gh-axi pr merge succeeds) and a landed teardown (fm-teardown.sh, before meta removal, skipped on --force since a forced discard is not landed work). Any unresolvable herdr target is a silent no-op; the publisher never blocks or fails the operation it is attached to.
…tions
The installed herdr CLI (0.8.0) rejects the WORKSPACE_ID positional when it
trails --source/--token options ("unknown option: <value>") - verified
empirically against the real binary with both orderings. report-signal has
no positional argument (--from/--to are options) and was unaffected.
…ory in docs/scripts.md
brchue-ux
force-pushed
the
fm/herdr-outcome-publisher
branch
from
August 7, 2026 19:02
0183e19 to
d869a5a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Build a reusable fleet-side publisher (bin/fm-herdr-outcome-publish.sh) that other firstmate scripts call at the moment firstmate learns a real work outcome (a PR merged, a task landed), publishing it into herdr as a momentary signal plus durable metadata. Design constraints from data/herdr-event-channel-research/report.md sections C-D (already researched, not re-derived here): herdr cannot derive outcomes itself, only firstmate knows them. Use ONLY the two herdr CLI commands that already ship in the installed herdr binary - 'herdr workspace report-signal' (four existing WorkspaceSignalKind values: transfer/completed/failed/idle - deliberately NOT widened, that is a separate herdr-side design decision out of scope here) and 'herdr workspace report-metadata' (durable per-workspace token ledger). Make two separate CLI calls (not one fused method) per report.md section D's recommendation, since the two channels have deliberately different retention rules and should stay decoupled. The target workspace is resolved only from the task's own state/.meta (herdr_session=, herdr_workspace_id=, written by fm-spawn.sh for backend=herdr tasks) - no second identity scheme invented. Wired into the two real outcome-learning moments in firstmate's own lifecycle: bin/fm-pr-merge.sh (right after gh-axi pr merge succeeds, outcome=pr_merged) and bin/fm-teardown.sh (right before task meta removal so herdr_session/workspace_id are still readable, outcome=landed, deliberately skipped when --force is passed since a forced teardown is an explicit discard of possibly-unlanded work, not a landed outcome). This is a decoration, never a blocker: any unresolvable target (non-herdr task, missing session/workspace meta fields, herdr/jq not installed, the CLI call itself failing) is a silent no-op that exits 0 without disturbing the caller's control flow; callers additionally append '|| true' for defense in depth. A malformed call (wrong arg count, an outcome kind outside the four WorkspaceSignalKind values) is treated as a caller bug and exits 2 with a usage message so a broken call site is caught in testing rather than silently swallowed. Colocated tests (tests/fm-herdr-outcome-publish.test.sh, plus new cases in tests/fm-pr-merge.test.sh and tests/fm-teardown.test.sh) assert observable behavior only - the exact herdr CLI invocations captured via a fake logging herdr stub in PATH, never implementation-source bytes. Follow-up fix on top of the initial commit: the installed herdr CLI (0.8.0) rejects report-metadata's WORKSPACE_ID positional argument when it trails --source/--token options ('unknown option: ', verified empirically against the real binary with both argument orderings) - reordered so the positional comes first, and updated the three tests asserting the exact CLI invocation. This task touches firstmate's own shared tracked material under bin/, so per AGENTS.md section 1 it ships through this repo's no-mistakes pipeline rather than a bare direct PR.
What Changed
bin/fm-herdr-outcome-publish.sh, a reusable publisher that resolves a herdr workspace target from a task's ownstate/<id>.meta(herdr_session=,herdr_workspace_id=) and makes two separateherdr workspaceCLI calls —report-signal(one of the four existingtransfer/completed/failed/idlekinds, direction mapped via--from/--to) andreport-metadata(durableoutcome=/summary=tokens) — keeping the momentary and durable channels decoupled per their different retention rules.bin/fm-pr-merge.shcalls it right after a successfulgh-axi pr merge(outcome=pr_merged), andbin/fm-teardown.shcalls it right before task meta removal (outcome=landed), skipped when--forceis passed since a forced teardown discards possibly-unlanded work rather than reporting a landed outcome.report-metadata'sWORKSPACE_IDpositional argument to come before its--source/--tokenoptions, since the installed herdr CLI (0.8.0) rejects the positional when it trails those options; updated the three tests asserting the exact CLI invocation accordingly.tests/fm-herdr-outcome-publish.test.shplus new cases intests/fm-pr-merge.test.shandtests/fm-teardown.test.shthat assert the exact captured CLI invocations via a fake logging herdr stub, and documented the new script indocs/scripts.md.Risk Assessment
✅ Low: This round's only change is a 5-line comment addition (bin/fm-herdr-outcome-publish.sh:8-12) clarifying that the cited report.md lives in the private, gitignored data/ directory per AGENTS.md section 2 (confirmed via .gitignore and git check-ignore), resolving the prior round's dangling-citation finding with no functional code touched.
Testing
All targeted tests pass: the fake-herdr-stub CLI transcripts confirm both report-signal and report-metadata are called with the WORKSPACE_ID positional ordered first (matching the empirically-verified 0.8.0 CLI fix), the two calls stay decoupled, the publisher is a true no-op (exit 0) on every unresolvable-target case, malformed calls exit 2 with usage, and the two real wiring points (fm-pr-merge on successful merge, fm-teardown before meta removal unless --force) publish exactly as specified. No issues found.
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed ✅
bin/fm-herdr-outcome-publish.sh:7- bin/fm-herdr-outcome-publish.sh's header repeatedly cites 'data/herdr-event-channel-research/report.md sections C and D' as the design rationale (four WorkspaceSignalKind values, two-call decoupling, --from/--to direction mapping, unknown-workspace-succeeds behavior), but this file does not exist anywhere in the repo's history (confirmed viagit log --all --diff-filter=A -- data/herdr-event-channel-research/report.mdand a full-treefind). The user intent states this research was 'already researched, not re-derived here,' implying the doc should exist (e.g. in a sibling repo or to be added later), but as committed here the citations are dangling — a future reader can't verify the design claims the code leans on.🔧 Fix: Clarify report.md citation points to private gitignored data/
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-herdr-outcome-publish.test.sh— 9/9 pass: signal+metadata publish, summary omission, transfer --to addressing, non-herdr/missing-fields/missing-meta silent no-ops, invalid-kind and wrong-arg-count usage errors (exit 2), herdr CLI failure never propagatesbash tests/fm-pr-merge.test.sh— 11/11 pass including newtest_publishes_herdr_outcome_on_mergeasserting the exact captured CLI args via fake herdr stub after a successful gh-axi pr mergebash tests/fm-teardown.test.sh— full file pass including newtest_landed_teardown_publishes_herdr_outcomeandtest_forced_teardown_publishes_no_herdr_outcome(confirms --force suppresses both report-signal and report-metadata calls)git status --porcelainpost-run — confirmed no leftover test artifacts in the worktree✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.