@fitlab-ai/agent-infra 0.11.12 → 0.11.14

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.
Files changed (120) hide show
  1. package/dist/bin/internal-cli.js +2 -7
  2. package/dist/lib/agent-clients/adapter.js +0 -3
  3. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +5 -9
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +1 -5
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +1 -5
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +11 -25
  7. package/dist/lib/agent-clients/adapters/codex-orchestration.js +1 -3
  8. package/dist/lib/agent-clients/adapters/codex.js +0 -2
  9. package/dist/lib/internal/cli-route-inventory.js +0 -1
  10. package/dist/lib/internal/sandbox-control.js +1 -81
  11. package/dist/lib/internal/task-finalization.js +29 -20
  12. package/dist/lib/internal/task-lifecycle.js +4 -2
  13. package/dist/lib/internal/task-operation-registry.js +1 -3
  14. package/dist/lib/internal/task-validate.js +14 -124
  15. package/dist/lib/platform/github-client.js +33 -3
  16. package/dist/lib/platform/release-notes.js +2 -2
  17. package/dist/lib/sandbox/commands/control-status.js +0 -1
  18. package/dist/lib/sandbox/commands/create.js +11 -6
  19. package/dist/lib/sandbox/commands/ls.js +4 -5
  20. package/dist/lib/sandbox/commands/rm.js +1 -1
  21. package/dist/lib/sandbox/config.js +12 -0
  22. package/dist/lib/sandbox/control/audit.js +1 -2
  23. package/dist/lib/sandbox/control/client.js +15 -110
  24. package/dist/lib/sandbox/control/executor.js +9 -59
  25. package/dist/lib/sandbox/control/host-recovery.js +89 -27
  26. package/dist/lib/sandbox/control/lifecycle.js +75 -9
  27. package/dist/lib/sandbox/control/protocol.js +11 -50
  28. package/dist/lib/sandbox/control/server.js +203 -253
  29. package/dist/lib/sandbox/control/task-view.js +0 -13
  30. package/dist/lib/sandbox/environment.js +7 -8
  31. package/dist/lib/sandbox/mounts.js +71 -52
  32. package/dist/lib/sandbox/recovery.js +30 -12
  33. package/dist/lib/sandbox/removal.js +37 -3
  34. package/dist/lib/sandbox/workspace-identity.js +18 -6
  35. package/dist/lib/sandbox/workspace-view.js +89 -6
  36. package/dist/lib/task/commands/ls.js +3 -3
  37. package/dist/lib/task/control-authority.js +41 -17
  38. package/dist/lib/task/control-recovery.js +2 -4
  39. package/dist/lib/task/finalization.js +27 -2
  40. package/dist/lib/task/lifecycle.js +294 -63
  41. package/dist/lib/task/orchestration.js +26 -72
  42. package/dist/lib/task/short-id.js +37 -27
  43. package/dist/lib/task/verification-engine.js +4 -11
  44. package/dist/lifecycle-build-manifest.json +3 -3
  45. package/lib/agent-clients/adapter.ts +0 -27
  46. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +6 -12
  47. package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +1 -5
  48. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -7
  49. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +1 -5
  50. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +21 -27
  51. package/lib/agent-clients/adapters/codex-orchestration.ts +1 -3
  52. package/lib/agent-clients/adapters/codex.ts +0 -2
  53. package/lib/internal/cli-route-inventory.ts +0 -1
  54. package/lib/internal/sandbox-control.ts +0 -97
  55. package/lib/internal/task-finalization.ts +33 -19
  56. package/lib/internal/task-lifecycle.ts +4 -2
  57. package/lib/internal/task-operation-registry.ts +1 -3
  58. package/lib/internal/task-validate.ts +13 -127
  59. package/lib/platform/github-client.ts +34 -3
  60. package/lib/platform/release-notes.ts +2 -2
  61. package/lib/sandbox/commands/control-status.ts +0 -1
  62. package/lib/sandbox/commands/create.ts +11 -5
  63. package/lib/sandbox/commands/ls.ts +4 -5
  64. package/lib/sandbox/commands/rm.ts +1 -1
  65. package/lib/sandbox/config.ts +13 -0
  66. package/lib/sandbox/control/audit.ts +1 -2
  67. package/lib/sandbox/control/client.ts +17 -138
  68. package/lib/sandbox/control/executor.ts +8 -65
  69. package/lib/sandbox/control/host-recovery.ts +94 -21
  70. package/lib/sandbox/control/lifecycle.ts +75 -10
  71. package/lib/sandbox/control/protocol.ts +12 -62
  72. package/lib/sandbox/control/server.ts +11 -61
  73. package/lib/sandbox/control/task-view.ts +0 -19
  74. package/lib/sandbox/environment.ts +7 -8
  75. package/lib/sandbox/mounts.ts +93 -68
  76. package/lib/sandbox/recovery.ts +37 -19
  77. package/lib/sandbox/removal.ts +36 -5
  78. package/lib/sandbox/workspace-identity.ts +16 -6
  79. package/lib/sandbox/workspace-view.ts +81 -7
  80. package/lib/task/commands/ls.ts +3 -3
  81. package/lib/task/control-authority.ts +41 -26
  82. package/lib/task/control-recovery.ts +3 -5
  83. package/lib/task/finalization.ts +29 -2
  84. package/lib/task/lifecycle.ts +282 -57
  85. package/lib/task/orchestration.ts +30 -68
  86. package/lib/task/short-id.ts +33 -40
  87. package/lib/task/verification-engine.ts +3 -9
  88. package/package.json +1 -1
  89. package/templates/.agents/rules/README.en.md +1 -0
  90. package/templates/.agents/rules/README.zh-CN.md +1 -0
  91. package/templates/.agents/rules/lifecycle-orchestration.en.md +3 -4
  92. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +3 -4
  93. package/templates/.agents/rules/strategy-pattern.en.md +25 -0
  94. package/templates/.agents/rules/strategy-pattern.zh-CN.md +25 -0
  95. package/templates/.agents/rules/task-short-id.en.md +18 -12
  96. package/templates/.agents/rules/task-short-id.zh-CN.md +12 -7
  97. package/templates/.agents/skills/code-task/reference/code-rules.en.md +4 -0
  98. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +4 -0
  99. package/templates/.agents/skills/complete-task/SKILL.en.md +5 -26
  100. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +5 -23
  101. package/templates/.agents/skills/create-release-note/SKILL.en.md +3 -1
  102. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +3 -1
  103. package/templates/.agents/skills/plan-task/SKILL.en.md +7 -4
  104. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +7 -4
  105. package/templates/.agents/skills/run-task/SKILL.en.md +2 -2
  106. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +2 -2
  107. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-client.js +0 -130
  108. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +0 -127
  109. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-operation.js +0 -131
  110. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-registration.js +0 -275
  111. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js +0 -106
  112. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +0 -345
  113. package/dist/lib/sandbox/control/agent-operation.js +0 -34
  114. package/lib/agent-clients/adapters/codex-lifecycle/controller-client.ts +0 -158
  115. package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +0 -163
  116. package/lib/agent-clients/adapters/codex-lifecycle/controller-operation.ts +0 -151
  117. package/lib/agent-clients/adapters/codex-lifecycle/controller-registration.ts +0 -352
  118. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.ts +0 -109
  119. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +0 -437
  120. package/lib/sandbox/control/agent-operation.ts +0 -49
