@henryqw/pi-subagent 15.1.3 → 16.0.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.
- package/CONTEXT.md +7 -10
- package/README.md +23 -54
- package/dist/index.d.ts +2 -1
- package/dist/index.js +9 -1
- package/dist/review-evidence.d.ts +1 -1
- package/dist/review-evidence.js +1 -1
- package/dist/worktree.d.ts +1 -1
- package/dist/worktree.js +5 -2
- package/docs/adr/001-composable-ephemeral-execution.md +2 -2
- package/docs/orchestration.md +10 -38
- package/examples/roles/implementer.md +5 -5
- package/examples/roles/reviewer.md +3 -6
- package/extensions/role-tools.ts +33 -1
- package/extensions/subagent.ts +6 -37
- package/extensions/task-name.ts +0 -2
- package/package.json +1 -5
- package/docs/adr/002-package-owned-delegate-flow-orchestration.md +0 -22
- package/docs/delegate-flow.html +0 -202
- package/docs/delegate-flow.svg +0 -181
- package/extensions/delegate-flow.ts +0 -932
- package/skills/pi-subagent-delegated-development/SKILL.md +0 -61
package/extensions/subagent.ts
CHANGED
|
@@ -33,7 +33,6 @@ import {
|
|
|
33
33
|
type WorktreePayload,
|
|
34
34
|
} from "@henryqw/pi-subagent";
|
|
35
35
|
import { DEFAULT_TIMEOUT_CONFIG, readSubagentConfig, type SubagentTimeoutConfig } from "./config.ts";
|
|
36
|
-
import { registerDelegateFlow } from "./delegate-flow.ts";
|
|
37
36
|
import { MODEL_CLASS_GUIDANCE } from "./model-class-policy.ts";
|
|
38
37
|
import {
|
|
39
38
|
formatBackgroundWorkflowResult,
|
|
@@ -54,8 +53,6 @@ import {
|
|
|
54
53
|
type ParsedWorkflow,
|
|
55
54
|
type WorkflowEntry,
|
|
56
55
|
} from "./workflow.ts";
|
|
57
|
-
import { TASK_NAME_CONTRACT } from "./task-name.ts";
|
|
58
|
-
|
|
59
56
|
const WIDGET_KEY = "subagent-status";
|
|
60
57
|
const WIDGET_INTERVAL_MS = 80;
|
|
61
58
|
const MAX_WIDGET_ITEMS = 8;
|
|
@@ -274,7 +271,6 @@ export default function subagentExtension(
|
|
|
274
271
|
].join("\n"), outputPad, 0);
|
|
275
272
|
});
|
|
276
273
|
const widgetItems = new Map<string, WidgetItem>();
|
|
277
|
-
const retainedWidgetTaskIds = new Set<string>();
|
|
278
274
|
// Each child is a full Pi process issuing its own model calls; cap parallel
|
|
279
275
|
// spend. Precedence: PI_SUBAGENT_MAX_SUBAGENTS env > config/pi-subagent/config.json
|
|
280
276
|
// maxSubagents > default 5. Invalid present config falls back to the default
|
|
@@ -314,7 +310,6 @@ export default function subagentExtension(
|
|
|
314
310
|
// Bumped by session_start and session_shutdown; background tasks may only
|
|
315
311
|
// deliver into the exact session that launched them.
|
|
316
312
|
let sessionEpoch = 0;
|
|
317
|
-
let invalidateDelegateFlow = () => {};
|
|
318
313
|
let widgetInstalled = false;
|
|
319
314
|
let widgetTimer: ReturnType<typeof setInterval> | undefined;
|
|
320
315
|
let spinnerIndex = 0;
|
|
@@ -327,11 +322,6 @@ export default function subagentExtension(
|
|
|
327
322
|
|
|
328
323
|
const requestWidgetRender = () => activeTui?.requestRender();
|
|
329
324
|
|
|
330
|
-
const setWidgetTaskRetained = (taskId: string, retained: boolean) => {
|
|
331
|
-
if (retained) retainedWidgetTaskIds.add(taskId);
|
|
332
|
-
else retainedWidgetTaskIds.delete(taskId);
|
|
333
|
-
};
|
|
334
|
-
|
|
335
325
|
const startWidgetTimer = () => {
|
|
336
326
|
if (widgetTimer) return;
|
|
337
327
|
widgetTimer = setInterval(() => {
|
|
@@ -366,7 +356,7 @@ export default function subagentExtension(
|
|
|
366
356
|
ensureWidget(ctx);
|
|
367
357
|
if (!widgetItems.has(id) && widgetItems.size >= MAX_WIDGET_ITEMS) {
|
|
368
358
|
for (const [oldestId, item] of widgetItems) {
|
|
369
|
-
if (item.status === "working" ||
|
|
359
|
+
if (item.status === "working" || item.taskId === taskId) continue;
|
|
370
360
|
widgetItems.delete(oldestId);
|
|
371
361
|
if (widgetItems.size < MAX_WIDGET_ITEMS) break;
|
|
372
362
|
}
|
|
@@ -451,7 +441,6 @@ export default function subagentExtension(
|
|
|
451
441
|
|
|
452
442
|
pi.on("session_start", (_event, ctx) => {
|
|
453
443
|
sessionEpoch += 1;
|
|
454
|
-
invalidateDelegateFlow();
|
|
455
444
|
latestCtx = ctx;
|
|
456
445
|
ensureWidget(ctx);
|
|
457
446
|
if (loadedConfig.error !== undefined) ctx.ui.notify(loadedConfig.error, "warning");
|
|
@@ -467,14 +456,12 @@ export default function subagentExtension(
|
|
|
467
456
|
failedToolPatches.clear();
|
|
468
457
|
stopWidgetTimer();
|
|
469
458
|
widgetItems.clear();
|
|
470
|
-
retainedWidgetTaskIds.clear();
|
|
471
459
|
activeTui = undefined;
|
|
472
460
|
widgetInstalled = false;
|
|
473
461
|
if (ctx.hasUI) ctx.ui.setWidget(WIDGET_KEY, undefined);
|
|
474
462
|
// Invalidate ordinary outcomes, abort children, then let preserved isolated
|
|
475
463
|
// work report into the outgoing session before Pi tears it down.
|
|
476
464
|
sessionEpoch += 1;
|
|
477
|
-
invalidateDelegateFlow();
|
|
478
465
|
const tasks = [...backgroundTasks.values()];
|
|
479
466
|
for (const { controller } of tasks) controller.abort();
|
|
480
467
|
await Promise.allSettled(tasks.map(({ settled }) => settled));
|
|
@@ -485,7 +472,7 @@ export default function subagentExtension(
|
|
|
485
472
|
pi.on("input", (event) => {
|
|
486
473
|
if (event.source === "extension") return;
|
|
487
474
|
for (const [id, item] of widgetItems) {
|
|
488
|
-
if (item.status !== "working"
|
|
475
|
+
if (item.status !== "working") widgetItems.delete(id);
|
|
489
476
|
}
|
|
490
477
|
requestWidgetRender();
|
|
491
478
|
});
|
|
@@ -573,34 +560,16 @@ export default function subagentExtension(
|
|
|
573
560
|
}
|
|
574
561
|
};
|
|
575
562
|
|
|
576
|
-
invalidateDelegateFlow = registerDelegateFlow(pi, {
|
|
577
|
-
executor,
|
|
578
|
-
maxRuntimeMs: timeoutPolicy.maxMs,
|
|
579
|
-
getSessionGeneration: () => sessionEpoch,
|
|
580
|
-
loadRoles,
|
|
581
|
-
resolveLaunch: (role, modelClass, ctx) => resolveRoleLaunch(pi, latestCtx ?? ctx, {
|
|
582
|
-
role,
|
|
583
|
-
task: DELEGATE_TASK,
|
|
584
|
-
...(modelClass === undefined ? {} : { modelClass }),
|
|
585
|
-
}),
|
|
586
|
-
startWidget: startWidgetItem,
|
|
587
|
-
setWidgetTaskRetained,
|
|
588
|
-
updateWidgetTokens,
|
|
589
|
-
updateWidgetActivity,
|
|
590
|
-
finishWidget: finishWidgetItem,
|
|
591
|
-
});
|
|
592
|
-
|
|
593
563
|
pi.registerTool({
|
|
594
564
|
name: "delegate_task",
|
|
595
565
|
label: "Subagent",
|
|
596
566
|
description: `Delegate one selected single, parallel, or chain workflow of bounded tasks to isolated Pi Subagents. Roles: ${roleSummary()}.`,
|
|
597
567
|
promptSnippet: "Delegate one bounded single, parallel, or chain workflow to isolated roles",
|
|
598
568
|
promptGuidelines: [
|
|
599
|
-
"
|
|
600
|
-
|
|
601
|
-
`For
|
|
602
|
-
"
|
|
603
|
-
"delegate_task background applies to the whole selected workflow and returns before results exist; use it only when the user explicitly asks for non-blocking work.",
|
|
569
|
+
"Use delegate_task with exactly one mode: role+name+task for one task, tasks for 1–8 independent tasks, or chain for 1–8 dependent tasks using {previous}. Prefer parallel whenever at least two outcomes are independently deliverable and verifiable; never split one invariant.",
|
|
570
|
+
"Each delegate_task entry needs one bounded outcome, scope and exclusions, context and constraints, deliverable, and focused validation. Discover unclear scope first; never pass the parent request unchanged. Parallel mutations need non-overlapping ownership; read-only tasks may overlap only for distinct questions. Keep integration and cross-cutting decisions in Main.",
|
|
571
|
+
`For delegate_task, ${MODEL_CLASS_GUIDANCE} A direct model replaces only the selected route's model; its thinking level stays unchanged.`,
|
|
572
|
+
"Use delegate_task background only when the user explicitly requests non-blocking work.",
|
|
604
573
|
],
|
|
605
574
|
parameters: WorkflowSchema,
|
|
606
575
|
prepareArguments(args) {
|
package/extensions/task-name.ts
CHANGED
|
@@ -3,13 +3,11 @@ import { Type, type Static } from "typebox";
|
|
|
3
3
|
|
|
4
4
|
const TASK_NAME_MAX_LENGTH = 29 as const;
|
|
5
5
|
const TASK_NAME_LIMIT_WORDING = `about five words and fewer than ${TASK_NAME_MAX_LENGTH + 1} characters`;
|
|
6
|
-
const TASK_NAME_WORDING = `short descriptive name of ${TASK_NAME_LIMIT_WORDING}`;
|
|
7
6
|
|
|
8
7
|
export const TASK_NAME_CONTRACT = {
|
|
9
8
|
minLength: 1,
|
|
10
9
|
maxLength: TASK_NAME_MAX_LENGTH,
|
|
11
10
|
description: `Short descriptive task name, ${TASK_NAME_LIMIT_WORDING}; C0/C1 control characters are rejected.`,
|
|
12
|
-
promptGuidance: `Use a ${TASK_NAME_WORDING} without C0/C1 control characters.`,
|
|
13
11
|
controlRanges: DISPLAY_TEXT_CONTRACT.controlRanges,
|
|
14
12
|
pattern: DISPLAY_TEXT_CONTRACT.pattern,
|
|
15
13
|
} as const;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@henryqw/pi-subagent",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.1",
|
|
4
4
|
"description": "Delegate bounded single, parallel, or chained tasks to isolated Pi roles.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"extensions",
|
|
20
20
|
"docs",
|
|
21
21
|
"examples",
|
|
22
|
-
"skills",
|
|
23
22
|
"README.md",
|
|
24
23
|
"CONTEXT.md"
|
|
25
24
|
],
|
|
@@ -59,9 +58,6 @@
|
|
|
59
58
|
"extensions": [
|
|
60
59
|
"./extensions/subagent.ts"
|
|
61
60
|
],
|
|
62
|
-
"skills": [
|
|
63
|
-
"./skills"
|
|
64
|
-
],
|
|
65
61
|
"image": "https://raw.githubusercontent.com/HenryQW/pi-harness/main/extensions/pi-subagent/example.png"
|
|
66
62
|
},
|
|
67
63
|
"dependencies": {
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Package-owned `delegate_flow` orchestration
|
|
2
|
-
|
|
3
|
-
## Decision
|
|
4
|
-
|
|
5
|
-
`delegate_task` remains the generic bounded Role tool described by [ADR 001](./001-composable-ephemeral-execution.md). Main plans and orchestrates; `delegate_flow` is a separate package-owned Git workflow with this fixed interface:
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
delegate_flow({ units: [{ id, task, modelClass?, validation: [{ command, args }], review? }] });
|
|
9
|
-
delegate_flow_continue({ guidance, modelClass? });
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
A Flow accepts 1–8 independent units with unique IDs. Route precedence is explicit unit or continuation `modelClass` > Role `modelClass` > configured `pi-subagent/delegateTask` assignment or declared default. An omitted unit class lets the frozen Implementer and, when applicable, Reviewer use their own Role defaults. The selected class resolves through the existing `pi-task-models` profile model-and-thinking route. `review` is optional non-empty text for the explicit judgment that declared validation cannot establish.
|
|
13
|
-
|
|
14
|
-
Only one memory-only Flow may be active. At start it resolves/freezes the effective `implementer` Role, including a same-named user override. It resolves/freezes the effective `reviewer` Role only when at least one requested unit has `review`. It requires a clean committed attached Main branch and creates one Unit Worktree per unit before launching Implementers in parallel. All started Implementers settle; Flow then processes units in declared order.
|
|
15
|
-
|
|
16
|
-
For each unit, Flow verifies Main, rebases the Unit Worktree in place when earlier Flow units advanced Main, inspects committed Git state, and runs declared validation. Validation is authoritative for objective verification. Without `review`, Flow skips exact evidence and Reviewer launch, then fast-forwards the exact validated tip through the existing guarded `git merge --ff-only` path. With `review`, it gives the Reviewer the exact `{base, tip, patchPath}` packet in that same worktree; only trimmed output exactly equal to `PASS` permits the same full-OID fast-forward. Cleanup uses non-forced worktree removal and branch deletion; cleanup refusal does not undo integration and returns completion with retained-work warnings.
|
|
17
|
-
|
|
18
|
-
If rebase drops all unit commits, `base === tip` is a no-op. Flow validates the state, skips Reviewer and merge, then cleans up ordinarily. Implementer failure, dirty or missing committed work, validation failure, and reviewer findings block the first affected declared unit. `delegate_flow_continue({ guidance, modelClass? })` launches a fresh ephemeral child with the frozen Implementer Role in that same Unit Worktree once, with original requirements, authoritative validation, previous block evidence, and Main guidance. Omitted continuation class retains a supplied Unit class and otherwise lets each frozen Role use its own default; a supplied class replaces both defaults for that repair and any subsequent Reviewer launch. A second block is terminal. Failed rebase, evidence/Reviewer, and other infrastructure failures retain worktrees. A reported fast-forward failure completes with its diagnostic as a warning only when Main is clean at the exact integrated tip; otherwise it is terminal. Earlier integrations are never rolled back.
|
|
19
|
-
|
|
20
|
-
## Consequences
|
|
21
|
-
|
|
22
|
-
Flow owns narrow deterministic Git mechanics while allowing user-owned Implementer and conditional Reviewer policy through same-named Role overrides. Overrides do not change validation authority, exact review protocol, approval, integration, or cleanup. Flow has no dependency graph, saved recovery, automatic retry, aggregate review, post-merge validation, Planner Role, or generic-role restriction. Units that overlap files, APIs, schemas, generated output, package metadata, lockfiles, or invariants must be combined or sequenced outside Flow.
|
package/docs/delegate-flow.html
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Delegate Flow lifecycle</title>
|
|
7
|
-
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
8
|
-
<style>
|
|
9
|
-
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
10
|
-
body { min-height: 100vh; display: grid; place-items: center; padding: 32px; background: #f0eee9; color: #101828; }
|
|
11
|
-
.frame { width: min(1280px, 100%); }
|
|
12
|
-
.eyebrow { margin-bottom: 8px; color: #4c5665; font: 500 8px/1 'Geist Mono', monospace; letter-spacing: .18em; text-transform: uppercase; }
|
|
13
|
-
h1 { margin-bottom: 24px; font: 600 28px/1.15 'Geist', sans-serif; letter-spacing: -.03em; }
|
|
14
|
-
svg { display: block; width: 100%; min-width: 960px; }
|
|
15
|
-
</style>
|
|
16
|
-
</head>
|
|
17
|
-
<body>
|
|
18
|
-
<main class="frame">
|
|
19
|
-
<p class="eyebrow">Flowchart · @henryqw/pi-subagent</p>
|
|
20
|
-
<h1>Delegate Flow lifecycle</h1>
|
|
21
|
-
<svg viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="delegate-flow-title delegate-flow-desc">
|
|
22
|
-
<title id="delegate-flow-title">Delegate Flow lifecycle</title>
|
|
23
|
-
<desc id="delegate-flow-desc">Flowchart showing setup, implementation, validation, optional exact review, one repair attempt, integration, cleanup, and retained-worktree failure outcomes.</desc>
|
|
24
|
-
<defs>
|
|
25
|
-
<style>
|
|
26
|
-
.zone { fill: #e6e4de; stroke: rgba(16,24,40,.141); stroke-width: 1; }
|
|
27
|
-
.zone-label { fill: #6a7282; font: 500 8px 'Geist Mono', monospace; letter-spacing: .18em; }
|
|
28
|
-
.node { fill: #fff; stroke: #101828; stroke-width: 1; }
|
|
29
|
-
.node-soft { fill: rgba(16,24,40,.03); stroke: rgba(16,24,40,.32); stroke-width: 1; }
|
|
30
|
-
.node-focal { fill: rgba(29,78,216,.08); stroke: #1d4ed8; stroke-width: 1.2; }
|
|
31
|
-
.node-failure { fill: rgba(16,24,40,.02); stroke: rgba(16,24,40,.42); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
32
|
-
.name { fill: #101828; font: 600 12px 'Geist', sans-serif; text-anchor: middle; }
|
|
33
|
-
.sub { fill: #4c5665; font: 400 8px 'Geist Mono', monospace; text-anchor: middle; }
|
|
34
|
-
.edge { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#arrow); }
|
|
35
|
-
.edge-failure { fill: none; stroke: #6a7282; stroke-width: 1.2; stroke-dasharray: 5 4; marker-end: url(#arrow); }
|
|
36
|
-
.edge-success { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#arrow-accent); }
|
|
37
|
-
.label-mask { fill: #f0eee9; }
|
|
38
|
-
.label { fill: #4c5665; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
39
|
-
.label-success { fill: #1d4ed8; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
40
|
-
.legend { fill: #4c5665; font: 400 8px 'Geist', sans-serif; }
|
|
41
|
-
</style>
|
|
42
|
-
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#4c5665"/></marker>
|
|
43
|
-
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#1d4ed8"/></marker>
|
|
44
|
-
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#1d4ed8"/></marker>
|
|
45
|
-
</defs>
|
|
46
|
-
|
|
47
|
-
<rect width="1280" height="720" fill="#f0eee9"/>
|
|
48
|
-
|
|
49
|
-
<!-- Zones -->
|
|
50
|
-
<rect class="zone" x="40" y="40" width="760" height="280" rx="8"/>
|
|
51
|
-
<text class="zone-label" x="56" y="64">INITIAL RUN</text>
|
|
52
|
-
<rect class="zone" x="40" y="340" width="760" height="260" rx="8"/>
|
|
53
|
-
<text class="zone-label" x="56" y="364">ONE REPAIR MAXIMUM</text>
|
|
54
|
-
<rect class="zone" x="840" y="40" width="400" height="560" rx="8"/>
|
|
55
|
-
<text class="zone-label" x="856" y="64">OUTCOMES</text>
|
|
56
|
-
|
|
57
|
-
<!-- Initial-run edges -->
|
|
58
|
-
<path class="edge" d="M248 128 H288"/>
|
|
59
|
-
<path class="edge" d="M464 128 H504"/>
|
|
60
|
-
<path class="edge" d="M600 128 H624"/>
|
|
61
|
-
<path class="edge" d="M784 128 H872"/>
|
|
62
|
-
<path class="edge" d="M704 176 V216"/>
|
|
63
|
-
<path class="edge-success" d="M784 248 H812 Q820 248 820 240 V152 Q820 144 828 144 H856 Q864 144 864 136 V128 H872"/>
|
|
64
|
-
|
|
65
|
-
<!-- Blocked initial-run paths to repair -->
|
|
66
|
-
<path class="edge" d="M376 160 V304 Q376 312 368 312 H160 Q152 312 152 320 V412"/>
|
|
67
|
-
<path class="edge" d="M552 160 V288 Q552 296 544 296 H136 Q128 296 128 304 V412"/>
|
|
68
|
-
<path class="edge" d="M664 280 V320 Q664 328 656 328 H184 Q176 328 176 336 V412"/>
|
|
69
|
-
|
|
70
|
-
<!-- Repair path -->
|
|
71
|
-
<path class="edge" d="M272 444 H320"/>
|
|
72
|
-
<path class="edge" d="M520 444 H592"/>
|
|
73
|
-
<path class="edge-success" d="M384 412 V384 Q384 376 392 376 H808 Q816 376 816 368 V120 Q816 112 824 112 H856 Q864 112 864 120 V128 H872"/>
|
|
74
|
-
<path class="edge-success" d="M768 444 H824 Q832 444 832 436 V168 Q832 160 840 160 H856 Q864 160 864 152 V128 H872"/>
|
|
75
|
-
|
|
76
|
-
<!-- Success outcome -->
|
|
77
|
-
<path class="edge-success" d="M880 128 H912"/>
|
|
78
|
-
<path class="edge-success" d="M1012 160 V216"/>
|
|
79
|
-
<path class="edge" d="M552 96 V80 Q552 72 560 72 H1144 Q1152 72 1152 80 V240 Q1152 248 1144 248 H1112"/>
|
|
80
|
-
|
|
81
|
-
<!-- Failure paths, fanned into one merge -->
|
|
82
|
-
<path class="edge-failure" d="M584 160 V304 Q584 312 592 312 H808 Q816 312 816 320 V488 Q816 496 824 496 H872"/>
|
|
83
|
-
<path class="edge-failure" d="M232 476 V568 Q232 576 240 576 H856 Q864 576 864 568 V512 Q864 504 872 504"/>
|
|
84
|
-
<path class="edge-failure" d="M472 476 V536 Q472 544 480 544 H840 Q848 544 848 536 V520 Q848 512 856 512 H872"/>
|
|
85
|
-
<path class="edge-failure" d="M768 460 H808 Q816 460 816 468 V512 Q816 520 824 520 H856 Q864 520 864 512 V504 H872"/>
|
|
86
|
-
<path class="edge-failure" d="M880 504 H912"/>
|
|
87
|
-
|
|
88
|
-
<!-- Completion-warning and integration-failure outcomes -->
|
|
89
|
-
<path class="edge-failure" d="M1012 280 V336"/>
|
|
90
|
-
<path class="edge-failure" d="M1112 136 H1184 Q1192 136 1192 144 V356 Q1192 364 1184 364 H1152"/>
|
|
91
|
-
<path class="edge-failure" d="M1112 112 H1208 Q1216 112 1216 120 V496 Q1216 504 1208 504 H1152"/>
|
|
92
|
-
|
|
93
|
-
<!-- Edge labels -->
|
|
94
|
-
<rect class="label-mask" x="272" y="252" width="128" height="12" rx="2"/>
|
|
95
|
-
<text class="label" x="336" y="261">IMPLEMENTER BLOCK</text>
|
|
96
|
-
<rect class="label-mask" x="416" y="276" width="120" height="12" rx="2"/>
|
|
97
|
-
<text class="label" x="476" y="285">VALIDATION BLOCK</text>
|
|
98
|
-
<rect class="label-mask" x="504" y="316" width="96" height="12" rx="2"/>
|
|
99
|
-
<text class="label" x="552" y="325">REVIEW BLOCK</text>
|
|
100
|
-
<rect class="label-mask" x="800" y="100" width="32" height="12" rx="2"/>
|
|
101
|
-
<text class="label" x="816" y="109">NO</text>
|
|
102
|
-
<rect class="label-mask" x="688" y="188" width="32" height="12" rx="2"/>
|
|
103
|
-
<text class="label" x="704" y="197">YES</text>
|
|
104
|
-
<rect class="label-mask" x="828" y="224" width="40" height="12" rx="2"/>
|
|
105
|
-
<text class="label-success" x="848" y="233">PASS</text>
|
|
106
|
-
<rect class="label-mask" x="520" y="364" width="144" height="12" rx="2"/>
|
|
107
|
-
<text class="label-success" x="592" y="373">NO REVIEW REQUESTED</text>
|
|
108
|
-
<rect class="label-mask" x="528" y="424" width="56" height="12" rx="2"/>
|
|
109
|
-
<text class="label" x="556" y="433">REVIEW</text>
|
|
110
|
-
<rect class="label-mask" x="800" y="404" width="40" height="12" rx="2"/>
|
|
111
|
-
<text class="label-success" x="820" y="413">PASS</text>
|
|
112
|
-
<rect class="label-mask" x="816" y="292" width="160" height="12" rx="2"/>
|
|
113
|
-
<text class="label" x="896" y="301">REBASE / INFRA FAILURE</text>
|
|
114
|
-
<rect class="label-mask" x="336" y="556" width="136" height="12" rx="2"/>
|
|
115
|
-
<text class="label" x="404" y="565">INFRASTRUCTURE FAILURE</text>
|
|
116
|
-
<rect class="label-mask" x="560" y="524" width="96" height="12" rx="2"/>
|
|
117
|
-
<text class="label" x="608" y="533">SECOND BLOCK</text>
|
|
118
|
-
<rect class="label-mask" x="748" y="476" width="96" height="12" rx="2"/>
|
|
119
|
-
<text class="label" x="796" y="485">SECOND BLOCK</text>
|
|
120
|
-
<rect class="label-mask" x="920" y="60" width="128" height="12" rx="2"/>
|
|
121
|
-
<text class="label" x="984" y="69">POST-REBASE NO-OP</text>
|
|
122
|
-
<rect class="label-mask" x="1024" y="296" width="120" height="12" rx="2"/>
|
|
123
|
-
<text class="label" x="1084" y="305">CLEANUP REFUSAL</text>
|
|
124
|
-
<rect class="label-mask" x="1024" y="312" width="152" height="12" rx="2"/>
|
|
125
|
-
<text class="label" x="1100" y="321">FF DIAGNOSTIC / CLEAN TIP</text>
|
|
126
|
-
<rect class="label-mask" x="1064" y="432" width="136" height="12" rx="2"/>
|
|
127
|
-
<text class="label" x="1132" y="441">OTHER FF FAILURE</text>
|
|
128
|
-
|
|
129
|
-
<!-- Nodes -->
|
|
130
|
-
<rect class="node-soft" x="72" y="96" width="176" height="64" rx="32"/>
|
|
131
|
-
<text class="name" x="160" y="124">Resolve roles</text>
|
|
132
|
-
<text class="sub" x="160" y="140">CREATE UNIT WORKTREES</text>
|
|
133
|
-
|
|
134
|
-
<rect class="node" x="288" y="96" width="176" height="64" rx="6"/>
|
|
135
|
-
<text class="name" x="376" y="124">Implement in parallel</text>
|
|
136
|
-
<text class="sub" x="376" y="140">EACH UNIT ISOLATED</text>
|
|
137
|
-
|
|
138
|
-
<rect class="node" x="504" y="96" width="96" height="64" rx="6"/>
|
|
139
|
-
<text class="name" x="552" y="120">Rebase</text>
|
|
140
|
-
<text class="sub" x="552" y="136">INSPECT</text>
|
|
141
|
-
<text class="sub" x="552" y="148">VALIDATE</text>
|
|
142
|
-
|
|
143
|
-
<polygon class="node" points="704,80 784,128 704,176 624,128"/>
|
|
144
|
-
<text class="name" x="704" y="124">Review</text>
|
|
145
|
-
<text class="sub" x="704" y="140">REQUESTED?</text>
|
|
146
|
-
|
|
147
|
-
<rect class="node" x="624" y="216" width="160" height="64" rx="6"/>
|
|
148
|
-
<text class="name" x="704" y="240">Exact review packet</text>
|
|
149
|
-
<text class="sub" x="704" y="256">BASE · TIP · PATCH</text>
|
|
150
|
-
<text class="sub" x="704" y="268">REQUIRE PASS</text>
|
|
151
|
-
|
|
152
|
-
<rect class="node-focal" x="912" y="96" width="200" height="64" rx="6"/>
|
|
153
|
-
<text class="name" x="1012" y="124">Integrate in order</text>
|
|
154
|
-
<text class="sub" x="1012" y="140">FAST-FORWARD EXACT TIP</text>
|
|
155
|
-
|
|
156
|
-
<rect class="node-soft" x="912" y="216" width="200" height="64" rx="32"/>
|
|
157
|
-
<text class="name" x="1012" y="244">Cleanup</text>
|
|
158
|
-
<text class="sub" x="1012" y="260">REMOVE WORKTREE + BRANCH</text>
|
|
159
|
-
|
|
160
|
-
<rect class="node-soft" x="912" y="336" width="240" height="72" rx="32"/>
|
|
161
|
-
<text class="name" x="1032" y="364">Completion warning</text>
|
|
162
|
-
<text class="sub" x="1032" y="380">CLEAN TIP · OR CLEANUP REFUSAL</text>
|
|
163
|
-
<text class="sub" x="1032" y="392">RETAIN REPORTED RESOURCES</text>
|
|
164
|
-
|
|
165
|
-
<rect class="node" x="72" y="412" width="200" height="64" rx="6"/>
|
|
166
|
-
<text class="name" x="172" y="440">One repair</text>
|
|
167
|
-
<text class="sub" x="172" y="456">DELEGATE_FLOW_CONTINUE</text>
|
|
168
|
-
|
|
169
|
-
<rect class="node" x="320" y="412" width="200" height="64" rx="6"/>
|
|
170
|
-
<text class="name" x="420" y="440">Revalidate repair</text>
|
|
171
|
-
<text class="sub" x="420" y="456">SAME UNIT WORKTREE</text>
|
|
172
|
-
|
|
173
|
-
<rect class="node" x="592" y="412" width="176" height="64" rx="6"/>
|
|
174
|
-
<text class="name" x="680" y="440">Re-review packet</text>
|
|
175
|
-
<text class="sub" x="680" y="456">REQUIRE PASS AGAIN</text>
|
|
176
|
-
|
|
177
|
-
<rect class="node-failure" x="912" y="472" width="240" height="64" rx="32"/>
|
|
178
|
-
<text class="name" x="1032" y="500">Terminal failure</text>
|
|
179
|
-
<text class="sub" x="1032" y="516">RETAIN UNIT WORKTREE</text>
|
|
180
|
-
|
|
181
|
-
<!-- Merge points -->
|
|
182
|
-
<circle cx="876" cy="128" r="4" fill="#1d4ed8"/>
|
|
183
|
-
<circle cx="876" cy="504" r="4" fill="#6a7282"/>
|
|
184
|
-
|
|
185
|
-
<!-- Legend -->
|
|
186
|
-
<line x1="40" y1="636" x2="1240" y2="636" stroke="rgba(16,24,40,.141)" stroke-width="0.8"/>
|
|
187
|
-
<text class="zone-label" x="40" y="656">LEGEND</text>
|
|
188
|
-
<rect class="node" x="120" y="648" width="24" height="12" rx="2"/>
|
|
189
|
-
<text class="legend" x="152" y="658">Step</text>
|
|
190
|
-
<polygon class="node" points="236,654 248,648 260,654 248,660"/>
|
|
191
|
-
<text class="legend" x="272" y="658">Decision</text>
|
|
192
|
-
<circle cx="380" cy="654" r="4" fill="#4c5665"/>
|
|
193
|
-
<text class="legend" x="392" y="658">Branch merge</text>
|
|
194
|
-
<line x1="512" y1="654" x2="548" y2="654" stroke="#1d4ed8" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
|
|
195
|
-
<text class="legend" x="560" y="658">Validated path</text>
|
|
196
|
-
<line x1="696" y1="654" x2="732" y2="654" stroke="#6a7282" stroke-width="1.2" stroke-dasharray="5 4" marker-end="url(#arrow)"/>
|
|
197
|
-
<text class="legend" x="744" y="658">Terminal path</text>
|
|
198
|
-
<text class="sub" x="1120" y="658">ONE REPAIR · NO AUTOMATIC RETRY</text>
|
|
199
|
-
</svg>
|
|
200
|
-
</main>
|
|
201
|
-
</body>
|
|
202
|
-
</html>
|
package/docs/delegate-flow.svg
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="delegate-flow-title delegate-flow-desc">
|
|
3
|
-
<title id="delegate-flow-title">Delegate Flow lifecycle</title>
|
|
4
|
-
<desc id="delegate-flow-desc">Flowchart showing setup, implementation, validation, optional exact review, one repair attempt, integration, cleanup, and retained-worktree failure outcomes.</desc>
|
|
5
|
-
<defs>
|
|
6
|
-
<style>
|
|
7
|
-
@import url("https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&display=swap");
|
|
8
|
-
.zone { fill: #e6e4de; stroke: rgba(16,24,40,.141); stroke-width: 1; }
|
|
9
|
-
.zone-label { fill: #6a7282; font: 500 8px 'Geist Mono', monospace; letter-spacing: .18em; }
|
|
10
|
-
.node { fill: #fff; stroke: #101828; stroke-width: 1; }
|
|
11
|
-
.node-soft { fill: rgba(16,24,40,.03); stroke: rgba(16,24,40,.32); stroke-width: 1; }
|
|
12
|
-
.node-focal { fill: rgba(29,78,216,.08); stroke: #1d4ed8; stroke-width: 1.2; }
|
|
13
|
-
.node-failure { fill: rgba(16,24,40,.02); stroke: rgba(16,24,40,.42); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
14
|
-
.name { fill: #101828; font: 600 12px 'Geist', sans-serif; text-anchor: middle; }
|
|
15
|
-
.sub { fill: #4c5665; font: 400 8px 'Geist Mono', monospace; text-anchor: middle; }
|
|
16
|
-
.edge { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#arrow); }
|
|
17
|
-
.edge-failure { fill: none; stroke: #6a7282; stroke-width: 1.2; stroke-dasharray: 5 4; marker-end: url(#arrow); }
|
|
18
|
-
.edge-success { fill: none; stroke: #1d4ed8; stroke-width: 1.4; marker-end: url(#arrow-accent); }
|
|
19
|
-
.label-mask { fill: #f0eee9; }
|
|
20
|
-
.label { fill: #4c5665; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
21
|
-
.label-success { fill: #1d4ed8; font: 500 8px 'Geist Mono', monospace; text-anchor: middle; letter-spacing: .04em; }
|
|
22
|
-
.legend { fill: #4c5665; font: 400 8px 'Geist', sans-serif; }
|
|
23
|
-
</style>
|
|
24
|
-
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#4c5665"/></marker>
|
|
25
|
-
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#1d4ed8"/></marker>
|
|
26
|
-
<marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="#1d4ed8"/></marker>
|
|
27
|
-
</defs>
|
|
28
|
-
|
|
29
|
-
<rect width="1280" height="720" fill="#f0eee9"/>
|
|
30
|
-
|
|
31
|
-
<!-- Zones -->
|
|
32
|
-
<rect class="zone" x="40" y="40" width="760" height="280" rx="8"/>
|
|
33
|
-
<text class="zone-label" x="56" y="64">INITIAL RUN</text>
|
|
34
|
-
<rect class="zone" x="40" y="340" width="760" height="260" rx="8"/>
|
|
35
|
-
<text class="zone-label" x="56" y="364">ONE REPAIR MAXIMUM</text>
|
|
36
|
-
<rect class="zone" x="840" y="40" width="400" height="560" rx="8"/>
|
|
37
|
-
<text class="zone-label" x="856" y="64">OUTCOMES</text>
|
|
38
|
-
|
|
39
|
-
<!-- Initial-run edges -->
|
|
40
|
-
<path class="edge" d="M248 128 H288"/>
|
|
41
|
-
<path class="edge" d="M464 128 H504"/>
|
|
42
|
-
<path class="edge" d="M600 128 H624"/>
|
|
43
|
-
<path class="edge" d="M784 128 H872"/>
|
|
44
|
-
<path class="edge" d="M704 176 V216"/>
|
|
45
|
-
<path class="edge-success" d="M784 248 H812 Q820 248 820 240 V152 Q820 144 828 144 H856 Q864 144 864 136 V128 H872"/>
|
|
46
|
-
|
|
47
|
-
<!-- Blocked initial-run paths to repair -->
|
|
48
|
-
<path class="edge" d="M376 160 V304 Q376 312 368 312 H160 Q152 312 152 320 V412"/>
|
|
49
|
-
<path class="edge" d="M552 160 V288 Q552 296 544 296 H136 Q128 296 128 304 V412"/>
|
|
50
|
-
<path class="edge" d="M664 280 V320 Q664 328 656 328 H184 Q176 328 176 336 V412"/>
|
|
51
|
-
|
|
52
|
-
<!-- Repair path -->
|
|
53
|
-
<path class="edge" d="M272 444 H320"/>
|
|
54
|
-
<path class="edge" d="M520 444 H592"/>
|
|
55
|
-
<path class="edge-success" d="M384 412 V384 Q384 376 392 376 H808 Q816 376 816 368 V120 Q816 112 824 112 H856 Q864 112 864 120 V128 H872"/>
|
|
56
|
-
<path class="edge-success" d="M768 444 H824 Q832 444 832 436 V168 Q832 160 840 160 H856 Q864 160 864 152 V128 H872"/>
|
|
57
|
-
|
|
58
|
-
<!-- Success outcome -->
|
|
59
|
-
<path class="edge-success" d="M880 128 H912"/>
|
|
60
|
-
<path class="edge-success" d="M1012 160 V216"/>
|
|
61
|
-
<path class="edge" d="M552 96 V80 Q552 72 560 72 H1144 Q1152 72 1152 80 V240 Q1152 248 1144 248 H1112"/>
|
|
62
|
-
|
|
63
|
-
<!-- Failure paths, fanned into one merge -->
|
|
64
|
-
<path class="edge-failure" d="M584 160 V304 Q584 312 592 312 H808 Q816 312 816 320 V488 Q816 496 824 496 H872"/>
|
|
65
|
-
<path class="edge-failure" d="M232 476 V568 Q232 576 240 576 H856 Q864 576 864 568 V512 Q864 504 872 504"/>
|
|
66
|
-
<path class="edge-failure" d="M472 476 V536 Q472 544 480 544 H840 Q848 544 848 536 V520 Q848 512 856 512 H872"/>
|
|
67
|
-
<path class="edge-failure" d="M768 460 H808 Q816 460 816 468 V512 Q816 520 824 520 H856 Q864 520 864 512 V504 H872"/>
|
|
68
|
-
<path class="edge-failure" d="M880 504 H912"/>
|
|
69
|
-
|
|
70
|
-
<!-- Completion-warning and integration-failure outcomes -->
|
|
71
|
-
<path class="edge-failure" d="M1012 280 V336"/>
|
|
72
|
-
<path class="edge-failure" d="M1112 136 H1184 Q1192 136 1192 144 V356 Q1192 364 1184 364 H1152"/>
|
|
73
|
-
<path class="edge-failure" d="M1112 112 H1208 Q1216 112 1216 120 V496 Q1216 504 1208 504 H1152"/>
|
|
74
|
-
|
|
75
|
-
<!-- Edge labels -->
|
|
76
|
-
<rect class="label-mask" x="272" y="252" width="128" height="12" rx="2"/>
|
|
77
|
-
<text class="label" x="336" y="261">IMPLEMENTER BLOCK</text>
|
|
78
|
-
<rect class="label-mask" x="416" y="276" width="120" height="12" rx="2"/>
|
|
79
|
-
<text class="label" x="476" y="285">VALIDATION BLOCK</text>
|
|
80
|
-
<rect class="label-mask" x="504" y="316" width="96" height="12" rx="2"/>
|
|
81
|
-
<text class="label" x="552" y="325">REVIEW BLOCK</text>
|
|
82
|
-
<rect class="label-mask" x="800" y="100" width="32" height="12" rx="2"/>
|
|
83
|
-
<text class="label" x="816" y="109">NO</text>
|
|
84
|
-
<rect class="label-mask" x="688" y="188" width="32" height="12" rx="2"/>
|
|
85
|
-
<text class="label" x="704" y="197">YES</text>
|
|
86
|
-
<rect class="label-mask" x="828" y="224" width="40" height="12" rx="2"/>
|
|
87
|
-
<text class="label-success" x="848" y="233">PASS</text>
|
|
88
|
-
<rect class="label-mask" x="520" y="364" width="144" height="12" rx="2"/>
|
|
89
|
-
<text class="label-success" x="592" y="373">NO REVIEW REQUESTED</text>
|
|
90
|
-
<rect class="label-mask" x="528" y="424" width="56" height="12" rx="2"/>
|
|
91
|
-
<text class="label" x="556" y="433">REVIEW</text>
|
|
92
|
-
<rect class="label-mask" x="800" y="404" width="40" height="12" rx="2"/>
|
|
93
|
-
<text class="label-success" x="820" y="413">PASS</text>
|
|
94
|
-
<rect class="label-mask" x="816" y="292" width="160" height="12" rx="2"/>
|
|
95
|
-
<text class="label" x="896" y="301">REBASE / INFRA FAILURE</text>
|
|
96
|
-
<rect class="label-mask" x="336" y="556" width="136" height="12" rx="2"/>
|
|
97
|
-
<text class="label" x="404" y="565">INFRASTRUCTURE FAILURE</text>
|
|
98
|
-
<rect class="label-mask" x="560" y="524" width="96" height="12" rx="2"/>
|
|
99
|
-
<text class="label" x="608" y="533">SECOND BLOCK</text>
|
|
100
|
-
<rect class="label-mask" x="748" y="476" width="96" height="12" rx="2"/>
|
|
101
|
-
<text class="label" x="796" y="485">SECOND BLOCK</text>
|
|
102
|
-
<rect class="label-mask" x="920" y="60" width="128" height="12" rx="2"/>
|
|
103
|
-
<text class="label" x="984" y="69">POST-REBASE NO-OP</text>
|
|
104
|
-
<rect class="label-mask" x="1024" y="296" width="120" height="12" rx="2"/>
|
|
105
|
-
<text class="label" x="1084" y="305">CLEANUP REFUSAL</text>
|
|
106
|
-
<rect class="label-mask" x="1024" y="312" width="152" height="12" rx="2"/>
|
|
107
|
-
<text class="label" x="1100" y="321">FF DIAGNOSTIC / CLEAN TIP</text>
|
|
108
|
-
<rect class="label-mask" x="1064" y="432" width="136" height="12" rx="2"/>
|
|
109
|
-
<text class="label" x="1132" y="441">OTHER FF FAILURE</text>
|
|
110
|
-
|
|
111
|
-
<!-- Nodes -->
|
|
112
|
-
<rect class="node-soft" x="72" y="96" width="176" height="64" rx="32"/>
|
|
113
|
-
<text class="name" x="160" y="124">Resolve roles</text>
|
|
114
|
-
<text class="sub" x="160" y="140">CREATE UNIT WORKTREES</text>
|
|
115
|
-
|
|
116
|
-
<rect class="node" x="288" y="96" width="176" height="64" rx="6"/>
|
|
117
|
-
<text class="name" x="376" y="124">Implement in parallel</text>
|
|
118
|
-
<text class="sub" x="376" y="140">EACH UNIT ISOLATED</text>
|
|
119
|
-
|
|
120
|
-
<rect class="node" x="504" y="96" width="96" height="64" rx="6"/>
|
|
121
|
-
<text class="name" x="552" y="120">Rebase</text>
|
|
122
|
-
<text class="sub" x="552" y="136">INSPECT</text>
|
|
123
|
-
<text class="sub" x="552" y="148">VALIDATE</text>
|
|
124
|
-
|
|
125
|
-
<polygon class="node" points="704,80 784,128 704,176 624,128"/>
|
|
126
|
-
<text class="name" x="704" y="124">Review</text>
|
|
127
|
-
<text class="sub" x="704" y="140">REQUESTED?</text>
|
|
128
|
-
|
|
129
|
-
<rect class="node" x="624" y="216" width="160" height="64" rx="6"/>
|
|
130
|
-
<text class="name" x="704" y="240">Exact review packet</text>
|
|
131
|
-
<text class="sub" x="704" y="256">BASE · TIP · PATCH</text>
|
|
132
|
-
<text class="sub" x="704" y="268">REQUIRE PASS</text>
|
|
133
|
-
|
|
134
|
-
<rect class="node-focal" x="912" y="96" width="200" height="64" rx="6"/>
|
|
135
|
-
<text class="name" x="1012" y="124">Integrate in order</text>
|
|
136
|
-
<text class="sub" x="1012" y="140">FAST-FORWARD EXACT TIP</text>
|
|
137
|
-
|
|
138
|
-
<rect class="node-soft" x="912" y="216" width="200" height="64" rx="32"/>
|
|
139
|
-
<text class="name" x="1012" y="244">Cleanup</text>
|
|
140
|
-
<text class="sub" x="1012" y="260">REMOVE WORKTREE + BRANCH</text>
|
|
141
|
-
|
|
142
|
-
<rect class="node-soft" x="912" y="336" width="240" height="72" rx="32"/>
|
|
143
|
-
<text class="name" x="1032" y="364">Completion warning</text>
|
|
144
|
-
<text class="sub" x="1032" y="380">CLEAN TIP · OR CLEANUP REFUSAL</text>
|
|
145
|
-
<text class="sub" x="1032" y="392">RETAIN REPORTED RESOURCES</text>
|
|
146
|
-
|
|
147
|
-
<rect class="node" x="72" y="412" width="200" height="64" rx="6"/>
|
|
148
|
-
<text class="name" x="172" y="440">One repair</text>
|
|
149
|
-
<text class="sub" x="172" y="456">DELEGATE_FLOW_CONTINUE</text>
|
|
150
|
-
|
|
151
|
-
<rect class="node" x="320" y="412" width="200" height="64" rx="6"/>
|
|
152
|
-
<text class="name" x="420" y="440">Revalidate repair</text>
|
|
153
|
-
<text class="sub" x="420" y="456">SAME UNIT WORKTREE</text>
|
|
154
|
-
|
|
155
|
-
<rect class="node" x="592" y="412" width="176" height="64" rx="6"/>
|
|
156
|
-
<text class="name" x="680" y="440">Re-review packet</text>
|
|
157
|
-
<text class="sub" x="680" y="456">REQUIRE PASS AGAIN</text>
|
|
158
|
-
|
|
159
|
-
<rect class="node-failure" x="912" y="472" width="240" height="64" rx="32"/>
|
|
160
|
-
<text class="name" x="1032" y="500">Terminal failure</text>
|
|
161
|
-
<text class="sub" x="1032" y="516">RETAIN UNIT WORKTREE</text>
|
|
162
|
-
|
|
163
|
-
<!-- Merge points -->
|
|
164
|
-
<circle cx="876" cy="128" r="4" fill="#1d4ed8"/>
|
|
165
|
-
<circle cx="876" cy="504" r="4" fill="#6a7282"/>
|
|
166
|
-
|
|
167
|
-
<!-- Legend -->
|
|
168
|
-
<line x1="40" y1="636" x2="1240" y2="636" stroke="rgba(16,24,40,.141)" stroke-width="0.8"/>
|
|
169
|
-
<text class="zone-label" x="40" y="656">LEGEND</text>
|
|
170
|
-
<rect class="node" x="120" y="648" width="24" height="12" rx="2"/>
|
|
171
|
-
<text class="legend" x="152" y="658">Step</text>
|
|
172
|
-
<polygon class="node" points="236,654 248,648 260,654 248,660"/>
|
|
173
|
-
<text class="legend" x="272" y="658">Decision</text>
|
|
174
|
-
<circle cx="380" cy="654" r="4" fill="#4c5665"/>
|
|
175
|
-
<text class="legend" x="392" y="658">Branch merge</text>
|
|
176
|
-
<line x1="512" y1="654" x2="548" y2="654" stroke="#1d4ed8" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
|
|
177
|
-
<text class="legend" x="560" y="658">Validated path</text>
|
|
178
|
-
<line x1="696" y1="654" x2="732" y2="654" stroke="#6a7282" stroke-width="1.2" stroke-dasharray="5 4" marker-end="url(#arrow)"/>
|
|
179
|
-
<text class="legend" x="744" y="658">Terminal path</text>
|
|
180
|
-
<text class="sub" x="1120" y="658">ONE REPAIR · NO AUTOMATIC RETRY</text>
|
|
181
|
-
</svg>
|