Skip to content

feat(bin): publish real work outcomes into herdr as signal + metadata - #3

Merged
brchue-ux merged 4 commits into
mainfrom
fm/herdr-outcome-publisher
Aug 7, 2026
Merged

feat(bin): publish real work outcomes into herdr as signal + metadata#3
brchue-ux merged 4 commits into
mainfrom
fm/herdr-outcome-publisher

Conversation

@brchue-ux

@brchue-ux brchue-ux commented Aug 7, 2026

Copy link
Copy Markdown
Owner

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

  • Added bin/fm-herdr-outcome-publish.sh, a reusable publisher that resolves a herdr workspace target from a task's own state/<id>.meta (herdr_session=, herdr_workspace_id=) and makes two separate herdr workspace CLI calls — report-signal (one of the four existing transfer/completed/failed/idle kinds, direction mapped via --from/--to) and report-metadata (durable outcome=/summary= tokens) — keeping the momentary and durable channels decoupled per their different retention rules.
  • The publisher is a pure decoration: any unresolvable target (non-herdr task, missing session/workspace meta, missing herdr/jq, or a failing CLI call) is a silent no-op exiting 0, while a malformed call (wrong arg count or an invalid signal kind) exits 2 as a caller-bug usage error.
  • Wired the publisher into firstmate's two real outcome-learning moments: bin/fm-pr-merge.sh calls it right after a successful gh-axi pr merge (outcome=pr_merged), and bin/fm-teardown.sh calls it right before task meta removal (outcome=landed), skipped when --force is passed since a forced teardown discards possibly-unlanded work rather than reporting a landed outcome.
  • Reordered report-metadata's WORKSPACE_ID positional argument to come before its --source/--token options, 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.
  • Added tests/fm-herdr-outcome-publish.test.sh plus new cases in tests/fm-pr-merge.test.sh and tests/fm-teardown.test.sh that assert the exact captured CLI invocations via a fake logging herdr stub, and documented the new script in docs/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 via git log --all --diff-filter=A -- data/herdr-event-channel-research/report.md and a full-tree find). 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 propagates
  • bash tests/fm-pr-merge.test.sh — 11/11 pass including new test_publishes_herdr_outcome_on_merge asserting the exact captured CLI args via fake herdr stub after a successful gh-axi pr merge
  • bash tests/fm-teardown.test.sh — full file pass including new test_landed_teardown_publishes_herdr_outcome and test_forced_teardown_publishes_no_herdr_outcome (confirms --force suppresses both report-signal and report-metadata calls)
  • git status --porcelain post-run — confirmed no leftover test artifacts in the worktree
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Bchue 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.
@brchue-ux
brchue-ux force-pushed the fm/herdr-outcome-publisher branch from 0183e19 to d869a5a Compare August 7, 2026 19:02
@brchue-ux brchue-ux changed the title feat(bin): publish real work outcomes into herdr as signal + durable metadata feat(bin): publish real work outcomes into herdr as signal + metadata Aug 7, 2026
@brchue-ux
brchue-ux merged commit b1f8f29 into main Aug 7, 2026
10 of 11 checks passed
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