@@ -18,49 +18,15 @@ import { inspectSandboxControlContainer } from './container-identity.js';
18
18
  import { acquireSandboxControlBrokerStartup, garbageCollectSandboxControlRoot, isSandboxControlRootQuiescing, readSandboxControlManifest } from './lifecycle.js';
19
19
  import { nextSandboxControlBackoff } from './timing.js';
20
20
  import { readTaskFinalizationReceipt } from '../../task/finalization.js';
21
- import { recoverAgentClientOperation, validateAgentClientOperation } from './agent-operation.js';
22
21
  import { validateSandboxControlIdentity } from './identity-sentinel.js';
23
- import { mergeSandboxTaskView, taskViewAfterFinalization, taskViewForManifest } from './task-view.js';
22
+ import { mergeSandboxTaskView, taskViewForManifest } from './task-view.js';
24
23
  import { taskCreateOutputUnavailableResult } from '../../task/create-service.js';
25
- async function taskViewForFinalizationResult(manifest, request, result) {
26
- if (request.family !== 'task-finalization' || result?.exitCode !== 0 || !manifest.taskId)
27
- return null;
28
- let receipt = null;
29
- for (let attempt = 0; attempt < 100 && !receipt; attempt += 1) {
30
- try {
31
- receipt = readTaskFinalizationReceipt(manifest.repoRoot, manifest.taskId);
32
- }
33
- catch {
34
- // A missing or temporarily moving task directory is retried before publishing completion.
35
- }
36
- if (!receipt)
37
- await new Promise((resolve) => setTimeout(resolve, 10));
38
- }
39
- const finalized = taskViewAfterFinalization({
40
- taskId: manifest.taskId,
41
- generation: manifest.generation,
42
- requestId: request.id,
43
- receipt
44
- });
45
- if (finalized.state === 'unknown')
46
- return finalized;
47
- const canonical = taskViewForManifest({ ...manifest, receipt });
48
- return canonical.state === 'current' && canonical.observedSource === 'completed'
49
- ? canonical
50
- : finalized;
51
- }
52
24
  function appendBrokerAudit(manifest, event, fields = {}) {
53
25
  appendDiagnosticAudit(manifest, event, { source: 'broker', ...fields });
54
26
  }
