spec: define governance decision model

This commit is contained in:
Eve
2026-05-07 16:31:48 +08:00
parent e1cc6bfa53
commit 4ab944101b
2 changed files with 1113 additions and 0 deletions

View File

@@ -0,0 +1,737 @@
# Reporting Governance Decision Model
## Purpose
This document defines the canonical policy decision model for the reporting-governance plugin. It specifies the stable output shape that policy evaluators, adapters, and enforcement layers use after inspecting canonical events and correlated evidence.
The decision model exists so governance can do more than merely detect risky conditions. It provides a machine-readable contract for **what enforcement action must happen next**, while preserving enough explanation and audit detail for operator review.
This model is designed to align with:
- `docs/specs/reporting-governance-event-model.md`
- `docs/specs/reporting-governance-evidence-model.md`
- `schemas/reporting-governance/event-envelope.schema.json`
- `schemas/reporting-governance/evidence.schema.json`
It must be able to express the four core gates discussed for the plugin:
1. **Pre-dispatch report-anchor gate**
2. **Subagent failure immediate-report gate**
3. **Silent-task launch blocker**
4. **Result-forwarding integrity gate**
## Design goals
- Provide one canonical decision object for all governance evaluations.
- Separate the primary disposition from optional remediation instructions.
- Support both blocking and non-blocking enforcement paths.
- Preserve audit trail when messages are rewritten or statuses are downgraded.
- Make operator-visible obligations explicit instead of implicit.
- Remain compatible with event/evidence correlation using `task_id`, `correlation_id`, evidence references, and policy identifiers.
## Canonical decision object
Every policy evaluation result should use the following logical shape.
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `decision` | string | yes | Canonical enforcement disposition from this document. |
| `policy_id` | string | yes | Stable identifier for the policy rule that produced the decision. |
| `severity` | string | yes | Risk/urgency classification used by enforcement and operator UX. |
| `reason` | string | yes | Human-readable rationale describing why the decision was produced. |
| `rewritten_message` | string or null | yes | Replacement or augmented operator-facing message text when `rewrite` or placeholder annotation is used. |
| `suggested_status` | string or null | yes | Recommended workflow status after enforcement, if any. |
| `required_actions` | array | yes | Ordered list of concrete enforcement actions to perform. |
| `operator_notice` | object or null | yes | Operator-visible notice requirements produced by the policy. |
## Core decisions
The following decision values are the stable governance API surface.
### 1. `allow`
The evaluated action may proceed unchanged.
Use when:
- required evidence threshold is met
- no gate violation is active
- the operator-visible reporting path is intact
Typical effect:
- permit dispatch, reporting, or status transition without mutation
### 2. `rewrite`
The evaluated outgoing report may proceed only after governance rewrites, augments, or normalizes the message.
Use when:
- the message is partially true but materially incomplete
- a placeholder or weak progress report must be converted into a compliant disclosure
- operator-facing text must include missing caveats, evidence references, or review markers
Required semantic:
- A rewrite **may alter outgoing report text but must preserve audit trail**. The original attempted message should remain recoverable through runtime logs, event payload history, or explicit audit metadata.
Typical effect:
- replace a misleading completion claim with a pending-verification notice
- append a warning that a child result exists but forwarding integrity is degraded
### 3. `block`
The evaluated action must not proceed.
Use when:
- required preconditions are absent
- silent launch is forbidden by policy
- a completion/status transition lacks minimum evidence
- dispatch or report would violate a hard gate
Required semantic:
- `block` prevents message dispatch or status transition, depending on the evaluated action.
Typical effect:
- prevent subagent dispatch without a report anchor
- reject a `completed` status update with only narrative evidence
### 4. `require_review`
The action may not be treated as accepted until explicit review occurs.
Use when:
- evidence is moderate but not authoritative
- policy wants human signoff before acceptance
- there is ambiguity that should not be silently auto-resolved
Typical effect:
- convert a completion claim into `pending_verification`
- emit an operator-visible review request with linked evidence
### 5. `force_checkpoint`
Governance requires an immediate operator-visible update.
Use when:
- a failure or integrity risk cannot remain internal-only
- a silence window has expired
- a child result arrived but no operator-facing follow-up was emitted
Required semantic:
- `force_checkpoint` creates an **immediate required operator-visible update**.
Typical effect:
- send a failure disclosure now
- send a “result received, forwarding repair in progress” checkpoint now
### 6. `escalate`
Governance requires routing to a higher-severity handling path, watcher, or human attention tier.
Use when:
- repeated violations occur
- the policy breach is severe enough that ordinary review is insufficient
- watchdog, silence, or forwarding failures require urgent visibility
Typical effect:
- raise alert severity
- route to incident or supervisor review channel
### 7. `downgrade_status`
Governance changes an optimistic or unsupported status to a safer state.
Use when:
- claimed completion lacks enough evidence
- verification is missing or inconclusive
- a report suggests closure before policy thresholds are met
Required semantic:
- `downgrade_status` changes `completed -> pending_verification` when evidence is insufficient.
- Policies may also use it for other conservative reversions when explicitly configured, but `completed -> pending_verification` is the required baseline behavior.
Typical effect:
- replace “done” with “pending verification”
- preserve evidence while preventing premature closure
### 8. `annotate_placeholder`
Governance permits a placeholder or continuity marker only if it is clearly labeled as incomplete.
Use when:
- the system must emit a temporary message to avoid blackhole behavior
- a result is known to exist but a full normalized summary is not yet ready
- a checkpoint is required before final synthesis is available
Typical effect:
- produce an operator-visible placeholder such as “child result received; verified forwarding summary pending”
- clearly distinguish placeholder reporting from real completion
## Severity vocabulary
Recommended canonical severity values:
- `info`
- `low`
- `medium`
- `high`
- `critical`
Interpretation:
- `info` / `low`: mostly advisory or formatting enforcement
- `medium`: normal governance correction or review requirement
- `high`: active policy violation or blocked transition
- `critical`: urgent anti-blackhole, incident, or escalation condition
## `suggested_status` vocabulary
The decision model does not own the full workflow state machine, but it should use stable status suggestions that align with the event model's `task_status_changed` and the evidence model's verification logic.
Recommended values:
- `in_progress`
- `pending_verification`
- `blocked`
- `failed`
- `awaiting_review`
- `completed`
Rules:
- `allow` may leave `suggested_status` as `null` when no change is needed.
- `downgrade_status` should usually set `suggested_status` to `pending_verification`.
- `block` may suggest `blocked`.
- `require_review` may suggest `awaiting_review` or `pending_verification`.
- `force_checkpoint` does not itself require a status change, but may pair with one.
## Required actions
`required_actions` is an ordered list describing what enforcement must happen next. It gives adapters a consistent execution contract even when the top-level decision is the same.
Each action should use this logical shape.
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `action` | string | yes | Canonical action verb. |
| `target` | string | yes | What the action applies to. |
| `mandatory` | boolean | yes | Whether the action must succeed before the workflow may continue. |
| `details` | object | no | Action-specific parameters. |
Recommended `action` values:
- `dispatch_message`
- `rewrite_message`
- `append_audit_note`
- `block_transition`
- `set_status`
- `request_review`
- `emit_event`
- `notify_operator`
- `start_watchdog`
- `raise_escalation`
- `record_placeholder`
Recommended `target` values:
- `outgoing_report`
- `status_transition`
- `operator_channel`
- `task_record`
- `event_stream`
- `watchdog`
- `review_queue`
Action semantics:
- If `decision = block`, at least one action should explicitly stop the attempted message or transition, usually `block_transition` or omission of `dispatch_message` plus a mandatory `emit_event`/`notify_operator` path.
- If `decision = rewrite`, at least one action should preserve the audit trail, usually `append_audit_note` or equivalent audit emission.
- If `decision = force_checkpoint`, at least one mandatory action should produce operator-visible output immediately.
- If `decision = downgrade_status`, at least one mandatory `set_status` action should point to `pending_verification` when insufficient evidence caused a premature completion claim.
## Operator notice
`operator_notice` makes operator-facing obligations explicit.
Recommended shape:
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `required` | boolean | yes | Whether governance requires an operator-visible notice. |
| `channel` | string or null | yes | Intended destination channel if known. |
| `urgency` | string or null | yes | Operator-facing urgency hint. |
| `message` | string or null | yes | Notice text or summary to send. |
| `must_reference` | array | no | Evidence/event refs that must be mentioned or linked. |
| `deadline` | string or null | yes | RFC 3339 deadline for the notice, if any. |
Semantics:
- `operator_notice.required = true` is expected for `force_checkpoint`, most `escalate` decisions, and high-risk `block` decisions that would otherwise be invisible.
- `annotate_placeholder` should usually set `operator_notice.message` to clearly disclose that the update is provisional.
- `require_review` should usually request review explicitly rather than implying it.
## Alignment with event and evidence models
### Relationship to canonical events
Decisions are produced by evaluating canonical event(s) and attached evidence. The decision object should be storable alongside or derivable from events such as:
- `report_anchor_missing`
- `subagent_spawn_failed`
- `silence_timeout`
- `task_claimed_complete`
- `subagent_completed`
- `subagent_result_not_forwarded`
- `forced_operator_update`
- `operator_review_requested`
The `policy_id` should identify the exact rule that interpreted those inputs.
### Relationship to evidence thresholds
The decision model is intentionally downstream of the evidence model.
Recommended mappings:
- no new evidence for a progress-bearing checkpoint -> `rewrite`, `annotate_placeholder`, or `force_checkpoint`, depending on policy and silence risk
- completion claim with less than `moderate` support -> `block` or `downgrade_status`
- verified completion claim without `strong` support -> `require_review` or `downgrade_status`
- child completion artifact without forwarding proof -> `force_checkpoint` or `escalate`
### Correlation expectations
Although not required top-level fields in the canonical decision schema, implementations should retain linkage from the evaluated event/evidence set through surrounding runtime metadata, policy logs, or action details. In particular, decisions should remain traceable to:
- `task_id`
- `correlation_id`
- relevant `event_id` values
- relevant `evidence_id` / `evidence_refs`
## Gate mapping
### 1. Pre-dispatch report-anchor gate
Typical trigger:
- attempted `subagent_spawned` or dispatch path where `operator_context.report_anchor.present = false`
Typical decisions:
- `block` when anchor is mandatory and absent
- `escalate` when absence persists or policy classifies it as severe
- `force_checkpoint` if governance must notify the operator immediately about the blocked dispatch
Typical actions:
- `emit_event` with `report_anchor_missing`
- `block_transition` on dispatch
- `notify_operator` if policy requires visible disclosure
### 2. Subagent failure immediate-report gate
Typical trigger:
- `subagent_spawn_failed`
Typical decisions:
- `force_checkpoint` as the normal baseline
- `escalate` if repeated or severe
Typical actions:
- `emit_event` for failure and disclosure path
- `notify_operator` immediately
- optionally `raise_escalation`
### 3. Silent-task launch blocker
Typical trigger:
- `task_started.payload.silent_task = true` while policy forbids unannounced silent operation
- `silence_timeout` fired with no acceptable checkpoint
Typical decisions:
- `block` for forbidden silent launch
- `force_checkpoint` once silence timeout has already occurred
- `annotate_placeholder` when a temporary disclosure is allowed but full details are not yet ready
Typical actions:
- stop launch or transition
- emit `silence_timeout` / `forced_operator_update`
- notify operator channel
### 4. Result-forwarding integrity gate
Typical trigger:
- `subagent_completed` indicates `result_available = true`
- no matching `subagent_result_forwarded` within policy window
- `subagent_result_not_forwarded` emitted or about to be emitted
Typical decisions:
- `force_checkpoint` when operator-visible follow-up is missing
- `annotate_placeholder` when a stopgap message is needed immediately
- `escalate` when forwarding integrity remains broken past deadline
Typical actions:
- `emit_event` for integrity failure
- `record_placeholder` and/or `dispatch_message`
- `notify_operator`
- `raise_escalation` for persistent failures
## Enforcement semantics by decision
### `allow`
- permit the evaluated action unchanged
- no rewrite or downgrade required
- may still record a low-severity audit decision
### `rewrite`
- replace or augment outgoing message content
- preserve original content in audit trail
- do not silently rewrite without recording that a rewrite occurred
### `block`
- prevent the attempted message, dispatch, or status transition
- produce an explicit reason
- if the block itself could become invisible, pair with `operator_notice.required = true`
### `require_review`
- prevent automatic acceptance
- route to review queue or operator channel
- keep underlying evidence attached for audit
### `force_checkpoint`
- create an immediate operator-visible update
- do not defer the notice behind the ordinary checkpoint schedule
- may coexist with `suggested_status` changes or escalation
### `escalate`
- raise visibility, severity, or routing tier
- should normally preserve the original violation context
- may include mandatory operator notice and watchdog/incident actions
### `downgrade_status`
- change optimistic status to a safer status
- required baseline: `completed -> pending_verification` when evidence is insufficient
- should preserve the original attempted claim in audit history
### `annotate_placeholder`
- permit limited continuity messaging without overstating certainty
- must label the message as provisional, incomplete, or awaiting verification/forwarding
- should not be mistaken for successful completion
## Examples
### Example 1: fake progress checkpoint rewritten into an honest placeholder
Scenario:
- A checkpoint message says “still making progress” but includes no new evidence since the previous checkpoint.
- Policy wants to avoid fake progress while still preventing silence.
Decision example:
```json
{
"decision": "annotate_placeholder",
"policy_id": "anti-fake-progress-v1",
"severity": "medium",
"reason": "checkpoint contains no new evidence and cannot count as substantive progress",
"rewritten_message": "Progress update: work is still in progress, but no new auditable artifact was attached since the previous checkpoint. Next update must include a file change, tool output, or decision record.",
"suggested_status": "in_progress",
"required_actions": [
{
"action": "rewrite_message",
"target": "outgoing_report",
"mandatory": true,
"details": {
"mode": "replace_with_placeholder"
}
},
{
"action": "append_audit_note",
"target": "task_record",
"mandatory": true,
"details": {
"note": "Original progress wording preserved for audit; placeholder annotation applied."
}
}
],
"operator_notice": {
"required": true,
"channel": "telegram",
"urgency": "medium",
"message": "Progress update sent with placeholder annotation because no new evidence was attached.",
"must_reference": [],
"deadline": null
}
}
```
Why this matters:
- Prevents fake progress from being treated as real progress.
- Still avoids silent blackhole behavior.
### Example 2: silence timeout requires immediate checkpoint
Scenario:
- A governed task exceeded its checkpoint window and triggered `silence_timeout`.
Decision example:
```json
{
"decision": "force_checkpoint",
"policy_id": "silence-timeout-v1",
"severity": "high",
"reason": "required reporting silence exceeded policy and the operator must receive an immediate update",
"rewritten_message": "Required update: task exceeded the allowed silence window. Immediate checkpoint issued while work status is reconciled.",
"suggested_status": "in_progress",
"required_actions": [
{
"action": "notify_operator",
"target": "operator_channel",
"mandatory": true,
"details": {
"kind": "forced_checkpoint"
}
},
{
"action": "emit_event",
"target": "event_stream",
"mandatory": true,
"details": {
"event_type": "forced_operator_update"
}
}
],
"operator_notice": {
"required": true,
"channel": "telegram",
"urgency": "high",
"message": "Task exceeded the allowed silence window and required an immediate checkpoint.",
"must_reference": ["silence_timeout"],
"deadline": "2026-05-07T16:00:00+08:00"
}
}
```
Why this matters:
- Covers the silent-task / overdue checkpoint path.
- Makes the operator-visible update mandatory and immediate.
### Example 3: unverified completion is downgraded
Scenario:
- A task claims `completed`, but attached evidence is only narrative or otherwise below the `moderate+` completion threshold.
Decision example:
```json
{
"decision": "downgrade_status",
"policy_id": "completion-evidence-threshold-v1",
"severity": "high",
"reason": "completion was claimed without sufficient auditable evidence",
"rewritten_message": "Completion claim received, but the task remains pending verification until auditable evidence is attached.",
"suggested_status": "pending_verification",
"required_actions": [
{
"action": "set_status",
"target": "status_transition",
"mandatory": true,
"details": {
"from": "completed",
"to": "pending_verification"
}
},
{
"action": "request_review",
"target": "review_queue",
"mandatory": true,
"details": {
"review_scope": "completion_evidence"
}
},
{
"action": "append_audit_note",
"target": "task_record",
"mandatory": true,
"details": {
"note": "Original completion claim preserved; downgraded by governance due to insufficient evidence."
}
}
],
"operator_notice": {
"required": true,
"channel": "telegram",
"urgency": "high",
"message": "Completion claim was downgraded to pending verification because sufficient evidence was not attached.",
"must_reference": [],
"deadline": null
}
}
```
Why this matters:
- Encodes the required `completed -> pending_verification` semantics.
- Prevents premature closure.
### Example 4: result arrived but operator-visible follow-up was missing
Scenario:
- A child result exists (`subagent_completed.result_available = true`), but no operator-facing forwarded result was emitted within the watchdog window.
- This is the recent failure mode the plugin must catch.
Decision example:
```json
{
"decision": "force_checkpoint",
"policy_id": "result-forwarding-integrity-v1",
"severity": "critical",
"reason": "child result was available but no operator-visible forwarding record was produced before the watchdog deadline",
"rewritten_message": "Checkpoint: child task result has been received, but the operator-visible forwarding step was missed. Governance is surfacing this immediately and preserving the result for follow-up.",
"suggested_status": "pending_verification",
"required_actions": [
{
"action": "notify_operator",
"target": "operator_channel",
"mandatory": true,
"details": {
"kind": "missing_forwarded_result"
}
},
{
"action": "emit_event",
"target": "event_stream",
"mandatory": true,
"details": {
"event_type": "subagent_result_not_forwarded"
}
},
{
"action": "record_placeholder",
"target": "outgoing_report",
"mandatory": true,
"details": {
"label": "result_received_forwarding_pending"
}
},
{
"action": "append_audit_note",
"target": "task_record",
"mandatory": true,
"details": {
"note": "Result existed before operator-visible follow-up; immediate checkpoint forced by governance."
}
}
],
"operator_notice": {
"required": true,
"channel": "telegram",
"urgency": "critical",
"message": "Child result was received but not forwarded visibly in time. Immediate checkpoint issued and follow-up is now required.",
"must_reference": [
"subagent_completed",
"subagent_result_not_forwarded"
],
"deadline": "2026-05-07T15:49:30+08:00"
}
}
```
Why this matters:
- Covers the exact blackhole-style failure where work finished but the operator path was not updated.
- Forces visible recovery instead of silent inconsistency.
### Example 5: report-anchor gate blocks dispatch
Scenario:
- A subagent dispatch is attempted without a required operator-visible report anchor.
Decision example:
```json
{
"decision": "block",
"policy_id": "pre-dispatch-report-anchor-v1",
"severity": "high",
"reason": "subagent dispatch requires a report anchor, but no operator-visible anchor was present",
"rewritten_message": null,
"suggested_status": "blocked",
"required_actions": [
{
"action": "block_transition",
"target": "status_transition",
"mandatory": true,
"details": {
"attempted_action": "subagent_dispatch"
}
},
{
"action": "emit_event",
"target": "event_stream",
"mandatory": true,
"details": {
"event_type": "report_anchor_missing"
}
}
],
"operator_notice": {
"required": false,
"channel": null,
"urgency": null,
"message": null,
"deadline": null
}
}
```
Why this matters:
- Expresses the hard pre-dispatch gate in a machine-enforceable way.
### Example 6: subagent failure immediately escalates to operator notice
Scenario:
- Subagent spawn failed and policy requires visible failure reporting immediately.
Decision example:
```json
{
"decision": "escalate",
"policy_id": "subagent-failure-immediate-report-v1",
"severity": "critical",
"reason": "subagent dispatch failed and the failure cannot remain internal-only",
"rewritten_message": "Immediate failure report: subagent dispatch failed before work could begin. Operator review and retry decision are required.",
"suggested_status": "blocked",
"required_actions": [
{
"action": "notify_operator",
"target": "operator_channel",
"mandatory": true,
"details": {
"kind": "dispatch_failure"
}
},
{
"action": "raise_escalation",
"target": "review_queue",
"mandatory": true,
"details": {
"tier": "operator_immediate"
}
},
{
"action": "emit_event",
"target": "event_stream",
"mandatory": true,
"details": {
"event_type": "forced_operator_update"
}
}
],
"operator_notice": {
"required": true,
"channel": "telegram",
"urgency": "critical",
"message": "Subagent dispatch failed and was escalated immediately for operator attention.",
"must_reference": ["subagent_spawn_failed"],
"deadline": "2026-05-07T15:41:10+08:00"
}
}
```
## Schema alignment note
The JSON Schema in `schemas/reporting-governance/decision.schema.json` encodes the canonical decision shape and enumerations from this document.
In particular it should preserve:
- the eight required core decision values
- the required top-level output fields
- action ordering and explicit mandatory flags
- operator notice shape for visible enforcement obligations
- status downgrade support for `pending_verification`
## Stability
The core decision values and required output fields in this document are canonical governance API values. Future revisions may extend optional metadata, but should avoid breaking the decision vocabulary or enforcement semantics without an explicit version change.

