Skip to content

feat(bin): add mark-feed process-event adapter for page marks - #9

Merged
NewAiCoder merged 2 commits into
mainfrom
fm/markfeed-procevent-adapter
Sep 26, 2026
Merged

NewAiCoder merged 2 commits into
mainfrom
fm/markfeed-procevent-adapter

Conversation

@NewAiCoder

Copy link
Copy Markdown
Owner

Intent

The captain's words (2026-09-26): "when I decide something here, currently you have no way of knowing that I did that until I tell you ... How can we improve this for session ledgers in general and any decide pages where I click anything, globally in all our page templates?" and, on the plan, "Yeah I think this is a good plan."
The page server side is shipped: a mark feed with a long-poll endpoint and a poll script that blocks until the next mark, prints one line per mark (mark <surface> <slug> <kind> <item> <value> [session=<8 chars>]) and exits. What is missing is the firstmate side: a process-event adapter so firstmate can register that script as a source and get a check: wake per mark.

What Changed

  • Added bin/fm-procevent-markfeed.sh, a process-event adapter (arm, classify, --help). It registers the page server's poll script as a source and turns each batch of mark <surface> <slug> <kind> <item> <value> [session=<8 chars>] lines into one check wake. The poll command is stored as argv and run directly, never through a shell, and mark text is treated as inert data. A clean exit with nothing printed re-arms silently. A poll failure with no marks is one terminal captured error that stops the source.
  • Added tests/fm-procevent-markfeed.test.sh and wired it into bin/fm-test-run.sh (test family, timing baseline, and the changed-path mapping for bin/fm-procevent-markfeed.sh).
  • Documented the adapter in docs/configuration.md, docs/scripts.md, and the process-event-sources skill. The skill now covers arming and the wake handling for marks, idle, error, and unknown outcomes.

Risk Assessment

✅ Low: A new, self-contained adapter that mirrors the existing quota and lavish adapters' arm/poll/classify/terminal/silent seams, treats mark lines as inert data, and has behavioral tests. I found no defect or unrequired component.

Testing

Ran the adapter's behavioral test file (passes under umask 022) and drove the adapter live through the real fm-procevent.sh runner in isolated state dirs. Marks gave one check wake per batch with the lines carried intact, idle gave no wake, and a failing command gave one wake and retired the source. The hostile-mark-line and arm/retire validation cases were exercised only by the test harness, so they are recorded as untested live. The one problem is a test-environment quirk: under the 0002 umask the test's final arm/retire case errors out, exactly as the sibling quota test does.

  • Live validation: ✅ go - 4 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Arm a mark-feed poll command and get a check: wake when it prints a mark (through the real procevent runner) ✅ pass live Live arm + fm-procevent.sh start: wake queue holds check: procevent markfeed markfeed-live 1, pending=1
A multi-mark batch arrives as one wake and the result carries both mark lines verbatim ✅ pass live Captured markfeed-m.1.result shows marks: 2 and both mark lines; a single wake entry
A clean exit with nothing printed re-arms silently with no wake ✅ pass live Live idle source: no wake entry for markfeed-i, pending=0
A failing poll command surfaces once and stops the source instead of waking on every restart ✅ pass live Live fail source (exit 5): one wake for markfeed-f, source absent from list afterwards
Adversarial: hostile mark line (shell metacharacters) is carried as inert data and cannot forge the result header ⏸️ untested no The prior payload recorded live=false for this scenario; it was covered only by tests/fm-procevent-markfeed.test.sh, not driven through the full runner against a real page server, so no live result wa…
Arm rejects a relative path, a missing command, and an invalid name; retire removes the source ⏸️ untested no The prior payload recorded live=false for this scenario; it was covered only by the test harness in an isolated state dir, not driven against the live product, so no live result was established.
Evidence: live marks run: wake queue and captured result
wake: 1790450831 1 check procevent:markfeed-m:1 check: procevent markfeed markfeed-m 1
result:
status: marks
exit: 0
marks: 2
output:
mark decide 2026-09-26-live card-1 choice yes session=abcd1234
mark ledger 2026-09-25-y t2 done true
list: markfeed-m markfeed none 1
- Outcome: ⚠️ 1 info across 1 run (2m9s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

⚠️ **Test** - 1 info
  • ℹ️ tests/fm-procevent-markfeed.test.sh (and the sibling fm-procevent-quota.test.sh) fail at the arm/retire step when run under umask 0002 (the no-mistakes daemon's umask) with 'process-event state root is not a private directory (bad-mode)'. They pass under umask 022. This is a pre-existing environment quirk shared with the sibling test, not a defect in this change.
  • Live validation: ✅ go - 4 of 6 scenarios driven live against the product
Scenario Result Live Evidence
Arm a mark-feed poll command and get a check: wake when it prints a mark (through the real procevent runner) ✅ pass live Live arm + fm-procevent.sh start: wake queue holds check: procevent markfeed markfeed-live 1, pending=1
A multi-mark batch arrives as one wake and the result carries both mark lines verbatim ✅ pass live Captured markfeed-m.1.result shows marks: 2 and both mark lines; a single wake entry
A clean exit with nothing printed re-arms silently with no wake ✅ pass live Live idle source: no wake entry for markfeed-i, pending=0
A failing poll command surfaces once and stops the source instead of waking on every restart ✅ pass live Live fail source (exit 5): one wake for markfeed-f, source absent from list afterwards
Adversarial: hostile mark line (shell metacharacters) is carried as inert data and cannot forge the result header ⏸️ untested no The prior payload recorded live=false for this scenario; it was covered only by tests/fm-procevent-markfeed.test.sh, not driven through the full runner against a real page server, so no live result wa…
Arm rejects a relative path, a missing command, and an invalid name; retire removes the source ⏸️ untested no The prior payload recorded live=false for this scenario; it was covered only by the test harness in an isolated state dir, not driven against the live product, so no live result was established.
  • bash tests/fm-procevent-markfeed.test.sh under umask 022 (all cases pass; under the daemon's umask 0002 the final arm/retire case fails with a bad-mode private-directory error, same as the sibling quota test)
  • Live: fm-procevent-markfeed.sh arm --name live -- &lt;poll script&gt; then fm-procevent.sh start markfeed-live in an isolated FM_HOME; a poll script printing one mark line produced one durable check: procevent markfeed markfeed-live 1 wake and 1 pending
  • Live: a two-mark poll produced one wake per batch, with the captured result document carrying both mark lines verbatim under output:
  • Live: a poll that exits 0 with no output added no wake and left 0 pending
  • Live: a poll that exits 5 produced one wake and the source was retired from list, so it is not restarted
  • Live: fm-procevent.sh handled cleared pending and fm-procevent-markfeed.sh retire live removed the source
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@NewAiCoder
NewAiCoder merged commit 3ce7f05 into main Sep 26, 2026
14 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