Repository navigation
fix: guard Lavish boards against lost form answers - #38
Merged
Merged
Conversation
…orm guard A decision board form whose inline onsubmit held text pasted into a quoted JavaScript string (an apostrophe in a title) failed to parse. The browser then submitted the form natively, the artifact frame landed on Lavish's 409 'no longer current' page, and a reload could not repair it, so answers were lost. fm-procevent-lavish.sh gains a check command that compiles every inline event handler and inline classic script, and arm now runs it first and refuses a board that would silently lose answers. A drop-in form guard asset cancels any uncancelled native submit, shows a visible alert, and queues a form-error prompt for the agent.
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
the lavish board is not capturing my responses.
No -- I entered the answers, and it submit. when I ddi that, I recieved a notice to reload the page that it was no longer current. However, reloadiung the page did not remediate the issue
Context: the board is the 2026-10-06 20:30 CDT status report, ~/firstmate/data/status-report-20261006/report.html (built by build.py in that folder; decision forms call window.lavish.queuePrompt), opened with
lavish-axi <file>as session http://127.0.0.1:4387/session/c6efbeaf94c38d45 and armed withbin/fm-procevent-lavish.sh arm <file>(procevent source lavish-c6efbeaf94c38d45). Evidence: report.html unchanged since 20:20:32; lavish lists the session open with 0 pending prompts and an agent-listener; the procevent runner relaunched at 21:31 with an empty claim output; no result file was ever written for that source, so no answer reached firstmate. The 2026-10-04 report used the same queuePrompt forms and its answers did arrive. The captain's answers were later given in chat, so nothing is pending on this board now.What Changed
checkcommand for inline event handlers and classic scripts, and run it on the physical artifact before every arm or re-arm, refusing registration when checks fail and reporting source locations.form-errorprompt.Risk Assessment
✅ Low: The changes are bounded to compile-only validation and an optional native-submit guard, and the comment-extraction and symlink fixes preserve the intended caller and ownership behavior.
Testing
After inspecting the change and CLI controls, exercised six targeted scenarios against an isolated real Lavish server and production process-event commands. Reproduced the stale-submit/reload failure, verified refusal and successful answer capture, and confirmed guard, comment, script-type, and symlink boundaries. Screenshots and persisted product outputs were collected; all scenarios passed and disposable resources were removed. No full suite, linters, formatters, or static analysis ran.
Evidence: Live CLI commands, refusal diagnostics, ownership transitions, and teardown
Source: Live CLI commands, refusal diagnostics, ownership transitions, and teardown
Evidence: Successful firstmate answer persisted by the real runner
Source: Successful firstmate answer persisted by the real runner
Evidence: Form-error delivered to the real process-event result
Source: Form-error delivered to the real process-event result
Evidence: Answer captured from board with JSON, module, and external script elements
Source: Answer captured from board with JSON, module, and external script elements
Evidence: Second task-owned answer persisted after re-arm
Source: Second task-owned answer persisted after re-arm
Evidence: Task inbox delivery before re-arm
Source: Task inbox delivery before re-arm
Evidence: Observed stale notice and guarded versus successful frame state
Source: Observed stale notice and guarded versus successful frame state
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
bin/fm-procevent-lavish.sh:269- Script extraction scans the original HTML before comments are removed. A valid board containing<!-- <script>const broken = ;</script> -->therefore has the inactive script compiled and is refused byarm, despite its live answer handlers working. The same invariant is violated at bin/fm-procevent-lavish.sh:267, where a commented-out guard counts as installed and suppresses the warning at :359. Comment removal at :279 happens too late for either operation. Make the shared extraction boundary distinguish live script elements from comment contents for both compilation and guard detection, without stripping HTML-like comments inside live JavaScript. Related changed sites: docs/verification/process-event-sources.md:131 promises commented-out scripts are ignored; tests/fm-procevent.test.sh:5032 and :5062 exercise only a commented-out form, leaving this script case uncovered.bin/fm-procevent-lavish.sh:394- The new gate checks the caller's path before canonicalization, whilecmd_checkrejects final-component symlinks at bin/fm-procevent-lavish.sh:311. Opening a sound board through a symlink and then arming that same path now fails before registration. Previously,armresolved the path and passed the physical file to its listener; source identity still explicitly supports this alias at :202–208, with existing coverage in tests/fm-procevent.test.sh:3156–3159. Resolve the artifact before invoking the checker and check the same canonical file used by the listener at :395–397. This must hold for both registration paths, :400 (task-owned) and :406 (firstmate-owned), including re-arms.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
Inspected the target diff and ranlavish-axi --helpto establish the runtime and isolation controls.Created a marked disposable home withbin/fm-lab-home.sh create <workspace-local-lab>and launched the reallavish-axi server --port 56033 --verbosewith isolated state.Ranbin/fm-procevent-lavish.sh check <board>andarm <board>against broken inline handlers, broken classic scripts, sound forms, commented-out scripts/guards, and JSON/module/external script elements.Drove real Lavish sessions in Chromium: selected answers, clicked Queue answer and Send to Agent, and inspected persisted process-event results and firstmate notifications.Submitted an unguarded apostrophe-broken form, reloaded Lavish, and submitted again to reproduce the repeated stale-artifact notice.Submitted a guarded form whose handler throws; captured its visible alert, delivered form-error result, and verifiedbin/fm-procevent-lavish.sh answers <result>returned no choice.Opened and armed a sound board through a symlink; re-armed the firstmate-owned alias and observed still-listening.Ran task-owned symlink arm/re-arm against a disposable private tmux endpoint: refused premature re-arm, captured feedback in the task inbox, acknowledged round one on re-arm, and captured a second answer.Captured browser screenshots, CLI transcripts, persisted feedback, inbox state, and round acknowledgment evidence; retired all sources, stopped the private server and tmux instance, and removed disposable workspace files.✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.