@defrex/autobuild 0.11.0 → 0.13.0

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 (136) hide show
  1. package/README.md +3 -1
  2. package/SPEC.md +335 -31
  3. package/docs/architecture.md +125 -7
  4. package/docs/configuration.md +142 -21
  5. package/docs/hosted-dispatcher.md +17 -2
  6. package/docs/hosted-service.md +240 -0
  7. package/docs/mcp.md +8 -2
  8. package/docs/operator-api.md +97 -7
  9. package/docs/remote-store-protocol.md +199 -144
  10. package/docs/remote-ticket-protocol.md +249 -19
  11. package/docs/setup.md +199 -16
  12. package/docs/ticket-dependencies.md +1 -1
  13. package/docs/ticket-migration.md +64 -0
  14. package/package.json +7 -6
  15. package/packages/core/src/cli/attention.ts +209 -0
  16. package/packages/core/src/cli/build-control.ts +12 -1
  17. package/packages/core/src/cli/configured-store.ts +17 -0
  18. package/packages/core/src/cli/connect.ts +364 -0
  19. package/packages/core/src/cli/context.ts +7 -1
  20. package/packages/core/src/cli/dashboard/model.ts +4 -5
  21. package/packages/core/src/cli/dashboard/poll.ts +1 -1
  22. package/packages/core/src/cli/dispatch.ts +336 -41
  23. package/packages/core/src/cli/harvest.ts +13 -3
  24. package/packages/core/src/cli/help.ts +51 -16
  25. package/packages/core/src/cli/init-validation.ts +27 -2
  26. package/packages/core/src/cli/installation.ts +67 -13
  27. package/packages/core/src/cli/main.ts +60 -16
  28. package/packages/core/src/cli/mcp.ts +9 -2
  29. package/packages/core/src/cli/pr-summary-publication.ts +220 -0
  30. package/packages/core/src/cli/pr-summary.ts +2 -0
  31. package/packages/core/src/cli/project-credentials.ts +132 -0
  32. package/packages/core/src/cli/repo-state.ts +15 -2
  33. package/packages/core/src/cli/self-update.ts +15 -1
  34. package/packages/core/src/cli/store-opening.ts +22 -14
  35. package/packages/core/src/cli/terminals.ts +0 -10
  36. package/packages/core/src/cli/ticket-assets.ts +7 -2
  37. package/packages/core/src/cli/ticket-editor.ts +82 -0
  38. package/packages/core/src/cli/ticket.ts +172 -35
  39. package/packages/core/src/cli/upgrade-compatibility.ts +80 -0
  40. package/packages/core/src/cli/wait.ts +84 -17
  41. package/packages/core/src/cli/watch.ts +197 -60
  42. package/packages/core/src/config/live.ts +3 -0
  43. package/packages/core/src/config/schema.ts +90 -11
  44. package/packages/core/src/connection.ts +86 -0
  45. package/packages/core/src/events/catalog.ts +11 -2
  46. package/packages/core/src/events/payloads.ts +50 -0
  47. package/packages/core/src/events/repository.ts +13 -0
  48. package/packages/core/src/integration/harness.ts +37 -2
  49. package/packages/core/src/kernel/__snapshots__/reducer-registry.test.ts.snap +145 -83
  50. package/packages/core/src/kernel/engine.ts +24 -0
  51. package/packages/core/src/kernel/generators/build-log.ts +11 -1
  52. package/packages/core/src/kernel/incremental-fixtures.ts +13 -2
  53. package/packages/core/src/kernel/log-index.ts +17 -0
  54. package/packages/core/src/kernel/pr-summary.ts +89 -0
  55. package/packages/core/src/kernel/reducer-registry.ts +10 -0
  56. package/packages/core/src/kernel/reducer.ts +8 -0
  57. package/packages/core/src/ontology.ts +2 -0
  58. package/packages/core/src/operator/annotations.ts +12 -0
  59. package/packages/core/src/operator/index.ts +12 -0
  60. package/packages/core/src/operator/protocol.ts +19 -2
  61. package/packages/core/src/operator/query.ts +38 -16
  62. package/packages/core/src/operator/registry.ts +61 -8
  63. package/packages/core/src/operator/ticket-source-backend.ts +17 -20
  64. package/packages/core/src/operator/tickets.ts +136 -28
  65. package/packages/core/src/plugin-sdk/index.ts +7 -0
  66. package/packages/core/src/plugins/manifest.ts +5 -3
  67. package/packages/core/src/plugins/runtimes.ts +7 -1
  68. package/packages/core/src/ports/forge/fake.ts +13 -1
  69. package/packages/core/src/ports/forge/github-transport.ts +36 -1
  70. package/packages/core/src/ports/forge/github.ts +29 -5
  71. package/packages/core/src/ports/forge/local-git.ts +12 -4
  72. package/packages/core/src/ports/forge/summary-marker.ts +8 -0
  73. package/packages/core/src/ports/runner/session-env.ts +3 -0
  74. package/packages/core/src/ports/tickets/contract.ts +66 -1
  75. package/packages/core/src/ports/tickets/create.ts +54 -10
  76. package/packages/core/src/ports/tickets/fake.ts +30 -1
  77. package/packages/core/src/ports/tickets/file-assets.ts +159 -0
  78. package/packages/core/src/ports/tickets/file-codec.ts +90 -0
  79. package/packages/core/src/ports/tickets/file.ts +114 -120
  80. package/packages/core/src/ports/tickets/grants.ts +47 -0
  81. package/packages/core/src/ports/tickets/hosted-index.ts +17 -3
  82. package/packages/core/src/ports/tickets/identity.ts +20 -0
  83. package/packages/core/src/ports/tickets/lifecycle.ts +18 -0
  84. package/packages/core/src/ports/tickets/linear.ts +74 -9
  85. package/packages/core/src/ports/tickets/migration.ts +336 -0
  86. package/packages/core/src/ports/tickets/operations.ts +38 -7
  87. package/packages/core/src/ports/tickets/portable-assets.ts +54 -0
  88. package/packages/core/src/ports/tickets/remote-protocol.ts +96 -0
  89. package/packages/core/src/ports/tickets/remote.ts +61 -3
  90. package/packages/core/src/ports/tickets/requested-id.ts +46 -0
  91. package/packages/core/src/ports/tickets/revision.ts +62 -0
  92. package/packages/core/src/ports/tickets/states.ts +61 -0
  93. package/packages/core/src/ports/types.ts +40 -3
  94. package/packages/core/src/ports/workspace/build-execution.ts +6 -1
  95. package/packages/core/src/ports/workspace/create.ts +15 -2
  96. package/packages/core/src/ports/workspace/distribution-archive.ts +3 -5
  97. package/packages/core/src/ports/workspace/harvest-execution.ts +3 -1
  98. package/packages/core/src/ports/workspace/local-build-execution.ts +8 -1
  99. package/packages/core/src/ports/workspace/operator-sandbox.ts +2 -0
  100. package/packages/core/src/ports/workspace/vercel-sandbox.ts +51 -19
  101. package/packages/core/src/processes/build-execution-state.ts +1 -1
  102. package/packages/core/src/processes/build-runner.ts +87 -26
  103. package/packages/core/src/processes/dispatch-failure-budget.ts +83 -0
  104. package/packages/core/src/processes/dispatcher.ts +168 -41
  105. package/packages/core/src/processes/execution-no-progress.ts +176 -0
  106. package/packages/core/src/processes/harvest-child.ts +31 -4
  107. package/packages/core/src/processes/harvest-execution-state.ts +19 -2
  108. package/packages/core/src/processes/harvest-runner.ts +166 -104
  109. package/packages/core/src/processes/harvest.ts +34 -14
  110. package/packages/core/src/processes/phase-failure-budget.ts +2 -0
  111. package/packages/core/src/processes/publication-loss.ts +18 -1
  112. package/packages/core/src/processes/repo-view.ts +35 -0
  113. package/packages/core/src/store/contract.ts +32 -1
  114. package/packages/core/src/store/local/store.ts +1 -1
  115. package/packages/core/src/store/remote/client.ts +1 -1
  116. package/packages/core/src/store/remote/compatibility.ts +90 -0
  117. package/packages/core/src/store/remote/credentials.ts +28 -0
  118. package/packages/core/src/store/remote/index.ts +14 -1
  119. package/packages/core/src/store/remote/protocol.ts +25 -0
  120. package/packages/core/src/store/remote/token.ts +74 -13
  121. package/packages/core/src/store/ticket-asset-snapshots.ts +192 -0
  122. package/packages/core/src/store/ticket-assets.ts +86 -8
  123. package/packages/core/src/store/types.ts +1 -1
  124. package/packages/core/src/testing/index.ts +7 -0
  125. package/skills/guide/SKILL.md +232 -34
  126. package/skills/guide/references/operator-api.md +142 -13
  127. package/skills/guide/references/plugin-authoring.md +10 -2
  128. package/skills/guide/references/remote-store-protocol.md +199 -144
  129. package/skills/guide/references/remote-ticket-protocol.md +253 -18
  130. package/skills/guide/references/setup.md +199 -16
  131. package/skills/guide/references/ticket-dependencies.md +1 -1
  132. package/skills/guide/references/ticket-migration.md +64 -0
  133. package/skills/operate/SKILL.md +126 -36
  134. package/skills/tickets/SKILL.md +71 -0
  135. package/templates/hosted-service/package.json +13 -0
  136. package/templates/hosted-service/vercel.json +7 -0
