feat(bin): add decision-tier classifier and default-with-veto CLI - #2862
feat(bin): add decision-tier classifier and default-with-veto CLI#2862pramendra wants to merge 9 commits into
Conversation
Fleet engineering plan workstream 1 ("widen the judgment channel"): a
category->tier classifier (auto / default-veto / hard-stop, fail-closed
on anything unrecognized), a timed default-with-veto record that
expires into action, and a report that turns a session's escalation
count into a measured number instead of a felt impression.
Standalone building block only - nothing in firstmate's live
escalation path calls into it yet; wiring it in is the captain's call.
…lib in toolbelt table
Confidence Score: 3/5The PR is not yet safe to merge because lock recovery can permanently block all decision writers and can delete an unrelated empty directory. The breaker mutex has no abandonment recovery, so termination during stale-lock handling leaves future writers retrying forever; recovery also still removes an empty directory without proving it belongs to this locking implementation. Files Needing Attention: bin/fm-decision-tier-lib.sh Reviews (8): Last reviewed commit: "no-mistakes: apply CI fixes" | Re-trigger Greptile |
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
| fm_decision_tier_lock_break() { # <lockdir> | ||
| local lockdir=$1 | ||
| local mutex="$lockdir.break" | ||
| mkdir "$mutex" 2>/dev/null || return 0 |
There was a problem hiding this comment.
Breaker mutex permanently blocks writers
When a process terminates after creating <log>.lock.break but before removing it, every later breaker returns because the mutex directory already exists. The stale primary lock therefore remains, causing all subsequent decision writers to retry indefinitely without recording their decisions.
| rmdir "$lockdir" 2>/dev/null | ||
| elif [ -e "$lockdir" ]; then |
There was a problem hiding this comment.
Intent
Workstream 1 of the fleet engineering plan (data/fleet-engineering-plan.html, ranked first by measured leverage, 'closes C, the actual 10x lever'): tier every decision into three classes - auto (consistent with precedent; firstmate acts and logs it), default-with-veto (firstmate states a recommendation and a default, acts unless the captain objects within a stated window, and the action is reversible), and hard stop (merges, destructive or irreversible actions, scope expansion, client-facing semantics - these always escalate, unconditionally). Build the MECHANISM (the classifier, the default-and-timeout machinery, the logging) as a library/policy module usable by firstmate's own escalation logic, with the three tiers as an explicit, documented, extensible classification. Do NOT wire it to actually change firstmate's live behavior yet (that activation is the captain's call) - make the mechanism real, tested, and ready to be turned on. Done when: a session's escalation count is a reported, measurable quantity, and every tier-2 decision carries a stated default that expires into action rather than blocking indefinitely. Acceptance criteria: the described mechanism is built and demonstrably works (show it, don't just assert it); prove any check added can fail by mutating what it guards and showing it go red; claim only what was measured, stating plainly what was NOT built and why scope was deliberately narrowed. This is firstmate's own shared tracked material (architecture work) - firstmate-coding-guidelines applies; keep scope to exactly what is asked, no speculative generality, no control planes beyond what is described.
What Changed
bin/fm-decision-tier-lib.sh, a sourced-only library implementing the single-owner category→tier classification table (auto/default-veto/hard-stop, failing closed tohard-stopon unrecognized categories), a 9-field TAB-separated decision-record log shape, default-with-veto status derivation (pending/vetoed/expired/unknown) computed purely from the log and a supplied epoch, and an aggregate report emitting counters includingescalation_count. Mutators (log_auto,log_hard_stop,open_default,veto) refuse when a category's tier disagrees with the requested operation or when a veto is attempted outside the pending window. The library is not called from firstmate's live escalation path.bin/fm-decision-tier.sh, a CLI over the library exposingclassify,categories,auto,hard-stop,open,veto,status, andreportsubcommands, with a--now <epoch>override on time-sensitive subcommands for deterministic use.tests/fm-decision-tier-lib.test.shandtests/fm-decision-tier.test.shcovering the classification table, record/log mutators, status derivation, and CLI subcommands; list both new scripts indocs/scripts.md's toolbelt table; add the generated.serena/project.ymland.serena/.gitignore.Risk Assessment
✅ Low: A self-contained, unwired library + CLI with no call sites elsewhere in the codebase; ran both new test suites (28 assertions) and they pass, and a targeted mutation of the fail-closed default arm correctly turned the corresponding assertion red, confirming the guard is real rather than vacuous.
Testing
Ran both new focused suites (
tests/fm-decision-tier-lib.test.sh,tests/fm-decision-tier.test.sh) directly — all assertions pass; verified the fail-closed classification guard is a real, mutation-provable check by flipping its default case and confirming both suites go red on that exact assertion, then restored the file cleanly; and produced an end-to-end CLI transcript exercising the full auto/default-veto/hard-stop lifecycle (including refusal of mis-tiered logging, a veto inside the window, a too-late veto refusal, and the aggregate escalation_count report) against a real decision log, which is the product-level evidence for this CLI mechanism.Evidence: End-to-end CLI transcript: classify/auto/hard-stop/open/veto/status/report lifecycle over a real decision log
Source: End-to-end CLI transcript: classify/auto/hard-stop/open/veto/status/report lifecycle over a real decision log
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-decision-tier-lib.test.shbash tests/fm-decision-tier.test.shmutation test: flipped fm_decision_tier_classify's fail-closed default arm from hard-stop to auto, reran both suites (both went red on the fail-closed assertions), then restored the file and reran both suites (green, git diff clean)manual CLI transcript: bin/fm-decision-tier.sh classify/auto/hard-stop/open/status/veto/report against a fresh temp log, covering the full tier lifecycle and mis-tier refusals✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.