@zigrivers/scaffold 3.29.0 → 3.30.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/content/guides/AUTHORING.md +143 -0
- package/content/guides/cli/index.html +1502 -0
- package/content/guides/cli/index.md +206 -0
- package/content/guides/concepts/index.html +1617 -0
- package/content/guides/concepts/index.md +347 -0
- package/content/guides/dashboard/index.html +1560 -0
- package/content/guides/dashboard/index.md +264 -0
- package/content/guides/index.html +1 -1
- package/content/guides/install/.diagrams/diagram-0.svg +1 -0
- package/content/guides/install/.diagrams/manifest.json +3 -0
- package/content/guides/install/index.html +1300 -0
- package/content/guides/install/index.md +186 -0
- package/content/guides/knowledge/.diagrams/diagram-0.svg +1 -0
- package/content/guides/knowledge/.diagrams/manifest.json +3 -0
- package/content/guides/knowledge/index.html +1412 -0
- package/content/guides/knowledge/index.md +209 -0
- package/content/guides/knowledge-freshness/.diagrams/diagram-0.svg +1 -0
- package/content/guides/knowledge-freshness/.diagrams/manifest.json +3 -0
- package/content/guides/knowledge-freshness/index.html +2442 -0
- package/content/guides/knowledge-freshness/index.md +893 -0
- package/content/guides/mmr/index.html +35 -17
- package/content/guides/mmr/index.md +39 -16
- package/content/guides/multi-agent/.diagrams/diagram-0.svg +1 -0
- package/content/guides/multi-agent/.diagrams/manifest.json +3 -0
- package/content/guides/multi-agent/index.html +1362 -0
- package/content/guides/multi-agent/index.md +243 -0
- package/content/guides/observability/.diagrams/diagram-0.svg +1 -0
- package/content/guides/observability/.diagrams/diagram-1.svg +1 -0
- package/content/guides/observability/.diagrams/diagram-2.svg +1 -0
- package/content/guides/observability/.diagrams/diagram-3.svg +1 -0
- package/content/guides/observability/.diagrams/manifest.json +6 -0
- package/content/guides/observability/index.html +2904 -0
- package/content/guides/observability/index.md +1097 -0
- package/content/guides/pipeline/.diagrams/diagram-0.svg +1 -0
- package/content/guides/pipeline/.diagrams/diagram-1.svg +1 -0
- package/content/guides/pipeline/.diagrams/manifest.json +4 -0
- package/content/guides/pipeline/index.html +1632 -0
- package/content/guides/pipeline/index.md +387 -0
- package/content/guides/review-workflow/.diagrams/diagram-0.svg +1 -0
- package/content/guides/review-workflow/.diagrams/diagram-1.svg +1 -0
- package/content/guides/review-workflow/.diagrams/manifest.json +4 -0
- package/content/guides/review-workflow/index.html +1437 -0
- package/content/guides/review-workflow/index.md +248 -0
- package/dist/guides/build.d.ts.map +1 -1
- package/dist/guides/build.js +7 -2
- package/dist/guides/build.js.map +1 -1
- package/dist/guides/build.test.js +8 -0
- package/dist/guides/build.test.js.map +1 -1
- package/dist/guides/directives-cite.test.d.ts +2 -0
- package/dist/guides/directives-cite.test.d.ts.map +1 -0
- package/dist/guides/directives-cite.test.js +26 -0
- package/dist/guides/directives-cite.test.js.map +1 -0
- package/dist/guides/directives.d.ts +1 -0
- package/dist/guides/directives.d.ts.map +1 -1
- package/dist/guides/directives.js +24 -0
- package/dist/guides/directives.js.map +1 -1
- package/dist/guides/links.d.ts +14 -0
- package/dist/guides/links.d.ts.map +1 -0
- package/dist/guides/links.js +56 -0
- package/dist/guides/links.js.map +1 -0
- package/dist/guides/links.test.d.ts +2 -0
- package/dist/guides/links.test.d.ts.map +1 -0
- package/dist/guides/links.test.js +72 -0
- package/dist/guides/links.test.js.map +1 -0
- package/dist/guides/render.d.ts +1 -0
- package/dist/guides/render.d.ts.map +1 -1
- package/dist/guides/render.js +1 -1
- package/dist/guides/render.js.map +1 -1
- package/dist/guides/sanitize.d.ts.map +1 -1
- package/dist/guides/sanitize.js +1 -0
- package/dist/guides/sanitize.js.map +1 -1
- package/package.json +1 -1
|
@@ -1099,12 +1099,12 @@ disagreement is what surfaces ambiguity.</p>
|
|
|
1099
1099
|
<ol>
|
|
1100
1100
|
<li><strong>Resolve a diff</strong> — from a PR, staged changes, a branch range, or a piped diff.</li>
|
|
1101
1101
|
<li><strong>Dispatch channels</strong> — each channel is a separate subprocess given the same
|
|
1102
|
-
prompt, run in parallel and isolated
|
|
1102
|
+
prompt, run in parallel and isolated <span class="fp" data-path="packages/mmr/src/commands/review.ts:636">packages/mmr/src/commands/review.ts:636</span>.</li>
|
|
1103
1103
|
<li><strong>Parse</strong> — each channel's raw output is parsed into a common <code>Finding</code> shape.</li>
|
|
1104
1104
|
<li><strong>Reconcile</strong> — findings are grouped by a stable key, de-duplicated, and
|
|
1105
|
-
scored for agreement and confidence
|
|
1105
|
+
scored for agreement and confidence <span class="fp" data-path="packages/mmr/src/core/reconciler.ts:43">packages/mmr/src/core/reconciler.ts:43</span>.</li>
|
|
1106
1106
|
<li><strong>Verdict</strong> — a severity gate yields <code>pass</code>, <code>degraded-pass</code>, <code>blocked</code>, or
|
|
1107
|
-
<code>needs-user-decision</code>.</li>
|
|
1107
|
+
<code>needs-user-decision</code> <span class="fp" data-path="packages/mmr/src/types.ts:25">packages/mmr/src/types.ts:25</span>.</li>
|
|
1108
1108
|
</ol>
|
|
1109
1109
|
<div class="callout callout-tip"><p><strong>Two layers, one mental model.</strong> The <code>mmr</code> CLI is the engine that dispatches
|
|
1110
1110
|
the built-in channels and computes the verdict. The <code>scaffold run review-pr</code> /
|
|
@@ -1231,7 +1231,7 @@ table.</p>
|
|
|
1231
1231
|
|
|
1232
1232
|
|
|
1233
1233
|
|
|
1234
|
-
<table><thead><tr><th>Flag</th><th>Group</th><th>Description</th></tr></thead><tbody><tr><td><code>--diff <path|-></code></td><td>input</td><td>Read a unified diff from a file, or <code>-</code> for stdin. Highest-priority input mode.</td></tr><tr><td><code>--pr <n></code></td><td>input</td><td>Fetch the PR diff via <code>gh pr diff</code>.</td></tr><tr><td><code>--staged</code></td><td>input</td><td>Review staged changes (<code>git diff --cached</code>).</td></tr><tr><td><code>--base <ref> [--head <ref>]</code></td><td>input</td><td>Review a branch range (<code>git diff base...head</code>, head defaults to HEAD).</td></tr><tr><td><em>(no input flag)</em></td><td>input</td><td>Falls back to unstaged working-tree changes (<code>git diff</code>).</td></tr><tr><td><code>--focus <text></code></td><td>control</td><td>Free-text focus areas appended to every channel prompt.</td></tr><tr><td><code>--fix-threshold <P0|P1|P2|P3></code></td><td>control</td><td>Severity gate. Findings at or above this block. Default P2 (from <code>.mmr.yaml</code>).</td></tr><tr><td><code>--channels <names…></code></td><td>control</td><td>Run only these channels, overriding config defaults. Abstract channels are filtered out.</td></tr><tr><td><code>--timeout <seconds></code></td><td>control</td><td>Per-channel timeout override.</td></tr><tr><td><code>--template <name></code></td><td>control</td><td>Use a named review-criteria template from config.</td></tr><tr><td><code>--format <json|text|markdown></code></td><td>output</td><td>Output format. Default <code>json</code>.</td></tr><tr><td><code>--sync</code></td><td>mode</td><td>Run the full pipeline (dispatch → parse → reconcile → verdict) and return results. Without it, dispatch is fire-and-forget.</td></tr><tr><td><code>--dry-run</code></td><td>mode</td><td>Resolve the diff and assemble the prompt without dispatching any channel.</td></tr><tr><td><code>--session <id></code></td><td>rounds</td><td>Link this run into a multi-round session
|
|
1234
|
+
<table><thead><tr><th>Flag</th><th>Group</th><th>Description</th></tr></thead><tbody><tr><td><code>--diff <path|-></code></td><td>input</td><td>Read a unified diff from a file, or <code>-</code> for stdin. Highest-priority input mode.</td></tr><tr><td><code>--pr <n></code></td><td>input</td><td>Fetch the PR diff via <code>gh pr diff</code>.</td></tr><tr><td><code>--staged</code></td><td>input</td><td>Review staged changes (<code>git diff --cached</code>).</td></tr><tr><td><code>--base <ref> [--head <ref>]</code></td><td>input</td><td>Review a branch range (<code>git diff base...head</code>, head defaults to HEAD).</td></tr><tr><td><em>(no input flag)</em></td><td>input</td><td>Falls back to unstaged working-tree changes (<code>git diff</code>).</td></tr><tr><td><code>--focus <text></code></td><td>control</td><td>Free-text focus areas appended to every channel prompt.</td></tr><tr><td><code>--fix-threshold <P0|P1|P2|P3></code></td><td>control</td><td>Severity gate. Findings at or above this block. Default P2 (from <code>.mmr.yaml</code>).</td></tr><tr><td><code>--channels <names…></code></td><td>control</td><td>Run only these channels, overriding config defaults. Abstract channels are filtered out.</td></tr><tr><td><code>--timeout <seconds></code></td><td>control</td><td>Per-channel timeout override.</td></tr><tr><td><code>--template <name></code></td><td>control</td><td>Use a named review-criteria template from config.</td></tr><tr><td><code>--format <json|text|markdown></code></td><td>output</td><td>Output format. Default <code>json</code>.</td></tr><tr><td><code>--sync</code></td><td>mode</td><td>Run the full pipeline (dispatch → parse → reconcile → verdict) and return results. Without it, dispatch is fire-and-forget.</td></tr><tr><td><code>--dry-run</code></td><td>mode</td><td>Resolve the diff and assemble the prompt without dispatching any channel.</td></tr><tr><td><code>--session <id></code></td><td>rounds</td><td>Link this run into a multi-round session; the id must match <code>^[A-Za-z0-9_-]+$</code> and not be a reserved name <span class="fp" data-path="packages/mmr/src/commands/sessions.ts:15">packages/mmr/src/commands/sessions.ts:15</span>.</td></tr><tr><td><code>--round <n></code></td><td>rounds</td><td>1-based round counter within a session.</td></tr><tr><td><code>--max-rounds <n></code></td><td>rounds</td><td>Hard cap on rounds. Defaults to 5 when <code>--session</code> is set without it.</td></tr><tr><td><code>--accept-new-acks</code></td><td>trust</td><td>Trust acknowledgment files newly introduced by the diff.</td></tr><tr><td><code>--trust-project-acks</code></td><td>trust</td><td>Trust working-tree project acks in non-Git / untrusted modes.</td></tr><tr><td><code>--trust-project-config</code></td><td>trust</td><td>Trust working-tree <code>.mmr.yaml</code> in untrusted modes.</td></tr><tr><td><code>--config-base-ref <ref></code></td><td>trust</td><td>Load <code>.mmr.yaml</code> and acks from a trusted Git ref instead of HEAD.</td></tr></tbody></table></div>
|
|
1235
1235
|
<h3 id="copy-paste-commands-by-target">Copy-paste commands by target</h3>
|
|
1236
1236
|
<pre><code class="language-bash"># PR review (full pipeline, JSON out)
|
|
1237
1237
|
mmr review --pr 123 --sync --format json
|
|
@@ -1289,7 +1289,7 @@ mmr review --pr 123 --channels grok claude --sync --format json
|
|
|
1289
1289
|
|
|
1290
1290
|
|
|
1291
1291
|
|
|
1292
|
-
<table><thead><tr><th>Command</th><th>Purpose</th></tr></thead><tbody><tr><td><code>mmr reconcile <job-id> --channel <name> --input <data></code></td><td>Inject an external channel's findings (e.g. the Superpowers agent) into an existing job and re-run the results pipeline. Input is a file, <code>-</code> for stdin, or inline JSON
|
|
1292
|
+
<table><thead><tr><th>Command</th><th>Purpose</th></tr></thead><tbody><tr><td><code>mmr reconcile <job-id> --channel <name> --input <data></code></td><td>Inject an external channel's findings (e.g. the Superpowers agent) into an existing job and re-run the results pipeline. Input is a file, <code>-</code> for stdin, or inline JSON. <span class="fp" data-path="packages/mmr/src/commands/reconcile.ts:17">packages/mmr/src/commands/reconcile.ts:17</span></td></tr><tr><td><code>mmr status <job-id></code></td><td>Per-channel status and elapsed time. Exit 0 = all complete, 1 = running, 2 = a channel failed, 5 = not found.</td></tr><tr><td><code>mmr results <job-id> [--raw]</code></td><td>Re-run parse → reconcile → format on a completed job. Exit code reflects the verdict.</td></tr><tr><td><code>mmr jobs <list|prune></code></td><td>List jobs, or prune old ones per <code>job_retention_days</code>.</td></tr><tr><td><code>mmr sessions <start|list|show|end> <id></code></td><td>Manage multi-round review sessions (stored under <code>~/.mmr/sessions/</code>).</td></tr><tr><td><code>mmr config <init|show|validate…></code></td><td>Scaffold and inspect <code>.mmr.yaml</code> (including OSS-runtime example blocks).</td></tr><tr><td><code>mmr ack <add|list|rm|prune></code></td><td>Sticky acknowledgments — silence a finding by its stable key so it stops blocking across rounds.</td></tr></tbody></table>
|
|
1293
1293
|
<pre><code class="language-bash"># Capture a job_id from a review, then fold in an agent channel:
|
|
1294
1294
|
mmr reconcile "$JOB_ID" --channel superpowers --input findings.json
|
|
1295
1295
|
</code></pre>
|
|
@@ -1321,7 +1321,7 @@ uses <code>prompt_delivery: prompt-file</code> — the dispatcher writes the pro
|
|
|
1321
1321
|
file and passes its path via the <code>{{prompt_file}}</code> placeholder. Grok wraps its
|
|
1322
1322
|
reply in a JSON <code>.text</code> field, which the parser unwraps before extracting
|
|
1323
1323
|
findings.</p></div>
|
|
1324
|
-
<div class="tabs"><div class="tablist" role="tablist"><button class="tab-btn active" role="tab" data-tab="0">Compare</button><button class="tab-btn" role="tab" data-tab="1">codex</button><button class="tab-btn" role="tab" data-tab="2">gemini</button><button class="tab-btn" role="tab" data-tab="3">claude</button><button class="tab-btn" role="tab" data-tab="4">grok</button><button class="tab-btn" role="tab" data-tab="5">doc-conformance</button></div><div class="tabpane active" data-tab="0">
|
|
1324
|
+
<div class="tabs"><div class="tablist" role="tablist"><button class="tab-btn active" role="tab" data-tab="0">Compare</button><button class="tab-btn" role="tab" data-tab="1">codex</button><button class="tab-btn" role="tab" data-tab="2">gemini</button><button class="tab-btn" role="tab" data-tab="3">claude</button><button class="tab-btn" role="tab" data-tab="4">grok</button><button class="tab-btn" role="tab" data-tab="5">doc-conformance</button></div><div class="tabpane active" data-tab="0"><p>The defaults, commands, and parsers below are the built-in presets <span class="fp" data-path="packages/mmr/src/config/defaults.ts:32">packages/mmr/src/config/defaults.ts:32</span>.</p>
|
|
1325
1325
|
|
|
1326
1326
|
|
|
1327
1327
|
|
|
@@ -1405,7 +1405,8 @@ timeout: 240
|
|
|
1405
1405
|
to its own output file; channels run in parallel and never share output.</li>
|
|
1406
1406
|
<li><strong>Prompt delivery.</strong> <code>stdin</code> mode pipes the prompt and closes stdin (avoids
|
|
1407
1407
|
<code>E2BIG</code> on large diffs). <code>prompt-file</code> mode writes the prompt to
|
|
1408
|
-
<code><channel>.prompt.txt</code> and substitutes <code>{{prompt_file}}</code> in the flags
|
|
1408
|
+
<code><channel>.prompt.txt</code> and substitutes <code>{{prompt_file}}</code> in the flags
|
|
1409
|
+
<span class="fp" data-path="packages/mmr/src/core/dispatcher.ts:79">packages/mmr/src/core/dispatcher.ts:79</span>.</li>
|
|
1409
1410
|
<li><strong>Timeout.</strong> A per-channel timer SIGKILLs the whole process group and marks
|
|
1410
1411
|
the channel <code>timeout</code>.</li>
|
|
1411
1412
|
<li><strong>Command parsing.</strong> <code>command</code> is split on whitespace and spawned without a
|
|
@@ -1417,10 +1418,12 @@ only):</em> a new subprocess channel (<code>command</code> + <code>flags</code>
|
|
|
1417
1418
|
<code>output_parser</code>), output reshaping via the <code>unwrap-jsonpath</code> or
|
|
1418
1419
|
<code>regex-findings</code> parser kinds, disabling/timeout overrides, and pointing the
|
|
1419
1420
|
compensator at a different channel — all pure <code>.mmr.yaml</code>. <em>Needs code:</em> a
|
|
1420
|
-
brand-new <em>named</em> parser must be registered in <code>core/parser.ts</code
|
|
1421
|
-
|
|
1421
|
+
brand-new <em>named</em> parser must be registered in <code>core/parser.ts</code>
|
|
1422
|
+
<span class="cite-advisory" data-path="packages/mmr/src/core/parser.ts:257">packages/mmr/src/core/parser.ts:257</span>; and the
|
|
1422
1423
|
<code>COMPENSATING_FOCUS</code> map carries per-channel focus text (falls back gracefully
|
|
1423
|
-
if absent)
|
|
1424
|
+
if absent). HTTP-endpoint channels (<code>kind: http</code>) are already supported via
|
|
1425
|
+
<code>dispatchHttpChannel</code> — pure <code>.mmr.yaml</code>, no extra code
|
|
1426
|
+
<span class="fp" data-path="packages/mmr/src/config/schema.ts:144">packages/mmr/src/config/schema.ts:144</span>.</p>
|
|
1424
1427
|
<h2 id="scaffold-wrappers">Scaffold wrappers</h2>
|
|
1425
1428
|
<p>Direct <code>mmr review</code> runs the built-in CLI channels. The <code>scaffold run</code> wrappers
|
|
1426
1429
|
add orchestration on top.</p>
|
|
@@ -1455,6 +1458,8 @@ and Grok as foreground Bash calls when the <code>mmr</code> CLI isn't available
|
|
|
1455
1458
|
the background. Background execution produces empty output.</p></div>
|
|
1456
1459
|
<h2 id="findings-reconciliation-verdicts">Findings, reconciliation & verdicts</h2>
|
|
1457
1460
|
<h3 id="the-finding-shape">The Finding shape</h3>
|
|
1461
|
+
<p>Every channel's output parses into this common shape
|
|
1462
|
+
<span class="fp" data-path="packages/mmr/src/types.ts:45">packages/mmr/src/types.ts:45</span>.</p>
|
|
1458
1463
|
<pre><code class="language-json">{
|
|
1459
1464
|
"id": "F-001",
|
|
1460
1465
|
"category": "security",
|
|
@@ -1464,16 +1469,23 @@ the background. Background execution produces empty output.</p></div>
|
|
|
1464
1469
|
"suggestion": "…"
|
|
1465
1470
|
}
|
|
1466
1471
|
</code></pre>
|
|
1467
|
-
<p>
|
|
1468
|
-
<code>
|
|
1469
|
-
cross-round matching), and
|
|
1472
|
+
<p>The <code>location</code> above (<code>src/auth.ts:42</code>) is illustrative. After reconciliation,
|
|
1473
|
+
each finding also carries <code>confidence</code>, <code>sources[]</code>, <code>agreement</code>, a stable
|
|
1474
|
+
<code>finding_key</code>, a <code>description_shingle</code> (for fuzzy cross-round matching), and
|
|
1475
|
+
<code>acknowledged</code> <span class="fp" data-path="packages/mmr/src/types.ts:54">packages/mmr/src/types.ts:54</span>.</p>
|
|
1470
1476
|
<h3 id="stable-identity-finding-key">Stable identity (<code>finding_key</code>)</h3>
|
|
1471
1477
|
<pre><code class="language-text">finding_key = sha1( normLocation | category | sha1(normDescription) | sha1(normSuggestion) )
|
|
1472
1478
|
</code></pre>
|
|
1473
1479
|
<p>Line numbers are stripped from the location and severity is <em>excluded</em>, so the
|
|
1474
|
-
same issue at P1 vs P2 collapses to one key
|
|
1475
|
-
|
|
1480
|
+
same issue at P1 vs P2 collapses to one key
|
|
1481
|
+
<span class="fp" data-path="packages/mmr/src/core/stable-id.ts:115">packages/mmr/src/core/stable-id.ts:115</span>. A character-5-gram shingle backs
|
|
1482
|
+
a Jaccard ≥ 0.7 fuzzy match. Intra-run, findings group by fuzzy shingle overlap
|
|
1483
|
+
<span class="fp" data-path="packages/mmr/src/core/reconciler.ts:83">packages/mmr/src/core/reconciler.ts:83</span>; across rounds, the ack store reuses
|
|
1484
|
+
the same threshold so a re-worded finding still matches a prior ack
|
|
1485
|
+
<span class="fp" data-path="packages/mmr/src/core/ack-store.ts:8">packages/mmr/src/core/ack-store.ts:8</span>.</p>
|
|
1476
1486
|
<h3 id="agreement-confidence">Agreement & confidence</h3>
|
|
1487
|
+
<p>Agreement and confidence are derived per group during reconciliation
|
|
1488
|
+
<span class="fp" data-path="packages/mmr/src/core/reconciler.ts:114">packages/mmr/src/core/reconciler.ts:114</span>.</p>
|
|
1477
1489
|
|
|
1478
1490
|
|
|
1479
1491
|
|
|
@@ -1518,9 +1530,15 @@ Jaccard ≥ 0.7 fuzzy match when wording drifts between rounds.</p>
|
|
|
1518
1530
|
<table><thead><tr><th>Sources</th><th>Severity</th><th>Agreement</th><th>Confidence</th></tr></thead><tbody><tr><td>2+</td><td>same</td><td>consensus</td><td>high</td></tr><tr><td>2+</td><td>differ</td><td>majority</td><td>medium</td></tr><tr><td>1</td><td><span class="sev sev-p0">P0</span></td><td>unique</td><td>high</td></tr><tr><td>1</td><td><code>compensating-*</code></td><td>unique</td><td>low</td></tr><tr><td>1</td><td>other</td><td>unique</td><td>medium</td></tr></tbody></table>
|
|
1519
1531
|
<h3 id="the-gate-the-four-verdicts">The gate & the four verdicts</h3>
|
|
1520
1532
|
<p>The gate <strong>passes</strong> when every unacknowledged finding is <em>below</em> the
|
|
1521
|
-
<code>fix_threshold</code>
|
|
1533
|
+
<code>fix_threshold</code> <span class="fp" data-path="packages/mmr/src/core/reconciler.ts:229">packages/mmr/src/core/reconciler.ts:229</span> (default
|
|
1534
|
+
<span class="sev sev-p2">P2</span> <span class="fp" data-path="packages/mmr/src/config/defaults.ts:16">packages/mmr/src/config/defaults.ts:16</span>). Severity tiers run
|
|
1522
1535
|
<span class="sev sev-p0">P0</span> (highest) → <span class="sev sev-p1">P1</span> → <span class="sev sev-p2">P2</span> →
|
|
1523
1536
|
<span class="sev sev-p3">P3</span> (lowest).</p>
|
|
1537
|
+
<p>The verdict is derived from gate result + channel health, in this branch order:
|
|
1538
|
+
<strong>zero channels completed → <code>needs-user-decision</code></strong>; else a failed gate →
|
|
1539
|
+
<code>blocked</code>; else some channels incomplete → <code>degraded-pass</code>; else <code>pass</code>
|
|
1540
|
+
<span class="fp" data-path="packages/mmr/src/core/reconciler.ts:247">packages/mmr/src/core/reconciler.ts:247</span>. (The no-completed-channels case
|
|
1541
|
+
short-circuits first, so it outranks <code>blocked</code>.)</p>
|
|
1524
1542
|
|
|
1525
1543
|
|
|
1526
1544
|
|
|
@@ -1622,7 +1640,7 @@ channels:
|
|
|
1622
1640
|
when you pass an explicit <code>--channels</code> list).</li>
|
|
1623
1641
|
<li><code>enabled: false</code> — per-channel off switch (how <code>doc-conformance</code> ships).</li>
|
|
1624
1642
|
<li><code>extends</code> — inherit from another channel (≤ 4 levels, cycle-checked); child
|
|
1625
|
-
fields override the parent
|
|
1643
|
+
fields override the parent <span class="fp" data-path="packages/mmr/src/config/loader.ts:145">packages/mmr/src/config/loader.ts:145</span>.</li>
|
|
1626
1644
|
<li><code>fix_threshold</code> — project gate; override per-run with <code>--fix-threshold</code>.</li>
|
|
1627
1645
|
</ul>
|
|
1628
1646
|
<div class="callout callout-danger"><p><strong>Trust boundary.</strong> When reviewing a diff, project <code>.mmr.yaml</code> and acks should
|
|
@@ -18,12 +18,12 @@ disagreement is what surfaces ambiguity.
|
|
|
18
18
|
|
|
19
19
|
1. **Resolve a diff** — from a PR, staged changes, a branch range, or a piped diff.
|
|
20
20
|
2. **Dispatch channels** — each channel is a separate subprocess given the same
|
|
21
|
-
prompt, run in parallel and isolated.
|
|
21
|
+
prompt, run in parallel and isolated :cite[packages/mmr/src/commands/review.ts:636].
|
|
22
22
|
3. **Parse** — each channel's raw output is parsed into a common `Finding` shape.
|
|
23
23
|
4. **Reconcile** — findings are grouped by a stable key, de-duplicated, and
|
|
24
|
-
scored for agreement and confidence.
|
|
24
|
+
scored for agreement and confidence :cite[packages/mmr/src/core/reconciler.ts:43].
|
|
25
25
|
5. **Verdict** — a severity gate yields `pass`, `degraded-pass`, `blocked`, or
|
|
26
|
-
`needs-user-decision
|
|
26
|
+
`needs-user-decision` :cite[packages/mmr/src/types.ts:25].
|
|
27
27
|
|
|
28
28
|
:::callout{type=tip}
|
|
29
29
|
**Two layers, one mental model.** The `mmr` CLI is the engine that dispatches
|
|
@@ -87,7 +87,7 @@ table.
|
|
|
87
87
|
| `--format <json\|text\|markdown>` | output | Output format. Default `json`. |
|
|
88
88
|
| `--sync` | mode | Run the full pipeline (dispatch → parse → reconcile → verdict) and return results. Without it, dispatch is fire-and-forget. |
|
|
89
89
|
| `--dry-run` | mode | Resolve the diff and assemble the prompt without dispatching any channel. |
|
|
90
|
-
| `--session <id>` | rounds | Link this run into a multi-round session
|
|
90
|
+
| `--session <id>` | rounds | Link this run into a multi-round session; the id must match `^[A-Za-z0-9_-]+$` and not be a reserved name :cite[packages/mmr/src/commands/sessions.ts:15]. |
|
|
91
91
|
| `--round <n>` | rounds | 1-based round counter within a session. |
|
|
92
92
|
| `--max-rounds <n>` | rounds | Hard cap on rounds. Defaults to 5 when `--session` is set without it. |
|
|
93
93
|
| `--accept-new-acks` | trust | Trust acknowledgment files newly introduced by the diff. |
|
|
@@ -122,7 +122,7 @@ mmr review --pr 123 --channels grok claude --sync --format json
|
|
|
122
122
|
|
|
123
123
|
| Command | Purpose |
|
|
124
124
|
| --- | --- |
|
|
125
|
-
| `mmr reconcile <job-id> --channel <name> --input <data>` | Inject an external channel's findings (e.g. the Superpowers agent) into an existing job and re-run the results pipeline. Input is a file, `-` for stdin, or inline JSON. |
|
|
125
|
+
| `mmr reconcile <job-id> --channel <name> --input <data>` | Inject an external channel's findings (e.g. the Superpowers agent) into an existing job and re-run the results pipeline. Input is a file, `-` for stdin, or inline JSON. :cite[packages/mmr/src/commands/reconcile.ts:17] |
|
|
126
126
|
| `mmr status <job-id>` | Per-channel status and elapsed time. Exit 0 = all complete, 1 = running, 2 = a channel failed, 5 = not found. |
|
|
127
127
|
| `mmr results <job-id> [--raw]` | Re-run parse → reconcile → format on a completed job. Exit code reflects the verdict. |
|
|
128
128
|
| `mmr jobs <list\|prune>` | List jobs, or prune old ones per `job_retention_days`. |
|
|
@@ -175,6 +175,8 @@ findings.
|
|
|
175
175
|
::::tabs
|
|
176
176
|
|
|
177
177
|
:::tab{title="Compare"}
|
|
178
|
+
The defaults, commands, and parsers below are the built-in presets :cite[packages/mmr/src/config/defaults.ts:32].
|
|
179
|
+
|
|
178
180
|
| Channel | Default | Strength | Prompt delivery | Parser |
|
|
179
181
|
| --- | --- | --- | --- | --- |
|
|
180
182
|
| `codex` | enabled | Correctness, security, API contracts | stdin | `default` |
|
|
@@ -251,7 +253,8 @@ Enable with `--channels doc-conformance` or in `.mmr.yaml`.
|
|
|
251
253
|
to its own output file; channels run in parallel and never share output.
|
|
252
254
|
- **Prompt delivery.** `stdin` mode pipes the prompt and closes stdin (avoids
|
|
253
255
|
`E2BIG` on large diffs). `prompt-file` mode writes the prompt to
|
|
254
|
-
`<channel>.prompt.txt` and substitutes `{{prompt_file}}` in the flags
|
|
256
|
+
`<channel>.prompt.txt` and substitutes `{{prompt_file}}` in the flags
|
|
257
|
+
:cite[packages/mmr/src/core/dispatcher.ts:79].
|
|
255
258
|
- **Timeout.** A per-channel timer SIGKILLs the whole process group and marks
|
|
256
259
|
the channel `timeout`.
|
|
257
260
|
- **Command parsing.** `command` is split on whitespace and spawned without a
|
|
@@ -263,10 +266,12 @@ only):* a new subprocess channel (`command` + `flags` + `auth` +
|
|
|
263
266
|
`output_parser`), output reshaping via the `unwrap-jsonpath` or
|
|
264
267
|
`regex-findings` parser kinds, disabling/timeout overrides, and pointing the
|
|
265
268
|
compensator at a different channel — all pure `.mmr.yaml`. *Needs code:* a
|
|
266
|
-
brand-new *named* parser must be registered in `core/parser.ts
|
|
267
|
-
|
|
269
|
+
brand-new *named* parser must be registered in `core/parser.ts`
|
|
270
|
+
:cite[packages/mmr/src/core/parser.ts:257]{mode=advisory}; and the
|
|
268
271
|
`COMPENSATING_FOCUS` map carries per-channel focus text (falls back gracefully
|
|
269
|
-
if absent).
|
|
272
|
+
if absent). HTTP-endpoint channels (`kind: http`) are already supported via
|
|
273
|
+
`dispatchHttpChannel` — pure `.mmr.yaml`, no extra code
|
|
274
|
+
:cite[packages/mmr/src/config/schema.ts:144].
|
|
270
275
|
|
|
271
276
|
## Scaffold wrappers
|
|
272
277
|
|
|
@@ -289,6 +294,9 @@ the background. Background execution produces empty output.
|
|
|
289
294
|
|
|
290
295
|
### The Finding shape
|
|
291
296
|
|
|
297
|
+
Every channel's output parses into this common shape
|
|
298
|
+
:cite[packages/mmr/src/types.ts:45].
|
|
299
|
+
|
|
292
300
|
```json
|
|
293
301
|
{
|
|
294
302
|
"id": "F-001",
|
|
@@ -300,9 +308,10 @@ the background. Background execution produces empty output.
|
|
|
300
308
|
}
|
|
301
309
|
```
|
|
302
310
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
cross-round matching), and
|
|
311
|
+
The `location` above (`src/auth.ts:42`) is illustrative. After reconciliation,
|
|
312
|
+
each finding also carries `confidence`, `sources[]`, `agreement`, a stable
|
|
313
|
+
`finding_key`, a `description_shingle` (for fuzzy cross-round matching), and
|
|
314
|
+
`acknowledged` :cite[packages/mmr/src/types.ts:54].
|
|
306
315
|
|
|
307
316
|
### Stable identity (`finding_key`)
|
|
308
317
|
|
|
@@ -311,11 +320,18 @@ finding_key = sha1( normLocation | category | sha1(normDescription) | sha1(normS
|
|
|
311
320
|
```
|
|
312
321
|
|
|
313
322
|
Line numbers are stripped from the location and severity is *excluded*, so the
|
|
314
|
-
same issue at P1 vs P2 collapses to one key
|
|
315
|
-
|
|
323
|
+
same issue at P1 vs P2 collapses to one key
|
|
324
|
+
:cite[packages/mmr/src/core/stable-id.ts:115]. A character-5-gram shingle backs
|
|
325
|
+
a Jaccard ≥ 0.7 fuzzy match. Intra-run, findings group by fuzzy shingle overlap
|
|
326
|
+
:cite[packages/mmr/src/core/reconciler.ts:83]; across rounds, the ack store reuses
|
|
327
|
+
the same threshold so a re-worded finding still matches a prior ack
|
|
328
|
+
:cite[packages/mmr/src/core/ack-store.ts:8].
|
|
316
329
|
|
|
317
330
|
### Agreement & confidence
|
|
318
331
|
|
|
332
|
+
Agreement and confidence are derived per group during reconciliation
|
|
333
|
+
:cite[packages/mmr/src/core/reconciler.ts:114].
|
|
334
|
+
|
|
319
335
|
| Sources | Severity | Agreement | Confidence |
|
|
320
336
|
| --- | --- | --- | --- |
|
|
321
337
|
| 2+ | same | consensus | high |
|
|
@@ -327,10 +343,17 @@ Jaccard ≥ 0.7 fuzzy match when wording drifts between rounds.
|
|
|
327
343
|
### The gate & the four verdicts
|
|
328
344
|
|
|
329
345
|
The gate **passes** when every unacknowledged finding is *below* the
|
|
330
|
-
`fix_threshold`
|
|
346
|
+
`fix_threshold` :cite[packages/mmr/src/core/reconciler.ts:229] (default
|
|
347
|
+
:sev[P2]{level=p2} :cite[packages/mmr/src/config/defaults.ts:16]). Severity tiers run
|
|
331
348
|
:sev[P0]{level=p0} (highest) → :sev[P1]{level=p1} → :sev[P2]{level=p2} →
|
|
332
349
|
:sev[P3]{level=p3} (lowest).
|
|
333
350
|
|
|
351
|
+
The verdict is derived from gate result + channel health, in this branch order:
|
|
352
|
+
**zero channels completed → `needs-user-decision`**; else a failed gate →
|
|
353
|
+
`blocked`; else some channels incomplete → `degraded-pass`; else `pass`
|
|
354
|
+
:cite[packages/mmr/src/core/reconciler.ts:247]. (The no-completed-channels case
|
|
355
|
+
short-circuits first, so it outranks `blocked`.)
|
|
356
|
+
|
|
334
357
|
| Verdict | Condition | Exit |
|
|
335
358
|
| --- | --- | --- |
|
|
336
359
|
| `pass` | Gate passed, all channels completed | 0 |
|
|
@@ -391,7 +414,7 @@ channels:
|
|
|
391
414
|
when you pass an explicit `--channels` list).
|
|
392
415
|
- `enabled: false` — per-channel off switch (how `doc-conformance` ships).
|
|
393
416
|
- `extends` — inherit from another channel (≤ 4 levels, cycle-checked); child
|
|
394
|
-
fields override the parent.
|
|
417
|
+
fields override the parent :cite[packages/mmr/src/config/loader.ts:145].
|
|
395
418
|
- `fix_threshold` — project gate; override per-run with `--fix-threshold`.
|
|
396
419
|
|
|
397
420
|
:::callout{type=danger}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" style="max-width: 1139.59px; background-color: transparent;" viewBox="0 0 1139.589111328125 987.3843994140625" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#666;stroke:#666;}#my-svg .marker.cross{stroke:#666;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#my-svg .cluster-label text{fill:#333;}#my-svg .cluster-label span{color:#333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#000000;color:#000000;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#eee;stroke:#999;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#666!important;stroke-width:0;stroke:#666;}#my-svg .arrowheadPath{fill:#333333;}#my-svg .edgePath .path{stroke:#666;stroke-width:1px;}#my-svg .flowchart-link{stroke:#666;fill:none;}#my-svg .edgeLabel{background-color:white;text-align:center;}#my-svg .edgeLabel p{background-color:white;}#my-svg .edgeLabel rect{opacity:0.5;background-color:white;fill:white;}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:hsl(0, 0%, 98.9215686275%);stroke:#707070;stroke-width:1px;}#my-svg .cluster text{fill:#333;}#my-svg .cluster span{color:#333;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(-160, 0%, 93.3333333333%);border:1px solid #707070;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:white;text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:white;padding:2px;}#my-svg .icon-shape .label rect,#my-svg .image-shape .label rect{opacity:0.5;background-color:white;fill:white;}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg .node .neo-node{stroke:#999;}#my-svg [data-look="neo"].node rect,#my-svg [data-look="neo"].cluster rect,#my-svg [data-look="neo"].node polygon{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].node path{stroke:url(#my-svg-gradient);stroke-width:1px;}#my-svg [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].node .neo-line path{stroke:#999;filter:none;}#my-svg [data-look="neo"].node circle{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].node circle .state-start{fill:#000000;}#my-svg [data-look="neo"].icon-shape .icon{fill:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg [data-look="neo"].icon-shape .icon-neo path{stroke:url(#my-svg-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointEnd-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="11.5" refY="7" markerUnits="userSpaceOnUse" markerWidth="10.5" markerHeight="14" orient="auto"><path d="M 0 0 L 11.5 7 L 0 14 z" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart-margin" class="marker flowchart-v2" viewBox="0 0 11.5 14" refX="1" refY="7" markerUnits="userSpaceOnUse" markerWidth="11.5" markerHeight="14" orient="auto"><polygon points="0,7 11.5,14 11.5,0" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refY="5" refX="12.25" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart-margin" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-2" refY="5" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="14" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 0; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="17.7" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5;"/></marker><marker id="my-svg_flowchart-v2-crossStart-margin" class="marker cross flowchart-v2" viewBox="0 0 15 15" refX="-3.5" refY="7.5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto"><path d="M 1,1 L 14,14 M 1,14 L 14,1" class="arrowMarkerPath" style="stroke-width: 2.5; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"/><g class="edgePaths"><path d="M378.359,57L378.359,61.167C378.359,65.333,378.359,73.667,378.359,81.333C378.359,89,378.359,96,378.359,99.5L378.359,103" id="my-svg-L_Start_InPlan_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Start_InPlan_0" data-points="W3sieCI6Mzc4LjM1OTM3NSwieSI6NTd9LHsieCI6Mzc4LjM1OTM3NSwieSI6ODJ9LHsieCI6Mzc4LjM1OTM3NSwieSI6MTA2Ljk5OTk5OTk5OTk5OTk3fV0=" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M306.247,256.909L272.687,275.011C239.128,293.113,172.009,329.318,138.45,364.067C104.891,398.816,104.891,432.11,104.891,448.758L104.891,465.405" id="my-svg-L_InPlan_Quick_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_InPlan_Quick_0" data-points="W3sieCI6MzA2LjI0NjU3NzU2NDk4NjcsInkiOjI1Ni45MDkwODM2Njg1MDIzfSx7IngiOjEwNC44OTA2MjUsInkiOjM2NS41MjE4ODExMDM1MTU2fSx7IngiOjEwNC44OTA2MjUsInkiOjQ2OS40MDQ2OTc0MTgyMTI5fV0=" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M378.359,329.022L378.359,335.105C378.359,341.189,378.359,353.355,378.359,376.086C378.359,398.816,378.359,432.11,378.359,448.758L378.359,465.405" id="my-svg-L_InPlan_Enh_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_InPlan_Enh_0" data-points="W3sieCI6Mzc4LjM1OTM3NSwieSI6MzI5LjAyMTg4MTEwMzUxNTZ9LHsieCI6Mzc4LjM1OTM3NSwieSI6MzY1LjUyMTg4MTEwMzUxNTZ9LHsieCI6Mzc4LjM1OTM3NSwieSI6NDY5LjQwNDY5NzQxODIxMjl9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M451.002,256.38L485.441,274.57C519.88,292.76,588.758,329.141,623.197,352.748C657.636,376.355,657.636,387.189,657.636,392.605L657.636,398.022" id="my-svg-L_InPlan_HowMany_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_InPlan_HowMany_0" data-points="W3sieCI6NDUxLjAwMTUwNjY3NTgxNzQsInkiOjI1Ni4zNzk3NDk0Mjc2OTgyNH0seyJ4Ijo2NTcuNjM1OTQwNTUxNzU3OCwieSI6MzY1LjUyMTg4MTEwMzUxNTZ9LHsieCI6NjU3LjYzNTk0MDU1MTc1NzgsInkiOjQwMi4wMjE4ODExMDM1MTU1N31d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M592.634,538.385L561.814,555.302C530.995,572.219,469.357,606.053,438.537,628.387C407.718,650.721,407.718,661.554,407.718,666.971L407.718,672.388" id="my-svg-L_HowMany_Single_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_HowMany_Single_0" data-points="W3sieCI6NTkyLjYzMzYzMTY2Njk3MDcsInkiOjUzOC4zODUyMDMzMjIyNDQxfSx7IngiOjQwNy43MTc5NzE4MDE3NTc4LCJ5Ijo2MzkuODg3NTEyMjA3MDMxMn0seyJ4Ijo0MDcuNzE3OTcxODAxNzU3OCwieSI6Njc2LjM4NzUxMjIwNzAzMTJ9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M722.51,538.513L753.12,555.409C783.729,572.305,844.948,606.096,875.558,628.409C906.167,650.721,906.167,661.554,906.167,666.971L906.167,672.388" id="my-svg-L_HowMany_Multi_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_HowMany_Multi_0" data-points="W3sieCI6NzIyLjUwOTk3MDkyMTM4NjgsInkiOjUzOC41MTM0ODE4Mzc0MDIyfSx7IngiOjkwNi4xNjcxOTA1NTE3NTc4LCJ5Ijo2MzkuODg3NTEyMjA3MDMxMn0seyJ4Ijo5MDYuMTY3MTkwNTUxNzU3OCwieSI6Njc2LjM4NzUxMjIwNzAzMTF9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M366.035,798.102L352.462,811.132C338.889,824.163,311.743,850.224,298.17,870.137C284.597,890.051,284.597,903.818,284.597,910.701L284.597,917.584" id="my-svg-L_Single_SS_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Single_SS_0" data-points="W3sieCI6MzY2LjAzNTQ3MjM0MTAwNjU0LCJ5Ijo3OTguMTAxODkzODQ5Nzk1Nn0seyJ4IjoyODQuNTk2ODc4MDUxNzU3OCwieSI6ODc2LjI4NDM5MzMxMDU0Njl9LHsieCI6Mjg0LjU5Njg3ODA1MTc1NzgsInkiOjkyMS41ODQzOTI1NDc2MDc0fV0=" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M449.4,798.102L462.974,811.132C476.547,824.163,503.693,850.224,517.266,870.137C530.839,890.051,530.839,903.818,530.839,910.701L530.839,917.584" id="my-svg-L_Single_SR_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Single_SR_0" data-points="W3sieCI6NDQ5LjQwMDQ3MTI2MjUwOTIsInkiOjc5OC4xMDE4OTM4NDk3OTU2fSx7IngiOjUzMC44MzkwNjU1NTE3NTc4LCJ5Ijo4NzYuMjg0MzkzMzEwNTQ2OX0seyJ4Ijo1MzAuODM5MDY1NTUxNzU3OCwieSI6OTIxLjU4NDM5MjU0NzYwNzR9XQ==" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M864.256,797.873L850.49,810.942C836.724,824.01,809.192,850.147,795.425,868.633C781.659,887.118,781.659,897.951,781.659,903.368L781.659,908.784" id="my-svg-L_Multi_MS_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Multi_MS_0" data-points="W3sieCI6ODY0LjI1NjA1NzI3OTA5NTgsInkiOjc5Ny44NzMyNjAwMzc4ODV9LHsieCI6NzgxLjY1OTM3ODA1MTc1NzgsInkiOjg3Ni4yODQzOTMzMTA1NDY5fSx7IngiOjc4MS42NTkzNzgwNTE3NTc4LCJ5Ijo5MTIuNzg0MzkzMzEwNTQ2OX1d" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M948.078,797.873L961.844,810.942C975.611,824.01,1003.143,850.147,1016.909,868.633C1030.675,887.118,1030.675,897.951,1030.675,903.368L1030.675,908.784" id="my-svg-L_Multi_MR_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_Multi_MR_0" data-points="W3sieCI6OTQ4LjA3ODMyMzgyNDQxOTYsInkiOjc5Ny44NzMyNjAwMzc4ODV9LHsieCI6MTAzMC42NzUwMDMwNTE3NTc4LCJ5Ijo4NzYuMjg0MzkzMzEwNTQ2OX0seyJ4IjoxMDMwLjY3NTAwMzA1MTc1NzgsInkiOjkxMi43ODQzOTMzMTA1NDY5fV0=" data-look="classic" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel"><g class="label" data-id="L_Start_InPlan_0" transform="translate(0, 0)"><text y="-10.1" text-anchor="middle"><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"/></text></g></g><g><rect class="background" style="stroke: none"/></g><g class="edgeLabel" transform="translate(104.890625, 365.5218811035156)"><g class="label" data-id="L_InPlan_Quick_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-96.890625" y="-1" width="193.78125" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">No</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> —</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> one-off</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> bug/refactor</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(378.359375, 365.5218811035156)"><g class="label" data-id="L_InPlan_Enh_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-96.109375" y="-1" width="192.21875" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">No</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> —</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> a</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> whole</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> new</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> feature</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(657.6359405517578, 365.5218811035156)"><g class="label" data-id="L_InPlan_HowMany_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-72.90625" y="-1" width="145.8125" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Yes</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> —</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> planned</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> tasks</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(407.7179718017578, 639.8875122070312)"><g class="label" data-id="L_HowMany_Single_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-38.6640625" y="-1" width="77.328125" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">One</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> agent</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(906.1671905517578, 639.8875122070312)"><g class="label" data-id="L_HowMany_Multi_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-53.9375" y="-1" width="107.875" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Several</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> agents</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(284.5968780517578, 876.2843933105469)"><g class="label" data-id="L_Single_SS_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-21.28125" y="-1" width="42.5625" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Fresh</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(530.8390655517578, 876.2843933105469)"><g class="label" data-id="L_Single_SR_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-35.6171875" y="-1" width="71.234375" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Resuming</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(781.6593780517578, 876.2843933105469)"><g class="label" data-id="L_Multi_MS_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-21.28125" y="-1" width="42.5625" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Fresh</tspan></tspan></text></g></g></g><g class="edgeLabel" transform="translate(1030.6750030517578, 876.2843933105469)"><g class="label" data-id="L_Multi_MR_0" transform="translate(0, -10.5)"><g><rect class="background" style="" x="-35.6171875" y="-1" width="71.234375" height="23"/><text y="-10.1" text-anchor="middle" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em" text-anchor="middle"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Resuming</tspan></tspan></text></g></g></g></g><g class="nodes"><g class="node default" id="my-svg-flowchart-Start-0" data-look="classic" transform="translate(378.359375, 32.5)"><rect class="basic label-container" style="" x="-112.4140625" y="-24.5" width="224.828125" height="49"/><g class="label" style="" transform="translate(0, -9.5)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Build-phase</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> work</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> to</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> do</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-InPlan-1" data-look="classic" transform="translate(378.359375, 218.0109405517578)"><polygon points="111.01093673706055,0 222.0218734741211,-111.01093673706055 111.01093673706055,-222.0218734741211 0,-111.01093673706055" class="label-container" transform="translate(-110.51093673706055, 111.01093673706055)"/><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Already</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> in</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> the</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">implementation</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> plan?</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-Quick-3" data-look="classic" transform="translate(104.890625, 502.70469665527344)"><rect class="basic label-container" style="" x="-94.875" y="-33.29999923706055" width="189.75" height="66.5999984741211"/><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">quick-task</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">single</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> scoped</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> task</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-Enh-5" data-look="classic" transform="translate(378.359375, 502.70469665527344)"><rect class="basic label-container" style="" x="-128.59375" y="-33.29999923706055" width="257.1875" height="66.5999984741211"/><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">new-enhancement</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">update</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> PRD</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> +</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> stories</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> +</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> plan</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-HowMany-7" data-look="classic" transform="translate(657.6359405517578, 502.70469665527344)"><polygon points="100.68281173706055,0 201.3656234741211,-100.68281173706055 100.68281173706055,-201.3656234741211 0,-100.68281173706055" class="label-container" transform="translate(-100.18281173706055, 100.68281173706055)"/><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">One</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> agent</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> or</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">several</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> in</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> parallel?</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-Single-9" data-look="classic" transform="translate(407.7179718017578, 758.0859527587891)"><polygon points="81.69843673706055,0 163.3968734741211,-81.69843673706055 81.69843673706055,-163.3968734741211 0,-81.69843673706055" class="label-container" transform="translate(-81.19843673706055, 81.69843673706055)"/><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Fresh</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> start</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> or</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">resuming?</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-Multi-11" data-look="classic" transform="translate(906.1671905517578, 758.0859527587891)"><polygon points="81.69843673706055,0 163.3968734741211,-81.69843673706055 81.69843673706055,-163.3968734741211 0,-81.69843673706055" class="label-container" transform="translate(-81.19843673706055, 81.69843673706055)"/><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">Fresh</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> start</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> or</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">resuming?</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-SS-13" data-look="classic" transform="translate(284.5968780517578, 946.0843925476074)"><rect class="basic label-container" style="" x="-93.5234375" y="-24.5" width="187.046875" height="49"/><g class="label" style="" transform="translate(0, -9.5)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">single-agent-start</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-SR-15" data-look="classic" transform="translate(530.8390655517578, 946.0843925476074)"><rect class="basic label-container" style="" x="-102.71875" y="-24.5" width="205.4375" height="49"/><g class="label" style="" transform="translate(0, -9.5)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">single-agent-resume</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-MS-17" data-look="classic" transform="translate(781.6593780517578, 946.0843925476074)"><rect class="basic label-container" style="" x="-98.1015625" y="-33.29999923706055" width="196.203125" height="66.5999984741211"/><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">multi-agent-start</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">(needs</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> a</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> worktree)</tspan></tspan></text></g></g></g><g class="node default" id="my-svg-flowchart-MR-19" data-look="classic" transform="translate(1030.6750030517578, 946.0843925476074)"><rect class="basic label-container" style="" x="-100.9140625" y="-33.29999923706055" width="201.828125" height="66.5999984741211"/><g class="label" style="" transform="translate(0, -18.299999237060547)"><rect/><g><rect class="background" style="stroke: none"/><text y="-10.1" style=""><tspan class="text-outer-tspan row" x="0" y="-0.1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">multi-agent-resume</tspan></tspan><tspan class="text-outer-tspan row" x="0" y="1em" dy="1.1em"><tspan font-style="normal" class="text-inner-tspan" font-weight="normal">(in</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> the</tspan><tspan font-style="normal" class="text-inner-tspan" font-weight="normal"> worktree)</tspan></tspan></text></g></g></g></g></g></g><defs><filter id="my-svg-drop-shadow" height="130%" width="130%"><feDropShadow dx="4" dy="4" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><defs><filter id="my-svg-drop-shadow-small" height="150%" width="150%"><feDropShadow dx="2" dy="2" stdDeviation="0" flood-opacity="0.06" flood-color="#000000"/></filter></defs><linearGradient id="my-svg-gradient" gradientUnits="objectBoundingBox" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="hsl(0, 0%, 83.3333333333%)" stop-opacity="1"/><stop offset="100%" stop-color="hsl(0, 0%, 88.9215686275%)" stop-opacity="1"/></linearGradient></svg>
|