fix(bin): acknowledge idle Pi submissions on Herdr - #2042
Closed
zachlandes wants to merge 9 commits into
Closed
zachlandes wants to merge 9 commits into
zachlandes wants to merge 9 commits into
Conversation
* Kept native agent-state confirmation unchanged for non-Pi agents.\n* Required a matching idle Pi identity and empty composer before clearing a digest buffer.\n* Added unit, real-lab, and showboat evidence for delivered and pending input.
zachlandes
force-pushed
the
fm/fix-afk-pi-herdr-ack
branch
from
August 11, 2026 01:58
89cf63d to
829f15a
Compare
Sways1024
added a commit
to Sways1024/firstmate
that referenced
this pull request
Aug 11, 2026
…rmed Root cause (kunchenguid#1859's residual after the composer-classifier fix): inject_msg types a digest once and requires backend confirmation; a submit that actually LANDED but returned `unknown` (pane unreadable at confirm time) preserved the buffer, and the next flush retyped the identical digest into the now-empty composer as a duplicate turn. The upstream 16h incident measured 94 no-op messages - 59 repeat deliveries of unchanged payloads - costing $6.90. Fix: an unknown verdict records the typed digest's hash and time in state/.subsuper-last-unconfirmed-inject. When the exact same digest next reaches an affirmatively EMPTY composer within FM_INJECT_DEDUP_SECS (default 3600), the earlier Enter is treated as accepted - a swallowed Enter would still show the text as pending and defer on the composer guard - and the buffer clears without a retype. A different digest always types normally, and a confirmed submit clears the marker. Suppressing the rare genuinely lost identical digest costs nothing: the payload is by definition unchanged. Regression: tests/fm-daemon.test.sh gains the unknown-then-identical case (marker armed, no retype, marker cleared, different digest unaffected), verified to fail against the previous retype behavior. All 100 daemon assertions plus the live herdr away-mode e2e tests pass. Upstream: kunchenguid#1859 (open; PR kunchenguid#2042 attacks the Pi acknowledgement half, unmerged).
* Refreshed the branch past upstream's Cursor harness work, which had moved the same Herdr submit core this fix touches. * Kept both new helpers rather than either side whole. Upstream added a rendered busy-footer read for a harness whose native agent-state never reports idle; this branch added the Pi identity-corroborated composer acknowledgement. Both sides had inserted a new function at the same point after fm_backend_herdr_composer_state, which is the only reason they collided. * The two paths cannot shadow each other: they sit on opposite arms of the submit core's idle-baseline test. A Cursor pane reports native `blocked`, which classifies busy, so it always takes the footer arm; Pi reports idle and always takes the Pi arm. A non-Pi agent reaching the Pi arm still resolves to `pending` exactly as before. * Merged the architecture sentence both sides rewrote so it names the footer fallback and the Pi acknowledgement instead of only one. * Added Cursor to the verification record's list of harnesses whose submit path this fix leaves alone; that list was written before the Cursor harness existed and read as complete.
# Conflicts: # .agents/skills/afk/SKILL.md # bin/backends/herdr.sh # docs/architecture.md # docs/herdr-backend.md # docs/verification/runtime-backends.md # tests/fm-backend-herdr.test.sh
Contributor
Author
|
Closing this PR. The behavior it adds — transport-layer acknowledgement of idle Pi submissions on Herdr — already exists on main as of commit 1bb72cc (via #2647): fm_backend_herdr_composer_state is already consulted whenever native state stays idle, for every harness including Pi. The function added here introduces only an extra |
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
Refresh the EXISTING upstream pull request #2042 ("fix(herdr): acknowledge idle Pi submissions") past its merge conflicts. This is NOT new feature work. The sole goal is to make that already-open pull request mergeable again after upstream main moved underneath it. It had mergeable=false, mergeable_state=dirty.
METHOD IS FIXED AND NOT OPEN TO CHANGE. Merge current origin/main INTO the branch, then push normally. Never rebase, never force-push, never reset --hard, never filter-branch this branch. Two load-bearing reasons: a history rewrite was not authorized, and a merge is trivially revertable while a rewritten branch is not. This is why the branch deliberately carries merge commit 315bb41 with two parents (829f15a, the previous pull request head, and f1a4af4, origin/main) instead of a linear history. Do not linearize it. Do not "clean up" the merge commit.
CONFLICT RESOLUTION RULE. For every conflict: understand what upstream changed and why, understand what this branch intends, and produce the version that preserves BOTH. A conflict resolved by deleting the other side's behaviour is a silent regression and was explicitly ruled unacceptable.
Two files conflicted. Both were resolved by keeping both sides.
bin/backends/herdr.sh. Upstream (PR feat: add Cursor CLI crew harness #2238, Cursor CLI crew harness) and this branch each inserted a DIFFERENT new function at the same insertion point just after fm_backend_herdr_composer_state. That adjacency was the entire reason they collided; the two functions are unrelated. Both were kept: upstream's fm_backend_herdr_rendered_busy_state (rendered busy-footer delivery confirmation for a harness whose native agent-state never reports idle) and this branch's fm_backend_herdr_pi_idle_composer_state (Pi identity-corroborated idle composer acknowledgement). The two paths provably cannot shadow each other: they sit on opposite arms of the submit core's idle-baseline test, and fm_backend_herdr_classify_submit_agent_status maps blocked to busy, so a Cursor pane (which Herdr reports as blocked in every state) always takes the footer arm and can never reach the Pi fallback, while Pi reports idle and always takes the Pi arm. A non-Pi agent that does reach the Pi arm still resolves to pending, exactly as before the change.
docs/architecture.md. A single sentence that both sides had rewritten. Merged so it names upstream's pre-Enter rendered-footer fallback AND this branch's Pi-only idle-delivery acknowledgement, rather than taking either side whole.
TWO DELIBERATE EDITS BEYOND THE RAW CONFLICT HUNKS. Upstream's new Cursor harness falsified two claims this branch had written as complete enumerations, so each was extended to stay true after the merge. First, the closing summary comment on fm_backend_herdr_send_text_submit had been narrowed into an exhaustive two-way claim and now also names the non-idle rendered-footer fallback. Second, the per-harness "retain their existing submit paths" list in docs/verification/runtime-backends.md now includes Cursor. These are intentional accuracy repairs that keep the merged tree from asserting something false. They are not scope creep and should not be reverted as unrelated.
SCOPE CONSTRAINT. Conflict resolution only. Do not improve unrelated code, do not refactor, do not extend the underlying Pi fix, and do not make behavioural choices this pull request never made. The branch's contribution over origin/main is deliberately exactly its original 14 files: no more, no fewer.
REPO CONTRIBUTOR RULES that apply to this change: one full sentence per line in tracked Markdown, plain dash rather than em dash, shellcheck-clean bin scripts, tests colocated in tests/ following the existing pattern, and never an agent name as a commit co-author.
DELIVERY CONSTRAINT. This pull request ALREADY EXISTS and must be UPDATED, never duplicated. Do not open a second pull request for this branch. Merge authority belongs to the upstream maintainer and is explicitly NOT ours; do not merge pull request 2042 and do not ask anyone to merge it. The job ends at green checks on the refreshed head.
KNOWN PRE-EXISTING FAILURES, ALREADY INVESTIGATED, OUT OF SCOPE, DO NOT FIX HERE. Four tests fail on this branch: tests/fm-bearings-snapshot.test.sh, tests/fm-wake-queue.test.sh, tests/fm-pi-watch-extension.test.sh, and tests/fm-calm-pi-extension.test.sh. All four were verified to fail byte-identically on a clean origin/main checkout with no merge involved, so they are pre-existing upstream failures in this environment and are not caused by this change. Three of them sit in areas upstream heavily rewrote (calm mode, wake queue, bearings) that this branch never touches. Fixing them would expand this conflict refresh well past its authorized scope.
EVIDENCE THAT THE MERGED AREA IS SOUND. tests/fm-backend-herdr.test.sh passes 178 of 178 with zero failures, with BOTH sides' cases green in the same run: this branch's three Pi tests and upstream's four Cursor and rendered-footer tests. bin/fm-lint.sh is clean, bin/fm-doc-audience-check.sh reports ok, and the test-runner coverage guard passes.
What Changed
Risk Assessment
✅ Low: The merge preserves both conflicted behaviors, retains the durable Pi acknowledgement invariant, and limits branch changes over main to the intended 14 files.
Testing
Targeted adapter tests and a real Pi-on-Herdr away-mode run confirmed exactly-once idle delivery, retained pending input, and preserved Cursor's rendered-footer path; commit topology and 14-file scope also match intent. This is a CLI/backend change, so the live transcript is the reviewer-visible evidence rather than a screenshot.
Evidence: Real Pi/Herdr end-to-end acknowledgement transcript
ok - real Pi/Herdr idle-native delivery clears the buffer after one typed digest ok - real Pi/Herdr unsubmitted input preserves the pending buffer evidence: pi=0.84.2 herdr=0.8.0 protocol=19 successful_send_texts=1Evidence: Focused Herdr adapter test transcript covering both merged behaviors
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
⏭️ **Rebase** - skipped
Step was skipped.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
Inspectedgit show -s --format='%H %P' HEADand the base-to-head file list to confirm merge commit315bb41retains both required parents and exactly 14 changed files.Rantests/fm-backend-herdr.test.sh, exercising the Pi fallback, swallowed-Enter handling, unchanged native confirmation, and Cursor rendered-footer fallback together.RanFM_AFK_PI_HERDR_ACK_E2E=1 tests/fm-afk-pi-herdr-ack-e2e.test.shagainst real Pi 0.84.2 and Herdr 0.8.0 protocol 19.Inspected the saved end-to-end transcript and confirmed the worktree remained clean after test teardown.bin/fm-composer-lib.sh:1304- The comment still says Herdr confirms only through native agent-state; updating it would expand the explicitly fixed 14-file change scope.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.