CI Pipeline / documentation (push) Canceled after 0s
CI Pipeline / canary (push) Canceled after 10s
CI Pipeline / type-check (push) Canceled after 0s
CI Pipeline / gitea-offline (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 11s
CI Pipeline / go-surface (push) Canceled after 11s
CI Pipeline / rust-surface (push) Canceled after 11s
CI Pipeline / best-practices (push) Canceled after 10s
Auto-version and Release / release (push) Canceled after 30s
CI Pipeline / lint (push) Canceled after 19s
deploy / deploy (push) Canceled after 33s
Stdlib-only Go module deciding each wave's lane so the owner stops specifying: hot-state registry ~/.rune/hot/dispatch_registry.json (lock/unlock/show, 4h STALE + --prune), classify with the one data-driven keyword->surface map, prefix-overlap queue-behind (owner -> PRIORITY-QUEUE with landing-boundary yield), owner-origin solo latency, disjoint-surface parallel split suggestion, --apply lock take atomic and fail-loud on locked/stale/changed; scripts/dispatch_check.sh wraps the pre-spawn discipline. go test -race green, vet + gofmt clean. Contract ADMIT-wave-dispatch-classifier.
166 lines
8.1 KiB
Python
166 lines
8.1 KiB
Python
"""Admission dispatch for the DISPATCH CLASSIFIER wave (the owner's
|
|
mechanism-not-law directive: "can we have something that intelligently
|
|
decides that so i dont have to specify").
|
|
|
|
Builds src/go/dispatch-classifier — a zero-dependency (stdlib-only) Go
|
|
module that decides solo-attention vs parallel-factory vs queue for
|
|
each incoming wave so the owner never specifies: (1) REGISTRY —
|
|
~/.rune/hot/dispatch_registry.json hot-state entries {agent_id,
|
|
surfaces, kind, since, owner_origin} with lock/unlock/show CLI
|
|
subcommands and 4h STALE flagging + --prune; (2) CLASSIFY —
|
|
`classify --brief <file> [--paths p1,p2] [--owner-origin] [--apply]`:
|
|
extract candidate surface prefixes (explicit paths win, else brief
|
|
paths, else keyword→surface heuristics kept in ONE data-driven map),
|
|
compute prefix overlap vs the registry's locked surfaces, and emit the
|
|
verdict QUEUE-BEHIND (PRIORITY-QUEUE when owner-origin; lock-holder
|
|
yields at next landing boundary) / SOLO (owner watching, latency wins)
|
|
/ PARALLEL (multiple disjoint surfaces with a suggested split) / SOLO;
|
|
--apply takes the lock atomically, fail-loud on stale/locked; (3)
|
|
TESTS — red-first per rule: overlap detection, owner-origin priority,
|
|
multi-surface split suggestion, lock/unlock lifecycle, stale-lock
|
|
handling, prefix-vs-exact matching; go test -race green, vet/gofmt
|
|
clean; (4) DISCIPLINE WIRING — scripts/dispatch_check.sh, the one-liner
|
|
wrapper the session agent runs before spawning anything, documented in
|
|
the module README in plain English.
|
|
approval_ref 'user:dispatch classifier directive 2026-10-22'.
|
|
"""
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
|
|
from rune import construction_activation as cact # noqa: E402
|
|
from rune import construction_admission as cadm # noqa: E402
|
|
from rune import construction_mode as cmode # noqa: E402
|
|
from rune import scaffold as sc # noqa: E402
|
|
|
|
ROOT = os.path.join(os.path.dirname(__file__), "..")
|
|
|
|
OBJECTIVE = (
|
|
"Build the DISPATCH CLASSIFIER: create the self-contained stdlib-only "
|
|
"Go module src/go/dispatch-classifier that decides solo-attention vs "
|
|
"parallel-factory vs queue for each incoming wave so the owner never "
|
|
"specifies — implement the hot-state registry "
|
|
"~/.rune/hot/dispatch_registry.json with lock/unlock/show subcommands "
|
|
"(entries {agent_id, surfaces, kind, since, owner_origin}; entries "
|
|
"older than 4h flagged STALE in show with a --prune flag), implement "
|
|
"classify --brief <file> [--paths p1,p2] [--owner-origin] [--apply] "
|
|
"that extracts candidate surface prefixes (explicit paths win, else "
|
|
"brief-named repo-relative paths, else keyword→surface heuristics "
|
|
"kept in one data-driven map), computes prefix overlap against the "
|
|
"registry's locked surfaces, and emits the JSON verdict "
|
|
"{decision, reason, surfaces, locks_to_take, queue_behind} — "
|
|
"QUEUE-BEHIND naming the agent and surface when any candidate "
|
|
"surface is locked by an in-flight agent (PRIORITY-QUEUE on "
|
|
"owner-origin, noting the lock-holder yields at its next landing "
|
|
"boundary), SOLO when owner-origin (full-attention lane, latency "
|
|
"wins), PARALLEL with a suggested split when the brief names "
|
|
"multiple disjoint surfaces, else SOLO — with --apply taking the "
|
|
"lock atomically and failing loud on stale/locked; add red-first "
|
|
"tests per rule (overlap detection, owner-origin priority, "
|
|
"multi-surface split suggestion, lock/unlock lifecycle, stale-lock "
|
|
"handling, prefix-vs-exact matching) green under go test -race with "
|
|
"vet and gofmt clean; add scripts/dispatch_check.sh, the one-liner "
|
|
"wrapper the session agent runs before spawning anything (reads the "
|
|
"brief, runs classify, prints the verdict, locks with --apply), and "
|
|
"document usage in the module README in plain English"
|
|
)
|
|
AFFECTED = [
|
|
"src/go/dispatch-classifier/",
|
|
"scripts/admit_wave_dispatch_classifier.py",
|
|
"scripts/dispatch_check.sh",
|
|
]
|
|
|
|
def main() -> int:
|
|
store = os.path.join(ROOT, "store", "scaffold")
|
|
scaffold = sc.Scaffold(store, "rune")
|
|
|
|
md = cmode.classify_mode(
|
|
OBJECTIVE,
|
|
target_project="rune",
|
|
project_exists=True,
|
|
affected_surface=AFFECTED,
|
|
)
|
|
print("classified mode:", md.mode)
|
|
|
|
need = {
|
|
"need_id": "need-dispatch-classifier",
|
|
"objective": OBJECTIVE,
|
|
"origin": "worker",
|
|
"project": "rune",
|
|
"task_ref": "wave-dispatch-classifier",
|
|
"affected_surface": AFFECTED,
|
|
"evidence_refs": [
|
|
"src/go/failure-filer (stdlib-only module pattern: go.mod, "
|
|
"main.go, flat package, *_test.go)",
|
|
"~/.rune/hot/ hot-state file convention (task_state.json in "
|
|
"src/go/webfeed/internal/webfeed/server.go:390)",
|
|
"scripts/check_landing.py rule-5 scope matcher (_scope_covers "
|
|
"prefix law — reused for registry surface overlap)",
|
|
"scripts/admit_wave_presentation.py (this admission pattern)",
|
|
"scripts/dispatch_check.sh discipline wrapper (new)",
|
|
],
|
|
}
|
|
act = cact.activate(md, need=need, scaffold=scaffold,
|
|
builder="wave-dispatch-classifier")
|
|
print("activated:", act.get("activated"), act.get("mode"))
|
|
|
|
env = cadm.admit(
|
|
act,
|
|
objective=OBJECTIVE,
|
|
builder="wave-dispatch-classifier",
|
|
affected_surface=AFFECTED,
|
|
evidence_refs=need["evidence_refs"],
|
|
origin="worker",
|
|
task_ref="wave-dispatch-classifier",
|
|
expected_new_entities=[
|
|
"src/go/dispatch-classifier (stdlib-only Go module: go.mod, "
|
|
"main.go, registry.go, classify.go, README.md)",
|
|
"src/go/dispatch-classifier (hot-state registry "
|
|
"~/.rune/hot/dispatch_registry.json: lock/unlock/show, "
|
|
"atomic writes, 4h STALE flagging + --prune)",
|
|
"src/go/dispatch-classifier (classify: surface extraction — "
|
|
"explicit paths, brief parsing, one data-driven keyword map; "
|
|
"prefix overlap vs locked surfaces; QUEUE-BEHIND / "
|
|
"PRIORITY-QUEUE / SOLO / PARALLEL verdicts with suggested "
|
|
"split; --apply takes the lock atomically, fail-loud)",
|
|
"src/go/dispatch-classifier (red-first tests per rule: "
|
|
"overlap, owner-origin priority, split suggestion, "
|
|
"lock/unlock lifecycle, stale handling, prefix-vs-exact; "
|
|
"go test -race green, vet + gofmt clean)",
|
|
"scripts/dispatch_check.sh (session-agent pre-spawn "
|
|
"discipline wrapper: read brief, classify, print verdict, "
|
|
"--apply locks)",
|
|
"tests: red-first suites per rule, -race green",
|
|
],
|
|
expected_runtime_effects=[
|
|
"an agent can lock/unlock its surfaces in the hot registry "
|
|
"and show prints the table with STALE flags for entries "
|
|
"older than 4h; --prune removes stale entries",
|
|
"classify reads a brief and returns the verdict JSON "
|
|
"without the owner specifying the mode; overlap with an "
|
|
"in-flight lock queues behind the named agent; owner-origin "
|
|
"wins latency (SOLO) or jumps the queue (PRIORITY-QUEUE); "
|
|
"disjoint multi-surface briefs suggest a parallel split",
|
|
"the session agent runs scripts/dispatch_check.sh before "
|
|
"spawning anything and follows the printed verdict",
|
|
],
|
|
verification_obligations=[
|
|
"cd src/go/dispatch-classifier && go test ./... -race green; "
|
|
"go vet ./... clean; gofmt -l . empty",
|
|
"CLI proofs: lock/unlock/show lifecycle, stale flagging + "
|
|
"prune, classify verdicts for overlap/owner-origin/split "
|
|
"cases, --apply lock take + fail-loud on stale/locked",
|
|
"scripts/dispatch_check.sh round-trip on a real brief file",
|
|
],
|
|
approval_ref="user:dispatch classifier directive 2026-10-22",
|
|
contract_id="ADMIT-wave-dispatch-classifier",
|
|
project_store=store,
|
|
project_id="rune",
|
|
)
|
|
print(json.dumps(env, indent=2, default=str)[:2400])
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|