@@ -138,27 +138,28 @@ exports[`reducer registry accumulator shapes 1`] = `
138
138
  "$.lastEvent.actor.user: string",
139
139
  "$.lastEvent.actor: object",
140
140
  "$.lastEvent.build: string",
141
+ "$.lastEvent.payload.answer: string",
141
142
  "$.lastEvent.payload.artifact.kind: string",
142
143
  "$.lastEvent.payload.artifact.rev: number",
143
144
  "$.lastEvent.payload.artifact: object",
144
- "$.lastEvent.payload.asset.assetId: number",
145
- "$.lastEvent.payload.asset.provider: string",
146
- "$.lastEvent.payload.asset.releaseId: number",
147
- "$.lastEvent.payload.asset.repository: string",
148
- "$.lastEvent.payload.asset.url: string",
149
- "$.lastEvent.payload.asset: object",
145
+ "$.lastEvent.payload.assets: array",
146
+ "$.lastEvent.payload.assets[].dirCount: number",
147
+ "$.lastEvent.payload.assets[].fileCount: number",
148
+ "$.lastEvent.payload.assets[].kind: string",
149
+ "$.lastEvent.payload.assets[].layout: string",
150
+ "$.lastEvent.payload.assets[].name: string",
151
+ "$.lastEvent.payload.assets[].revision: number",
152
+ "$.lastEvent.payload.assets[].size: number",
153
+ "$.lastEvent.payload.assets[]: object",
150
154
  "$.lastEvent.payload.attempt: number",
151
155
  "$.lastEvent.payload.base.sha: string",
152
156
  "$.lastEvent.payload.base.source: string",
153
157
  "$.lastEvent.payload.base: object",
158
+ "$.lastEvent.payload.base: string",
159
+ "$.lastEvent.payload.baseSha: string",
160
+ "$.lastEvent.payload.boundary: number",
154
161
  "$.lastEvent.payload.branch: string",
155
162
  "$.lastEvent.payload.cause: string",
156
- "$.lastEvent.payload.cleanupPending: boolean",
157
- "$.lastEvent.payload.command: string",
158
- "$.lastEvent.payload.commandSeq: number",
159
- "$.lastEvent.payload.commits.base: string",
160
- "$.lastEvent.payload.commits.head: string",
161
- "$.lastEvent.payload.commits: object",
162
163
  "$.lastEvent.payload.counters.claimed: number",
163
164
  "$.lastEvent.payload.counters.closed: number",
164
165
  "$.lastEvent.payload.counters.conflicted: number",
@@ -174,7 +175,6 @@ exports[`reducer registry accumulator shapes 1`] = `
174
175
  "$.lastEvent.payload.decision: string",
