@defrex/autobuild 0.9.0 → 0.10.1

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 (85) hide show
  1. package/README.md +97 -113
  2. package/SPEC.md +17 -4
  3. package/docs/architecture.md +109 -0
  4. package/docs/configuration.md +26 -7
  5. package/docs/remote-store-protocol.md +35 -0
  6. package/docs/website.md +4 -0
  7. package/package.json +6 -4
  8. package/packages/core/src/cli/dashboard/facts.ts +215 -0
  9. package/packages/core/src/cli/dashboard/frame-parse.ts +223 -0
  10. package/packages/core/src/cli/dashboard/model.ts +85 -147
  11. package/packages/core/src/cli/dashboard/poll.ts +7 -2
  12. package/packages/core/src/cli/dispatch-process.ts +1 -13
  13. package/packages/core/src/cli/dispatch.ts +80 -37
  14. package/packages/core/src/cli/help.ts +15 -1
  15. package/packages/core/src/cli/init-validation.ts +18 -0
  16. package/packages/core/src/cli/init.ts +3 -2
  17. package/packages/core/src/cli/installation.ts +50 -8
  18. package/packages/core/src/cli/self-update.ts +77 -2
  19. package/packages/core/src/cli/status.ts +1 -1
  20. package/packages/core/src/cli/ticket.ts +146 -1
  21. package/packages/core/src/cli/wait.ts +10 -2
  22. package/packages/core/src/cli/watch.ts +10 -2
  23. package/packages/core/src/config/live.ts +1 -0
  24. package/packages/core/src/config/pipeline-source.ts +17 -5
  25. package/packages/core/src/config/schema.ts +21 -0
  26. package/packages/core/src/integration/harness.ts +113 -1
  27. package/packages/core/src/kernel/__snapshots__/reducer-registry.test.ts.snap +1369 -0
  28. package/packages/core/src/kernel/auto-merge-default.ts +43 -9
  29. package/packages/core/src/kernel/auto-merge.ts +99 -22
  30. package/packages/core/src/kernel/dispatch-settings.ts +42 -17
  31. package/packages/core/src/kernel/dispatch-status.ts +23 -0
  32. package/packages/core/src/kernel/engine.ts +9 -438
  33. package/packages/core/src/kernel/generators/build-log.ts +259 -0
  34. package/packages/core/src/kernel/generators/repository-journals.ts +206 -0
  35. package/packages/core/src/kernel/generators/session-log.ts +72 -0
  36. package/packages/core/src/kernel/harvest.ts +62 -18
  37. package/packages/core/src/kernel/incremental-contract.ts +75 -0
  38. package/packages/core/src/kernel/incremental-fixtures.ts +211 -0
  39. package/packages/core/src/kernel/incremental.ts +53 -0
  40. package/packages/core/src/kernel/log-index.ts +620 -0
  41. package/packages/core/src/kernel/pr-attachments.ts +164 -46
  42. package/packages/core/src/kernel/reducer-registry.ts +164 -0
  43. package/packages/core/src/kernel/reducer.ts +216 -74
  44. package/packages/core/src/operator/query.ts +68 -28
  45. package/packages/core/src/operator/read-view.ts +98 -0
  46. package/packages/core/src/orchestrator/prompt.ts +3 -1
  47. package/packages/core/src/ports/tickets/fake.ts +5 -1
  48. package/packages/core/src/ports/tickets/file.ts +169 -48
  49. package/packages/core/src/ports/tickets/linear.ts +33 -1
  50. package/packages/core/src/ports/tickets/operations.ts +1 -1
  51. package/packages/core/src/ports/tickets/remote.ts +8 -1
  52. package/packages/core/src/ports/types.ts +32 -1
  53. package/packages/core/src/processes/build-execution-state.ts +31 -15
  54. package/packages/core/src/processes/build-runner.ts +184 -90
  55. package/packages/core/src/processes/dispatcher-selectors.ts +123 -0
  56. package/packages/core/src/processes/dispatcher.ts +270 -176
  57. package/packages/core/src/processes/execution-settlement.ts +72 -39
  58. package/packages/core/src/processes/harvest-execution-state.ts +41 -29
  59. package/packages/core/src/processes/infrastructure-failure-budget.ts +31 -18
  60. package/packages/core/src/processes/orchestrator-tick.ts +44 -3
  61. package/packages/core/src/processes/publication-state.ts +164 -52
  62. package/packages/core/src/processes/repo-view.ts +1436 -0
  63. package/packages/core/src/processes/sandbox-state.ts +26 -2
  64. package/packages/core/src/processes/tick-state.ts +33 -0
  65. package/packages/core/src/store/adapter.ts +10 -1
  66. package/packages/core/src/store/build-scope.ts +26 -0
  67. package/packages/core/src/store/contract.ts +337 -0
  68. package/packages/core/src/store/digest.ts +71 -18
  69. package/packages/core/src/store/local/schema.ts +17 -0
  70. package/packages/core/src/store/local/store.ts +111 -4
  71. package/packages/core/src/store/memory.ts +68 -1
  72. package/packages/core/src/store/phase-session.ts +23 -0
  73. package/packages/core/src/store/remote/client.ts +50 -1
  74. package/packages/core/src/store/remote/index.ts +2 -0
  75. package/packages/core/src/store/remote/protocol.ts +15 -0
  76. package/packages/core/src/store/repo-state-events.ts +72 -7
  77. package/packages/core/src/store/session-handle.ts +30 -0
  78. package/packages/core/src/store/session-reducer.ts +52 -11
  79. package/packages/core/src/store/snapshots.ts +88 -0
  80. package/packages/core/src/store/ticket-assets.ts +41 -8
  81. package/packages/core/src/store/types.ts +38 -0
  82. package/skills/guide/SKILL.md +38 -21
  83. package/skills/guide/references/remote-store-protocol.md +35 -0
  84. package/skills/operate/SKILL.md +146 -19
  85. package/skills/tickets/SKILL.md +57 -5
