codex-workflow-v2 2.0.0-beta.13.8 → 2.0.0-beta.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 (281) hide show
  1. package/README.md +27 -388
  2. package/dist/reviewer-runtime-build.json +96 -32
  3. package/dist/src/alpha6/adoption.d.ts +2 -0
  4. package/dist/src/alpha6/adoption.js +22 -0
  5. package/dist/src/alpha6/adoption.js.map +1 -1
  6. package/dist/src/alpha6/captured-check-evidence.d.ts +51 -0
  7. package/dist/src/alpha6/captured-check-evidence.js +152 -0
  8. package/dist/src/alpha6/captured-check-evidence.js.map +1 -0
  9. package/dist/src/alpha6/component-owner.d.ts +15 -1
  10. package/dist/src/alpha6/component-owner.js +44 -2
  11. package/dist/src/alpha6/component-owner.js.map +1 -1
  12. package/dist/src/alpha6/corrective-decision-boundary.d.ts +4 -0
  13. package/dist/src/alpha6/corrective-decision-boundary.js +47 -0
  14. package/dist/src/alpha6/corrective-decision-boundary.js.map +1 -0
  15. package/dist/src/alpha6/downstream-proof.d.ts +1 -25
  16. package/dist/src/alpha6/downstream-proof.js +0 -171
  17. package/dist/src/alpha6/downstream-proof.js.map +1 -1
  18. package/dist/src/alpha6/failed-step-planning-recovery.d.ts +10 -0
  19. package/dist/src/alpha6/failed-step-planning-recovery.js +93 -0
  20. package/dist/src/alpha6/failed-step-planning-recovery.js.map +1 -0
  21. package/dist/src/alpha6/literal-test-invocation.d.ts +2 -0
  22. package/dist/src/alpha6/literal-test-invocation.js +106 -0
  23. package/dist/src/alpha6/literal-test-invocation.js.map +1 -0
  24. package/dist/src/alpha6/milestone.d.ts +2 -0
  25. package/dist/src/alpha6/milestone.js +10 -1
  26. package/dist/src/alpha6/milestone.js.map +1 -1
  27. package/dist/src/alpha6/navigation-dirty-carryover.d.ts +11 -0
  28. package/dist/src/alpha6/navigation-dirty-carryover.js +130 -0
  29. package/dist/src/alpha6/navigation-dirty-carryover.js.map +1 -0
  30. package/dist/src/alpha6/plan-integrity.js +7 -5
  31. package/dist/src/alpha6/plan-integrity.js.map +1 -1
  32. package/dist/src/alpha6/plan-risk.d.ts +2 -0
  33. package/dist/src/alpha6/plan-risk.js +10 -3
  34. package/dist/src/alpha6/plan-risk.js.map +1 -1
  35. package/dist/src/alpha6/remediation.d.ts +6 -21
  36. package/dist/src/alpha6/remediation.js +161 -476
  37. package/dist/src/alpha6/remediation.js.map +1 -1
  38. package/dist/src/alpha6/root-cause-replan-carryover.d.ts +4 -1
  39. package/dist/src/alpha6/root-cause-replan-carryover.js +29 -5
  40. package/dist/src/alpha6/root-cause-replan-carryover.js.map +1 -1
  41. package/dist/src/beta1/project-transaction.d.ts +3 -1
  42. package/dist/src/beta1/project-transaction.js +6 -2
  43. package/dist/src/beta1/project-transaction.js.map +1 -1
  44. package/dist/src/checks/runner.d.ts +26 -0
  45. package/dist/src/checks/runner.js +223 -0
  46. package/dist/src/checks/runner.js.map +1 -0
  47. package/dist/src/checks/task-sync.d.ts +10 -0
  48. package/dist/src/checks/task-sync.js +41 -0
  49. package/dist/src/checks/task-sync.js.map +1 -0
  50. package/dist/src/checks/worker.d.ts +1 -0
  51. package/dist/src/checks/worker.js +154 -0
  52. package/dist/src/checks/worker.js.map +1 -0
  53. package/dist/src/cli-actions.d.ts +2 -2
  54. package/dist/src/cli-actions.js +3 -15
  55. package/dist/src/cli-actions.js.map +1 -1
  56. package/dist/src/cli.js +14 -98
  57. package/dist/src/cli.js.map +1 -1
  58. package/dist/src/contracts.d.ts +35 -32
  59. package/dist/src/dependency-provenance.d.ts +2 -2
  60. package/dist/src/dependency-provenance.js +12 -69
  61. package/dist/src/dependency-provenance.js.map +1 -1
  62. package/dist/src/domain/base-sync-conflict.d.ts +13 -0
  63. package/dist/src/domain/base-sync-conflict.js +32 -0
  64. package/dist/src/domain/base-sync-conflict.js.map +1 -0
  65. package/dist/src/domain/step-start-admission.d.ts +4 -0
  66. package/dist/src/domain/step-start-admission.js +9 -0
  67. package/dist/src/domain/step-start-admission.js.map +1 -0
  68. package/dist/src/domain/virgin-registration.d.ts +3 -0
  69. package/dist/src/domain/virgin-registration.js +65 -0
  70. package/dist/src/domain/virgin-registration.js.map +1 -0
  71. package/dist/src/errors.d.ts +1 -1
  72. package/dist/src/errors.js.map +1 -1
  73. package/dist/src/gateway-handshake.js +0 -8
  74. package/dist/src/gateway-handshake.js.map +1 -1
  75. package/dist/src/git.d.ts +3 -1
  76. package/dist/src/git.js +41 -14
  77. package/dist/src/git.js.map +1 -1
  78. package/dist/src/graph.js +25 -3
  79. package/dist/src/graph.js.map +1 -1
  80. package/dist/src/index.d.ts +1 -0
  81. package/dist/src/lifecycle/corrective-replan.js +3 -3
  82. package/dist/src/lifecycle/corrective-replan.js.map +1 -1
  83. package/dist/src/navigation-actions.d.ts +9 -0
  84. package/dist/src/navigation-actions.js +72 -0
  85. package/dist/src/navigation-actions.js.map +1 -0
  86. package/dist/src/navigation-update-artifact.d.ts +5 -0
  87. package/dist/src/navigation-update-artifact.js +227 -0
  88. package/dist/src/navigation-update-artifact.js.map +1 -0
  89. package/dist/src/navigation-update.d.ts +39 -0
  90. package/dist/src/navigation-update.js +82 -0
  91. package/dist/src/navigation-update.js.map +1 -0
  92. package/dist/src/observation.js +52 -29
  93. package/dist/src/observation.js.map +1 -1
  94. package/dist/src/observed-routes.js +5 -6
  95. package/dist/src/observed-routes.js.map +1 -1
  96. package/dist/src/pending-review-update.d.ts +0 -13
  97. package/dist/src/pending-review-update.js +1 -6
  98. package/dist/src/pending-review-update.js.map +1 -1
  99. package/dist/src/reviewer.d.ts +1 -1
  100. package/dist/src/reviewer.js +20 -17
  101. package/dist/src/reviewer.js.map +1 -1
  102. package/dist/src/runtime.d.ts +3 -0
  103. package/dist/src/runtime.js +6 -0
  104. package/dist/src/runtime.js.map +1 -0
  105. package/dist/src/state/corrective-replan-executor.d.ts +10 -0
  106. package/dist/src/state/corrective-replan-executor.js +37 -1
  107. package/dist/src/state/corrective-replan-executor.js.map +1 -1
  108. package/dist/src/state/corrective-replan-public-schema.js +15 -2
  109. package/dist/src/state/corrective-replan-public-schema.js.map +1 -1
  110. package/dist/src/state/corrective-replan-public.js +6 -5
  111. package/dist/src/state/corrective-replan-public.js.map +1 -1
  112. package/dist/src/state/corrective-replan-transaction.d.ts +1 -0
  113. package/dist/src/state/corrective-replan-transaction.js +12 -11
  114. package/dist/src/state/corrective-replan-transaction.js.map +1 -1
  115. package/dist/src/state/corrective-yield-executor.js +2 -2
  116. package/dist/src/state/corrective-yield-executor.js.map +1 -1
  117. package/dist/src/state/corrective-yield-transaction.d.ts +1 -0
  118. package/dist/src/state/corrective-yield-transaction.js +11 -10
  119. package/dist/src/state/corrective-yield-transaction.js.map +1 -1
  120. package/dist/src/state/lock.d.ts +4 -0
  121. package/dist/src/state/lock.js +21 -0
  122. package/dist/src/state/lock.js.map +1 -1
  123. package/dist/src/version.d.ts +1 -1
  124. package/dist/src/version.js +1 -1
  125. package/dist/src/version.js.map +1 -1
  126. package/dist/src/workflow-blocker-route.d.ts +8 -0
  127. package/dist/src/workflow-blocker-route.js +106 -0
  128. package/dist/src/workflow-blocker-route.js.map +1 -0
  129. package/dist/src/workflow.d.ts +48 -63
  130. package/dist/src/workflow.js +698 -1470
  131. package/dist/src/workflow.js.map +1 -1
  132. package/docs/autonomy-guardrails.md +26 -304
  133. package/docs/decisions.md +14 -112
  134. package/docs/development-flow.md +35 -238
  135. package/docs/project-memory.md +31 -50
  136. package/docs/release-app-evidence.md +190 -0
  137. package/docs/release.md +95 -363
  138. package/docs/updating-existing-project.md +19 -717
  139. package/package.json +11 -13
  140. package/plugins/codex-workflow-gateway/.codex-plugin/plugin.json +2 -2
  141. package/plugins/codex-workflow-gateway/references/chat-dispatch.md +73 -197
  142. package/plugins/codex-workflow-gateway/references/codebase-memory-routing.md +57 -0
  143. package/plugins/codex-workflow-gateway/references/protocol.md +42 -445
  144. package/plugins/codex-workflow-gateway/scripts/chat-dispatch.mjs +7 -1
  145. package/plugins/codex-workflow-gateway/scripts/chat-model-policy.mjs +10 -8
  146. package/plugins/codex-workflow-gateway/scripts/chat-registry.mjs +23 -5
  147. package/plugins/codex-workflow-gateway/skills/codex-workflow-gateway/SKILL.md +66 -740
  148. package/references/state-machine.md +4 -4
  149. package/roles/technical-planner.md +1 -1
  150. package/schemas/corrective-decision-event.schema.json +3 -1
  151. package/schemas/project-knowledge-map.schema.json +3 -1
  152. package/schemas/remediation-event.schema.json +10 -1
  153. package/schemas/task.schema.json +46 -2
  154. package/schemas/transition-payloads.schema.json +16 -1
  155. package/src/alpha6/adoption.ts +1123 -0
  156. package/src/alpha6/captured-check-evidence.ts +132 -0
  157. package/src/alpha6/check-support-anchor.ts +128 -0
  158. package/src/alpha6/component-owner.ts +168 -0
  159. package/src/alpha6/corrective-decision-boundary.ts +39 -0
  160. package/src/alpha6/downstream-proof.ts +520 -0
  161. package/src/alpha6/failed-step-planning-recovery.ts +88 -0
  162. package/src/alpha6/handoff.ts +1443 -0
  163. package/src/alpha6/journal.ts +473 -0
  164. package/src/alpha6/literal-test-invocation.ts +84 -0
  165. package/src/alpha6/mechanical-feasibility.ts +488 -0
  166. package/src/alpha6/milestone.ts +2192 -0
  167. package/src/alpha6/navigation-dirty-carryover.ts +154 -0
  168. package/src/alpha6/npm-check-contract.ts +47 -0
  169. package/src/alpha6/plan-integrity.ts +298 -0
  170. package/src/alpha6/plan-risk.ts +1480 -0
  171. package/src/alpha6/preexecution-replan.ts +187 -0
  172. package/src/alpha6/remediation-cause.ts +98 -0
  173. package/src/alpha6/remediation.ts +2438 -0
  174. package/src/alpha6/review.ts +1198 -0
  175. package/src/alpha6/root-cause-replan-carryover.ts +491 -0
  176. package/src/alpha6/store-sidecars.ts +335 -0
  177. package/src/alpha7/autonomy.ts +411 -0
  178. package/src/alpha7/corrective-recovery.ts +1332 -0
  179. package/src/artifacts.ts +130 -0
  180. package/src/beta1/project-transaction.ts +355 -0
  181. package/src/change-explanation.ts +153 -0
  182. package/src/checks/runner.ts +245 -0
  183. package/src/checks/task-sync.ts +41 -0
  184. package/src/checks/worker.ts +149 -0
  185. package/src/cli-actions.ts +107 -0
  186. package/src/cli.ts +1457 -0
  187. package/src/contracts.ts +1494 -0
  188. package/src/credential-output.ts +89 -0
  189. package/src/credential-transport.ts +215 -0
  190. package/src/delegation.ts +190 -0
  191. package/src/dependency-provenance.ts +472 -0
  192. package/src/diagnostics.ts +93 -0
  193. package/src/domain/base-sync-conflict.ts +35 -0
  194. package/src/domain/completed-step-carryover.ts +76 -0
  195. package/src/domain/discovery.ts +27 -0
  196. package/src/domain/plan-semantics.ts +58 -0
  197. package/src/domain/step-start-admission.ts +10 -0
  198. package/src/domain/validation.ts +177 -0
  199. package/src/domain/virgin-registration.ts +46 -0
  200. package/src/errors.ts +24 -0
  201. package/src/fs-utils.ts +61 -0
  202. package/src/gateway-handshake.ts +95 -0
  203. package/src/git.ts +183 -0
  204. package/src/graph.ts +342 -0
  205. package/src/historical-step-provenance.ts +136 -0
  206. package/src/index.ts +23 -0
  207. package/src/lifecycle/canonical-hash.ts +28 -0
  208. package/src/lifecycle/catalog.ts +202 -0
  209. package/src/lifecycle/compiler-inspection.ts +29 -0
  210. package/src/lifecycle/core-static-readiness.ts +132 -0
  211. package/src/lifecycle/corrective-replan-authority.ts +136 -0
  212. package/src/lifecycle/corrective-replan-binding-manifest.ts +51 -0
  213. package/src/lifecycle/corrective-replan-credential-core.ts +408 -0
  214. package/src/lifecycle/corrective-replan-credential-schema.ts +54 -0
  215. package/src/lifecycle/corrective-replan-credentials.ts +48 -0
  216. package/src/lifecycle/corrective-replan.ts +843 -0
  217. package/src/lifecycle/evaluator.ts +48 -0
  218. package/src/lifecycle/fingerprint.ts +488 -0
  219. package/src/lifecycle/immutable.ts +8 -0
  220. package/src/lifecycle/implementation-table.ts +118 -0
  221. package/src/lifecycle/index.ts +8 -0
  222. package/src/lifecycle/schema-artifact.ts +263 -0
  223. package/src/lifecycle/semantic-registry.ts +572 -0
  224. package/src/lifecycle/types.ts +838 -0
  225. package/src/memory.ts +273 -0
  226. package/src/migration.ts +161 -0
  227. package/src/navigation-actions.ts +70 -0
  228. package/src/navigation-update-artifact.ts +198 -0
  229. package/src/navigation-update.ts +121 -0
  230. package/src/observation.ts +225 -0
  231. package/src/observed-routes.ts +660 -0
  232. package/src/operational-contract.ts +125 -0
  233. package/src/pending-review-update.ts +175 -0
  234. package/src/repository.ts +99 -0
  235. package/src/reviewer.ts +1879 -0
  236. package/src/runtime.ts +6 -0
  237. package/src/state/corrective-replan-executor.ts +818 -0
  238. package/src/state/corrective-replan-public-schema.ts +83 -0
  239. package/src/state/corrective-replan-public.ts +908 -0
  240. package/src/state/corrective-replan-transaction.ts +949 -0
  241. package/src/state/corrective-yield-executor.ts +327 -0
  242. package/src/state/corrective-yield-transaction.ts +730 -0
  243. package/src/state/lock.ts +902 -0
  244. package/src/state/store.ts +567 -0
  245. package/src/transition-core.ts +330 -0
  246. package/src/ulid.ts +24 -0
  247. package/src/version.ts +2 -0
  248. package/src/workflow-blocker-route.ts +109 -0
  249. package/src/workflow.ts +10172 -0
  250. package/docs/alpha7.1-implementation-brief.md +0 -268
  251. package/docs/alpha7.2-corrective-context-refresh-brief.md +0 -484
  252. package/docs/alpha7.2.1-remediation-recovery-brief.md +0 -86
  253. package/docs/beta1-stabilization-brief.md +0 -165
  254. package/docs/beta11-plan-integrity-recovery-brief.md +0 -38
  255. package/docs/beta13.2-signal-review-recovery.md +0 -38
  256. package/docs/beta2-initial-assembly-navigation-brief.md +0 -616
  257. package/docs/change-model.md +0 -118
  258. package/docs/delegated-approval.md +0 -254
  259. package/docs/lifecycle/state-machine-stabilization.md +0 -641
  260. package/docs/pdf/README.md +0 -24
  261. package/docs/pdf/codex-workflow-v2-architecture-ru.pdf +0 -0
  262. package/docs/pdf/codex-workflow-v2-chat-only-guide-ru.pdf +0 -0
  263. package/docs/pdf/codex-workflow-v2-technical-reference-ru.pdf +0 -0
  264. package/docs/pdf/requirements.txt +0 -1
  265. package/docs/pdf/sources/codex-workflow-v2-architecture-ru.md +0 -478
  266. package/docs/pdf/sources/codex-workflow-v2-chat-only-guide-ru.md +0 -508
  267. package/docs/pdf/sources/codex-workflow-v2-technical-reference-ru.md +0 -778
  268. package/docs/pending-review-update.md +0 -15
  269. package/docs/problem-briefs/01-pre-implementation-integrity.md +0 -482
  270. package/docs/problem-briefs/02-minimal-step-integrity.md +0 -411
  271. package/docs/problem-briefs/03-minimal-agent-context-integrity.md +0 -358
  272. package/docs/problem-briefs/04-task-dependency-and-structural-replacement-integrity.md +0 -573
  273. package/docs/problem-briefs/BRIEF-TEMPLATE.md +0 -56
  274. package/docs/problem-briefs/README.md +0 -120
  275. package/docs/problem-briefs/evidence/p01-mechanical-feasibility-corpus.md +0 -90
  276. package/docs/problem-briefs/evidence/signal-v4-pre-m3-replay.md +0 -246
  277. package/docs/split-required-recovery.md +0 -47
  278. package/docs/stable-release-defect-register.md +0 -730
  279. package/docs/validation-report.md +0 -182
  280. package/scripts/generate-pdf-docs.py +0 -524
  281. package/scripts/run-pdf-docs.mjs +0 -62