55
27
  function operationKey(request) {
56
- if (request.family === 'task-finalization')
57
- return request.operation;
58
28
  if (request.family === 'task-create')
59
29
  return 'create';
60
- if (request.family === 'agent-client')
61
- return request.operation;
62
- if (request.family !== 'task-lifecycle')
63
- return null;
64
30
  try {
65
31
  const operation = parseTaskControlOperation(request.family, request.args);
66
32
  return operation.family === 'task-lifecycle' ? operation.request.intent : null;
@@ -220,11 +186,9 @@ function taskCreateDomainEvidence(manifest, output) {
220
186
  async function readRecoveryDomain(manifest, manifestPath, request, operation, terminalResult, payloadOutput) {
221
187
  if (!operation)
222
188
  return { domain: null };
223
- const taskRef = request.family === 'task-finalization'
224
- ? manifest.taskId
225
- : 'args' in request ? request.args[0] ?? null : manifest.taskId;
189
+ const taskRef = 'args' in request ? request.args[0] ?? null : manifest.taskId;
226
190
  const output = parseControlOutput(payloadOutput);
227
- if (!taskRef && operation.family !== 'task-create' && operation.family !== 'agent-client') {
191
+ if (!taskRef && operation.family !== 'task-create') {
228
192
  return { domain: null };
229
193
  }
230
194
  if (operation.family === 'task-lifecycle') {
@@ -252,14 +216,6 @@ async function readRecoveryDomain(manifest, manifestPath, request, operation, te
252
216
  if (operation.family === 'task-create') {
253
217
  return { domain: taskCreateDomainEvidence(manifest, output) };
254
218
  }
255
- if (operation.family === 'agent-client' && request.family === 'agent-client') {
256
- return { domain: recoverAgentClientOperation({
257
- request,
258
- manifest,
259
- manifestPath,
260
- stdout: payloadOutput
261
- }) };
262
- }
263
219
  return { domain: null };
264
220
  }
265
221
  function readCommittedCriticalPhases(manifest, requestId) {
@@ -474,11 +430,7 @@ async function recoverProcessing(manifest, manifestPath, broker, brokerOwns) {
474
430
  let terminalReconciled = false;
475
431
  try {
476
432
  const rawRequest = JSON.parse(fs.readFileSync(path.join(processingDirectory, 'request.json'), 'utf8'));
477
- request = validateSandboxControlRequest(rawRequest, manifest, {
478
- now: typeof rawRequest.issuedAt === 'number' ? rawRequest.issuedAt : undefined
479
- });
480
- if (request.family === 'agent-client')
481
- validateAgentClientOperation(request, manifest);
433
+ request = validateSandboxControlRequest(rawRequest, manifest);
482
434
  }
483
435
  catch {
484
436
  // Missing or malformed request evidence remains fail-closed below.
@@ -730,6 +682,8 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
730
682
  try {
731
683
  if (!brokerOwns())
732
684
  return;
685
+ if (isSandboxControlRootQuiescing(root))
686
+ return;
733
687
  if (taskView.state === 'current' && taskView.observedSource === 'completed') {
734
688
  // Recheck durable re-entry evidence before publishing a trusted startup view.
735
689
  const unverified = { ...taskView, state: 'unknown',
@@ -836,11 +790,6 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
836
790
  settledExecution = active;
837
791
  active = null;
838
792
  }
839
- const finalizationView = settledExecution
840
- ? await taskViewForFinalizationResult(manifest, settledExecution.request, settledExecution.result)
841
- : null;
842
- if (finalizationView)
843
- taskView = finalizationView;
844
793
  let reasonCode = null;
845
794
  try {
846
795
  if (!brokerOwns())
@@ -918,224 +867,230 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
918
867
  fs.rmSync(path.join(manifest.processingDir, settledExecution.request.id), { recursive: true, force: true });
919
868
  }
920
869
  let retiring = false;
921
- for (const name of fs.readdirSync(requestsDir).sort()) {
922
- if (!/^[a-f0-9-]{16,64}\.json$/.test(name))
923
- continue;
924
- const id = name.slice(0, -5);
925
- const source = path.join(requestsDir, name);
926
- let claimed = null;
927
- let validatedRequest = null;
928
- let prepared = null;
929
- try {
930
- if (!brokerOwns()) {
931
- retiring = true;
932
- break;
933
- }
934
- claimed = claimRequest(manifest, source, id);
935
- appendBrokerAudit(manifest, 'request-claimed', {
936
- requestId: id,
937
- requestSourcePath: source,
938
- requestClaimedPath: claimed,
939
- requestProcessingDir: path.dirname(claimed)
940
- });
941
- if (!brokerOwns()) {
942
- retiring = true;
943
- break;
944
- }
945
- consumeRequest(consumedDir, id);
946
- if (!brokerOwns()) {
947
- retiring = true;
948
- break;
949
- }
950
- if (reasonCode)
951
- throw new Error(reasonCode);
952
- if (active)
953
- throw new Error('SANDBOX_CONTROL_BUSY');
954
- const request = validateSandboxControlRequest(JSON.parse(fs.readFileSync(claimed, 'utf8')), manifest);
955
- if (request.family === 'agent-client')
956
- validateAgentClientOperation(request, manifest);
957
- validatedRequest = request;
958
- criticalRequestPhase(manifest, request, 'validated', 'in-progress');
959
- appendBrokerAudit(manifest, 'request-validated', {
960
- ...requestAuditFields(manifest, request),
961
- requestPath: claimed
962
- });
963
- if (bindingCheck(manifest))
964
- throw new Error('SANDBOX_WORKTREE_BINDING_LOST');
965
- if (readActiveLease(manifest))
966
- throw new Error('SANDBOX_CONTROL_HANDOFF_ACTIVE');
967
- criticalRequestPhase(manifest, request, 'gated', 'in-progress');
968
- appendBrokerAudit(manifest, 'request-gates-passed', {
969
- ...requestAuditFields(manifest, request),
970
- requestPath: claimed,
971
- bindingChecked: true,
972
- handoffLeaseChecked: true
973
- });
974
- criticalRequestPhase(manifest, request, 'reserved', 'in-progress');
975
- writeSandboxControlReservation(manifest, request.id, sandboxControlGenerationUsage(manifest));
976
- appendBrokerAudit(manifest, 'executor-reservation-written', {
977
- ...requestAuditFields(manifest, request),
978
- requestPath: claimed,
979
- executionPath: executionPath(manifest, request.id)
980
- });
981
- appendBrokerAudit(manifest, 'executor-prepare-start', {
982
- ...requestAuditFields(manifest, request),
983
- requestPath: claimed,
984
- executorCwd: manifest.repoRoot,
985
- executorEntry: options.internalCliPath ?? process.argv[1] ?? null
986
- });
987
- prepared = await prepareExecution({
988
- manifest, manifestPath, request, requestPath: claimed,
989
- internalCliPath: options.internalCliPath ?? process.argv[1]
990
- });
991
- const preparedExecution = prepared;
992
- if (!preparedExecution)
993
- throw new Error('SANDBOX_CONTROL_EXECUTION_PREPARE_INVALID');
994
- criticalRequestPhase(manifest, request, 'prepared', 'in-progress', `${preparedExecution.execution.child.pid}`);
995
- appendBrokerAudit(manifest, 'executor-prepared', {
996
- ...requestAuditFields(manifest, request),
997
- requestPath: claimed,
998
- executorCwd: manifest.repoRoot,
999
- childPid: preparedExecution.execution.child.pid,
1000
- childStartTime: preparedExecution.execution.child.startTime,
1001
- childProcessGroupId: preparedExecution.execution.child.processGroupId,
1002
- executionPath: executionPath(manifest, request.id)
1003
- });
1004
- const execution = {
1005
- request, prepared: preparedExecution, result: null,
1006
- resultEvidenceWritten: false, failure: null, settled: false
1007
- };
1008
- active = execution;
1009
- preparedExecution.completion.then((result) => {
1010
- execution.result = sanitizeSandboxControlResult(manifest, result);
1011
- appendBrokerAudit(manifest, 'executor-completed', {
870
+ const quiescing = isSandboxControlRootQuiescing(root);
871
+ if (quiescing && !active)
872
+ break;
873
+ if (!quiescing)
874
+ for (const name of fs.readdirSync(requestsDir).sort()) {
875
+ if (!/^[a-f0-9-]{16,64}\.json$/.test(name))
876
+ continue;
877
+ const id = name.slice(0, -5);
878
+ const source = path.join(requestsDir, name);
879
+ let claimed = null;
880
+ let validatedRequest = null;
881
+ let prepared = null;
882
+ try {
883
+ if (isSandboxControlRootQuiescing(root)) {
884
+ retiring = true;
885
+ break;
886
+ }
887
+ if (!brokerOwns()) {
888
+ retiring = true;
889
+ break;
890
+ }
891
+ claimed = claimRequest(manifest, source, id);
892
+ appendBrokerAudit(manifest, 'request-claimed', {
893
+ requestId: id,
894
+ requestSourcePath: source,
895
+ requestClaimedPath: claimed,
896
+ requestProcessingDir: path.dirname(claimed)
897
+ });
898
+ if (!brokerOwns()) {
899
+ retiring = true;
900
+ break;
901
+ }
902
+ consumeRequest(consumedDir, id);
903
+ if (!brokerOwns()) {
904
+ retiring = true;
905
+ break;
906
+ }
907
+ if (reasonCode)
908
+ throw new Error(reasonCode);
909
+ if (active)
910
+ throw new Error('SANDBOX_CONTROL_BUSY');
911
+ const request = validateSandboxControlRequest(JSON.parse(fs.readFileSync(claimed, 'utf8')), manifest);
912
+ validatedRequest = request;
913
+ criticalRequestPhase(manifest, request, 'validated', 'in-progress');
914
+ appendBrokerAudit(manifest, 'request-validated', {
915
+ ...requestAuditFields(manifest, request),
916
+ requestPath: claimed
917
+ });
918
+ if (bindingCheck(manifest))
919
+ throw new Error('SANDBOX_WORKTREE_BINDING_LOST');
920
+ if (readActiveLease(manifest))
921
+ throw new Error('SANDBOX_CONTROL_HANDOFF_ACTIVE');
922
+ criticalRequestPhase(manifest, request, 'gated', 'in-progress');
923
+ appendBrokerAudit(manifest, 'request-gates-passed', {
924
+ ...requestAuditFields(manifest, request),
925
+ requestPath: claimed,
926
+ bindingChecked: true,
927
+ handoffLeaseChecked: true
928
+ });
929
+ criticalRequestPhase(manifest, request, 'reserved', 'in-progress');
930
+ writeSandboxControlReservation(manifest, request.id, sandboxControlGenerationUsage(manifest));
931
+ appendBrokerAudit(manifest, 'executor-reservation-written', {
932
+ ...requestAuditFields(manifest, request),
933
+ requestPath: claimed,
934
+ executionPath: executionPath(manifest, request.id)
935
+ });
936
+ appendBrokerAudit(manifest, 'executor-prepare-start', {
937
+ ...requestAuditFields(manifest, request),
938
+ requestPath: claimed,
939
+ executorCwd: manifest.repoRoot,
940
+ executorEntry: options.internalCliPath ?? process.argv[1] ?? null
941
+ });
942
+ prepared = await prepareExecution({
943
+ manifest, manifestPath, request, requestPath: claimed,
944
+ internalCliPath: options.internalCliPath ?? process.argv[1]
945
+ });
946
+ const preparedExecution = prepared;
947
+ if (!preparedExecution)
948
+ throw new Error('SANDBOX_CONTROL_EXECUTION_PREPARE_INVALID');
949
+ criticalRequestPhase(manifest, request, 'prepared', 'in-progress', `${preparedExecution.execution.child.pid}`);
950
+ appendBrokerAudit(manifest, 'executor-prepared', {
1012
951
  ...requestAuditFields(manifest, request),
1013
- ...resultAuditFields(execution.result),
952
+ requestPath: claimed,
953
+ executorCwd: manifest.repoRoot,
1014
954
  childPid: preparedExecution.execution.child.pid,
1015
- childStartTime: preparedExecution.execution.child.startTime
955
+ childStartTime: preparedExecution.execution.child.startTime,
956
+ childProcessGroupId: preparedExecution.execution.child.processGroupId,
957
+ executionPath: executionPath(manifest, request.id)
1016
958
  });
1017
- try {
1018
- writeSandboxControlResultEvidence(manifest, request.id, execution.result);
1019
- execution.resultEvidenceWritten = true;
1020
- execution.settled = true;
1021
- appendBrokerAudit(manifest, 'executor-result-evidence-written', {
959
+ const execution = {
960
+ request, prepared: preparedExecution, result: null,
961
+ resultEvidenceWritten: false, failure: null, settled: false
962
+ };
963
+ active = execution;
964
+ preparedExecution.completion.then((result) => {
965
+ execution.result = sanitizeSandboxControlResult(manifest, result);
966
+ appendBrokerAudit(manifest, 'executor-completed', {
1022
967
  ...requestAuditFields(manifest, request),
1023
- resultPath: path.join(manifest.processingDir, request.id, 'result.json'),
1024
- ...resultAuditFields(execution.result)
968
+ ...resultAuditFields(execution.result),
969
+ childPid: preparedExecution.execution.child.pid,
970
+ childStartTime: preparedExecution.execution.child.startTime
1025
971
  });
1026
- }
1027
- catch (error) {
972
+ try {
973
+ writeSandboxControlResultEvidence(manifest, request.id, execution.result);
974
+ execution.resultEvidenceWritten = true;
975
+ execution.settled = true;
976
+ appendBrokerAudit(manifest, 'executor-result-evidence-written', {
977
+ ...requestAuditFields(manifest, request),
978
+ resultPath: path.join(manifest.processingDir, request.id, 'result.json'),
979
+ ...resultAuditFields(execution.result)
980
+ });
981
+ }
982
+ catch (error) {
983
+ execution.failure = error;
984
+ appendBrokerAudit(manifest, 'executor-result-evidence-failed', {
985
+ ...requestAuditFields(manifest, request),
986
+ errorType: error instanceof Error ? error.name : typeof error,
987
+ });
988
+ }
989
+ }, (error) => {
1028
990
  execution.failure = error;
1029
- appendBrokerAudit(manifest, 'executor-result-evidence-failed', {
991
+ execution.settled = true;
992
+ appendBrokerAudit(manifest, 'executor-failed', {
1030
993
  ...requestAuditFields(manifest, request),
994
+ childPid: preparedExecution.execution.child.pid,
995
+ childStartTime: preparedExecution.execution.child.startTime,
1031
996
  errorType: error instanceof Error ? error.name : typeof error,
1032
997
  });
1033
- }
1034
- }, (error) => {
1035
- execution.failure = error;
1036
- execution.settled = true;
1037
- appendBrokerAudit(manifest, 'executor-failed', {
1038
- ...requestAuditFields(manifest, request),
1039
- childPid: preparedExecution.execution.child.pid,
1040
- childStartTime: preparedExecution.execution.child.startTime,
1041
- errorType: error instanceof Error ? error.name : typeof error,
1042
998
  });
1043
- });
1044
- if (!brokerOwns()) {
1045
- prepared.terminate(false);
1046
- active = null;
1047
- retiring = true;
1048
- continue;
1049
- }
1050
- criticalRequestPhase(manifest, request, 'accepted-authorized', 'in-progress');
1051
- writeAcceptedResponse(manifest, {
1052
- version: 2, id, phase: 'accepted', exitCode: null, stdout: '', stderr: '', error: null
1053
- });
1054
- writeSandboxControlTransition(manifest, { requestId: request.id, phase: 'accepted-committed' });
1055
- appendBrokerAudit(manifest, 'request-accepted', {
1056
- ...requestAuditFields(manifest, request),
1057
- acceptedPath: acceptedResponsePath(manifest, id),
1058
- executionPhase: 'prepared'
1059
- });
1060
- if (!brokerOwns()) {
1061
- prepared.terminate(false);
1062
- active = null;
1063
- retiring = true;
1064
- break;
1065
- }
1066
- try {
1067
- criticalRequestPhase(manifest, request, 'start-authorized', 'in-progress', `${prepared.execution.child.pid}`);
1068
- appendBrokerAudit(manifest, 'executor-start', {
1069
- ...requestAuditFields(manifest, request),
1070
- childPid: prepared.execution.child.pid,
1071
- childStartTime: prepared.execution.child.startTime,
1072
- executionPath: executionPath(manifest, request.id)
999
+ if (!brokerOwns()) {
1000
+ prepared.terminate(false);
1001
+ active = null;
1002
+ retiring = true;
1003
+ continue;
1004
+ }
1005
+ criticalRequestPhase(manifest, request, 'accepted-authorized', 'in-progress');
1006
+ writeAcceptedResponse(manifest, {
1007
+ version: 2, id, phase: 'accepted', exitCode: null, stdout: '', stderr: '', error: null
1073
1008
  });
1074
- prepared.start(brokerOwns);
1075
- }
1076
- catch (error) {
1077
- appendBrokerAudit(manifest, 'executor-start-failed', {
1009
+ writeSandboxControlTransition(manifest, { requestId: request.id, phase: 'accepted-committed' });
1010
+ appendBrokerAudit(manifest, 'request-accepted', {
1078
1011
  ...requestAuditFields(manifest, request),
1079
- errorType: error instanceof Error ? error.name : typeof error,
1012
+ acceptedPath: acceptedResponsePath(manifest, id),
1013
+ executionPhase: 'prepared'
1080
1014
  });
1081
- const owned = brokerOwns();
1082
- prepared.terminate(owned);
1083
- if (!owned || !brokerOwns()) {
1015
+ if (!brokerOwns()) {
1016
+ prepared.terminate(false);
1084
1017
  active = null;
1085
1018
  retiring = true;
1086
1019
  break;
1087
1020
  }
1088
- writeSandboxControlResponse(manifest, unknown(id));
1089
- if (!brokerOwns()) {
1021
+ try {
1022
+ criticalRequestPhase(manifest, request, 'start-authorized', 'in-progress', `${prepared.execution.child.pid}`);
1023
+ appendBrokerAudit(manifest, 'executor-start', {
1024
+ ...requestAuditFields(manifest, request),
1025
+ childPid: prepared.execution.child.pid,
1026
+ childStartTime: prepared.execution.child.startTime,
1027
+ executionPath: executionPath(manifest, request.id)
1028
+ });
1029
+ prepared.start(brokerOwns);
1030
+ }
1031
+ catch (error) {
1032
+ appendBrokerAudit(manifest, 'executor-start-failed', {
1033
+ ...requestAuditFields(manifest, request),
1034
+ errorType: error instanceof Error ? error.name : typeof error,
1035
+ });
1036
+ const owned = brokerOwns();
1037
+ prepared.terminate(owned);
1038
+ if (!owned || !brokerOwns()) {
1039
+ active = null;
1040
+ retiring = true;
1041
+ break;
1042
+ }
1043
+ writeSandboxControlResponse(manifest, unknown(id));
1044
+ if (!brokerOwns()) {
1045
+ active = null;
1046
+ retiring = true;
1047
+ break;
1048
+ }
1049
+ removeAcceptedResponse(manifest, id);
1050
+ fs.rmSync(path.join(manifest.processingDir, id), { recursive: true, force: true });
1051
+ active = null;
1052
+ claimed = null;
1053
+ if (!brokerOwns()) {
1054
+ retiring = true;
1055
+ break;
1056
+ }
1057
+ appendBrokerAudit(manifest, 'executor-gate-failed', { requestId: id });
1058
+ continue;
1059
+ }
1060
+ }
1061
+ catch (error) {
1062
+ if (prepared) {
1063
+ try {
1064
+ prepared.terminate(brokerOwns());
1065
+ }
1066
+ catch { /* cleanup is best effort after a failed admission */ }
1067
+ prepared = null;
1090
1068
  active = null;
1069
+ }
1070
+ if (!brokerOwns()) {
1091
1071
  retiring = true;
1092
1072
  break;
1093
1073
  }
1094
- removeAcceptedResponse(manifest, id);
1095
- fs.rmSync(path.join(manifest.processingDir, id), { recursive: true, force: true });
1096
- active = null;
1097
- claimed = null;
1074
+ const detail = controlError(error);
1075
+ appendBrokerAudit(manifest, 'request-rejected', {
1076
+ requestId: id,
1077
+ requestFamily: validatedRequest?.family ?? null,
1078
+ sandboxTaskId: manifest.taskId,
1079
+ requestPath: claimed,
1080
+ errorCode: detail.code,
1081
+ errorRetryable: detail.retryable,
1082
+ errorType: error instanceof Error ? error.name : typeof error,
1083
+ });
1084
+ writeSandboxControlResponse(manifest, rejected(id, error));
1098
1085
  if (!brokerOwns()) {
1099
1086
  retiring = true;
1100
1087
  break;
1101
1088
  }
1102
- appendBrokerAudit(manifest, 'executor-gate-failed', { requestId: id });
1103
- continue;
1104
- }
1105
- }
1106
- catch (error) {
1107
- if (prepared) {
1108
- try {
1109
- prepared.terminate(brokerOwns());
1110
- }
1111
- catch { /* cleanup is best effort after a failed admission */ }
1112
- prepared = null;
1113
- active = null;
1114
- }
1115
- if (!brokerOwns()) {
1116
- retiring = true;
1117
- break;
1118
- }
1119
- const detail = controlError(error);
1120
- appendBrokerAudit(manifest, 'request-rejected', {
1121
- requestId: id,
1122
- requestFamily: validatedRequest?.family ?? null,
1123
- sandboxTaskId: manifest.taskId,
1124
- requestPath: claimed,
1125
- errorCode: detail.code,
1126
- errorRetryable: detail.retryable,
1127
- errorType: error instanceof Error ? error.name : typeof error,
1128
- });
1129
- writeSandboxControlResponse(manifest, rejected(id, error));
1130
- if (!brokerOwns()) {
1131
- retiring = true;
1132
- break;
1089
+ removeAcceptedResponse(manifest, id);
1090
+ if (claimed)
1091
+ fs.rmSync(path.dirname(claimed), { recursive: true, force: true });
1133
1092
  }
1134
- removeAcceptedResponse(manifest, id);
1135
- if (claimed)
1136
- fs.rmSync(path.dirname(claimed), { recursive: true, force: true });
1137
1093
  }
1138
- }
1139
1094
  if (retiring || !brokerOwns())
1140
1095
  break;
1141
1096
  await delay(timing.controlTickMs);
@@ -1157,11 +1112,6 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
1157
1112
  }
1158
1113
  }
1159
1114
  if (owned && active.result && active.resultEvidenceWritten) {
1160
- const finalizationView = await taskViewForFinalizationResult(manifest, active.request, active.result);
1161
- if (finalizationView) {
1162
- taskView = finalizationView;
1163
- writeSandboxControlStatus(manifest, broker, 'healthy', null, null, Date.now(), taskView);
1164
- }
1165
1115
  if (publishExecutionResult(manifest, active.request, active.result, brokerOwns)) {
1166
1116
  if (brokerOwns()) {
1167
1117
  removeAcceptedResponse(manifest, active.request.id);
@@ -130,19 +130,6 @@ export function projectSandboxTaskView(input) {
130
130
  reasonCode: receipt ? 'SANDBOX_TASK_VIEW_SOURCE_UNCONFIRMED' : 'SANDBOX_TASK_VIEW_EVIDENCE_UNAVAILABLE'
131
131
  };
132
132
  }
133
- export function taskViewAfterFinalization(params) {
134
- const receipt = receiptIdentity(params.receipt, params.generation, params.requestId);
135
- if (!receipt) {
136
- return {
137
- state: 'unknown', taskId: params.taskId, observedSource: 'unknown', receipt: null,
138
- reasonCode: 'SANDBOX_TASK_VIEW_RECEIPT_INVALID'
139
- };
140
- }
141
- return {
142
- state: 'finalized-stale', taskId: params.taskId, observedSource: 'active', receipt,
143
- reasonCode: 'SANDBOX_TASK_VIEW_FINALIZED'
144
- };
145
- }
146
133
  export function mergeSandboxTaskView(canonical, previous) {
147
134
  if (previous.state !== 'finalized-stale' && previous.state !== 'unknown')
148
135
  return canonical;
@@ -5,14 +5,13 @@ export const SANDBOX_CONTROL_STATUS_MOUNT = '/run/agent-infra/control-status';
5
5
  const TASK_MARKER_KEYS = [
6
6
  'AGENT_INFRA_SANDBOX',
7
7
  'AGENT_INFRA_TASK_ID',
8
- 'AGENT_INFRA_CONTROL_TOKEN',
9
8
  'AGENT_INFRA_CONTROL_GENERATION',
10
9
  'AGENT_INFRA_CONTROL_DIR',
10
+ 'AGENT_INFRA_CONTROL_ROOT_DIR',
11
11
  'AGENT_INFRA_CONTROL_STATUS_DIR',
12
12
  'AGENT_INFRA_RUNTIME_DIR'
13
13
  ];
14
14
  const TASK_CONTROL_MARKER_KEYS = [
15
- 'AGENT_INFRA_CONTROL_TOKEN',
16
15
  'AGENT_INFRA_CONTROL_GENERATION',
17
16
  'AGENT_INFRA_CONTROL_DIR',
18
17
  'AGENT_INFRA_CONTROL_STATUS_DIR'
@@ -77,7 +76,6 @@ export function hasSandboxControlMarker(env = process.env) {
77
76
  export function resolveSandboxControlTransport(env = process.env, options = {}) {
78
77
  const markerState = sandboxTaskMarkerState(env);
79
78
  const hasAnyMarker = markerState !== 'none'
80
- || Boolean(env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING)
81
79
  || Boolean(env.AGENT_INFRA_EXECUTOR_MANIFEST);
82
80
  const fixedStatusDir = options.statusMountPath ?? SANDBOX_CONTROL_STATUS_MOUNT;
83
81
  const fixedStatusProbe = path.isAbsolute(fixedStatusDir)
@@ -98,6 +96,10 @@ export function resolveSandboxControlTransport(env = process.env, options = {})
98
96
  if (!hasCompleteConfig) {
99
97
  return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_CONFIGURATION_INCOMPLETE' };
100
98
  }
99
+ if (markerState === 'task-bound'
100
+ && (!env.AGENT_INFRA_CONTROL_ROOT_DIR || !path.isAbsolute(env.AGENT_INFRA_CONTROL_ROOT_DIR))) {
101
+ return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_CONFIGURATION_INCOMPLETE' };
102
+ }
101
103
  const configuredStatusDir = env.AGENT_INFRA_CONTROL_STATUS_DIR;
102
104
  const configuredStatusProbe = configuredStatusDir && path.isAbsolute(configuredStatusDir)
103
105
  ? nativeDirectoryProbe(configuredStatusDir) : 'absent';
@@ -108,7 +110,7 @@ export function resolveSandboxControlTransport(env = process.env, options = {})
108
110
  ? configuredStatusProbe === 'present' ? configuredStatusDir : null
109
111
  : fixedStatusMounted ? fixedStatusDir : null;
110
112
  const statusMounted = statusDir !== null;
111
- if (env.AGENT_INFRA_EXECUTOR_MANIFEST || env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING) {
113
+ if (env.AGENT_INFRA_EXECUTOR_MANIFEST) {
112
114
  return { kind: 'fail-closed', reasonCode: 'TASK_CONTROL_TRANSPORT_INVALID' };
113
115
  }
114
116
  const taskBound = Boolean(env.AGENT_INFRA_TASK_ID);
@@ -124,9 +126,6 @@ export function resolveSandboxControlTransport(env = process.env, options = {})
124
126
  ? 'SANDBOX_CONTROL_IDENTITY_MISSING'
125
127
  : 'SANDBOX_CONTROL_IDENTITY_MALFORMED' };
126
128
  }
127
- if (sentinel.generation !== env.AGENT_INFRA_CONTROL_GENERATION) {
128
- return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_GENERATION_MISMATCH' };
129
- }
130
129
  if (sentinel.controlRootId !== env.AGENT_INFRA_CONTROL_ROOT_ID) {
131
130
  return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_ROOT_ID_MISMATCH' };
132
131
  }
@@ -134,7 +133,7 @@ export function resolveSandboxControlTransport(env = process.env, options = {})
134
133
  && (sentinel.taskId !== env.AGENT_INFRA_TASK_ID || !runtime)) {
135
134
  return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_TOPOLOGY_MISMATCH' };
136
135
  }
137
- if (sentinel.mode === 'branch-only' && (taskBound || runtime)) {
136
+ if (sentinel.mode === 'branch-only' && (taskBound || runtime || Boolean(env.AGENT_INFRA_CONTROL_ROOT_DIR))) {
138
137
  return { kind: 'fail-closed', reasonCode: 'SANDBOX_CONTROL_IDENTITY_TOPOLOGY_MISMATCH' };
139
138
  }
140
139
  return { kind: options.localWorkflow ? 'sandbox-local' : 'broker-client', reasonCode: null };