docs: close reporting-governance entrypoint semantics gap

This commit is contained in:
Eve
2026-05-08 21:35:55 +08:00
parent 6f2ea9b3b3
commit bdd33bd42d
6 changed files with 460 additions and 7 deletions

View File

@@ -36,6 +36,7 @@ Without an adapter interface, those runtime pieces remain implementation islands
For the current mainline slice, the package-owned runtime source of truth is the package adapter surface and package scripts under `plugins/reporting-governance/`. For the current mainline slice, the package-owned runtime source of truth is the package adapter surface and package scripts under `plugins/reporting-governance/`.
Repo-root `scripts/*.mjs` files should be read as compatibility wrappers or operator conveniences unless explicitly stated otherwise. Repo-root `scripts/*.mjs` files should be read as compatibility wrappers or operator conveniences unless explicitly stated otherwise.
When this spec names package entrypoints as `scripts/...`, that path is package-root-relative within `plugins/reporting-governance/`; repo-root wrappers remain the separate compatibility layer.
## Scope ## Scope

View File

@@ -0,0 +1,412 @@
# Reporting Governance Capability Descriptor
## Purpose
This document defines the **capability descriptor** for the reporting-governance plugin.
It turns runtime support from implied prose into a machine-readable contract that can be:
- validated before deployment
- checked against deployment profiles
- attached to audit bundles
- used by the next implementation stage for evaluator / decision-runner wiring
This spec is intentionally the next step after:
- `docs/specs/reporting-governance-adapter-interface.md`
- `docs/specs/reporting-governance-deployment-model.md`
- `schemas/reporting-governance/adapter-capabilities.schema.json`
The adapter-interface spec defines **what adapters must be able to describe**.
This capability-descriptor spec defines **how one concrete runtime publishes that description as a package artifact**.
## Why this exists now
The current mainline already has:
- canonical event / evidence / decision / policy-pack contracts
- deployment profiles
- a validated watchdog reference runtime composition
But the plugin still lacks one package-level truth source answering:
- which runtime surfaces exist in this deployment
- which enforcement actions are actually available
- whether the runtime can only queue, can bridge, or can truly ack final delivery
- which storage and receipt guarantees are real
Without a capability descriptor, the next evaluator / decision-runner stage would still have to guess runtime powers from docs and scripts.
## Scope
This spec defines:
1. the package role of a capability descriptor
2. the minimum descriptor shape
3. the OpenClaw reference descriptor for the watchdog composition
4. package-boundary implications for `core/`, `adapters/`, `storage/`, `artifacts/`, and reference implementations
5. how evaluator / decision-runner should consume descriptor data next
This spec does **not** define:
- the policy evaluator itself
- the deployment-profile schema
- one mandatory programming language API
- the full audit export manifest format
## Mainline decision
The reporting-governance plugin now uses this package distinction:
- **schema**: validation contract for descriptor shape
- **capability descriptor**: one concrete runtime claim validated by that schema
- **deployment profile**: requested operating posture
- **adapter modules**: implementation surfaces that may satisfy some or all requested posture
In short:
- profiles express **desired behavior**
- capability descriptors express **actual runtime power**
- evaluator / decision-runner must operate from the intersection of both
## Package location
Capability descriptors belong under the plugin package boundary:
```text
plugins/reporting-governance/
capabilities/
openclaw-watchdog-reference.json
examples/
openclaw-watchdog-reference.descriptor.example.json
```
The canonical validation schema remains under:
```text
schemas/reporting-governance/capability-descriptor.schema.json
```
This keeps the split clear:
- `schemas/` = canonical validation contracts
- `plugins/reporting-governance/capabilities/` = package-owned runtime declarations; `runtime.entrypoint: "scripts/..."` is resolved relative to the package root
- `plugins/reporting-governance/examples/` = copyable reference inputs using the same package-root-relative `scripts/...` semantics
## Descriptor responsibilities
A capability descriptor must answer five questions.
### 1. What runtime is this?
Examples:
- `openclaw`
- future host runtimes
- future embedded or CI-only runtimes
### 2. Which adapter surfaces are present?
Examples:
- `watchdog`
- `queue`
- `dispatcher`
- `bridge`
- `sender_binding`
- `orchestrator`
### 3. Which governance actions are truly available?
Examples:
- block transition
- rewrite message
- annotate placeholder
- force checkpoint
- request review
- downgrade status
- escalate
### 4. What notification truth model is supported?
At minimum, whether the runtime distinguishes:
- `prepared`
- `queued`
- `dispatched`
- `pending_external_send`
- `acked`
- `blocked`
### 5. What persistence and audit guarantees exist?
Examples:
- can events be persisted?
- can receipts be written?
- can original attempted messages be preserved?
- can decision outputs be stored yet, or is that still pending the next phase?
## Descriptor shape
The canonical descriptor shape is validated by:
- `schemas/reporting-governance/capability-descriptor.schema.json`
The schema reuses the same top-level resource model already established for adapter capabilities:
- `apiVersion`
- `kind`
- `metadata`
- `runtime`
- `compatibility`
- `capabilities`
- optional `defaults`
- optional `notes`
## OpenClaw reference descriptor
The first package-mainline descriptor is the **OpenClaw watchdog reference composition**.
Descriptor identity:
- runtime: `openclaw`
- mode: `hybrid`
- runtime `entrypoint`: `scripts/watchdog_auto_notify_orchestrator.mjs` resolved from `plugins/reporting-governance/` package root
- surfaces:
- `watchdog`
- `queue`
- `dispatcher`
- `bridge`
- `sender_binding`
- `orchestrator`
- `scheduler`
- `storage`
### What it must claim
This reference descriptor should claim support for:
- watchdog overdue observation
- canonical watchdog event generation
- queue-backed operator notices
- spool/handoff dispatch
- bridge-supervised sender invocation
- truthful `acked | blocked | pending_external_send` outcomes
- persistence of events, evidence, queue items, spool artifacts, and receipts
### What it should not overclaim
At this stage, the reference descriptor should **not** overclaim:
- full inline hook interception as complete
- final delivery proof in every deployment
- fully packaged decision persistence if the evaluator / decision runner is not extracted yet
- all completion-claim governance paths
This is why some support levels remain `partial` rather than `full`.
## Package boundary decisions
This spec fixes the package skeleton boundaries needed for the next implementation round.
## `src/core/`
`core/` contains runtime-agnostic governance logic.
It should own:
- canonical event normalization
- evidence building / evidence-reference shaping
- policy evaluation
- decision execution planning
- capability/profile compatibility checks
It should **not** own:
- cron installation
- filesystem-specific queue scanning loops
- OpenClaw sender invocations
- repo-local wrapper scripts
Minimum package direction:
```text
src/core/
capability-profile-compatibility.mjs
decision-runner.mjs
evidence-builder.mjs
event-normalizer.mjs
policy-evaluator.mjs
```
## `src/adapters/`
`adapters/` contains runtime-facing integration modules.
It should own:
- OpenClaw watchdog adapter wrapper
- queue / dispatcher adapter wrapper
- bridge adapter wrapper
- sender-binding adapter wrapper
- orchestrator adapter wrapper
It may initially wrap existing repo scripts while package extraction is still in progress.
It should **not** absorb canonical policy semantics that belong in `core/`.
Minimum package direction:
```text
src/adapters/
bridge-adapter.mjs
dispatcher-adapter.mjs
orchestrator-adapter.mjs
sender-binding-adapter.mjs
watchdog-adapter.mjs
```
## `src/storage/`
`storage/` contains package-level readers/writers for durable governance artifacts.
It should own contracts for:
- event store
- evidence store
- receipt store
- queue-item store
- spool-artifact store
- future decision store
- future audit export manifest support
It should not define governance meaning; it only persists governed artifacts.
Minimum package direction:
```text
src/storage/
decision-store.mjs
event-store.mjs
evidence-store.mjs
queue-store.mjs
receipt-store.mjs
spool-store.mjs
```
## `artifacts/` boundary
The plugin package does not need a required checked-in `artifacts/` source directory yet.
Instead, **artifacts** are the runtime outputs produced by storage contracts and runtime bindings.
For current OpenClaw reference behavior, the artifact classes are still represented by runtime directories such as:
- `state/long-task-watchdog/`
- `state/long-task-watchdog-events/`
- `state/operator-notify-queue/`
- `state/operator-notify-dispatch-spool/`
- `state/operator-notify-bridge-receipts/`
- `state/operator-notify-sender-attempts/`
Mainline interpretation:
- these are **runtime artifact locations**
- package `src/storage/` should become the code boundary that reads/writes them
- future audit export bundles should consume these classes through storage abstractions rather than raw script coupling
## Reference implementations boundary
Reference implementations are executable, runtime-specific realizations of the package contracts.
For this MVP stage, the main reference implementation is the watchdog chain described in:
- `CODER_WATCHDOG_REPORT.md`
Within the package skeleton, it belongs under:
```text
plugins/reporting-governance/src/reference/openclaw-watchdog-chain.md
```
and is represented in code-adjacent terms by:
- `src/adapters/watchdog-adapter.mjs`
- `src/adapters/dispatcher-adapter.mjs`
- `src/adapters/bridge-adapter.mjs`
- `src/adapters/sender-binding-adapter.mjs`
- `src/adapters/orchestrator-adapter.mjs`
This means the **watchdog reference runtime composition is categorized as a reference implementation, not as plugin core**.
That is the key boundary that keeps the next evaluator / decision-runner work clean.
## Consumption by evaluator / decision runner
The next implementation stage should use the capability descriptor in two places.
### 1. Preflight compatibility
Before executing a policy action, the runtime should compare:
- requested profile behavior
- policy-required action
- actual adapter capability support
Examples:
- if `force_checkpoint` is requested but only queue/bridge notice is available, downgrade to honest deferred notice + receipt
- if direct send is requested but only `pending_external_send` is supportable, preserve the weaker truthful state
### 2. Action planning
The decision runner should use capability support to choose execution paths such as:
- inline block
- queue-only notice
- bridge-mediated send
- status downgrade + review request
- blocked-with-gap receipt
This keeps the evaluator portable and avoids encoding OpenClaw-specific assumptions inside `core/`.
## Verification expectations
Capability descriptor work should be verified at minimum by:
1. schema validation of the descriptor JSON
2. package skeleton presence checks
3. consistency review against:
- adapter-interface spec
- deployment model
- roadmap lane terminology
## Minimal synchronization with roadmap and deployment model
This capability-descriptor step advances:
- roadmap lane 3: package extraction
- roadmap lane 4: capability/profile/deployment binding
The deployment model does not need redesign.
It only needs to recognize that the first concrete package artifact for this lane is now:
- a package-owned OpenClaw capability descriptor
- plus the minimal package skeleton that gives it a stable home
## Summary
This spec establishes the reporting-governance capability descriptor as the package-level truth contract between:
- runtime-specific adapter power
- deployment-profile intent
- future evaluator / decision-runner behavior
It also fixes the package boundaries needed for the next phase:
- `core/` = runtime-agnostic governance logic
- `adapters/` = runtime integration surfaces
- `storage/` = durable artifact I/O contracts
- runtime `artifacts/` = produced outputs, not core source
- watchdog chain = reference implementation housed under the package skeleton, not plugin core

