@quolu/lattice 0.35.0 → 0.36.1
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/README.ja.md +28 -1
- package/README.md +8 -0
- package/bin/lattice.mjs +9 -1
- package/docs/bridge-setup.md +13 -0
- package/docs/schemas/lattice.phase_todo_revision.v3.schema.json +312 -0
- package/docs/schemas/lattice.todo_extraction.v2.schema.json +298 -0
- package/docs/schemas/lattice.todo_revision.v2.schema.json +220 -0
- package/docs/schemas/lattice.todo_revision_set.v3.schema.json +363 -0
- package/package.json +5 -1
- package/src/cli-help.mjs +12 -7
- package/src/project-cli.mjs +103 -1
- package/src/todo-cli.mjs +103 -10
- package/src/todo-contracts.mjs +2 -2
- package/src/todo-gantt-html-shared.mjs +2 -1
- package/src/todo-gantt-layout.mjs +13 -3
- package/src/todo-gantt-scope.mjs +27 -2
- package/src/todo-migration.mjs +108 -0
- package/src/todo-revision.mjs +568 -2
- package/src/todo-status.mjs +5 -2
- package/src/todo-store.mjs +155 -33
package/README.ja.md
CHANGED
|
@@ -197,7 +197,34 @@ lattice todo migrate --input <extraction.json> --serialization-reviewed
|
|
|
197
197
|
`active_set`と`next_ready`で観測できます。
|
|
198
198
|
ToDo完了は軽量確認までで、所属ToDoが全てdoneになったPhaseは`gate_ready`となり、`todo phase review`後に
|
|
199
199
|
required evidenceを束縛した`todo phase accept`で重監査の判断を記録します。監査回数やPhase数を自動追加する
|
|
200
|
-
機能ではありません。
|
|
200
|
+
機能ではありません。
|
|
201
|
+
|
|
202
|
+
**監査の既定は「有り」です。** phaseを持たないplanも終端に重監査が要ります(予約Phase
|
|
203
|
+
`terminal-audit`を暗黙に1つ持ちます)。全taskがdoneになった状態は「完走」ではなく`gate_ready`=
|
|
204
|
+
**監査待ち**であり、工程図のlive scopeはそのplanのToDoを畳みません——完走扱いで図から消えることが
|
|
205
|
+
「閉じた」の可視表現なので、監査の記録なしにそこへ行かせません。作成時に拒否はせず、
|
|
206
|
+
`todo migrate`/`plan create`の結果と最後のdoneのadvisoryで`terminal_audit_required`を通知します。
|
|
207
|
+
**終端監査はToDoのdispatch可否へ影響しません**(Phaseは重監査の順序だけを制御し、開始順はToDo DAGが決めます)。
|
|
208
|
+
規約は[ADR 0147](docs/adr/0147-audit-is-on-by-default.md)が正です。
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
lattice todo phase status --plan <key> # phase無しplanでも暗黙Phaseを返す(implicit: true)
|
|
212
|
+
lattice todo phase review --plan <key> --phase terminal-audit --reason <text>
|
|
213
|
+
lattice todo phase accept --plan <key> --phase terminal-audit --input <file>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
誤ってphase無しで作ったplanへ後からPhaseを被せる場合は、`revise-phase`の
|
|
217
|
+
`state_policy: acquire_phase`でdone状態を保ったまま獲得できます(未割当→割当の向きだけを許し、
|
|
218
|
+
既にphaseを持つtaskの付け替えは拒否します)。
|
|
219
|
+
|
|
220
|
+
契約のJSON Schemaは各入口から取れます。入力が合わないときは、違反フィールドのpathが
|
|
221
|
+
error detailの`violation_path`へ載ります(配列のソート違反は`/tasks/1`のようにindexまで名指しします)。
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
lattice plan create --schema --json # 既定は最新v3
|
|
225
|
+
lattice todo revise-phase --schema --json
|
|
226
|
+
lattice plan show <plan_key> --json # planのtask・依存・phase・状態を1コマンドで読む
|
|
227
|
+
```Phase状態は
|
|
201
228
|
`lattice todo phase status --plan <key>`、閲覧中に進捗が更新される工程表は
|
|
202
229
|
`lattice todo gantt serve --port 0`で確認できます。live viewerはloopback-only、read-onlyで、
|
|
203
230
|
`/projects/<project_id>/`というproject固有URLを返します。別projectからそれぞれ起動すれば、独立port・独立SSE経路で同時表示できます。
|
package/README.md
CHANGED
|
@@ -150,6 +150,14 @@ point of use.
|
|
|
150
150
|
transform that cannot be verified is not adopted. A finding that cannot be independently
|
|
151
151
|
re-derived is not recorded.
|
|
152
152
|
|
|
153
|
+
**Heavy audit is on by default.** A plan without explicit phases still carries an implicit
|
|
154
|
+
terminal audit: every task being done means `gate_ready` — *awaiting audit* — not finished. The
|
|
155
|
+
live dependency diagram refuses to fold such a plan away, because folding is how the product
|
|
156
|
+
says "closed", and nothing gets there without an evidence-bound `phase accept`. Creation is never
|
|
157
|
+
rejected over it; the requirement is reported instead. And the audit gate never touches dispatch:
|
|
158
|
+
phases order reviews, the ToDo DAG orders work
|
|
159
|
+
([ADR 0147](docs/adr/0147-audit-is-on-by-default.md)).
|
|
160
|
+
|
|
153
161
|
## Patent
|
|
154
162
|
|
|
155
163
|
The design in this repository is the subject of a Japanese patent application:
|
package/bin/lattice.mjs
CHANGED
|
@@ -50,13 +50,21 @@ if (help !== null) {
|
|
|
50
50
|
process.exitCode = projectCliFailure(process.stderr, error);
|
|
51
51
|
}
|
|
52
52
|
} else if (args.length === 5 && args[0] === 'plan' && args[1] === 'create'
|
|
53
|
-
&& args[2] === '--schema-version' && ['2', '3'].includes(args[3]) && args[4] === '--json') {
|
|
53
|
+
&& args[2] === '--schema-version' && ['1', '2', '3'].includes(args[3]) && args[4] === '--json') {
|
|
54
54
|
const { projectCliFailure, runPlanCreateSchema } = await import('../src/project-cli.mjs');
|
|
55
55
|
try {
|
|
56
56
|
process.exitCode = await runPlanCreateSchema({ stdout: process.stdout, version: Number(args[3]) });
|
|
57
57
|
} catch (error) {
|
|
58
58
|
process.exitCode = projectCliFailure(process.stderr, error);
|
|
59
59
|
}
|
|
60
|
+
} else if (args.length === 4 && args[0] === 'plan' && args[1] === 'show'
|
|
61
|
+
&& typeof args[2] === 'string' && args[2].length > 0 && args[3] === '--json') {
|
|
62
|
+
const { projectCliFailure, runPlanShow } = await import('../src/project-cli.mjs');
|
|
63
|
+
try {
|
|
64
|
+
process.exitCode = await runPlanShow({ cwd: process.cwd(), planKey: args[2], stdout: process.stdout });
|
|
65
|
+
} catch (error) {
|
|
66
|
+
process.exitCode = projectCliFailure(process.stderr, error);
|
|
67
|
+
}
|
|
60
68
|
} else if (args.length === 2 && args[0] === 'factory-diagnostics' && args[1] === '--json') {
|
|
61
69
|
const { buildFactoryDiagnostics } = await import('../src/factory-diagnostics.mjs');
|
|
62
70
|
const diagnostics = await buildFactoryDiagnostics();
|
package/docs/bridge-setup.md
CHANGED
|
@@ -107,6 +107,19 @@ public hostname `lattice.kitepon.dev` を次のoriginへ対応付ける。
|
|
|
107
107
|
3. **Cloudflare public HTTPS**: `https://lattice.kitepon.dev/projects/`がredirectなしで200となり、一覧から開いた
|
|
108
108
|
`/projects/<project_id>/`のHTML titleが`Lattice — <project名> 依存工程図`である。
|
|
109
109
|
|
|
110
|
+
公開viewerの404も、ブラウザとAPIの両契約を別々に確認する。未知URLへ`Accept: text/html`を
|
|
111
|
+
付けたrequestはHTTP 404かつ`Content-Type: text/html`で、`noindex, nofollow`と
|
|
112
|
+
`/projects/`、`https://kitepon.dev/`への戻り先を持つ。`Accept: application/json`では
|
|
113
|
+
HTTP 404かつ`Content-Type: application/json`で、既存の
|
|
114
|
+
`lattice.todo_gantt_http_error.v1`を返す。
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
curl --silent --show-error --include --header 'Accept: text/html' \
|
|
118
|
+
https://lattice.kitepon.dev/unknown
|
|
119
|
+
curl --silent --show-error --include --header 'Accept: application/json' \
|
|
120
|
+
https://lattice.kitepon.dev/unknown
|
|
121
|
+
```
|
|
122
|
+
|
|
110
123
|
外部gateはHTMLだけで閉じず、各projectの
|
|
111
124
|
`https://lattice.kitepon.dev/projects/<project_id>/events`も確認する。応答は200かつ
|
|
112
125
|
`Content-Type: text/event-stream`で、接続直後に`event: state`と現在の`head_digest`を返さなければならない。
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/kitepon-rgb/Lattice/blob/main/docs/schemas/lattice.phase_todo_revision.v3.schema.json",
|
|
4
|
+
"title": "lattice.phase_todo_revision.v3",
|
|
5
|
+
"description": "`lattice todo revise-phase`が受理する最新契約。v1/v2のphase-audited desired state・task/phase migrationへ、runtime task migration・source inventory・per-ToDo source cutover batchを加えた12 keyの完全契約。",
|
|
6
|
+
"$comment": "Runtime validation (src/todo-revision.mjs validatePhaseTodoRevision) additionally enforces: canonical JSON+LF bytes; strict sort order on task_migration (by from_task_id), runtime_task_migration.entries (by predecessor_task_id), runtime_task_migration.entries[].successor_task_ids/evidence_digests, and source_inventory.excluded_tombstones/source_cutover_batch.operations (by source_ref); uniqueness constraints across all of those; desired_plan.plan_version === phaseTodoRevisionPlanVersion(...); runtime_task_migration projects onto task_migration exactly (validRuntimeTodoProjection) and its successor_task_ids cover exactly desired_plan.tasks; phase_migration's target phase set equals desired_plan.phases exactly; every reconciliation.*_digest field against its own recomputation; and revision_digest as the canonical self-digest over every other top-level field.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"required": [
|
|
10
|
+
"schema", "project_id", "plan_key", "predecessor", "desired_plan",
|
|
11
|
+
"runtime_task_migration", "task_migration", "phase_migration", "source_inventory",
|
|
12
|
+
"reconciliation", "source_cutover_batch", "revision_digest"
|
|
13
|
+
],
|
|
14
|
+
"properties": {
|
|
15
|
+
"schema": { "const": "lattice.phase_todo_revision.v3" },
|
|
16
|
+
"project_id": { "$ref": "#/$defs/identifier" },
|
|
17
|
+
"plan_key": { "$ref": "#/$defs/identifier" },
|
|
18
|
+
"predecessor": { "$ref": "#/$defs/predecessor" },
|
|
19
|
+
"desired_plan": { "$ref": "#/$defs/desiredPlanV5" },
|
|
20
|
+
"runtime_task_migration": { "$ref": "#/$defs/runtimeTaskMigration" },
|
|
21
|
+
"task_migration": {
|
|
22
|
+
"type": "array", "minItems": 1, "maxItems": 512,
|
|
23
|
+
"items": { "$ref": "#/$defs/taskMigrationEntry" }
|
|
24
|
+
},
|
|
25
|
+
"phase_migration": {
|
|
26
|
+
"type": "array", "minItems": 1, "maxItems": 512,
|
|
27
|
+
"items": { "$ref": "#/$defs/phaseMigrationEntry" }
|
|
28
|
+
},
|
|
29
|
+
"source_inventory": { "$ref": "#/$defs/sourceInventory" },
|
|
30
|
+
"reconciliation": {
|
|
31
|
+
"type": "object", "additionalProperties": false,
|
|
32
|
+
"required": [
|
|
33
|
+
"predecessor_reconciliation_digest", "source_inventory_digest", "desired_plan_digest",
|
|
34
|
+
"runtime_task_migration_digest", "task_migration_digest", "phase_migration_digest",
|
|
35
|
+
"source_cutover_batch_digest", "reconciliation_digest"
|
|
36
|
+
],
|
|
37
|
+
"properties": {
|
|
38
|
+
"predecessor_reconciliation_digest": { "$ref": "#/$defs/digest" },
|
|
39
|
+
"source_inventory_digest": { "$ref": "#/$defs/digest" },
|
|
40
|
+
"desired_plan_digest": { "$ref": "#/$defs/digest" },
|
|
41
|
+
"runtime_task_migration_digest": { "$ref": "#/$defs/digest" },
|
|
42
|
+
"task_migration_digest": { "$ref": "#/$defs/digest" },
|
|
43
|
+
"phase_migration_digest": { "$ref": "#/$defs/digest" },
|
|
44
|
+
"source_cutover_batch_digest": { "$ref": "#/$defs/digest" },
|
|
45
|
+
"reconciliation_digest": { "$ref": "#/$defs/digest" }
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"source_cutover_batch": { "$ref": "#/$defs/sourceCutoverBatch" },
|
|
49
|
+
"revision_digest": { "$ref": "#/$defs/digest" }
|
|
50
|
+
},
|
|
51
|
+
"$defs": {
|
|
52
|
+
"identifier": { "type": "string", "pattern": "^[0-9A-Za-z](?:[0-9A-Za-z._-]{0,127})$" },
|
|
53
|
+
"digest": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
|
|
54
|
+
"nullableDigest": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/digest" }] },
|
|
55
|
+
"gitSha": { "type": "string", "pattern": "^[0-9a-f]{40}$" },
|
|
56
|
+
"repoRef": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"minLength": 1,
|
|
59
|
+
"maxLength": 1024,
|
|
60
|
+
"pattern": "^(?!/)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*\\\\)(?!.*[\\u0000-\\u001f\\u007f])[^/]+(?:/[^/]+)*$"
|
|
61
|
+
},
|
|
62
|
+
"sourceLineRef": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"minLength": 1,
|
|
65
|
+
"maxLength": 1024,
|
|
66
|
+
"$comment": "repoRefと同じ形に加え#L<line>を必須にする。実際の判定はparseTodoSourceRef(src/todo-revision.mjs)。",
|
|
67
|
+
"pattern": "^(?!/)(?!.*(?:^|/)\\.{1,2}(?:/|$))(?!.*\\\\)(?!.*[\\u0000-\\u001f\\u007f])[^/]+(?:/[^/]+)*#L[1-9][0-9]*$"
|
|
68
|
+
},
|
|
69
|
+
"nullableRepoRef": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/repoRef" }] },
|
|
70
|
+
"text": { "type": "string", "minLength": 1, "maxLength": 16384 },
|
|
71
|
+
"nullableText": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/text" }] },
|
|
72
|
+
"nodeRef": {
|
|
73
|
+
"type": "object", "additionalProperties": false,
|
|
74
|
+
"required": ["project_id", "plan_key", "task_id"],
|
|
75
|
+
"properties": {
|
|
76
|
+
"project_id": { "$ref": "#/$defs/identifier" },
|
|
77
|
+
"plan_key": { "$ref": "#/$defs/identifier" },
|
|
78
|
+
"task_id": { "$ref": "#/$defs/identifier" },
|
|
79
|
+
"expected_topology_digest": { "$ref": "#/$defs/digest" }
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"phaseRef": {
|
|
83
|
+
"type": "object", "additionalProperties": false,
|
|
84
|
+
"required": ["project_id", "plan_key", "phase_id"],
|
|
85
|
+
"properties": {
|
|
86
|
+
"project_id": { "$ref": "#/$defs/identifier" },
|
|
87
|
+
"plan_key": { "$ref": "#/$defs/identifier" },
|
|
88
|
+
"phase_id": { "$ref": "#/$defs/identifier" },
|
|
89
|
+
"expected_topology_digest": { "$ref": "#/$defs/digest" }
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"edge": {
|
|
93
|
+
"type": "object", "additionalProperties": false, "required": ["from", "to"],
|
|
94
|
+
"properties": { "from": { "$ref": "#/$defs/nodeRef" }, "to": { "$ref": "#/$defs/nodeRef" } }
|
|
95
|
+
},
|
|
96
|
+
"phaseAcceptDependency": {
|
|
97
|
+
"type": "object", "additionalProperties": false, "required": ["from", "to"],
|
|
98
|
+
"properties": { "from": { "$ref": "#/$defs/phaseRef" }, "to": { "$ref": "#/$defs/nodeRef" } }
|
|
99
|
+
},
|
|
100
|
+
"join": {
|
|
101
|
+
"type": "object", "additionalProperties": false, "required": ["id", "after", "before"],
|
|
102
|
+
"properties": {
|
|
103
|
+
"id": { "$ref": "#/$defs/identifier" },
|
|
104
|
+
"after": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/nodeRef" } },
|
|
105
|
+
"before": { "$ref": "#/$defs/nodeRef" }
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"narrativeAnchor": {
|
|
109
|
+
"type": "object", "additionalProperties": false,
|
|
110
|
+
"required": ["origin_plan_ref", "origin_line", "source_commit", "source_line_digest"],
|
|
111
|
+
"properties": {
|
|
112
|
+
"origin_plan_ref": { "$ref": "#/$defs/repoRef" },
|
|
113
|
+
"origin_line": { "type": "integer", "minimum": 1 },
|
|
114
|
+
"source_commit": { "type": "string", "pattern": "^(?:[0-9a-f]{40}|[0-9a-f]{64})$" },
|
|
115
|
+
"source_line_digest": { "$ref": "#/$defs/digest" }
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"compileBinding": {
|
|
119
|
+
"oneOf": [
|
|
120
|
+
{ "type": "null" },
|
|
121
|
+
{
|
|
122
|
+
"type": "object", "additionalProperties": false,
|
|
123
|
+
"required": ["boundary_manifest_digest", "compiled_plan_digest", "topology_digest", "base_sha"],
|
|
124
|
+
"properties": {
|
|
125
|
+
"boundary_manifest_digest": { "$ref": "#/$defs/digest" },
|
|
126
|
+
"compiled_plan_digest": { "$ref": "#/$defs/digest" },
|
|
127
|
+
"topology_digest": { "$ref": "#/$defs/digest" },
|
|
128
|
+
"base_sha": { "$ref": "#/$defs/gitSha" }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
"predecessor": {
|
|
134
|
+
"type": "object", "additionalProperties": false,
|
|
135
|
+
"required": ["plan_digest", "journal_head_digest", "plan_version"],
|
|
136
|
+
"properties": {
|
|
137
|
+
"plan_digest": { "$ref": "#/$defs/digest" },
|
|
138
|
+
"journal_head_digest": { "$ref": "#/$defs/digest" },
|
|
139
|
+
"plan_version": { "$ref": "#/$defs/identifier" }
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"taskV4": {
|
|
143
|
+
"type": "object", "additionalProperties": false,
|
|
144
|
+
"required": [
|
|
145
|
+
"task_id", "title", "lane", "narrative_ref", "narrative_anchor", "compile_binding",
|
|
146
|
+
"parent_task_id", "phase_id"
|
|
147
|
+
],
|
|
148
|
+
"properties": {
|
|
149
|
+
"task_id": { "$ref": "#/$defs/identifier" },
|
|
150
|
+
"title": { "$ref": "#/$defs/nullableText" },
|
|
151
|
+
"lane": { "$ref": "#/$defs/identifier" },
|
|
152
|
+
"narrative_ref": { "$ref": "#/$defs/nullableRepoRef" },
|
|
153
|
+
"narrative_anchor": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/narrativeAnchor" }] },
|
|
154
|
+
"compile_binding": { "$ref": "#/$defs/compileBinding" },
|
|
155
|
+
"parent_task_id": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/identifier" }] },
|
|
156
|
+
"phase_id": { "$ref": "#/$defs/identifier" }
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"phase": {
|
|
160
|
+
"type": "object", "additionalProperties": false,
|
|
161
|
+
"required": ["phase_id", "title", "gate_policy", "predecessor_phase_ids", "required_evidence_slots"],
|
|
162
|
+
"properties": {
|
|
163
|
+
"phase_id": { "$ref": "#/$defs/identifier" },
|
|
164
|
+
"title": { "$ref": "#/$defs/nullableText" },
|
|
165
|
+
"gate_policy": { "$ref": "#/$defs/identifier" },
|
|
166
|
+
"predecessor_phase_ids": {
|
|
167
|
+
"type": "array", "items": { "$ref": "#/$defs/identifier" }, "uniqueItems": true
|
|
168
|
+
},
|
|
169
|
+
"required_evidence_slots": {
|
|
170
|
+
"type": "array", "minItems": 1, "items": { "$ref": "#/$defs/identifier" }, "uniqueItems": true
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"desiredPlanV5": {
|
|
175
|
+
"type": "object", "additionalProperties": false,
|
|
176
|
+
"required": [
|
|
177
|
+
"schema", "project_id", "plan_key", "plan_version", "predecessor_plan_digest",
|
|
178
|
+
"tasks", "hard_dependencies", "joins", "phases", "phase_accept_dependencies",
|
|
179
|
+
"topology_digest", "plan_digest"
|
|
180
|
+
],
|
|
181
|
+
"properties": {
|
|
182
|
+
"schema": { "const": "lattice.todo_plan.v5" },
|
|
183
|
+
"project_id": { "$ref": "#/$defs/identifier" },
|
|
184
|
+
"plan_key": { "$ref": "#/$defs/identifier" },
|
|
185
|
+
"plan_version": { "$ref": "#/$defs/identifier" },
|
|
186
|
+
"predecessor_plan_digest": { "$ref": "#/$defs/nullableDigest" },
|
|
187
|
+
"tasks": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/taskV4" } },
|
|
188
|
+
"hard_dependencies": { "type": "array", "maxItems": 2048, "items": { "$ref": "#/$defs/edge" } },
|
|
189
|
+
"joins": { "type": "array", "maxItems": 128, "items": { "$ref": "#/$defs/join" } },
|
|
190
|
+
"phases": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/phase" } },
|
|
191
|
+
"phase_accept_dependencies": {
|
|
192
|
+
"type": "array", "maxItems": 2048, "items": { "$ref": "#/$defs/phaseAcceptDependency" }
|
|
193
|
+
},
|
|
194
|
+
"topology_digest": { "$ref": "#/$defs/digest" },
|
|
195
|
+
"plan_digest": { "$ref": "#/$defs/digest" }
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"taskMigrationEntry": {
|
|
199
|
+
"type": "object", "additionalProperties": false,
|
|
200
|
+
"required": ["from_task_id", "to_task_id", "state_policy"],
|
|
201
|
+
"properties": {
|
|
202
|
+
"from_task_id": { "$ref": "#/$defs/identifier" },
|
|
203
|
+
"to_task_id": { "oneOf": [{ "const": "removed" }, { "$ref": "#/$defs/identifier" }] },
|
|
204
|
+
"state_policy": {
|
|
205
|
+
"enum": ["carry", "carry_reconciled_metadata", "reset_pending", "removed"],
|
|
206
|
+
"$comment": "'removed'はto_task_id==='removed'の時だけ、他の3値はto_task_idがidentifierの時だけ許される(runtime cross-check)。runtime_task_migrationのdisposition投影とも一致していなければならない(validRuntimeTodoProjection)。"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
"phaseMigrationEntry": {
|
|
211
|
+
"type": "object", "additionalProperties": false,
|
|
212
|
+
"required": ["from_phase_id", "to_phase_id", "state_policy"],
|
|
213
|
+
"properties": {
|
|
214
|
+
"from_phase_id": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/identifier" }] },
|
|
215
|
+
"to_phase_id": { "oneOf": [{ "const": "removed" }, { "$ref": "#/$defs/identifier" }] },
|
|
216
|
+
"state_policy": {
|
|
217
|
+
"enum": ["carry", "reset", "removed"],
|
|
218
|
+
"$comment": "carryはfrom_phase_id!=null かつ to_phase_id!=='removed'の時だけ、removedはfrom_phase_id!=null かつ to_phase_id==='removed'の時だけ、resetはto_phase_id!=='removed'の時だけ許される(runtime cross-check)。"
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
"runtimeTaskMigrationEntry": {
|
|
223
|
+
"type": "object", "additionalProperties": false,
|
|
224
|
+
"required": ["predecessor_task_id", "disposition", "successor_task_ids", "reason", "evidence_digests"],
|
|
225
|
+
"properties": {
|
|
226
|
+
"predecessor_task_id": { "$ref": "#/$defs/identifier" },
|
|
227
|
+
"disposition": { "enum": ["carry", "stay", "replace", "split", "retire"] },
|
|
228
|
+
"successor_task_ids": {
|
|
229
|
+
"type": "array", "maxItems": 512, "items": { "$ref": "#/$defs/identifier" }, "uniqueItems": true,
|
|
230
|
+
"$comment": "carry/stayは要素1つでpredecessor_task_idと同一、retireは空、replace/splitは1つ以上(runtime cross-check)。全entry合算で重複禁止。"
|
|
231
|
+
},
|
|
232
|
+
"reason": { "$ref": "#/$defs/text" },
|
|
233
|
+
"evidence_digests": {
|
|
234
|
+
"type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/digest" },
|
|
235
|
+
"uniqueItems": true
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"runtimeTaskMigration": {
|
|
240
|
+
"type": "object", "additionalProperties": false,
|
|
241
|
+
"required": ["schema", "entries", "migration_digest"],
|
|
242
|
+
"properties": {
|
|
243
|
+
"schema": { "const": "lattice.runtime_task_migration.v1" },
|
|
244
|
+
"entries": {
|
|
245
|
+
"type": "array", "minItems": 1, "maxItems": 512,
|
|
246
|
+
"items": { "$ref": "#/$defs/runtimeTaskMigrationEntry" }
|
|
247
|
+
},
|
|
248
|
+
"migration_digest": { "$ref": "#/$defs/digest" }
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"sourceInventoryActiveEntry": {
|
|
252
|
+
"type": "object", "additionalProperties": false,
|
|
253
|
+
"required": ["task_id", "source_ref", "source_digest"],
|
|
254
|
+
"properties": {
|
|
255
|
+
"task_id": { "$ref": "#/$defs/identifier" },
|
|
256
|
+
"source_ref": { "$ref": "#/$defs/sourceLineRef" },
|
|
257
|
+
"source_digest": { "$ref": "#/$defs/digest" }
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
"sourceInventoryTombstone": {
|
|
261
|
+
"type": "object", "additionalProperties": false,
|
|
262
|
+
"required": ["source_ref", "source_digest", "exclusion_reason"],
|
|
263
|
+
"properties": {
|
|
264
|
+
"source_ref": { "$ref": "#/$defs/sourceLineRef" },
|
|
265
|
+
"source_digest": { "$ref": "#/$defs/digest" },
|
|
266
|
+
"exclusion_reason": { "$ref": "#/$defs/text" }
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"sourceInventory": {
|
|
270
|
+
"type": "object", "additionalProperties": false,
|
|
271
|
+
"required": ["active", "excluded_tombstones"],
|
|
272
|
+
"$comment": "activeはdesired_plan.tasksと同じ順序・同じtask_id集合でなければならず、各entryのsource_refはそのtaskのnarrative_refと一致する必要がある(revise-phase v3固有のrequireNarrativeRef、runtime cross-check)。",
|
|
273
|
+
"properties": {
|
|
274
|
+
"active": {
|
|
275
|
+
"type": "array", "maxItems": 512, "items": { "$ref": "#/$defs/sourceInventoryActiveEntry" }
|
|
276
|
+
},
|
|
277
|
+
"excluded_tombstones": {
|
|
278
|
+
"type": "array", "maxItems": 2048, "items": { "$ref": "#/$defs/sourceInventoryTombstone" }
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
"sourceCutoverOperation": {
|
|
283
|
+
"type": "object", "additionalProperties": false,
|
|
284
|
+
"required": ["task_id", "disposition", "source_ref", "source_digest", "live_replacement"],
|
|
285
|
+
"properties": {
|
|
286
|
+
"task_id": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/identifier" }] },
|
|
287
|
+
"disposition": { "enum": ["active", "excluded"] },
|
|
288
|
+
"source_ref": { "$ref": "#/$defs/sourceLineRef" },
|
|
289
|
+
"source_digest": { "$ref": "#/$defs/digest" },
|
|
290
|
+
"live_replacement": {
|
|
291
|
+
"type": "string", "minLength": 1, "maxLength": 4096,
|
|
292
|
+
"$comment": "改行・制御文字禁止に加え、Markdownチェックボックス行に見える文字列は拒否される(validLiveReplacement)。"
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
"sourceCutoverBatch": {
|
|
297
|
+
"type": "object", "additionalProperties": false,
|
|
298
|
+
"required": ["batch_id", "archive_ref", "operations", "batch_digest"],
|
|
299
|
+
"properties": {
|
|
300
|
+
"batch_id": { "$ref": "#/$defs/identifier" },
|
|
301
|
+
"archive_ref": {
|
|
302
|
+
"allOf": [{ "$ref": "#/$defs/repoRef" }, { "pattern": "\\.md$" }],
|
|
303
|
+
"$comment": "#L<line>付きのsourceLineRef形にはなり得ない(runtime cross-check)。"
|
|
304
|
+
},
|
|
305
|
+
"operations": {
|
|
306
|
+
"type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/$defs/sourceCutoverOperation" }
|
|
307
|
+
},
|
|
308
|
+
"batch_digest": { "$ref": "#/$defs/digest" }
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|