Skip to content

Commit 2371ee3

Browse files
committed
feat(app+boj): loopback HTTP backend, shared fight crate, expert summoning
Push #2 — wire the army and make the squabbler summonable, keeping the core detachable and every hand-off honest. squabble-fight (new crate): - The host-side fight brain, extracted from squabble-cli so the CLI and the App serve ONE planner and cannot drift: ecosystem-context reader (context.rs) + workflow ground-truth (workflows.rs) + the pure planner (plan / plan_at_root). git-mv'd to preserve history; tests moved along and extended (fail-safe on missing repo root; every red accounted for). squabble-app (stub → real): - Loopback-only axum server on 127.0.0.1:${SQUABBLE_PORT:-7741}: GET /health, POST /api/v1/diagnose (Gate → Diagnosis), POST /api/v1/fight ({slug, gate, repo_root?} → Outcome/Report manifest). This is the process the boj-server `cicd-squabbler-mcp` cartridge proxies to — cartridge gateways run in a Deno sandbox with --allow-net only (no subprocess), so the squabbler must be reachable over loopback HTTP. - The GitHub App *webhook* leg (check_run.requested_action + octocrab) remains honestly absent: no webhook route is registered; a delivery gets a plain 404, never a fake 200. Refuses non-loopback binding (no auth layer). squabble-cli: - `squabble fight --summon` (feature `boj`, ureq; the default build compiles the client out entirely and gains zero deps): maps each EscalateToExpert to its specialist cartridge via POST {BOJ_URL:-http://localhost:7700} /cartridge/<name>/invoke — Security→panic-attack-mcp/panic_attack_scan, Proof→echidna-llm-mcp/consult, Hypatia*→hypatia-mcp/hypatia_scan_repo. - Honest actuation: dispatch-fix is recorded as assessed (actuation external — no fixer cartridge exists today); a summon can only ADD evidence, never remove or downgrade an escalation, and never changes the outcome colour. - Fail-closed (AGENTIC no-silent-skip): unreachable server/expert appends explicit evidence to every escalation and the blockers list; a build without the feature refuses `--summon` loudly (exit 2) instead of pretending. squabble-core: - Diagnosis gains Serialize/Deserialize so hosts can emit it as evidence. No engine semantics changed; the SPARK-mirrored gate invariant is untouched. Verified: 42 default-feature tests + boj-feature tests green; fmt + clippy clean in both configs; live end-to-end — the App served /health, /diagnose, and /fight over the real ipv6-only checkout (the fight correctly no longer flags the AGPL label that PR ipv6-only#45 removed — the loop observes its own completed work); --summon verified fail-closed against a dead port and loudly-refusing without the feature. Companion: hyperpolymath/boj-server-cartridges cartridge `cartridges/domains/ci-cd/cicd-squabbler-mcp` (same branch name). Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SUURnQUnzTXYftzWFs5pfZ
1 parent a9bbf20 commit 2371ee3

14 files changed

Lines changed: 1768 additions & 364 deletions

File tree

.machine_readable/descriptiles/STATE.a2ml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ status = "active" # active | paused | archived
1212
[project-context]
1313
name = "cicd-squabbler"
1414
purpose = "CI/CD gate fighter: drives a stuck branch-protection gate to a legitimately-satisfied green by satisfying its required checks — never by admin override, enforce_admins toggle, or removing/renaming a required context. Rust fight engine + SPARK-proved gate invariant. Detachable; no hypatia/estate dependency."
15-
completion-percentage = 88
15+
completion-percentage = 92
1616

1717
[position]
1818
phase = "implementation" # design | implementation | testing | maintenance | archived
@@ -28,8 +28,10 @@ milestones = [
2828
{ name = "Call-in-the-big-guns — Moves 8-9 (EscalateToExpert → hypatia/fleet/echidna/security groups; AssignGateOwner → owned-upstream / misconfigured-gate / should-be-added-to-ci). Both non-satisfying by construction; SPARK invariant untouched.", completion = 100 },
2929
{ name = "Ecosystem-context reader (host-only a2ml/k9 → RepoContext; fail-safe, never a core dependency)", completion = 100 },
3030
{ name = "`squabble fight` orchestration — classifies each red as self-win | escalate | assign-owner via workflow ground-truth; first binary to emit an Outcome/Report evidence manifest. Proven on ipv6-only#43 (5 reds classified).", completion = 100 },
31-
{ name = "squabble-app GitHub App webhook server (currently an honest stub — exits EX_UNAVAILABLE rather than fake OK)", completion = 20 },
32-
{ name = "boj-server client + cicd-squabbler-mcp cartridge + specialist expert groups (escalations become live hypatia/fleet/echidna calls) — designed, deferred to next push; EscalateToExpert is the seam", completion = 0 },
31+
{ name = "Shared fight planner extracted to squabble-fight crate (context reader + workflow ground-truth + planner) so the CLI and the App serve one brain and cannot drift", completion = 100 },
32+
{ name = "squabble-app loopback HTTP backend (axum, 127.0.0.1:7741): /health, /api/v1/diagnose, /api/v1/fight — the process the cicd-squabbler-mcp cartridge proxies to. The GitHub App *webhook* leg (check_run.requested_action + octocrab) remains honestly absent (no webhook route registered).", completion = 100 },
33+
{ name = "boj-server expert client (feature `boj`, ureq; default build gains zero deps): `squabble fight --summon` maps each EscalateToExpert to its cartridge (Security→panic-attack-mcp, Proof→echidna-llm-mcp, Hypatia*→hypatia-mcp; dispatch-fix recorded as assessed+tracked, actuation external — no fixer cartridge exists). Fail-closed on unreachable experts; loud refusal when built without the feature.", completion = 100 },
34+
{ name = "cicd-squabbler-mcp cartridge (boj-server-cartridges cartridges/domains/ci-cd/): squabble_fight + squabble_diagnose tools, mod.js proxy to SQUABBLE_BACKEND_URL, no ffi block (JS dispatch path)", completion = 100 },
3335
{ name = "RSR scaffolding customisation (identity, root-allow, A2ML manifests)", completion = 80 },
3436
]
3537

@@ -39,8 +41,8 @@ milestones = [
3941

4042
[critical-next-actions]
4143
actions = [
42-
"Wire the escalation seam to boj-server: a feature-gated MCP/REST client + a cicd-squabbler-mcp cartridge, so EscalateToExpert calls hypatia-mcp/fleet-mcp/echidna live (specialist groups: Hypatia, Hypatia+Fleet, Proof, Security). Fail-closed if unreachable.",
43-
"Implement `squabble fight --apply` (and the squabble-app webhook) so self-win moves are enacted + re-run, not only planned.",
44+
"Implement `squabble fight --apply` (and the squabble-app GitHub App webhook leg: check_run.requested_action + octocrab) so self-win moves are enacted + re-run, not only planned.",
45+
"Live-fire --summon against a running boj-server with the expert backends up (hypatia :7701, panic-attack, echidna) — today's verification proves the wiring + fail-closed degradation; the experts themselves are not yet deployed.",
4446
"Extend the SPARK invariant to cover the licence-policy gate class (v0.2; v0.1 moves are Rust-only for that class).",
4547
"Register the CLADE (uuid 38bec2ed-bb12-44ee-9fb4-08872370c27b) into hyperpolymath/gv-clade-index (owner action).",
4648
]

0 commit comments

Comments
 (0)