View File

@@ -313,6 +313,8 @@ Examples:
The completed watchdog chain is now treated as the first reference deployment composition. The completed watchdog chain is now treated as the first reference deployment composition.
For the current mainline slice, the package-owned source of truth is the package entrypoint set under `plugins/reporting-governance/scripts/` together with package profile artifacts under `plugins/reporting-governance/profiles/`. For the current mainline slice, the package-owned source of truth is the package entrypoint set under `plugins/reporting-governance/scripts/` together with package profile artifacts under `plugins/reporting-governance/profiles/`.
Within package-owned artifacts such as capability descriptors, `runtime.entrypoint: "scripts/..."` means package-root-relative to `plugins/reporting-governance/`.
Within deployment profile artifacts, `spec.bindings.entrypoint` and `spec.bindings.scripts.*` remain repo-root-relative paths like `plugins/reporting-governance/scripts/...`, because they bind the installed package back into a concrete workspace/repo runtime.
Repo-root `scripts/*.mjs` wrappers and install helpers remain migration/deployment conveniences, not the architectural source of runtime truth. Repo-root `scripts/*.mjs` wrappers and install helpers remain migration/deployment conveniences, not the architectural source of runtime truth.
### Reference composition ### Reference composition
@@ -331,16 +333,16 @@ watchdog runner
| Runtime piece | Deployment role | | Runtime piece | Deployment role |
| --- | --- | | --- | --- |
| `scripts/long_task_watchdog.mjs` | watchdog adapter executable in the deployed package | | package `scripts/long_task_watchdog.mjs` | watchdog adapter executable in the deployed package (`scripts/...` here means package-root-relative inside `plugins/reporting-governance/`) |
| `state/long-task-watchdog/*.json` | portable runtime-artifact evidence | | `state/long-task-watchdog/*.json` | portable runtime-artifact evidence |
| `state/long-task-watchdog-events/*.json` | portable canonical event artifacts | | `state/long-task-watchdog-events/*.json` | portable canonical event artifacts |
| `state/operator-notify-queue/*.json` | queue-layer audit artifacts and deferred notice obligations | | `state/operator-notify-queue/*.json` | queue-layer audit artifacts and deferred notice obligations |
| `scripts/operator_notify_dispatcher.mjs` | dispatcher adapter for handoff generation | | package `scripts/operator_notify_dispatcher.mjs` | dispatcher adapter for handoff generation |
| `state/operator-notify-dispatch-spool/*.json` | spool/handoff audit artifacts proving dispatch, not delivery | | `state/operator-notify-dispatch-spool/*.json` | spool/handoff audit artifacts proving dispatch, not delivery |
| `scripts/operator_notify_bridge_supervisor.mjs` | bridge adapter for upper-runtime send boundary | | package `scripts/operator_notify_bridge_supervisor.mjs` | bridge adapter for upper-runtime send boundary |
| `scripts/operator_notify_sender_binding.mjs` | sender-binding adapter selectable by deployment profile | | package `scripts/operator_notify_sender_binding.mjs` | sender-binding adapter selectable by deployment profile |
| `state/operator-notify-bridge-receipts/*.json` | portable delivery-state receipts | | `state/operator-notify-bridge-receipts/*.json` | portable delivery-state receipts |
| `scripts/watchdog_auto_notify_orchestrator.mjs` | orchestrator adapter and single deployment entrypoint | | package `scripts/watchdog_auto_notify_orchestrator.mjs` | orchestrator adapter and single deployment entrypoint |
| cron installer / wrapper | runtime binding for scheduled execution | | cron installer / wrapper | runtime binding for scheduled execution |
### Mainline conclusion ### Mainline conclusion

