Files
octopus-workflow/core/schemas/runs-bundle.schema.json
T

274 lines
12 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://eightarms.net/octopus-workflow/schemas/runs-bundle.schema.json",
"title": "Tier 1 Run Archive Bundle",
"description": "Composite archive bundle committed at close: runs/archive/{slug}.json = {meta, index}. Dual-profile by schema_version: >= 2 strict (closed core field set + free-form context bag), 1 or absent legacy (structural typing only; historical drift normalized by repair-run-bundles.ts, see [org-internal #2588]). Validated by validate-run-bundles.ts; CI wiring: .gitea/workflows/octopus-schemas.yml. Authoritative layout: templates/runs-layout.md. Boundary rule: rules/two-tier-artifacts.md.",
"type": "object",
"additionalProperties": false,
"required": ["meta", "index"],
"properties": {
"meta": true,
"index": true,
"working_notes": {
"type": "string",
"description": "Final content of runs/{slug}/working-notes.md ([org-internal #2600]), inlined at archive time when the file exists. The one Tier 1 artifact whose CONTENT (not just digest) rides in the bundle — the run's narrative memory (decisions, dead ends, reviewer feedback), consumed by later retro probes and the notes-injection degradation path ([org-internal #2601]). Absent when the run kept no working notes."
},
"review_history": {
"type": "array",
"description": "Offline-verifiability digest of the run's review rounds (TD/TRC-F006, [org-internal #2688]): one entry per review stage the run executed, each derived from that stage's live reviews/{stage}/status.json history[] at archive time. Lets closed-run probes reconstruct round counts and verdicts from the bundle alone, without the (removed) live workspace or path reconstruction ([org-internal #2591]). Absent when the run kept no review rounds.",
"items": { "$ref": "#/$defs/reviewHistoryEntry" }
}
},
"allOf": [
{
"if": {
"properties": {
"meta": {
"properties": { "schema_version": { "const": 2 } },
"required": ["schema_version"]
}
}
},
"then": { "properties": { "meta": { "$ref": "#/$defs/metaStrict" } } },
"else": { "properties": { "meta": { "$ref": "#/$defs/metaLegacy" } } }
},
{
"if": {
"properties": {
"index": {
"properties": { "schema_version": { "const": 2 } },
"required": ["schema_version"]
}
}
},
"then": { "properties": { "index": { "$ref": "#/$defs/indexStrict" } } },
"else": { "properties": { "index": { "$ref": "#/$defs/indexLegacy" } } }
}
],
"$defs": {
"reviewHistoryEntry": {
"type": "object",
"additionalProperties": false,
"required": ["stage", "rounds", "final_verdict"],
"description": "Per-stage summary of one review stage's rounds. Shapes mirror review-status.schema.json (stage dir name; history[] item fields).",
"properties": {
"stage": {
"type": "string",
"minLength": 1,
"description": "Review stage identifier matching the reviews/{stage}/ directory (e.g. code, review-dag, audit-process — the live values; design-space is a retired historical value)."
},
"rounds": { "type": "integer", "minimum": 1, "description": "Number of executed rounds." },
"final_verdict": { "type": "string", "enum": ["PASS", "WARN", "FAIL"] },
"per_round": {
"type": "array",
"description": "One entry per executed round, mirroring the live status.json history[] items.",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["round", "overall_verdict", "blockers", "majors"],
"properties": {
"round": { "type": "integer", "minimum": 1 },
"overall_verdict": { "type": "string", "enum": ["PASS", "WARN", "FAIL"] },
"blockers": { "type": "integer", "minimum": 0 },
"majors": { "type": "integer", "minimum": 0 },
"minors": { "type": "integer", "minimum": 0, "description": "Count of MINOR findings for this round." }
}
}
}
}
},
"ticket": {
"oneOf": [
{ "type": "null" },
{
"type": "object",
"additionalProperties": false,
"required": ["owner", "repo", "number"],
"properties": {
"owner": { "type": "string", "minLength": 1 },
"repo": { "type": "string", "minLength": 1 },
"number": { "type": "integer", "minimum": 1 }
}
}
],
"description": "Source issue reference, or null for an ad-hoc run (no ticket)."
},
"parentEpic": {
"oneOf": [
{ "type": "null" },
{
"type": "object",
"additionalProperties": false,
"required": ["number"],
"properties": { "number": { "type": "integer", "minimum": 1 } }
}
],
"description": "Parent Epic issue number, or null if the run is not under an Epic."
},
"metaLegacy": {
"type": "object",
"additionalProperties": true,
"required": ["slug", "state", "created_at"],
"description": "Legacy profile (schema_version 1 or absent): historical bundles AND current live-workspace runs — runs-meta.schema.json / runs-index.schema.json pin schema_version 1 today. Core fields type-checked when present; extra context properties (route/pr/node/kind/...) tolerated as-is. The v2 strict profile (below) is the migration target: it becomes the profile for new runs once the live-workspace schemas are bumped to emit schema_version 2 with the context bag.",
"properties": {
"schema_version": { "type": "integer", "minimum": 1 },
"slug": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
"branch": { "type": "string" },
"state": { "type": "string", "enum": ["active", "archived"] },
"created_at": { "type": "string", "anyOf": [{ "format": "date-time" }, { "format": "date" }] },
"updated_at": { "type": "string", "anyOf": [{ "format": "date-time" }, { "format": "date" }] },
"closed_at": { "type": ["string", "null"], "anyOf": [{ "format": "date-time" }, { "format": "date" }] },
"close_commit_sha": {
"type": ["string", "null"],
"pattern": "^([0-9a-f]{40}|[0-9a-f]{64})$",
"description": "Full git SHA, or null when unresolvable (legacy runs whose landing commit is unknown)."
},
"ticket": { "$ref": "#/$defs/ticket" },
"parent_epic": { "$ref": "#/$defs/parentEpic" },
"worktree": { "type": ["string", "null"] }
}
},
"metaStrict": {
"type": "object",
"additionalProperties": false,
"required": ["schema_version", "slug", "state", "created_at", "updated_at", "ticket"],
"description": "Strict profile (schema_version 2): closed core field set. Run-specific context (route/pr/node/task_node/...) goes in the context bag — the ONLY place for non-core fields.",
"allOf": [
{
"if": { "properties": { "state": { "const": "archived" } }, "required": ["state"] },
"then": {
"properties": {
"closed_at": { "type": "string", "format": "date-time" },
"close_commit_sha": { "type": "string", "pattern": "^([0-9a-f]{40}|[0-9a-f]{64})$" }
},
"required": ["closed_at", "close_commit_sha"]
}
}
],
"properties": {
"schema_version": { "type": "integer", "const": 2 },
"slug": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
"branch": { "type": "string", "minLength": 1 },
"worktree": {
"type": ["string", "null"],
"description": "Absolute path of the worktree hosting this run, or null for ad-hoc runs without a worktree."
},
"state": { "type": "string", "enum": ["active", "archived"] },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"closed_at": { "type": ["string", "null"], "format": "date-time" },
"close_commit_sha": { "type": ["string", "null"], "pattern": "^([0-9a-f]{40}|[0-9a-f]{64})$" },
"ticket": { "$ref": "#/$defs/ticket" },
"parent_epic": { "$ref": "#/$defs/parentEpic" },
"context": {
"type": "object",
"additionalProperties": true,
"description": "Free-form run context (route, pr, node, task_node, mode, kind, ...). In v2 every non-core field MUST live here, not at meta top level."
}
}
},
"artifactLegacy": {
"type": "object",
"additionalProperties": true,
"required": ["path"],
"properties": {
"path": { "type": "string", "minLength": 1 },
"sha": {
"type": ["string", "null"],
"pattern": "^[0-9a-f]{12,64}$",
"description": "Legacy digests may be truncated (12/16-hex; source files no longer exist, cannot be re-computed). v2 requires full 64-hex."
}
}
},
"artifactStrict": {
"type": "object",
"additionalProperties": false,
"required": ["path", "type", "tier"],
"properties": {
"path": { "type": "string", "minLength": 1 },
"type": {
"type": "string",
"enum": [
"meta",
"index",
"design",
"plan",
"review-findings",
"review-status",
"review-synthesis",
"synthesis-prompt",
"precondition-gate",
"working-notes",
"analysis",
"browser-evidence",
"other"
]
},
"schema": { "type": ["string", "null"], "format": "uri" },
"tier": { "type": "integer", "const": 1 },
"stage": {
"type": ["string", "null"],
"enum": [
"requirements",
"design",
"plan-iterations",
"roadmap",
"implement",
"review-roadmap",
"review-design-space",
"review-iteration-plan",
"review-dag",
"review-code",
"verify",
"audit-process",
"merge-pr",
null
],
"description": "Producing pipeline stage. Live stage ids (per schemas/workflow-routing.schema.json): review-dag, review-code, verify, audit-process, merge-pr. Retired/phase names retained only so historical archived bundles keep validating."
},
"produced_by": {
"type": ["string", "null"],
"enum": [
"Producer",
"Reviewer",
"Verifier",
"Tool",
"Coordinator",
"Analyst",
"Architect",
"Planner",
"Developer",
"Synthesizer",
"Orchestrator",
"Remediator",
"Auditor",
null
]
},
"sha": { "type": ["string", "null"], "pattern": "^[0-9a-f]{64}$" },
"tier2_ref": { "type": ["string", "null"] }
}
},
"indexLegacy": {
"type": "object",
"additionalProperties": true,
"required": ["artifacts"],
"properties": {
"schema_version": { "type": "integer", "minimum": 1 },
"slug": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
"artifacts": { "type": "array", "items": { "$ref": "#/$defs/artifactLegacy" } }
}
},
"indexStrict": {
"type": "object",
"additionalProperties": false,
"required": ["schema_version", "slug", "artifacts"],
"properties": {
"schema_version": { "type": "integer", "const": 2 },
"slug": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
"artifacts": { "type": "array", "items": { "$ref": "#/$defs/artifactStrict" } }
}
}
}
}