175
176
  "$.lastEvent.payload.defaultSeq: number",
176
177
  "$.lastEvent.payload.dependencyDiagnostics: array",
177
- "$.lastEvent.payload.designationSeq: number",
178
178
  "$.lastEvent.payload.dispositions: array",
179
179
  "$.lastEvent.payload.dispositions[].action: string",
180
180
  "$.lastEvent.payload.dispositions[].occurrence.build: string",
@@ -185,15 +185,15 @@ exports[`reducer registry accumulator shapes 1`] = `
185
185
  "$.lastEvent.payload.effectiveConfig.kind: string",
186
186
  "$.lastEvent.payload.effectiveConfig.rev: number",
187
187
  "$.lastEvent.payload.effectiveConfig: object",
188
+ "$.lastEvent.payload.eligibleAfter: string",
188
189
  "$.lastEvent.payload.enabled: boolean",
189
190
  "$.lastEvent.payload.environmentId: string",
190
191
  "$.lastEvent.payload.error: string",
191
192
  "$.lastEvent.payload.escalation: number",
192
193
  "$.lastEvent.payload.execution: string",
193
- "$.lastEvent.payload.exitStatus: number",
194
194
  "$.lastEvent.payload.filename: string",
195
- "$.lastEvent.payload.files: array",
196
195
  "$.lastEvent.payload.findings: array",
196
+ "$.lastEvent.payload.generation: number",
197
197
  "$.lastEvent.payload.globs: array",
198
198
  "$.lastEvent.payload.globs[]: string",
199
199
  "$.lastEvent.payload.host: string",
@@ -207,37 +207,36 @@ exports[`reducer registry accumulator shapes 1`] = `
207
207
  "$.lastEvent.payload.kind: string",
208
208
  "$.lastEvent.payload.level: string",
209
209
  "$.lastEvent.payload.mediaType: string",
210
+ "$.lastEvent.payload.mergeCommit: string",
210
211
  "$.lastEvent.payload.message: string",
211
212
  "$.lastEvent.payload.observations: array",
212
213
  "$.lastEvent.payload.observations[].build: string",
213
214
  "$.lastEvent.payload.observations[].seq: number",
214
215
  "$.lastEvent.payload.observations[]: object",
216
+ "$.lastEvent.payload.occurrence: number",
215
217
  "$.lastEvent.payload.ok: boolean",
216
218
  "$.lastEvent.payload.operation: string",
217
219
  "$.lastEvent.payload.operator: string",
218
220
  "$.lastEvent.payload.outcome: string",
219
- "$.lastEvent.payload.output: string",
220
221
  "$.lastEvent.payload.phase: string",
221
222
  "$.lastEvent.payload.pid: number",
222
- "$.lastEvent.payload.policyCause: string",
223
223
  "$.lastEvent.payload.pr.headSha: string",
224
224
  "$.lastEvent.payload.pr.number: number",
225
225
  "$.lastEvent.payload.pr.url: string",
226
+ "$.lastEvent.payload.pr: number",
226
227
  "$.lastEvent.payload.pr: object",
227
228
  "$.lastEvent.payload.provider: string",
228
229
  "$.lastEvent.payload.question: string",
229
230
  "$.lastEvent.payload.queued: number",
230
231
  "$.lastEvent.payload.reason: string",
231
232
  "$.lastEvent.payload.ref: string",
232
- "$.lastEvent.payload.refs: array",
233
- "$.lastEvent.payload.refs[]: string",
234
233
  "$.lastEvent.payload.remote: boolean",
235
234
  "$.lastEvent.payload.report.kind: string",
236
235
  "$.lastEvent.payload.report.rev: number",
237
236
  "$.lastEvent.payload.report: object",
238
237
  "$.lastEvent.payload.request: number",
239
238
  "$.lastEvent.payload.resetAt: string",
240
- "$.lastEvent.payload.retryable: boolean",
239
+ "$.lastEvent.payload.resolution: string",
241
240
  "$.lastEvent.payload.role: string",
242
241
  "$.lastEvent.payload.roleWarnings: array",
243
242
  "$.lastEvent.payload.roleWarnings[]: string",
