@alecsibilia/luca 14.0.0-alpha.2 → 14.0.0-alpha.21
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.
- package/CHANGELOG.md +76 -0
- package/README.md +7 -2
- package/board/client/board-look.ts +31 -1
- package/board/client/board-panel-parts.tsx +150 -0
- package/board/client/board-panel-stages.ts +99 -0
- package/board/client/board-panel-styles.ts +223 -0
- package/board/client/board-panel.tsx +77 -1275
- package/board/client/engine-life.ts +48 -0
- package/board/client/final-review-stack.tsx +144 -0
- package/board/client/heartbeat.tsx +61 -0
- package/board/client/helper-lines.tsx +69 -0
- package/board/client/live-feed.tsx +86 -0
- package/board/client/live-line.ts +73 -0
- package/board/client/model-line.tsx +178 -0
- package/board/client/needs-you-section.tsx +133 -0
- package/board/client/one-line.tsx +193 -0
- package/board/client/repo-wait-banner.tsx +69 -0
- package/board/client/run-footer.tsx +68 -0
- package/board/client/run-header.tsx +189 -0
- package/board/client/run-picker.tsx +98 -0
- package/board/client/status-bar.tsx +131 -0
- package/board/client/step-dots.tsx +127 -0
- package/board/client/stuck-actions.tsx +269 -0
- package/board/client/ticket-card-view.tsx +238 -0
- package/board/client/ticket-detail.tsx +87 -0
- package/board/client/ticket-stack.tsx +119 -0
- package/board/client/ticket-wait.ts +188 -0
- package/board/client/timeline-rows.tsx +41 -14
- package/board/client/usage-line.tsx +51 -0
- package/board/client/wait-line.tsx +39 -0
- package/board/index.client.tsx +1 -1
- package/board/index.server.ts +7 -1
- package/board/package.json +1 -1
- package/board/server/board-panel-state-helpers.ts +67 -0
- package/board/server/board-server-check.ts +294 -0
- package/board/server/board-server-engine.ts +129 -0
- package/board/server/board-server-events.ts +134 -0
- package/board/server/board-server-read.ts +190 -0
- package/board/server/board-server-resume.ts +164 -0
- package/board/server/board-server-start.ts +174 -0
- package/board/server/board-server-store.ts +281 -0
- package/board/server/board-server-types.ts +114 -0
- package/board/server/board-server-util.ts +4 -0
- package/board/server/board-server.ts +52 -943
- package/board/server/board-vocabulary-engine.ts +144 -0
- package/board/server/board-vocabulary-review.ts +115 -0
- package/board/server/board-vocabulary-run.ts +145 -0
- package/board/server/board-vocabulary-shapes.ts +153 -0
- package/board/server/board-vocabulary.ts +20 -375
- package/board/server/current-step-panel-helpers.ts +108 -0
- package/board/server/describe-record.ts +403 -0
- package/board/server/engine-launch.ts +20 -3
- package/board/server/engine-restart-helpers.ts +105 -0
- package/board/server/engine-watch.ts +45 -5
- package/board/server/journal-rebuild-helpers.ts +169 -0
- package/board/server/live-file.ts +130 -0
- package/board/server/luca-version.ts +1 -1
- package/board/server/make-rows.ts +14 -629
- package/board/server/record-texts.ts +350 -0
- package/board/server/reduce-board-agent-start.ts +224 -0
- package/board/server/reduce-board-agents.ts +160 -0
- package/board/server/reduce-board-counters.ts +138 -0
- package/board/server/reduce-board-create.ts +148 -0
- package/board/server/reduce-board-final-review.ts +174 -0
- package/board/server/reduce-board-needs-you.ts +283 -0
- package/board/server/reduce-board-reasons.ts +59 -0
- package/board/server/reduce-board-run.ts +255 -0
- package/board/server/reduce-board-settle.ts +88 -0
- package/board/server/reduce-board-steps.ts +226 -0
- package/board/server/reduce-board-text.ts +139 -0
- package/board/server/reduce-board-ticket-checks.ts +168 -0
- package/board/server/reduce-board-ticket-join.ts +144 -0
- package/board/server/reduce-board-ticket-start.ts +132 -0
- package/board/server/reduce-board-update.ts +117 -0
- package/board/server/reduce-board-usage.ts +247 -0
- package/board/server/reduce-board.ts +100 -1917
- package/board/server/reply-post.ts +407 -0
- package/board/server/run-registry.ts +8 -4
- package/board/server/ticket-stages-panel-helpers.ts +296 -0
- package/board/shared/board-rows.ts +9 -0
- package/board/shared/board-rpc.ts +42 -0
- package/board/shared/board-state-counts.ts +77 -0
- package/board/shared/board-state-live.ts +99 -0
- package/board/shared/board-state-review.ts +59 -0
- package/board/shared/board-state-run.ts +236 -0
- package/board/shared/board-state-ticket.ts +257 -0
- package/board/shared/board-state-usage.ts +107 -0
- package/board/shared/board-state.ts +97 -567
- package/board/shared/reply-actions.ts +207 -0
- package/engine/agents/agent-launcher.ts +27 -4
- package/engine/agents/claude-launcher-helpers.ts +233 -0
- package/engine/agents/claude-launcher.ts +28 -669
- package/engine/agents/claude-messages.ts +212 -0
- package/engine/agents/claude-options.ts +43 -8
- package/engine/agents/common-instructions.ts +138 -0
- package/engine/agents/input-channel.ts +36 -0
- package/engine/agents/launch-paths.ts +29 -0
- package/engine/agents/launch-session.ts +227 -0
- package/engine/agents/learner-instructions.ts +31 -0
- package/engine/agents/open-session.ts +210 -0
- package/engine/agents/prompt-sections.ts +95 -0
- package/engine/agents/rejoin-prompts.ts +135 -0
- package/engine/agents/reviewer-instructions.ts +99 -0
- package/engine/agents/role-instructions.ts +31 -244
- package/engine/agents/role-prompts.ts +39 -109
- package/engine/agents/role-results.ts +106 -7
- package/engine/agents/scripted-launcher.ts +21 -6
- package/engine/agents/session-pool.ts +124 -0
- package/engine/agents/turn-progress.ts +283 -0
- package/engine/agents/writer-instructions.ts +151 -0
- package/engine/cli/computer-adapters-real.ts +15 -3
- package/engine/cli/computer-adapters.ts +2 -0
- package/engine/cli/computer-checks.ts +87 -4
- package/engine/cli/config-reload-text.ts +39 -0
- package/engine/cli/decision-model-setup.ts +70 -0
- package/engine/cli/doctor-command.ts +1 -0
- package/engine/cli/doctor.ts +21 -3
- package/engine/cli/going-runs.ts +192 -36
- package/engine/cli/init-command.ts +1 -0
- package/engine/cli/init.ts +23 -1
- package/engine/cli/live-runs.ts +73 -0
- package/engine/cli/luca-run.ts +42 -7
- package/engine/cli/luca-skills.ts +183 -0
- package/engine/cli/luca.ts +8 -1
- package/engine/cli/models-command.ts +119 -0
- package/engine/cli/read-run.ts +81 -0
- package/engine/cli/run-args.ts +33 -6
- package/engine/cli/run-demo.ts +143 -0
- package/engine/cli/run-end.ts +184 -0
- package/engine/cli/run-modes-helpers.ts +81 -0
- package/engine/cli/run-modes.ts +62 -439
- package/engine/cli/setup.ts +5 -48
- package/engine/cli/unfinished-runs.ts +122 -0
- package/engine/cli/upgrade-command.ts +212 -30
- package/engine/cli/upgrade-finish.ts +149 -0
- package/engine/cli/upgrade.ts +112 -71
- package/engine/config/config-fields.ts +127 -0
- package/engine/config/config-reload.ts +250 -0
- package/engine/config/engine-config-schema.ts +235 -0
- package/engine/config/engine-config.ts +72 -142
- package/engine/config/test-commands.ts +102 -0
- package/engine/core/agent-guards-helpers.ts +84 -0
- package/engine/core/agent-turn.ts +395 -0
- package/engine/core/already-done.ts +44 -1
- package/engine/core/build-action.ts +214 -0
- package/engine/core/build-context.ts +135 -0
- package/engine/core/build-launch.ts +259 -0
- package/engine/core/commit-in.ts +282 -0
- package/engine/core/decide-build-early.ts +108 -0
- package/engine/core/decide-build-ending.ts +145 -0
- package/engine/core/decide-build-helpers.ts +87 -0
- package/engine/core/decide-build-tickets.ts +207 -0
- package/engine/core/decide-build-view.ts +103 -0
- package/engine/core/decide-build.ts +101 -1368
- package/engine/core/decide-final-fix.ts +203 -0
- package/engine/core/decide-final-review.ts +55 -310
- package/engine/core/decide-red-green.ts +398 -0
- package/engine/core/decide-rejoin.ts +259 -0
- package/engine/core/decide-repo-wait.ts +129 -0
- package/engine/core/decide-run-budget.ts +86 -12
- package/engine/core/decide-stuck-helpers.ts +127 -0
- package/engine/core/decide-stuck.ts +60 -8
- package/engine/core/decide-ticket-review.ts +95 -0
- package/engine/core/decide-ticket.ts +267 -0
- package/engine/core/decide-waits.ts +47 -0
- package/engine/core/decide.ts +74 -23
- package/engine/core/engine-chores.ts +163 -0
- package/engine/core/environment-rerun.ts +83 -0
- package/engine/core/evidence-text.ts +84 -0
- package/engine/core/execute-action.ts +303 -0
- package/engine/core/execute-already-done-check.ts +133 -0
- package/engine/core/execute-build.ts +68 -944
- package/engine/core/execute-changeset.ts +5 -7
- package/engine/core/execute-final-review.ts +125 -13
- package/engine/core/execute-gates.ts +182 -0
- package/engine/core/execute-intake.ts +130 -0
- package/engine/core/execute-join.ts +276 -0
- package/engine/core/execute-memory.ts +12 -0
- package/engine/core/execute-pull-request.ts +84 -0
- package/engine/core/execute-red-check.ts +219 -0
- package/engine/core/execute-repo-wait.ts +129 -0
- package/engine/core/execute-stuck.ts +25 -10
- package/engine/core/execute-waits.ts +158 -0
- package/engine/core/execute-with-jev.ts +118 -0
- package/engine/core/execute.ts +124 -831
- package/engine/core/final-failure-cap.ts +38 -0
- package/engine/core/final-review-action.ts +125 -0
- package/engine/core/final-review-text.ts +63 -17
- package/engine/core/final-stuck-text.ts +86 -0
- package/engine/core/fix-loop-text.ts +49 -2
- package/engine/core/left-out.ts +120 -0
- package/engine/core/live-file.ts +372 -0
- package/engine/core/loop-caps.ts +25 -2
- package/engine/core/not-in-run.ts +7 -3
- package/engine/core/pull-request-text.ts +255 -6
- package/engine/core/repo-wait-text.ts +81 -0
- package/engine/core/review-text.ts +55 -1
- package/engine/core/run-crash-recovery-helpers.ts +16 -0
- package/engine/core/run-session-close-helpers.ts +96 -0
- package/engine/core/run-start.ts +148 -0
- package/engine/core/run-stuck-text.ts +86 -0
- package/engine/core/schedule-rules.ts +193 -0
- package/engine/core/stuck-detail-text.ts +89 -0
- package/engine/core/stuck-format.ts +22 -0
- package/engine/core/stuck-text.ts +29 -332
- package/engine/core/ticket-stuck-text.ts +192 -0
- package/engine/core/worktree-changes.ts +106 -0
- package/engine/gates/already-done-check.ts +120 -0
- package/engine/gates/feature-map.ts +96 -0
- package/engine/gates/gate-runner.ts +108 -108
- package/engine/gates/gate-schemas.ts +61 -2
- package/engine/gates/leftover-scan.ts +154 -31
- package/engine/gates/new-tests.ts +45 -0
- package/engine/gates/own-files-check.ts +98 -0
- package/engine/gates/prepare-check.ts +60 -0
- package/engine/gates/prepare-slots.ts +99 -0
- package/engine/gates/red-check.ts +184 -16
- package/engine/gates/shell-check.ts +64 -0
- package/engine/gates/slot-waits.ts +55 -0
- package/engine/gates/slow-test-runner.ts +59 -0
- package/engine/gates/test-checks.ts +161 -0
- package/engine/gates/test-runner.ts +164 -5
- package/engine/gates/test-slots.ts +48 -0
- package/engine/git/git-adapter.ts +55 -396
- package/engine/git/git-commits.ts +132 -0
- package/engine/git/git-join.ts +139 -0
- package/engine/git/git-read.ts +123 -0
- package/engine/git/git-run.ts +32 -0
- package/engine/git/git-worktrees.ts +143 -0
- package/engine/git/outside-links.ts +55 -0
- package/engine/guards/after-turn-check.ts +31 -5
- package/engine/guards/guard-hook.ts +60 -12
- package/engine/guards/guard-roles.ts +68 -0
- package/engine/guards/helper-rules.ts +92 -0
- package/engine/guards/permission-rules.ts +161 -0
- package/engine/guards/role-rules-helpers.ts +48 -0
- package/engine/guards/role-rules.ts +34 -606
- package/engine/guards/shell-rules.ts +344 -0
- package/engine/guards/worktree-git.ts +208 -0
- package/engine/guards/worktree-snapshot.ts +412 -0
- package/engine/guards/worktree-state.ts +28 -825
- package/engine/guards/worktree-undo.ts +260 -0
- package/engine/guards/write-rules.ts +149 -0
- package/engine/index.ts +30 -9
- package/engine/intake/criteria-checks.ts +114 -0
- package/engine/intake/intake-checks.ts +164 -30
- package/engine/intake/intake-schemas.ts +37 -2
- package/engine/jev/clef-client.ts +259 -0
- package/engine/jev/decision-model-credentials.ts +212 -0
- package/engine/jev/jev-jobs.ts +144 -60
- package/engine/jev/jev-schemas.ts +86 -5
- package/engine/jev/jev-shadow-helpers.ts +218 -0
- package/engine/jev/jev-shadow.ts +109 -64
- package/engine/jev/model-pick.ts +275 -0
- package/engine/journal/agent-entries.ts +167 -0
- package/engine/journal/agent-message-entries.ts +72 -0
- package/engine/journal/agent-turn-replay.ts +203 -0
- package/engine/journal/already-done-entries.ts +55 -0
- package/engine/journal/commit-entries.ts +56 -0
- package/engine/journal/cross-ticket-replay.ts +222 -0
- package/engine/journal/decision-model-entries.ts +86 -0
- package/engine/journal/entry-fields.ts +10 -0
- package/engine/journal/final-review-entries.ts +128 -0
- package/engine/journal/final-review-replay.ts +324 -0
- package/engine/journal/final-review-round.ts +320 -0
- package/engine/journal/final-review-state.ts +180 -0
- package/engine/journal/gate-entries.ts +81 -0
- package/engine/journal/intake-entries.ts +87 -0
- package/engine/journal/join-entries.ts +126 -0
- package/engine/journal/journal-entry-schema.ts +218 -0
- package/engine/journal/journal-kinds.ts +97 -0
- package/engine/journal/journal-record-schema.ts +218 -0
- package/engine/journal/journal-record.ts +43 -1400
- package/engine/journal/journal.ts +6 -1
- package/engine/journal/limit-entries.ts +90 -0
- package/engine/journal/memory-entries.ts +124 -0
- package/engine/journal/memory-replay.ts +157 -0
- package/engine/journal/plan-replay.ts +139 -0
- package/engine/journal/pull-request-entries.ts +41 -0
- package/engine/journal/replay.ts +157 -2144
- package/engine/journal/reply-replay.ts +144 -0
- package/engine/journal/repo-wait-entries.ts +53 -0
- package/engine/journal/run-entries.ts +172 -0
- package/engine/journal/run-state.ts +264 -0
- package/engine/journal/shared-failure-replay.ts +133 -0
- package/engine/journal/stuck-entries.ts +193 -0
- package/engine/journal/ticket-progress.ts +392 -0
- package/engine/journal/ticket-replay.ts +411 -0
- package/engine/journal/ticket-result-replay.ts +364 -0
- package/engine/journal/ticket-retry-replay.ts +142 -0
- package/engine/journal/worktree-entries.ts +122 -0
- package/engine/models/model-score.ts +512 -0
- package/engine/shell/run-command.ts +187 -18
- package/engine/testing/agent-turn-fixtures.ts +287 -0
- package/engine/testing/already-done-fixtures.ts +97 -0
- package/engine/testing/build-fixtures.ts +68 -973
- package/engine/testing/checkouts-fixtures.ts +48 -0
- package/engine/testing/final-review-fixtures.ts +62 -1
- package/engine/testing/final-review-steps.ts +143 -0
- package/engine/testing/limit-fixtures.ts +85 -0
- package/engine/testing/live-file-fixtures.ts +57 -0
- package/engine/testing/practice-repo.ts +10 -4
- package/engine/testing/practice-run.ts +1 -1
- package/engine/testing/reply-fixtures.ts +88 -0
- package/engine/testing/run-budget-fixtures.ts +165 -0
- package/engine/testing/run-fixtures.ts +219 -0
- package/engine/testing/sdk-play.ts +177 -0
- package/engine/testing/setup-repo.ts +194 -0
- package/engine/testing/step-record-fixtures.ts +55 -0
- package/engine/testing/ticket-step-fixtures.ts +272 -0
- package/engine/testing/wait-scenarios.ts +186 -0
- package/engine/tracker/gh-retry.ts +217 -0
- package/engine/tracker/github-tracker.ts +310 -90
- package/engine/tracker/in-memory-tracker.ts +8 -4
- package/engine/tracker/tracker.ts +131 -6
- package/package.json +2 -1
- package/skills/luca-retro/SKILL.md +74 -0
- package/skills/luca-retro/scripts/retro-summary.ts +1356 -0
- package/skills/luca-unstick/SKILL.md +153 -0
- package/skills/luca-unstick/scripts/stuck-summary.ts +1063 -0
- package/engine/jev/jev-client.ts +0 -173
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { ENTRY_FIELDS } from './entry-fields'
|
|
4
|
+
import { StuckReasonSchema } from './stuck-entries'
|
|
5
|
+
|
|
6
|
+
import { LensNameSchema } from '../agents/role-results'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The journal entries of the final review: its rounds, each lens's
|
|
10
|
+
* reviewer, fix rounds, and how it ends (stuck, retried, passed, shipped).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A final review round started: the run branch is reviewed from `from_sha`
|
|
15
|
+
* (round 1 and the fresh pass: where the run branch started; later rounds:
|
|
16
|
+
* the previous round's `head_sha`) to `head_sha`, its HEAD now. `lenses` are
|
|
17
|
+
* the lenses due this round (every lens in round 1 and the fresh pass, then
|
|
18
|
+
* only those that had blocking findings), `files` the files that diff changes, and `rules` the rule files
|
|
19
|
+
* of the engine config, read by the engine word for word (`text` is `null`
|
|
20
|
+
* for a file it could not read), for the rules lens. Written with
|
|
21
|
+
* `ticket: null`.
|
|
22
|
+
*/
|
|
23
|
+
export const FinalReviewStartedEntrySchema = z.object({
|
|
24
|
+
...ENTRY_FIELDS,
|
|
25
|
+
kind: z.literal('final_review_started'),
|
|
26
|
+
content: z.object({
|
|
27
|
+
round: z.number().int().min(1),
|
|
28
|
+
from_sha: z.string().min(1),
|
|
29
|
+
head_sha: z.string().min(1),
|
|
30
|
+
lenses: z.array(LensNameSchema),
|
|
31
|
+
files: z.array(z.string()).default([]),
|
|
32
|
+
rules: z.array(
|
|
33
|
+
z.object({ path: z.string(), text: z.string().nullable() })
|
|
34
|
+
),
|
|
35
|
+
/**
|
|
36
|
+
* Round 1 with a slow test command: its slow tests are due once its
|
|
37
|
+
* lenses are in (#563). An older engine's record has none.
|
|
38
|
+
*/
|
|
39
|
+
slow_due: z.boolean().optional(),
|
|
40
|
+
/**
|
|
41
|
+
* The fresh pass (#548): every lens reads the whole run branch again,
|
|
42
|
+
* without earlier findings, after the last fix round. `false` for
|
|
43
|
+
* any other round, and in older journals.
|
|
44
|
+
*/
|
|
45
|
+
fresh: z.boolean().default(false),
|
|
46
|
+
}),
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
/** A lens's reviewer is about to start, right before its `agent_started`. */
|
|
50
|
+
export const LensStartedEntrySchema = z.object({
|
|
51
|
+
...ENTRY_FIELDS,
|
|
52
|
+
kind: z.literal('lens_started'),
|
|
53
|
+
content: z.object({
|
|
54
|
+
lens: LensNameSchema,
|
|
55
|
+
round: z.number().int().min(1),
|
|
56
|
+
}),
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A lens's reviewer finished, right after its `agent_finished`: its findings
|
|
61
|
+
* counted by severity. Not written for a failed turn.
|
|
62
|
+
*/
|
|
63
|
+
export const LensFinishedEntrySchema = z.object({
|
|
64
|
+
...ENTRY_FIELDS,
|
|
65
|
+
kind: z.literal('lens_finished'),
|
|
66
|
+
content: z.object({
|
|
67
|
+
lens: LensNameSchema,
|
|
68
|
+
round: z.number().int().min(1),
|
|
69
|
+
findings: z.object({
|
|
70
|
+
blocker: z.number().int().min(0),
|
|
71
|
+
should_fix: z.number().int().min(0),
|
|
72
|
+
nit: z.number().int().min(0),
|
|
73
|
+
}),
|
|
74
|
+
}),
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
/** A final review fix round starts, before its first fixer. */
|
|
78
|
+
export const FinalReviewFixingEntrySchema = z.object({
|
|
79
|
+
...ENTRY_FIELDS,
|
|
80
|
+
kind: z.literal('final_review_fixing'),
|
|
81
|
+
content: z.object({ round: z.number().int().min(1) }),
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
/** The final review is stuck: the PR waits for a person's reply (#366). */
|
|
85
|
+
export const FinalReviewStuckEntrySchema = z.object({
|
|
86
|
+
...ENTRY_FIELDS,
|
|
87
|
+
kind: z.literal('final_review_stuck'),
|
|
88
|
+
content: z.object({ reason: StuckReasonSchema, detail: z.string() }),
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The owner replied `retry` to the stuck final review: its open fix round
|
|
93
|
+
* starts over as round 1 with fresh fixers and fresh counts, keeping any
|
|
94
|
+
* edits the owner made in the run branch's worktree.
|
|
95
|
+
*/
|
|
96
|
+
export const FinalReviewRetriedEntrySchema = z.object({
|
|
97
|
+
...ENTRY_FIELDS,
|
|
98
|
+
kind: z.literal('final_review_retried'),
|
|
99
|
+
content: z.object({}),
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
/** Every lens due in the latest round approved; the PR opens next. */
|
|
103
|
+
export const FinalReviewPassedEntrySchema = z.object({
|
|
104
|
+
...ENTRY_FIELDS,
|
|
105
|
+
kind: z.literal('final_review_passed'),
|
|
106
|
+
content: z.object({}),
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The person replied `ship` to the stuck final review: the PR opens with the
|
|
111
|
+
* findings still open listed at the top. Appended by the reply reader (#366)
|
|
112
|
+
* through `shipFinalReview`. `commit` is the commit of the edits left
|
|
113
|
+
* uncommitted in the run branch's worktree at ship time (#509), listed in
|
|
114
|
+
* the PR as not reviewed; with none, it is left out.
|
|
115
|
+
*/
|
|
116
|
+
export const FinalReviewShippedEntrySchema = z.object({
|
|
117
|
+
...ENTRY_FIELDS,
|
|
118
|
+
kind: z.literal('final_review_shipped'),
|
|
119
|
+
content: z.object({
|
|
120
|
+
commit: z
|
|
121
|
+
.object({
|
|
122
|
+
sha: z.string(),
|
|
123
|
+
message: z.string(),
|
|
124
|
+
files: z.array(z.string()),
|
|
125
|
+
})
|
|
126
|
+
.optional(),
|
|
127
|
+
}),
|
|
128
|
+
})
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The final review's records in replay: which records are the final
|
|
3
|
+
* review's, its state after each, its stuck report and reply, and its
|
|
4
|
+
* `retry`.
|
|
5
|
+
*/
|
|
6
|
+
import omit from 'lodash/omit'
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
assumptionsOf,
|
|
10
|
+
isFixerRole,
|
|
11
|
+
outOfTurnsAfter,
|
|
12
|
+
sessionsAfter,
|
|
13
|
+
} from './agent-turn-replay'
|
|
14
|
+
import { finalResultChange, roundDone, settleRound } from './final-review-round'
|
|
15
|
+
import type { FinalReviewState } from './final-review-state'
|
|
16
|
+
import type { JournalRecord } from './journal-record'
|
|
17
|
+
import type { RunState } from './run-state'
|
|
18
|
+
import type { CrashCounts } from './step-records'
|
|
19
|
+
|
|
20
|
+
/** The final review's own kinds, and the kinds it shares with tickets. */
|
|
21
|
+
type FinalRecord = Extract<
|
|
22
|
+
JournalRecord,
|
|
23
|
+
{
|
|
24
|
+
kind:
|
|
25
|
+
| 'final_review_started'
|
|
26
|
+
| 'lens_started'
|
|
27
|
+
| 'lens_finished'
|
|
28
|
+
| 'final_review_fixing'
|
|
29
|
+
| 'final_review_stuck'
|
|
30
|
+
| 'final_review_passed'
|
|
31
|
+
| 'final_review_shipped'
|
|
32
|
+
| 'agent_started'
|
|
33
|
+
| 'agent_finished'
|
|
34
|
+
| 'agent_failed'
|
|
35
|
+
| 'agent_session'
|
|
36
|
+
| 'gates_run'
|
|
37
|
+
| 'leftover_scan'
|
|
38
|
+
| 'commit_made'
|
|
39
|
+
| 'run_branch_pushed'
|
|
40
|
+
}
|
|
41
|
+
>
|
|
42
|
+
|
|
43
|
+
const FINAL_KINDS = new Set<JournalRecord['kind']>([
|
|
44
|
+
'final_review_started',
|
|
45
|
+
'lens_started',
|
|
46
|
+
'lens_finished',
|
|
47
|
+
'final_review_fixing',
|
|
48
|
+
'final_review_stuck',
|
|
49
|
+
'final_review_passed',
|
|
50
|
+
'final_review_shipped',
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
/** Kinds tickets journal too; ticket-less ones are the final review's once it started. */
|
|
54
|
+
const SHARED_KINDS = new Set<JournalRecord['kind']>([
|
|
55
|
+
'agent_started',
|
|
56
|
+
'agent_finished',
|
|
57
|
+
'agent_failed',
|
|
58
|
+
'agent_session',
|
|
59
|
+
'gates_run',
|
|
60
|
+
'leftover_scan',
|
|
61
|
+
'commit_made',
|
|
62
|
+
'run_branch_pushed',
|
|
63
|
+
])
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The record if it is the final review's, else `null`: one of its own
|
|
67
|
+
* kinds, or a ticket-less agent, gate, scan, commit, or push record once
|
|
68
|
+
* the final review started. Before that, ticket-less records keep their old
|
|
69
|
+
* meaning (such as the run branch's gates after a join).
|
|
70
|
+
*/
|
|
71
|
+
export const finalRecordOf = ({
|
|
72
|
+
state,
|
|
73
|
+
record,
|
|
74
|
+
}: {
|
|
75
|
+
state: RunState
|
|
76
|
+
record: JournalRecord
|
|
77
|
+
}): FinalRecord | null => {
|
|
78
|
+
const mine =
|
|
79
|
+
FINAL_KINDS.has(record.kind) ||
|
|
80
|
+
(record.ticket === null &&
|
|
81
|
+
state.final_review.round > 0 &&
|
|
82
|
+
SHARED_KINDS.has(record.kind))
|
|
83
|
+
return mine ? (record as FinalRecord) : null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The final review after one of its records. */
|
|
87
|
+
export const finalReviewAfter = ({
|
|
88
|
+
review,
|
|
89
|
+
record,
|
|
90
|
+
}: {
|
|
91
|
+
review: FinalReviewState
|
|
92
|
+
record: FinalRecord
|
|
93
|
+
}): FinalReviewState => {
|
|
94
|
+
switch (record.kind) {
|
|
95
|
+
case 'final_review_started': {
|
|
96
|
+
const { round, from_sha, head_sha, lenses, files, rules, fresh } =
|
|
97
|
+
record.content
|
|
98
|
+
return {
|
|
99
|
+
...review,
|
|
100
|
+
round,
|
|
101
|
+
from_sha,
|
|
102
|
+
head_sha,
|
|
103
|
+
files,
|
|
104
|
+
lenses_due: lenses,
|
|
105
|
+
rules,
|
|
106
|
+
results: {},
|
|
107
|
+
slow_due: record.content.slow_due ?? false,
|
|
108
|
+
slow_tests: null,
|
|
109
|
+
fresh,
|
|
110
|
+
fresh_started: review.fresh_started || fresh,
|
|
111
|
+
// The fresh pass sees no earlier findings or answers (#548).
|
|
112
|
+
...(fresh ? { fix: null } : {}),
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
case 'agent_started':
|
|
116
|
+
return isFixerRole(record.content.role)
|
|
117
|
+
? { ...review, crashed_turn: null }
|
|
118
|
+
: review
|
|
119
|
+
case 'lens_started':
|
|
120
|
+
case 'lens_finished':
|
|
121
|
+
case 'agent_session':
|
|
122
|
+
return review
|
|
123
|
+
case 'final_review_fixing':
|
|
124
|
+
return review.fix !== null &&
|
|
125
|
+
record.content.round === review.fix.round
|
|
126
|
+
? { ...review, fixing_started: true }
|
|
127
|
+
: review
|
|
128
|
+
case 'final_review_stuck':
|
|
129
|
+
return { ...review, stuck: record.content }
|
|
130
|
+
case 'final_review_passed':
|
|
131
|
+
return { ...review, passed: true }
|
|
132
|
+
case 'final_review_shipped':
|
|
133
|
+
return review.stuck === null
|
|
134
|
+
? review
|
|
135
|
+
: {
|
|
136
|
+
...review,
|
|
137
|
+
shipped: true,
|
|
138
|
+
shipped_edits: record.content.commit ?? null,
|
|
139
|
+
}
|
|
140
|
+
case 'agent_finished': {
|
|
141
|
+
const finished = record.content
|
|
142
|
+
const { role } = finished
|
|
143
|
+
return finalResultChange({
|
|
144
|
+
review: {
|
|
145
|
+
...review,
|
|
146
|
+
agent_failures: omit(review.agent_failures, role),
|
|
147
|
+
engine_failures: omit(review.engine_failures, role),
|
|
148
|
+
sessions: sessionsAfter({
|
|
149
|
+
sessions: review.sessions,
|
|
150
|
+
role,
|
|
151
|
+
session_id: finished.session_id,
|
|
152
|
+
}),
|
|
153
|
+
assumptions: [
|
|
154
|
+
...review.assumptions,
|
|
155
|
+
...assumptionsOf(finished),
|
|
156
|
+
],
|
|
157
|
+
// Only a new `environment` answer opens another rerun.
|
|
158
|
+
environment: null,
|
|
159
|
+
},
|
|
160
|
+
finished,
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
case 'agent_failed': {
|
|
164
|
+
const { role, error, failure, session_id } = record.content
|
|
165
|
+
const agent_failures = {
|
|
166
|
+
...review.agent_failures,
|
|
167
|
+
[role]: { role, error, failure, session_id },
|
|
168
|
+
}
|
|
169
|
+
const out_of_turns = outOfTurnsAfter({
|
|
170
|
+
counts: review.out_of_turns,
|
|
171
|
+
failed: record.content,
|
|
172
|
+
})
|
|
173
|
+
if (failure === 'engine') {
|
|
174
|
+
return {
|
|
175
|
+
...review,
|
|
176
|
+
agent_failures,
|
|
177
|
+
out_of_turns,
|
|
178
|
+
engine_failures: {
|
|
179
|
+
...review.engine_failures,
|
|
180
|
+
[role]: (review.engine_failures[role] ?? 0) + 1,
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
...review,
|
|
186
|
+
agent_failures,
|
|
187
|
+
out_of_turns,
|
|
188
|
+
engine_failures: omit(review.engine_failures, role),
|
|
189
|
+
failed_tries: {
|
|
190
|
+
...review.failed_tries,
|
|
191
|
+
[role]: (review.failed_tries[role] ?? 0) + 1,
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
case 'gates_run': {
|
|
196
|
+
const { ok, checks, target } = record.content
|
|
197
|
+
// Round 1's slow tests (#563): not the fix round's gates.
|
|
198
|
+
if (target === 'final_slow') {
|
|
199
|
+
const next = { ...review, slow_tests: { ok, checks } }
|
|
200
|
+
// They run once the lenses are in, so they settle the round;
|
|
201
|
+
// a run no round was waiting for settles none.
|
|
202
|
+
const awaited = review.slow_due && review.slow_tests === null
|
|
203
|
+
return awaited && roundDone({ review: next })
|
|
204
|
+
? settleRound({ review: next })
|
|
205
|
+
: next
|
|
206
|
+
}
|
|
207
|
+
return { ...review, gates: { ok, checks } }
|
|
208
|
+
}
|
|
209
|
+
case 'leftover_scan':
|
|
210
|
+
return { ...review, leftovers: record.content.hits }
|
|
211
|
+
case 'commit_made':
|
|
212
|
+
return {
|
|
213
|
+
...review,
|
|
214
|
+
commit: {
|
|
215
|
+
sha: record.content.sha,
|
|
216
|
+
files: record.content.files,
|
|
217
|
+
},
|
|
218
|
+
}
|
|
219
|
+
case 'run_branch_pushed':
|
|
220
|
+
return {
|
|
221
|
+
...review,
|
|
222
|
+
pushed: record.content.sha,
|
|
223
|
+
fix_pushed: true,
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The final review's report and reply after one of its records: a new
|
|
230
|
+
* stuck is told afresh, and a ship settles the reply.
|
|
231
|
+
*/
|
|
232
|
+
export const finalRepliesAfter = ({
|
|
233
|
+
state,
|
|
234
|
+
record,
|
|
235
|
+
}: {
|
|
236
|
+
state: RunState
|
|
237
|
+
record: JournalRecord
|
|
238
|
+
}): Pick<RunState, 'final_stuck_report' | 'final_reply'> => {
|
|
239
|
+
switch (record.kind) {
|
|
240
|
+
case 'final_review_stuck':
|
|
241
|
+
return { final_stuck_report: null, final_reply: null }
|
|
242
|
+
case 'final_review_shipped':
|
|
243
|
+
return {
|
|
244
|
+
final_stuck_report: state.final_stuck_report,
|
|
245
|
+
final_reply: null,
|
|
246
|
+
}
|
|
247
|
+
default:
|
|
248
|
+
return {
|
|
249
|
+
final_stuck_report: state.final_stuck_report,
|
|
250
|
+
final_reply: state.final_reply,
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The stuck final review resumed by `retry`, like a resumed ticket: fresh
|
|
257
|
+
* fixers (no session kept) and fresh counts, and the owner's edits in the
|
|
258
|
+
* run branch's worktree kept. A leftover scan, failed gates (or gates an
|
|
259
|
+
* `environment` answer blamed), or a step crashes cut off just run again; a failed lens gets a fresh one; otherwise the open fix round
|
|
260
|
+
* starts over as round 1, so the fixes (and the owner's edits) are gated,
|
|
261
|
+
* committed, pushed, and re-reviewed.
|
|
262
|
+
*/
|
|
263
|
+
export const resumedFinalReview = ({
|
|
264
|
+
review,
|
|
265
|
+
}: {
|
|
266
|
+
review: FinalReviewState
|
|
267
|
+
}): FinalReviewState => {
|
|
268
|
+
const base: FinalReviewState = {
|
|
269
|
+
...review,
|
|
270
|
+
stuck: null,
|
|
271
|
+
shipped: false,
|
|
272
|
+
sessions: {},
|
|
273
|
+
agent_failures: {},
|
|
274
|
+
failed_tries: {},
|
|
275
|
+
engine_failures: {},
|
|
276
|
+
gate_fix_rounds: 0,
|
|
277
|
+
setup_change: null,
|
|
278
|
+
environment_reruns: 0,
|
|
279
|
+
environment: null,
|
|
280
|
+
gates: review.commit === null ? null : review.gates,
|
|
281
|
+
leftovers: review.commit === null ? null : review.leftovers,
|
|
282
|
+
}
|
|
283
|
+
const { fix, stuck } = review
|
|
284
|
+
if (
|
|
285
|
+
fix === null ||
|
|
286
|
+
stuck?.reason === 'leftovers_found' ||
|
|
287
|
+
stuck?.reason === 'gates_failed' ||
|
|
288
|
+
stuck?.reason === 'environment_failed' ||
|
|
289
|
+
stuck?.reason === 'agent_failed' ||
|
|
290
|
+
stuck?.reason === 'crashed'
|
|
291
|
+
) {
|
|
292
|
+
return base
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
...base,
|
|
296
|
+
round: 1,
|
|
297
|
+
fix: {
|
|
298
|
+
...fix,
|
|
299
|
+
round: 1,
|
|
300
|
+
tests_answered: !fix.findings.some(({ kind }) => kind === 'test'),
|
|
301
|
+
code_answered: !fix.findings.some(({ kind }) => kind === 'code'),
|
|
302
|
+
responses: [],
|
|
303
|
+
handed_off: {},
|
|
304
|
+
bad_test: null,
|
|
305
|
+
},
|
|
306
|
+
fixing_started: false,
|
|
307
|
+
commit: null,
|
|
308
|
+
pushed: null,
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** The final review's scheduler keys: `final`, and `lens:<lens>`. */
|
|
313
|
+
export const isFinalKey = (key: string): boolean =>
|
|
314
|
+
key === 'final' || key.startsWith('lens:')
|
|
315
|
+
|
|
316
|
+
/** The crash counts without the final review's keys, for its `retry`. */
|
|
317
|
+
export const omitFinalKeys = ({
|
|
318
|
+
crashes,
|
|
319
|
+
}: {
|
|
320
|
+
crashes: CrashCounts
|
|
321
|
+
}): CrashCounts =>
|
|
322
|
+
Object.fromEntries(
|
|
323
|
+
Object.entries(crashes).filter(([key]) => !isFinalKey(key))
|
|
324
|
+
)
|