@quolu/lattice 0.58.2 → 0.58.4
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/package.json +1 -1
- package/src/cli-help.mjs +4 -2
- package/src/todo-cli.mjs +206 -22
- package/src/todo-store.mjs +2 -2
- package/src/todo-structure-contracts.mjs +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quolu/lattice",
|
|
3
|
-
"version": "0.58.
|
|
3
|
+
"version": "0.58.4",
|
|
4
4
|
"description": "Schedulability compiler for multi-agent development: observe real code boundaries, refactor the conflicting seam, recompile the plan for parallel execution",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Quo / クオ at kitepon.dev",
|
package/src/cli-help.mjs
CHANGED
|
@@ -113,8 +113,10 @@ Write commands:
|
|
|
113
113
|
# 検査済みplanned sourceをcanonical refへ保存する。compile成功までは有効化しない
|
|
114
114
|
structure compile --plan <key> --input <file>
|
|
115
115
|
# source graph・Git provenance・ToDo DAGを結合する。consistent時だけplanへimmutableに有効化する
|
|
116
|
+
structure realize --plan <key> --task <id> (--planned|--realized <actual-structure.json>) [--commit <HEAD|sha>]...
|
|
117
|
+
# AIはplannedどおりか実体構造だけを判断する。identity・HEAD・履歴鎖・digest・actor・時刻は機械生成する
|
|
116
118
|
structure realize --plan <key> --task <id> --input <file>
|
|
117
|
-
#
|
|
119
|
+
# 完全なrealization envelopeを移送・再生する互換入口
|
|
118
120
|
structure finalize --plan <key> --json
|
|
119
121
|
# 全対象task完了後、最終HEADと全realizationを再結合する。fresh consistentだけterminal受理へ進む
|
|
120
122
|
seam-proposal compile --plan <key> # 並列可否記録と実sensorからseam提案を記録する
|
|
@@ -236,7 +238,7 @@ const SUBCOMMAND_USAGE = Object.freeze({
|
|
|
236
238
|
'todo note list': 'todo note list --plan <key> [--task <id>] --json',
|
|
237
239
|
'todo bindings': 'todo bindings [--plan <key>] [--json]',
|
|
238
240
|
'todo independence': 'todo independence [--plan <key>] [--json] | compile --plan <key> --input <file> | witness migrate --plan <key>',
|
|
239
|
-
'todo structure': 'todo structure --schema --json | [--plan <key>] --json | input --plan <key> --input <file> [--dry-run --json] | compile --plan <key> --input <file> | realize --plan <key> --task <id> --input <
|
|
241
|
+
'todo structure': 'todo structure --schema --json | [--plan <key>] --json | input --plan <key> --input <file> [--dry-run --json] | compile --plan <key> --input <file> | realize --plan <key> --task <id> (--planned|--realized <actual-structure.json>) [--commit <HEAD|sha>]... | realize --plan <key> --task <id> --input <full-realization.json> | finalize --plan <key> --json',
|
|
240
242
|
'todo seam-profile': 'todo seam-profile --plan <key> --file <path> [--json]',
|
|
241
243
|
'todo seam-proposal': 'todo seam-proposal [--plan <key>] [--json] | compile --plan <key>',
|
|
242
244
|
'todo verify': 'todo verify [--plan <key>] [--json]',
|
package/src/todo-cli.mjs
CHANGED
|
@@ -74,6 +74,10 @@ import {
|
|
|
74
74
|
} from './todo-store.mjs';
|
|
75
75
|
import {
|
|
76
76
|
TODO_STRUCTURE_BINDING_SCHEMA,
|
|
77
|
+
TODO_STRUCTURE_LIMITS,
|
|
78
|
+
TODO_STRUCTURE_REALIZATION_SCHEMA,
|
|
79
|
+
digestTodoStructureTransform,
|
|
80
|
+
explainTodoStructureTransform,
|
|
77
81
|
explainTodoStructureRealization,
|
|
78
82
|
explainTodoStructureSet,
|
|
79
83
|
} from './todo-structure-contracts.mjs';
|
|
@@ -646,7 +650,7 @@ function terminalAuditDoneAdvisory(plan, phases) {
|
|
|
646
650
|
|
|
647
651
|
async function mutate({
|
|
648
652
|
repoRoot, env, planKey, taskId, kind, payload, evidenceRef, advisory = null,
|
|
649
|
-
noteContext = null,
|
|
653
|
+
noteContext = null, structureContext = null,
|
|
650
654
|
}) {
|
|
651
655
|
const actor = mutationActor(env);
|
|
652
656
|
const evidence = evidenceRef === null ? null : await readEvidenceInput(repoRoot, evidenceRef);
|
|
@@ -674,7 +678,7 @@ async function mutate({
|
|
|
674
678
|
throw new TypeError('start mutation requires note context');
|
|
675
679
|
}
|
|
676
680
|
const result = {
|
|
677
|
-
schema: includesNoteContext ? 'lattice.todo_mutation_result.
|
|
681
|
+
schema: includesNoteContext ? 'lattice.todo_mutation_result.v5' : 'lattice.todo_mutation_result.v2',
|
|
678
682
|
project_id: event.project_id,
|
|
679
683
|
plan_key: event.plan_key,
|
|
680
684
|
plan_version: event.plan_version,
|
|
@@ -689,6 +693,7 @@ async function mutate({
|
|
|
689
693
|
...(includesNoteContext ? {
|
|
690
694
|
design_memo: designMemoProjection(authoredTask),
|
|
691
695
|
note_context: noteContext,
|
|
696
|
+
structure_context: structureContext,
|
|
692
697
|
} : {}),
|
|
693
698
|
result_digest: '',
|
|
694
699
|
};
|
|
@@ -696,6 +701,41 @@ async function mutate({
|
|
|
696
701
|
return result;
|
|
697
702
|
}
|
|
698
703
|
|
|
704
|
+
async function startStructureContext({ repoRoot, store, planKey, taskId }) {
|
|
705
|
+
const member = store.members.find(({ descriptor }) => descriptor.plan_key === planKey);
|
|
706
|
+
if (member === undefined) throw new TodoStoreError('STORE_INCONSISTENT', 'plan_not_active');
|
|
707
|
+
const source = await readTodoStructureSource({ repoRoot, planKey });
|
|
708
|
+
const binding = await readTodoStructureBinding({
|
|
709
|
+
repoRoot, planKey, planVersion: member.plan.plan_version,
|
|
710
|
+
});
|
|
711
|
+
if (source === null || binding === null) return {
|
|
712
|
+
status: 'not_enabled', enabled: false, freshness: null, stale_reasons: [],
|
|
713
|
+
structure_set_digest: null, task: null, next_actions: [],
|
|
714
|
+
};
|
|
715
|
+
if (source.structure_set_digest !== binding.structure_set_digest) {
|
|
716
|
+
throw new TodoStoreError('STRUCTURE_LIFECYCLE_GATE_FAILED',
|
|
717
|
+
'enabled_structure_source_unreadable', undefined, { plan_key: planKey });
|
|
718
|
+
}
|
|
719
|
+
const task = source.tasks.find(({ task_id: id }) => id === taskId);
|
|
720
|
+
if (task === undefined) {
|
|
721
|
+
throw new TodoStoreError('STRUCTURE_LIFECYCLE_GATE_FAILED',
|
|
722
|
+
'enabled_structure_task_missing', undefined, { plan_key: planKey, task_id: taskId });
|
|
723
|
+
}
|
|
724
|
+
const state = await readTodoStructureState({ repoRoot, store, planKey });
|
|
725
|
+
return {
|
|
726
|
+
status: 'available', enabled: true, freshness: state.status,
|
|
727
|
+
stale_reasons: state.stale_reasons,
|
|
728
|
+
structure_set_digest: source.structure_set_digest,
|
|
729
|
+
task: structuredClone(task),
|
|
730
|
+
next_actions: task.applicability === 'graph'
|
|
731
|
+
? [
|
|
732
|
+
`lattice todo structure realize --plan ${planKey} --task ${taskId} --planned`,
|
|
733
|
+
`lattice todo structure realize --plan ${planKey} --task ${taskId} --realized <actual-structure.json>`,
|
|
734
|
+
]
|
|
735
|
+
: [],
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
|
|
699
739
|
function designMemoProjection(task) {
|
|
700
740
|
if (typeof task.design_memo === 'string') {
|
|
701
741
|
return { status: 'available', markdown: task.design_memo, prompt: TODO_DESIGN_MEMO_PROMPT };
|
|
@@ -898,8 +938,12 @@ async function startTask({
|
|
|
898
938
|
const advisory = await startAdvisory({
|
|
899
939
|
repoRoot, store, projection, planKey, taskId: resolvedTaskId,
|
|
900
940
|
});
|
|
941
|
+
const structureContext = await startStructureContext({
|
|
942
|
+
repoRoot, store, planKey, taskId: resolvedTaskId,
|
|
943
|
+
});
|
|
901
944
|
return mutate({ repoRoot, env, planKey, taskId: resolvedTaskId, kind: 'start',
|
|
902
|
-
payload: { override_reason: overrideReason }, evidenceRef: null, advisory, noteContext
|
|
945
|
+
payload: { override_reason: overrideReason }, evidenceRef: null, advisory, noteContext,
|
|
946
|
+
structureContext });
|
|
903
947
|
}
|
|
904
948
|
|
|
905
949
|
async function retractStart({ repoRoot, env, planKey, taskId, reason }) {
|
|
@@ -1961,6 +2005,31 @@ function structurePlanMember(store, requestedPlanKey) {
|
|
|
1961
2005
|
return store.members[0];
|
|
1962
2006
|
}
|
|
1963
2007
|
|
|
2008
|
+
function parseAutomatedStructureRealizeArgs(argv) {
|
|
2009
|
+
if (argv[0] !== 'structure' || argv[1] !== 'realize'
|
|
2010
|
+
|| argv[2] !== '--plan' || !isTodoIdentifier(argv[3])
|
|
2011
|
+
|| argv[4] !== '--task' || !isTodoIdentifier(argv[5])) return null;
|
|
2012
|
+
let cursor;
|
|
2013
|
+
let usePlanned;
|
|
2014
|
+
let realizedRef = null;
|
|
2015
|
+
if (argv[6] === '--planned') {
|
|
2016
|
+
cursor = 7; usePlanned = true;
|
|
2017
|
+
} else if (argv[6] === '--realized' && isTodoRef(argv[7])) {
|
|
2018
|
+
cursor = 8; usePlanned = false; realizedRef = argv[7];
|
|
2019
|
+
} else {
|
|
2020
|
+
return null;
|
|
2021
|
+
}
|
|
2022
|
+
const commitRefs = [];
|
|
2023
|
+
while (cursor < argv.length) {
|
|
2024
|
+
if (argv[cursor] !== '--commit' || typeof argv[cursor + 1] !== 'string') return null;
|
|
2025
|
+
commitRefs.push(argv[cursor + 1]);
|
|
2026
|
+
cursor += 2;
|
|
2027
|
+
}
|
|
2028
|
+
return {
|
|
2029
|
+
planKey: argv[3], taskId: argv[5], usePlanned, realizedRef, commitRefs,
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
|
|
1964
2033
|
function structureNextActions({ coverage, planKey, findings = [], staleReasons = [] }) {
|
|
1965
2034
|
const actions = [];
|
|
1966
2035
|
const add = (value) => { if (!actions.includes(value)) actions.push(value); };
|
|
@@ -1976,14 +2045,16 @@ function structureNextActions({ coverage, planKey, findings = [], staleReasons =
|
|
|
1976
2045
|
if (staleReasons.includes('realization_head_digest')) {
|
|
1977
2046
|
add(`lattice todo structure --plan ${planKey} --json`);
|
|
1978
2047
|
} else {
|
|
1979
|
-
add(`lattice todo structure realize --plan ${planKey} --task <task-id> --
|
|
2048
|
+
add(`lattice todo structure realize --plan ${planKey} --task <task-id> --planned`);
|
|
2049
|
+
add(`lattice todo structure realize --plan ${planKey} --task <task-id> --realized <actual-structure.json>`);
|
|
1980
2050
|
}
|
|
1981
2051
|
add(`lattice todo structure finalize --plan ${planKey} --json`);
|
|
1982
2052
|
} else if (coverage === 'superseded') {
|
|
1983
2053
|
add(`lattice todo structure input --plan ${planKey} --input <migrated-structure-set.json> --dry-run --json`);
|
|
1984
2054
|
} else if (coverage === 'consistent') {
|
|
1985
2055
|
add(`lattice todo structure --plan ${planKey} --json`);
|
|
1986
|
-
add(`lattice todo structure realize --plan ${planKey} --task <task-id> --
|
|
2056
|
+
add(`lattice todo structure realize --plan ${planKey} --task <task-id> --planned`);
|
|
2057
|
+
add(`lattice todo structure realize --plan ${planKey} --task <task-id> --realized <actual-structure.json>`);
|
|
1987
2058
|
add(`lattice todo structure finalize --plan ${planKey} --json`);
|
|
1988
2059
|
}
|
|
1989
2060
|
return actions;
|
|
@@ -2097,6 +2168,24 @@ async function readStructureRealizationInput(repoRoot, inputRef) {
|
|
|
2097
2168
|
});
|
|
2098
2169
|
}
|
|
2099
2170
|
|
|
2171
|
+
async function readStructureRealizedTransformInput(repoRoot, inputRef) {
|
|
2172
|
+
let explained = null;
|
|
2173
|
+
return readJsonInput(repoRoot, inputRef, {
|
|
2174
|
+
validate: (value) => {
|
|
2175
|
+
explained = explainTodoStructureTransform(value);
|
|
2176
|
+
return explained.valid;
|
|
2177
|
+
},
|
|
2178
|
+
invalidCode: 'INVALID_TODO_STRUCTURE_TRANSFORM',
|
|
2179
|
+
}).catch((error) => {
|
|
2180
|
+
if (error?.code === 'INVALID_TODO_STRUCTURE_TRANSFORM' && explained !== null) {
|
|
2181
|
+
throw new TodoStoreError(error.code, explained.reason, undefined, {
|
|
2182
|
+
input_ref: inputRef, path: explained.path,
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
throw error;
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2100
2189
|
async function readCurrentStructureEffective(repoRoot, structureSet) {
|
|
2101
2190
|
const realizations = [];
|
|
2102
2191
|
for (const task of structureSet.tasks.filter(({ applicability }) => applicability === 'graph')) {
|
|
@@ -2107,22 +2196,7 @@ async function readCurrentStructureEffective(repoRoot, structureSet) {
|
|
|
2107
2196
|
return projectTodoStructureEffective({ structureSet, realizations });
|
|
2108
2197
|
}
|
|
2109
2198
|
|
|
2110
|
-
async function
|
|
2111
|
-
const realization = await readStructureRealizationInput(repoRoot, inputRef);
|
|
2112
|
-
const actor = mutationActor(env);
|
|
2113
|
-
if (realization.plan_key !== planKey || realization.task_id !== taskId) {
|
|
2114
|
-
throw new TodoStoreError('STRUCTURE_REALIZATION_BINDING_MISMATCH',
|
|
2115
|
-
'cli_target_mismatch', undefined, {
|
|
2116
|
-
expected: { plan_key: planKey, task_id: taskId },
|
|
2117
|
-
actual: { plan_key: realization.plan_key, task_id: realization.task_id },
|
|
2118
|
-
});
|
|
2119
|
-
}
|
|
2120
|
-
if (canonicalizeTodoArtifact(realization.actor) !== canonicalizeTodoArtifact(actor)) {
|
|
2121
|
-
throw new TodoStoreError('STRUCTURE_REALIZATION_BINDING_MISMATCH',
|
|
2122
|
-
'actor_environment_mismatch', undefined, {
|
|
2123
|
-
expected_actor: actor, actual_actor: realization.actor,
|
|
2124
|
-
});
|
|
2125
|
-
}
|
|
2199
|
+
async function recordStructureRealization({ repoRoot, planKey, taskId, realization }) {
|
|
2126
2200
|
const appended = await appendTodoStructureRealization({ repoRoot, realization });
|
|
2127
2201
|
const structureSet = await readTodoStructureSource({ repoRoot, planKey });
|
|
2128
2202
|
const effective = await readCurrentStructureEffective(repoRoot, structureSet);
|
|
@@ -2143,6 +2217,103 @@ async function structureRealize({ repoRoot, env, planKey, taskId, inputRef }) {
|
|
|
2143
2217
|
return result;
|
|
2144
2218
|
}
|
|
2145
2219
|
|
|
2220
|
+
async function structureRealize({ repoRoot, env, planKey, taskId, inputRef }) {
|
|
2221
|
+
const realization = await readStructureRealizationInput(repoRoot, inputRef);
|
|
2222
|
+
const actor = mutationActor(env);
|
|
2223
|
+
if (realization.plan_key !== planKey || realization.task_id !== taskId) {
|
|
2224
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_BINDING_MISMATCH',
|
|
2225
|
+
'cli_target_mismatch', undefined, {
|
|
2226
|
+
expected: { plan_key: planKey, task_id: taskId },
|
|
2227
|
+
actual: { plan_key: realization.plan_key, task_id: realization.task_id },
|
|
2228
|
+
});
|
|
2229
|
+
}
|
|
2230
|
+
if (canonicalizeTodoArtifact(realization.actor) !== canonicalizeTodoArtifact(actor)) {
|
|
2231
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_BINDING_MISMATCH',
|
|
2232
|
+
'actor_environment_mismatch', undefined, {
|
|
2233
|
+
expected_actor: actor, actual_actor: realization.actor,
|
|
2234
|
+
});
|
|
2235
|
+
}
|
|
2236
|
+
return recordStructureRealization({ repoRoot, planKey, taskId, realization });
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
function resolveStructureRealizationCommits(repoRoot, refs) {
|
|
2240
|
+
const requested = refs.length === 0 ? ['HEAD'] : refs;
|
|
2241
|
+
if (requested.length > TODO_STRUCTURE_LIMITS.commitsPerRealization) {
|
|
2242
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_COMMIT_REF_INVALID',
|
|
2243
|
+
'commit_ref_count_exceeds_limit', undefined, {
|
|
2244
|
+
actual: requested.length, limit: TODO_STRUCTURE_LIMITS.commitsPerRealization,
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
const resolved = [];
|
|
2248
|
+
for (const ref of requested) {
|
|
2249
|
+
if (!(ref === 'HEAD' || /^[0-9a-f]{40}$/u.test(ref))) {
|
|
2250
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_COMMIT_REF_INVALID',
|
|
2251
|
+
'commit_ref_must_be_head_or_full_sha', undefined, { commit_ref: ref });
|
|
2252
|
+
}
|
|
2253
|
+
let oid;
|
|
2254
|
+
try {
|
|
2255
|
+
oid = gitSync(['rev-parse', '--verify', `${ref}^{commit}`], {
|
|
2256
|
+
cwd: repoRoot, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],
|
|
2257
|
+
}).trim();
|
|
2258
|
+
} catch {
|
|
2259
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_COMMIT_REF_INVALID',
|
|
2260
|
+
'commit_ref_unresolved', undefined, { commit_ref: ref });
|
|
2261
|
+
}
|
|
2262
|
+
if (!/^[0-9a-f]{40}$/u.test(oid)) {
|
|
2263
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_COMMIT_REF_INVALID',
|
|
2264
|
+
'commit_ref_resolved_invalid_oid', undefined, { commit_ref: ref });
|
|
2265
|
+
}
|
|
2266
|
+
if (resolved.includes(oid)) {
|
|
2267
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_COMMIT_REF_INVALID',
|
|
2268
|
+
'duplicate_commit_ref', undefined, { commit_ref: ref, commit_oid: oid });
|
|
2269
|
+
}
|
|
2270
|
+
resolved.push(oid);
|
|
2271
|
+
}
|
|
2272
|
+
return resolved.sort();
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
async function structureRealizeActual({
|
|
2276
|
+
repoRoot, env, planKey, taskId, realizedRef, usePlanned, commitRefs,
|
|
2277
|
+
}) {
|
|
2278
|
+
const structureSet = await readTodoStructureSource({ repoRoot, planKey });
|
|
2279
|
+
if (structureSet === null) {
|
|
2280
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_BINDING_MISMATCH',
|
|
2281
|
+
'planned_structure_source_missing', undefined, { plan_key: planKey });
|
|
2282
|
+
}
|
|
2283
|
+
const task = structureSet.tasks.find(({ task_id: id }) => id === taskId);
|
|
2284
|
+
if (task?.applicability !== 'graph') {
|
|
2285
|
+
throw new TodoStoreError('STRUCTURE_REALIZATION_BINDING_MISMATCH',
|
|
2286
|
+
'task_not_graph_applicable', undefined, { plan_key: planKey, task_id: taskId });
|
|
2287
|
+
}
|
|
2288
|
+
const realized = usePlanned
|
|
2289
|
+
? structuredClone(task.planned)
|
|
2290
|
+
: await readStructureRealizedTransformInput(repoRoot, realizedRef);
|
|
2291
|
+
const chain = await readTodoStructureRealizationChain({
|
|
2292
|
+
repoRoot, structureSet, taskId,
|
|
2293
|
+
});
|
|
2294
|
+
const previous = chain.at(-1) ?? null;
|
|
2295
|
+
const realization = {
|
|
2296
|
+
schema: TODO_STRUCTURE_REALIZATION_SCHEMA,
|
|
2297
|
+
project_id: structureSet.project_id,
|
|
2298
|
+
plan_key: structureSet.plan_key,
|
|
2299
|
+
plan_version: structureSet.plan_version,
|
|
2300
|
+
task_id: taskId,
|
|
2301
|
+
sequence: (previous?.sequence ?? 0) + 1,
|
|
2302
|
+
previous_digest: previous?.realization_digest ?? null,
|
|
2303
|
+
structure_set_digest: structureSet.structure_set_digest,
|
|
2304
|
+
planned_digest: digestTodoStructureTransform(task.planned),
|
|
2305
|
+
head_sha: currentHeadSha(repoRoot),
|
|
2306
|
+
commit_oids: resolveStructureRealizationCommits(repoRoot, commitRefs),
|
|
2307
|
+
realized,
|
|
2308
|
+
supersedes: previous?.realization_digest ?? null,
|
|
2309
|
+
actor: mutationActor(env),
|
|
2310
|
+
recorded_at: new Date().toISOString(),
|
|
2311
|
+
realization_digest: '',
|
|
2312
|
+
};
|
|
2313
|
+
realization.realization_digest = todoSelfDigest(realization, 'realization_digest');
|
|
2314
|
+
return recordStructureRealization({ repoRoot, planKey, taskId, realization });
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2146
2317
|
async function structureFinalize({ repoRoot, env, planKey }) {
|
|
2147
2318
|
const store = await readTodoStore({ repoRoot });
|
|
2148
2319
|
const member = structurePlanMember(store, planKey);
|
|
@@ -2178,7 +2349,7 @@ async function structureFinalize({ repoRoot, env, planKey }) {
|
|
|
2178
2349
|
throw new TodoStoreError('STRUCTURE_FINALIZATION_UNAVAILABLE',
|
|
2179
2350
|
'realization_missing', undefined, {
|
|
2180
2351
|
plan_key: planKey, task_id: task.task_id,
|
|
2181
|
-
next_action: `lattice todo structure realize --plan ${planKey} --task ${task.task_id} --
|
|
2352
|
+
next_action: `lattice todo structure realize --plan ${planKey} --task ${task.task_id} --realized <actual-structure.json>`,
|
|
2182
2353
|
});
|
|
2183
2354
|
}
|
|
2184
2355
|
realizations.push(...chain);
|
|
@@ -3442,6 +3613,14 @@ export async function runTodoCli({ argv, cwd, stdout, stderr, env = process.env
|
|
|
3442
3613
|
});
|
|
3443
3614
|
}
|
|
3444
3615
|
|
|
3616
|
+
if (argv[0] === 'structure' && argv[1] === 'realize'
|
|
3617
|
+
&& argv[6] === '--realized' && typeof argv[7] === 'string' && path.isAbsolute(argv[7])) {
|
|
3618
|
+
return typedArgumentFailure(stderr, 'INPUT_OUTSIDE_REPOSITORY', 'absolute_input_path_rejected', {
|
|
3619
|
+
argument: '--realized', expected: 'repo-relative path', actual: 'absolute path',
|
|
3620
|
+
next_action: 'place_the_input_inside_the_repository_and_pass_a_repo_relative_path',
|
|
3621
|
+
});
|
|
3622
|
+
}
|
|
3623
|
+
|
|
3445
3624
|
// `--schema --json`はstoreを読まない決定的な出力(`plan create --schema`と同じ規律)。
|
|
3446
3625
|
// 通常dispatchより前に処理し、repoRoot解決やdashboard daemon起動を経由させない。
|
|
3447
3626
|
if (argv.length === 3 && argv[1] === '--schema' && argv[2] === '--json'
|
|
@@ -3476,6 +3655,7 @@ export async function runTodoCli({ argv, cwd, stdout, stderr, env = process.env
|
|
|
3476
3655
|
}
|
|
3477
3656
|
}
|
|
3478
3657
|
|
|
3658
|
+
const automatedStructureRealize = parseAutomatedStructureRealizeArgs(argv);
|
|
3479
3659
|
let action = null;
|
|
3480
3660
|
if ((argv.length === 1 && argv[0] === 'status')
|
|
3481
3661
|
|| (argv.length === 2 && argv[0] === 'status' && argv[1] === '--json')) {
|
|
@@ -3578,6 +3758,10 @@ export async function runTodoCli({ argv, cwd, stdout, stderr, env = process.env
|
|
|
3578
3758
|
action = (repoRoot) => structureRealize({
|
|
3579
3759
|
repoRoot, env, planKey: argv[3], taskId: argv[5], inputRef: argv[7],
|
|
3580
3760
|
});
|
|
3761
|
+
} else if (automatedStructureRealize !== null) {
|
|
3762
|
+
action = (repoRoot) => structureRealizeActual({
|
|
3763
|
+
repoRoot, env, ...automatedStructureRealize,
|
|
3764
|
+
});
|
|
3581
3765
|
} else if (argv.length === 5 && argv[0] === 'structure' && argv[1] === 'finalize'
|
|
3582
3766
|
&& argv[2] === '--plan' && isTodoIdentifier(argv[3]) && argv[4] === '--json') {
|
|
3583
3767
|
action = (repoRoot) => structureFinalize({ repoRoot, env, planKey: argv[3] });
|
package/src/todo-store.mjs
CHANGED
|
@@ -1640,7 +1640,7 @@ async function enforceTodoStructureLifecycleGate(repoRoot, member, eventInput) {
|
|
|
1640
1640
|
if (latest === undefined) {
|
|
1641
1641
|
fail('STRUCTURE_REALIZATION_REQUIRED', 'fresh_realization_missing', {
|
|
1642
1642
|
plan_key: member.plan.plan_key, task_id: eventInput.task_id,
|
|
1643
|
-
next_action: `lattice todo structure realize --plan ${member.plan.plan_key} --task ${eventInput.task_id} --
|
|
1643
|
+
next_action: `lattice todo structure realize --plan ${member.plan.plan_key} --task ${eventInput.task_id} --realized <actual-structure.json>`,
|
|
1644
1644
|
});
|
|
1645
1645
|
}
|
|
1646
1646
|
let currentHead;
|
|
@@ -1655,7 +1655,7 @@ async function enforceTodoStructureLifecycleGate(repoRoot, member, eventInput) {
|
|
|
1655
1655
|
fail('STRUCTURE_REALIZATION_REQUIRED', 'realization_head_stale', {
|
|
1656
1656
|
plan_key: member.plan.plan_key, task_id: eventInput.task_id,
|
|
1657
1657
|
realization_head_sha: latest.head_sha, current_head_sha: currentHead,
|
|
1658
|
-
next_action: `lattice todo structure realize --plan ${member.plan.plan_key} --task ${eventInput.task_id} --
|
|
1658
|
+
next_action: `lattice todo structure realize --plan ${member.plan.plan_key} --task ${eventInput.task_id} --realized <actual-structure.json>`,
|
|
1659
1659
|
});
|
|
1660
1660
|
}
|
|
1661
1661
|
}
|
|
@@ -467,6 +467,11 @@ export const digestTodoStructureTransform = (value) => todoSelfDigest(
|
|
|
467
467
|
{ schema: 'lattice.todo_structure_transform.v1', transform: value, digest: '' }, 'digest',
|
|
468
468
|
);
|
|
469
469
|
|
|
470
|
+
/** AIが判断して渡す実体構造だけを、realization envelopeとは独立に検証する。 */
|
|
471
|
+
export function explainTodoStructureTransform(value) {
|
|
472
|
+
return transform(value, '');
|
|
473
|
+
}
|
|
474
|
+
|
|
470
475
|
export function explainTodoStructureRealization(value, { structureSet = null, previous = null,
|
|
471
476
|
priorDigests = null } = {}) {
|
|
472
477
|
try {
|