View File

@@ -19,7 +19,7 @@
"orchestrator", "orchestrator",
"storage" "storage"
], ],
"entrypoint": "plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs" "entrypoint": "scripts/watchdog_auto_notify_orchestrator.mjs"
}, },
"compatibility": { "compatibility": {
"plugin_spec_versions": [ "plugin_spec_versions": [

View File

@@ -27,7 +27,7 @@
"src/" "src/"
], ],
"scripts": { "scripts": {
"test": "node --test test/package-structure.test.mjs test/policy-evaluator.test.mjs test/compatibility-preflight.test.mjs test/profile-artifact.test.mjs test/profile-generator.test.mjs test/decision-runner.test.mjs test/decision-store.test.mjs test/decision-store-runtime.integration.test.mjs test/governance-contract.integration.test.mjs test/watchdog-chain.integration.test.mjs test/orchestrator-execution.test.mjs test/runtime-integrated.integration.test.mjs test/exports-boundary.integration.test.mjs test/packed-consumer-install.smoke.test.mjs", "test": "node --test test/package-structure.test.mjs test/descriptor-entrypoint-resolution.test.mjs test/policy-evaluator.test.mjs test/compatibility-preflight.test.mjs test/profile-artifact.test.mjs test/profile-generator.test.mjs test/decision-runner.test.mjs test/decision-store.test.mjs test/decision-store-runtime.integration.test.mjs test/governance-contract.integration.test.mjs test/watchdog-chain.integration.test.mjs test/orchestrator-execution.test.mjs test/runtime-integrated.integration.test.mjs test/exports-boundary.integration.test.mjs test/packed-consumer-install.smoke.test.mjs",
"smoke": "node ./scripts/package-smoke.mjs --compact" "smoke": "node ./scripts/package-smoke.mjs --compact"
}, },
"dependencies": { "dependencies": {

View File

@@ -0,0 +1,38 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import capabilityDescriptor from '../capabilities/openclaw-watchdog-reference.json' with { type: 'json' };
import exampleDescriptor from '../examples/openclaw-watchdog-reference.descriptor.example.json' with { type: 'json' };
import { createDeploymentBindingContract } from '../src/storage/profile-artifact.mjs';
import profileArtifact from '../profiles/strict-manager-mode.profile.json' with { type: 'json' };
const packageRoot = path.resolve(import.meta.dirname, '..');
const repoRoot = path.resolve(packageRoot, '..', '..');
function resolvePackageEntrypoint(entrypoint) {
return path.resolve(packageRoot, entrypoint);
}
test('capability descriptor and example entrypoint resolve from package root to the package-owned orchestrator', () => {
const canonicalPath = path.resolve(packageRoot, 'scripts/watchdog_auto_notify_orchestrator.mjs');
const descriptorEntrypoint = resolvePackageEntrypoint(capabilityDescriptor.runtime.entrypoint);
const exampleEntrypoint = resolvePackageEntrypoint(exampleDescriptor.runtime.entrypoint);
assert.equal(capabilityDescriptor.runtime.entrypoint, 'scripts/watchdog_auto_notify_orchestrator.mjs');
assert.equal(exampleDescriptor.runtime.entrypoint, 'scripts/watchdog_auto_notify_orchestrator.mjs');
assert.equal(descriptorEntrypoint, canonicalPath);
assert.equal(exampleEntrypoint, canonicalPath);
assert.equal(fs.existsSync(canonicalPath), true);
});
test('deployment profile binding stays repo-root-relative while targeting the same package-owned orchestrator', () => {
const binding = createDeploymentBindingContract({ artifact: profileArtifact, repoRootOverride: repoRoot });
const canonicalPath = path.resolve(packageRoot, 'scripts/watchdog_auto_notify_orchestrator.mjs');
assert.equal(profileArtifact.spec.bindings.entrypoint, 'plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs');
assert.equal(binding.entrypoint, canonicalPath);
assert.equal(binding.scripts.orchestrator, canonicalPath);
});