@@ -23,11 +23,9 @@
23
23
  */
24
24
  import type { Config } from '../config/schema'
25
25
  import type { AbEvent } from '../events/catalog'
26
- import { normalizeVerifyCompletion, type EventPayload } from '../events/payloads'
27
26
  import {
28
27
  isVerifyPhase,
29
28
  verifyPhase,
30
- type ArtifactRef,
31
29
  type CorePhase,
32
30
  type EscalationSource,
33
31
  type EscalationTarget,
@@ -35,10 +33,9 @@ import {
35
33
  type Finding,
36
34
  type Phase,
37
35
  type PolicyEscalationCause,
38
- type ReviewVerdictKind,
39
- type VerifyOutcome,
40
36
  } from '../ontology'
41
- import { reduceBuild, type AnsweredEscalation } from './reducer'
37
+ import { indexLog, type LogIndex, type LoopIndex } from './log-index'
38
+ import { reduceBuild, type AnsweredEscalation, type BuildState } from './reducer'
42
39
  import { stalledChains, type FindingChain } from './stall'
43
40
 
44
41
  // ── The decision contract ────────────────────────────────────────────────────
@@ -110,153 +107,15 @@ export type Decision =
110
107
  refs?: string[]
111
108
  }
112
109
 
113
- // ── Raw-log index ────────────────────────────────────────────────────────────
114
- //
115
- // Every field here is a projection the reducer does not carry (or carries
116
- // without the seq the engine routes on). Loop and verify progress counts only
117
- // events with seq > restartSeq (§6.3 immutability: every reviewer approves
118
- // conformance to ONE spec revision — a drifting spec silently converts
119
- // approvals into approvals-of-something-else, so approvals of an old spec do
120
- // not carry across `spec.revised`).
121
-
122
- interface VerdictRecord {
123
- seq: number
124
- round: number
125
- verdict: ReviewVerdictKind
126
- findings: Finding[]
127
- reason?: string
128
- }
129
-
130
- interface PlanCompletionRecord {
131
- seq: number
132
- artifact: ArtifactRef
133
- verifySteps?: string[]
134
- }
135
-
136
- interface RoundRecord {
137
- startedSeq?: number
138
- completedSeq?: number
139
- /** Plan only. Kept separately so approval snapshots this exact completion. */
140
- planCompletion?: PlanCompletionRecord
141
- verdict?: VerdictRecord
142
- }
143
-
144
- interface LoopIndex {
145
- /**
146
- * Max round in any of this loop's events over the FULL log. Round numbers
147
- * continue monotonically across spec restarts (next round = max round ever
148
- * seen + 1) so the log stays unambiguous: "plan round 1" must name exactly
149
- * one producer run, not one per spec revision.
150
- */
151
- maxRoundEver: number
152
- /** Max round with post-restart events; 0 when the loop is untouched. */
153
- maxRound: number
154
- /** Post-restart per-round event records (latest occurrence wins). */
155
- rounds: Map<number, RoundRecord>
156
- /** Latest post-restart revise verdict — the findings-feedback source. */
157
- latestRevise?: VerdictRecord
158
- /** seq of the latest post-restart approve verdict (verify cycle boundary). */
159
- latestApproveSeq: number
160
- /** Plan only: the completion present when the latest approve verdict landed.
161
- * A later orphan or superseded completion cannot replace this snapshot. */
162
- approvedPlan?: PlanCompletionRecord
163
- /** Findings per round (index round-1), post-restart — stalledChains input.
164
- * The reducer's reviewFindings spans restarts; this one must not. */
165
- findingsByRound: Finding[][]
166
- }
167
-
168
- interface VerifyRecord {
169
- seq: number
170
- step: string
171
- attempt: number
172
- outcome: VerifyOutcome
173
- report?: ArtifactRef
174
- reason?: string
175
- }
176
-
177
- interface GuidanceDelivery {
178
- escalation: string
179
- /** seq of the matching `session.started` that made the carrier actionable. */
180
- seq: number
181
- }
182
-
183
- interface ReconcileStartRecord {
184
- seq: number
185
- attempt: number
186
- baseSha: string
187
- }
188
-
189
- interface ReconcileCompletionRecord extends ReconcileStartRecord {
190
- completedSeq: number
191
- }
192
-
193
- interface ReconcileProgressRecord {
194
- seq: number
195
- conflictSeq: number
196
- attempt: number
197
- baseSha: string
198
- }
199
-
200
- interface LogIndex {
201
- /** seq of the latest `spec.revised`, else 0 — the restart boundary (§6.3). */
202
- restartSeq: number
203
- plan: LoopIndex
204
- code: LoopIndex
205
- /** Post-restart `verify.completed` facts with seq, for the same sequence-based
206
- * cycle boundary query exposed by the reducer (§15.6-A). */
207
- verifyCompleted: VerifyRecord[]
208
- /** Post-restart `verify.started` facts — a crashed step re-runs at the SAME
209
- * attempt (§15.6-C), so the current cycle's attempt must be readable from
210
- * its start events even before any completion lands. */
211
- verifyStarted: { seq: number; attempt: number }[]
212
- /**
213
- * Max verify attempt in any `verify.started`/`verify.completed` over the
214
- * FULL log. Attempt numbers continue monotonically across spec restarts and
215
- * reconcile cycles — the same rationale as LoopIndex.maxRoundEver: the log
216
- * stays unambiguous ("verify attempt 2" names exactly one cycle) and D5
217
- * failure keys (verify:<step>, round = attempt) never collide across cycles.
218
- * This high-water allocates attempt numbers; current-cycle membership is
219
- * independently sequence-based.
220
- */
221
- maxVerifyAttemptEver: number
222
- /** seq of the latest post-restart `reconcile.completed` — cycle boundary
223
- * input: reconciliation changed code, verify re-runs in full (§15.7). */
224
- lastReconcileCompletedSeq: number
225
- /** seq of the latest post-restart `implement.completed` — a verify failure
226
- * with an implement round after it was already routed (§15.6-A). */
227
- lastImplementCompletedSeq: number
228
- /** Post-restart `finalize.completed` seen (the reducer only projects pr). */
229
- finalizeCompleted: boolean
230
- /** Post-restart `finalize.step-completed` steps, ok true OR false —
231
- * post-steps are failure-tolerant (§5), so any completion counts. */
232
- finalizeStepsDone: Set<string>
233
- /** Latest `pr.conflicted` (full log — the epilogue is restart-orthogonal);
234
- * only its seq is needed for policy/dedupe. Its baseSha is detection-time
235
- * evidence, not the reconcile merge target (§15.7). */
236
- lastConflict?: { seq: number }
237
- /** A `reconcile.started` after lastConflict without its completion — a
238
- * crashed reconcile re-runs the SAME attempt from its start (§15.6-C). */
239
- conflictReconcileStarted?: { attempt: number }
240
- /** Most recent completed reconcile, paired with the latest same-occurrence
241
- * start so crash retries use the base that actually completed. */
242
- lastReconcileCompleted?: ReconcileCompletionRecord
243
- /** Explicit authoritative observation for the current repeat conflict. */
244
- lastConflictProgressCheck?: ReconcileProgressRecord
245
- /** Distinct completed attempts observed still conflicted at the same base.
246
- * A later attempt start supplies the observation for pre-event logs. */
247
- reconcileNoProgressCount: number
248
- /** Guidance carriers that reached a matching durable session launch.
249
- * Plan, implement, and agent-verify starts may cite feedback (§15.3), but a
250
- * citation alone remains recoverable across the pre-launch crash boundary.
251
- * Only a later `session.started` for the same phase and round/attempt marks
252
- * that answer delivered (§15.6-B). */
253
- guidanceDeliveries: GuidanceDelivery[]
254
- }
255
-
256
110
  export function decideNext(events: AbEvent[], config: Config): Decision {
257
- const state = reduceBuild(events)
258
- const log = indexLog(events)
111
+ return decideNextFromFacts(reduceBuild(events), indexLog(events), config)
112
+ }
259
113
 