@@ -253,10 +252,8 @@ exports[`reducer registry accumulator shapes 1`] = `
253
252
  "$.lastEvent.payload.snapshots.outcome: string",
254
253
  "$.lastEvent.payload.snapshots: object",
255
254
  "$.lastEvent.payload.source: string",
256
- "$.lastEvent.payload.stage: string",
257
255
  "$.lastEvent.payload.step: string",
258
256
  "$.lastEvent.payload.stream: string",
259
- "$.lastEvent.payload.summary: string",
260
257
  "$.lastEvent.payload.text: string",
261
258
  "$.lastEvent.payload.ticket.id: string",
262
259
  "$.lastEvent.payload.ticket.source: string",
@@ -324,7 +321,6 @@ exports[`reducer registry accumulator shapes 1`] = `
324
321
  "$.pending.abort[].actor.user: string",
325
322
  "$.pending.abort[].actor: object",
326
323
  "$.pending.abort[].command: string",
327
- "$.pending.abort[].reason: string",
328
324
  "$.pending.abort[].reason: undefined",
329
325
  "$.pending.abort[].seq: number",
330
326
  "$.pending.abort[]: object",
@@ -393,7 +389,6 @@ exports[`reducer registry accumulator shapes 1`] = `
393
389
  "$.terminal: string",
394
390
  "$.terminal: undefined",
395
391
  "$.verify.currentStep: string",
396
- "$.verify.currentStep: undefined",
397
392
  "$.verify.cycleSince: number",
398
393
  "$.verify.maxAttemptSeen: number",
399
394
  "$.verify.results: array",
@@ -520,19 +515,11 @@ exports[`reducer registry accumulator shapes 1`] = `
520
515
  "$.intervals.reconcile.open: object",
521
516
  "$.intervals.reconcile: object",
522
517
  "$.intervals.verify:types.closed: array",
523
- "$.intervals.verify:types.closed[].end: number",
524
- "$.intervals.verify:types.closed[].start: number",
525
- "$.intervals.verify:types.closed[].startSeq: number",
526
- "$.intervals.verify:types.closed[]: object",
527
518
  "$.intervals.verify:types.open.start: number",
528
519
  "$.intervals.verify:types.open.startSeq: number",
529
520
  "$.intervals.verify:types.open: object",
530
521
  "$.intervals.verify:types: object",
531
522
  "$.intervals.verify:unit.closed: array",
532
- "$.intervals.verify:unit.closed[].end: number",
533
- "$.intervals.verify:unit.closed[].start: number",
534
- "$.intervals.verify:unit.closed[].startSeq: number",
535
- "$.intervals.verify:unit.closed[]: object",
536
523
  "$.intervals.verify:unit.open.start: number",
537
524
  "$.intervals.verify:unit.open.startSeq: number",
538
525
  "$.intervals.verify:unit.open: object",
@@ -587,6 +574,23 @@ exports[`reducer registry accumulator shapes 1`] = `
587
574
  "$.workspaceReleased: number",
588
575
  "$: object",
589
576
  ],
577
+ "dispatchFailureBudget": [
578
+ "$.aborted: boolean",
579
+ "$.failures: array",
580
+ "$.failures[].actor.kind: string",
581
+ "$.failures[].actor: object",
582
+ "$.failures[].build: string",
583
+ "$.failures[].payload.attempt: number",
584
+ "$.failures[].payload.error: string",
585
+ "$.failures[].payload.stage: string",
586
+ "$.failures[].payload: object",
587
+ "$.failures[].seq: number",
588
+ "$.failures[].ts: string",
589
+ "$.failures[].type: string",
590
+ "$.failures[]: object",
591
+ "$.open: array",
592
+ "$: object",
593
+ ],
590
594
  "dispatchSettings": [
591
595
  "$.autoMergeSeq: number",
592
596
  "$.defaultAutoMerge: boolean",
@@ -617,6 +621,21 @@ exports[`reducer registry accumulator shapes 1`] = `
617
621
  "$.yieldedHolder: undefined",
618
622
  "$: object",
619
623
  ],