View File

@@ -0,0 +1,376 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://cowbay.org/schemas/reporting-governance/decision.schema.json",
"title": "Reporting Governance Decision",
"description": "Canonical policy decision schema for the reporting-governance plugin.",
"type": "object",
"additionalProperties": false,
"required": [
"decision",
"policy_id",
"severity",
"reason",
"rewritten_message",
"suggested_status",
"required_actions",
"operator_notice"
],
"properties": {
"decision": {
"$ref": "#/$defs/decision",
"description": "Canonical enforcement disposition."
},
"policy_id": {
"type": "string",
"minLength": 1,
"description": "Stable policy rule identifier that produced the decision."
},
"severity": {
"$ref": "#/$defs/severity",
"description": "Risk or urgency classification for the decision."
},
"reason": {
"type": "string",
"minLength": 1,
"description": "Human-readable rationale for the decision."
},
"rewritten_message": {
"type": ["string", "null"],
"description": "Replacement or annotated outgoing message text when governance rewrites or forces placeholder disclosure."
},
"suggested_status": {
"$ref": "#/$defs/suggestedStatusOrNull",
"description": "Recommended workflow status after enforcement, if any."
},
"required_actions": {
"type": "array",
"items": {
"$ref": "#/$defs/requiredAction"
},
"description": "Ordered list of required enforcement actions."
},
"operator_notice": {
"$ref": "#/$defs/operatorNoticeOrNull",
"description": "Operator-visible notice requirement produced by the policy."
}
},
"$defs": {
"decision": {
"type": "string",
"enum": [
"allow",
"rewrite",
"block",
"require_review",
"force_checkpoint",
"escalate",
"downgrade_status",
"annotate_placeholder"
]
},
"severity": {
"type": "string",
"enum": [
"info",
"low",
"medium",
"high",
"critical"
]
},
"suggestedStatus": {
"type": "string",
"enum": [
"in_progress",
"pending_verification",
"blocked",
"failed",
"awaiting_review",
"completed"
]
},
"suggestedStatusOrNull": {
"oneOf": [
{
"$ref": "#/$defs/suggestedStatus"
},
{
"type": "null"
}
]
},
"actionVerb": {
"type": "string",
"enum": [
"dispatch_message",
"rewrite_message",
"append_audit_note",
"block_transition",
"set_status",
"request_review",
"emit_event",
"notify_operator",
"start_watchdog",
"raise_escalation",
"record_placeholder"
]
},
"actionTarget": {
"type": "string",
"enum": [
"outgoing_report",
"status_transition",
"operator_channel",
"task_record",
"event_stream",
"watchdog",
"review_queue"
]
},
"requiredAction": {
"type": "object",
"additionalProperties": false,
"required": [
"action",
"target",
"mandatory"
],
"properties": {
"action": {
"$ref": "#/$defs/actionVerb"
},
"target": {
"$ref": "#/$defs/actionTarget"
},
"mandatory": {
"type": "boolean"
},
"details": {
"type": "object",
"additionalProperties": true
}
}
},
"urgency": {
"type": "string",
"enum": [
"info",
"low",
"medium",
"high",
"critical"
]
},
"operatorNotice": {
"type": "object",
"additionalProperties": false,
"required": [
"required",
"channel",
"urgency",
"message",
"deadline"
],
"properties": {
"required": {
"type": "boolean"
},
"channel": {
"type": ["string", "null"]
},
"urgency": {
"oneOf": [
{
"$ref": "#/$defs/urgency"
},
{
"type": "null"
}
]
},
"message": {
"type": ["string", "null"]
},
"must_reference": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
},
"deadline": {
"type": ["string", "null"],
"format": "date-time"
}
}
},
"operatorNoticeOrNull": {
"oneOf": [
{
"$ref": "#/$defs/operatorNotice"
},
{
"type": "null"
}
]
}
},
"allOf": [
{
"if": {
"properties": {
"decision": {
"const": "rewrite"
}
},
"required": ["decision"]
},
"then": {
"properties": {
"rewritten_message": {
"type": "string",
"minLength": 1
}
}
}
},
{
"if": {
"properties": {
"decision": {
"const": "annotate_placeholder"
}
},
"required": ["decision"]
},
"then": {
"properties": {
"rewritten_message": {
"type": "string",
"minLength": 1
},
"operator_notice": {
"$ref": "#/$defs/operatorNotice"
}
}
}
},
{
"if": {
"properties": {
"decision": {
"const": "force_checkpoint"
}
},
"required": ["decision"]
},
"then": {
"properties": {
"operator_notice": {
"$ref": "#/$defs/operatorNotice"
}
},
"allOf": [
{
"properties": {
"operator_notice": {
"properties": {
"required": {
"const": true
}
},
"required": ["required"]
}
}
},
{
"properties": {
"required_actions": {
"contains": {
"type": "object",
"properties": {
"action": {
"enum": ["notify_operator", "dispatch_message"]
},
"mandatory": {
"const": true
}
},
"required": ["action", "mandatory"]
}
}
}
}
]
}
},
{
"if": {
"properties": {
"decision": {
"const": "downgrade_status"
}
},
"required": ["decision"]
},
"then": {
"properties": {
"suggested_status": {
"const": "pending_verification"
},
"required_actions": {
"contains": {
"type": "object",
"properties": {
"action": {
"const": "set_status"
},
"mandatory": {
"const": true
},
"details": {
"type": "object",
"properties": {
"to": {
"const": "pending_verification"
}
},
"required": ["to"]
}
},
"required": ["action", "mandatory", "details"]
}
}
}
}
},
{
"if": {
"properties": {
"decision": {
"const": "block"
}
},
"required": ["decision"]
},
"then": {
"properties": {
"required_actions": {
"contains": {
"type": "object",
"properties": {
"action": {
"const": "block_transition"
},
"mandatory": {
"const": true
}
},
"required": ["action", "mandatory"]
}
}
}
}
}
]
}