codex-workflow-v2 2.0.0-beta.1 → 2.0.0-beta.11

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 (187) hide show
  1. package/README.md +94 -12
  2. package/dist/src/alpha6/adoption.js +13 -3
  3. package/dist/src/alpha6/adoption.js.map +1 -1
  4. package/dist/src/alpha6/handoff.d.ts +26 -2
  5. package/dist/src/alpha6/handoff.js +277 -29
  6. package/dist/src/alpha6/handoff.js.map +1 -1
  7. package/dist/src/alpha6/mechanical-feasibility.d.ts +7 -0
  8. package/dist/src/alpha6/mechanical-feasibility.js +303 -0
  9. package/dist/src/alpha6/mechanical-feasibility.js.map +1 -0
  10. package/dist/src/alpha6/milestone.d.ts +37 -2
  11. package/dist/src/alpha6/milestone.js +472 -33
  12. package/dist/src/alpha6/milestone.js.map +1 -1
  13. package/dist/src/alpha6/plan-integrity.d.ts +14 -0
  14. package/dist/src/alpha6/plan-integrity.js +127 -0
  15. package/dist/src/alpha6/plan-integrity.js.map +1 -0
  16. package/dist/src/alpha6/plan-risk.d.ts +1 -0
  17. package/dist/src/alpha6/plan-risk.js +15 -7
  18. package/dist/src/alpha6/plan-risk.js.map +1 -1
  19. package/dist/src/alpha6/remediation.d.ts +2 -1
  20. package/dist/src/alpha6/remediation.js +186 -9
  21. package/dist/src/alpha6/remediation.js.map +1 -1
  22. package/dist/src/alpha6/review.d.ts +3 -0
  23. package/dist/src/alpha6/review.js +24 -0
  24. package/dist/src/alpha6/review.js.map +1 -1
  25. package/dist/src/cli.js +486 -46
  26. package/dist/src/cli.js.map +1 -1
  27. package/dist/src/contracts.d.ts +238 -6
  28. package/dist/src/contracts.js +1 -1
  29. package/dist/src/credential-output.d.ts +10 -0
  30. package/dist/src/credential-output.js +73 -0
  31. package/dist/src/credential-output.js.map +1 -0
  32. package/dist/src/dependency-provenance.d.ts +19 -0
  33. package/dist/src/dependency-provenance.js +185 -0
  34. package/dist/src/dependency-provenance.js.map +1 -0
  35. package/dist/src/errors.d.ts +1 -1
  36. package/dist/src/errors.js.map +1 -1
  37. package/dist/src/git.d.ts +1 -1
  38. package/dist/src/git.js +13 -5
  39. package/dist/src/git.js.map +1 -1
  40. package/dist/src/index.d.ts +2 -1
  41. package/dist/src/index.js +2 -1
  42. package/dist/src/index.js.map +1 -1
  43. package/dist/src/lifecycle/canonical-hash.d.ts +6 -0
  44. package/dist/src/lifecycle/canonical-hash.js +24 -0
  45. package/dist/src/lifecycle/canonical-hash.js.map +1 -0
  46. package/dist/src/lifecycle/catalog.d.ts +26 -0
  47. package/dist/src/lifecycle/catalog.js +208 -0
  48. package/dist/src/lifecycle/catalog.js.map +1 -0
  49. package/dist/src/lifecycle/compiler-inspection.d.ts +48 -0
  50. package/dist/src/lifecycle/compiler-inspection.js +29 -0
  51. package/dist/src/lifecycle/compiler-inspection.js.map +1 -0
  52. package/dist/src/lifecycle/core-static-readiness.d.ts +6 -0
  53. package/dist/src/lifecycle/core-static-readiness.js +130 -0
  54. package/dist/src/lifecycle/core-static-readiness.js.map +1 -0
  55. package/dist/src/lifecycle/corrective-replan-authority.d.ts +53 -0
  56. package/dist/src/lifecycle/corrective-replan-authority.js +139 -0
  57. package/dist/src/lifecycle/corrective-replan-authority.js.map +1 -0
  58. package/dist/src/lifecycle/corrective-replan-binding-manifest.d.ts +21 -0
  59. package/dist/src/lifecycle/corrective-replan-binding-manifest.js +35 -0
  60. package/dist/src/lifecycle/corrective-replan-binding-manifest.js.map +1 -0
  61. package/dist/src/lifecycle/corrective-replan-credential-core.d.ts +86 -0
  62. package/dist/src/lifecycle/corrective-replan-credential-core.js +563 -0
  63. package/dist/src/lifecycle/corrective-replan-credential-core.js.map +1 -0
  64. package/dist/src/lifecycle/corrective-replan-credential-schema.d.ts +17 -0
  65. package/dist/src/lifecycle/corrective-replan-credential-schema.js +44 -0
  66. package/dist/src/lifecycle/corrective-replan-credential-schema.js.map +1 -0
  67. package/dist/src/lifecycle/corrective-replan-credentials.d.ts +47 -0
  68. package/dist/src/lifecycle/corrective-replan-credentials.js +103 -0
  69. package/dist/src/lifecycle/corrective-replan-credentials.js.map +1 -0
  70. package/dist/src/lifecycle/corrective-replan.d.ts +64 -0
  71. package/dist/src/lifecycle/corrective-replan.js +553 -0
  72. package/dist/src/lifecycle/corrective-replan.js.map +1 -0
  73. package/dist/src/lifecycle/evaluator.d.ts +2 -0
  74. package/dist/src/lifecycle/evaluator.js +35 -0
  75. package/dist/src/lifecycle/evaluator.js.map +1 -0
  76. package/dist/src/lifecycle/fingerprint.d.ts +31 -0
  77. package/dist/src/lifecycle/fingerprint.js +388 -0
  78. package/dist/src/lifecycle/fingerprint.js.map +1 -0
  79. package/dist/src/lifecycle/immutable.d.ts +1 -0
  80. package/dist/src/lifecycle/immutable.js +10 -0
  81. package/dist/src/lifecycle/immutable.js.map +1 -0
  82. package/dist/src/lifecycle/implementation-table.d.ts +29 -0
  83. package/dist/src/lifecycle/implementation-table.js +87 -0
  84. package/dist/src/lifecycle/implementation-table.js.map +1 -0
  85. package/dist/src/lifecycle/index.d.ts +4 -0
  86. package/dist/src/lifecycle/index.js +5 -0
  87. package/dist/src/lifecycle/index.js.map +1 -0
  88. package/dist/src/lifecycle/schema-artifact.d.ts +12 -0
  89. package/dist/src/lifecycle/schema-artifact.js +214 -0
  90. package/dist/src/lifecycle/schema-artifact.js.map +1 -0
  91. package/dist/src/lifecycle/semantic-registry.d.ts +6 -0
  92. package/dist/src/lifecycle/semantic-registry.js +489 -0
  93. package/dist/src/lifecycle/semantic-registry.js.map +1 -0
  94. package/dist/src/lifecycle/types.d.ts +718 -0
  95. package/dist/src/lifecycle/types.js +4 -0
  96. package/dist/src/lifecycle/types.js.map +1 -0
  97. package/dist/src/observation.d.ts +20 -0
  98. package/dist/src/observation.js +171 -0
  99. package/dist/src/observation.js.map +1 -0
  100. package/dist/src/reviewer.d.ts +43 -1
  101. package/dist/src/reviewer.js +203 -50
  102. package/dist/src/reviewer.js.map +1 -1
  103. package/dist/src/state/corrective-replan-executor.d.ts +64 -0
  104. package/dist/src/state/corrective-replan-executor.js +608 -0
  105. package/dist/src/state/corrective-replan-executor.js.map +1 -0
  106. package/dist/src/state/corrective-replan-public-schema.d.ts +3 -0
  107. package/dist/src/state/corrective-replan-public-schema.js +43 -0
  108. package/dist/src/state/corrective-replan-public-schema.js.map +1 -0
  109. package/dist/src/state/corrective-replan-public.d.ts +95 -0
  110. package/dist/src/state/corrective-replan-public.js +665 -0
  111. package/dist/src/state/corrective-replan-public.js.map +1 -0
  112. package/dist/src/state/corrective-replan-transaction.d.ts +160 -0
  113. package/dist/src/state/corrective-replan-transaction.js +730 -0
  114. package/dist/src/state/corrective-replan-transaction.js.map +1 -0
  115. package/dist/src/state/corrective-yield-executor.d.ts +31 -0
  116. package/dist/src/state/corrective-yield-executor.js +236 -0
  117. package/dist/src/state/corrective-yield-executor.js.map +1 -0
  118. package/dist/src/state/corrective-yield-transaction.d.ts +97 -0
  119. package/dist/src/state/corrective-yield-transaction.js +591 -0
  120. package/dist/src/state/corrective-yield-transaction.js.map +1 -0
  121. package/dist/src/state/lock.d.ts +76 -3
  122. package/dist/src/state/lock.js +611 -30
  123. package/dist/src/state/lock.js.map +1 -1
  124. package/dist/src/state/store.d.ts +3 -0
  125. package/dist/src/state/store.js +65 -12
  126. package/dist/src/state/store.js.map +1 -1
  127. package/dist/src/transition-core.d.ts +67 -0
  128. package/dist/src/transition-core.js +318 -0
  129. package/dist/src/transition-core.js.map +1 -0
  130. package/dist/src/version.d.ts +1 -1
  131. package/dist/src/version.js +1 -1
  132. package/dist/src/version.js.map +1 -1
  133. package/dist/src/workflow.d.ts +88 -24
  134. package/dist/src/workflow.js +1647 -270
  135. package/dist/src/workflow.js.map +1 -1
  136. package/docs/autonomy-guardrails.md +61 -1
  137. package/docs/beta11-plan-integrity-recovery-brief.md +38 -0
  138. package/docs/beta2-initial-assembly-navigation-brief.md +616 -0
  139. package/docs/delegated-approval.md +26 -1
  140. package/docs/development-flow.md +63 -8
  141. package/docs/lifecycle/state-machine-stabilization.md +641 -0
  142. package/docs/pdf/README.md +24 -0
  143. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  144. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  145. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  146. package/docs/pdf/requirements.txt +1 -0
  147. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +234 -0
  148. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +334 -0
  149. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +413 -0
  150. package/docs/problem-briefs/01-pre-implementation-integrity.md +478 -0
  151. package/docs/problem-briefs/02-minimal-step-integrity.md +411 -0
  152. package/docs/problem-briefs/03-minimal-agent-context-integrity.md +358 -0
  153. package/docs/problem-briefs/04-task-dependency-and-structural-replacement-integrity.md +566 -0
  154. package/docs/problem-briefs/BRIEF-TEMPLATE.md +56 -0
  155. package/docs/problem-briefs/README.md +120 -0
  156. package/docs/problem-briefs/evidence/p01-mechanical-feasibility-corpus.md +90 -0
  157. package/docs/problem-briefs/evidence/signal-v4-pre-m3-replay.md +246 -0
  158. package/docs/release.md +30 -6
  159. package/docs/split-required-recovery.md +19 -25
  160. package/docs/stable-release-defect-register.md +465 -3
  161. package/docs/updating-existing-project.md +59 -4
  162. package/docs/validation-report.md +124 -56
  163. package/package.json +9 -1
  164. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +10 -3
  165. package/plugins/codex-workflow-gateway/references/protocol.md +92 -4
  166. package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +376 -0
  167. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +263 -4
  168. package/references/state-machine.md +13 -6
  169. package/roles/delivery-coordinator.md +39 -0
  170. package/schemas/adoption-posture-event.schema.json +1 -1
  171. package/schemas/authorization-event.schema.json +64 -1
  172. package/schemas/context-envelope.schema.json +1 -1
  173. package/schemas/corrective-decision-event.schema.json +48 -3
  174. package/schemas/corrective-replan-credentials.private.schema.json +98 -0
  175. package/schemas/corrective-replan-execution-event.private.schema.json +53 -0
  176. package/schemas/corrective-replan-public.schema.json +142 -0
  177. package/schemas/corrective-replan-task-transaction.private.schema.json +151 -0
  178. package/schemas/corrective-yield-task-transaction.private.schema.json +98 -0
  179. package/schemas/milestone-scope-change-event.schema.json +6 -1
  180. package/schemas/milestone.schema.json +6 -1
  181. package/schemas/remediation-event.schema.json +11 -1
  182. package/schemas/task-handoff-event.schema.json +19 -3
  183. package/schemas/task.schema.json +24 -1
  184. package/schemas/transition-definition.schema.json +2609 -0
  185. package/schemas/transition-payloads.schema.json +140 -0
  186. package/scripts/generate-pdf-docs.py +512 -0
  187. package/scripts/run-pdf-docs.mjs +62 -0