624
+ "executionNoProgress": [
625
+ "$.active.eligible: boolean",
626
+ "$.active.instance: string",
627
+ "$.active.seq: number",
628
+ "$.active: null",
629
+ "$.active: object",
630
+ "$.count: number",
631
+ "$.latest.instance: string",
632
+ "$.latest.seq: number",
633
+ "$.latest: null",
634
+ "$.latest: object",
635
+ "$.open: array",
636
+ "$.open[]: string",
637
+ "$: object",
638
+ ],
620
639
  "frozenPrImageHost": [
621
640
  "$.created.seq: number",
622
641
  "$.created: object",
@@ -719,20 +738,6 @@ exports[`reducer registry accumulator shapes 1`] = `
719
738
  "$.byKind.screenshot.type: string",
720
739
  "$.byKind.screenshot: object",
721
740
  "$.byKind: object",
722
- "$.hostedByDesignation.1.actor.kind: string",
723
- "$.hostedByDesignation.1.actor: object",
724
- "$.hostedByDesignation.1.build: string",
725
- "$.hostedByDesignation.1.payload.asset.assetId: number",
726
- "$.hostedByDesignation.1.payload.asset.provider: string",
727
- "$.hostedByDesignation.1.payload.asset.releaseId: number",
728
- "$.hostedByDesignation.1.payload.asset.repository: string",
729
- "$.hostedByDesignation.1.payload.asset.url: string",
730
- "$.hostedByDesignation.1.payload.asset: object",
731
- "$.hostedByDesignation.1.payload.designationSeq: number",
732
- "$.hostedByDesignation.1.payload: object",
733
- "$.hostedByDesignation.1.seq: number",
734
- "$.hostedByDesignation.1.ts: string",
735
- "$.hostedByDesignation.1.type: string",
736
741
  "$.hostedByDesignation.12.actor.kind: string",
737
742
  "$.hostedByDesignation.12.actor: object",
738
743
  "$.hostedByDesignation.12.build: string",
@@ -748,37 +753,36 @@ exports[`reducer registry accumulator shapes 1`] = `
748
753
  "$.hostedByDesignation.12.ts: string",
749
754
  "$.hostedByDesignation.12.type: string",
750
755
  "$.hostedByDesignation.12: object",
751
- "$.hostedByDesignation.15.actor.kind: string",
752
- "$.hostedByDesignation.15.actor: object",
753
- "$.hostedByDesignation.15.build: string",
754
- "$.hostedByDesignation.15.payload.asset.assetId: number",
755
- "$.hostedByDesignation.15.payload.asset.provider: string",
756
- "$.hostedByDesignation.15.payload.asset.releaseId: number",
757
- "$.hostedByDesignation.15.payload.asset.repository: string",
758
- "$.hostedByDesignation.15.payload.asset.url: string",
759
- "$.hostedByDesignation.15.payload.asset: object",
760
- "$.hostedByDesignation.15.payload.designationSeq: number",
761
- "$.hostedByDesignation.15.payload: object",
762
- "$.hostedByDesignation.15.seq: number",
763
- "$.hostedByDesignation.15.ts: string",
764
- "$.hostedByDesignation.15.type: string",
765
- "$.hostedByDesignation.15: object",
766
- "$.hostedByDesignation.1: object",
767
- "$.hostedByDesignation.2.actor.kind: string",
768
- "$.hostedByDesignation.2.actor: object",
769
- "$.hostedByDesignation.2.build: string",
770
- "$.hostedByDesignation.2.payload.asset.assetId: number",
771
- "$.hostedByDesignation.2.payload.asset.provider: string",
772
- "$.hostedByDesignation.2.payload.asset.releaseId: number",
773
- "$.hostedByDesignation.2.payload.asset.repository: string",
774
- "$.hostedByDesignation.2.payload.asset.url: string",
775
- "$.hostedByDesignation.2.payload.asset: object",
776
- "$.hostedByDesignation.2.payload.designationSeq: number",
777
- "$.hostedByDesignation.2.payload: object",
778
- "$.hostedByDesignation.2.seq: number",
779
- "$.hostedByDesignation.2.ts: string",
780
- "$.hostedByDesignation.2.type: string",
781
- "$.hostedByDesignation.2: object",
756
+ "$.hostedByDesignation.13.actor.kind: string",
757
+ "$.hostedByDesignation.13.actor: object",
758
+ "$.hostedByDesignation.13.build: string",
759
+ "$.hostedByDesignation.13.payload.asset.assetId: number",
760
+ "$.hostedByDesignation.13.payload.asset.provider: string",
761
+ "$.hostedByDesignation.13.payload.asset.releaseId: number",
762
+ "$.hostedByDesignation.13.payload.asset.repository: string",
763
+ "$.hostedByDesignation.13.payload.asset.url: string",
764
+ "$.hostedByDesignation.13.payload.asset: object",
765
+ "$.hostedByDesignation.13.payload.designationSeq: number",
766
+ "$.hostedByDesignation.13.payload: object",
767
+ "$.hostedByDesignation.13.seq: number",
768
+ "$.hostedByDesignation.13.ts: string",
769
+ "$.hostedByDesignation.13.type: string",
770
+ "$.hostedByDesignation.13: object",
771
+ "$.hostedByDesignation.19.actor.kind: string",
772
+ "$.hostedByDesignation.19.actor: object",
773
+ "$.hostedByDesignation.19.build: string",
774
+ "$.hostedByDesignation.19.payload.asset.assetId: number",
775
+ "$.hostedByDesignation.19.payload.asset.provider: string",
776
+ "$.hostedByDesignation.19.payload.asset.releaseId: number",
777
+ "$.hostedByDesignation.19.payload.asset.repository: string",
778
+ "$.hostedByDesignation.19.payload.asset.url: string",
779
+ "$.hostedByDesignation.19.payload.asset: object",
780
+ "$.hostedByDesignation.19.payload.designationSeq: number",
781
+ "$.hostedByDesignation.19.payload: object",
782
+ "$.hostedByDesignation.19.seq: number",
783
+ "$.hostedByDesignation.19.ts: string",
784
+ "$.hostedByDesignation.19.type: string",
785
+ "$.hostedByDesignation.19: object",
782
786
  "$.hostedByDesignation.3.actor.kind: string",
783
787
  "$.hostedByDesignation.3.actor: object",
784
788
  "$.hostedByDesignation.3.build: string",
@@ -809,6 +813,36 @@ exports[`reducer registry accumulator shapes 1`] = `
809
813
  "$.hostedByDesignation.4.ts: string",
810
814
  "$.hostedByDesignation.4.type: string",
811
815
  "$.hostedByDesignation.4: object",
816
+ "$.hostedByDesignation.5.actor.kind: string",
817
+ "$.hostedByDesignation.5.actor: object",
818
+ "$.hostedByDesignation.5.build: string",
819
+ "$.hostedByDesignation.5.payload.asset.assetId: number",
820
+ "$.hostedByDesignation.5.payload.asset.provider: string",
821
+ "$.hostedByDesignation.5.payload.asset.releaseId: number",
822
+ "$.hostedByDesignation.5.payload.asset.repository: string",
823
+ "$.hostedByDesignation.5.payload.asset.url: string",
824
+ "$.hostedByDesignation.5.payload.asset: object",
825
+ "$.hostedByDesignation.5.payload.designationSeq: number",
826
+ "$.hostedByDesignation.5.payload: object",
827
+ "$.hostedByDesignation.5.seq: number",
828
+ "$.hostedByDesignation.5.ts: string",
829
+ "$.hostedByDesignation.5.type: string",
830
+ "$.hostedByDesignation.5: object",
831
+ "$.hostedByDesignation.6.actor.kind: string",
832
+ "$.hostedByDesignation.6.actor: object",
833
+ "$.hostedByDesignation.6.build: string",
834
+ "$.hostedByDesignation.6.payload.asset.assetId: number",
835
+ "$.hostedByDesignation.6.payload.asset.provider: string",
836
+ "$.hostedByDesignation.6.payload.asset.releaseId: number",
837
+ "$.hostedByDesignation.6.payload.asset.repository: string",
838
+ "$.hostedByDesignation.6.payload.asset.url: string",
839
+ "$.hostedByDesignation.6.payload.asset: object",
840
+ "$.hostedByDesignation.6.payload.designationSeq: number",
841
+ "$.hostedByDesignation.6.payload: object",
842
+ "$.hostedByDesignation.6.seq: number",
843
+ "$.hostedByDesignation.6.ts: string",
844
+ "$.hostedByDesignation.6.type: string",
845
+ "$.hostedByDesignation.6: object",
812
846
  "$.hostedByDesignation.8.actor.kind: string",
813
847
  "$.hostedByDesignation.8.actor: object",
814
848
  "$.hostedByDesignation.8.build: string",
@@ -1025,16 +1059,15 @@ exports[`reducer registry accumulator shapes 1`] = `
1025
1059
  "$.hosted[].type: string",
1026
1060
  "$.hosted[]: object",
1027
1061
  "$.reclaimedAt.10: number",
1028
- "$.reclaimedAt.11: number",
1029
- "$.reclaimedAt.15: number",
1062
+ "$.reclaimedAt.12: number",
1030
1063
  "$.reclaimedAt.16: number",
1031
- "$.reclaimedAt.18: number",
1032
- "$.reclaimedAt.1: number",
1064
+ "$.reclaimedAt.17: number",
1065
+ "$.reclaimedAt.19: number",
1033
1066
  "$.reclaimedAt.20: number",
1034
- "$.reclaimedAt.3: number",
1067
+ "$.reclaimedAt.2: number",
1035
1068
  "$.reclaimedAt.6: number",
1036
- "$.reclaimedAt.7: number",
1037
1069
  "$.reclaimedAt.8: number",
1070
+ "$.reclaimedAt.9: number",
1038
1071
  "$.reclaimedAt: object",
1039
1072
  "$: object",
1040
1073
  ],
