12 KiB
Reporting Governance Plugin
This package is the emerging package boundary for the reporting-governance mainline.
Current purpose:
- give the plugin a real package home
- publish capability descriptors as package artifacts
- fix boundaries between
core/,adapters/,storage/, and reference implementations - prepare the next implementation round for evaluator / decision-runner extraction
- provide a minimal package-level policy evaluator and decision runner skeleton that can be verified in isolation
- add one minimal package-owned deployment profile artifact / loader / binding contract slice that is executable in tests
- let profile artifacts drive one real orchestrator adapter entrypoint instead of staying test-only
- add one minimal runtime-integrated slice wiring contract planning into real orchestrator execution
Package skeleton
plugins/reporting-governance/
package.json
README.md
capabilities/
profiles/
profiles-src/
schemas/
scripts/
docs/
examples/
src/
core/
index.mjs
policy-evaluator.mjs
decision-runner.mjs
execute-governance-contract.mjs
runtime-integrated.mjs
adapters/
storage/
reference/
index.mjs
test/
Boundary rules
src/core/
Runtime-agnostic governance logic:
- canonical event normalization
- evidence building
- policy evaluation
- decision running
- capability/profile compatibility
src/adapters/
Runtime-facing adapter modules:
- watchdog adapter
- dispatcher adapter
- bridge adapter
- sender-binding adapter
- orchestrator adapter
These may initially wrap existing repo scripts while extraction is still in progress.
src/storage/
Durable I/O contracts for governance artifacts:
- events
- evidence
- queue items
- spool artifacts
- receipts
- decision/profile/package artifacts
- future decisions / audit manifests
src/reference/
Reference runtime compositions and migration notes.
The watchdog reference runtime composition belongs here, as a reference implementation for OpenClaw rather than as package core logic.
Public surface and compatibility
Current public package surface is intentionally narrow:
- root export:
@openclaw/plugin-reporting-governance - adapter exports:
@openclaw/plugin-reporting-governance/adapters@openclaw/plugin-reporting-governance/adapters/watchdog@openclaw/plugin-reporting-governance/adapters/dispatcher@openclaw/plugin-reporting-governance/adapters/bridge-supervisor@openclaw/plugin-reporting-governance/adapters/sender-binding@openclaw/plugin-reporting-governance/adapters/orchestrator
@openclaw/plugin-reporting-governance/adapters 目前只代表 runtime adapter entrypoints。
createRuntimeBinding(...)、loadDeploymentProfileArtifact(...)、createDeploymentBindingContract(...) 不再掛在 ./adapters barrel;前者仍由 root export 提供,後兩者屬於 storage/profile artifact slice。
What is currently exposed from the root export:
evaluatePolicyPack(...)evaluatePolicies(...)planDecisionExecution(...)executeGovernanceContract(...)executeRuntimeIntegratedGovernance(...)- package metadata helpers such as
packageName - package-owned adapter entrypoints and
runWatchdogChain(...)
Compatibility posture for this slice:
0.1.0-mainlineshould be treated as pre-1.0, surface-tightening phase.- Deep imports into
src/are not supported API even if files exist in-repo. - Tests now explicitly enforce that private paths like
src/adapters/runtime-binding.mjsstay outsideexports. - Adding a symbol to a file under
src/does not mean it is public unless wired through packageexports. - Future tightening of root/adapters exports may still be a breaking change until a stable
1.0surface is declared.
Compatibility envelope vs legacy compatibility mode
This slice now makes the boundary explicit:
- compatibility envelope present = caller provides a deployment profile and/or package version pin, so
runCompatibilityPreflight(...)must enforce canonical schema paths, declared plugin compatibility, required expectations, and action support fail-closed. - legacy compatibility mode = caller omits profile + package version entirely, so preflight keeps old call sites alive, records the missing version pin as a note, and does not fail only because descriptor schema/version metadata drifted.
Hard rule:
- legacy mode is a caller-compatibility concession, not a relaxed truth model.
- once any profile/package compatibility envelope is supplied, schema mismatch becomes blocking again.
Practical migration rule:
- new integrations should always send a profile artifact or package version pin.
- old integrations may temporarily call without one, but should treat returned notes as migration debt.
- depend on package root exports or declared adapter subpaths only
- do not couple runtime integrations to repo-private file paths
- treat capability descriptors and schemas as package artifacts, but not as guaranteed JS import entrypoints unless exported later
Current reference composition
The current reference composition is the OpenClaw watchdog chain:
watchdog -> queue -> dispatcher -> bridge -> sender binding -> acked|blocked|pending_external_send
Package-home documentation:
src/reference/openclaw-watchdog-chain.mdcapabilities/openclaw-watchdog-reference.jsonprofiles/strict-manager-mode.profile.json
Mainline background specs remain in:
docs/specs/reporting-governance-capability-descriptor.mddocs/specs/reporting-governance-adapter-interface.mddocs/specs/reporting-governance-deployment-model.md
Minimal profile artifact / loader / binding contract slice
This round adds one small but real package artifact path:
- package artifact:
profiles/strict-manager-mode.profile.json - loader:
src/storage/profile-artifact.mjs#loadDeploymentProfileArtifact(...) - validator:
src/storage/profile-artifact.mjs#validateDeploymentProfileArtifact(...) - binding contract:
src/storage/profile-artifact.mjs#createDeploymentBindingContract(...)
What this slice does:
- package ships a profile artifact snapshot under package boundary
- loader resolves that artifact from package-local path
- validator fail-closes minimal boundary drift on
kind,apiVersion,spec.bindings.entrypoint,scripts,artifact_roots, andspec.package.pluginVersion - binding contract translates profile-declared script/artifact roots into concrete repo/runtime paths
- validator rejects
artifact_rootsabsolute paths, lexical escapes, and symlink escapes that resolve outside repo realpath boundary - adapter runtime binding can be instantiated from that contract in tests
- orchestrator adapter can now bootstrap from package profile artifact input directly
queueItemsnow has two checks: load-time artifact validation and orchestrator use-time realpath recheck before runtime consumption
What this slice does not claim yet:
- full profile schema validation pipeline
- automatic YAML -> artifact generation
- generalized multi-profile packaging
- production deployment installer
It is intentionally the smallest verifiable step that proves package profile artifacts are executable inputs rather than documentation only.
Minimal evaluator / decision runner now included
The current package now includes a small but runnable core/ implementation:
src/core/policy-evaluator.mjssrc/core/decision-runner.mjssrc/core/execute-governance-contract.mjssrc/core/runtime-integrated.mjssrc/core/index.mjs
Current package-core responsibilities:
- normalize evaluator facts from canonical event payload + evidence + local context
- match policy-pack rules by trigger and structured conditions
- produce canonical decision-model shaped decision objects
- choose the highest-precedence decision when multiple rules match
- convert a canonical decision into an execution plan, enforcement intent, and receipt skeleton
- truthfully degrade unsupported enforcement paths based on the capability descriptor
- provide one minimal contract path from
capability descriptor -> policy decision -> execution planning - surface deployment binding metadata when caller passes a validated profile artifact
- optionally hand that deployment binding into the orchestrator adapter when caller explicitly supplies runtime execution inputs
Still runtime-adapter responsibility at this stage:
- intercepting real outgoing messages or status transitions inline
- actually sending operator notices
- acking final delivery to external channels
- persisting decisions/receipts into a production decision store
- installing schedulers / watchdog loops / bridge sender bindings
This means core/ now owns evaluation and planning semantics, while adapters still own actual enforcement side effects.
Minimal end-to-end contract slice now included
This slice now has one small but testable contract path:
- capability descriptor advertises real enforcement support
- policy evaluator emits a canonical decision from event/evidence/context
- decision runner converts that decision into execution planning
- validated profile artifact can supply deployment binding metadata
- runtime-integrated helper can take that binding and route it into the orchestrator adapter
- orchestrator adapter consumes the same binding and runs one real runtime layer
- the result declares:
- adapter-dispatch actions required
- package-core actions possible locally
- blocked mandatory actions when capability support is missing
- truthful delivery / receipt state
- runtime execution result when explicitly requested
Current runtime contract in this repo is intentionally narrower than a future generalized aggregation model:
- single notice settlement path only
- one governance-triggered operator notice route is evaluated as one truth boundary
- overall truth state may promote to
ackedonly when the observed terminal outcome set for that single path is fully acked - mixed observed outcomes such as
acked + pendingoracked + blockedmust stay non-acked - this slice does not yet claim generalized multi-notice aggregation, fan-in settlement, or cross-notice quorum semantics
This is intentionally planning-level end-to-end plus one adapter bootstrap layer, not full live inline interception. It proves contract alignment without pretending all runtime enforcement is already extracted.
What this means for implementers right now:
- treat
dispatched/pending_external_send/blockedas honest end states unless the single notice path reaches sender-backed ack proof - do not collapse partial success into overall
acked - if future work introduces multiple notice paths, that must land as a separate runtime-contract slice with its own tests
Not yet included
This package still does not claim full implementation of:
- generalized event normalization modules
- generalized evidence builder modules
- production decision persistence
- complete rewrite / placeholder / review / status-downgrade adapter execution
- non-watchdog full runtime governance interception
It now provides the first package-mainline evaluator / decision-runner core, a compatibility-envelope boundary, a minimal package profile artifact/binding slice, and one profile-driven orchestrator path, but the remaining enforcement surface is still intentionally honest about adapter gaps.
Package-first smoke
Minimal package-local smoke path:
cd plugins/reporting-governance
npm test
npm run smoke
# or after package install/link
reporting-governance-package-smoke --compact
Repeatable packed-consumer install smoke is now also covered by package test:
cd plugins/reporting-governance
npm pack
node --test test/packed-consumer-install.smoke.test.mjs
That path verifies a clean temp consumer can npm install <tarball> and then use only declared public surfaces:
- package root export:
@openclaw/plugin-reporting-governance - exported subpath:
@openclaw/plugin-reporting-governance/adapters/orchestrator - package bin:
reporting-governance-package-smoke
This smoke path uses package-local profiles-src/, schemas/, and scripts only.
It writes temp runtime artifacts under a caller-provided or temp workspace and verifies the dry-run orchestrator path end to end.