Status: partial build, clean stopping point. Handing to the separate build-mode project for completion.
Date: 2026-06-05
Origin: uploaded m87-governed-loop.bpmn (reference model) + README.md. Goal is a dual reference/executable MIT OSS repo for github.com/MacFall7, hardened enough to claim BPMN authorship for the Camunda FDE application.
A BPMN 2.0 encoding of the M87 governed execution loop (Proposal ≠ Execution), in two forms:
reference/m87-governed-loop.bpmn— the originalisExecutable="false"governance reference model. Untouched. This is the spec.executable/m87-governed-loop.bpmn— a Camunda 8 / ZeebeisExecutable="true"variant. Service tasks carryzeebe:taskDefinitionjob types; the four gateways carry FEEL conditions, and every gateway'sdefaultflow routes to a refusing exit so fail-closed is structural, not convention.
The governance decisions are implemented once as pure deterministic functions and reused by the engine workers. That is the design spine: a gate is a function, a gateway is the same function, and the function is unit-testable without a running cluster.
- Two BPMN files, not one. Keep the pristine reference model for the spec/diagram; ship the executable variant for deployment. Node IDs are identical across both so the diagram interchange and the invariant-mapping table stay valid for both.
- Fail-closed is structural in the executable model. Gateway
defaultflows go toEnd_Halt/End_RejManifest/FailReceipt/End_RejVerify. The permissive branch requires an explicit FEEL condition (=constraints_ok = true,=tool_in_manifest = true,=budget_exceeded = false,=artifact_verified = true). Missing/ambiguous variables route to refusal. - Pure gates own the logic; workers are thin.
governed_loop/gates.pyis the single source of truth. The Zeebe/pyzeebe worker layer only marshals variables in and out. Same intent for the Java module. - Missing telemetry = fail. A run that cannot prove it stayed inside the autonomy budget is treated as having left it. Unknown risk is not "low". No declared hash means not verified.
- Receipts are deterministic. Timestamp is injected by the caller so the same inputs + clock produce a byte-identical receipt. Even a failure emits an artifact-backed receipt (hash of the failure reason).
- Zeebe variable contract (set by the
validate,execute,verify-artifactworkers):constraints_ok: bool,tool_in_manifest: bool,budget_exceeded: bool,artifact_verified: bool.
| BPMN end event | Terminal |
Trigger |
|---|---|---|
| End_Complete | COMPLETE | artifact produced and verified |
| End_Halt | HALT | constraints unsatisfied / unclear (default branch) |
| End_RejManifest | REJECT_MANIFEST | tool absent from manifest, or action_type mismatch |
| End_Failed | FAILED | budget exceeded, runtime error, or missing telemetry |
| End_RejVerify | REJECT_VERIFY | no artifact, hash mismatch, or validation command failed |
- Repo scaffold + MIT
LICENSE. -
reference/model preserved verbatim.xmllintwell-formed. -
executable/Zeebe variant authored.xmllintwell-formed; 8zeebe:taskDefinition, 4 gateway defaults, 4 FEEL conditions. -
policy/governance_policy.yaml+policy/tool_manifest.yaml. - Python pure core:
policy.py,gates.py,receipts.py,__init__.py,pyproject.toml. - Pure-core smoke test passed (11/11 paths + budget boundary + deterministic receipt). All five terminals reached on the right inputs; every gate fails closed on malformed/ambiguous input. Run record below.
COMPLETE, HALT(no trace / risk=high / forbidden target),
REJECT_MANIFEST(unknown tool / action mismatch),
FAILED(budget steps / missing telemetry / error flag),
REJECT_VERIFY(tampered hash / validation fail) -> all matched expected terminal
boundary steps==20 -> COMPLETE (at-limit is allowed)
-
workers/python/governed_loop/workers.py— pyzeebe job workers (validate,execute,verify-artifact, etc.) wiring the pure gates to the Zeebe variable contract above. Lazy-import pyzeebe so the package imports without it. -
workers/python/tests/test_gates.py— port the smoke cases into a real pytest suite (one assertion per fail-closed exit + the success path + the budget boundary). Frame as invariant proofs. - Java module under
workers/java/—pom.xml(JUnit 5 + SnakeYAML +io.camunda:spring-boot-starter-camunda-sdk),Gates.java/Policy.java/Receipts.javamirroring the Python logic exactly,Workers.javawith@JobWorkerhandlers,GatesTest.javamirroring the Python tests. Note: Java was NOT compiled in the origin session (no local JDK/Maven). Compile + runmvn teston first pickup. -
.github/workflows/ci.yml— matrix:xmllint --nooutboth BPMN files;pytest(Python);mvn -q test(Java). -
docs/invariant-mapping.md— expand the README invariant→BPMN table; note it now applies to both files. - README rewrite — document the dual reference/executable structure, the Zeebe deploy steps (
zbctl deploy executable/m87-governed-loop.bpmn), the variable contract, and the test story. Drop the original footer caveat ("mapping to executable is out of scope") since that is now done. - Verify the executable BPMN against the real Camunda 8 schema (Modeler or
zbctl/Web Modeler deploy) —xmllintonly checks well-formedness, not Zeebe schema conformance.
m87-governed-loop/
├── LICENSE
├── HANDOFF.md <- this file
├── reference/m87-governed-loop.bpmn (isExecutable=false, preserved)
├── executable/m87-governed-loop.bpmn (Zeebe, isExecutable=true)
├── policy/governance_policy.yaml
├── policy/tool_manifest.yaml
├── workers/python/
│ ├── pyproject.toml
│ └── governed_loop/{__init__,policy,gates,receipts}.py (smoke-verified)
├── workers/java/ (dirs scaffolded, sources pending)
└── .github/workflows/ (pending)
Shipping the executable variant + green CI lets the Camunda FDE screening answer move from "worked with workflow tools conceptually" toward "configured, debugged, or written BPMN workflows." The warm-route DM hook: a governed execution loop authored in Camunda's own engine format. Application package lives at Job Search/m87-career-ops/applications/camunda-ai-process-fde/.
Picked up in the build-mode project. Remaining-work checklist is now done; status: shippable.
-
workers/python/governed_loop/workers.py— eight pyzeebe job handlers + engine-agnostic pure handlers (handle_validate/execute/verify/...). pyzeebe is lazily imported insidecreate_worker, so the package imports without the extra. -
workers/python/tests/test_gates.py— 26 invariant proofs, green. One assertion block per fail-closed exit + the success path + the budget boundary + deterministic-receipt + worker-routing. - Java module
workers/java/—pom.xml(JUnit 5 + SnakeYAML +io.camunda:spring-boot-starter-camunda-sdk),Terminal/Decision/Policy/Manifest/Receipts/Gates.java(pure core, mirrors Python),PolicyLoader.java(SnakeYAML),Workers.java(@JobWorker),GatesTest.java(8 proofs mirroring Python). -
.github/workflows/ci.yml— three jobs:xmllintboth BPMN + fail-closed structure assertion;pytest;mvn test. -
docs/invariant-mapping.md— three-layer mapping (BPMN ↔ pure function ↔ proof) + terminal map. -
README.mdrewritten for the dual reference/executable structure, variable contract, deploy steps, and test story. Old "out of scope" caveat dropped. -
workers/python/README.mdadded sopip install -e workers/pythonresolves itsreadme.
gates.pydecide()raisedAttributeErroron a non-dict execution result — it called.get()while building the failure receipt, so a malformed result crashed instead of failing closed. The origin smoke test missed it because it only called the gate function directly, never routed a non-dict throughdecide(). Fix:decide()now derives a safetelemetryview (result if isinstance(result, dict) else {}) for the receipt cost fields, while the budget gate still sees the raw value for the correct reason string. Covered bytest_failed_*[not-a-dict].
xmllint --nooutboth BPMN: well-formed. Fail-closed structure assertion: 4 gateway defaults, 4 FEEL conditions, 8zeebe:taskDefinition— all present.- Python:
pip install -e ".[dev]"+pytest→ 26 passed.
- Java compile +
mvn test— sandbox had a JRE only (nojavac, no Maven, no root). The pure-core Java mirrors the verified Python line-for-line andGatesTestdepends only on the core + JUnit (not on Camunda), somvn testproves the logic on first pickup. One thing to confirm: the@JobWorker/@Variableimport package matches the exact Camunda SDK version (io.camunda.zeebe.spring.client.annotationfor 8.6.x). IfWorkers.javafails to resolve, bump/adjust the import to the SDK version pinned inpom.xml. - Camunda 8 schema conformance of
executable/—xmllintchecks well-formedness only, not the Zeebe schema. Deploy once viazbctl deploy resourceor Web Modeler to confirm the engine accepts it.
Adversarial CTO-grade audit run (report: m87-governed-loop-AUDIT-2026-06-05.md). BPMN structure verified sound (fail-closed wiring correct on all four gateways, full reachability/DI). Four flags found and all fixed + regression-tested, verified locally in both languages:
- H1 / L1 / L2 — budget gate now fails closed on malformed telemetry. Non-numeric (
steps_used: "3"), boolean, or negative telemetry previously crasheddecide()/Gates.decide(TypeError / ClassCastException); now coerced and routed toFAILED. (gates.py,Gates.java; tests in both suites.) - M1 — manifest
targets_allowedis now enforced. A write to a target outside a tool's declared allow-list returnsREJECT_MANIFEST(wasCOMPLETE). (tool_in_manifest/toolInManifest.) - H2 — receipt hashing is now canonical and cross-language identical. Both languages hash structured artifacts via canonical JSON; verified Java
computeHash({k:v,n:1})== Pythoncompute_hash==e18b0bd8…. (Receipts.canonicalJson.) - M2 — runtime equivalence is now proven.
test_bpmn_equivalence.pyparses the executable BPMN and asserts its routing ==decide()across all five terminals.
Decorative policy/manifest keys (escalation.on_unclear, version, tool external) annotated as descriptive-only in the YAML.
Verified locally: Python pytest → 44 passed. Java pure core compiled under javac 17 + a logic harness → all checks pass incl. cross-language hash parity. (Java mvn test + the full Workers.java/Camunda path still run authoritatively in CI.)