@mgiles/perk 3.1.0 → 3.3.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.
- package/README.md +5 -0
- package/extension/authoring/gist/draft.ts +198 -0
- package/extension/authoring/gist/prose.ts +46 -0
- package/extension/authoring/gist/review.ts +133 -0
- package/extension/authoring/gist/save.ts +118 -0
- package/extension/authoring/objective/draft.ts +345 -0
- package/extension/{factories/objectiveDreamReport.ts → authoring/objective/dreamReportGate.ts} +74 -131
- package/extension/authoring/objective/planning.ts +124 -0
- package/extension/authoring/objective/prose.ts +103 -0
- package/extension/authoring/objective/review.ts +128 -0
- package/extension/authoring/objective/save.ts +224 -0
- package/extension/authoring/plan/draft.ts +84 -0
- package/extension/authoring/plan/prose.ts +41 -0
- package/extension/authoring/plan/review.ts +269 -0
- package/extension/authoring/plan/save.ts +256 -0
- package/extension/authoring/plan/source.ts +82 -0
- package/extension/authoring/refinement/context.ts +468 -0
- package/extension/authoring/refinement/draft.ts +261 -0
- package/extension/authoring/refinement/prose.ts +79 -0
- package/extension/authoring/refinement/review.ts +111 -0
- package/extension/authoring/refinement/save.ts +119 -0
- package/extension/authoring/review/approvalGate.ts +34 -0
- package/extension/authoring/review/draftContext.ts +68 -0
- package/extension/codeReview/automated.ts +352 -0
- package/extension/codeReview/submission.ts +229 -0
- package/extension/delivery/address.ts +295 -0
- package/extension/delivery/ci.ts +355 -0
- package/extension/delivery/commitCompact.ts +93 -0
- package/extension/delivery/conflictResolution.ts +247 -0
- package/extension/delivery/ready.ts +193 -0
- package/extension/delivery/stackConflict.ts +361 -0
- package/extension/delivery/stackObjective.ts +16 -0
- package/extension/delivery/stackReconcile.ts +165 -0
- package/extension/delivery/submit.ts +171 -0
- package/extension/index.ts +369 -359
- package/extension/learning/analystWave.ts +324 -0
- package/extension/learning/audit.ts +667 -0
- package/extension/learning/capture.ts +92 -0
- package/extension/learning/containment.ts +104 -0
- package/extension/{waves/dreamWave.ts → learning/dream.ts} +112 -94
- package/extension/learning/dreamAnalysis.ts +435 -0
- package/extension/{waves/dreamReducerWave.ts → learning/dreamReducer.ts} +46 -41
- package/extension/{waves → learning}/dreamReport.ts +35 -31
- package/extension/learning/harvest.ts +491 -0
- package/extension/learning/prose.ts +66 -0
- package/extension/learning/routing.ts +79 -0
- package/extension/pi/v1/bashScanTimeout.ts +64 -0
- package/extension/{doors/prReview.ts → pi/v1/codeReview/automated.ts} +215 -310
- package/extension/{doors/prReviewBrowser.ts → pi/v1/codeReview/browser.ts} +125 -57
- package/extension/{doors/hunkHandoff.ts → pi/v1/codeReview/checkout.ts} +12 -8
- package/extension/{doors/reviewWaveTools.ts → pi/v1/codeReview/reviewWave.ts} +169 -116
- package/extension/pi/v1/codeReview/stack.ts +606 -0
- package/extension/pi/v1/codeReview/submit.ts +354 -0
- package/extension/{doors/prReviewTerminal.ts → pi/v1/codeReview/terminal.ts} +32 -27
- package/extension/pi/v1/contextEvidence.ts +80 -0
- package/extension/pi/v1/contextInjection.ts +207 -0
- package/extension/{doors → pi/v1/delivery}/address.ts +163 -265
- package/extension/pi/v1/delivery/ci.ts +570 -0
- package/extension/pi/v1/delivery/commitCompact.ts +201 -0
- package/extension/pi/v1/delivery/conflictResolverEngine.ts +425 -0
- package/extension/{doors → pi/v1/delivery}/land.ts +128 -60
- package/extension/pi/v1/delivery/ready.ts +322 -0
- package/extension/pi/v1/delivery/stackConflictResolver.ts +172 -0
- package/extension/pi/v1/delivery/stackDrive.ts +120 -0
- package/extension/pi/v1/delivery/stackLand.ts +223 -0
- package/extension/pi/v1/delivery/stackRecover.ts +265 -0
- package/extension/pi/v1/delivery/stackStatus.ts +237 -0
- package/extension/pi/v1/delivery/stackSync.ts +658 -0
- package/extension/pi/v1/delivery/submit.ts +389 -0
- package/extension/pi/v1/delivery/submitConflict.ts +186 -0
- package/extension/pi/v1/draftReview.ts +431 -0
- package/extension/{doors → pi/v1}/draftReviewWaveTools.ts +141 -151
- package/extension/pi/v1/gist.ts +794 -0
- package/extension/pi/v1/learning/audit.ts +186 -0
- package/extension/pi/v1/learning/dream.ts +207 -0
- package/extension/{doors/learnFactory.ts → pi/v1/learning/factory.ts} +18 -65
- package/extension/{doors/harvestWaveTools.ts → pi/v1/learning/harvest.ts} +46 -100
- package/extension/pi/v1/learning/learn.ts +585 -0
- package/extension/{doors → pi/v1}/lifecycleGates.ts +14 -59
- package/extension/{factories → pi/v1}/objective.ts +53 -33
- package/extension/pi/v1/objectiveAuthoring.ts +672 -0
- package/extension/pi/v1/objectiveDreamGate.ts +160 -0
- package/extension/pi/v1/objectivePlanning.ts +776 -0
- package/extension/pi/v1/objectiveRefinement.ts +1320 -0
- package/extension/pi/v1/objectiveReview.ts +451 -0
- package/extension/{doors → pi/v1}/objectiveReviewBrowser.ts +259 -172
- package/extension/pi/v1/plan.ts +812 -0
- package/extension/pi/v1/planReview.ts +820 -0
- package/extension/{doors → pi/v1}/planReviewBrowser.ts +228 -152
- package/extension/{doors/annotationPush.ts → pi/v1/providers/annotations.ts} +158 -89
- package/extension/pi/v1/providers/plannotator.ts +487 -0
- package/extension/{doors → pi/v1/providers}/plannotatorHandoff.ts +152 -34
- package/extension/pi/v1/providers/selection.ts +43 -0
- package/extension/{adapters/planAdapterTombell.ts → pi/v1/providers/tombell.ts} +43 -72
- package/extension/pi/v1/review.ts +538 -0
- package/extension/pi/v1/reviewOutcome.ts +9 -0
- package/extension/pi/v1/scoutWave.ts +318 -0
- package/extension/{doors → pi/v1}/selfcheck.ts +4 -4
- package/extension/session/branchWorkflowSession.ts +60 -0
- package/extension/session/lifecycle.ts +644 -0
- package/extension/session/lifecycleGates.ts +64 -0
- package/extension/session/saveDestination.ts +87 -0
- package/extension/session/workflowSession.ts +971 -0
- package/extension/substrate/agentScratch.ts +27 -54
- package/extension/substrate/bashScanTimeout.ts +181 -0
- package/extension/substrate/bindingDelivery.ts +38 -30
- package/extension/substrate/bindings.ts +4 -5
- package/extension/substrate/cache.ts +64 -12
- package/extension/substrate/childRestrictions.ts +39 -0
- package/extension/substrate/coldDoor.ts +17 -1
- package/extension/substrate/config.ts +157 -19
- package/extension/substrate/git.ts +88 -6
- package/extension/substrate/modelVisible.ts +53 -0
- package/extension/substrate/paths.ts +2 -7
- package/extension/substrate/prompts.ts +22 -0
- package/extension/substrate/registry.ts +2 -0
- package/extension/substrate/resolverLease.ts +364 -0
- package/extension/substrate/sessionData.ts +85 -152
- package/extension/substrate/toolGating.ts +279 -84
- package/extension/substrate/unifiedDiff.ts +1 -1
- package/extension/substrate/workflowState.ts +191 -166
- package/extension/substrate/worktreeResolverLock.ts +261 -0
- package/extension/surfaces/surfaces.ts +79 -27
- package/extension/waves/adversarialReviewWave.ts +103 -48
- package/extension/waves/blockedReports.ts +59 -0
- package/extension/waves/draftReviewWave.ts +42 -42
- package/extension/waves/laneIdentity.ts +77 -0
- package/extension/waves/objectiveExplorerWave.ts +24 -24
- package/extension/waves/prReviewWave.ts +89 -77
- package/extension/waves/reportWave.ts +438 -578
- package/extension/waves/reviewClassifierWave.ts +22 -22
- package/extension/waves/rpcAdapter.ts +100 -15
- package/extension/waves/scoutWave.ts +192 -0
- package/extension/waves/transport.ts +480 -0
- package/extension/worker/sdkAdapter.ts +494 -0
- package/extension/worker/stageExecution.ts +679 -0
- package/extension/workerMain.ts +18 -19
- package/package.json +6 -4
- package/prompts/_fixtures/live.yaml +98 -10
- package/prompts/contexts/adapters/plannotator-gist.md +6 -0
- package/prompts/contexts/adapters/plannotator-objective.md +6 -0
- package/prompts/contexts/adapters/plannotator-plan.md +8 -1
- package/prompts/contexts/adapters/plannotator-refinement.md +22 -0
- package/prompts/contexts/adapters/tombell-plan.md +4 -0
- package/prompts/contexts/objective-refinement.md +17 -0
- package/prompts/contexts/plan-authoring.md +6 -5
- package/prompts/contexts/read-only.md +1 -1
- package/prompts/stages/conflict-resolution-continuation.md +9 -0
- package/prompts/stages/conflict-resolution.md +4 -4
- package/prompts/stages/objective-author/adopt.md +1 -1
- package/prompts/stages/objective-author/file.md +1 -1
- package/prompts/stages/objective-author/seed.md +1 -1
- package/prompts/stages/objective-plan/guidance.md +2 -2
- package/prompts/stages/objective-plan/seed.md +9 -1
- package/prompts/stages/objective-reconcile-ready.md +7 -0
- package/prompts/stages/objective-reconcile.md +1 -1
- package/prompts/stages/objective-refine/seed.md +18 -0
- package/prompts/stages/objective-review-browser.md +4 -4
- package/prompts/stages/objective-sync.md +1 -1
- package/prompts/stages/plan-review-browser.md +4 -4
- package/prompts/stages/pr-review-browser/active.md +3 -4
- package/prompts/stages/pr-review-browser/foreign.md +3 -4
- package/prompts/stages/pr-review-terminal/active.md +3 -3
- package/prompts/stages/pr-review-terminal/foreign.md +3 -3
- package/prompts/stages/pr-review.md +3 -3
- package/prompts/stages/stack-review/cold.md +1 -0
- package/prompts/stages/stack-review-browser/stack.md +22 -0
- package/shared/README.md +8 -3
- package/shared/bindings.yaml +6 -3
- package/shared/contracts.md +4499 -2147
- package/shared/fixtures/issues-table.json +130 -0
- package/shared/registry.yaml +29 -1
- package/shared/schemas/outputs/objective-node-engagement.schema.json +318 -0
- package/shared/schemas/outputs/objective-stack-status.schema.json +178 -2
- package/shared/schemas/outputs/pr-ready.schema.json +110 -2
- package/shared/schemas/outputs/pr-review-context.schema.json +54 -9
- package/shared/schemas/outputs/pr-review-stack-context.schema.json +196 -0
- package/extension/adapters/planAdapterPlannotator.ts +0 -362
- package/extension/doors/auditWaveTools.ts +0 -352
- package/extension/doors/ciExecutor.ts +0 -756
- package/extension/doors/commitCompact.ts +0 -251
- package/extension/doors/dreamWaveTools.ts +0 -475
- package/extension/doors/learn.ts +0 -655
- package/extension/doors/objectiveStack.ts +0 -1143
- package/extension/doors/prReviewDynamic.ts +0 -276
- package/extension/doors/ready.ts +0 -87
- package/extension/doors/submit.ts +0 -347
- package/extension/doors/submitPrReview.ts +0 -408
- package/extension/factories/gistAuthor.ts +0 -94
- package/extension/factories/gistDraft.ts +0 -265
- package/extension/factories/gistSave.ts +0 -251
- package/extension/factories/implementHere.ts +0 -116
- package/extension/factories/objectiveAuthor.ts +0 -98
- package/extension/factories/objectiveDraft.ts +0 -466
- package/extension/factories/objectivePlan.ts +0 -975
- package/extension/factories/objectiveSave.ts +0 -363
- package/extension/factories/planDraft.ts +0 -140
- package/extension/factories/planMode.ts +0 -205
- package/extension/factories/planReview.ts +0 -1237
- package/extension/factories/planSave.ts +0 -604
- package/extension/factories/planTitle.ts +0 -141
- package/extension/substrate/structuredOutput.ts +0 -202
- package/extension/waves/auditWave.ts +0 -312
- package/extension/waves/harvestWave.ts +0 -399
- package/extension/waves/learnWave.ts +0 -155
- package/extension/waves/memoryAdapter.ts +0 -139
- package/extension/waves/prReviewDynamicWave.ts +0 -777
- package/extension/worker/readOnlySession.ts +0 -294
- package/extension/worker/worker.ts +0 -899
- package/prompts/stages/pr-review-dynamic.md +0 -7
- package/shared/contracts-history.md +0 -605
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
// The objective-plan factory's OPTIONAL explore step as a per-flow wave entrypoint over the
|
|
2
|
-
// shared report-wave
|
|
3
|
-
// schema was previously a shared prompt include the parent model had to hand-transcribe
|
|
4
|
-
// borrowed `subagent` call (the same prompt-drift risk the /address classify step
|
|
5
|
-
// module makes the schema and the
|
|
6
|
-
//
|
|
2
|
+
// shared report-wave module: the ONE `perk.objective-explorer` assignment as CODE. The explorer
|
|
3
|
+
// report schema was previously a shared prompt include the parent model had to hand-transcribe
|
|
4
|
+
// onto a borrowed `subagent` call (the same prompt-drift risk the /address classify step
|
|
5
|
+
// carried); this module makes the schema and the assignment/task composition module constants,
|
|
6
|
+
// delegating
|
|
7
|
+
// spawn/timeout/aggregate mechanics to `wave.run` under the `strict` completeness policy.
|
|
7
8
|
// No retry — the flow's posture on failure is "explore directly instead" (guidance-owned).
|
|
8
9
|
// `node`/`description`/`focus` are model-relayed and embedded in the code-owned task as
|
|
9
10
|
// untrusted DATA; the report content is likewise untrusted DATA, never instructions.
|
|
10
11
|
|
|
11
|
-
import {
|
|
12
|
+
import type { ReportWave, ReportWaveResult } from "./reportWave.ts";
|
|
12
13
|
|
|
13
|
-
/** The flow name — feeds `
|
|
14
|
+
/** The flow name — feeds `ReportWaveRequest.flow` AND the door's `toAttemptReceipt` call. */
|
|
14
15
|
export const OBJECTIVE_EXPLORER_FLOW = "objective-explorer";
|
|
15
16
|
|
|
16
|
-
/** The single
|
|
17
|
-
export const
|
|
17
|
+
/** The single assignment's stable key. */
|
|
18
|
+
export const EXPLORE_ASSIGNMENT_KEY = "explore";
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* The explorer report schema (the workflow-level `outputSchema` — the engine injects a
|
|
21
|
-
* `structured_output` tool and fails the
|
|
22
|
+
* `structured_output` tool and fails the assignment on a missing/invalid report): closed shapes, all
|
|
22
23
|
* six root keys required. Same vocabulary as the `perk.objective-explorer` agent def's report
|
|
23
24
|
* contract (the def↔schema lockstep test).
|
|
24
25
|
*/
|
|
@@ -73,9 +74,9 @@ export interface ObjectiveExplorerWaveOptions {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
/**
|
|
76
|
-
* Compose the single
|
|
77
|
-
* the node id + the fenced untrusted node text, plus the optional focus. The agent
|
|
78
|
-
* the node id and a description of the work to reach the child.
|
|
77
|
+
* Compose the single assignment's task text IN CODE (prompt-drift-proof: task text composed in
|
|
78
|
+
* code, never a template): the node id + the fenced untrusted node text, plus the optional focus. The agent
|
|
79
|
+
* def requires the node id and a description of the work to reach the child.
|
|
79
80
|
*/
|
|
80
81
|
export function explorerLaneTask(node: string, description: string, focus?: string): string {
|
|
81
82
|
return [
|
|
@@ -89,22 +90,21 @@ export function explorerLaneTask(node: string, description: string, focus?: stri
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
/**
|
|
92
|
-
* Run the objective-explorer wave: ONE fresh-context `perk.objective-explorer`
|
|
93
|
-
* code-owned task, `strict` completeness, no retry, module-default timeout. Returns the
|
|
94
|
-
* `
|
|
93
|
+
* Run the objective-explorer wave: ONE fresh-context `perk.objective-explorer` assignment over
|
|
94
|
+
* the code-owned task, `strict` completeness, no retry, module-default timeout. Returns the
|
|
95
|
+
* wave's `ReportWaveResult` unchanged — the only projection lives in the tool.
|
|
95
96
|
*/
|
|
96
97
|
export async function runObjectiveExplorerWave(
|
|
97
|
-
|
|
98
|
+
wave: ReportWave,
|
|
98
99
|
opts: ObjectiveExplorerWaveOptions,
|
|
99
|
-
): Promise<
|
|
100
|
-
return await
|
|
101
|
-
adapter,
|
|
100
|
+
): Promise<ReportWaveResult> {
|
|
101
|
+
return await wave.run(
|
|
102
102
|
{
|
|
103
103
|
flow: OBJECTIVE_EXPLORER_FLOW,
|
|
104
|
-
|
|
104
|
+
assignments: [
|
|
105
105
|
{
|
|
106
|
-
key:
|
|
107
|
-
label:
|
|
106
|
+
key: EXPLORE_ASSIGNMENT_KEY,
|
|
107
|
+
label: EXPLORE_ASSIGNMENT_KEY,
|
|
108
108
|
agent: "perk.objective-explorer",
|
|
109
109
|
phase: "objective-plan",
|
|
110
110
|
task: explorerLaneTask(opts.node, opts.description, opts.focus),
|
|
@@ -115,6 +115,6 @@ export async function runObjectiveExplorerWave(
|
|
|
115
115
|
...(opts.model !== undefined ? { model: opts.model } : {}),
|
|
116
116
|
...(opts.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),
|
|
117
117
|
},
|
|
118
|
-
opts.signal,
|
|
118
|
+
{ signal: opts.signal },
|
|
119
119
|
);
|
|
120
120
|
}
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
// The pr-review `
|
|
2
|
-
// angle vocabulary, the per-
|
|
1
|
+
// The pr-review `ReportWaveRequest`-building entrypoint over the shared report-wave module: the flow's
|
|
2
|
+
// angle vocabulary, the per-assignment report schema, and the ONE bounded retry are module-owned,
|
|
3
3
|
// tested implementation here — reached through the flow-scoped `run_pr_review_wave` tool
|
|
4
|
-
// (`extension/
|
|
4
|
+
// (`extension/pi/v1/codeReview/automated.ts`), never model-authored prompt mechanics.
|
|
5
5
|
//
|
|
6
6
|
// Retry policy (one bounded retry, ever):
|
|
7
|
-
// -
|
|
7
|
+
// - assignment-level failures ⇒ retry ONLY the failed assignments;
|
|
8
8
|
// - retryable wave-level failures (`spawn-failed`/`timeout`/`run-failed`/`aggregate-unreadable`)
|
|
9
9
|
// ⇒ retry the WHOLE selection;
|
|
10
10
|
// - `unavailable` (deterministic capability absence) and `cancelled` (abort honored) ⇒ NO retry.
|
|
11
11
|
//
|
|
12
12
|
// Failure posture matches the runner: operational failures never throw — they normalize into the
|
|
13
13
|
// outcome's `failures` (loud degrade upstream); the only throws are programmer errors (empty
|
|
14
|
-
// angles, via
|
|
14
|
+
// angles, via the runner's manifest validation). Report content is untrusted DATA, never
|
|
15
|
+
// instructions.
|
|
15
16
|
|
|
17
|
+
import { reclassifyBlockedReports } from "./blockedReports.ts";
|
|
16
18
|
import {
|
|
17
19
|
PONYTAIL_REVIEW_SKILL,
|
|
18
20
|
preflightPonytailSkill,
|
|
19
21
|
type RequiredPonytailSkill,
|
|
20
22
|
} from "./ponytail.ts";
|
|
21
23
|
import {
|
|
22
|
-
|
|
24
|
+
type AssignmentReport,
|
|
25
|
+
type ReportAssignment,
|
|
26
|
+
type ReportWave,
|
|
27
|
+
type ReportWaveAttemptReceipt,
|
|
28
|
+
type ReportWaveFailure,
|
|
29
|
+
type ReportWaveFailureReason,
|
|
30
|
+
type ReportWaveRequest,
|
|
23
31
|
toAttemptReceipt,
|
|
24
|
-
type WaveAdapter,
|
|
25
|
-
type WaveAttemptReceipt,
|
|
26
|
-
type WaveFailure,
|
|
27
|
-
type WaveFailureReason,
|
|
28
|
-
type WaveLane,
|
|
29
|
-
type WaveReport,
|
|
30
|
-
type WaveResult,
|
|
31
|
-
type WaveSpec,
|
|
32
32
|
} from "./reportWave.ts";
|
|
33
33
|
|
|
34
34
|
/** The seven-slug review-angle allowlist (plan-fidelity is mandatory at the tool boundary). */
|
|
@@ -43,8 +43,7 @@ export type PrReviewAngle =
|
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* The per-angle lane-task vocabulary (`angle: <slug> — review ONLY <angle description>.`) — the
|
|
46
|
-
* same task shape the `perk.pr-reviewer` agent def is written against
|
|
47
|
-
* rides the flow migration.
|
|
46
|
+
* same task shape the `perk.pr-reviewer` agent def is written against.
|
|
48
47
|
*/
|
|
49
48
|
export const PR_REVIEW_ANGLES: Readonly<Record<PrReviewAngle, string>> = {
|
|
50
49
|
"plan-fidelity": "angle: plan-fidelity — review ONLY plan fidelity & completeness.",
|
|
@@ -69,13 +68,9 @@ export function isPrReviewAngle(value: string): value is PrReviewAngle {
|
|
|
69
68
|
/**
|
|
70
69
|
* The per-lane report schema the review wave enforces as its `outputSchema` — the engine injects
|
|
71
70
|
* a `structured_output` tool into each lane and fails any lane whose report is missing or
|
|
72
|
-
* schema-invalid
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* makes an internally inconsistent report (a `clean` verdict carrying findings) schema-INVALID,
|
|
76
|
-
* so it fails its lane instead of reaching reconciliation — the engine's validator (TypeBox
|
|
77
|
-
* `Compile`) enforces JSON-Schema conditionals (verified against the installed pi-subagents
|
|
78
|
-
* 0.43.0 toolchain).
|
|
71
|
+
* schema-invalid. A valid blocked report is still an incomplete assessment, normalized into
|
|
72
|
+
* a lane failure before coverage/retry. The closed four-field contract forbids findings on
|
|
73
|
+
* clean/blocked reports and requires a nonblank diagnosis on blocked reports.
|
|
79
74
|
*/
|
|
80
75
|
export const PR_REVIEW_REPORT_SCHEMA = {
|
|
81
76
|
type: "object",
|
|
@@ -97,7 +92,7 @@ export const PR_REVIEW_REPORT_SCHEMA = {
|
|
|
97
92
|
},
|
|
98
93
|
verdict: {
|
|
99
94
|
type: "string",
|
|
100
|
-
enum: ["clean", "actionable"],
|
|
95
|
+
enum: ["clean", "actionable", "blocked"],
|
|
101
96
|
},
|
|
102
97
|
findings: {
|
|
103
98
|
type: "array",
|
|
@@ -117,18 +112,25 @@ export const PR_REVIEW_REPORT_SCHEMA = {
|
|
|
117
112
|
items: { type: "string" },
|
|
118
113
|
},
|
|
119
114
|
},
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
115
|
+
allOf: [
|
|
116
|
+
{
|
|
117
|
+
if: { properties: { verdict: { enum: ["clean", "blocked"] } } },
|
|
118
|
+
// biome-ignore lint/suspicious/noThenProperty: JSON-Schema conditional, not a thenable.
|
|
119
|
+
then: { properties: { findings: { maxItems: 0 } } },
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
if: { properties: { verdict: { const: "blocked" } } },
|
|
123
|
+
// biome-ignore lint/suspicious/noThenProperty: JSON-Schema conditional, not a thenable.
|
|
124
|
+
then: {
|
|
125
|
+
properties: { fyi: { minItems: 1, items: { type: "string", pattern: "\\S" } } },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
],
|
|
127
129
|
};
|
|
128
130
|
|
|
129
131
|
type EffectivePrReviewAngle = PrReviewAngle | "ponytail";
|
|
130
132
|
|
|
131
|
-
type RequiredSkillPreflight = NonNullable<
|
|
133
|
+
type RequiredSkillPreflight = NonNullable<ReportWaveRequest["requiredSkillPreflight"]>;
|
|
132
134
|
|
|
133
135
|
export interface PrReviewWaveOptions {
|
|
134
136
|
/** The resolved active-plan PR number shared by every lane in this pass. */
|
|
@@ -142,28 +144,28 @@ export interface PrReviewWaveOptions {
|
|
|
142
144
|
timeoutMs?: number;
|
|
143
145
|
signal?: AbortSignal;
|
|
144
146
|
/** Test seam; production validates the exact source-bound Ponytail review skill. */
|
|
145
|
-
requiredSkillPreflight?:
|
|
147
|
+
requiredSkillPreflight?: ReportWaveRequest["requiredSkillPreflight"];
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
export interface PrReviewWaveOutcome {
|
|
149
151
|
/** True ⟺ every effective lane (selected angles + final Ponytail) is covered after retry. */
|
|
150
152
|
complete: boolean;
|
|
151
|
-
/** Effective
|
|
153
|
+
/** Effective keys with completed schema-valid assessments after retry (selected order + Ponytail). */
|
|
152
154
|
covered: string[];
|
|
153
155
|
/** Lane keys sent in the retry wave (empty when none ran). */
|
|
154
156
|
retried: string[];
|
|
155
|
-
reports:
|
|
157
|
+
reports: AssignmentReport[];
|
|
156
158
|
/** The surviving failures (the retry wave's, when one ran). */
|
|
157
|
-
failures:
|
|
159
|
+
failures: ReportWaveFailure[];
|
|
158
160
|
/**
|
|
159
161
|
* One output-free receipt per top-level launch, run order (observability only — never a
|
|
160
162
|
* decision input; a failed lane and its relaunch stay distinguishable as distinct attempts).
|
|
161
163
|
*/
|
|
162
|
-
attempts:
|
|
164
|
+
attempts: ReportWaveAttemptReceipt[];
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
/** The wave-level failure reasons worth one full-selection retry (transient, not deterministic). */
|
|
166
|
-
const RETRYABLE_WAVE_REASONS: ReadonlySet<
|
|
168
|
+
const RETRYABLE_WAVE_REASONS: ReadonlySet<ReportWaveFailureReason> = new Set([
|
|
167
169
|
"spawn-failed",
|
|
168
170
|
"timeout",
|
|
169
171
|
"run-failed",
|
|
@@ -192,15 +194,15 @@ export function reviewTargetSuffix(pr: number): string {
|
|
|
192
194
|
}
|
|
193
195
|
|
|
194
196
|
/**
|
|
195
|
-
* Build the reviewer
|
|
196
|
-
* vocabulary task. Exported so the dynamic-review sibling's
|
|
197
|
-
* byte-identical reviewer
|
|
197
|
+
* Build the reviewer assignments for a selection: key = label = slug, the fixed agent/phase,
|
|
198
|
+
* the vocabulary task. Exported so the dynamic-review sibling's per-assignment retry builds
|
|
199
|
+
* byte-identical reviewer assignments.
|
|
198
200
|
*/
|
|
199
|
-
export function
|
|
201
|
+
export function buildPrReviewAssignments(
|
|
200
202
|
angles: PrReviewAngle[],
|
|
201
203
|
pr: number,
|
|
202
204
|
directive?: string,
|
|
203
|
-
):
|
|
205
|
+
): ReportAssignment[] {
|
|
204
206
|
const suffix = reviewTargetSuffix(pr) + directiveSuffix(directive);
|
|
205
207
|
return angles.map((angle) => ({
|
|
206
208
|
key: angle,
|
|
@@ -211,7 +213,7 @@ export function buildPrReviewLanes(
|
|
|
211
213
|
}));
|
|
212
214
|
}
|
|
213
215
|
|
|
214
|
-
export function
|
|
216
|
+
export function buildPonytailReviewAssignment(pr: number, directive?: string): ReportAssignment {
|
|
215
217
|
return {
|
|
216
218
|
key: "ponytail",
|
|
217
219
|
label: "ponytail",
|
|
@@ -226,15 +228,15 @@ export function buildPonytailReviewLane(pr: number, directive?: string): WaveLan
|
|
|
226
228
|
};
|
|
227
229
|
}
|
|
228
230
|
|
|
229
|
-
function
|
|
231
|
+
function buildEffectivePrReviewAssignments(
|
|
230
232
|
angles: EffectivePrReviewAngle[],
|
|
231
233
|
pr: number,
|
|
232
234
|
directive?: string,
|
|
233
|
-
):
|
|
235
|
+
): ReportAssignment[] {
|
|
234
236
|
const suffix = reviewTargetSuffix(pr) + directiveSuffix(directive);
|
|
235
237
|
return angles.map((angle) =>
|
|
236
238
|
angle === "ponytail"
|
|
237
|
-
?
|
|
239
|
+
? buildPonytailReviewAssignment(pr, directive)
|
|
238
240
|
: {
|
|
239
241
|
key: angle,
|
|
240
242
|
label: angle,
|
|
@@ -245,14 +247,14 @@ function buildEffectivePrReviewLanes(
|
|
|
245
247
|
);
|
|
246
248
|
}
|
|
247
249
|
|
|
248
|
-
function
|
|
249
|
-
|
|
250
|
+
function buildRequest(
|
|
251
|
+
assignments: ReportAssignment[],
|
|
250
252
|
opts: PrReviewWaveOptions,
|
|
251
253
|
requiredSkillPreflight: RequiredSkillPreflight,
|
|
252
|
-
):
|
|
254
|
+
): ReportWaveRequest {
|
|
253
255
|
return {
|
|
254
256
|
flow: "pr-review",
|
|
255
|
-
|
|
257
|
+
assignments,
|
|
256
258
|
outputSchema: PR_REVIEW_REPORT_SCHEMA,
|
|
257
259
|
completeness: "strict",
|
|
258
260
|
...(opts.model !== undefined ? { model: opts.model } : {}),
|
|
@@ -262,13 +264,13 @@ function buildSpec(
|
|
|
262
264
|
}
|
|
263
265
|
|
|
264
266
|
/**
|
|
265
|
-
* Pick
|
|
266
|
-
*
|
|
267
|
-
*
|
|
267
|
+
* Pick retry keys from failures, never report availability. A retryable wave-level failure
|
|
268
|
+
* (`key: null`) retries the whole runnable selection even when partial reports survived;
|
|
269
|
+
* otherwise assignment-level failures retry exactly the failed keys.
|
|
268
270
|
*/
|
|
269
271
|
function retrySelection(
|
|
270
272
|
angles: EffectivePrReviewAngle[],
|
|
271
|
-
failures:
|
|
273
|
+
failures: ReportWaveFailure[],
|
|
272
274
|
): EffectivePrReviewAngle[] {
|
|
273
275
|
const unavailable = new Set(
|
|
274
276
|
failures
|
|
@@ -289,12 +291,18 @@ function retrySelection(
|
|
|
289
291
|
return angles.filter((angle) => failed.has(angle));
|
|
290
292
|
}
|
|
291
293
|
|
|
294
|
+
// Only the typed verdict classifies a pr-review report as blocked (the `verdict: "blocked"`
|
|
295
|
+
// arm of `PR_REVIEW_REPORT_SCHEMA`); diagnostic prose never does.
|
|
296
|
+
function isBlockedVerdict(report: Record<string, unknown>): boolean {
|
|
297
|
+
return report.verdict === "blocked";
|
|
298
|
+
}
|
|
299
|
+
|
|
292
300
|
function outcomeOf(
|
|
293
301
|
angles: EffectivePrReviewAngle[],
|
|
294
|
-
reports:
|
|
295
|
-
failures:
|
|
302
|
+
reports: AssignmentReport[],
|
|
303
|
+
failures: ReportWaveFailure[],
|
|
296
304
|
retried: string[],
|
|
297
|
-
attempts:
|
|
305
|
+
attempts: ReportWaveAttemptReceipt[],
|
|
298
306
|
): PrReviewWaveOutcome {
|
|
299
307
|
const byKey = new Map(reports.map((report) => [report.key, report]));
|
|
300
308
|
const ordered = angles.flatMap((angle) => {
|
|
@@ -302,7 +310,7 @@ function outcomeOf(
|
|
|
302
310
|
return report === undefined ? [] : [report];
|
|
303
311
|
});
|
|
304
312
|
return {
|
|
305
|
-
complete: ordered.length === angles.length,
|
|
313
|
+
complete: ordered.length === angles.length && failures.length === 0,
|
|
306
314
|
covered: ordered.map((report) => report.key),
|
|
307
315
|
retried,
|
|
308
316
|
reports: ordered,
|
|
@@ -312,14 +320,14 @@ function outcomeOf(
|
|
|
312
320
|
}
|
|
313
321
|
|
|
314
322
|
/**
|
|
315
|
-
* Run the pr-review report wave: build the
|
|
316
|
-
*
|
|
317
|
-
* retry (failed
|
|
323
|
+
* Run the pr-review report wave: build the assignments from the angle vocabulary, run the
|
|
324
|
+
* shared wave under the strict completeness policy, and — when incomplete — apply the ONE
|
|
325
|
+
* bounded retry (failed assignments only, or the whole selection on a retryable wave-level failure, or none on
|
|
318
326
|
* `unavailable`/`cancelled`), merging first-wave successes for non-retried keys with the retry
|
|
319
327
|
* wave's results.
|
|
320
328
|
*/
|
|
321
329
|
export async function runPrReviewWave(
|
|
322
|
-
|
|
330
|
+
wave: ReportWave,
|
|
323
331
|
opts: PrReviewWaveOptions,
|
|
324
332
|
): Promise<PrReviewWaveOutcome> {
|
|
325
333
|
if (opts.angles.length === 0) {
|
|
@@ -336,14 +344,16 @@ export async function runPrReviewWave(
|
|
|
336
344
|
}
|
|
337
345
|
return check;
|
|
338
346
|
};
|
|
339
|
-
const first
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
347
|
+
const first = reclassifyBlockedReports(
|
|
348
|
+
await wave.run(
|
|
349
|
+
buildRequest(
|
|
350
|
+
buildEffectivePrReviewAssignments(angles, opts.pr, opts.directive),
|
|
351
|
+
opts,
|
|
352
|
+
requiredSkillPreflight,
|
|
353
|
+
),
|
|
354
|
+
{ signal: opts.signal },
|
|
345
355
|
),
|
|
346
|
-
|
|
356
|
+
isBlockedVerdict,
|
|
347
357
|
);
|
|
348
358
|
// The first attempt's receipt is preserved VERBATIM even when a retry runs — ordered
|
|
349
359
|
// attempts keep a failed lane and its relaunch distinguishable (distinct child runIds).
|
|
@@ -357,14 +367,16 @@ export async function runPrReviewWave(
|
|
|
357
367
|
return outcomeOf(angles, first.reports, first.failures, [], attempts);
|
|
358
368
|
}
|
|
359
369
|
|
|
360
|
-
const second =
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
370
|
+
const second = reclassifyBlockedReports(
|
|
371
|
+
await wave.run(
|
|
372
|
+
buildRequest(
|
|
373
|
+
buildEffectivePrReviewAssignments(retried, opts.pr, opts.directive),
|
|
374
|
+
opts,
|
|
375
|
+
requiredSkillPreflight,
|
|
376
|
+
),
|
|
377
|
+
{ signal: opts.signal },
|
|
366
378
|
),
|
|
367
|
-
|
|
379
|
+
isBlockedVerdict,
|
|
368
380
|
);
|
|
369
381
|
attempts.push(toAttemptReceipt("pr-review", 2, retried, second.receipt));
|
|
370
382
|
const retriedSet = new Set<string>(retried);
|