@namewta/speculo 0.8.9 → 0.8.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/structured.js +186 -0
- package/dist/src/structured.js.map +1 -1
- package/package.json +1 -1
- package/template/canonical/canonical-specdev-goal-plan.md +14 -4
- package/template/canonical/canonical-specdev-orchestrate-implementation.md +27 -7
- package/template/canonical/canonical-specdev-tickets.md +5 -2
- package/template/commands/archive-and-consolidate.md +9 -0
- package/template/commands/status.md +3 -3
- package/template/workflows/ops/A-archive-and-learn/A-archive-and-learn.md +64 -0
- package/template/workflows/ops/A-archive-and-learn/promotion-plan-template.md +41 -0
- package/template/workflows/ops/A-archive-and-learn/retrospective-template.md +53 -0
- package/template/workflows/ops/E-execute-and-stabilize/E-execute-and-stabilize.md +75 -0
- package/template/workflows/ops/E-execute-and-stabilize/attempt-summary-template.md +44 -0
- package/template/workflows/ops/E-execute-and-stabilize/diagnosis-template.md +24 -0
- package/template/workflows/ops/E-execute-and-stabilize/handoff-template.md +32 -0
- package/template/workflows/ops/E-execute-and-stabilize/rollback-template.md +26 -0
- package/template/workflows/ops/E-execute-and-stabilize/verification-state-template.json +30 -0
- package/template/workflows/ops/E-execute-and-stabilize/verification-template.md +55 -0
- package/template/workflows/ops/I-intake-and-assess/I-intake-and-assess.md +66 -0
- package/template/workflows/ops/I-intake-and-assess/change-status-template.json +26 -0
- package/template/workflows/ops/I-intake-and-assess/collector-catalog.md +28 -0
- package/template/workflows/ops/I-intake-and-assess/deployment-dossier-template.md +62 -0
- package/template/workflows/ops/I-intake-and-assess/global-change-status-template.json +26 -0
- package/template/workflows/ops/I-intake-and-assess/project-detection.md +38 -0
- package/template/workflows/ops/I-intake-and-assess/request-template.md +44 -0
- package/template/workflows/ops/I-intake-and-assess/system-report-template.md +34 -0
- package/template/workflows/ops/I-intake-and-assess/target-profile-template.json +24 -0
- package/template/workflows/ops/INDEX.md +30 -0
- package/template/workflows/ops/P-plan-and-approve/P-plan-and-approve.md +65 -0
- package/template/workflows/ops/P-plan-and-approve/plan-review-template.md +78 -0
- package/template/workflows/ops/README.md +120 -0
- package/template/workflows/ops/_state/archive/.gitkeep +1 -0
- package/template/workflows/ops/_state/changes/.gitkeep +1 -0
- package/template/workflows/ops/_state/status.json +6 -0
- package/template/workflows/ops/common/rules/artifact-contract.md +37 -0
- package/template/workflows/ops/common/rules/closure-and-learning.md +25 -0
- package/template/workflows/ops/common/rules/evidence-and-redaction.md +22 -0
- package/template/workflows/ops/common/rules/execution-loop.md +27 -0
- package/template/workflows/ops/common/rules/path-and-scope-contract.md +21 -0
- package/template/workflows/ops/common/rules/plan-and-approval.md +25 -0
- package/template/workflows/ops/common/rules/project-and-change-scope.md +20 -0
- package/template/workflows/ops/common/rules/target-profile-and-release-gates.md +44 -0
- package/template/workflows/ops/common/schemas/approval.schema.json +28 -0
- package/template/workflows/ops/common/schemas/attempt.schema.json +42 -0
- package/template/workflows/ops/common/schemas/change-status.schema.json +43 -0
- package/template/workflows/ops/common/schemas/deployment-model.schema.json +26 -0
- package/template/workflows/ops/common/schemas/implementation-plan.schema.json +221 -0
- package/template/workflows/ops/common/schemas/inventory-snapshot.schema.json +31 -0
- package/template/workflows/ops/common/schemas/journal-event.schema.json +22 -0
- package/template/workflows/ops/common/schemas/project.schema.json +19 -0
- package/template/workflows/ops/common/schemas/promotion-approval.schema.json +20 -0
- package/template/workflows/ops/common/schemas/promotion-manifest.schema.json +22 -0
- package/template/workflows/ops/common/schemas/status.schema.json +30 -0
- package/template/workflows/ops/common/schemas/target-profile.schema.json +32 -0
- package/template/workflows/ops/common/schemas/verification-state.schema.json +30 -0
- package/template/workflows/ops/common/tools/close-change.mjs +177 -0
- package/template/workflows/ops/common/tools/validate-ops.mjs +992 -0
- package/template/workflows/ops/runtime-contract.json +14 -0
- package/template/workflows/specdev/I-implement/I-implement.md +6 -3
- package/template/workflows/specdev/I-implement/evidence-template.md +13 -0
- package/template/workflows/specdev/O-orchestrate-implementation/execution-loop.md +3 -2
- package/template/workflows/specdev/P-goal-plan/completion-control.md +3 -0
- package/template/workflows/specdev/P-goal-plan/lead-orchestration.md +6 -2
- package/template/workflows/specdev/common/skills/dev-worktree/references/finalize.md +5 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 计划与批准合同
|
|
2
|
+
|
|
3
|
+
## Ready 门
|
|
4
|
+
|
|
5
|
+
P 只有在 request 明确、快照新鲜度被接受、deployment model 与 target profile v1 无 blocking unknown、source revision/target fingerprint/profile digest 可重建、deployment root 和整体控制面身份已确认、健康与恢复可判定时生成 Ready plan。重新规划还必须绑定触发 attempt 和 diagnosis。
|
|
6
|
+
|
|
7
|
+
计划深度随事故半径增长:本地可丢弃环境可 lite;共享非生产默认 standard;生产、全局配置、数据、流量、权限、密钥或不可逆动作必须 deep。
|
|
8
|
+
|
|
9
|
+
## 结构化操作与版本
|
|
10
|
+
|
|
11
|
+
每个 plan-NNN.json 使用 schema v3,并绑定 target profile path/digest。它包含 required Gate DAG、batch `gate_ids`、`after_batches`、不可变 artifact requirements、逐项 verification contract、data protection、staging/activation/previous refs 和恢复策略。每个 operation 包含 id、batch、kind、target、cwd、preconditions、write set、external mutation、preview、apply、postconditions、rollback、risk、privilege 和 evidence。无法使用 typed adapter 时,以 custom-command 显示完整 shell、command、引用方式和风险。
|
|
12
|
+
|
|
13
|
+
plan-NNN 永不覆盖。修订版记录 supersedes_plan_path;由失败 attempt 触发时再记录 triggered_by_attempt,执行前按用户审核意见修订时允许后者为 null。修订版完整重述当前待执行状态;旧已执行 batch 只由 attempt evidence 表示,不能自动成为新 plan 的批准。旧 plan v2 只读且不可重新批准;继续 mutation 必须生成 v3,不能推导缺失的 identity、Gate 或数据保护结论。
|
|
14
|
+
|
|
15
|
+
## Gate、候选与数据保护
|
|
16
|
+
|
|
17
|
+
每个 required Gate 和 verification id 只有一个 owner。batch `gate_ids` 表示启动前置 Gate,可为空;Gate `after_batches` 表示生成 Gate 结论前必须完成的批次;两者与各自依赖合成的 DAG 必须可拓扑排序。不可变候选使用 SHA-256、image digest 或 provider immutable id;可变 tag 仅作显示。适用时计划包含授权 root 内独立 staging、目标端摘要重验、原子 activation、previous ref 和保留策略。
|
|
18
|
+
|
|
19
|
+
每个 data mutation 映射 data-protection 条目。production 不接受 waiver;local waiver 仅在用户对精确对象明确批准并记录 decision locator、exact scope、对象身份、零冲突 preflight 和 forward-only 恢复边界时有效。backup 不只证明存在,还要规划可读性、restore ref 与恢复验证。cleanup 使用独立 batch。
|
|
20
|
+
|
|
21
|
+
## 批量批准
|
|
22
|
+
|
|
23
|
+
P 一次展示 target/profile identity、完整待执行 batch、Gate/依赖、候选摘要、数据保护、差异、外部 mutation、全局环境 key/scope/source/impact/rollback、风险、验证、恢复、cleanup 和期限。用户可以一条回复批准多个 ids,不逐命令确认。approval 绑定 scope/project/change、plan SHA-256、source、target、batches、条件和期限,不保存密钥。
|
|
24
|
+
|
|
25
|
+
profile/计划内容、固定点、identity、权限、external mutation、数据保护或期限漂移时,不执行受影响 batch;保留旧工件,将 approval invalidated,并返回 I/P 生成新版本。用户最初要求部署不等于对后续修复、回滚、数据恢复、cleanup、归档或知识改写的授权。
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Project 与 Change Scope
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
- `global`:宿主机、共享环境、Docker/集群控制面基线或跨项目运维规则;change 位于根 changes/archive。
|
|
6
|
+
- `project`:指定应用、仓库或可独立部署组件;change 和永久知识位于 `projects/{project_id}`。
|
|
7
|
+
|
|
8
|
+
项目工作不得使用 global scope 来绕过项目历史;project change 可在 A 阶段把确实跨项目的候选提升到全局知识。
|
|
9
|
+
|
|
10
|
+
## 项目身份
|
|
11
|
+
|
|
12
|
+
`project_id` 是 lowercase kebab 稳定目录 id,不等同于可变 display name。识别顺序:用户显式 id、已登记无凭据 VCS identity、monorepo component identity、workspace/package identity、用户确认 alias。目录 basename 只能提出候选。
|
|
13
|
+
|
|
14
|
+
VCS identity 必须移除 scheme userinfo、token、query 和 fragment;无法可靠脱敏时存储 hash 与人类可识别 label,不保存原值。identity 冲突或多个项目命中时一次展示并请求选择,不自动合并历史。
|
|
15
|
+
|
|
16
|
+
## Change 选择
|
|
17
|
+
|
|
18
|
+
全局索引 entry 统一为 `{scope, project_id, change}`。tuple 唯一;change 名只需在同一 scope root 内唯一。新 change 先写完整目录和 `.status.json`,再加入 active;失败时不留下索引悬挂。
|
|
19
|
+
|
|
20
|
+
归档 change 不恢复写入。follow-up 继承 project/global scope,但 request 明确记录来源 archive locator 和仍适用的事实;不得复制旧批准作为当前授权。
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Target Profile、发布 Gate 与数据保护
|
|
2
|
+
|
|
3
|
+
## 三层证据
|
|
4
|
+
|
|
5
|
+
I 拥有 `deployment/target-profile.json`,记录非敏感期望、现场身份和授权边界;P 拥有绑定 profile 摘要的 plan,记录候选、Gate、数据保护和恢复策略;E 在每个 attempt 中拥有 `verification-state.json`,记录实测身份、Gate、构件、探针、稳定窗口和恢复资产。Markdown 只投影这些结构化事实。
|
|
6
|
+
|
|
7
|
+
profile、plan 或 verification state 禁止保存 secret 值。只保存 key、provider/受控 locator、版本、是否必须存在和 presence 证据。需要生成私密配置时,输出必须位于 deployment root 或外部受控位置,权限和未回显证明进入 attempt;私密文件本身不得复制进 Ops state 或 HANDOFF。
|
|
8
|
+
|
|
9
|
+
## Operation Mode 与接管
|
|
10
|
+
|
|
11
|
+
- `audit`:只读盘点;不批准 mutation。
|
|
12
|
+
- `takeover`:已存在持久目录、控制面资源、数据、路由或服务时的默认模式;保持现场身份和命名。
|
|
13
|
+
- `fresh`:只在证据证明目标为空、归属清楚且 protected/unknown targets 为空时允许。
|
|
14
|
+
- `release`:向已确认目标发布不可变候选。
|
|
15
|
+
- `upgrade`:从已确认现役版本迁移到新候选。
|
|
16
|
+
- `rollback`:恢复已验证且兼容的目标或反向操作。
|
|
17
|
+
|
|
18
|
+
现场为 `present` 或 `unknown` 时不得选择 fresh。差异分类为 `ownership-conflict` 或 `unknown` 时 profile 必须 blocked;不得通过改用 global scope、改名或宽泛命令绕过。
|
|
19
|
+
|
|
20
|
+
## 控制面身份
|
|
21
|
+
|
|
22
|
+
身份由一组不可拆分 assertions 表示。每项声明 provider、key、`exact | ordered-list | set | digest` 比较、非敏感 expected 和 evidence。Compose 的 project、有序 files、env file、services、labels/image identity 和 bind host 应分别进入 assertions;目录名、容器名前缀或单一文件不能独立证明身份。
|
|
23
|
+
|
|
24
|
+
mutation 模式要求整体 `identity_confirmed=true` 和确认 evidence。E 在第一条 mutation 前重采集 actual 并逐 assertion 比较;任何漂移使 approval 失效并返回 I/P。
|
|
25
|
+
|
|
26
|
+
## 构件与提升
|
|
27
|
+
|
|
28
|
+
发布构件使用不可变 SHA-256 或 provider 的不可变 digest/image ID。适用时计划必须声明授权 root 下的独立 staging、activation target 和 previous ref;传输后在目标端重算摘要,再原子切换活动指针。未验证候选不得进入 active 位置,可变 tag 不构成不可变身份。
|
|
29
|
+
|
|
30
|
+
失败候选、previous release、rollback material 和脱敏日志默认保留。cleanup 不继承部署批准,只能由新的 plan batch 执行。
|
|
31
|
+
|
|
32
|
+
## 数据保护
|
|
33
|
+
|
|
34
|
+
每个 data mutation 映射到一个 `data_protection` 条目。默认策略为 verified backup:记录受控 evidence locator、摘要、可读性、restore ref 和恢复验证。production 不接受 waiver。
|
|
35
|
+
|
|
36
|
+
只有 local 环境且用户针对精确对象明确批准时允许 waiver;必须同时记录 decision locator、exact scope、对象身份确认、零冲突 preflight 和 `forward-only` 恢复边界。执行器事务能力未知、备份不可读或恢复路径未验证时,在第一条持久写入前停止。
|
|
37
|
+
|
|
38
|
+
## Gate 与验证
|
|
39
|
+
|
|
40
|
+
plan 的 required Gate 与 batch 形成组合 DAG:batch `gate_ids` 是启动该批次前必须 passed 的 Gate,可为空;Gate `after_batches` 是计算该 Gate 前必须完成的批次。E 只能在 batch 的全部 gate ids 已 passed 后开始该 batch;Gate failed/blocked 后不得执行新的 operation、提升活动指针或删除候选,后续 Gate只能标记 skipped。
|
|
41
|
+
|
|
42
|
+
每个 required verification id 必须由 Gate 引用并在 verification state 有唯一结果。HTTP 探针独立声明允许状态、允许业务码和认证要求;稳定窗口声明 interval、timeout 和连续成功数。瞬时失败可以记录,但连续成功不足或超时仍失败。多实例收敛通过显式 convergence group 比较不可变构件和运行配置摘要。
|
|
43
|
+
|
|
44
|
+
成功、回滚或作为 completed 依据的 abandoned attempt 必须生成 verification state 和无密钥 handoff,并证明 required Gates、数据保护、恢复资产和接受的残余风险。
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:approval:v2",
|
|
4
|
+
"title": "Ops Plan Approval",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "artifact", "scope", "project_id", "approval_id", "change", "plan_path", "plan_digest", "source_revision", "target_fingerprint", "approved_batches", "excluded_batches", "confirmed_global_environment_keys", "conditions", "decision", "decision_summary", "decided_at", "expires_at"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 2},
|
|
9
|
+
"artifact": {"const": "ops-plan-approval"},
|
|
10
|
+
"scope": {"enum": ["global", "project"]},
|
|
11
|
+
"project_id": {"type": ["string", "null"], "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
12
|
+
"approval_id": {"type": "string", "pattern": "^APPROVAL-[0-9]{3}$"},
|
|
13
|
+
"change": {"type": "string"},
|
|
14
|
+
"plan_path": {"type": "string", "pattern": "^plan/plan-[0-9]{3}\\.json$"},
|
|
15
|
+
"plan_digest": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
|
|
16
|
+
"source_revision": {"type": "string", "minLength": 1},
|
|
17
|
+
"target_fingerprint": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
|
|
18
|
+
"approved_batches": {"type": "array", "items": {"type": "string", "pattern": "^B[0-9]{2}$"}, "minItems": 1, "uniqueItems": true},
|
|
19
|
+
"excluded_batches": {"type": "array", "items": {"type": "string", "pattern": "^B[0-9]{2}$"}, "uniqueItems": true},
|
|
20
|
+
"confirmed_global_environment_keys": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
|
21
|
+
"conditions": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
|
22
|
+
"decision": {"const": "approved"},
|
|
23
|
+
"decision_summary": {"type": "string", "minLength": 1},
|
|
24
|
+
"decided_at": {"type": "string", "format": "date-time"},
|
|
25
|
+
"expires_at": {"type": "string", "format": "date-time"}
|
|
26
|
+
},
|
|
27
|
+
"additionalProperties": false
|
|
28
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:attempt:v2",
|
|
4
|
+
"title": "Ops Execution Attempt",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "artifact", "scope", "project_id", "change", "attempt_id", "kind", "triggered_by_attempt", "plan_path", "plan_digest", "approval_path", "target_profile_path", "target_profile_digest", "started_at", "ended_at", "result", "executed_batches", "failed_operation", "mutation_performed", "journal_path", "diagnosis_path", "verification_path", "verification_state_path", "verification_state_digest", "handoff_path", "retained_artifacts", "blockers"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 2},
|
|
9
|
+
"artifact": {"const": "ops-execution-attempt"},
|
|
10
|
+
"scope": {"enum": ["global", "project"]},
|
|
11
|
+
"project_id": {"type": ["string", "null"], "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
12
|
+
"change": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
13
|
+
"attempt_id": {"type": "string", "pattern": "^ATTEMPT-[0-9]{3}$"},
|
|
14
|
+
"kind": {"enum": ["deploy", "remediation", "rollback", "verification-only"]},
|
|
15
|
+
"triggered_by_attempt": {"type": ["string", "null"], "pattern": "^ATTEMPT-[0-9]{3}$"},
|
|
16
|
+
"plan_path": {"anyOf": [{"type": "null"}, {"type": "string", "pattern": "^plan/plan-[0-9]{3}\\.json$"}]},
|
|
17
|
+
"plan_digest": {"type": ["string", "null"], "pattern": "^[a-f0-9]{64}$"},
|
|
18
|
+
"approval_path": {"anyOf": [{"type": "null"}, {"type": "string", "pattern": "^plan/approval-[0-9]{3}\\.json$"}]},
|
|
19
|
+
"target_profile_path": {"type": ["string", "null"], "pattern": "^deployment/target-profile\\.json$"},
|
|
20
|
+
"target_profile_digest": {"type": ["string", "null"], "pattern": "^[a-f0-9]{64}$"},
|
|
21
|
+
"started_at": {"type": "string", "format": "date-time"},
|
|
22
|
+
"ended_at": {"type": ["string", "null"], "format": "date-time"},
|
|
23
|
+
"result": {"enum": ["running", "succeeded", "failed", "blocked", "rolled_back", "abandoned"]},
|
|
24
|
+
"executed_batches": {"type": "array", "items": {"type": "string", "pattern": "^B[0-9]{2}$"}, "uniqueItems": true},
|
|
25
|
+
"failed_operation": {"type": ["string", "null"], "pattern": "^OP[0-9]{3}$"},
|
|
26
|
+
"mutation_performed": {"type": "boolean"},
|
|
27
|
+
"journal_path": {"type": "string", "pattern": "^execution/attempts/ATTEMPT-[0-9]{3}/journal\\.jsonl$"},
|
|
28
|
+
"diagnosis_path": {"type": ["string", "null"], "pattern": "^execution/attempts/ATTEMPT-[0-9]{3}/diagnosis\\.md$"},
|
|
29
|
+
"verification_path": {"type": ["string", "null"], "pattern": "^execution/attempts/ATTEMPT-[0-9]{3}/verification\\.md$"},
|
|
30
|
+
"verification_state_path": {"type": ["string", "null"], "pattern": "^execution/attempts/ATTEMPT-[0-9]{3}/verification-state\\.json$"},
|
|
31
|
+
"verification_state_digest": {"type": ["string", "null"], "pattern": "^[a-f0-9]{64}$"},
|
|
32
|
+
"handoff_path": {"type": ["string", "null"], "pattern": "^execution/attempts/ATTEMPT-[0-9]{3}/HANDOFF\\.md$"},
|
|
33
|
+
"retained_artifacts": {"type": "array", "items": {"type": "object", "required": ["id", "kind", "locator", "reason"], "properties": {"id": {"type": "string", "minLength": 1}, "kind": {"type": "string", "minLength": 1}, "locator": {"type": "string", "minLength": 1}, "reason": {"type": "string", "minLength": 1}}, "additionalProperties": false}},
|
|
34
|
+
"blockers": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true}
|
|
35
|
+
},
|
|
36
|
+
"allOf": [
|
|
37
|
+
{"if": {"properties": {"scope": {"const": "global"}}}, "then": {"properties": {"project_id": {"const": null}}}},
|
|
38
|
+
{"if": {"properties": {"scope": {"const": "project"}}}, "then": {"properties": {"project_id": {"type": "string"}}}},
|
|
39
|
+
{"if": {"properties": {"kind": {"not": {"const": "verification-only"}}}}, "then": {"properties": {"plan_path": {"type": "string"}, "plan_digest": {"type": "string"}, "approval_path": {"type": "string"}, "target_profile_path": {"type": "string"}, "target_profile_digest": {"type": "string"}}}}
|
|
40
|
+
],
|
|
41
|
+
"additionalProperties": false
|
|
42
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:change-status:v2",
|
|
4
|
+
"title": "Ops Change Status",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schema_version", "artifact", "scope", "project_id", "change", "change_status", "phase",
|
|
8
|
+
"current_work", "works_run", "created_at", "updated_at", "completed_at", "archived_at",
|
|
9
|
+
"archive_path", "source_revision", "target_fingerprint", "plan_path", "plan_digest",
|
|
10
|
+
"approval_path", "approval_status", "approved_batches", "latest_attempt_id", "outcome", "blockers"
|
|
11
|
+
],
|
|
12
|
+
"properties": {
|
|
13
|
+
"schema_version": {"const": 2},
|
|
14
|
+
"artifact": {"const": "ops-change-status"},
|
|
15
|
+
"scope": {"enum": ["global", "project"]},
|
|
16
|
+
"project_id": {"type": ["string", "null"], "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
17
|
+
"change": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
18
|
+
"change_status": {"enum": ["active", "blocked", "completed", "archived"]},
|
|
19
|
+
"phase": {"enum": ["intake", "assessment", "planning", "awaiting_approval", "approved", "executing", "diagnosing", "stabilizing", "ready_to_archive", "archived"]},
|
|
20
|
+
"current_work": {"anyOf": [{"type": "null"}, {"enum": ["ops/archive-and-learn", "ops/execute-and-stabilize", "ops/intake-and-assess", "ops/plan-and-approve"]}]},
|
|
21
|
+
"works_run": {"type": "array", "items": {"enum": ["ops/archive-and-learn", "ops/execute-and-stabilize", "ops/intake-and-assess", "ops/plan-and-approve"]}, "uniqueItems": true},
|
|
22
|
+
"created_at": {"type": "string", "format": "date-time"},
|
|
23
|
+
"updated_at": {"type": "string", "format": "date-time"},
|
|
24
|
+
"completed_at": {"type": ["string", "null"], "format": "date-time"},
|
|
25
|
+
"archived_at": {"type": ["string", "null"], "format": "date-time"},
|
|
26
|
+
"archive_path": {"type": ["string", "null"]},
|
|
27
|
+
"source_revision": {"type": ["string", "null"], "minLength": 1},
|
|
28
|
+
"target_fingerprint": {"type": ["string", "null"], "pattern": "^[a-f0-9]{64}$"},
|
|
29
|
+
"plan_path": {"anyOf": [{"type": "null"}, {"type": "string", "pattern": "^plan/plan-[0-9]{3}\\.json$"}]},
|
|
30
|
+
"plan_digest": {"type": ["string", "null"], "pattern": "^[a-f0-9]{64}$"},
|
|
31
|
+
"approval_path": {"anyOf": [{"type": "null"}, {"type": "string", "pattern": "^plan/approval-[0-9]{3}\\.json$"}]},
|
|
32
|
+
"approval_status": {"enum": ["not_requested", "pending", "approved", "invalidated"]},
|
|
33
|
+
"approved_batches": {"type": "array", "items": {"type": "string", "pattern": "^B[0-9]{2}$"}, "uniqueItems": true},
|
|
34
|
+
"latest_attempt_id": {"type": ["string", "null"], "pattern": "^ATTEMPT-[0-9]{3}$"},
|
|
35
|
+
"outcome": {"enum": ["pending", "succeeded", "rolled_back", "abandoned"]},
|
|
36
|
+
"blockers": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true}
|
|
37
|
+
},
|
|
38
|
+
"allOf": [
|
|
39
|
+
{"if": {"properties": {"scope": {"const": "global"}}}, "then": {"properties": {"project_id": {"const": null}}}},
|
|
40
|
+
{"if": {"properties": {"scope": {"const": "project"}}}, "then": {"properties": {"project_id": {"type": "string"}}}}
|
|
41
|
+
],
|
|
42
|
+
"additionalProperties": false
|
|
43
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:deployment-model:v2",
|
|
4
|
+
"title": "Ops Deployment Model",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "artifact", "scope", "project_id", "change", "generated_at", "project", "components", "dependencies", "configuration", "data", "deployment_options", "selected_method", "health_checks", "unknowns", "readiness"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 2},
|
|
9
|
+
"artifact": {"const": "ops-deployment-model"},
|
|
10
|
+
"scope": {"enum": ["global", "project"]},
|
|
11
|
+
"project_id": {"type": ["string", "null"], "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
12
|
+
"change": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
13
|
+
"generated_at": {"type": "string", "format": "date-time"},
|
|
14
|
+
"project": {"anyOf": [{"type": "null"}, {"type": "object", "required": ["source_root", "source_revision", "languages", "build", "start"], "properties": {"source_root": {"type": "string", "minLength": 1}, "source_revision": {"type": "string", "minLength": 1}, "languages": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "build": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}, "start": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}}, "additionalProperties": false}]},
|
|
15
|
+
"components": {"type": "array", "items": {"type": "object", "required": ["id", "kind", "source"], "properties": {"id": {"type": "string"}, "kind": {"type": "string"}, "source": {"type": "string"}}, "additionalProperties": false}},
|
|
16
|
+
"dependencies": {"type": "array", "items": {"type": "object", "required": ["id", "kind", "required", "source", "target_disposition"], "properties": {"id": {"type": "string"}, "kind": {"type": "string"}, "required": {"type": "boolean"}, "source": {"type": "string"}, "target_disposition": {"enum": ["existing", "provision", "external", "unresolved"]}}, "additionalProperties": false}},
|
|
17
|
+
"configuration": {"type": "array", "items": {"type": "object", "required": ["key", "scope", "required", "secret", "source_ref"], "properties": {"key": {"type": "string", "minLength": 1}, "scope": {"enum": ["process", "service", "project", "container", "cluster", "global"]}, "required": {"type": "boolean"}, "secret": {"type": "boolean"}, "source_ref": {"type": ["string", "null"]}}, "additionalProperties": false}},
|
|
18
|
+
"data": {"type": "array", "items": {"type": "object", "required": ["id", "kind", "persistence", "migration"], "properties": {"id": {"type": "string"}, "kind": {"type": "string"}, "persistence": {"type": "string"}, "migration": {"type": ["string", "null"]}}, "additionalProperties": false}},
|
|
19
|
+
"deployment_options": {"type": "array", "items": {"type": "object", "required": ["id", "method", "evidence", "tradeoffs"], "properties": {"id": {"type": "string"}, "method": {"type": "string"}, "evidence": {"type": "array", "items": {"type": "string"}}, "tradeoffs": {"type": "array", "items": {"type": "string"}}}, "additionalProperties": false}},
|
|
20
|
+
"selected_method": {"type": ["string", "null"]},
|
|
21
|
+
"health_checks": {"type": "array", "items": {"type": "object", "required": ["id", "kind", "target", "success"], "properties": {"id": {"type": "string"}, "kind": {"type": "string"}, "target": {"type": "string"}, "success": {"type": "string"}}, "additionalProperties": false}},
|
|
22
|
+
"unknowns": {"type": "array", "items": {"type": "object", "required": ["id", "question", "blocking", "owner"], "properties": {"id": {"type": "string"}, "question": {"type": "string"}, "blocking": {"type": "boolean"}, "owner": {"type": "string"}}, "additionalProperties": false}},
|
|
23
|
+
"readiness": {"enum": ["blocked", "ready"]}
|
|
24
|
+
},
|
|
25
|
+
"additionalProperties": false
|
|
26
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:implementation-plan:v3",
|
|
4
|
+
"title": "Ops Implementation Plan",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "artifact", "scope", "project_id", "plan_id", "change", "created_at", "supersedes_plan_path", "triggered_by_attempt", "depth", "status", "input_bindings", "scope_definition", "batches", "external_mutations", "global_environment_changes", "operations", "artifact_requirements", "gates", "data_protection", "retention_policy", "verification", "rollback_strategy", "blockers"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 3},
|
|
9
|
+
"artifact": {"const": "ops-implementation-plan"},
|
|
10
|
+
"scope": {"enum": ["global", "project"]},
|
|
11
|
+
"project_id": {"type": ["string", "null"], "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
12
|
+
"plan_id": {"type": "string", "pattern": "^PLAN-[0-9]{3}$"},
|
|
13
|
+
"change": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
14
|
+
"created_at": {"type": "string", "format": "date-time"},
|
|
15
|
+
"supersedes_plan_path": {"anyOf": [{"type": "null"}, {"type": "string", "pattern": "^plan/plan-[0-9]{3}\\.json$"}]},
|
|
16
|
+
"triggered_by_attempt": {"type": ["string", "null"], "pattern": "^ATTEMPT-[0-9]{3}$"},
|
|
17
|
+
"depth": {"enum": ["lite", "standard", "deep"]},
|
|
18
|
+
"status": {"enum": ["blocked", "ready"]},
|
|
19
|
+
"input_bindings": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"required": ["request_path", "snapshot_path", "snapshot_digest", "deployment_model_path", "deployment_model_digest", "target_profile_path", "target_profile_digest", "source_revision", "target_fingerprint"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"request_path": {"type": "string", "minLength": 1},
|
|
24
|
+
"snapshot_path": {"type": "string", "minLength": 1},
|
|
25
|
+
"snapshot_digest": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
|
|
26
|
+
"deployment_model_path": {"type": "string", "minLength": 1},
|
|
27
|
+
"deployment_model_digest": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
|
|
28
|
+
"target_profile_path": {"type": "string", "pattern": "^deployment/target-profile\\.json$"},
|
|
29
|
+
"target_profile_digest": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
|
|
30
|
+
"source_revision": {"type": "string", "minLength": 1},
|
|
31
|
+
"target_fingerprint": {"type": "string", "pattern": "^[a-f0-9]{64}$"}
|
|
32
|
+
},
|
|
33
|
+
"additionalProperties": false
|
|
34
|
+
},
|
|
35
|
+
"scope_definition": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"required": ["source_root", "deployment_root", "read_roots", "write_roots", "forbidden_roots"],
|
|
38
|
+
"properties": {
|
|
39
|
+
"source_root": {"type": "string", "minLength": 1},
|
|
40
|
+
"deployment_root": {"type": "string", "minLength": 1},
|
|
41
|
+
"read_roots": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
|
42
|
+
"write_roots": {"type": "array", "items": {"type": "string"}, "minItems": 1, "uniqueItems": true},
|
|
43
|
+
"forbidden_roots": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
|
|
44
|
+
},
|
|
45
|
+
"additionalProperties": false
|
|
46
|
+
},
|
|
47
|
+
"batches": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"items": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"required": ["id", "title", "risk", "requires_confirmation", "depends_on", "operation_ids", "gate_ids"],
|
|
52
|
+
"properties": {
|
|
53
|
+
"id": {"type": "string", "pattern": "^B[0-9]{2}$"},
|
|
54
|
+
"title": {"type": "string", "minLength": 1},
|
|
55
|
+
"risk": {"enum": ["low", "medium", "high", "critical"]},
|
|
56
|
+
"requires_confirmation": {"const": true},
|
|
57
|
+
"depends_on": {"type": "array", "items": {"type": "string", "pattern": "^B[0-9]{2}$"}, "uniqueItems": true},
|
|
58
|
+
"operation_ids": {"type": "array", "items": {"type": "string", "pattern": "^OP[0-9]{3}$"}, "minItems": 1, "uniqueItems": true},
|
|
59
|
+
"gate_ids": {"type": "array", "items": {"type": "string", "pattern": "^G[0-9]{2}$"}, "uniqueItems": true}
|
|
60
|
+
},
|
|
61
|
+
"additionalProperties": false
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"external_mutations": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"items": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"required": ["id", "provider", "target", "current_state", "desired_state", "privilege", "blast_radius", "preview", "rollback", "batch_id"],
|
|
69
|
+
"properties": {
|
|
70
|
+
"id": {"type": "string", "pattern": "^EM[0-9]{3}$"},
|
|
71
|
+
"provider": {"type": "string"},
|
|
72
|
+
"target": {"type": "string"},
|
|
73
|
+
"current_state": {"type": "string"},
|
|
74
|
+
"desired_state": {"type": "string"},
|
|
75
|
+
"privilege": {"type": "string"},
|
|
76
|
+
"blast_radius": {"type": "string"},
|
|
77
|
+
"preview": {"type": "string"},
|
|
78
|
+
"rollback": {"type": "string"},
|
|
79
|
+
"batch_id": {"type": "string", "pattern": "^B[0-9]{2}$"}
|
|
80
|
+
},
|
|
81
|
+
"additionalProperties": false
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"global_environment_changes": {
|
|
85
|
+
"type": "array",
|
|
86
|
+
"items": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"required": ["key", "target_scope", "value_source_ref", "impact", "rollback", "batch_id"],
|
|
89
|
+
"properties": {
|
|
90
|
+
"key": {"type": "string"},
|
|
91
|
+
"target_scope": {"type": "string"},
|
|
92
|
+
"value_source_ref": {"type": "string"},
|
|
93
|
+
"impact": {"type": "string"},
|
|
94
|
+
"rollback": {"type": "string"},
|
|
95
|
+
"batch_id": {"type": "string", "pattern": "^B[0-9]{2}$"}
|
|
96
|
+
},
|
|
97
|
+
"additionalProperties": false
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"operations": {
|
|
101
|
+
"type": "array",
|
|
102
|
+
"items": {
|
|
103
|
+
"type": "object",
|
|
104
|
+
"required": ["id", "batch_id", "kind", "target", "working_directory", "preconditions", "write_set", "external_mutation_id", "preview", "apply", "postconditions", "rollback", "risk", "required_privilege", "evidence_path"],
|
|
105
|
+
"properties": {
|
|
106
|
+
"id": {"type": "string", "pattern": "^OP[0-9]{3}$"},
|
|
107
|
+
"batch_id": {"type": "string", "pattern": "^B[0-9]{2}$"},
|
|
108
|
+
"kind": {"enum": ["filesystem", "docker-compose", "systemd", "kubernetes", "helm", "terraform", "ansible", "database", "custom-command"]},
|
|
109
|
+
"target": {"type": "string"},
|
|
110
|
+
"working_directory": {"type": "string"},
|
|
111
|
+
"preconditions": {"type": "array", "items": {"type": "string"}, "minItems": 1},
|
|
112
|
+
"write_set": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
|
113
|
+
"external_mutation_id": {"type": ["string", "null"], "pattern": "^EM[0-9]{3}$"},
|
|
114
|
+
"preview": {"type": "object", "required": ["supported", "command", "limitations"], "properties": {"supported": {"type": "boolean"}, "command": {"type": ["string", "null"]}, "limitations": {"type": "array", "items": {"type": "string"}}}, "additionalProperties": false},
|
|
115
|
+
"apply": {"type": "object", "required": ["shell", "command"], "properties": {"shell": {"type": "string"}, "command": {"type": "string"}}, "additionalProperties": false},
|
|
116
|
+
"postconditions": {"type": "array", "items": {"type": "string"}, "minItems": 1},
|
|
117
|
+
"rollback": {"type": "object", "required": ["mode", "trigger", "command"], "properties": {"mode": {"enum": ["automatic", "manual", "not-available"]}, "trigger": {"type": "string"}, "command": {"type": ["string", "null"]}}, "additionalProperties": false},
|
|
118
|
+
"risk": {"enum": ["low", "medium", "high", "critical"]},
|
|
119
|
+
"required_privilege": {"type": "string"},
|
|
120
|
+
"evidence_path": {"type": "string"}
|
|
121
|
+
},
|
|
122
|
+
"additionalProperties": false
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"artifact_requirements": {
|
|
126
|
+
"type": "array",
|
|
127
|
+
"items": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"required": ["id", "kind", "source_ref", "immutable_digest", "staging_ref", "activation_target", "previous_ref", "required"],
|
|
130
|
+
"properties": {
|
|
131
|
+
"id": {"type": "string", "pattern": "^AR[0-9]{3}$"},
|
|
132
|
+
"kind": {"enum": ["file", "archive", "container-image", "static-bundle", "other"]},
|
|
133
|
+
"source_ref": {"type": "string", "minLength": 1},
|
|
134
|
+
"immutable_digest": {"type": "string", "pattern": "^(?:sha256:)?[a-f0-9]{64}$"},
|
|
135
|
+
"staging_ref": {"type": ["string", "null"]},
|
|
136
|
+
"activation_target": {"type": "string", "minLength": 1},
|
|
137
|
+
"previous_ref": {"type": ["string", "null"]},
|
|
138
|
+
"required": {"type": "boolean"}
|
|
139
|
+
},
|
|
140
|
+
"additionalProperties": false
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"gates": {
|
|
144
|
+
"type": "array",
|
|
145
|
+
"items": {
|
|
146
|
+
"type": "object",
|
|
147
|
+
"required": ["id", "title", "depends_on", "after_batches", "verification_ids", "required"],
|
|
148
|
+
"properties": {
|
|
149
|
+
"id": {"type": "string", "pattern": "^G[0-9]{2}$"},
|
|
150
|
+
"title": {"type": "string", "minLength": 1},
|
|
151
|
+
"depends_on": {"type": "array", "items": {"type": "string", "pattern": "^G[0-9]{2}$"}, "uniqueItems": true},
|
|
152
|
+
"after_batches": {"type": "array", "items": {"type": "string", "pattern": "^B[0-9]{2}$"}, "minItems": 1, "uniqueItems": true},
|
|
153
|
+
"verification_ids": {"type": "array", "items": {"type": "string", "pattern": "^VR[0-9]{3}$"}, "minItems": 1, "uniqueItems": true},
|
|
154
|
+
"required": {"type": "boolean"}
|
|
155
|
+
},
|
|
156
|
+
"additionalProperties": false
|
|
157
|
+
},
|
|
158
|
+
"minItems": 1
|
|
159
|
+
},
|
|
160
|
+
"data_protection": {
|
|
161
|
+
"type": "array",
|
|
162
|
+
"items": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"required": ["id", "resource", "operation_ids", "strategy", "backup", "waiver"],
|
|
165
|
+
"properties": {
|
|
166
|
+
"id": {"type": "string", "pattern": "^DP[0-9]{3}$"},
|
|
167
|
+
"resource": {"type": "string", "minLength": 1},
|
|
168
|
+
"operation_ids": {"type": "array", "items": {"type": "string", "pattern": "^OP[0-9]{3}$"}, "uniqueItems": true},
|
|
169
|
+
"strategy": {"enum": ["verified-backup", "waiver", "not-required"]},
|
|
170
|
+
"backup": {
|
|
171
|
+
"anyOf": [
|
|
172
|
+
{"type": "null"},
|
|
173
|
+
{"type": "object", "required": ["evidence_path", "digest", "readability_verified", "restore_ref", "restore_verified"], "properties": {"evidence_path": {"type": "string", "minLength": 1}, "digest": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, "readability_verified": {"const": true}, "restore_ref": {"type": "string", "minLength": 1}, "restore_verified": {"type": "boolean"}}, "additionalProperties": false}
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
"waiver": {
|
|
177
|
+
"anyOf": [
|
|
178
|
+
{"type": "null"},
|
|
179
|
+
{"type": "object", "required": ["decision_ref", "exact_scope", "object_identity_verified", "conflicts_absent", "recovery_mode"], "properties": {"decision_ref": {"type": "string", "minLength": 1}, "exact_scope": {"type": "string", "minLength": 1}, "object_identity_verified": {"const": true}, "conflicts_absent": {"const": true}, "recovery_mode": {"const": "forward-only"}}, "additionalProperties": false}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"additionalProperties": false
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"retention_policy": {
|
|
187
|
+
"type": "object",
|
|
188
|
+
"required": ["retain_failed_candidates", "retain_previous_release", "cleanup_requires_separate_approval"],
|
|
189
|
+
"properties": {
|
|
190
|
+
"retain_failed_candidates": {"const": true},
|
|
191
|
+
"retain_previous_release": {"const": true},
|
|
192
|
+
"cleanup_requires_separate_approval": {"const": true}
|
|
193
|
+
},
|
|
194
|
+
"additionalProperties": false
|
|
195
|
+
},
|
|
196
|
+
"verification": {
|
|
197
|
+
"type": "array",
|
|
198
|
+
"items": {
|
|
199
|
+
"type": "object",
|
|
200
|
+
"required": ["id", "kind", "target", "required", "expected", "stability", "convergence_group"],
|
|
201
|
+
"properties": {
|
|
202
|
+
"id": {"type": "string", "pattern": "^VR[0-9]{3}$"},
|
|
203
|
+
"kind": {"enum": ["http", "tcp", "command", "service", "artifact", "data", "custom"]},
|
|
204
|
+
"target": {"type": "string", "minLength": 1},
|
|
205
|
+
"required": {"type": "boolean"},
|
|
206
|
+
"expected": {"type": "object", "required": ["description", "http_statuses", "business_codes", "authenticated"], "properties": {"description": {"type": "string", "minLength": 1}, "http_statuses": {"type": "array", "items": {"type": "integer", "minimum": 100, "maximum": 599}, "uniqueItems": true}, "business_codes": {"type": "array", "items": {"type": ["integer", "string"]}, "uniqueItems": true}, "authenticated": {"type": ["boolean", "null"]}}, "additionalProperties": false},
|
|
207
|
+
"stability": {"anyOf": [{"type": "null"}, {"type": "object", "required": ["interval_seconds", "timeout_seconds", "required_consecutive_successes"], "properties": {"interval_seconds": {"type": "number", "exclusiveMinimum": 0}, "timeout_seconds": {"type": "number", "exclusiveMinimum": 0}, "required_consecutive_successes": {"type": "integer", "minimum": 1}}, "additionalProperties": false}]},
|
|
208
|
+
"convergence_group": {"type": ["string", "null"]}
|
|
209
|
+
},
|
|
210
|
+
"additionalProperties": false
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"rollback_strategy": {"type": "string", "minLength": 1},
|
|
214
|
+
"blockers": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true}
|
|
215
|
+
},
|
|
216
|
+
"allOf": [
|
|
217
|
+
{"if": {"properties": {"scope": {"const": "global"}}}, "then": {"properties": {"project_id": {"const": null}}}},
|
|
218
|
+
{"if": {"properties": {"scope": {"const": "project"}}}, "then": {"properties": {"project_id": {"type": "string"}}}}
|
|
219
|
+
],
|
|
220
|
+
"additionalProperties": false
|
|
221
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:inventory-snapshot:v2",
|
|
4
|
+
"title": "Ops Inventory Snapshot",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "artifact", "scope", "project_id", "snapshot_id", "change", "captured_at", "scope_definition", "target_fingerprint", "collectors", "gaps", "redactions"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 2},
|
|
9
|
+
"artifact": {"const": "ops-inventory-snapshot"},
|
|
10
|
+
"scope": {"enum": ["global", "project"]},
|
|
11
|
+
"project_id": {"type": ["string", "null"], "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
12
|
+
"snapshot_id": {"type": "string", "pattern": "^[0-9]{8}T[0-9]{6}Z(?:-[0-9]{2})?$"},
|
|
13
|
+
"change": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
14
|
+
"captured_at": {"type": "string", "format": "date-time"},
|
|
15
|
+
"scope_definition": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"required": ["levels", "targets", "approved_deep_roots"],
|
|
18
|
+
"properties": {
|
|
19
|
+
"levels": {"type": "array", "items": {"enum": ["L0", "L1", "L2"]}, "uniqueItems": true, "minItems": 1},
|
|
20
|
+
"targets": {"type": "array", "items": {"type": "string", "minLength": 1}, "minItems": 1, "uniqueItems": true},
|
|
21
|
+
"approved_deep_roots": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true}
|
|
22
|
+
},
|
|
23
|
+
"additionalProperties": false
|
|
24
|
+
},
|
|
25
|
+
"target_fingerprint": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
|
|
26
|
+
"collectors": {"type": "array", "items": {"type": "object", "required": ["id", "category", "tool", "target", "status", "facts", "evidence", "error"], "properties": {"id": {"type": "string"}, "category": {"enum": ["host", "filesystem", "runtime", "service", "network", "container", "cluster", "project-location"]}, "tool": {"type": "string"}, "target": {"type": "string"}, "status": {"enum": ["observed", "partial", "unavailable", "denied", "failed"]}, "facts": {"type": "object", "additionalProperties": true}, "evidence": {"type": "array", "items": {"type": "string"}}, "error": {"type": ["string", "null"]}}, "additionalProperties": false}, "minItems": 1},
|
|
27
|
+
"gaps": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true},
|
|
28
|
+
"redactions": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true}
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": false
|
|
31
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:journal-event:v1",
|
|
4
|
+
"title": "Ops Attempt Journal Event",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "artifact", "sequence", "at", "event", "batch_id", "gate_id", "operation_id", "result", "summary", "output_digest", "evidence"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 1},
|
|
9
|
+
"artifact": {"const": "ops-journal-event"},
|
|
10
|
+
"sequence": {"type": "integer", "minimum": 1},
|
|
11
|
+
"at": {"type": "string", "format": "date-time"},
|
|
12
|
+
"event": {"enum": ["attempt-start", "gate-result", "operation-intent", "operation-result", "postcondition-result", "attempt-end"]},
|
|
13
|
+
"batch_id": {"type": ["string", "null"], "pattern": "^B[0-9]{2}$"},
|
|
14
|
+
"gate_id": {"type": ["string", "null"], "pattern": "^G[0-9]{2}$"},
|
|
15
|
+
"operation_id": {"type": ["string", "null"], "pattern": "^OP[0-9]{3}$"},
|
|
16
|
+
"result": {"enum": ["pending", "passed", "failed", "blocked", "skipped"]},
|
|
17
|
+
"summary": {"type": "string", "minLength": 1},
|
|
18
|
+
"output_digest": {"type": ["string", "null"], "pattern": "^[a-f0-9]{64}$"},
|
|
19
|
+
"evidence": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true}
|
|
20
|
+
},
|
|
21
|
+
"additionalProperties": false
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:project:v1",
|
|
4
|
+
"title": "Ops Project Identity",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "artifact", "project_id", "display_name", "aliases", "identities", "source_hints", "created_at", "updated_at"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 1},
|
|
9
|
+
"artifact": {"const": "ops-project"},
|
|
10
|
+
"project_id": {"type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
11
|
+
"display_name": {"type": "string", "minLength": 1},
|
|
12
|
+
"aliases": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true},
|
|
13
|
+
"identities": {"type": "array", "items": {"type": "object", "required": ["kind", "value", "source"], "properties": {"kind": {"enum": ["vcs", "monorepo-component", "workspace", "package", "user-confirmed", "digest"]}, "value": {"type": "string", "minLength": 1}, "source": {"type": "string", "minLength": 1}}, "additionalProperties": false}, "minItems": 1},
|
|
14
|
+
"source_hints": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true},
|
|
15
|
+
"created_at": {"type": "string", "format": "date-time"},
|
|
16
|
+
"updated_at": {"type": "string", "format": "date-time"}
|
|
17
|
+
},
|
|
18
|
+
"additionalProperties": false
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:speculo:ops:promotion-approval:v1",
|
|
4
|
+
"title": "Ops Promotion Approval",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "artifact", "scope", "project_id", "change", "manifest_path", "manifest_digest", "decision", "decision_summary", "decided_at"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 1},
|
|
9
|
+
"artifact": {"const": "ops-promotion-approval"},
|
|
10
|
+
"scope": {"enum": ["global", "project"]},
|
|
11
|
+
"project_id": {"type": ["string", "null"], "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"},
|
|
12
|
+
"change": {"type": "string"},
|
|
13
|
+
"manifest_path": {"const": "promotion/manifest.json"},
|
|
14
|
+
"manifest_digest": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
|
|
15
|
+
"decision": {"const": "approved"},
|
|
16
|
+
"decision_summary": {"type": "string", "minLength": 1},
|
|
17
|
+
"decided_at": {"type": "string", "format": "date-time"}
|
|
18
|
+
},
|
|
19
|
+
"additionalProperties": false
|
|
20
|
+
}
|