114
+ /** `decideNext` over already-reduced facts: a caller holding the build state
115
+ * and log index (a reducer snapshot advanced to the log tail) decides without
116
+ * the event array. `decideNext(events, config)` is exactly this over
117
+ * `reduceBuild(events)` and `indexLog(events)`. */
118
+ export function decideNextFromFacts(state: BuildState, log: LogIndex, config: Config): Decision {
260
119
  // ── 1. Terminal (§15.5: terminal wins, latest wins) ────────────────────────
261
120
  if (state.status === 'aborted') return { kind: 'wait', reason: 'aborted' }
262
121
  if (state.status === 'done') return { kind: 'wait', reason: 'done' }
@@ -757,291 +616,3 @@ function guidanceDestination(
757
616
  if (isVerifyPhase(phase)) return source === 'agent' ? phase : 'code'
758
617
  return 'other'
759
618
  }
760
-
761
- // ── Raw-log indexing ─────────────────────────────────────────────────────────
762
-
763
- type ReviewVerdictPayload = EventPayload<'plan-review.verdict'>
764
-
765
- function emptyLoop(): LoopIndex {
766
- return {
767
- maxRoundEver: 0,
768
- maxRound: 0,
769
- rounds: new Map(),
770
- latestApproveSeq: 0,
771
- findingsByRound: [],
772
- }
773
- }
774
-
775
- function indexLog(events: AbEvent[]): LogIndex {
776
- // Pass 1: the restart boundary — seq of the latest spec.revised (§6.3).
777
- let restartSeq = 0
778
- for (const event of events) {
779
- if (event.type === 'spec.revised') restartSeq = event.seq
780
- }
781
-
782
- const plan = emptyLoop()
783
- const code = emptyLoop()
784
- const verifyCompleted: VerifyRecord[] = []
785
- const verifyStarted: { seq: number; attempt: number }[] = []
786
- let maxVerifyAttemptEver = 0
787
- const finalizeStepsDone = new Set<string>()
788
- const guidanceDeliveries: GuidanceDelivery[] = []
789
- const pendingGuidanceStarts = new Map<string, { escalation: string; seq: number }>()
790
- let lastReconcileCompletedSeq = 0
791
- let lastImplementCompletedSeq = 0
792
- let finalizeCompleted = false
793
- let lastConflict: { seq: number } | undefined
794
- let conflictReconcileStarted: { attempt: number } | undefined
795
- const conflictSeqs = new Set<number>()
796
- const reconcileStarts: ReconcileStartRecord[] = []
797
- const reconcileCompletions: ReconcileCompletionRecord[] = []
798
- const reconcileProgressChecks: ReconcileProgressRecord[] = []
799
- let activeReconcileStart: ReconcileStartRecord | undefined
800
-
801
- /** Track a loop round: maxRoundEver over the full log; the per-round record
802
- * only for post-restart events (returns undefined pre-restart). */
803
- const roundRecord = (loop: LoopIndex, r: number, post: boolean): RoundRecord | undefined => {
804
- if (r > loop.maxRoundEver) loop.maxRoundEver = r
805
- if (!post) return undefined
806
- if (r > loop.maxRound) loop.maxRound = r
807
- let record = loop.rounds.get(r)
808
- if (record === undefined) {
809
- record = {}
810
- loop.rounds.set(r, record)
811
- }
812
- return record
813
- }
814
-
815
- const noteGuidanceStart = (key: string, feedback: Feedback | undefined, seq: number): void => {
816
- // A newer start is the authoritative carrier for this exact occurrence.
817
- // In particular, a guidance-free retry must not let its later session
818
- // consume an older citation that never launched.
819
- if (feedback !== undefined && 'guidance' in feedback) {
820
- pendingGuidanceStarts.set(key, { escalation: feedback.guidance.escalation, seq })
821
- } else {
822
- pendingGuidanceStarts.delete(key)
823
- }
824
- }
825
-
826
- const noteVerdict = (
827
- loop: LoopIndex,
828
- payload: ReviewVerdictPayload,
829
- seq: number,
830
- post: boolean,
831
- ): void => {
832
- const record = roundRecord(loop, payload.round, post)
833
- if (record === undefined) return
834
- const verdict: VerdictRecord = {
835
- seq,
836
- round: payload.round,
837
- verdict: payload.verdict,
838
- findings: payload.findings,
839
- reason: payload.reason,
840
- }
841
- record.verdict = verdict
842
- if (payload.verdict === 'revise') loop.latestRevise = verdict
843
- if (payload.verdict === 'approve') {
844
- loop.latestApproveSeq = seq
845
- // Snapshot at verdict time. A plan.completed appended later — even for
846
- // this round — was never reviewed and therefore has no authority.
847
- if (loop === plan) loop.approvedPlan = record.planCompletion
848
- }
849
- // Findings per round, reducer-style padding (rounds without verdicts stay
850
- // empty — including every pre-restart round, which is the point).
851
- while (loop.findingsByRound.length < payload.round) loop.findingsByRound.push([])
852
- loop.findingsByRound[payload.round - 1] = payload.findings
853
- }
854
-
855
- for (const event of events) {
856
- const post = event.seq > restartSeq
857
- switch (event.type) {
858
- case 'plan.started': {
859
- noteGuidanceStart(`plan@${event.payload.round}`, event.payload.feedback, event.seq)
860
- const record = roundRecord(plan, event.payload.round, post)
861
- if (record !== undefined) record.startedSeq = event.seq
862
- break
863
- }
864
- case 'plan.completed': {
865
- const record = roundRecord(plan, event.payload.round, post)
866
- if (record !== undefined) {
867
- record.completedSeq = event.seq
868
- record.planCompletion = {
869
- seq: event.seq,
870
- artifact: event.payload.artifact,
871
- ...(event.payload.verifySteps !== undefined
872
- ? { verifySteps: [...event.payload.verifySteps] }
873
- : {}),
874
- }
875
- }
876
- break
877
- }
878
- case 'plan-review.started':
879
- roundRecord(plan, event.payload.round, post)
880
- break
881
- case 'plan-review.verdict':
882
- noteVerdict(plan, event.payload, event.seq, post)
883
- break
884
-
885
- case 'implement.started': {
886
- noteGuidanceStart(`implement@${event.payload.round}`, event.payload.feedback, event.seq)
887
- const record = roundRecord(code, event.payload.round, post)
888
- if (record !== undefined) record.startedSeq = event.seq
889
- break
890
- }
891
- case 'implement.completed': {
892
- const record = roundRecord(code, event.payload.round, post)
893
- if (record !== undefined) record.completedSeq = event.seq
894
- if (post) lastImplementCompletedSeq = event.seq
895
- break
896
- }
897
- case 'code-review.started':
898
- roundRecord(code, event.payload.round, post)
899
- break
900
- case 'code-review.verdict':
901
- noteVerdict(code, event.payload, event.seq, post)
902
- break
903
-
904
- case 'verify.started': {
905
- noteGuidanceStart(
906
- `${verifyPhase(event.payload.step)}@${event.payload.attempt}`,
907
- event.payload.feedback,
908
- event.seq,
909
- )
910
- maxVerifyAttemptEver = Math.max(maxVerifyAttemptEver, event.payload.attempt)
911
- if (post) verifyStarted.push({ seq: event.seq, attempt: event.payload.attempt })
912
- break
913
- }
914
- case 'session.started': {
915
- if (event.payload.round === undefined) break
916
- const key = `${event.payload.phase}@${event.payload.round}`
917
- const carrier = pendingGuidanceStarts.get(key)
918
- if (carrier !== undefined && carrier.seq < event.seq) {
919
- guidanceDeliveries.push({ escalation: carrier.escalation, seq: event.seq })
920
- pendingGuidanceStarts.delete(key)
921
- }
922
- break
923
- }
924
- case 'verify.completed': {
925
- const result = normalizeVerifyCompletion(event.payload)
926
- maxVerifyAttemptEver = Math.max(maxVerifyAttemptEver, result.attempt)
927
- if (post) {
928
- verifyCompleted.push({
929
- seq: event.seq,
930
- step: result.step,
931
- attempt: result.attempt,
932
- outcome: result.outcome,
933
- ...(result.report !== undefined ? { report: result.report } : {}),
934
- ...(result.reason !== undefined ? { reason: result.reason } : {}),
935
- })
936
- }
937
- break
938
- }
939
-
940
- case 'finalize.completed':
941
- if (post) finalizeCompleted = true
942
- break
943
- case 'finalize.step-completed':
944
- if (post) finalizeStepsDone.add(event.payload.step)
945
- break
946
-
947
- case 'pr.conflicted':
948
- lastConflict = { seq: event.seq }
949
- conflictSeqs.add(event.seq)
950
- conflictReconcileStarted = undefined
951
- break
952
- case 'reconcile.progress-checked':
953
- reconcileProgressChecks.push({ seq: event.seq, ...event.payload })
954
- break
955
- case 'reconcile.started': {
956
- const start = { seq: event.seq, ...event.payload }
957
- reconcileStarts.push(start)
958
- activeReconcileStart = start
959
- if (lastConflict !== undefined && event.seq > lastConflict.seq) {
960
- conflictReconcileStarted = { attempt: event.payload.attempt }
961
- }
962
- break
963
- }
964
- case 'reconcile.completed':
965
- if (post) lastReconcileCompletedSeq = event.seq
966
- if (activeReconcileStart !== undefined) {
967
- reconcileCompletions.push({
968
- ...activeReconcileStart,
969
- completedSeq: event.seq,
970
- })
971
- activeReconcileStart = undefined
972
- }
973
- conflictReconcileStarted = undefined
974
- break
975
-
976
- default:
977
- break
978
- }
979
- }
980
-
981
- // One completed occurrence per monotonic attempt. A later duplicate
982
- // completion is safer to pair with its own latest start than with an older
983
- // aggregate high-water, and malformed unmatched completions classify nothing.
984
- const completedByAttempt = new Map<number, ReconcileCompletionRecord>()
985
- for (const completion of reconcileCompletions) {
986
- completedByAttempt.set(completion.attempt, completion)
987
- }
988
- const completed = [...completedByAttempt.values()].sort(
989
- (left, right) => left.completedSeq - right.completedSeq,
990
- )
991
-
992
- let reconcileNoProgressCount = 0
993
- for (const completion of completed) {
994
- const nextStart = reconcileStarts.find(
995
- (start) => start.seq > completion.completedSeq && start.attempt > completion.attempt,
996
- )
997
- const observationLimit = nextStart?.seq ?? Number.POSITIVE_INFINITY
998
- // Explicit checks win over the historical fallback. Use the latest one
999
- // that could have routed this next occurrence; duplicate conflict facts do
1000
- // not count one completed reconcile more than once.
1001
- const explicit = reconcileProgressChecks
1002
- .filter(
1003
- (check) =>
1004
- check.attempt === completion.attempt &&
1005
- check.seq > completion.completedSeq &&
1006
- check.seq < observationLimit &&
1007
- check.conflictSeq > completion.completedSeq &&
1008
- check.seq > check.conflictSeq &&
1009
- conflictSeqs.has(check.conflictSeq),
1010
- )
1011
- .at(-1)
1012
- const observedBase = explicit?.baseSha ?? nextStart?.baseSha
1013
- if (observedBase === completion.baseSha) reconcileNoProgressCount += 1
1014
- }
1015
-
1016
- const lastReconcileCompleted = completed.at(-1)
1017
- const lastConflictProgressCheck =
1018
- lastConflict === undefined || lastReconcileCompleted === undefined
1019
- ? undefined
1020
- : reconcileProgressChecks
1021
- .filter(
1022
- (check) =>
1023
- check.conflictSeq === lastConflict.seq &&
1024
- check.attempt === lastReconcileCompleted.attempt &&
1025
- check.seq > lastConflict.seq,
1026
- )
1027
- .at(-1)
1028
-
1029
- return {
1030
- restartSeq,
1031
- plan,
1032
- code,
1033
- verifyCompleted,
1034
- verifyStarted,
1035
- maxVerifyAttemptEver,
1036
- lastReconcileCompletedSeq,
1037
- lastImplementCompletedSeq,
1038
- finalizeCompleted,
1039
- finalizeStepsDone,
1040
- lastConflict,
1041
- conflictReconcileStarted,
1042
- lastReconcileCompleted,
1043
- lastConflictProgressCheck,
1044
- reconcileNoProgressCount,
1045
- guidanceDeliveries,
1046
- }
1047
- }