@@ -0,0 +1,408 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { types as utilTypes } from 'node:util';
3
+ import { correctiveReplanBindingManifest } from './corrective-replan-binding-manifest.js';
4
+ import { installedAuthoritySemanticBindings } from './corrective-replan-authority.js';
5
+ import { correctiveReplanCredentialSchemaValidators } from './corrective-replan-credential-schema.js';
6
+ import { hashCanonical } from './fingerprint.js';
7
+ import { deepFreeze } from './immutable.js';
8
+ import { LIFECYCLE_EPOCH } from './types.js';
9
+ type JsonRecord = Record<string, unknown>;
10
+ type Reason = 'schema' | 'binding' | 'authority' | 'sod' | 'time' | 'integrity' | 'provenance';
11
+ type Issue = Readonly<{ issueId: string; path: string; reasonClass: Reason }>;
12
+ type Result<T> = Readonly<{ ok: true; value: Readonly<T>; issues: readonly [] }>
13
+ | Readonly<{ ok: false; value: null; issues: readonly Issue[]; reportHash: string }>;
14
+ type Verification<T> = Readonly<{ valid: true; projection: Readonly<T>; issues: readonly []; reportHash: string }>
15
+ | Readonly<{ valid: false; projection: null; issues: readonly Issue[]; reportHash: string }>;
16
+ declare const planBrand: unique symbol; declare const challengeBrand: unique symbol;
17
+ declare const confirmationBrand: unique symbol; declare const receiptBrand: unique symbol; declare const eventBrand: unique symbol;
18
+ export type PlanValidationHandle = Readonly<{ [planBrand]: never }>;
19
+ export type HumanChallengeHandle = Readonly<{ [challengeBrand]: never }>;
20
+ export type VerifiedConfirmationHandle = Readonly<{ [confirmationBrand]: never }>;
21
+ export type ReceiptHandle = Readonly<{ [receiptBrand]: never }>;
22
+ export type StoredPlanValidationEventHandle = Readonly<{ [eventBrand]: never }>;
23
+ export interface CorrectiveReplanCredentialCorePorts {
24
+ readonly snapshotSource: { readCorrectiveReplanSnapshot(taskId: string): unknown };
25
+ readonly coreClock: { nowMs(): number };
26
+ readonly idSource: { nextId(kind: 'plan-validation-attestation' | 'human-challenge' | 'receipt' | 'plan-validation-event'): string };
27
+ readonly challengeCodeSource: { issueConfirmationCode(): string };
28
+ readonly validationEventTailSource: { readPlanValidationTail(taskId: string): unknown };
29
+ }
30
+ export interface CorrectiveReplanCredentialKernel {
31
+ issuePlanValidation(input: unknown): Result<JsonRecord>; issueHumanChallenge(input: unknown): Result<JsonRecord>; confirmHuman(input: unknown): Result<JsonRecord>; issueReceipt(input: unknown): Result<JsonRecord>;
32
+ verifyReceipt(input: unknown): Verification<JsonRecord>; materializeStoredEvent(input: unknown): Result<JsonRecord>; verifyStoredEvent(input: unknown): Verification<JsonRecord>;
33
+ }
34
+ export interface CredentialFunctionBinding { readonly id: string; readonly version: 1; readonly kind: 'materializer' | 'verifier';
35
+ readonly implementationId: `implementation.${string}`; readonly implementationVersion: 1; readonly wiring: 'invoked';
36
+ readonly callable: (issuer: unknown, input: unknown) => unknown }
37
+ interface KernelRecord { readonly ports: CapturedPorts; readonly plans: WeakMap<object, PlanRecord>;
38
+ readonly challenges: WeakMap<object, ChallengeRecord>; readonly confirmations: WeakMap<object, ConfirmationRecord>;
39
+ readonly receipts: WeakMap<object, ReceiptRecord>; readonly events: WeakMap<object, EventRecord>;
40
+ readonly preparations: Map<string, PreparationRecord>; readonly preparationGeneration: { value: number };
41
+ readonly challenged: WeakSet<object>; readonly confirmed: WeakSet<object>;
42
+ readonly receipted: WeakSet<object>; readonly evented: WeakSet<object> }
43
+ interface PreparationRecord { readonly generation: number; readonly status: 'reserved' | 'active'; readonly expiresAtMs: number }
44
+ interface CapturedPorts { readSnapshot(taskId: string): unknown; now(): number; nextId(kind: Parameters<CorrectiveReplanCredentialCorePorts['idSource']['nextId']>[0]): string; issueCode(): string; readTail(taskId: string): unknown }
45
+ interface PlanRecord { readonly preparationKey: string; readonly generation: number; readonly snapshot: JsonRecord; readonly snapshotBindingHash: string; readonly binding: JsonRecord; readonly attestation: JsonRecord }
46
+ interface ChallengeRecord { readonly plan: PlanRecord; readonly challenge: JsonRecord }
47
+ interface ConfirmationRecord { readonly challenge: ChallengeRecord; readonly projection: JsonRecord }
48
+ interface ReceiptRecord { readonly plan: PlanRecord; readonly confirmation: ConfirmationRecord; readonly receipt: JsonRecord }
49
+ interface EventRecord { readonly receipt: ReceiptRecord; readonly event: JsonRecord }
50
+ const kernels = new WeakMap<object, KernelRecord>();
51
+ const TTL = 900_000; const MAX_SAFE = Number.MAX_SAFE_INTEGER;
52
+ const MALFORMED = Symbol('malformed'); const LIMIT = Symbol('limit');
53
+ export function createCorrectiveReplanCredentialKernel(ports: CorrectiveReplanCredentialCorePorts): CorrectiveReplanCredentialKernel {
54
+ if (!exactKeys(ports, ['snapshotSource', 'coreClock', 'idSource', 'challengeCodeSource', 'validationEventTailSource']))
55
+ throw new TypeError('Invalid corrective replan Core ports.');
56
+ const captured: CapturedPorts = deepFreeze({
57
+ readSnapshot: ports.snapshotSource.readCorrectiveReplanSnapshot.bind(ports.snapshotSource),
58
+ now: ports.coreClock.nowMs.bind(ports.coreClock), nextId: ports.idSource.nextId.bind(ports.idSource),
59
+ issueCode: ports.challengeCodeSource.issueConfirmationCode.bind(ports.challengeCodeSource),
60
+ readTail: ports.validationEventTailSource.readPlanValidationTail.bind(ports.validationEventTailSource),
61
+ });
62
+ const issuer = Object.freeze(Object.create(null)) as object;
63
+ kernels.set(issuer, { ports: captured, plans: new WeakMap(), challenges: new WeakMap(), confirmations: new WeakMap(),
64
+ receipts: new WeakMap(), events: new WeakMap(), preparations: new Map(), preparationGeneration: { value: 0 },
65
+ challenged: new WeakSet(), confirmed: new WeakSet(), receipted: new WeakSet(), evented: new WeakSet() });
66
+ return deepFreeze({
67
+ issuePlanValidation: (input: unknown) => totalResult(() => issuePlanValidation(issuer, input)),
68
+ issueHumanChallenge: (input: unknown) => totalResult(() => issueHumanChallenge(issuer, input)),
69
+ confirmHuman: (input: unknown) => totalResult(() => confirmHuman(issuer, input)),
70
+ issueReceipt: (input: unknown) => totalResult(() => issueReceipt(issuer, input)),
71
+ verifyReceipt: (input: unknown) => totalVerification(() => verifyReceipt(issuer, input)),
72
+ materializeStoredEvent: (input: unknown) => totalResult(() => materializeStoredEvent(issuer, input)),
73
+ verifyStoredEvent: (input: unknown) => totalVerification(() => verifyStoredEvent(issuer, input)),
74
+ });
75
+ }
76
+ const issuePlanValidation = (issuer: unknown, input: unknown): Result<JsonRecord> => {
77
+ const kernel = kernels.get(object(issuer)); if (!kernel) return rejected('credential.provenance.invalid', '/', 'provenance');
78
+ const owned = copyOwnedJson(input); if (owned === LIMIT) return rejected('credential.operation.limit-exceeded', '/', 'schema');
79
+ if (owned === MALFORMED || !exactKeys(owned, ['taskId', 'draft'])) return rejected('credential.operation.malformed', '/', 'schema');
80
+ const envelope = owned;
81
+ if (!canonicalId(envelope.taskId) || !exactDraft(envelope.draft)) return rejected('credential.plan-validation.input-invalid', '/draft', 'schema');
82
+ const now = safeTime(kernel.ports.now()); if (now === null) return rejected('credential.time.invalid', '/coreClock', 'time');
83
+ const loaded = loadCanonicalSnapshot(kernel, envelope.taskId); if ('issueId' in loaded) return rejected(loaded.issueId, loaded.path, loaded.reasonClass);
84
+ const { snapshot, snapshotBindingHash } = loaded;
85
+ const base = record(snapshot.baseValues); const expected = record(snapshot.validationExpectation); const draft = record(envelope.draft);
86
+ for (const key of ['requirements', 'acceptance', 'architecture'] as const)
87
+ if (!same(draft[key], expected[key])) return rejected('credential.plan-validation.snapshot-mismatch', `/draft/${key}`, 'binding');
88
+ const validatorContext = record(draft.validatorContext); const plannerContextHash = get(expected, '/plannerContext/contextHash');
89
+ if (validatorContext.contextHash === plannerContextHash) return rejected('credential.plan-validation.context-invalid', '/draft/validatorContext', 'binding');
90
+ if (base.planAuthorIdentityHash === base.planValidatorIdentityHash)
91
+ return rejected('credential.plan-validation.sod-invalid', '/snapshot/baseValues/planValidatorIdentityHash', 'sod');
92
+ const findings = array(draft.findings); const dispositions = array(draft.dispositions);
93
+ if (!keyedBijection(findings, dispositions)) return rejected('credential.plan-validation.findings-invalid', '/draft/findings', 'binding');
94
+ const plannerCaptured = safeTime(get(expected, '/plannerContext/capturedAtMs'));
95
+ if (plannerCaptured === null || plannerCaptured > now) return rejected('credential.plan-validation.context-time-invalid', '/snapshot/validationExpectation/plannerContext/capturedAtMs', 'time');
96
+ const preparationKey = hashCanonical({ family: 'corrective-replan', snapshotBindingHash, transitionId: base.transitionId,
97
+ taskId: base.taskId, revision: base.revision, candidatePlanHash: base.candidatePlanHash, candidateStepSetHash: base.candidateStepSetHash });
98
+ const previous = kernel.preparations.get(preparationKey);
99
+ if (previous && now < previous.expiresAtMs) return rejected('credential.preparation.duplicate', '/taskId', 'provenance');
100
+ if (previous) kernel.preparations.delete(preparationKey);
101
+ const generation = ++kernel.preparationGeneration.value;
102
+ kernel.preparations.set(preparationKey, { generation, status: 'reserved', expiresAtMs: now + TTL }); let committed = false;
103
+ try {
104
+ const sortedFindings = sortRows(findings); const sortedDispositions = sortRows(dispositions);
105
+ const freshContext = { sourceSnapshotHash: snapshotBindingHash, plannerContextHash, validatorContextHash: validatorContext.contextHash, passed: true };
106
+ const validation = { domain: 'codex-workflow/plan-validation/v1', source: expected.source, candidate: expected.candidate,
107
+ requirements: draft.requirements, acceptance: draft.acceptance, architecture: draft.architecture,
108
+ planAuthor: expected.planAuthor, plannerContext: expected.plannerContext, validator: expected.validator,
109
+ validatorContext: { contextHash: validatorContext.contextHash, capturedAtMs: now }, freshContext,
110
+ passed: true, findings: sortedFindings, dispositions: sortedDispositions, validatedAtMs: now, expiresAtMs: now + TTL };
111
+ const planValidationHash = hashCanonical(validation); const values: JsonRecord = { ...clone(base), planValidationHash };
112
+ if (!canonicalManifestValues(values, true)) return rejected('credential.binding.values-invalid', '/binding/values', 'binding');
113
+ const capability = { id: 'capability.task.corrective-replan', version: 1,
114
+ issuer: { kind: 'human', identityHash: values.humanPrincipalIdentityHash }, source: 'human-confirmation',
115
+ scope: { transitionId: values.transitionId, taskId: values.taskId, candidatePlanHash: values.candidatePlanHash,
116
+ manifestSha256: correctiveReplanBindingManifest.manifestSha256 }, delegation: 'forbidden' };
117
+ const bindingBase = { schemaVersion: 1, manifestRef: { id: correctiveReplanBindingManifest.id, version: 1 },
118
+ manifestSha256: correctiveReplanBindingManifest.manifestSha256, values, capability };
119
+ const binding = { ...bindingBase, bindingSha256: hashCanonical(bindingBase) };
120
+ if (!schema('schema.corrective-replan-binding', binding)) return rejected('credential.binding.invalid', '/binding', 'schema');
121
+ const attestationBase = { schemaVersion: 1, attestationId: safeId(kernel.ports.nextId('plan-validation-attestation')),
122
+ bindingSha256: binding.bindingSha256, source: validation.source, candidate: validation.candidate,
123
+ requirements: validation.requirements, acceptance: validation.acceptance, architecture: validation.architecture,
124
+ planAuthor: validation.planAuthor, plannerContext: validation.plannerContext, validator: validation.validator,
125
+ validatorContext: validation.validatorContext, freshContext, passed: true,
126
+ findings: sortedFindings, dispositions: sortedDispositions, validatedAtMs: now, expiresAtMs: now + TTL };
127
+ if (!attestationBase.attestationId) return rejected('credential.id.invalid', '/idSource', 'integrity');
128
+ const attestation = { ...attestationBase, attestationHash: hashCanonical(attestationBase) };
129
+ if (!schema('schema.corrective-replan-plan-validation-attestation', attestation)) return rejected('credential.plan-validation.invalid', '/attestation', 'schema');
130
+ const handle = opaque(); const recordValue = deepFreeze({ preparationKey, generation, snapshot, snapshotBindingHash, binding, attestation });
131
+ kernel.plans.set(handle, recordValue); kernel.preparations.set(preparationKey, { generation, status: 'active', expiresAtMs: now + TTL }); committed = true;
132
+ return accepted({ handle: handle as PlanValidationHandle, binding, attestation });
133
+ } finally { if (!committed && kernel.preparations.get(preparationKey)?.generation === generation) kernel.preparations.delete(preparationKey); }
134
+ };
135
+ const issueHumanChallenge = (issuer: unknown, input: unknown): Result<JsonRecord> => {
136
+ const kernel = kernels.get(object(issuer)); if (!kernel) return rejected('credential.provenance.invalid', '/', 'provenance');
137
+ if (!exactKeys(input, ['planValidation'])) return rejected('credential.envelope.invalid', '/', 'schema');
138
+ const handle = object((input as JsonRecord).planValidation); const plan = kernel.plans.get(handle);
139
+ if (!plan) return rejected('credential.provenance.invalid', '/planValidation', 'provenance');
140
+ if (!activePreparation(kernel, plan)) return rejected('credential.preparation.superseded', '/planValidation', 'provenance');
141
+ if (kernel.challenged.has(handle)) return rejected('credential.provenance.invalid', '/planValidation', 'provenance');
142
+ const now = safeTime(kernel.ports.now()); if (now === null) return rejected('credential.time.invalid', '/coreClock', 'time');
143
+ if (now < number(plan.attestation.validatedAtMs)) return rejected('credential.challenge.time-invalid', '/coreClock', 'time');
144
+ const expiresAtMs = Math.min(now + TTL, number(plan.attestation.expiresAtMs));
145
+ if (now >= expiresAtMs) return rejected('credential.challenge.expired', '/planValidation', 'time');
146
+ const challengeId = safeId(kernel.ports.nextId('human-challenge'));
147
+ if (!challengeId) return rejected('credential.challenge.source-invalid', '/idSource', 'integrity');
148
+ const code = kernel.ports.issueCode(); if (typeof code !== 'string' || !/^[0-9]{6}$/.test(code)) return rejected('credential.challenge.source-invalid', '/challengeCodeSource', 'integrity');
149
+ const core = { schemaVersion: 1, challengeId, owner: 'workflow-core', bindingSha256: plan.binding.bindingSha256,
150
+ codeSha256: sha(code), issuedAtMs: now, expiresAtMs };
151
+ const challenge = deepFreeze({ ...core, challengeHash: hashCanonical(core) }); const challengeHandle = opaque();
152
+ kernel.challenges.set(challengeHandle, deepFreeze({ plan, challenge })); kernel.challenged.add(handle);
153
+ return accepted({ handle: challengeHandle as HumanChallengeHandle,
154
+ delivery: { kind: 'corrective-replan-human-challenge-delivery', version: 1, challengeId, confirmationCode: code, expiresAtMs } });
155
+ };
156
+ const confirmHuman = (issuer: unknown, input: unknown): Result<JsonRecord> => {
157
+ const kernel = kernels.get(object(issuer)); if (!kernel) return rejected('credential.provenance.invalid', '/', 'provenance');
158
+ if (!exactKeys(input, ['challenge', 'confirmation'])) return rejected('credential.envelope.invalid', '/', 'schema');
159
+ const confirmation = (input as JsonRecord).confirmation;
160
+ if (!schema('schema.corrective-replan-human-confirmation-input', confirmation)) return rejected('credential.confirmation.input-invalid', '/confirmation', 'schema');
161
+ const challengeHandle = object((input as JsonRecord).challenge); const challenge = kernel.challenges.get(challengeHandle);
162
+ if (!challenge) return rejected('credential.provenance.invalid', '/challenge', 'provenance');
163
+ if (!activePreparation(kernel, challenge.plan)) return rejected('credential.preparation.superseded', '/challenge', 'provenance');
164
+ if (kernel.confirmed.has(challengeHandle)) return rejected('credential.provenance.invalid', '/challenge', 'provenance');
165
+ const candidate = confirmation as JsonRecord; const now = safeTime(kernel.ports.now());
166
+ if (now === null) return rejected('credential.time.invalid', '/coreClock', 'time');
167
+ const validatedAt = number(challenge.plan.attestation.validatedAtMs); const issuedAt = number(challenge.challenge.issuedAtMs);
168
+ const expiresAt = number(challenge.challenge.expiresAtMs);
169
+ if (now >= expiresAt) return rejected('credential.confirmation.expired', '/coreClock', 'time');
170
+ if (now < validatedAt || now < issuedAt) return rejected('credential.confirmation.time-invalid', '/coreClock', 'time');
171
+ if (candidate.challengeId !== challenge.challenge.challengeId || sha(string(candidate.confirmationCode)) !== challenge.challenge.codeSha256)
172
+ return rejected('credential.confirmation.invalid', '/confirmation/confirmationCode', 'integrity');
173
+ const projection = { challengeId: challenge.challenge.challengeId, challengeHash: challenge.challenge.challengeHash,
174
+ bindingSha256: challenge.plan.binding.bindingSha256,
175
+ humanPrincipalIdentityHash: get(challenge.plan.binding, '/values/humanPrincipalIdentityHash'), confirmedAtMs: now };
176
+ const handle = opaque(); kernel.confirmations.set(handle, deepFreeze({ challenge, projection })); kernel.confirmed.add(challengeHandle);
177
+ return accepted({ handle: handle as VerifiedConfirmationHandle, projection });
178
+ };
179
+ const issueReceipt = (issuer: unknown, input: unknown): Result<JsonRecord> => {
180
+ const kernel = kernels.get(object(issuer)); if (!kernel) return rejected('credential.provenance.invalid', '/', 'provenance');
181
+ if (!exactKeys(input, ['planValidation', 'confirmation'])) return rejected('credential.envelope.invalid', '/', 'schema');
182
+ const plan = kernel.plans.get(object((input as JsonRecord).planValidation));
183
+ const confirmationHandle = object((input as JsonRecord).confirmation); const confirmation = kernel.confirmations.get(confirmationHandle);
184
+ if (!plan || !confirmation || confirmation.challenge.plan !== plan) return rejected('credential.provenance.invalid', '/', 'provenance');
185
+ if (!activePreparation(kernel, plan)) return rejected('credential.preparation.superseded', '/planValidation', 'provenance');
186
+ if (kernel.receipted.has(confirmationHandle)) return rejected('credential.provenance.invalid', '/', 'provenance');
187
+ const freshness = receiptFreshnessIssue(kernel, plan); if (freshness) return rejected(freshness.issueId, freshness.path, freshness.reasonClass);
188
+ const now = safeTime(kernel.ports.now()); if (now === null) return rejected('credential.time.invalid', '/coreClock', 'time');
189
+ const confirmedAt = number(confirmation.projection.confirmedAtMs); const validatedAt = number(plan.attestation.validatedAtMs);
190
+ const expiresAtMs = Math.min(number(plan.attestation.expiresAtMs), number(confirmation.challenge.challenge.expiresAtMs));
191
+ if (validatedAt > confirmedAt || confirmedAt > now || now >= expiresAtMs) return rejected('credential.receipt.time-invalid', '/coreClock', 'time');
192
+ const values = record(plan.binding.values); const author = values.planAuthorIdentityHash;
193
+ if (!authorityPassed('authority-role-evaluator.corrective-replan.eligible-role', {
194
+ actorIdentityHash: values.actorIdentityHash, actorRole: values.actorRole,
195
+ eligibleRoles: ['delivery-coordinator', 'technical-planner'],
196
+ })) return rejected('credential.receipt.role-invalid', '/binding/values/actorRole', 'authority');
197
+ if (!authorityPassed('identity-comparator.corrective-replan.author-validator', {
198
+ leftIdentityHash: author, rightIdentityHash: values.planValidatorIdentityHash,
199
+ }) || !authorityPassed('identity-comparator.corrective-replan.author-risk-auditor', {
200
+ leftIdentityHash: author, rightIdentityHash: values.riskAuditorIdentityHash,
201
+ }) || !authorityPassed('identity-comparator.corrective-replan.author-human-principal', {
202
+ leftIdentityHash: author, rightIdentityHash: values.humanPrincipalIdentityHash,
203
+ }))
204
+ return rejected('credential.receipt.sod-invalid', '/binding/values', 'sod');
205
+ const snapshotGrant = record(plan.snapshot.priorPlanAuthorization); const receiptId = safeId(kernel.ports.nextId('receipt'));
206
+ if (!receiptId || snapshotGrant.requiredDisposition !== 'superseded') return rejected('credential.receipt.source-invalid', '/snapshot/priorPlanAuthorization', 'authority');
207
+ const validation = { attestationId: plan.attestation.attestationId, attestationHash: plan.attestation.attestationHash,
208
+ planValidationHash: values.planValidationHash, snapshotBindingHash: plan.snapshotBindingHash, planAuthorIdentityHash: values.planAuthorIdentityHash,
209
+ planValidatorIdentityHash: values.planValidatorIdentityHash, findingsHash: hashCanonical(plan.attestation.findings),
210
+ dispositionsHash: hashCanonical(plan.attestation.dispositions), validatedAtMs: plan.attestation.validatedAtMs,
211
+ expiresAtMs: plan.attestation.expiresAtMs };
212
+ const base = { schemaVersion: 1, receiptId, domain: 'codex-workflow/corrective-replan-receipt/v1',
213
+ binding: plan.binding, validation, audit: { riskAuditHash: values.riskAuditHash, riskAuditorIdentityHash: values.riskAuditorIdentityHash },
214
+ human: { challengeId: confirmation.projection.challengeId, challengeHash: confirmation.projection.challengeHash,
215
+ humanPrincipalIdentityHash: confirmation.projection.humanPrincipalIdentityHash, confirmedAtMs: confirmation.projection.confirmedAtMs },
216
+ supersession: { priorGrantHash: snapshotGrant.grantHash, disposition: 'superseded' },
217
+ issuedAtMs: now, expiresAtMs };
218
+ const withDomain = { ...base, domainHash: hashCanonical(base) }; const receipt = deepFreeze({ ...withDomain, receiptHash: hashCanonical(withDomain) });
219
+ if (!schema('schema.corrective-replan-receipt', receipt)) return rejected('credential.receipt.invalid', '/receipt', 'schema');
220
+ const handle = opaque(); kernel.receipts.set(handle, deepFreeze({ plan, confirmation, receipt })); kernel.receipted.add(confirmationHandle);
221
+ return accepted({ handle: handle as ReceiptHandle, receipt });
222
+ };
223
+ const verifyReceipt = (issuer: unknown, input: unknown): Verification<JsonRecord> => {
224
+ const kernel = kernels.get(object(issuer)); if (!kernel) return verificationRejected('credential.provenance.invalid', '/', 'provenance');
225
+ if (!exactKeys(input, ['receipt', 'candidate'])) return verificationRejected('credential.envelope.invalid', '/', 'schema');
226
+ const recordValue = kernel.receipts.get(object((input as JsonRecord).receipt)); if (!recordValue) return verificationRejected('credential.provenance.invalid', '/receipt', 'provenance');
227
+ const candidate = (input as JsonRecord).candidate;
228
+ if (!schema('schema.corrective-replan-receipt', candidate)) return verificationRejected('credential.receipt.invalid', '/candidate', 'schema');
229
+ if (!same(candidate, recordValue.receipt)) return verificationRejected('credential.receipt.mismatch', '/candidate', 'integrity');
230
+ const freshness = receiptFreshnessIssue(kernel, recordValue.plan); if (freshness) return verificationRejected(freshness.issueId, freshness.path, freshness.reasonClass);
231
+ const now = safeTime(kernel.ports.now()); if (now === null) return verificationRejected('credential.time.invalid', '/coreClock', 'time');
232
+ if (now < number(recordValue.receipt.issuedAtMs)) return verificationRejected('credential.receipt.time-invalid', '/coreClock', 'time');
233
+ if (now >= number(recordValue.receipt.expiresAtMs)) return verificationRejected('credential.receipt.expired', '/coreClock', 'time');
234
+ return verified(recordValue.receipt);
235
+ };
236
+ const materializeStoredEvent = (issuer: unknown, input: unknown): Result<JsonRecord> => {
237
+ const kernel = kernels.get(object(issuer)); if (!kernel) return rejected('credential.provenance.invalid', '/', 'provenance');
238
+ if (!exactKeys(input, ['receipt'])) return rejected('credential.envelope.invalid', '/', 'schema');
239
+ const handle = object((input as JsonRecord).receipt); const receipt = kernel.receipts.get(handle);
240
+ if (!receipt || kernel.evented.has(handle)) return rejected('credential.provenance.invalid', '/receipt', 'provenance');
241
+ const now = safeTime(kernel.ports.now()); if (now === null) return rejected('credential.time.invalid', '/coreClock', 'time');
242
+ if (now < number(receipt.receipt.issuedAtMs)) return rejected('credential.event.time-invalid', '/coreClock', 'time');
243
+ const freshness = receiptFreshnessIssue(kernel, receipt.plan); if (freshness) return rejected(freshness.issueId, freshness.path, freshness.reasonClass);
244
+ if (now >= number(receipt.receipt.expiresAtMs)) return rejected('credential.receipt.expired', '/coreClock', 'time');
245
+ const tail = kernel.ports.readTail(string(get(receipt.receipt, '/binding/values/taskId')));
246
+ const previousEventHash = tail === null ? null : exactKeys(tail, ['eventHash']) ? tail.eventHash : undefined;
247
+ const eventId = safeId(kernel.ports.nextId('plan-validation-event'));
248
+ if (!(previousEventHash === null || hex(previousEventHash)) || !eventId) return rejected('credential.event.source-invalid', '/validationEventTailSource', 'integrity');
249
+ const base = { schemaVersion: 1, eventId, previousEventHash, taskId: get(receipt.receipt, '/binding/values/taskId'),
250
+ candidatePlanHash: get(receipt.receipt, '/binding/values/candidatePlanHash'), attestationId: get(receipt.receipt, '/validation/attestationId'),
251
+ attestationHash: get(receipt.receipt, '/validation/attestationHash'), receiptId: receipt.receipt.receiptId,
252
+ receiptHash: receipt.receipt.receiptHash, receiptDomainHash: receipt.receipt.domainHash,
253
+ challengeId: receipt.confirmation.projection.challengeId, challengeHash: receipt.confirmation.projection.challengeHash,
254
+ recordedAt: new Date(now).toISOString(), recordedAtMs: now };
255
+ const event = deepFreeze({ ...base, eventHash: hashCanonical(base) });
256
+ if (!schema('schema.corrective-replan-stored-plan-validation-event', event)) return rejected('credential.event.invalid', '/event', 'schema');
257
+ const eventHandle = opaque(); kernel.events.set(eventHandle, deepFreeze({ receipt, event })); kernel.evented.add(handle);
258
+ return accepted({ handle: eventHandle as StoredPlanValidationEventHandle, event });
259
+ };
260
+ const verifyStoredEvent = (issuer: unknown, input: unknown): Verification<JsonRecord> => {
261
+ const kernel = kernels.get(object(issuer)); if (!kernel) return verificationRejected('credential.provenance.invalid', '/', 'provenance');
262
+ if (!exactKeys(input, ['event', 'candidate'])) return verificationRejected('credential.envelope.invalid', '/', 'schema');
263
+ const recordValue = kernel.events.get(object((input as JsonRecord).event)); if (!recordValue) return verificationRejected('credential.provenance.invalid', '/event', 'provenance');
264
+ const candidate = (input as JsonRecord).candidate;
265
+ if (!schema('schema.corrective-replan-stored-plan-validation-event', candidate)) return verificationRejected('credential.event.invalid', '/candidate', 'schema');
266
+ if (!same(candidate, recordValue.event)) return verificationRejected('credential.event.mismatch', '/candidate', 'integrity');
267
+ return verified(recordValue.event);
268
+ };
269
+ const functions = [issuePlanValidation, issueHumanChallenge, confirmHuman, issueReceipt, verifyReceipt, materializeStoredEvent, verifyStoredEvent];
270
+ const ids = ['credential-materializer.corrective-replan.plan-validation-attestation', 'credential-materializer.corrective-replan.expected-human-challenge',
271
+ 'credential-verifier.corrective-replan.human-confirmation', 'credential-materializer.corrective-replan.receipt',
272
+ 'credential-verifier.corrective-replan.receipt', 'credential-materializer.corrective-replan.stored-plan-validation-event',
273
+ 'credential-verifier.corrective-replan.stored-plan-validation-event'] as const;
274
+ export const correctiveReplanCredentialFunctionBindings: readonly CredentialFunctionBinding[] = deepFreeze(ids.map((id, index) => ({ id, version: 1,
275
+ kind: id.includes('materializer') ? 'materializer' as const : 'verifier' as const, implementationId: `implementation.${id}` as const,
276
+ implementationVersion: 1, wiring: 'invoked', callable: functions[index]! })));
277
+ function loadCanonicalSnapshot(kernel: KernelRecord, taskId: string): { snapshot: JsonRecord; snapshotBindingHash: string } | Issue {
278
+ const source = kernel.ports.readSnapshot(taskId); if (!isRecord(source)) return issue('credential.snapshot.missing', '/taskId', 'binding');
279
+ if (source.bindingManifest !== correctiveReplanBindingManifest) return issue('credential.snapshot.manifest-invalid', '/snapshot/bindingManifest', 'binding');
280
+ const invalid = snapshotIssue(source, taskId); if (invalid) return invalid;
281
+ const snapshot = deepFreeze({ ...clone(source), bindingManifest: correctiveReplanBindingManifest });
282
+ return { snapshot, snapshotBindingHash: hashCanonical(snapshot) };
283
+ }
284
+ function receiptFreshnessIssue(kernel: KernelRecord, plan: PlanRecord): Issue | null {
285
+ const loaded = loadCanonicalSnapshot(kernel, string(get(plan.binding, '/values/taskId')));
286
+ if ('issueId' in loaded) return issue('credential.receipt.snapshot-stale', '/snapshotBindingHash', 'binding');
287
+ if (!same(loaded.snapshot.priorPlanAuthorization, plan.snapshot.priorPlanAuthorization))
288
+ return issue('credential.receipt.grant-stale', '/snapshot/priorPlanAuthorization/grantHash', 'authority');
289
+ return loaded.snapshotBindingHash === plan.snapshotBindingHash ? null : issue('credential.receipt.snapshot-stale', '/snapshotBindingHash', 'binding');
290
+ }
291
+ function snapshotIssue(snapshot: JsonRecord, taskId: unknown): Issue | null {
292
+ if (!exactKeys(snapshot, ['snapshotVersion', 'bindingManifest', 'worktree', 'baseValues', 'validationExpectation', 'priorPlanAuthorization']) || snapshot.snapshotVersion !== 2)
293
+ return issue('credential.snapshot.invalid', '/snapshot', 'schema');
294
+ const base = record(snapshot.baseValues); const expected = record(snapshot.validationExpectation);
295
+ if (base.taskId !== taskId || base.transitionId !== 'task.plan.corrective-replan' || base.capabilityId !== 'capability.task.corrective-replan'
296
+ || base.capabilityVersion !== 1 || base.lifecycleEpoch !== LIFECYCLE_EPOCH || !canonicalManifestValues(base, false))
297
+ return issue('credential.snapshot.values-invalid', '/snapshot/baseValues', 'binding');
298
+ if (!validWorktree(snapshot.worktree, base.gitHead) || !validExpectation(expected) || !exactKeys(snapshot.priorPlanAuthorization, ['grantHash', 'requiredDisposition'])
299
+ || !hex(record(snapshot.priorPlanAuthorization).grantHash) || record(snapshot.priorPlanAuthorization).requiredDisposition !== 'superseded')
300
+ return issue('credential.snapshot.invalid', '/snapshot/validationExpectation', 'schema');
301
+ const pairs: Array<readonly [string, string]> = [['taskId', 'taskId'], ['revision', 'revision'], ['currentPlanHash', 'currentPlanHash'],
302
+ ['briefHash', 'briefHash'], ['knowledgeRevision', 'knowledgeRevision'], ['knowledgeHash', 'knowledgeHash'], ['gitHead', 'gitHead'],
303
+ ['guardedStepId', 'guardedStepId'], ['correctiveDecisionHash', 'correctiveDecisionHash'], ['remediationTailHash', 'remediationTailHash']];
304
+ if (pairs.some(([sourceKey, baseKey]) => get(expected, `/source/${sourceKey}`) !== base[baseKey])
305
+ || get(expected, '/candidate/planHash') !== base.candidatePlanHash || get(expected, '/candidate/stepSetHash') !== base.candidateStepSetHash
306
+ || get(expected, '/planAuthor/identityHash') !== base.planAuthorIdentityHash || get(expected, '/validator/identityHash') !== base.planValidatorIdentityHash)
307
+ return issue('credential.snapshot.cross-link-invalid', '/snapshot/validationExpectation', 'binding');
308
+ return null;
309
+ }
310
+ function validWorktree(value: unknown, gitHead: unknown): boolean {
311
+ if (!exactKeys(value, ['kind', 'version', 'gitHead', 'changeSha256', 'entries'])
312
+ || value.kind !== 'guarded-step-worktree' || value.version !== 1 || value.gitHead !== gitHead
313
+ || !hex(value.changeSha256) || !Array.isArray(value.entries)) return false;
314
+ const entries = value.entries as unknown[];
315
+ if (entries.length > 256) return false;
316
+ const paths = new Set<string>();
317
+ for (const candidate of entries) {
318
+ if (!isRecord(candidate) || typeof candidate.path !== 'string' || paths.has(candidate.path)) return false;
319
+ paths.add(candidate.path);
320
+ if (candidate.disposition === 'deleted') {
321
+ if (!exactKeys(candidate, ['path', 'disposition'])) return false;
322
+ } else if (candidate.disposition === 'present') {
323
+ if (!exactKeys(candidate, ['path', 'disposition', 'executable', 'contentSha256'])
324
+ || typeof candidate.executable !== 'boolean' || !hex(candidate.contentSha256)) return false;
325
+ } else return false;
326
+ }
327
+ return entries.every((entry, index) => index === 0
328
+ || String((entries[index - 1] as JsonRecord).path).localeCompare(String((entry as JsonRecord).path)) < 0)
329
+ && value.changeSha256 === hashCanonical({ domain: 'codex-workflow/corrective-replan-worktree/v1', entries });
330
+ }
331
+ function canonicalManifestValues(values: JsonRecord, includePlanValidationHash: boolean): boolean {
332
+ const rows = (correctiveReplanBindingManifest.rows as readonly JsonRecord[])
333
+ .filter((row) => includePlanValidationHash || row.bindingId !== 'planValidationHash');
334
+ if (Object.keys(values).sort().join('\0') !== rows.map((row) => string(row.bindingId)).sort().join('\0')) return false;
335
+ return rows.every((row) => {
336
+ const id = string(row.bindingId); const value = values[id];
337
+ switch (row.canonicalization) {
338
+ case 'lowercase-hex': return hex(value);
339
+ case 'safe-nonnegative-integer': return safeTime(value) !== null;
340
+ case 'nfc-trim': return canonicalId(value);
341
+ case 'lowercase-git-oid': return typeof value === 'string' && /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(value);
342
+ case 'registered-enum': return value === 'delivery-coordinator' || value === 'technical-planner';
343
+ case 'exact': return value === (id === 'transitionId' ? 'task.plan.corrective-replan' : 'capability.task.corrective-replan');
344
+ default: return false;
345
+ }
346
+ });
347
+ }
348
+ function validExpectation(value: JsonRecord): boolean { return exactKeys(value, ['source', 'candidate', 'requirements', 'acceptance', 'architecture', 'planAuthor', 'plannerContext', 'validator'])
349
+ && exactKeys(value.source, ['taskId', 'revision', 'currentPlanHash', 'briefHash', 'knowledgeRevision', 'knowledgeHash', 'gitHead', 'guardedStepId', 'correctiveDecisionHash', 'remediationTailHash'])
350
+ && exactKeys(value.candidate, ['planHash', 'stepSetHash']) && validCoverage(value.requirements) && validCoverage(value.acceptance)
351
+ && validArchitecture(value.architecture) && validIdentity(value.planAuthor) && validIdentity(value.validator)
352
+ && validContext(value.plannerContext, true); }
353
+ function exactDraft(value: unknown): boolean { if (!exactKeys(value, ['schemaVersion', 'requirements', 'acceptance', 'architecture', 'validatorContext', 'passed', 'findings', 'dispositions'])) return false;
354
+ const draft = value as JsonRecord; const findings = array(draft.findings); const dispositions = array(draft.dispositions);
355
+ return draft.schemaVersion === 1 && draft.passed === true && validCoverage(draft.requirements) && validCoverage(draft.acceptance)
356
+ && validArchitecture(draft.architecture) && validContext(draft.validatorContext, false) && findings.length <= 128 && dispositions.length <= 128
357
+ && findings.every(validFinding) && dispositions.every(validDisposition); }
358
+ function validCoverage(value: unknown): boolean { return exactKeys(value, ['sourceHash', 'coverageHash', 'passed']) && hex(value.sourceHash) && hex(value.coverageHash) && value.passed === true; }
359
+ function validArchitecture(value: unknown): boolean { return exactKeys(value, ['sourceHash', 'compatibilityHash', 'passed']) && hex(value.sourceHash) && hex(value.compatibilityHash) && value.passed === true; }
360
+ function validIdentity(value: unknown): boolean { return exactKeys(value, ['identityHash']) && hex(value.identityHash); }
361
+ function validContext(value: unknown, captured: boolean): boolean { return exactKeys(value, captured ? ['contextHash', 'capturedAtMs'] : ['contextHash']) && hex(value.contextHash) && (!captured || safeTime(value.capturedAtMs) !== null); }
362
+ function validFinding(value: unknown): boolean { return exactKeys(value, ['findingId', 'severity', 'requirementRef', 'evidenceHash']) && canonicalId(value.findingId) && canonicalId(value.requirementRef) && ['low', 'medium', 'high'].includes(string(value.severity)) && hex(value.evidenceHash); }
363
+ function validDisposition(value: unknown): boolean { return exactKeys(value, ['findingId', 'decision', 'evidenceHash']) && canonicalId(value.findingId) && ['resolved', 'accepted-documented-limitation'].includes(string(value.decision)) && hex(value.evidenceHash); }
364
+ function keyedBijection(findings: unknown[], dispositions: unknown[]): boolean { const findingIds = findings.map((entry) => string(record(entry).findingId));
365
+ const dispositionIds = dispositions.map((entry) => string(record(entry).findingId)); return findingIds.length === dispositions.length
366
+ && findingIds.every(Boolean) && new Set(findingIds).size === findingIds.length && new Set(dispositionIds).size === dispositionIds.length
367
+ && [...findingIds].sort().join('\0') === [...dispositionIds].sort().join('\0'); }
368
+ function sortRows(rows: unknown[]) { return rows.map(clone).sort((a, b) => { const left = string(record(a).findingId); const right = string(record(b).findingId); return left < right ? -1 : left > right ? 1 : 0; }); }
369
+ function schema(id: string, value: unknown): boolean { return correctiveReplanCredentialSchemaValidators.find((entry) => entry.id === id)?.callable(value) === true; }
370
+ function accepted<T extends JsonRecord>(value: T): Result<T> { return deepFreeze({ ok: true, value: deepFreeze(value), issues: [] }); }
371
+ function rejected(issueId: string, path: string, reasonClass: Reason): Result<never> { const issues = [issue(issueId, path, reasonClass)]; return deepFreeze({ ok: false, value: null, issues, reportHash: hashCanonical(issues) }); }
372
+ function verified<T extends JsonRecord>(projection: T): Verification<T> { const content = { valid: true as const, projection: deepFreeze(projection), issues: [] as const }; return deepFreeze({ ...content, reportHash: hashCanonical(content) }); }
373
+ function verificationRejected(issueId: string, path: string, reasonClass: Reason): Verification<never> { const issues = [issue(issueId, path, reasonClass)]; return deepFreeze({ valid: false, projection: null, issues, reportHash: hashCanonical(issues) }); }
374
+ function issue(issueId: string, path: string, reasonClass: Reason): Issue { return { issueId, path, reasonClass }; }
375
+ function totalResult(invoke: () => Result<JsonRecord>): Result<JsonRecord> { try { return invoke(); } catch { return rejected('credential.operation.malformed', '/', 'schema'); } }
376
+ function totalVerification(invoke: () => Verification<JsonRecord>): Verification<JsonRecord> { try { return invoke(); } catch { return verificationRejected('credential.operation.malformed', '/', 'schema'); } }
377
+ function activePreparation(kernel: KernelRecord, plan: PlanRecord): boolean { const current = kernel.preparations.get(plan.preparationKey); return current?.status === 'active' && current.generation === plan.generation; }
378
+ function exactKeys(value: unknown, keys: readonly string[]): value is JsonRecord { return isRecord(value) && Object.keys(value).sort().join('\0') === [...keys].sort().join('\0'); }
379
+ function isRecord(value: unknown): value is JsonRecord { return value !== null && typeof value === 'object' && !Array.isArray(value); }
380
+ function copyOwnedJson(value: unknown, budget = { nodes: 0, bytes: 0, active: new Set<object>() }, depth = 0): unknown {
381
+ if (++budget.nodes > 4096 || (budget.bytes += 8) > 262_144 || depth > 32) return LIMIT;
382
+ if (typeof value === 'string') { budget.bytes += Buffer.byteLength(value, 'utf8'); return budget.bytes > 262_144 ? LIMIT : value; } if (value === null || typeof value === 'boolean') return value;
383
+ if (typeof value === 'number') return Number.isSafeInteger(value) ? value : MALFORMED; if (typeof value !== 'object' || utilTypes.isProxy(value) || budget.active.has(value)) return MALFORMED;
384
+ const arrayValue = Array.isArray(value); const prototype = Object.getPrototypeOf(value); if (prototype !== (arrayValue ? Array.prototype : Object.prototype) && prototype !== null) return MALFORMED;
385
+ const keys = Reflect.ownKeys(value); if (keys.some((key) => typeof key !== 'string')) return MALFORMED; const names = (keys as string[]).filter((key) => !arrayValue || key !== 'length'); const descriptors = Object.getOwnPropertyDescriptors(value);
386
+ if (arrayValue && (names.length !== value.length || names.some((key, index) => key !== String(index)))) return MALFORMED; const result: JsonRecord | unknown[] = arrayValue ? [] : Object.create(null); budget.active.add(value);
387
+ for (const key of names) { const descriptor = descriptors[key]; budget.bytes += Buffer.byteLength(key, 'utf8'); if (budget.bytes > 262_144) return LIMIT; if (!descriptor?.enumerable || !('value' in descriptor)) return MALFORMED;
388
+ const child = copyOwnedJson(descriptor.value, budget, depth + 1); if (child === LIMIT || child === MALFORMED) return child; (result as JsonRecord)[key] = child; }
389
+ budget.active.delete(value); return result;
390
+ }
391
+ function record(value: unknown): JsonRecord { return isRecord(value) ? value : {}; }
392
+ function object(value: unknown): object { return value !== null && typeof value === 'object' ? value : Object.freeze(Object.create(null)) as object; }
393
+ function opaque(): object { return Object.freeze(Object.create(null)) as object; }
394
+ function array(value: unknown): unknown[] { return Array.isArray(value) ? value : []; }
395
+ function string(value: unknown): string { return typeof value === 'string' ? value : ''; }
396
+ function number(value: unknown): number { return typeof value === 'number' ? value : Number.NaN; }
397
+ function safeTime(value: unknown): number | null { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 && value <= MAX_SAFE ? value : null; }
398
+ function safeId(value: unknown): string { return canonicalId(value) ? value : ''; }
399
+ function canonicalId(value: unknown): value is string { return typeof value === 'string' && value.length > 0 && value.length <= 256 && value === value.trim() && value === value.normalize('NFC'); }
400
+ function hex(value: unknown): value is string { return typeof value === 'string' && /^[a-f0-9]{64}$/.test(value); }
401
+ function get(value: unknown, path: string): unknown { return path.split('/').filter(Boolean).reduce((cursor: unknown, key) => isRecord(cursor) ? cursor[key] : undefined, value); }
402
+ function same(left: unknown, right: unknown): boolean { try { return hashCanonical(left) === hashCanonical(right); } catch { return false; } }
403
+ function authorityPassed(id: string, input: unknown): boolean {
404
+ const binding = installedAuthoritySemanticBindings.find((entry) => entry.id === id);
405
+ return binding !== undefined && record(binding.callable(input)).passed === true;
406
+ }
407
+ function clone<T>(value: T): T { return structuredClone(value); }
408
+ function sha(value: string): string { return createHash('sha256').update(value).digest('hex'); }
@@ -0,0 +1,54 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync } from 'node:fs';
3
+ import { Ajv2020 } from 'ajv/dist/2020.js';
4
+ import { hashCanonical } from './fingerprint.js';
5
+ import { deepFreeze } from './immutable.js';
6
+
7
+ export const credentialSchemaIds = [
8
+ 'schema.corrective-replan-binding', 'schema.corrective-replan-plan-validation-attestation',
9
+ 'schema.corrective-replan-human-confirmation-input', 'schema.corrective-replan-receipt',
10
+ 'schema.corrective-replan-stored-plan-validation-event',
11
+ ] as const;
12
+ const names = ['correctiveReplanBindingV1', 'planValidationAttestationV1', 'humanConfirmationInputV1',
13
+ 'correctiveReplanReceiptV1', 'storedPlanValidationEventV1'] as const;
14
+ const bytes = readFileSync(new URL('../../../schemas/corrective-replan-credentials.private.schema.json', import.meta.url));
15
+ const document = JSON.parse(bytes.toString('utf8')) as { $id: string; $defs: Record<string, unknown> };
16
+ const ajv = new Ajv2020({
17
+ allErrors: true,
18
+ strict: true,
19
+ formats: {
20
+ 'date-time': {
21
+ type: 'string',
22
+ validate(value: string) {
23
+ const parsed = Date.parse(value);
24
+ return Number.isFinite(parsed) && new Date(parsed).toISOString() === value;
25
+ },
26
+ },
27
+ },
28
+ });
29
+ if (!ajv.validateSchema(document)) throw new TypeError(`Invalid private credential schema: ${ajv.errorsText(ajv.errors)}`);
30
+ ajv.addSchema(document, document.$id);
31
+ const documentSha256 = createHash('sha256').update(bytes).digest('hex');
32
+
33
+ export interface CredentialSchemaArtifact {
34
+ readonly id: typeof credentialSchemaIds[number]; readonly version: 1;
35
+ readonly implementationId: `implementation.${string}`; readonly implementationVersion: 1;
36
+ readonly documentBytesSha256: string; readonly schemaPointer: string; readonly subschemaCanonicalSha256: string;
37
+ readonly document: unknown;
38
+ }
39
+ export interface CredentialSchemaValidator extends Omit<CredentialSchemaArtifact, 'document' | 'documentBytesSha256' | 'schemaPointer'> {
40
+ readonly artifactDocumentBytesSha256: string; readonly callable: (payload: unknown) => boolean;
41
+ }
42
+
43
+ const artifacts = credentialSchemaIds.map((id, index) => ({ id, version: 1 as const,
44
+ implementationId: `implementation.schema-artifact.${names[index]}` as const, implementationVersion: 1 as const,
45
+ documentBytesSha256: documentSha256, schemaPointer: `#/$defs/${names[index]}`, subschemaCanonicalSha256: hashCanonical(document.$defs[names[index]!]), document }));
46
+ const validators = artifacts.map((artifact, index) => {
47
+ const validate = ajv.compile({ $ref: `${document.$id}#/$defs/${names[index]}` });
48
+ return { id: artifact.id, version: 1 as const,
49
+ implementationId: `implementation.schema-validator.ajv-draft-2020-12.${names[index]}` as const,
50
+ implementationVersion: 1 as const, artifactDocumentBytesSha256: documentSha256,
51
+ subschemaCanonicalSha256: artifact.subschemaCanonicalSha256, callable: (payload: unknown) => validate(payload) === true };
52
+ });
53
+ export const correctiveReplanCredentialSchemaArtifacts: readonly CredentialSchemaArtifact[] = deepFreeze(artifacts);
54
+ export const correctiveReplanCredentialSchemaValidators: readonly CredentialSchemaValidator[] = deepFreeze(validators);
@@ -0,0 +1,48 @@
1
+ import { types as utilTypes } from 'node:util';
2
+ import { correctiveReplanBindingManifest } from './corrective-replan-binding-manifest.js';
3
+ import { correctiveReplanCredentialFunctionBindings } from './corrective-replan-credential-core.js';
4
+ import { correctiveReplanCredentialSchemaArtifacts, correctiveReplanCredentialSchemaValidators } from './corrective-replan-credential-schema.js';
5
+ import { hashCanonical } from './fingerprint.js';
6
+ import { deepFreeze } from './immutable.js';
7
+
8
+ const executionLinkage = deepFreeze({ status: 'active' as const, transitionId: 'task.plan.corrective-replan' as const }); const kernelDescriptor = deepFreeze({ id: 'credential-kernel.corrective-replan', version: 1 as const, wiring: 'invoked' as const,
9
+ buildSha256: hashCanonical({ family: 'corrective-replan', kernelVersion: 1, manifestSha256: correctiveReplanBindingManifest.manifestSha256,
10
+ functions: correctiveReplanCredentialFunctionBindings.map(({ id, version, implementationId, implementationVersion }) => ({ id, version, implementationId, implementationVersion })) }) });
11
+ type ClosureIssue = { issueId: string; path: string; ref?: string; message: string };
12
+ type Candidate = { original: object; index: number; id: string; version: number; callable?: unknown };
13
+
14
+ export function diagnoseCorrectiveReplanCredentialClosure(input: unknown = undefined) { try {
15
+ const issues: ClosureIssue[] = []; const allowed = ['authorityBindingManifest', 'schemaArtifacts', 'schemaValidators', 'functionBindings'];
16
+ let source = top(input); if (!source || Object.keys(source).some((key) => !allowed.includes(key))) { issues.push(problem('credential.closure.input-invalid', '/', 'closure-input')); source = {}; }
17
+ const artifacts = collection(source.schemaArtifacts, correctiveReplanCredentialSchemaArtifacts); if (!artifacts) issues.push(problem('credential.closure.collection-invalid', '/schemaArtifacts', 'schemaArtifacts'));
18
+ const validators = collection(source.schemaValidators, correctiveReplanCredentialSchemaValidators); if (!validators) issues.push(problem('credential.closure.collection-invalid', '/schemaValidators', 'schemaValidators'));
19
+ const functions = collection(source.functionBindings, correctiveReplanCredentialFunctionBindings); if (!functions) issues.push(problem('credential.closure.collection-invalid', '/functionBindings', 'functionBindings'));
20
+ if ((source.authorityBindingManifest ?? correctiveReplanBindingManifest) !== correctiveReplanBindingManifest) issues.push(problem('credential.manifest.substituted', '/authorityBindingManifest', correctiveReplanBindingManifest.id));
21
+ exact(correctiveReplanCredentialSchemaArtifacts, artifacts ?? [], 'schemaArtifacts', 'credential.schema-artifact', false, issues);
22
+ exact(correctiveReplanCredentialSchemaValidators, validators ?? [], 'schemaValidators', 'credential.schema-validator', true, issues);
23
+ exact(correctiveReplanCredentialFunctionBindings, functions ?? [], 'functionBindings', 'credential.function', true, issues); return finish(issues);
24
+ } catch { return finish([problem('credential.closure.input-invalid', '/', 'closure-input')]); } }
25
+
26
+ function finish(issues: ClosureIssue[]) { const ordered = issues.sort((a, b) => { const left = `${a.path}\0${a.issueId}`; const right = `${b.path}\0${b.issueId}`; return left < right ? -1 : left > right ? 1 : 0; });
27
+ const projection = { manifestSha256: correctiveReplanBindingManifest.manifestSha256, artifacts: correctiveReplanCredentialSchemaArtifacts.map(project), validators: correctiveReplanCredentialSchemaValidators.map(project), functions: correctiveReplanCredentialFunctionBindings.map(project), pendingBlockers: [] };
28
+ return deepFreeze({ closed: ordered.length === 0, issues: ordered, manifestSha256: correctiveReplanBindingManifest.manifestSha256, closureSha256: hashCanonical(projection), pendingBlockers: [] }); }
29
+ function top(input: unknown): Record<string, unknown> | null { if (input === undefined) return {}; if (!plain(input)) return null;
30
+ const keys = Reflect.ownKeys(input); if (keys.some((key) => typeof key !== 'string')) return null; const descriptors = Object.getOwnPropertyDescriptors(input); const result: Record<string, unknown> = Object.create(null);
31
+ for (const key of keys as string[]) { const descriptor = descriptors[key]; if (!descriptor?.enumerable || !('value' in descriptor)) return null; result[key] = descriptor.value; } return result; }
32
+ function collection(value: unknown, installed: readonly { id: string; version: number; callable?: unknown }[]): Candidate[] | null { if (value === undefined) return installed.map(view);
33
+ if (utilTypes.isProxy(value) || !Array.isArray(value) || value.length > 16) return null; const keys = Reflect.ownKeys(value); const descriptors = Object.getOwnPropertyDescriptors(value);
34
+ const names = keys.filter((key) => key !== 'length'); if (names.some((key, index) => typeof key !== 'string' || key !== String(index)) || names.length !== value.length) return null; const result: Candidate[] = [];
35
+ for (const key of names as string[]) { const cell = descriptors[key]; if (!cell?.enumerable || !('value' in cell) || !plain(cell.value)) return null; const row = Object.getOwnPropertyDescriptors(cell.value);
36
+ if (Reflect.ownKeys(cell.value).some((name) => typeof name !== 'string' || !row[name]?.enumerable || !('value' in row[name]!)) || typeof row.id?.value !== 'string' || !row.id.value.includes('.') || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,255}$/.test(row.id.value) || typeof row.version?.value !== 'number') return null;
37
+ result.push({ original: cell.value, index: Number(key), id: row.id.value, version: row.version.value, callable: row.callable?.value }); } return result; }
38
+ function exact<T extends { id: string; version: number; callable?: unknown }>(installed: readonly T[], candidate: Candidate[], collectionName: string, prefix: string, callable: boolean, issues: ClosureIssue[]) { for (const expected of installed) { const matches = candidate.filter((entry) => entry.id === expected.id && entry.version === expected.version);
39
+ if (matches.length !== 1) issues.push(problem(`${prefix}.${matches.length ? 'duplicate' : 'missing'}`, `/${prefix}/${expected.id}`, expected.id)); else if (matches[0]!.original !== expected || (callable && matches[0]!.callable !== expected.callable)) issues.push(problem(`${prefix}.${callable ? 'callable-substituted' : 'substituted'}`, `/${prefix}/${expected.id}`, expected.id)); }
40
+ candidate.filter((entry) => !installed.some((expected) => expected.id === entry.id && expected.version === entry.version)).forEach((entry) => issues.push({ issueId: `${prefix}.extra`, path: `/${collectionName}/${entry.index}`, ref: 'closure-extra-row', message: 'Candidate row is not installed.' })); }
41
+ function view(entry: { id: string; version: number; callable?: unknown }, index: number): Candidate { return { original: entry, index, id: entry.id, version: entry.version, callable: entry.callable }; }
42
+ function problem(issueId: string, path: string, ref: string): ClosureIssue { return { issueId, path, ref, message: `${ref} is not the installed exact identity.` }; }
43
+ function project(entry: object) { const { callable: _callable, document: _document, ...value } = entry as Record<string, unknown>; return value; }
44
+ function plain(value: unknown): value is object { if (value === null || typeof value !== 'object' || Array.isArray(value) || utilTypes.isProxy(value)) return false; const prototype = Object.getPrototypeOf(value); return prototype === Object.prototype || prototype === null; }
45
+
46
+ export const correctiveReplanCredentialInspection = deepFreeze({ authorityBindingManifest: correctiveReplanBindingManifest, executionLinkage, kernelDescriptor,
47
+ schemaArtifacts: correctiveReplanCredentialSchemaArtifacts, schemaValidators: correctiveReplanCredentialSchemaValidators,
48
+ functionBindings: correctiveReplanCredentialFunctionBindings, diagnoseClosure: diagnoseCorrectiveReplanCredentialClosure });