changedInput schema / anyOf
Previous value: -[
- {
- "additionalProperties": false,
- "description": "action=\"create\": Create a task under a component. One task ≈ one PR. `success_criteria` is required — it is the contract the implementer and the reviewer both work against. Pass `check` only when a command can genuinely decide done without a human; for unattended certification also pass `check_paths`. Most tasks have neither, and that is fine. Give a markdown body with ## Why / ## How / ## Test plan — the canonical contract headings are written for you from the arguments.",
- "properties": {
- "action": {
- "const": "create",
- "type": "string"
- },
- "anchor_files": {
- "description": "(create only) Repo-relative file paths this task is about. Anchoring an open task to the code it touches surfaces it when an agent later edits that file — so they don't step on toes or duplicate planned work.",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "anchor_symbols": {
- "description": "(create only) Symbol names this task is about (function / class / constant / env var).",
- "items": {
- "type": "string"
- },
- "type": "array"
- },
- "assignee_user_id": {
- "anyOf": [
- {
- "format": "uuid",
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "(create only) Pre-assign to a user uuid (NOT a shareable id); usually leave null."
- },
- "body": {
- "description": "(create only) Markdown body (optional). Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
- "type": "string"
- },
- "check": {
- "description": "OPTIONAL — a success criterion you can RUN: a command that decides done WITHOUT a human (e.g. a test command that must exit 0, or a script that prints a number to compare against a target). Appended under `## Check`. A task that has one is runnable by a loop; unattended certification additionally requires `check_paths` so the maker cannot silently modify its own verifier. The verdict then comes from the command, not from anyone's opinion. Most tasks have no runnable check, and that is fine: omit it and a human decides when it's done, which is the normal answer for anything whose 'done' is a judgment (design, architecture, docs, ambiguous work). Do not invent a check to fill this field in. A made-up check is worse than no check: it launders a guess into something that looks like a fact, and an agent will then iterate against it and merge on it.",
- "type": "string"
- },
- "check_paths": {
- "description": "OPTIONAL — repo-relative paths the declared check depends on: its test/script and every fixture or directory it reads. Required to CERTIFY an unattended loop: `stele loop verify` fails closed when a task has a check but no declared check paths. These paths are explicit because guessing them from an arbitrary shell command silently under-protects the verifier. Repeat paths as needed.",
- "items": {
- "minLength": 1,
- "type": "string"
- },
- "minItems": 1,
- "type": "array"
- },
- "component_id": {
- "description": "REQUIRED for create — parent component shareable id.",
- "type": "string"
- },
- "kind": {
- "description": "(create only) Task kind; defaults to 'task'. Non-'task' kinds are non-claimable containers that roll up from their `blocks`-children: 'epic' groups related tasks; 'objective' is a standing goal (end-state in its body) with ordered 'milestone' phases under it.",
- "enum": [
- "task",
- "epic",
- "objective",
- "milestone"
- ],
- "type": "string"
- },
- "position": {
- "description": "(create only) Explicit ordering of a milestone within its objective (1-based).",
- "type": "integer"
- },
- "priority": {
- "anyOf": [
- {
- "enum": [
- "P0",
- "P1",
- "P2",
- "P3"
- ],
- "type": "string"
- },
- {
- "type": "null"
- }
- ],
- "description": "(create only) Priority P0 (most urgent) … P3. Omit/null = unprioritized."
- },
- "privacy_bypass": {
- "description": "true writes despite a privacy flag on a public project. Only meaningful after a flag; the user decides whether the content can be public.",
- "type": "boolean"
- },
- "privacy_false_positive": {
- "description": "With privacy_bypass: true reports the privacy flag as wrong.",
- "type": "boolean"
- },
- "privacy_judgement_id": {
- "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
- "type": "string"
- },
- "privacy_note": {
- "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
- "maxLength": 500,
- "type": "string"
- },
- "project_slug": {
- "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
- "minLength": 1,
- "type": "string"
- },
- "scope": {
- "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
- "type": "string"
- },
- "success_criteria": {
- "description": "REQUIRED — how anyone (a person, or an agent picking this up cold) knows the task is DONE. State what must be TRUE when it's finished, not what you intend to do. Appended to the body under `## Success criteria`, which is the contract the implementer and the reviewer both work against — so a task without one is a task nobody can finish or check.",
- "minLength": 1,
- "type": "string"
- },
- "target_date": {
- "description": "(create only) Optional soft target date — ISO date e.g. 2026-09-30. Valid on any kind: the date an objective or milestone is aimed at, and the date a plain task is expected by. Set it whenever someone committed to a deadline (\"I'll have it by Friday\"); a commitment with no date on it is a wish.",
- "type": "string"
- },
- "title": {
- "description": "REQUIRED for create — imperative one-liner (\"Add OAuth refresh\").",
- "maxLength": 300,
- "minLength": 1,
- "type": "string"
- },
- "topics": {
- "description": "(create only) Short tag list.",
- "items": {
- "type": "string"
- },
- "type": "array"
- }
- },
- "required": [
- "action",
- "project_slug",
- "component_id",
- "title",
- "success_criteria"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "description": "action=\"claim\": Atomically claim a task (open → in_progress), recording you as owner. Claim before you start so others know you're on it. Returns the task, or { result: 'conflict' } if someone else holds it — no race window.",
- "properties": {
- "action": {
- "const": "claim",
- "type": "string"
- },
- "dispatched_with": {
- "description": "(claim only) Operator's full briefing prompt when this claim is from a dispatched sub-agent. It is stored with the claim, up to 16 KB; longer text is truncated with a warning.",
- "type": "string"
- },
- "node_id": {
- "description": "REQUIRED for claim/complete/release/reopen/force_release — task shareable id (e.g. TASK-42).",
- "type": "string"
- },
- "parent_task_id": {
- "description": "(claim only) Operator's claimed task id (e.g. TASK-487) when this claim is from a sub-agent dispatched by the operator. Leave null for direct claims.",
- "type": "string"
- },
- "project_slug": {
- "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "action",
- "project_slug",
- "node_id"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "description": "action=\"complete\": Mark a task done. REQUIRED `summary` is appended under ## Completion summary (what shipped, where it landed, what you learned). Also closes a container (epic/objective/milestone): no claim needed, but it is REFUSED while any child is unfinished, and the error names them. A container normally closes itself when its last child closes, so completing one is mainly how you record what it delivered — and it marks the close as yours, so a child reopening later won't undo it. The result may list nearby decision/architecture nodes to re-verify (still-true / edit / supersede); that part is advisory.",
- "properties": {
- "action": {
- "const": "complete",
- "type": "string"
- },
- "node_id": {
- "description": "Task shareable id (e.g. TASK-42).",
- "type": "string"
- },
- "privacy_bypass": {
- "description": "true writes despite a privacy flag on a public project. Only meaningful after a flag; the user decides whether the content can be public.",
- "type": "boolean"
- },
- "privacy_false_positive": {
- "description": "With privacy_bypass: true reports the privacy flag as wrong.",
- "type": "boolean"
- },
- "privacy_judgement_id": {
- "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
- "type": "string"
- },
- "privacy_note": {
- "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
- "maxLength": 500,
- "type": "string"
- },
- "project_slug": {
- "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
- "minLength": 1,
- "type": "string"
- },
- "summary": {
- "description": "REQUIRED — what actually happened. The graph only learns from what closing writes down: what shipped, where it landed, what you found out, what you'd warn the next person about. A task closed with nothing said is a task the next agent has to re-derive from the diff.",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "action",
- "project_slug",
- "node_id",
- "summary"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "description": "action=\"release\": Release a task you claimed (in_progress → open) so someone else can pick it up — use when you can't finish (out of context, blocked, wrong scope).",
- "properties": {
- "action": {
- "const": "release",
- "type": "string"
- },
- "node_id": {
- "description": "Task shareable id (e.g. TASK-42).",
- "type": "string"
- },
- "project_slug": {
- "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "action",
- "project_slug",
- "node_id"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "description": "action=\"reopen\": Recovery: send a closed task (done or cancelled) back to open and clear its completion metadata so it reads as unheld and claimable again. For a stuck in_progress task, use task(action=\"force_release\") instead (this is for closed tasks).",
- "properties": {
- "action": {
- "const": "reopen",
- "type": "string"
- },
- "node_id": {
- "description": "Task shareable id (e.g. TASK-42).",
- "type": "string"
- },
- "project_slug": {
- "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "action",
- "project_slug",
- "node_id"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "description": "action=\"force_release\": Admin recovery: release an in_progress task WITHOUT holding the claim, so it returns to open for others. The release is attributed to you in the claim history (not the prior claimer). For a closed task use task(action=\"reopen\"); to take a task over rather than free it, use destructive(action=\"force_claim_task\").",
- "properties": {
- "action": {
- "const": "force_release",
- "type": "string"
- },
- "node_id": {
- "description": "Task shareable id (e.g. TASK-42).",
- "type": "string"
- },
- "project_slug": {
- "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
- "minLength": 1,
- "type": "string"
- }
- },
- "required": [
- "action",
- "project_slug",
- "node_id"
- ],
- "type": "object"
- },
- {
- "additionalProperties": false,
- "description": "action=\"loop_finalize\": Create the durable final loop envelope. Deterministic correctness comes only from the latest mechanically evidenced attempt; independent reviewer and operator intent/scope judgments remain separate fields. Approval requires all three, so model judgment can reject work but can never manufacture correctness.",
- "properties": {
- "action": {
- "const": "loop_finalize",
- "type": "string"
- },
- "node_id": {
- "description": "The loop task to finalize (TASK-N).",
- "pattern": "^TASK-\\d+$",
- "type": "string"
- },
- "operator_summary": {
- "description": "Why the operator judged the change in or out of intent and scope.",
- "minLength": 1,
- "type": "string"
- },
- "operator_verdict": {
- "description": "The operator's judgment of whether the change stays within the task's intent and scope.",
- "enum": [
- "approved",
- "rejected"
- ],
- "type": "string"
- },
- "privacy_bypass": {
- "description": "true writes despite a privacy flag on a public project. Only meaningful after a flag; the user decides whether the content can be public.",
- "type": "boolean"
- },
- "privacy_false_positive": {
- "description": "With privacy_bypass: true reports the privacy flag as wrong.",
- "type": "boolean"
- },
- "privacy_judgement_id": {
- "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
- "type": "string"
- },
- "privacy_note": {
- "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
- "maxLength": 500,
- "type": "string"
- },
- "project_slug": {
- "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
- "minLength": 1,
- "type": "string"
- },
- "reviewer_summary": {
- "description": "Why the reviewer approved or rejected the change.",
- "minLength": 1,
- "type": "string"
- },
- "reviewer_verdict": {
- "description": "The independent reviewer's judgment of the change.",
- "enum": [
- "approved",
- "rejected"
- ],
- "type": "string"
- }
- },
- "required": [
- "action",
- "project_slug",
- "node_id",
- "reviewer_verdict",
- "reviewer_summary",
- "operator_verdict",
- "operator_summary"
- ],
- "type": "object"
- }
-]New value: +[
+ {
+ "additionalProperties": false,
+ "description": "action=\"create\": Create a task under a component. One task ≈ one PR. `success_criteria` is required — it is the contract the implementer and the reviewer both work against. Pass `check` only when a command can genuinely decide done without a human; for unattended certification also pass `check_paths`. Most tasks have neither, and that is fine. Give a markdown body with ## Why / ## How / ## Test plan — the canonical contract headings are written for you from the arguments.",
+ "properties": {
+ "action": {
+ "const": "create",
+ "type": "string"
+ },
+ "anchor_files": {
+ "description": "(create only) Repo-relative file paths this task is about. Anchoring an open task to the code it touches surfaces it when an agent later edits that file — so they don't step on toes or duplicate planned work.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "anchor_symbols": {
+ "description": "(create only) Symbol names this task is about (function / class / constant / env var).",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ },
+ "assignee_user_id": {
+ "anyOf": [
+ {
+ "format": "uuid",
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "(create only) Pre-assign to a user uuid (NOT a shareable id); usually leave null."
+ },
+ "body": {
+ "description": "(create only) Markdown body (optional). Write it in plain style: one idea per sentence, active voice, lead with the condition, one term per concept, exact technical names.",
+ "type": "string"
+ },
+ "check": {
+ "description": "OPTIONAL — a success criterion you can RUN: a command that decides done WITHOUT a human (e.g. a test command that must exit 0, or a script that prints a number to compare against a target). Appended under `## Check`. A task that has one is runnable by a loop; unattended certification additionally requires `check_paths` so the maker cannot silently modify its own verifier. The verdict then comes from the command, not from anyone's opinion. Most tasks have no runnable check, and that is fine: omit it and a human decides when it's done, which is the normal answer for anything whose 'done' is a judgment (design, architecture, docs, ambiguous work). Do not invent a check to fill this field in. A made-up check is worse than no check: it launders a guess into something that looks like a fact, and an agent will then iterate against it and merge on it.",
+ "type": "string"
+ },
+ "check_paths": {
+ "description": "OPTIONAL — repo-relative paths the declared check depends on: its test/script and every fixture or directory it reads. Required to CERTIFY an unattended loop: `stele loop verify` fails closed when a task has a check but no declared check paths. These paths are explicit because guessing them from an arbitrary shell command silently under-protects the verifier. Repeat paths as needed.",
+ "items": {
+ "minLength": 1,
+ "type": "string"
+ },
+ "minItems": 1,
+ "type": "array"
+ },
+ "component_id": {
+ "description": "REQUIRED for create — parent component shareable id.",
+ "type": "string"
+ },
+ "kind": {
+ "description": "(create only) Task kind; defaults to 'task'. Non-'task' kinds are non-claimable containers that roll up from their `blocks`-children: 'epic' groups related tasks; 'objective' is a standing goal with ordered 'milestone' phases under it. Every kind still takes `success_criteria`: for an objective it is the end state that means the goal is reached.",
+ "enum": [
+ "task",
+ "epic",
+ "objective",
+ "milestone"
+ ],
+ "type": "string"
+ },
+ "position": {
+ "description": "(create only) Explicit ordering of a milestone within its objective (1-based).",
+ "type": "integer"
+ },
+ "priority": {
+ "anyOf": [
+ {
+ "enum": [
+ "P0",
+ "P1",
+ "P2",
+ "P3"
+ ],
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "(create only) Priority P0 (most urgent) … P3. Omit/null = unprioritized."
+ },
+ "privacy_bypass": {
+ "description": "true writes despite a privacy flag. Only meaningful after a flag; the user decides whether the content can be written.",
+ "type": "boolean"
+ },
+ "privacy_false_positive": {
+ "description": "With privacy_bypass: true reports the privacy flag as wrong.",
+ "type": "boolean"
+ },
+ "privacy_judgement_id": {
+ "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
+ "type": "string"
+ },
+ "privacy_note": {
+ "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
+ "maxLength": 500,
+ "type": "string"
+ },
+ "project_slug": {
+ "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "scope": {
+ "description": "(create only) Workspace scope. Omit or 'auto' = scope to the workspace mapped to the current git branch, else trunk (shared truth). 'trunk' = force shared truth even on a branch. Or pass a workspace name/id to target it. Branch-scoped writes are invisible to collaborators off that workspace.",
+ "type": "string"
+ },
+ "success_criteria": {
+ "description": "REQUIRED — how anyone (a person, or an agent picking this up cold) knows the task is DONE. State what must be TRUE when it's finished, not what you intend to do. Appended to the body under `## Success criteria`, which is the contract the implementer and the reviewer both work against — so a task without one is a task nobody can finish or check.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "target_date": {
+ "description": "(create only) Optional soft target date — ISO date e.g. 2026-09-30. Valid on any kind: the date an objective or milestone is aimed at, and the date a plain task is expected by. Set it whenever someone committed to a deadline (\"I'll have it by Friday\"); a commitment with no date on it is a wish.",
+ "type": "string"
+ },
+ "title": {
+ "description": "REQUIRED for create — imperative one-liner (\"Add OAuth refresh\").",
+ "maxLength": 300,
+ "minLength": 1,
+ "type": "string"
+ },
+ "topics": {
+ "description": "(create only) Short tag list.",
+ "items": {
+ "type": "string"
+ },
+ "type": "array"
+ }
+ },
+ "required": [
+ "action",
+ "project_slug",
+ "component_id",
+ "title",
+ "success_criteria"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "description": "action=\"claim\": Atomically claim a task (open → in_progress), recording you as owner. Claim before you start so others know you're on it. Returns the task, or { result: 'conflict' } if someone else holds it — no race window.",
+ "properties": {
+ "action": {
+ "const": "claim",
+ "type": "string"
+ },
+ "dispatched_with": {
+ "description": "(claim only) Operator's full briefing prompt when this claim is from a dispatched sub-agent. It is stored with the claim, up to 16 KB; longer text is truncated with a warning.",
+ "type": "string"
+ },
+ "node_id": {
+ "description": "REQUIRED for claim/complete/release/reopen/force_release — task shareable id (e.g. TASK-42).",
+ "type": "string"
+ },
+ "parent_task_id": {
+ "description": "(claim only) Operator's claimed task id (e.g. TASK-487) when this claim is from a sub-agent dispatched by the operator. Leave null for direct claims.",
+ "type": "string"
+ },
+ "project_slug": {
+ "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "action",
+ "project_slug",
+ "node_id"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "description": "action=\"complete\": Mark a task done. REQUIRED `summary` is appended under ## Completion summary (what shipped, where it landed, what you learned). Also closes a container (epic/objective/milestone): no claim needed, but it is REFUSED while any child is unfinished, and the error names them. A container normally closes itself when its last child closes, so completing one is mainly how you record what it delivered — and it marks the close as yours, so a child reopening later won't undo it. The result may list nearby decision/architecture nodes to re-verify (still-true / edit / supersede); that part is advisory.",
+ "properties": {
+ "action": {
+ "const": "complete",
+ "type": "string"
+ },
+ "node_id": {
+ "description": "Task shareable id (e.g. TASK-42).",
+ "type": "string"
+ },
+ "privacy_bypass": {
+ "description": "true writes despite a privacy flag. Only meaningful after a flag; the user decides whether the content can be written.",
+ "type": "boolean"
+ },
+ "privacy_false_positive": {
+ "description": "With privacy_bypass: true reports the privacy flag as wrong.",
+ "type": "boolean"
+ },
+ "privacy_judgement_id": {
+ "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
+ "type": "string"
+ },
+ "privacy_note": {
+ "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
+ "maxLength": 500,
+ "type": "string"
+ },
+ "project_slug": {
+ "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "summary": {
+ "description": "REQUIRED — what actually happened. The graph only learns from what closing writes down: what shipped, where it landed, what you found out, what you'd warn the next person about. A task closed with nothing said is a task the next agent has to re-derive from the diff.",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "action",
+ "project_slug",
+ "node_id",
+ "summary"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "description": "action=\"release\": Release a task you claimed (in_progress → open) so someone else can pick it up — use when you can't finish (out of context, blocked, wrong scope).",
+ "properties": {
+ "action": {
+ "const": "release",
+ "type": "string"
+ },
+ "node_id": {
+ "description": "Task shareable id (e.g. TASK-42).",
+ "type": "string"
+ },
+ "project_slug": {
+ "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "action",
+ "project_slug",
+ "node_id"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "description": "action=\"reopen\": Recovery: send a closed task (done or cancelled) back to open and clear its completion metadata so it reads as unheld and claimable again. For a stuck in_progress task, use task(action=\"force_release\") instead (this is for closed tasks).",
+ "properties": {
+ "action": {
+ "const": "reopen",
+ "type": "string"
+ },
+ "node_id": {
+ "description": "Task shareable id (e.g. TASK-42).",
+ "type": "string"
+ },
+ "project_slug": {
+ "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "action",
+ "project_slug",
+ "node_id"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "description": "action=\"force_release\": Admin recovery: release an in_progress task WITHOUT holding the claim, so it returns to open for others. The release is attributed to you in the claim history (not the prior claimer). For a closed task use task(action=\"reopen\"); to take a task over rather than free it, use destructive(action=\"force_claim_task\").",
+ "properties": {
+ "action": {
+ "const": "force_release",
+ "type": "string"
+ },
+ "node_id": {
+ "description": "Task shareable id (e.g. TASK-42).",
+ "type": "string"
+ },
+ "project_slug": {
+ "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
+ "minLength": 1,
+ "type": "string"
+ }
+ },
+ "required": [
+ "action",
+ "project_slug",
+ "node_id"
+ ],
+ "type": "object"
+ },
+ {
+ "additionalProperties": false,
+ "description": "action=\"loop_finalize\": Create the durable final loop envelope. Deterministic correctness comes only from the latest mechanically evidenced attempt; independent reviewer and operator intent/scope judgments remain separate fields. Approval requires all three, so model judgment can reject work but can never manufacture correctness.",
+ "properties": {
+ "action": {
+ "const": "loop_finalize",
+ "type": "string"
+ },
+ "node_id": {
+ "description": "The loop task to finalize (TASK-N).",
+ "pattern": "^TASK-\\d+$",
+ "type": "string"
+ },
+ "operator_summary": {
+ "description": "Why the operator judged the change in or out of intent and scope.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "operator_verdict": {
+ "description": "The operator's judgment of whether the change stays within the task's intent and scope.",
+ "enum": [
+ "approved",
+ "rejected"
+ ],
+ "type": "string"
+ },
+ "privacy_bypass": {
+ "description": "true writes despite a privacy flag. Only meaningful after a flag; the user decides whether the content can be written.",
+ "type": "boolean"
+ },
+ "privacy_false_positive": {
+ "description": "With privacy_bypass: true reports the privacy flag as wrong.",
+ "type": "boolean"
+ },
+ "privacy_judgement_id": {
+ "description": "With privacy_bypass: the judgement_id the privacy flag returned.",
+ "type": "string"
+ },
+ "privacy_note": {
+ "description": "With privacy_bypass: an optional short reason, kept with the bypass.",
+ "maxLength": 500,
+ "type": "string"
+ },
+ "project_slug": {
+ "description": "Project slug, e.g. \"acme-app\" — list(what=\"projects\") returns yours.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "reviewer_summary": {
+ "description": "Why the reviewer approved or rejected the change.",
+ "minLength": 1,
+ "type": "string"
+ },
+ "reviewer_verdict": {
+ "description": "The independent reviewer's judgment of the change.",
+ "enum": [
+ "approved",
+ "rejected"
+ ],
+ "type": "string"
+ }
+ },
+ "required": [
+ "action",
+ "project_slug",
+ "node_id",
+ "reviewer_verdict",
+ "reviewer_summary",
+ "operator_verdict",
+ "operator_summary"
+ ],
+ "type": "object"
+ }
+]