@fitlab-ai/agent-infra 0.11.3 → 0.11.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/README.md +17 -8
- package/README.zh-CN.md +17 -8
- package/dist/bin/internal-cli.js +1 -1
- package/dist/lib/internal/cli-route-inventory.js +1 -1
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-finalization.js +41 -1
- package/dist/lib/internal/task-ledger.js +13 -5
- package/dist/lib/internal/task-operation-registry.js +1 -0
- package/dist/lib/platform/completion-backfill.js +63 -17
- package/dist/lib/sandbox/control/server.js +26 -143
- package/dist/lib/sandbox/task-cleanup.js +13 -20
- package/dist/lib/task/artifact-command.js +11 -4
- package/dist/lib/task/artifact-lifecycle.js +217 -85
- package/dist/lib/task/artifact-operations.js +1 -26
- package/dist/lib/task/artifact-receipts.js +4 -1
- package/dist/lib/task/artifact-schema.js +1 -0
- package/dist/lib/task/artifact-selection.js +25 -0
- package/dist/lib/task/capabilities.js +158 -39
- package/dist/lib/task/commands/status.js +9 -2
- package/dist/lib/task/control-authority.js +3 -2
- package/dist/lib/task/decision-intents.js +12 -0
- package/dist/lib/task/delivery.js +1 -43
- package/dist/lib/task/events.js +80 -64
- package/dist/lib/task/finalization.js +301 -143
- package/dist/lib/task/ledger-intents.js +157 -15
- package/dist/lib/task/lifecycle-path.js +75 -0
- package/dist/lib/task/lifecycle.js +10 -0
- package/dist/lib/task/local-artifact-finalization.js +1 -20
- package/dist/lib/task/orchestration.js +17 -7
- package/dist/lib/task/review-finalization.js +3 -16
- package/dist/lib/task/rework-intent.js +70 -4
- package/dist/lib/task/verification-engine.js +20 -30
- package/dist/lib/task/verification.js +1 -0
- package/dist/lib/task/workflow-warning-intents.js +21 -6
- package/dist/lib/task/workspace-snapshot.js +7 -2
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/internal/cli-route-inventory.ts +1 -1
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-finalization.ts +40 -1
- package/lib/internal/task-ledger.ts +12 -5
- package/lib/internal/task-operation-registry.ts +1 -0
- package/lib/platform/completion-backfill.ts +78 -16
- package/lib/sandbox/control/server.ts +21 -146
- package/lib/sandbox/task-cleanup.ts +12 -20
- package/lib/task/artifact-command.ts +14 -4
- package/lib/task/artifact-lifecycle.ts +236 -85
- package/lib/task/artifact-operations.ts +1 -26
- package/lib/task/artifact-receipts.ts +4 -1
- package/lib/task/artifact-schema.ts +1 -0
- package/lib/task/artifact-selection.ts +53 -0
- package/lib/task/capabilities.ts +154 -40
- package/lib/task/commands/status.ts +11 -2
- package/lib/task/control-authority.ts +3 -1
- package/lib/task/decision-intents.ts +9 -0
- package/lib/task/delivery.ts +1 -40
- package/lib/task/events.ts +82 -64
- package/lib/task/finalization.ts +269 -111
- package/lib/task/ledger-intents.ts +155 -15
- package/lib/task/lifecycle-path.ts +98 -0
- package/lib/task/lifecycle.ts +13 -0
- package/lib/task/local-artifact-finalization.ts +2 -25
- package/lib/task/orchestration.ts +26 -8
- package/lib/task/review-finalization.ts +3 -16
- package/lib/task/rework-intent.ts +75 -5
- package/lib/task/verification-engine.ts +19 -30
- package/lib/task/verification.ts +2 -1
- package/lib/task/workflow-warning-intents.ts +18 -6
- package/lib/task/workspace-snapshot.ts +3 -2
- package/package.json +1 -1
- package/templates/.agents/rules/review-handshake.en.md +4 -4
- package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
- package/templates/.agents/skills/analyze-task/SKILL.en.md +11 -4
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -4
- package/templates/.agents/skills/code-task/SKILL.en.md +14 -8
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +18 -13
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +2 -2
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +4 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +4 -4
- package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +13 -10
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +13 -10
- package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +18 -2
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +11 -6
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +11 -6
- package/templates/.agents/workflows/feature-development.en.yaml +11 -6
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +11 -6
- package/templates/.agents/workflows/refactoring.en.yaml +11 -6
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +11 -6
- package/dist/lib/sandbox/control/finalization-response.js +0 -33
- package/lib/sandbox/control/finalization-response.ts +0 -35
package/dist/lib/task/events.js
CHANGED
|
@@ -18,15 +18,16 @@ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-
|
|
|
18
18
|
import { captureTaskWriteMetadata, writeTask } from './write.js';
|
|
19
19
|
import { allowsManualOverride } from './guard-override.js';
|
|
20
20
|
import { validateLocalArtifact } from './local-artifact-finalization.js';
|
|
21
|
-
import { buildLifecycleFacts, canStart } from './capabilities.js';
|
|
21
|
+
import { buildLifecycleFacts, canStart, effectiveReworkTarget } from './capabilities.js';
|
|
22
22
|
import { createInvalidationOperation, invalidationMutation, parseInvalidationDocument, targetIdFor, upsertInvalidation } from './invalidation.js';
|
|
23
23
|
import { reconcileTaskInvalidation } from './invalidation-command.js';
|
|
24
24
|
import { consumeReworkIntents, parseReworkIntentDocument, reworkIntentMutation, supersedeReworkIntents } from './rework-intent.js';
|
|
25
|
-
import { ARTIFACT_FAMILIES,
|
|
25
|
+
import { ARTIFACT_FAMILIES, parseQualificationAudit, parseTaskQualification, upstreamArtifactDigest } from './qualification-audit.js';
|
|
26
26
|
import { getArtifactSchema } from './artifact-schema.js';
|
|
27
27
|
import { canonicalSemanticDigest, inspectArtifactContract } from './artifact-operations.js';
|
|
28
28
|
import { consumeLifecycleRecoveryAttestation, lifecycleRecoveryAttestationDigest, validateLifecycleRecoveryAttestation } from './control-authority.js';
|
|
29
29
|
import { readManualValidationCompletion } from './manual-validation-completion.js';
|
|
30
|
+
import { parseLifecyclePathDecision } from './lifecycle-path.js';
|
|
30
31
|
const eventCatalog = [
|
|
31
32
|
'analyze.started', 'analyze.awaiting-input', 'analyze.completed',
|
|
32
33
|
'review-analysis.started', 'review-analysis.completed',
|
|
@@ -37,21 +38,46 @@ const eventCatalog = [
|
|
|
37
38
|
'manual-validation.started', 'manual-validation.completed',
|
|
38
39
|
'validation-run.started', 'validation-run.completed'
|
|
39
40
|
];
|
|
40
|
-
function
|
|
41
|
+
function branchWorktree(repoRoot, branch) {
|
|
42
|
+
if (!branch)
|
|
43
|
+
return repoRoot;
|
|
44
|
+
try {
|
|
45
|
+
const records = execFileSync('git', ['worktree', 'list', '--porcelain'], {
|
|
46
|
+
cwd: repoRoot,
|
|
47
|
+
encoding: 'utf8',
|
|
48
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
49
|
+
}).trim().split(/\r?\n\r?\n/);
|
|
50
|
+
const expectedRef = `refs/heads/${branch}`;
|
|
51
|
+
for (const record of records) {
|
|
52
|
+
const worktree = /^worktree (.+)$/m.exec(record)?.[1];
|
|
53
|
+
const branchRef = /^branch (.+)$/m.exec(record)?.[1];
|
|
54
|
+
if (worktree && branchRef === expectedRef)
|
|
55
|
+
return worktree;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// A missing worktree must not anchor a review to an unrelated repository.
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
function approvedCleanReviewedCommit(reviewContent, verdict, repoRoot, branch) {
|
|
41
64
|
if (verdict !== 'approved')
|
|
42
65
|
return null;
|
|
43
66
|
const reviewedHead = extractReviewedHead(reviewContent) || extractReviewBaseline(reviewContent);
|
|
44
67
|
const reviewedTree = extractReviewedSnapshotTree(reviewContent);
|
|
45
68
|
if (!/^[a-f0-9]{40}$/.test(reviewedHead) || !/^[a-f0-9]{40}$/.test(reviewedTree))
|
|
46
69
|
return null;
|
|
70
|
+
const worktree = branchWorktree(repoRoot, branch);
|
|
71
|
+
if (!worktree)
|
|
72
|
+
return null;
|
|
47
73
|
try {
|
|
48
|
-
const currentHead = execFileSync('git', ['-C',
|
|
74
|
+
const currentHead = execFileSync('git', ['-C', worktree, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).trim();
|
|
49
75
|
if (currentHead !== reviewedHead)
|
|
50
76
|
return null;
|
|
51
|
-
const currentTree = execFileSync('git', ['-C',
|
|
77
|
+
const currentTree = execFileSync('git', ['-C', worktree, 'rev-parse', 'HEAD^{tree}'], { encoding: 'utf8' }).trim();
|
|
52
78
|
if (currentTree !== reviewedTree)
|
|
53
79
|
return null;
|
|
54
|
-
execFileSync('git', ['-C',
|
|
80
|
+
execFileSync('git', ['-C', worktree, 'diff-index', '--quiet', 'HEAD', '--']);
|
|
55
81
|
return reviewedHead;
|
|
56
82
|
}
|
|
57
83
|
catch {
|
|
@@ -283,7 +309,13 @@ function failed(request, error, extra = {}) {
|
|
|
283
309
|
}
|
|
284
310
|
function normalizeStarted(request, repoRoot) {
|
|
285
311
|
const family = eventParts(request.event).family;
|
|
286
|
-
const context = resolveArtifactContext(request.taskRef, FAMILY[family].artifact, {
|
|
312
|
+
const context = resolveArtifactContext(request.taskRef, FAMILY[family].artifact, {
|
|
313
|
+
repoRoot,
|
|
314
|
+
reasonCode: request.reasonCode,
|
|
315
|
+
sourceFinding: request.sourceFinding,
|
|
316
|
+
sourceArtifact: request.sourceArtifact,
|
|
317
|
+
sourceSha256: request.sourceSha256
|
|
318
|
+
});
|
|
287
319
|
if (context.status !== 'ready' || !context.next) {
|
|
288
320
|
return { error: { code: context.error?.code ?? 'EVENT_ARTIFACT_CONFLICT', message: context.error?.message ?? context.codeMode?.message ?? 'artifact context is not writable' }, context };
|
|
289
321
|
}
|
|
@@ -337,24 +369,6 @@ function openStartedIdentity(rows, family) {
|
|
|
337
369
|
function reviewInputFamily(family) {
|
|
338
370
|
return family === 'review-analysis' ? 'analysis' : family === 'review-plan' ? 'plan' : 'code';
|
|
339
371
|
}
|
|
340
|
-
function relationForStartedInput(family, input) {
|
|
341
|
-
if (family.startsWith('review-')) {
|
|
342
|
-
return input.family === reviewInputFamily(family) ? 'reviewed-input' : 'approval-context';
|
|
343
|
-
}
|
|
344
|
-
const consumer = family === 'analyze' ? 'analysis' : family;
|
|
345
|
-
if ((consumer === 'plan' && input.family === 'analysis') || (consumer === 'code' && input.family === 'plan'))
|
|
346
|
-
return 'required-input';
|
|
347
|
-
return 'review-context';
|
|
348
|
-
}
|
|
349
|
-
function qualificationRelationsForStarted(family, inputs) {
|
|
350
|
-
return inputs.map((input) => ({
|
|
351
|
-
upstreamFamily: input.family,
|
|
352
|
-
upstreamArtifact: input.name,
|
|
353
|
-
upstreamRound: input.round,
|
|
354
|
-
upstreamSha256: sha256File(input.path),
|
|
355
|
-
relation: relationForStartedInput(family, input)
|
|
356
|
-
}));
|
|
357
|
-
}
|
|
358
372
|
function lifecycleAction(family) {
|
|
359
373
|
return family === 'analyze' ? 'analysis' : family;
|
|
360
374
|
}
|
|
@@ -555,7 +569,21 @@ function reworkIntentMutationForCompletion(content, taskDir, family, artifact, t
|
|
|
555
569
|
return [];
|
|
556
570
|
}
|
|
557
571
|
}));
|
|
558
|
-
|
|
572
|
+
const action = family === 'analyze' ? 'analysis' : family;
|
|
573
|
+
let target = action;
|
|
574
|
+
if (family === 'analyze') {
|
|
575
|
+
const previousAnalysis = fs.readdirSync(taskDir)
|
|
576
|
+
.map((name) => parseArtifactName(name))
|
|
577
|
+
.filter((identity) => identity?.family === 'analysis' && identity.name !== artifact.name)
|
|
578
|
+
.sort((left, right) => right.round - left.round || left.name.localeCompare(right.name))[0];
|
|
579
|
+
const pathState = previousAnalysis
|
|
580
|
+
? parseLifecyclePathDecision(fs.readFileSync(path.join(taskDir, previousAnalysis.name), 'utf8'))
|
|
581
|
+
: undefined;
|
|
582
|
+
const pending = next.find((intent) => intent.status === 'pending');
|
|
583
|
+
if (pending && effectiveReworkTarget(pending.target, pathState) === action)
|
|
584
|
+
target = pending.target;
|
|
585
|
+
}
|
|
586
|
+
next = consumeReworkIntents(next, target, hashes, timestamp).intents;
|
|
559
587
|
}
|
|
560
588
|
if (family === 'review-analysis' || family === 'review-plan' || family === 'review-code') {
|
|
561
589
|
next = supersedeReworkIntents(next, artifact.name, hash, timestamp).intents;
|
|
@@ -577,13 +605,16 @@ function buildCompletionReceipt(content, taskDir, family, artifact, completedAt,
|
|
|
577
605
|
const startedSha256 = typeof frontmatter.code_input_sha256 === 'string'
|
|
578
606
|
? frontmatter.code_input_sha256 : existing?.inputSha256 ?? '';
|
|
579
607
|
if (!startedInput || !startedSha256)
|
|
580
|
-
return { ok: false, message: 'code.started
|
|
581
|
-
const
|
|
582
|
-
if (
|
|
583
|
-
return { ok: false, message: `code input '${startedInput}'
|
|
608
|
+
return { ok: false, message: 'code.started lifecycle input context is missing' };
|
|
609
|
+
const inputIdentity = parseArtifactName(startedInput);
|
|
610
|
+
if (!inputIdentity || !['analysis', 'plan'].includes(inputIdentity.family))
|
|
611
|
+
return { ok: false, message: `code input '${startedInput}' has an invalid family` };
|
|
612
|
+
const lifecycleInput = inspectArtifactDirectory(taskDir, inputIdentity.family);
|
|
613
|
+
if (lifecycleInput.status !== 'ready' || !lifecycleInput.latest || lifecycleInput.latest.name !== startedInput) {
|
|
614
|
+
return { ok: false, message: `code input '${startedInput}' is not the latest ${inputIdentity.family} artifact` };
|
|
584
615
|
}
|
|
585
616
|
try {
|
|
586
|
-
const inputSha256 = sha256File(
|
|
617
|
+
const inputSha256 = sha256File(lifecycleInput.latest.path);
|
|
587
618
|
if (inputSha256 !== startedSha256)
|
|
588
619
|
return { ok: false, message: `code input ${startedInput} changed after code.started` };
|
|
589
620
|
return {
|
|
@@ -595,7 +626,7 @@ function buildCompletionReceipt(content, taskDir, family, artifact, completedAt,
|
|
|
595
626
|
};
|
|
596
627
|
}
|
|
597
628
|
catch (error) {
|
|
598
|
-
return { ok: false, message: `cannot hash code input
|
|
629
|
+
return { ok: false, message: `cannot hash code lifecycle input: ${error instanceof Error ? error.message : String(error)}` };
|
|
599
630
|
}
|
|
600
631
|
}
|
|
601
632
|
if (!family.startsWith('review-'))
|
|
@@ -753,6 +784,12 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
753
784
|
normalized = { ...request, round: openIdentity.round, artifact: artifactName(FAMILY[initialParts.family].artifact, openIdentity.round), fixFor: openIdentity.fixFor, implementationInput: openIdentity.implementationInput };
|
|
754
785
|
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, typeof frontmatter.current_step === 'string' ? frontmatter.current_step : '', identity(normalized), openIdentity.row.started, frontmatter, null);
|
|
755
786
|
}
|
|
787
|
+
if (rows.some((item) => item.started && !item.done)) {
|
|
788
|
+
return failed(request, {
|
|
789
|
+
code: 'EVENT_TRANSITION_INVALID',
|
|
790
|
+
message: 'EXECUTION_BUSY: another lifecycle execution is open'
|
|
791
|
+
}, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
792
|
+
}
|
|
756
793
|
const result = normalizeStarted(request, resolved.repoRoot);
|
|
757
794
|
artifactContext = result.context;
|
|
758
795
|
if ('error' in result)
|
|
@@ -822,25 +859,13 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
822
859
|
reviewContent = fs.readFileSync(completedArtifact.path, 'utf8');
|
|
823
860
|
}
|
|
824
861
|
catch (error) {
|
|
825
|
-
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot read
|
|
862
|
+
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot read ${completedArtifact.name}: ${error instanceof Error ? error.message : String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
826
863
|
}
|
|
827
864
|
const schema = getArtifactSchema(eventIdentity.family);
|
|
828
865
|
const structure = schema ? inspectArtifactContract(reviewContent, schema) : null;
|
|
829
866
|
if (structure && !structure.ok) {
|
|
830
867
|
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `shared artifact structure invalid: ${structure.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
831
868
|
}
|
|
832
|
-
const expected = expectedQualificationRelations(content, eventIdentity.family);
|
|
833
|
-
if (!expected.ok) {
|
|
834
|
-
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `${expected.code}: ${expected.message}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
835
|
-
}
|
|
836
|
-
const qualification = validateQualificationAudit(content, reviewContent, {
|
|
837
|
-
family: eventIdentity.family,
|
|
838
|
-
artifact: completedArtifact.name,
|
|
839
|
-
expectedUpstreamRelations: expected.relations
|
|
840
|
-
});
|
|
841
|
-
if (!qualification.ok) {
|
|
842
|
-
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `${qualification.code}: ${qualification.message}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
843
|
-
}
|
|
844
869
|
}
|
|
845
870
|
if (eventIdentity.family === 'analyze' || eventIdentity.family === 'plan' || eventIdentity.family === 'code') {
|
|
846
871
|
const localFamily = eventIdentity.family === 'analyze'
|
|
@@ -854,9 +879,7 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
854
879
|
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot read ${completedArtifact.name}: ${String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
855
880
|
}
|
|
856
881
|
const local = validateLocalArtifact(artifactContent, {
|
|
857
|
-
family: localFamily
|
|
858
|
-
taskContent: content,
|
|
859
|
-
artifact: completedArtifact.name
|
|
882
|
+
family: localFamily
|
|
860
883
|
});
|
|
861
884
|
if (!local.ok) {
|
|
862
885
|
return failed(normalized, {
|
|
@@ -892,7 +915,9 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
892
915
|
const capabilityOverride = capability.reasonCode === 'TASK_NOT_ACTIVE'
|
|
893
916
|
? stateOverride
|
|
894
917
|
: allowsManualOverride(options.manualOverride, 'task-event', 'EVENT_TRANSITION_INVALID');
|
|
895
|
-
|
|
918
|
+
const safetyFailure = capability.reasonCode === 'TASK_NOT_ACTIVE'
|
|
919
|
+
|| capability.reasonCode === 'LIFECYCLE_EXECUTION_OPEN';
|
|
920
|
+
if (!capability.allowed && (normalized.initiator === 'orchestrator' || safetyFailure) && !capabilityOverride) {
|
|
896
921
|
const code = capability.reasonCode === 'INVALIDATION_INCOMPLETE' ? 'TASK_INVALIDATION_BLOCKED' : 'EVENT_TRANSITION_INVALID';
|
|
897
922
|
return failed(normalized, { code, message: `${capability.reasonCode}: ${capability.evidence.join(', ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
898
923
|
}
|
|
@@ -901,10 +926,11 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
901
926
|
if (findingCountError)
|
|
902
927
|
return failed(normalized, findingCountError, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
903
928
|
let orchestrationCompletion = null;
|
|
904
|
-
if (eventIdentity.phase === 'completed' &&
|
|
929
|
+
if (eventIdentity.phase === 'completed' && normalized.orchestrated
|
|
930
|
+
&& eventIdentity.family !== 'manual-validation' && eventIdentity.family !== 'validation-run') {
|
|
905
931
|
const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
|
|
906
932
|
const execution = validateLifecycleExecution(normalized.taskRef, {
|
|
907
|
-
mode:
|
|
933
|
+
mode: 'orchestrated',
|
|
908
934
|
identity: {
|
|
909
935
|
stage: orchestrationStage,
|
|
910
936
|
round: normalized.round,
|
|
@@ -969,18 +995,10 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
969
995
|
if (currentFact)
|
|
970
996
|
frontmatterSet.completion_facts = JSON.stringify(replaceCompletionFact(completionFacts(frontmatter), currentFact));
|
|
971
997
|
let frontmatterRemove;
|
|
972
|
-
if (eventIdentity.phase === 'started' && artifactContext) {
|
|
973
|
-
try {
|
|
974
|
-
frontmatterSet.qualification_input_relations = JSON.stringify(qualificationRelationsForStarted(eventIdentity.family, artifactContext.inputs));
|
|
975
|
-
}
|
|
976
|
-
catch (error) {
|
|
977
|
-
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot capture qualification input relations: ${error instanceof Error ? error.message : String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
998
|
if (eventIdentity.phase === 'started' && eventIdentity.family === 'code') {
|
|
981
|
-
const planInput = artifactContext?.inputs.find((input) => input.family === 'plan');
|
|
999
|
+
const planInput = artifactContext?.inputs.find((input) => input.family === 'plan' || input.family === 'analysis');
|
|
982
1000
|
if (!planInput)
|
|
983
|
-
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: 'code.started
|
|
1001
|
+
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: 'code.started lifecycle input context is unavailable' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
|
|
984
1002
|
try {
|
|
985
1003
|
frontmatterSet.code_input_artifact = planInput.name;
|
|
986
1004
|
frontmatterSet.code_input_sha256 = sha256File(planInput.path);
|
|
@@ -1009,14 +1027,12 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
1009
1027
|
frontmatterRemove = ['review_input_artifact', 'review_input_sha256'];
|
|
1010
1028
|
}
|
|
1011
1029
|
if (eventIdentity.phase === 'completed' && eventIdentity.family === 'review-code' && reviewContent !== null) {
|
|
1012
|
-
const reviewedCommit = approvedCleanReviewedCommit(reviewContent, normalized.verdict, resolved.repoRoot);
|
|
1030
|
+
const reviewedCommit = approvedCleanReviewedCommit(reviewContent, normalized.verdict, resolved.repoRoot, typeof frontmatter.branch === 'string' ? frontmatter.branch : '');
|
|
1013
1031
|
if (reviewedCommit)
|
|
1014
1032
|
frontmatterSet.last_reviewed_commit = reviewedCommit;
|
|
1015
1033
|
else if (normalized.verdict === 'approved')
|
|
1016
1034
|
frontmatterSet.last_reviewed_commit = '';
|
|
1017
1035
|
}
|
|
1018
|
-
if (eventIdentity.phase === 'completed')
|
|
1019
|
-
frontmatterRemove = [...(frontmatterRemove ?? []), 'qualification_input_relations'];
|
|
1020
1036
|
if (eventIdentity.phase === 'started' && normalized.implementationInput)
|
|
1021
1037
|
frontmatterSet.last_reviewed_commit = '';
|
|
1022
1038
|
const mutations = [
|