@@ -0,0 +1,4 @@
1
+ export const LIFECYCLE_EPOCH = 2;
2
+ export const TRANSITION_DEFINITION_FORMAT_VERSION = 4;
3
+ export const TRANSITION_CATALOG_FORMAT_VERSION = 4;
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lifecycle/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAG,CAAU,CAAC;AAC1C,MAAM,CAAC,MAAM,oCAAoC,GAAG,CAAU,CAAC;AAC/D,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAU,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { AdoptionPostureEvent, ProjectRecord, WorkflowObservation, WriterLease } from './contracts.js';
2
+ import type { RepositoryIdentity } from './repository.js';
3
+ import type { FileStateStore } from './state/store.js';
4
+ export interface WorkflowObservationBoundary {
5
+ identity: RepositoryIdentity;
6
+ project: ProjectRecord | null;
7
+ currentAdoptionPosture: AdoptionPostureEvent | null;
8
+ leases: WriterLease[];
9
+ observation: WorkflowObservation;
10
+ }
11
+ /**
12
+ * Reads only the persistence boundary needed to decide whether a coherent lifecycle snapshot can
13
+ * be loaded. It deliberately does not register a project, recover a journal, initialize adoption,
14
+ * or construct a WriterLockManager.
15
+ */
16
+ export declare function inspectWorkflowObservationBoundary(options: {
17
+ store: FileStateStore;
18
+ identity: RepositoryIdentity;
19
+ now: Date;
20
+ }): WorkflowObservationBoundary;
@@ -0,0 +1,171 @@
1
+ import { existsSync, readdirSync, realpathSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { readCurrentAdoptionPosture } from './alpha6/adoption.js';
4
+ import { listMilestoneTransactionJournals } from './alpha6/journal.js';
5
+ import { assertNoSymlinkPathComponents } from './alpha6/store-sidecars.js';
6
+ import { listProjectTransactions } from './beta1/project-transaction.js';
7
+ import { listCoreTaskOperationMutexes, listWriterLeases, toPublicCoreTaskOperation, toPublicWriterLease, } from './state/lock.js';
8
+ import { inspectCorrectiveReplanTaskTransactions } from './state/corrective-replan-transaction.js';
9
+ import { inspectCorrectiveYieldTaskTransactions } from './state/corrective-yield-transaction.js';
10
+ /**
11
+ * Reads only the persistence boundary needed to decide whether a coherent lifecycle snapshot can
12
+ * be loaded. It deliberately does not register a project, recover a journal, initialize adoption,
13
+ * or construct a WriterLockManager.
14
+ */
15
+ export function inspectWorkflowObservationBoundary(options) {
16
+ const { store, identity, now } = options;
17
+ const projectRoot = store.projectRoot(identity.projectId);
18
+ const projectFile = path.join(projectRoot, 'project.json');
19
+ const lockRoot = store.lockRoot(identity.projectId);
20
+ const stateRootPresent = existsSync(store.root);
21
+ const projectRootPresent = existsSync(projectRoot);
22
+ const lockRootPresent = existsSync(lockRoot);
23
+ const missingRegistration = !existsSync(projectFile);
24
+ const pendingProjectTransactions = observeProjectTransactions(projectRoot, identity.projectId);
25
+ const pendingMilestoneTransactions = observeMilestoneTransactions(store, identity.projectId);
26
+ const replanTransactions = inspectCorrectiveReplanTaskTransactions(projectRoot, store.root);
27
+ const yieldTransactions = inspectCorrectiveYieldTaskTransactions(projectRoot, store.root);
28
+ const taskTransactions = {
29
+ pending: [...replanTransactions.pending, ...yieldTransactions.pending]
30
+ .sort((left, right) => left.taskId.localeCompare(right.taskId) || left.transactionId.localeCompare(right.transactionId)),
31
+ corrupt: [...replanTransactions.corrupt, ...yieldTransactions.corrupt]
32
+ .sort((left, right) => left.taskId.localeCompare(right.taskId) || left.transactionId.localeCompare(right.transactionId)),
33
+ };
34
+ const pendingTaskTransitionIds = [...new Set(taskTransactions.pending.map((transaction) => transaction.transitionId))];
35
+ const mixedPendingTaskTransitions = pendingTaskTransitionIds.length > 1;
36
+ const leases = listWriterLeases(lockRoot);
37
+ const coreTaskOperations = listCoreTaskOperationMutexes(lockRoot, store.root)
38
+ .map((mutex) => toPublicCoreTaskOperation(mutex, now));
39
+ const orphanCoreTaskOperations = coreTaskOperations.filter((operation) => !taskTransactions.pending.some((transaction) => transaction.taskId === operation.entityId && transaction.transactionId === operation.operationId));
40
+ const project = !missingRegistration && pendingProjectTransactions.length === 0
41
+ ? store.readProject(identity.projectId)
42
+ : null;
43
+ const repositoryRootBound = project?.repositoryRoots.includes(identity.repositoryRoot) ?? false;
44
+ const adoptionAssessed = pendingProjectTransactions.length === 0
45
+ && pendingMilestoneTransactions.length === 0
46
+ && taskTransactions.pending.length === 0
47
+ && taskTransactions.corrupt.length === 0
48
+ && orphanCoreTaskOperations.length === 0;
49
+ const currentAdoptionPosture = adoptionAssessed && stateRootPresent
50
+ ? readCurrentAdoptionPosture(store, identity.projectId)
51
+ : null;
52
+ const missingAdoption = adoptionAssessed && currentAdoptionPosture === null;
53
+ const observedLeases = leases.map((lease) => toPublicWriterLease(lease, now));
54
+ const activeLeases = observedLeases.filter((lease) => !lease.stale);
55
+ const staleLeases = observedLeases.filter((lease) => lease.stale);
56
+ const reasonCodes = [];
57
+ if (missingRegistration)
58
+ reasonCodes.push('PROJECT_REGISTRATION_MISSING');
59
+ if (project && !repositoryRootBound)
60
+ reasonCodes.push('PROJECT_REPOSITORY_ROOT_UNBOUND');
61
+ if (pendingProjectTransactions.length > 0)
62
+ reasonCodes.push('PROJECT_RECOVERY_REQUIRED');
63
+ if (pendingMilestoneTransactions.length > 0)
64
+ reasonCodes.push('MILESTONE_RECOVERY_REQUIRED');
65
+ if (taskTransactions.pending.length > 0)
66
+ reasonCodes.push('TASK_RECOVERY_REQUIRED');
67
+ if (taskTransactions.corrupt.length > 0)
68
+ reasonCodes.push('TASK_TRANSACTION_INTEGRITY_FAILED');
69
+ if (orphanCoreTaskOperations.some((operation) => !operation.stale))
70
+ reasonCodes.push('TASK_OPERATION_IN_PROGRESS');
71
+ if (orphanCoreTaskOperations.some((operation) => operation.stale))
72
+ reasonCodes.push('STALE_TASK_OPERATION');
73
+ if (activeLeases.length > 0)
74
+ reasonCodes.push('ACTIVE_WRITER_LEASE');
75
+ if (staleLeases.length > 0)
76
+ reasonCodes.push('STALE_WRITER_LEASE');
77
+ if (missingAdoption)
78
+ reasonCodes.push('ADOPTION_MISSING');
79
+ const blocked = missingRegistration
80
+ || (project !== null && !repositoryRootBound)
81
+ || pendingProjectTransactions.length > 0
82
+ || taskTransactions.corrupt.length > 0
83
+ || mixedPendingTaskTransitions
84
+ || orphanCoreTaskOperations.length > 0;
85
+ const repairable = taskTransactions.pending.length > 0
86
+ || pendingMilestoneTransactions.length > 0
87
+ || staleLeases.length > 0;
88
+ const kind = blocked ? 'blocked' : repairable ? 'repair' : 'assessment';
89
+ const repair = kind !== 'repair'
90
+ ? null
91
+ : taskTransactions.pending.length > 0
92
+ ? {
93
+ command: pendingTaskTransitionIds[0] === 'task.coordination.corrective-yield'
94
+ ? 'task corrective-yield-recover'
95
+ : 'task corrective-replan-recover',
96
+ cataloged: false,
97
+ available: true,
98
+ projectId: identity.projectId,
99
+ taskIds: [...new Set(taskTransactions.pending.map((transaction) => transaction.taskId))].sort(),
100
+ transactionIds: taskTransactions.pending.map((transaction) => transaction.transactionId).sort(),
101
+ }
102
+ : pendingMilestoneTransactions.length > 0
103
+ ? {
104
+ command: 'milestone recover',
105
+ cataloged: false,
106
+ projectId: identity.projectId,
107
+ milestoneIds: [...new Set(pendingMilestoneTransactions.map((transaction) => transaction.milestoneId))].sort(),
108
+ transactionIds: pendingMilestoneTransactions.map((transaction) => transaction.transactionId).sort(),
109
+ }
110
+ : {
111
+ command: 'locks repair',
112
+ cataloged: false,
113
+ projectId: identity.projectId,
114
+ entityIds: staleLeases.map((lease) => lease.entityId).sort(),
115
+ };
116
+ return {
117
+ identity,
118
+ project,
119
+ currentAdoptionPosture,
120
+ leases,
121
+ observation: {
122
+ kind,
123
+ reasonCodes,
124
+ stateRootPresent,
125
+ projectRootPresent,
126
+ lockRootPresent,
127
+ missingRegistration,
128
+ repositoryRootBound,
129
+ adoptionAssessed,
130
+ missingAdoption,
131
+ pendingProjectTransactions,
132
+ pendingMilestoneTransactions,
133
+ pendingTaskTransactions: taskTransactions.pending,
134
+ corruptTaskTransactions: taskTransactions.corrupt,
135
+ coreTaskOperations,
136
+ leases: observedLeases,
137
+ availableRepairTransitionId: null,
138
+ repair,
139
+ },
140
+ };
141
+ }
142
+ function observeProjectTransactions(projectRoot, projectId) {
143
+ return listProjectTransactions(projectRoot, projectId)
144
+ .map((transaction) => ({ ...transaction }))
145
+ .sort((left, right) => left.preparedAt.localeCompare(right.preparedAt)
146
+ || left.transactionId.localeCompare(right.transactionId));
147
+ }
148
+ function observeMilestoneTransactions(store, projectId) {
149
+ const milestonesRoot = path.join(store.projectRoot(projectId), 'milestones');
150
+ if (!existsSync(milestonesRoot))
151
+ return [];
152
+ assertNoSymlinkPathComponents(milestonesRoot, {
153
+ label: 'Milestones observation root',
154
+ requireLeaf: true,
155
+ trustedRoot: store.root,
156
+ });
157
+ return readdirSync(milestonesRoot, { withFileTypes: true })
158
+ .filter((entry) => entry.isDirectory())
159
+ .flatMap((entry) => listMilestoneTransactionJournals(realpathSync(path.join(milestonesRoot, entry.name)), {
160
+ expectedMilestoneId: entry.name,
161
+ }).map((journal) => ({
162
+ milestoneId: journal.milestoneId,
163
+ transactionId: journal.transactionId,
164
+ phase: journal.phase,
165
+ preparedAt: journal.preparedAt,
166
+ updatedAt: journal.updatedAt,
167
+ })))
168
+ .sort((left, right) => left.preparedAt.localeCompare(right.preparedAt)
169
+ || left.transactionId.localeCompare(right.transactionId));
170
+ }
171
+ //# sourceMappingURL=observation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observation.js","sourceRoot":"","sources":["../../src/observation.ts"],"names":[],"mappings":"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"}
@@ -3,10 +3,12 @@ export interface ReviewerProcessResult {
3
3
  status: number | null;
4
4
  stdout: string;
5
5
  stderr: string;
6
+ timedOut?: boolean;
6
7
  }
7
8
  export type ReviewerCommandRunner = (command: string, args: string[], options: {
8
9
  cwd: string;
9
10
  input: string;
11
+ timeoutMs: number;
10
12
  }) => ReviewerProcessResult;
11
13
  export interface StrictReviewOutput extends ReviewInput {
12
14
  isolationProbe: 'denied' | 'written' | 'not-attempted';
@@ -16,6 +18,7 @@ export interface StrictReviewerLaunchResult {
16
18
  verifiedIsolation: boolean;
17
19
  command: string[];
18
20
  processStatus: number | null;
21
+ timedOut: boolean;
19
22
  stderr: string;
20
23
  before: RepositorySeal;
21
24
  after: RepositorySeal;
@@ -24,11 +27,45 @@ export interface StrictStepReviewerLaunchResult extends StrictReviewerLaunchResu
24
27
  reviewedCommit: string;
25
28
  reviewerOutputHash: string;
26
29
  }
27
- interface RepositorySeal {
30
+ export interface RepositorySeal {
28
31
  headCommit: string;
29
32
  changedFiles: string[];
30
33
  contentHash: string;
31
34
  }
35
+ export interface ExternalStrictStepReviewPacket {
36
+ protocol: 'codex-workflow-external-strict-step-review-v1';
37
+ taskId: string;
38
+ stepId: string;
39
+ reviewedCommit: string;
40
+ packet: Record<string, unknown>;
41
+ packetHash: string;
42
+ repositorySeal: RepositorySeal;
43
+ repositorySealHash: string;
44
+ }
45
+ export interface ExternalStrictStepReviewInput {
46
+ protocol: 'codex-workflow-external-strict-step-review-v1';
47
+ packetHash: string;
48
+ repositorySealHash: string;
49
+ reviewerThreadId: string;
50
+ review: ReviewInput;
51
+ }
52
+ export interface ExternalStrictTaskReviewPacket {
53
+ protocol: 'codex-workflow-external-strict-task-review-v1';
54
+ taskId: string;
55
+ reviewedCommit: string;
56
+ packet: Record<string, unknown>;
57
+ packetHash: string;
58
+ repositorySeal: RepositorySeal;
59
+ repositorySealHash: string;
60
+ }
61
+ export interface ExternalStrictTaskReviewInput {
62
+ protocol: 'codex-workflow-external-strict-task-review-v1';
63
+ packetHash: string;
64
+ repositorySealHash: string;
65
+ reviewerThreadId: string;
66
+ review: ReviewInput;
67
+ }
68
+ export declare const STRICT_REVIEWER_TIMEOUT_MS = 180000;
32
69
  declare const REVIEW_SCHEMA: {
33
70
  readonly type: "object";
34
71
  readonly additionalProperties: false;
@@ -84,4 +121,9 @@ declare const REVIEW_SCHEMA: {
84
121
  };
85
122
  export declare function launchStrictReviewer(repositoryRoot: string, task: TaskState, taskRoot: string, envelope: ContextEnvelope, runner?: ReviewerCommandRunner): StrictReviewerLaunchResult;
86
123
  export declare function launchStrictStepReviewer(repositoryRoot: string, task: TaskState, taskRoot: string, envelope: ContextEnvelope, stepId: string, currentEvidence: StepEvidence, runner?: ReviewerCommandRunner): StrictStepReviewerLaunchResult;
124
+ export declare function prepareExternalStrictStepReviewPacket(repositoryRoot: string, task: TaskState, taskRoot: string, envelope: ContextEnvelope, stepId: string, currentEvidence: StepEvidence): ExternalStrictStepReviewPacket;
125
+ export declare function prepareExternalStrictTaskReviewPacket(repositoryRoot: string, task: TaskState, taskRoot: string, envelope: ContextEnvelope): ExternalStrictTaskReviewPacket;
126
+ export declare function validateExternalStrictStepReviewInput(value: unknown, expected: ExternalStrictStepReviewPacket): ReviewInput;
127
+ export declare function validateExternalStrictTaskReviewInput(value: unknown, expected: ExternalStrictTaskReviewPacket): ReviewInput;
128
+ export declare function strictReviewInputHash(review: ReviewInput): string;
87
129
  export { REVIEW_SCHEMA };
@@ -1,11 +1,12 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { existsSync, lstatSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { existsSync, lstatSync, mkdtempSync, readFileSync, readlinkSync, rmSync, writeFileSync } from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
6
  import { canonicalJsonStringify } from './alpha6/store-sidecars.js';
7
7
  import { changedFiles, headCommit, runGit } from './repository.js';
8
8
  const FULL_GIT_SHA_PATTERN = /^[a-f0-9]{40}$/;
9
+ export const STRICT_REVIEWER_TIMEOUT_MS = 180_000;
9
10
  const REVIEW_SCHEMA = {
10
11
  type: 'object',
11
12
  additionalProperties: false,
@@ -65,6 +66,7 @@ export function launchStrictReviewer(repositoryRoot, task, taskRoot, envelope, r
65
66
  verifiedIsolation: launch.verifiedIsolation,
66
67
  command: launch.command,
67
68
  processStatus: launch.processStatus,
69
+ timedOut: launch.timedOut,
68
70
  stderr: launch.stderr,
69
71
  before: launch.before,
70
72
  after: launch.after,
@@ -89,51 +91,21 @@ export function launchStrictStepReviewer(repositoryRoot, task, taskRoot, envelop
89
91
  if (reviewedCommit !== currentHead) {
90
92
  return failedStepLaunch(repositoryRoot, [], null, `Strict step reviewer requires the canonical Step evidence commit to match repository HEAD for ${stepId} on task ${task.id}.`, reviewedCommit);
91
93
  }
94
+ const packet = strictStepReviewPayload(repositoryRoot, task, taskRoot, envelope, step, reviewedCommit, currentEvidence);
92
95
  const launch = runStrictReviewerLaunch(repositoryRoot, {
93
96
  protocol: 'codex-workflow-strict-step-review-v1',
94
97
  task,
95
98
  taskRoot,
96
99
  envelope,
97
100
  commandSummary: 'Strict step reviewer did not return valid output proving the denied write probe.',
98
- packet: {
99
- protocol: 'codex-workflow-strict-step-review-v1',
100
- instruction: [
101
- 'Act only as the independent reviewer described by the context envelope.',
102
- 'Before reviewing, attempt to create .codex-reviewer-write-probe in the repository.',
103
- 'The attempt must be denied by the sandbox. Report isolationProbe="denied" only when it was denied.',
104
- 'Review only the supplied Task Step and bind your findings to the supplied reviewedCommit.',
105
- 'Do not modify any repository file. Return only the requested JSON result.',
106
- ],
107
- envelope,
108
- task: {
109
- id: task.id,
110
- baseCommit: task.baseCommit,
111
- headCommit: headCommit(repositoryRoot),
112
- brief: readFileSync(path.join(taskRoot, 'brief.md'), 'utf8'),
113
- plan: readFileSync(path.join(taskRoot, 'plan.md'), 'utf8'),
114
- diff: task.baseCommit ? runGit(repositoryRoot, ['diff', '--no-ext-diff', `${task.baseCommit}..HEAD`]) : '',
115
- },
116
- step: {
117
- id: step.id,
118
- title: step.title,
119
- objective: step.objective,
120
- requirements: step.requirements,
121
- dependencies: step.dependencies,
122
- expectedOutputs: step.expectedOutputs,
123
- allowedWrites: step.allowedWrites,
124
- forbiddenScope: step.forbiddenScope,
125
- checks: step.checks,
126
- status: step.status,
127
- reviewedCommit,
128
- evidence: currentEvidence,
129
- },
130
- },
101
+ packet,
131
102
  }, runner);
132
103
  return {
133
104
  review: launch.review,
134
105
  verifiedIsolation: launch.verifiedIsolation,
135
106
  command: launch.command,
136
107
  processStatus: launch.processStatus,
108
+ timedOut: launch.timedOut,
137
109
  stderr: launch.stderr,
138
110
  before: launch.before,
139
111
  after: launch.after,
@@ -141,14 +113,184 @@ export function launchStrictStepReviewer(repositoryRoot, task, taskRoot, envelop
141
113
  reviewerOutputHash: launch.reviewerOutputHash,
142
114
  };
143
115
  }
116
+ export function prepareExternalStrictStepReviewPacket(repositoryRoot, task, taskRoot, envelope, stepId, currentEvidence) {
117
+ const step = task.steps.find((candidate) => candidate.id === stepId);
118
+ if (!step || !step.evidence || canonicalJsonStringify(step.evidence) !== canonicalJsonStringify(currentEvidence)) {
119
+ throw new Error(`Strict Step Review packet requires exact canonical evidence for ${stepId}.`);
120
+ }
121
+ const reviewedCommit = currentEvidence.commitSha;
122
+ if (!FULL_GIT_SHA_PATTERN.test(reviewedCommit) || reviewedCommit !== headCommit(repositoryRoot)) {
123
+ throw new Error(`Strict Step Review packet requires ${stepId} evidence to match repository HEAD.`);
124
+ }
125
+ const packet = strictStepReviewPayload(repositoryRoot, task, taskRoot, envelope, step, reviewedCommit, currentEvidence);
126
+ const repositorySeal = sealRepository(repositoryRoot);
127
+ return {
128
+ protocol: 'codex-workflow-external-strict-step-review-v1',
129
+ taskId: task.id,
130
+ stepId,
131
+ reviewedCommit,
132
+ packet,
133
+ packetHash: canonicalHash(packet),
134
+ repositorySeal,
135
+ repositorySealHash: canonicalHash(repositorySeal),
136
+ };
137
+ }
138
+ export function prepareExternalStrictTaskReviewPacket(repositoryRoot, task, taskRoot, envelope) {
139
+ const reviewedCommit = headCommit(repositoryRoot);
140
+ if (!FULL_GIT_SHA_PATTERN.test(reviewedCommit)) {
141
+ throw new Error(`Strict Task Review packet requires a full lowercase Git SHA for ${task.id}.`);
142
+ }
143
+ const packet = {
144
+ protocol: 'codex-workflow-strict-review-v1',
145
+ instruction: [
146
+ 'Act only as the independent reviewer described by the context envelope.',
147
+ 'Review the supplied Task result and bind every finding to reviewedCommit.',
148
+ 'Do not modify any repository or Workflow state. Return one ReviewInput JSON object.',
149
+ ],
150
+ envelope,
151
+ task: strictTaskReviewSubject(repositoryRoot, task, taskRoot),
152
+ };
153
+ const repositorySeal = sealRepository(repositoryRoot);
154
+ return {
155
+ protocol: 'codex-workflow-external-strict-task-review-v1',
156
+ taskId: task.id,
157
+ reviewedCommit,
158
+ packet,
159
+ packetHash: canonicalHash(packet),
160
+ repositorySeal,
161
+ repositorySealHash: canonicalHash(repositorySeal),
162
+ };
163
+ }
164
+ export function validateExternalStrictStepReviewInput(value, expected) {
165
+ return validateExternalReviewEnvelope(value, expected);
166
+ }
167
+ export function validateExternalStrictTaskReviewInput(value, expected) {
168
+ return validateExternalReviewEnvelope(value, expected);
169
+ }
170
+ export function strictReviewInputHash(review) {
171
+ return hashReviewInput(review);
172
+ }
173
+ function strictStepReviewPayload(repositoryRoot, task, taskRoot, envelope, step, reviewedCommit, currentEvidence) {
174
+ return {
175
+ protocol: 'codex-workflow-strict-step-review-v1',
176
+ instruction: [
177
+ 'Act only as the independent reviewer described by the context envelope.',
178
+ 'Review only the supplied Task Step and bind findings to reviewedCommit.',
179
+ 'Do not modify any repository or Workflow state. Return one ReviewInput JSON object.',
180
+ ],
181
+ envelope,
182
+ task: {
183
+ id: task.id,
184
+ baseCommit: task.baseCommit,
185
+ headCommit: headCommit(repositoryRoot),
186
+ brief: readFileSync(path.join(taskRoot, 'brief.md'), 'utf8'),
187
+ plan: readFileSync(path.join(taskRoot, 'plan.md'), 'utf8'),
188
+ diff: task.baseCommit ? runGit(repositoryRoot, ['diff', '--no-ext-diff', `${task.baseCommit}..HEAD`]) : '',
189
+ },
190
+ step: {
191
+ id: step.id,
192
+ title: step.title,
193
+ objective: step.objective,
194
+ requirements: step.requirements,
195
+ dependencies: step.dependencies,
196
+ expectedOutputs: step.expectedOutputs,
197
+ allowedWrites: step.allowedWrites,
198
+ forbiddenScope: step.forbiddenScope,
199
+ checks: step.checks,
200
+ status: step.status,
201
+ reviewedCommit,
202
+ evidence: currentEvidence,
203
+ },
204
+ };
205
+ }
206
+ function strictTaskReviewSubject(repositoryRoot, task, taskRoot) {
207
+ return {
208
+ id: task.id,
209
+ baseCommit: task.baseCommit,
210
+ headCommit: headCommit(repositoryRoot),
211
+ brief: readFileSync(path.join(taskRoot, 'brief.md'), 'utf8'),
212
+ plan: readFileSync(path.join(taskRoot, 'plan.md'), 'utf8'),
213
+ evidence: readFileSync(path.join(taskRoot, 'evidence.json'), 'utf8'),
214
+ diff: task.baseCommit ? runGit(repositoryRoot, ['diff', '--no-ext-diff', `${task.baseCommit}..HEAD`]) : '',
215
+ };
216
+ }
217
+ function validateExternalReviewEnvelope(value, expected) {
218
+ if (!isExactRecord(value, ['protocol', 'packetHash', 'repositorySealHash', 'reviewerThreadId', 'review'])) {
219
+ throw new Error('invalid external review envelope');
220
+ }
221
+ if (value.protocol !== expected.protocol)
222
+ throw new Error('invalid external review protocol');
223
+ if (value.packetHash !== expected.packetHash)
224
+ throw new Error('external review packet hash mismatch');
225
+ if (value.repositorySealHash !== expected.repositorySealHash)
226
+ throw new Error('external review repository seal mismatch');
227
+ if (typeof value.reviewerThreadId !== 'string' || !value.reviewerThreadId.trim()) {
228
+ throw new Error('external reviewer thread id is required');
229
+ }
230
+ if (!isExactRecord(value.review, ['status', 'reviewer', 'summary', 'findings'])) {
231
+ throw new Error('invalid external strict review');
232
+ }
233
+ const review = value.review;
234
+ if (!['passed', 'failed'].includes(String(review.status))
235
+ || typeof review.reviewer !== 'string' || !review.reviewer.trim()
236
+ || typeof review.summary !== 'string' || !review.summary.trim()
237
+ || !Array.isArray(review.findings)) {
238
+ throw new Error('invalid external strict review');
239
+ }
240
+ const findings = review.findings.map((candidate) => {
241
+ if (!isExactRecord(candidate, ['id', 'severity', 'requirement', 'summary', 'evidence', 'requiredAction'])
242
+ || typeof candidate.id !== 'string' || !candidate.id.trim()
243
+ || !['critical', 'major', 'minor'].includes(String(candidate.severity))
244
+ || (candidate.requirement !== null && typeof candidate.requirement !== 'string')
245
+ || typeof candidate.summary !== 'string' || !candidate.summary.trim()
246
+ || typeof candidate.evidence !== 'string' || !candidate.evidence.trim()
247
+ || typeof candidate.requiredAction !== 'string' || !candidate.requiredAction.trim()) {
248
+ throw new Error('invalid external strict review finding');
249
+ }
250
+ return {
251
+ id: candidate.id,
252
+ severity: candidate.severity,
253
+ requirement: candidate.requirement,
254
+ summary: candidate.summary,
255
+ evidence: candidate.evidence,
256
+ requiredAction: candidate.requiredAction,
257
+ };
258
+ });
259
+ if ((review.status === 'passed' && findings.length > 0) || (review.status === 'failed' && findings.length === 0)) {
260
+ throw new Error('invalid external strict review finding cardinality');
261
+ }
262
+ return {
263
+ status: review.status,
264
+ reviewer: review.reviewer,
265
+ summary: review.summary,
266
+ findings,
267
+ };
268
+ }
269
+ function isExactRecord(value, keys) {
270
+ if (!value || typeof value !== 'object' || Array.isArray(value))
271
+ return false;
272
+ const actual = Object.keys(value).sort();
273
+ return actual.length === keys.length && actual.every((key, index) => key === [...keys].sort()[index]);
274
+ }
275
+ function canonicalHash(value) {
276
+ return createHash('sha256').update(canonicalJsonStringify(value)).digest('hex');
277
+ }
144
278
  function spawnReviewer(command, args, options) {
145
279
  const result = spawnSync(command, args, {
146
280
  cwd: options.cwd,
147
281
  input: options.input,
148
282
  encoding: 'utf8',
149
283
  maxBuffer: 16 * 1024 * 1024,
284
+ timeout: options.timeoutMs,
285
+ killSignal: 'SIGKILL',
150
286
  });
151
- return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
287
+ const timedOut = result.error !== undefined && 'code' in result.error && result.error.code === 'ETIMEDOUT';
288
+ return {
289
+ status: result.status,
290
+ stdout: result.stdout ?? '',
291
+ stderr: [result.stderr ?? '', result.error?.message ?? ''].filter(Boolean).join('\n'),
292
+ timedOut,
293
+ };
152
294
  }
153
295
  function runStrictReviewerLaunch(repositoryRoot, options, runner) {
154
296
  const temporary = mkdtempSync(path.join(os.tmpdir(), 'codex-workflow-review-'));
@@ -163,7 +305,8 @@ function runStrictReviewerLaunch(repositoryRoot, options, runner) {
163
305
  }
164
306
  const before = sealRepository(repositoryRoot);
165
307
  const command = [
166
- 'codex', 'exec', '--ephemeral', '--ignore-user-config', '--ignore-rules', '--sandbox', 'read-only',
308
+ 'codex', '--ask-for-approval', 'never', 'exec',
309
+ '--ephemeral', '--ignore-user-config', '--ignore-rules', '--sandbox', 'read-only',
167
310
  '--output-schema', schemaFile, '--output-last-message', outputFile, '--json', '-C', repositoryRoot, '-',
168
311
  ];
169
312
  let processResult;
@@ -171,6 +314,7 @@ function runStrictReviewerLaunch(repositoryRoot, options, runner) {
171
314
  processResult = runner(command[0], command.slice(1), {
172
315
  cwd: repositoryRoot,
173
316
  input: `${JSON.stringify(options.packet)}\n`,
317
+ timeoutMs: STRICT_REVIEWER_TIMEOUT_MS,
174
318
  });
175
319
  }
176
320
  catch (error) {
@@ -195,17 +339,20 @@ function runStrictReviewerLaunch(repositoryRoot, options, runner) {
195
339
  const verifiedIsolation = unchanged && output?.isolationProbe === 'denied' && processResult.status === 0;
196
340
  const review = verifiedIsolation && output
197
341
  ? stripProbe(output)
198
- : unverifiedReview(processResult.status !== 0
199
- ? `Strict reviewer process failed with status ${String(processResult.status)}.`
200
- : probeWritten || !unchanged
201
- ? 'Strict reviewer modified repository state; review discarded.'
202
- : options.commandSummary);
342
+ : unverifiedReview(processResult.timedOut
343
+ ? `Strict reviewer exceeded the ${STRICT_REVIEWER_TIMEOUT_MS}ms execution deadline.`
344
+ : processResult.status !== 0
345
+ ? `Strict reviewer process failed with status ${String(processResult.status)}.`
346
+ : probeWritten || !unchanged
347
+ ? 'Strict reviewer modified repository state; review discarded.'
348
+ : options.commandSummary);
203
349
  const reviewerOutputHash = hashReviewInput(review);
204
350
  return {
205
351
  review,
206
352
  verifiedIsolation,
207
353
  command,
208
354
  processStatus: processResult.status,
355
+ timedOut: processResult.timedOut === true,
209
356
  stderr: processResult.stderr,
210
357
  before,
211
358
  after,
@@ -216,22 +363,27 @@ function sealRepository(repositoryRoot) {
216
363
  return {
217
364
  headCommit: headCommit(repositoryRoot),
218
365
  changedFiles: changedFiles(repositoryRoot),
219
- contentHash: hashTree(repositoryRoot, repositoryRoot),
366
+ contentHash: hashReviewableTree(repositoryRoot),
220
367
  };
221
368
  }
222
- function hashTree(repositoryRoot, current) {
369
+ function hashReviewableTree(repositoryRoot) {
370
+ const listed = spawnSync('git', ['-C', repositoryRoot, 'ls-files', '--cached', '--others', '--exclude-standard', '-z'], { encoding: 'utf8' });
371
+ if (listed.status !== 0) {
372
+ throw new Error('Unable to enumerate reviewable repository files.');
373
+ }
223
374
  const hash = createHash('sha256');
224
- for (const name of readdirSync(current).sort()) {
225
- if (current === repositoryRoot && name === '.git')
375
+ const paths = listed.stdout.split('\0').filter(Boolean).sort();
376
+ for (const relative of paths) {
377
+ const absolute = path.join(repositoryRoot, relative);
378
+ hash.update(`${relative}\0`);
379
+ if (!existsSync(absolute)) {
380
+ hash.update('missing');
226
381
  continue;
227
- const absolute = path.join(current, name);
228
- const relative = path.relative(repositoryRoot, absolute).split(path.sep).join('/');
382
+ }
229
383
  const stat = lstatSync(absolute);
230
- hash.update(`${relative}\0${stat.mode & 0o777}\0`);
384
+ hash.update(`${stat.mode & 0o777}\0`);
231
385
  if (stat.isSymbolicLink())
232
386
  hash.update(`link:${readlinkSync(absolute)}`);
233
- else if (stat.isDirectory())
234
- hash.update(hashTree(repositoryRoot, absolute));
235
387
  else if (stat.isFile())
236
388
  hash.update(readFileSync(absolute));
237
389
  }
@@ -280,6 +432,7 @@ function failedLaunch(repositoryRoot, command, processStatus, summary) {
280
432
  verifiedIsolation: false,
281
433
  command,
282
434
  processStatus,
435
+ timedOut: false,
283
436
  stderr: summary,
284
437
  before: seal,
285
438
  after: seal,