feat(loopspec): bind verifiers executably and actuate lawful transitions - #53
feat(loopspec): bind verifiers executably and actuate lawful transitions#53sbracewell64 wants to merge 2 commits into
Conversation
LoopSpec validated specs nobody could run. Measured at HEAD: one spec registered, zero callers of bin/fm-loopspec.sh anywhere in bin/, zero entries in state/loopspec/, and execution_path_implemented false on all sixteen triggers, so assert_runnable could never pass. Two defects kept it inert. The verifier was a bare name. verification.verifier was a slug the machinery never executed, and finish took the verdict from its caller. A spec naming a verifier that did not exist validated, claimed, and reached a success terminal on an asserted pass - the named-but- unreachable case, which looks bound and verifies nothing. Now verifier_command names a repository-owned executable, an enabled spec must have one that resolves and runs, `verify` executes it, and a success terminal requires a recorded run bound to that spec version, event key and iteration. NO_VERIFIER_RAN is never success, and the party doing the work no longer certifies the work. Nothing actuated. bin/fm-loop-actuate.sh is the governed wake-to-action table: when one lawful transition follows from the recorded state, code executes it instead of spending a coordinator turn. It is not a runtime - no loop, no poll, no daemon, no storage of its own. Arming appends an ordinary check record to the existing durable queue, and every execution leaves loop=<spec>@<version> with its canonical verifier, without which adoption cannot be demonstrated at all. Selection keeps its ruled shape: the deterministic filter narrows over tiny typed applicability headers, never spec bodies, and hands a genuine two-or-three tie back as a decision rather than inventing a tie-break. Also generalizes required_terminal_states, which hard-coded the first spec's own vocabulary and made a second spec unauthorable, to the universal safety stops plus required kinds. Adds fork-landing as the first enabled production spec. It terminates at a carried pull request whose checks have run, never a merged one, and forbids merging outright: a loop that merged would convert a delivery mechanism into an authority expansion.
…arsable Production run against a freshly opened fork pull request exposed a second shape from the forge: a pull request whose checks have not been registered reports "no CI checks configured" rather than a summary line. The verdict was already correct - unavailable, never a resolved empty set, because a pull request nothing has examined must not read as verified - but the diagnostic blamed an unparsable summary for what is actually a pull request too young to have checks. The distinction matters when reading why a loop did not advance.
Production evidence — LoopSpec activationReal registry ( 1. Attended — this branch, before its fork PR existedDeterministic selection, iteration opened, verifier read the forge and 2. UNATTENDED — a real fork landing whose checks had resolvedEvidence the verifier itself produced and the loop recorded: This is the approved unattended authority shown operational rather than 3. A repeated wake for an already-handled event mutates nothing4. Fail-closed on a pull request nothing has examinedA pull request with no checks registered is unavailable, never a resolved 5. Arming appends to the existing durable wake queueAn ordinary `check` record on the shared queue — the same kind the existing 6. The inert spec stays inertDurable execution recordEvery execution carries `loop=@` and its canonical Measurements
|
Makes LoopSpec operational. Delivered under the captain's 2026-08-06 activation
commission and the standing fork-retarget rule.
Delivery disclosure — read this first
This PR carries no attestation marker and has had no automated review. It
ships direct-PR, deliberately bypassing the no-mistakes pipeline, so nothing here
has been through automated code review. Everything below under "What I verified"
I ran myself; everything I did not verify is named as such.
The state this changes
Measured at fork trunk
ed376cf:bin/fm-loopspec.shanywhere inbin/: 0state/loopspec/: 0execution_path_implemented: 0 of 16That last figure is the structural reason nothing ran:
assert_runnablerequiresan implemented, verified, enabled execution path, and no trigger had one, so no
spec could ever start an iteration.
Two defects kept it inert
1. The verifier was a bare name that nothing executed
verification.verifierwas a slug, andfinishtook the verdict from--verifier-result— supplied by the caller. Reproduced on the shipped codebefore changing it: a spec naming
totally-nonexistent-verifiervalidated,claimed, and reached a success terminal on an asserted
pass.This is the named-but-unreachable case: it looks bound and verifies nothing.
Now
verification.verifier_commandnames a repository-owned executable;an enabled spec must name one that resolves inside the repo and is executable;
fm-loopspec.sh verifyruns it; and a success terminal requires a recordedrun bound to that spec version, event key and iteration.
NO_VERIFIER_RANisnever success, and a verdict cannot be carried over from an earlier iteration.
Non-success terminals deliberately still need no run — a loop must always be able
to record that it failed, including when the verifier is what broke.
2. Nothing actuated
bin/fm-loop-actuate.shis the governed wake-to-action table. When exactly onelawful transition follows from the recorded state, code executes it rather than
spending a coordinator turn. Run
fm-loop-actuate.sh tableto read the mappingwithout reading the code.
It is not a runtime: no loop, no sleep, no poll, no daemon, no storage of its
own. One invocation performs at most one transition and exits. Arming appends an
ordinary
checkrecord to the existing durable wake queue throughfm_wake_append— the same pathfm-procevent.shuses — rather than opening aparallel one.
Every execution appends
loop=<spec-id>@<version>with its canonical verifier.Without that record adoption cannot be demonstrated at all.
Also: the schema made a second spec unauthorable
required_terminal_stateshard-coded the first spec's own vocabulary(
delta_emitted,confirmed_work_found). Generalized to the universal safetystops plus
required_terminal_kinds, so a loop must declare how it succeeds,no-ops, fails and refuses without inheriting another domain's nouns.
Selection keeps its ruled shape
The deterministic filter narrows over tiny typed applicability headers, never
spec bodies — the registry is never loaded into context. A genuine two-or-three
tie is handed back as a decision rather than resolved by an invented tie-break,
preserving the ruling that route selection is a decision firstmate makes. Four or
more is reported as a filtering defect, not a harder choice.
The production loop stops before the merge
loopspecs/fork-landing.jsonis the first enabled spec. Its terminal is acarried pull request whose checks have run — never a merged one — and merging
is in
forbidden_actions. A loop that merged would convert a delivery mechanisminto an authority expansion. A test asserts the spec declares no merge terminal,
permits no merge action, and forbids merging outright.
Its verifier is level
l2: deterministic, reading the forge, needing no model andno vendor diversity — which matters while maker and checker sit with the same
vendor.
Production evidence
Real execution against the live fork, real registry, real verifier:
The verifier read GitHub and correctly reported no fork pull request existed for
this branch yet, so code executed CONTINUE.
Then the same loop, through the unattended path, against a real fork landing
whose checks had resolved:
That is the approved unattended authority demonstrated as operational rather than
report-only, and it landed nothing: merge authority is not the proof case. The
evidence the verifier itself recorded includes
NOT GREEN - 2 check(s) failed, so the success record cannot be misread as agreen light.
Full production transcript, including the duplicate-wake refusal, the durable
wake append and the fail-closed cases, is in a comment on this PR.
What I verified
Run on this branch, all passing:
bin/fm-lint.sh— clean (ShellCheck 0.11.0, pinned)bin/fm-test-run.sh tests/fm-loopspec.test.sh tests/fm-loop-actuate.test.sh—24 + 11 assertions, 0 failed
bin/fm-test-run.sh --check-coverage—total=134 parallel=24 serial=99 serial_shards=4 herdr=11bin/fm-doc-audience-check.sh—ok surfaces=72 local_links=213bin/fm-test-run.sh --lane portable-serial-2of4—total=25 failed=0 skipped_gate=4, the shard both my suites land inTerminal, stagnation and budget behaviour each have red-capable coverage: every
block drives its negative control and witnesses it failing before trusting the
positive result.
Not verified: the full test suite beyond the shards named above, and behaviour
on any harness or runtime backend other than this one. No automated review ran.
Two pre-existing CI failures that are NOT from this branch
Both are expected. Neither is fixed or silenced here.
PR must be raised via no-mistakes— this PR carries no attestation markerby design, as disclosed above.
Behavior portable serial 2— a trunk-wide failure the fork is behindupstream on; firstmate is handling it by resyncing.
Proven rather than asserted: PR #49 is an unrelated branch off the same fork
trunk
ed376cf, with entirely different content and no LoopSpec changes at all,and its checks read
12 passed, 2 failed, 14 totalfailing exactlyPR must be raised via no-mistakesandBehavior portable serial 2.Serial shard 2 passes locally on this branch (
total=25 failed=0 skipped_gate=4), which does not contradict the CI failure — it locates it in theCI environment rather than in this change, and 4 env-gated tests skip locally.
This PR's own checks had not started when this was written. The fork's Actions
queue is backed up: PR #52's runs were still
queued36 minutes after creation,and no run had been scheduled for this PR at all. So its result is genuinely
unknown, not green — which is exactly what the new verifier reports for it:
unavailable: pull request 53 has no checks registered yet, so nothing has examined it. This PR is expected to be red on the two checks above, and is notbeing presented as green.
Scope boundary
Deliberately stopped at a working loop with real evidence rather than half-
building the whole. Not included, and each is separate work: an automatic
detector for
upstream-changes(arming is firstmate's existing observation madeexplicit, and
detector_implementedstaysfalseaccordingly); the two-thresholdcapacity band, which is ruled but owned by a separate queued task and is not
reimplemented here; and a verifier adapter for
approved-work-reconciliation,which stays
ready_not_activewith its gap recorded truthfully rather thanhidden behind a bare name.