@@ -1164,6 +1197,7 @@ exports[`reducer registry accumulator shapes 1`] = `
1164
1197
  "$.retained[].payload.base: string",
1165
1198
  "$.retained[].payload.baseBranch: string",
1166
1199
  "$.retained[].payload.baseSha: string",
1200
+ "$.retained[].payload.boundary: number",
1167
1201
  "$.retained[].payload.branch: string",
1168
1202
  "$.retained[].payload.cause: string",
1169
1203
  "$.retained[].payload.cleanupPending: boolean",
@@ -1188,6 +1222,7 @@ exports[`reducer registry accumulator shapes 1`] = `
1188
1222
  "$.retained[].payload.defaultSeq: number",
1189
1223
  "$.retained[].payload.dependencyDiagnostics: array",
1190
1224
  "$.retained[].payload.designationSeq: number",
1225
+ "$.retained[].payload.disposition: string",
1191
1226
  "$.retained[].payload.dispositions: array",
1192
1227
  "$.retained[].payload.dispositions[].action: string",
1193
1228
  "$.retained[].payload.dispositions[].occurrence.build: string",
@@ -1198,6 +1233,7 @@ exports[`reducer registry accumulator shapes 1`] = `
1198
1233
  "$.retained[].payload.effectiveConfig.kind: string",
1199
1234
  "$.retained[].payload.effectiveConfig.rev: number",
1200
1235
  "$.retained[].payload.effectiveConfig: object",
1236
+ "$.retained[].payload.eligibleAfter: string",
1201
1237
  "$.retained[].payload.enabled: boolean",
1202
1238
  "$.retained[].payload.environmentId: string",
1203
1239
  "$.retained[].payload.error: string",
@@ -1227,6 +1263,7 @@ exports[`reducer registry accumulator shapes 1`] = `
1227
1263
  "$.retained[].payload.observations[].build: string",
1228
1264
  "$.retained[].payload.observations[].seq: number",
1229
1265
  "$.retained[].payload.observations[]: object",
1266
+ "$.retained[].payload.occurrence: number",
1230
1267
  "$.retained[].payload.ok: boolean",
1231
1268
  "$.retained[].payload.operation: string",
1232
1269
  "$.retained[].payload.operator: string",
@@ -1239,6 +1276,7 @@ exports[`reducer registry accumulator shapes 1`] = `
1239
1276
  "$.retained[].payload.pr.headSha: string",
1240
1277
  "$.retained[].payload.pr.number: number",
1241
1278
  "$.retained[].payload.pr.url: string",
1279
+ "$.retained[].payload.pr: number",
1242
1280
  "$.retained[].payload.pr: object",
1243
1281
  "$.retained[].payload.provider: string",
1244
1282
  "$.retained[].payload.question: string",
@@ -1368,6 +1406,30 @@ exports[`reducer registry accumulator shapes 1`] = `
1368
1406
  "$.failures[]: number",
