@quolu/lattice 0.67.4 → 0.67.5
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 +1 -0
- package/src/todo-cli.mjs +51 -3
- package/src/todo-contracts.mjs +6 -0
- package/src/todo-store.mjs +12 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quolu/lattice",
|
|
3
|
-
"version": "0.67.
|
|
3
|
+
"version": "0.67.5",
|
|
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
|
@@ -110,6 +110,7 @@ Write commands:
|
|
|
110
110
|
reopen --plan <key> --task <id> --reason <text> [--override-reason <text>]
|
|
111
111
|
evidence promote --plan <key> --task <id> --evidence <file>
|
|
112
112
|
# done状態と完了時刻を維持し、最新doneへ追記eventで証拠を再束縛する
|
|
113
|
+
start --plan <key> --task <id> --rebind --reason <text> # 改訂でcarryされたin-progressへ現版のstart束縛を積み直す(ADR 0191)
|
|
113
114
|
dependency connect --from-plan <key> --from-task <id> --to-plan <key> --to-task <id> --reason <text>
|
|
114
115
|
dependency disconnect --from-plan <key> --from-task <id> --to-plan <key> --to-task <id> --reason <text>
|
|
115
116
|
# 開発中に発見した依存を明示接続する(同一plan内・plan跨ぎとも)。依存の自動推定は行わない
|
package/src/todo-cli.mjs
CHANGED
|
@@ -901,6 +901,47 @@ async function startTask({
|
|
|
901
901
|
structureContext });
|
|
902
902
|
}
|
|
903
903
|
|
|
904
|
+
// plan改訂でcarryされたin-progress ToDoの再束縛入口(ADR 0191)。task状態・開始時刻は
|
|
905
|
+
// 変えず、現plan_version・現actorのstart束縛だけをjournalへ積む。runtime intakeは
|
|
906
|
+
// literal startだけを束縛に使いcarryを推定しないため、改訂を跨いだ進行中工程の
|
|
907
|
+
// 再開はこの入口だけが正規経路になる。advisory・independence gateは初回startで
|
|
908
|
+
// 済んでいるため再適用しない。
|
|
909
|
+
async function rebindStart({ repoRoot, env, planKey, taskId, reason }) {
|
|
910
|
+
const store = await readTodoStore({ repoRoot });
|
|
911
|
+
const member = store.members.find(({ descriptor }) => descriptor.plan_key === planKey);
|
|
912
|
+
if (member === undefined) throw new TodoStoreError('STORE_INCONSISTENT', 'plan_not_active');
|
|
913
|
+
const task = member.tasks.find(({ task_id: candidate }) => candidate === taskId);
|
|
914
|
+
if (task === undefined) {
|
|
915
|
+
throw new TodoStoreError('TASK_NOT_FOUND', 'task_not_found', undefined, {
|
|
916
|
+
requested_task_id: taskId,
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
if (task.status !== 'in-progress') {
|
|
920
|
+
throw new TodoStoreError('TASK_START_BINDING_UNSUPPORTED', 'rebind_requires_in_progress', undefined, {
|
|
921
|
+
task_id: taskId, status: task.status,
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
let noteContext;
|
|
925
|
+
try {
|
|
926
|
+
({ context: noteContext } = await readTodoNoteContext({ repoRoot, store, planKey, taskId }));
|
|
927
|
+
} catch (error) {
|
|
928
|
+
if (!['NOTE_LOG_CORRUPT', 'NOTE_PROJECTION_INVALID'].includes(error?.code)) throw error;
|
|
929
|
+
noteContext = {
|
|
930
|
+
schema: 'lattice.todo_note_context.unreadable.v1',
|
|
931
|
+
project_id: member.plan.project_id,
|
|
932
|
+
plan_key: planKey,
|
|
933
|
+
task_id: taskId,
|
|
934
|
+
code: error.code,
|
|
935
|
+
reason: error.detail?.reason ?? 'note_context_unreadable',
|
|
936
|
+
next_action: `lattice todo note list --plan ${planKey} --json`,
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
return mutate({
|
|
940
|
+
repoRoot, env, planKey, taskId, kind: 'start',
|
|
941
|
+
payload: { start_mode: 'rebind', reason }, evidenceRef: null, noteContext,
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
|
|
904
945
|
async function retractStart({ repoRoot, env, planKey, taskId, reason }) {
|
|
905
946
|
const actor = mutationActor(env);
|
|
906
947
|
const store = await readTodoStore({ repoRoot });
|
|
@@ -3970,11 +4011,18 @@ export async function runTodoCli({ argv, cwd, stdout, stderr, env = process.env
|
|
|
3970
4011
|
action = (repoRoot) => phaseBaseline({ repoRoot, env, reason: argv[3], exceptPlanKeys });
|
|
3971
4012
|
} else if (argv[0] === 'start') {
|
|
3972
4013
|
const flags = matchFlagCommand(argv, ['start'], {
|
|
3973
|
-
known: ['plan', 'task', 'parallel-frontier', 'override-reason', 'serial-confirmed'],
|
|
4014
|
+
known: ['plan', 'task', 'parallel-frontier', 'override-reason', 'serial-confirmed', 'rebind', 'reason'],
|
|
3974
4015
|
required: ['plan', 'task'],
|
|
3975
|
-
booleans: ['parallel-frontier', 'serial-confirmed'],
|
|
4016
|
+
booleans: ['parallel-frontier', 'serial-confirmed', 'rebind'],
|
|
3976
4017
|
});
|
|
3977
|
-
if (flags !== null &&
|
|
4018
|
+
if (flags !== null && flags.rebind === true) {
|
|
4019
|
+
if (isTodoIdentifier(flags.plan) && isTodoIdentifier(flags.task)
|
|
4020
|
+
&& typeof flags.reason === 'string' && flags.reason.length > 0) {
|
|
4021
|
+
action = (repoRoot) => rebindStart({
|
|
4022
|
+
repoRoot, env, planKey: flags.plan, taskId: flags.task, reason: flags.reason,
|
|
4023
|
+
});
|
|
4024
|
+
}
|
|
4025
|
+
} else if (flags !== null && isTodoIdentifier(flags.plan) && isTodoIdentifier(flags.task)
|
|
3978
4026
|
&& (flags['override-reason'] === undefined || (typeof flags['override-reason'] === 'string'
|
|
3979
4027
|
&& flags['override-reason'].length > 0))) {
|
|
3980
4028
|
action = (repoRoot) => startTask({
|
package/src/todo-contracts.mjs
CHANGED
|
@@ -532,6 +532,12 @@ function validPayload(event) {
|
|
|
532
532
|
&& isTodoDigest(payload.target_event_digest)
|
|
533
533
|
&& nullableText(payload.reason) && payload.reason !== null;
|
|
534
534
|
}
|
|
535
|
+
// rebind: plan改訂でcarryされたin-progress ToDoへ、現plan_versionの明示的start束縛を積み直す
|
|
536
|
+
// (runtime intakeはliteral startだけを束縛に使い、carryを推定しない。ADR 0191)
|
|
537
|
+
if (event.kind === 'start' && payload?.start_mode === 'rebind') {
|
|
538
|
+
return exactRecord(payload, ['start_mode', 'reason'])
|
|
539
|
+
&& nullableText(payload.reason) && payload.reason !== null;
|
|
540
|
+
}
|
|
535
541
|
if (event.kind === 'start') return exactRecord(payload, ['override_reason']) && nullableText(payload.override_reason);
|
|
536
542
|
if (event.kind === 'start_retracted') return exactRecord(payload, ['reason', 'target_start_digest'])
|
|
537
543
|
&& nullableText(payload.reason) && payload.reason !== null
|
package/src/todo-store.mjs
CHANGED
|
@@ -678,6 +678,17 @@ function replay(plan, events, { now = new Date(), verifyEvidence, verifyImportSo
|
|
|
678
678
|
if (state === undefined) fail('STORE_INCONSISTENT', 'event_task_missing');
|
|
679
679
|
const dependenciesDone = localPredecessors(plan, event.task_id).every((id) => states.get(id)?.status === 'done');
|
|
680
680
|
if (event.kind === 'start') {
|
|
681
|
+
if (event.payload.start_mode === 'rebind') {
|
|
682
|
+
// 改訂でcarryされたin-progressの再束縛。状態・開始時刻は動かさず、start束縛だけを
|
|
683
|
+
// 現actor・現plan_versionのeventへ更新する(ADR 0191)
|
|
684
|
+
if (state.status !== 'in-progress') {
|
|
685
|
+
fail('STORE_INCONSISTENT', 'invalid_rebind_start_transition');
|
|
686
|
+
}
|
|
687
|
+
authoredStartBindings.set(event.task_id, {
|
|
688
|
+
actor: structuredClone(event.actor), event_digest: event.event_digest,
|
|
689
|
+
});
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
681
692
|
if (event.payload.start_mode === 'historical_import') {
|
|
682
693
|
if (!importedGenesis || state.status !== 'pending') {
|
|
683
694
|
fail('STORE_INCONSISTENT', 'invalid_historical_import_start_transition');
|
|
@@ -1125,6 +1136,7 @@ function validateMergedTransition(store, member, event) {
|
|
|
1125
1136
|
const phaseAcceptReady = mergedPhaseAcceptReady(store, targetKey);
|
|
1126
1137
|
const dependenciesDone = taskDependenciesDone && phaseAcceptReady;
|
|
1127
1138
|
if (event.kind === 'start' && event.payload.start_mode !== 'historical_import'
|
|
1139
|
+
&& event.payload.start_mode !== 'rebind'
|
|
1128
1140
|
&& (!phaseAcceptReady || (!taskDependenciesDone && event.payload.override_reason === null))) {
|
|
1129
1141
|
fail('STORE_INCONSISTENT', 'invalid_start_transition');
|
|
1130
1142
|
}
|