From bdd33bd42df925c2ec9c1008025a72ba487de8ac Mon Sep 17 00:00:00 2001 From: Eve Date: Fri, 8 May 2026 21:35:55 +0800 Subject: [PATCH] docs: close reporting-governance entrypoint semantics gap --- .../reporting-governance-adapter-interface.md | 1 + ...orting-governance-capability-descriptor.md | 412 ++++++++++++++++++ .../reporting-governance-deployment-model.md | 12 +- ...watchdog-reference.descriptor.example.json | 2 +- plugins/reporting-governance/package.json | 2 +- .../descriptor-entrypoint-resolution.test.mjs | 38 ++ 6 files changed, 460 insertions(+), 7 deletions(-) create mode 100644 docs/specs/reporting-governance-capability-descriptor.md create mode 100644 plugins/reporting-governance/test/descriptor-entrypoint-resolution.test.mjs diff --git a/docs/specs/reporting-governance-adapter-interface.md b/docs/specs/reporting-governance-adapter-interface.md index 597a926..02d463c 100644 --- a/docs/specs/reporting-governance-adapter-interface.md +++ b/docs/specs/reporting-governance-adapter-interface.md @@ -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/`. 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 diff --git a/docs/specs/reporting-governance-capability-descriptor.md b/docs/specs/reporting-governance-capability-descriptor.md new file mode 100644 index 0000000..46ae098 --- /dev/null +++ b/docs/specs/reporting-governance-capability-descriptor.md @@ -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 diff --git a/docs/specs/reporting-governance-deployment-model.md b/docs/specs/reporting-governance-deployment-model.md index 1713238..5a85c76 100644 --- a/docs/specs/reporting-governance-deployment-model.md +++ b/docs/specs/reporting-governance-deployment-model.md @@ -313,6 +313,8 @@ Examples: 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/`. +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. ### Reference composition @@ -331,16 +333,16 @@ watchdog runner | 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-events/*.json` | portable canonical event artifacts | | `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 | -| `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_bridge_supervisor.mjs` | bridge adapter for upper-runtime send boundary | +| package `scripts/operator_notify_sender_binding.mjs` | sender-binding adapter selectable by deployment profile | | `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 | ### Mainline conclusion diff --git a/plugins/reporting-governance/examples/openclaw-watchdog-reference.descriptor.example.json b/plugins/reporting-governance/examples/openclaw-watchdog-reference.descriptor.example.json index 39226fd..ffb5a85 100644 --- a/plugins/reporting-governance/examples/openclaw-watchdog-reference.descriptor.example.json +++ b/plugins/reporting-governance/examples/openclaw-watchdog-reference.descriptor.example.json @@ -19,7 +19,7 @@ "orchestrator", "storage" ], - "entrypoint": "plugins/reporting-governance/scripts/watchdog_auto_notify_orchestrator.mjs" + "entrypoint": "scripts/watchdog_auto_notify_orchestrator.mjs" }, "compatibility": { "plugin_spec_versions": [ diff --git a/plugins/reporting-governance/package.json b/plugins/reporting-governance/package.json index afae1fa..3a159d1 100644 --- a/plugins/reporting-governance/package.json +++ b/plugins/reporting-governance/package.json @@ -27,7 +27,7 @@ "src/" ], "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" }, "dependencies": { diff --git a/plugins/reporting-governance/test/descriptor-entrypoint-resolution.test.mjs b/plugins/reporting-governance/test/descriptor-entrypoint-resolution.test.mjs new file mode 100644 index 0000000..6aaeb39 --- /dev/null +++ b/plugins/reporting-governance/test/descriptor-entrypoint-resolution.test.mjs @@ -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); +});