1369
1407
  "$: object",
1370
1408
  ],
1409
+ "summaryBoundary": [
1410
+ "$.boundary: number",
1411
+ "$.occurrence: number",
1412
+ "$.sessions.s_a: boolean",
1413
+ "$.sessions.s_b: boolean",
1414
+ "$.sessions: object",
1415
+ "$: object",
1416
+ ],
1417
+ "summaryRequests": [
1418
+ "$.requests: array",
1419
+ "$.requests[].actor.kind: string",
1420
+ "$.requests[].actor: object",
1421
+ "$.requests[].build: string",
1422
+ "$.requests[].payload.boundary: number",
1423
+ "$.requests[].payload.occurrence: number",
1424
+ "$.requests[].payload: object",
1425
+ "$.requests[].seq: number",
1426
+ "$.requests[].ts: string",
1427
+ "$.requests[].type: string",
1428
+ "$.requests[]: object",
1429
+ "$.settled: array",
1430
+ "$.settled[]: number",
1431
+ "$: object",
1432
+ ],
1371
1433
  "ticketSourceHealth": [
1372
1434
  "$.active.cause: string",
1373
1435
  "$.active.message: string",
@@ -55,6 +55,7 @@ export type VerifyAction =
55
55
  export type FinalizeAction = { kind: 'check'; command: string } | { kind: 'agent'; skill: string }
56
56
 
57
57
  export type Decision =
58
+ | { kind: 'capture-reconcile-policy'; reconcileSeq: number }
58
59
  | { kind: 'wait'; reason: WaitReason }
59
60
  | { kind: 'acknowledge'; command: 'pause' | 'resume' | 'abort' }
60
61
  | {
@@ -80,6 +81,7 @@ export type Decision =
80
81
  step: string
81
82
  attempt: number
82
83
  reason: string
84
+ skipCause?: 'post-reconcile-policy'
83
85
  }
84
86
  | { kind: 'run-finalize-step'; step: string; action: FinalizeAction }
85
87
  | {
@@ -313,6 +315,18 @@ export function decideNextFromFacts(state: BuildState, log: LogIndex, config: Co
313
315
  const cycleAttempts = [...cycleResults, ...cycleStarted].map((v) => v.attempt)
314
316
  const attempt =
315
317
  cycleAttempts.length > 0 ? Math.max(...cycleAttempts) : log.maxVerifyAttemptEver + 1
318
+ // Freeze only a fresh reconcile cycle. A newer code-review approval restores
319
+ // ordinary verification. Already-started historical cycles have no snapshot:
320
+ // preserve their rerun-all policy, including after a crashed verify start.
321
+ const reconcileCycle =
322
+ log.lastReconcileCompletedSeq > Math.max(log.code.latestApproveSeq, log.restartSeq)
323
+ const policy =
324
+ reconcileCycle && log.reconcilePolicy?.reconcileSeq === cycleBoundary
325
+ ? log.reconcilePolicy
326
+ : undefined
327
+ if (reconcileCycle && policy === undefined && cycleAttempts.length === 0) {
328
+ return { kind: 'capture-reconcile-policy', reconcileSeq: cycleBoundary }
329
+ }
316
330
  const approvedPlan = log.plan.approvedPlan
317
331
  const approvedSelection =
318
332
  approvedPlan?.verifySteps === undefined
@@ -333,6 +347,16 @@ export function decideNextFromFacts(state: BuildState, log: LogIndex, config: Co
333
347
  const stepConfig = config.verify.stepConfigs[step]
334
348
  if (stepConfig === undefined) continue // unreachable: configSchema cross-validates (§16.1)
335
349
 
350
+ const exclusion = policy?.steps.find((s) => s.step === step && !s.enabled)
351
+ if (exclusion !== undefined)
352
+ return {
353
+ kind: 'skip-verify',
354
+ step,
355
+ attempt,
356
+ skipCause: 'post-reconcile-policy',
357
+ reason: `skipped by post-reconcile policy: ${exclusion.source} = false`,
358
+ }
359
+
336
360
  // Missing selection data is the historical default-all behavior. For a
337
361
  // current explicit selection, exclusion precedes path evaluation and any
338
362
  // verifier construction. Mandatory gates remain selected defensively even
@@ -151,7 +151,7 @@ function randomWrite(rand: () => number): EventWrite {
151
151
  id,
152
152
  phase: 'plan',
153
153
  source: 'policy',
154
- policyCause: 'infrastructure-failure-limit',
154
+ policyCause: round % 2 === 0 ? 'execution-no-progress' : 'infrastructure-failure-limit',
155
155
  question: 'q',
156
156
  }),
157
157
  () =>
@@ -207,6 +207,16 @@ function randomWrite(rand: () => number): EventWrite {
207
207
  },
208
208
  }),
209
209
  () => w('pr-attachment.reclaimed', { hostedSeq: 1 + Math.floor(rand() * 20) }),
210
+ () => w('pr-summary.requested', { occurrence: round, boundary: round + 1 }),
211
+ () => w('pr-summary.settled', { request: round, disposition: 'attempted' }),
212
+ () => w('pr-summary.attempted', { occurrence: round, boundary: round + 1, pr: 7 }),
213
+ () =>
214
+ w('pr-summary.result', {
215
+ attempt: round,
216
+ outcome: 'rate-limited',
217
+ eligibleAfter: '2026-10-15T00:01:00.000Z',
218
+ }),
219
+ () => w('finalize.step-started', { step: 'notes' }),
210
220
  () => w('build.auto-merge-default-observed', { defaultSeq: round }),
211
221
  () =>
212
222
  w('observation.recorded', {
@@ -99,7 +99,12 @@ export function randomBuildItem(rand: Rand): readonly [string, Record<string, un
99
99
  ],
100
100
  () => [
101
101
  'execution.ended',
102
- { instance, workspaceRef: ref, outcome: pick(rand, ['completed', 'stopped', 'lost']) },
102
+ {
103
+ instance,
104
+ workspaceRef: ref,
105
+ outcome: pick(rand, ['completed', 'stopped', 'lost']),
106
+ ...(rand() < 0.5 ? { exitCode: pick(rand, [0, 1, null]) } : {}),
107
+ },
103
108
  ],
104
109
  () => [
105
110
  'workspace.provisioned',
@@ -132,7 +137,13 @@ export function randomBuildItem(rand: Rand): readonly [string, Record<string, un
132
137
  phase: pick(rand, ['setup', 'plan', 'implement', 'verify:unit']),
133
138
  source: pick(rand, ['policy', 'agent']),
134
139
  ...(rand() < 0.7
135
- ? { policyCause: pick(rand, ['infrastructure-failure-limit', 'setup-failure-limit']) }
140
+ ? {
141
+ policyCause: pick(rand, [
142
+ 'infrastructure-failure-limit',
143
+ 'setup-failure-limit',
144
+ 'execution-no-progress',
145
+ ]),
146
+ }
136
147
  : {}),
137
148
  ...(rand() < 0.5 ? { round: 1 } : {}),
138
149
  question: 'q',
@@ -84,6 +84,7 @@ export interface VerifyRecord {
84
84
  attempt: number
85
85
  outcome: VerifyOutcome
86
86
  report?: ArtifactRef
87
+ skipCause?: 'post-reconcile-policy'
87
88
  reason?: string
88
89
  }
89
90
 
@@ -111,6 +112,12 @@ export interface ReconcileProgressRecord {
111
112
  }
112
113
 
113
114
  export interface LogIndex {
115
+ /** Latest post-restart policy fact; authoritative only for its originating
116
+ * reconcile completion, never for a newer review or reconcile cycle. */
117
+ reconcilePolicy?: {
118
+ reconcileSeq: number
119
+ steps: { step: string; enabled: boolean; source: string }[]
120
+ }
114
121
  /** seq of the latest `spec.revised`, else 0 — the restart boundary (§6.3). */
115
122
  restartSeq: number
116
123
  plan: LoopIndex
@@ -195,6 +202,7 @@ export type LogIndexCandidate =
195
202
  }
196
203
  | { kind: 'implement-completed'; seq: number }
197
204
  | { kind: 'verify-started'; seq: number; attempt: number }
205
+ | { kind: 'reconcile-policy'; seq: number; policy: NonNullable<LogIndex['reconcilePolicy']> }
198
206
  | { kind: 'verify-completed'; record: VerifyRecord }
199
207
  | { kind: 'finalize-completed'; seq: number }
200
208
  | { kind: 'finalize-step'; seq: number; step: string }
@@ -362,6 +370,9 @@ function foldLogIndex(acc: LogIndexAcc, events: readonly AbEvent[]): void {
362
370
  }
363
371
  break
364
372
  }
373
+ case 'verify.reconcile-policy-captured':
374
+ acc.candidates.push({ kind: 'reconcile-policy', seq: event.seq, policy: event.payload })
375
+ break
365
376
  case 'verify.completed': {
366
377
  const result = normalizeVerifyCompletion(event.payload)
367
378
  acc.maxVerifyAttemptEver = Math.max(acc.maxVerifyAttemptEver, result.attempt)
@@ -374,6 +385,7 @@ function foldLogIndex(acc: LogIndexAcc, events: readonly AbEvent[]): void {
374
385
  outcome: result.outcome,
375
386
  ...(result.report !== undefined ? { report: result.report } : {}),
376
387
  ...(result.reason !== undefined ? { reason: result.reason } : {}),
388
+ ...(result.skipCause !== undefined ? { skipCause: result.skipCause } : {}),
377
389
  },
378
390
  })
379
391
  break
@@ -451,6 +463,7 @@ function finishLogIndex(acc: LogIndexAcc): LogIndex {
451
463
  const verifyCompleted: VerifyRecord[] = []
452
464
  const verifyStarted: { seq: number; attempt: number }[] = []
453
465
  const finalizeStepsDone = new Set<string>()
466
+ let reconcilePolicy: LogIndex['reconcilePolicy']
454
467
  let lastReconcileCompletedSeq = 0
455
468
  let lastImplementCompletedSeq = 0
456
469
  let finalizeCompleted = false
@@ -521,6 +534,9 @@ function finishLogIndex(acc: LogIndexAcc): LogIndex {
521
534
  case 'verify-started':
522
535
  verifyStarted.push({ seq: candidate.seq, attempt: candidate.attempt })
523
536
  break
537
+ case 'reconcile-policy':
538
+ reconcilePolicy = candidate.policy
539
+ break
524
540
  case 'verify-completed':
525
541
  verifyCompleted.push({ ...candidate.record })
526
542
  break
@@ -594,6 +610,7 @@ function finishLogIndex(acc: LogIndexAcc): LogIndex {
594
610
  verifyCompleted,
595
611
  verifyStarted,
596
612
  maxVerifyAttemptEver: acc.maxVerifyAttemptEver,
613
+ reconcilePolicy,
597
614
  lastReconcileCompletedSeq,
598
615
  lastImplementCompletedSeq,
599
616
  finalizeCompleted,