Add six-pattern toolbox to s16 with composition walkthrough

Introduce Classify-And-Act through Loop Until Done after primitives,
map each onto agent/parallel/pipeline, show review-changes as a
fanout+verify composition, and add a matching six-panel SVG.

Co-authored-by: Xinlu Lai <CrazyBoyM@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-08-12 13:52:20 +00:00
parent 9d2f43cfe6
commit 06fef3be44
5 changed files with 423 additions and 30 deletions

View File

@@ -88,17 +88,38 @@ results = await ctx.pipeline(DIMENSIONS, audit, verify)
confirmed = [f for r in results if r for f in r["confirmed"]] confirmed = [f for r in results if r for f in r["confirmed"]]
``` ```
## パターンは、元が取れるときだけ ## レシピが書けるようになったら
カタログを暗記する必要はありません。サンプルが何をしているかに気づけば、手元に三つのスタイルがあります。 上の動詞は小麦粉と火加減です。人が何度も発明し直すのは、少数の*形*——dynamic agentic workflow のよくあるパターンです。道具箱だと思ってください。必点メニューではありません。痛みが出たときに手を伸ばし、残りは壁に掛けておきます。
変更を review の各 dimension へ**広げ**、きれいな机で進め、一つの確認リストへ**まとめ**ます。fan-out-and-synthesize です。かけらが一つの騒がしい context で混線するときに効きます。 ![Six Workflow Patterns](images/six-workflow-patterns.svg)
verify の内側では、第二の助手が各 finding をあえて疑います。adversarial verification——自分の宿題に甘くならないための、構造からの答えです。 *人が何度も発明する六つの形。トポロジーは script が持ち、このレッスンでは `agent` / `parallel` / `pipeline` / `phase` / journal で各形を話します。*
残るのは、生成したものへのフィルタです。Generate-and-filter。候補が入り、通ったものだけが出ます。 **Classify-And-Act。** 痛み: 万能の助手は何でもそこそこ。形: classifier がタスクを見て、専門家 A / B / C へ振り分ける。このレッスンでは、だいたい `agent({schema})` がラベルを返し、script の `if`/`match` が続く `agent`(または入れ子の `workflow`)を呼びます。全部が本当に同じ扱いでよいなら、使わない——振り分けは儀式になります。
同じ道具箱には classify-and-act、tournament、loop-until-done もあり、あとで出会います。余分なコストが、安くは手に入らない明瞭さや安全を買うときだけ、スタイルを借りてください。 **Fanout-And-Synthesize。** 痛み: 五十ファイルは一つの疲れた context に入らず、押し込めば混線する。形: 仕事を分け、多くの agent を走らせ、barrier で待ち、まとめる。各 item に自分の stage があるなら `pipeline`、次が全結果を要すなら `parallel`。まとめは gather のあとのふつうの Python。関連ファイルが三つか五つで一通しで足りるなら、使わない。
**Adversarial Verification。** 痛み: 狐が鶏小屋を採点する。形: worker が出す。独立した verifier が反証や負荷をかける。生き残ったものだけ残る。写し方は、生産の `agent`、それから verifier `agent``parallel`(できれば schema 付き)、そのあと filter。`phase` で “Review” と “Verify” を分ける。間違えても安いなら使わない——すべてのメモに法廷は要らない。
**Generate-And-Filter。** 痛み: 欲しいのは選択肢であり、最初に賢く聞こえた案ではない。形: 多くの generator がアイデアを rubric + dedupe の filter に流し、best を残して残りを捨てる。写し方は generator の `parallel`、そのあと script 側の filterまたは schema 付きの審判 `agent`)。生成が高いとき journal / resume が効く。良い答えの空間がもともと狭いなら使わない。
**Tournament。** 痛み: 味や順位では絶対スコアがぼやける(「この名前はどれくらい良い?」)。形: ペアごとの審判、トーナメント表、勝者——比較判断は孤独な採点に勝る。写し方は、script 内で pairwise 審判 `agent``parallel` を回し、一つ残るまで続ける。鋭い rubric が一通しで勝者を決めるなら使わない。
**Loop Until Done。** 痛み: 坑道にまだ何巡あるか分からない。形: 「新しい発見?」が yes のあいだ spawn し続け、空振りや完了条件で止まる。写し方は `while``agent`/`parallel` を包み、schema 付きの停止チェックと硬い `budget` を置く。長い掘りが止まるなら journal resume と組む。仕事量が分かっているなら、固定の `pipeline` の方が単純で安全。
いくつか顔が付いたあと、道具箱は一目で収まります。
| パターン | プリミティブの素描 | 手を伸ばすとき |
|----------|--------------------|----------------|
| Classify-And-Act | `agent` → 分岐 → `agent` | 項目ごとに違う専門家が要る |
| Fanout-And-Synthesize | `pipeline` / `parallel` → 統合 | きれいな机がたくさん、そのあと一つの要約 |
| Adversarial Verification | 生産 → `parallel(verify)` → filter | 間違えると高い |
| Generate-And-Filter | `parallel(gens)` → rubric filter | まず選択肢、それから味 |
| Tournament | pairwise 審判 `agent` の bracket | 順位/味に鋭い物差しがない |
| Loop Until Done | `while` + 停止チェック + `budget` | どれだけ埋まっているか不明 |
組み合わせはふつうです。深い調査はしばしば fanout → filter → verify → synthesize と重ねます。私たちのサンプルは、すでに二つの音の小さな和音です。
## 次の段が受け取れる答え ## 次の段が受け取れる答え
@@ -141,18 +162,22 @@ journal: [A ✓] [B ✓] [C ✓] [D ✓]
resume: A hit → B hit → C 変更 → D は live resume: A hit → B hit → C 変更 → D は live
``` ```
## `review-changes` を歩く ## `review-changes` を歩く — ひとつの composition
四つの dimension が同じ二段の道を共有します——広げ、敵対的に確かめ、残ったものを残す。 サンプルは「一つのパターン」ではありません。**Fanout-And-Synthesize** の中に **Adversarial Verification** が入り、終わりで軽く generate-and-filter がかかる——`isReal` の finding だけが残ります。
```text ```text
correctness ── audit ── verify ──┐ correctness ── audit ── verify ──┐
security ── audit ── verify ──┤── 確認済みの finding security ── audit ── verify ──┤── 確認済みの finding
performance ── audit ── verify ──┤ performance ── audit ── verify ──┤
style ── audit ── verify ──┘ style ── audit ── verify ──┘
fanout synthesize
└── 各 finding: 懐疑的 verify ──┘
``` ```
Review は各 auditor を自分の机に置き、correctness の雑談が security へ流れ込まないようにします。Verify は各 finding を、著者ではない懐疑者へ渡します。本物だけが残り、severity で並びます。三つの癖が、お気に入りの席を失う感触が、そこにあります `pipeline(DIMENSIONS, audit, verify)` が各 dimension に机を渡し、correctness の雑談が security へ流れないようにします。`verify` 内の verifier agent の `parallel` が敵対の和音です。ふつうのリスト filter が synthesize。`phase` が Review と Verify を印し、journal が各 `agent()` を覚えるので、止まっても audit をやり直さない
三つの癖がお気に入りの席を失う感触があります。艦隊は二つの dimension で止められず、著者は審判ではなく、トポロジーは途中で漂いません。
```python ```python
async def sample_workflow(ctx, args): async def sample_workflow(ctx, args):
@@ -205,4 +230,4 @@ Review が Verify に道を譲るのを見てください。完全な resume で
s16 はバッチの回し方です。[s17 Goal Loop](../s17_goal_loop/) は戸口で別の問いをします。止めるべきか、もう一ターンか。繰り返せるレシピに硬い「完了」も要るときは、そちらと組んでください。 s16 はバッチの回し方です。[s17 Goal Loop](../s17_goal_loop/) は戸口で別の問いをします。止めるべきか、もう一ターンか。繰り返せるレシピに硬い「完了」も要るときは、そちらと組んでください。
<!-- translation-sync: zh@v13, en@v13, ja@v13 --> <!-- translation-sync: zh@v14, en@v14, ja@v14 -->

View File

@@ -88,17 +88,38 @@ results = await ctx.pipeline(DIMENSIONS, audit, verify)
confirmed = [f for r in results if r for f in r["confirmed"]] confirmed = [f for r in results if r for f in r["confirmed"]]
``` ```
## Patterns, when they earn their keep ## Once you can write the recipe
You do not need a catalog. Notice what our sample already does, and you have three styles in hand. The verbs above are flour and heat. What people keep reinventing are a handful of *shapes* — common patterns for dynamic agentic workflows. Think of them as a toolbox, not a mandatory menu. Reach for one when its pain shows up; leave the rest on the pegboard.
It **fans out** the change across review dimensions, each on a clean desk, then **synthesizes** one confirmed list. That is fan-out-and-synthesize — useful when pieces would contaminate each other in one crowded context. ![Six Workflow Patterns](images/six-workflow-patterns.svg)
Inside verify, a second helper tries to knock each finding down. That is adversarial verification — the structural answer to grading your own homework. *Six shapes people keep reinventing. The script owns the topology; `agent` / `parallel` / `pipeline` / `phase` / journal are how each shape is spoken in this lesson.*
What survives is a filter over what was generated. Generate-and-filter: candidates in, only the ones that pass out. **Classify-And-Act.** Pain: one generic helper is mediocre at everything. Shape: a classifier looks at the task, then routes to specialist A, B, or C. In this lesson that is usually one `agent({schema})` that returns a label, then an `if`/`match` in the script that calls the right follow-up `agent` (or a nested `workflow`). Skip it when every item truly needs the same treatment — routing is just ceremony then.
The same toolbox holds other cuts you will meet later — classify-and-act, tournament, loop-until-done. Borrow a style only when the extra cost buys clarity or safety you could not get cheaper. **Fanout-And-Synthesize.** Pain: fifty files will not fit one tired context, and they contaminate each other if they try. Shape: split the work, run many agents, wait at a barrier, merge. Map it with `pipeline` when each item has its own stages, or `parallel` when the next step needs every result together; put the merge in ordinary Python after the gather. Skip it for three related files a single pass can hold.
**Adversarial Verification.** Pain: the fox grades the henhouse. Shape: a worker produces; independent verifiers try to refute or stress-test; only survivors remain. Map it with a produce `agent`, then `parallel` of verifier `agent`s (ideally `schema`d), then a filter. Phases help (“Review” then “Verify”). Skip it when the cost of a wrong answer is low — not every note needs a tribunal.
**Generate-And-Filter.** Pain: you need options, not the first idea that sounded clever. Shape: many generators spill ideas into a rubric + dedupe filter; best stay, rest go. Map it with `parallel` over generators, then script-side filter (or one judge `agent` with a schema). Journal/resume matter when generation is expensive. Skip it when the space of good answers is already tiny.
**Tournament.** Pain: absolute scores are mushy for taste and ranking (“how good is this name?”). Shape: pairwise judges, a bracket, a winner — comparative judgment beats lonely scoring. Map it with rounds of `parallel` judge `agent`s over pairs, looping in the script until one remains. Skip it when a clear rubric already picks a winner in one pass.
**Loop Until Done.** Pain: you do not know how many passes the mine still holds. Shape: keep spawning while “new findings?” is yes; stop on dry rounds or a done condition. Map it with a `while` over `agent`/`parallel`, a schemad stop check, and a hard `budget` so the loop cannot eat the house. Pair with journal resume when a long dig may pause. Skip it when the work has a known size — a fixed `pipeline` is simpler and safer.
After a few of those have a face, the toolbox fits in one glance:
| Pattern | Primitive sketch | Reach for it when… |
|---------|------------------|--------------------|
| Classify-And-Act | `agent` → branch → `agent` | Items need different specialists |
| Fanout-And-Synthesize | `pipeline` / `parallel` → merge | Many clean desks, then one summary |
| Adversarial Verification | produce → `parallel(verify)` → filter | Wrong answers are expensive |
| Generate-And-Filter | `parallel(gens)` → rubric filter | You need options, then taste |
| Tournament | pairwise judge `agent`s in a bracket | Ranking / taste without a sharp scale |
| Loop Until Done | `while` + stop check + `budget` | Unknown amount of buried work |
Compositions are normal. Deep research often stacks fanout → filter → verify → synthesize. Our sample is already a small chord of two notes.
## Answers the next stage can hold ## Answers the next stage can hold
@@ -141,18 +162,22 @@ journal: [A ✓] [B ✓] [C ✓] [D ✓]
resume: A hit → B hit → C changed → D runs live resume: A hit → B hit → C changed → D runs live
``` ```
## Walking `review-changes` ## Walking `review-changes` — a composition
Four dimensions share one two-stage path — fan out, verify adversarially, keep what survives: The sample is not “one pattern.” It is **Fanout-And-Synthesize** with **Adversarial Verification** inside — and a light generate-and-filter at the end when only `isReal` findings survive.
```text ```text
correctness ── audit ── verify ──┐ correctness ── audit ── verify ──┐
security ── audit ── verify ──┤── confirmed findings security ── audit ── verify ──┤── confirmed findings
performance ── audit ── verify ──┤ performance ── audit ── verify ──┤
style ── audit ── verify ──┘ style ── audit ── verify ──┘
fanout synthesize
└── each finding: skeptical verify ──┘
``` ```
Review puts each auditor at its own desk so correctness talk does not bleed into security talk. Verify hands every finding to a skeptic who was not the author. Only the real ones remain, sorted by severity. You can almost feel the three failure modes losing their favorite seats. `pipeline(DIMENSIONS, audit, verify)` gives each dimension its own desk so correctness talk does not bleed into security. Inside `verify`, `parallel` of verifier agents is the adversarial chord. Ordinary list filtering is the synthesize step. Phases mark Review then Verify; the journal remembers every `agent()` so a pause does not redo the audits.
You can almost feel the three failure modes losing their favorite seats: the fleet cannot stop after two dimensions, the author is not the judge, and the topology does not drift mid-run.
```python ```python
async def sample_workflow(ctx, args): async def sample_workflow(ctx, args):
@@ -205,4 +230,4 @@ Watch Review give way to Verify. Watch agents flip from `done` to `cached` on a
s16 is how a batch runs. [s17 Goal Loop](../s17_goal_loop/) asks a different question at the door: should we stop, or take another turn? Pair them when a repeatable recipe also needs a hard “done.” s16 is how a batch runs. [s17 Goal Loop](../s17_goal_loop/) asks a different question at the door: should we stop, or take another turn? Pair them when a repeatable recipe also needs a hard “done.”
<!-- translation-sync: zh@v13, en@v13, ja@v13 --> <!-- translation-sync: zh@v14, en@v14, ja@v14 -->

View File

@@ -88,17 +88,38 @@ results = await ctx.pipeline(DIMENSIONS, audit, verify)
confirmed = [f for r in results if r for f in r["confirmed"]] confirmed = [f for r in results if r for f in r["confirmed"]]
``` ```
## 模式:用得着才拿 ## 会写菜谱之后
不必背目录。看清示例在干什么,手里就有三种风格 上面那些动词是面粉和火候。人们反复发明的,是少数几种*形状*——动态 agentic workflow 的常见模式。把它们想成工具箱,不是必点菜单。痛点出现再伸手;其余的留在挂板上
它把改动**分发**到各个审查维度,每人一张干净桌子,再**汇总**成一份确认列表——fan-out-and-synthesize。碎片若挤在同一个嘈杂上下文里会互相串味时这一招值钱。 ![六种 Workflow 模式](images/six-workflow-patterns.svg)
验证阶段里,第二个帮手专门来挑每条 finding 的刺——adversarial verification结构上回答“别给自己的作业打高分”。 *人们反复发明的六种形状。脚本掌管拓扑;本课里用 `agent` / `parallel` / `pipeline` / `phase` / journal 把每种形状说出来。*
留下来的是对生成物做过滤。Generate-and-filter候选进来过关的留下 **Classify-And-Act分类再行动** 痛点:一个万金油帮手样样稀松。形状:分类器看一眼任务,再路由到专家 A、B 或 C。本课里多半是一次带 `schema``agent` 返回标签,脚本里 `if`/`match` 再叫对的后续 `agent`(或嵌一层 `workflow`)。每件东西其实都该同样处理时,就别用——路由只是仪式
同一工具箱里还有 classify-and-act、tournament、loop-until-done以后都会遇见。只有额外成本能买到更清楚或更稳妥的结果时才去借一种风格 **Fanout-And-Synthesize分发再汇总** 痛点:五十个文件塞不进一个疲倦的上下文,挤在一起还会串味。形状:拆开、多 agent 跑、在屏障处等齐、再合并。每件有自己阶段时用 `pipeline`;下一步必须凑齐全部结果时用 `parallel`;合并写在 gather 之后的普通 Python 里。三五个相关文件一趟就能看完时,就别用
**Adversarial Verification对抗验证** 痛点:狐狸给鸡窝打分。形状:工人产出;独立验证者来反驳或施压;只留下幸存者。映射:一次生产用的 `agent`,再 `parallel` 一组验证 `agent`(最好带 `schema`),然后过滤。`phase` 标出 “Review” 再 “Verify”。答错代价很低时就别用——不是每张便条都要法庭。
**Generate-And-Filter生成再过滤** 痛点:你要的是选项,不是第一个听起来机灵的念头。形状:许多生成器把想法倒进“量尺 + 去重”的过滤器;最好的留下,其余丢掉。映射:`parallel` 生成,再在脚本里过滤(或一个带 schema 的裁判 `agent`。生成很贵时journal/续跑特别有用。好答案空间本来就很小,就别用。
**Tournament锦标赛** 痛点:品味和排序上,绝对分数糊成一团(“这个名字有多好?”)。形状:两两比较的裁判、淘汰支架、冠军——相对判断胜过孤独打分。映射:脚本里多轮 `parallel` 的 pairwise 裁判 `agent`,直到剩一个。清晰量尺一趟就能选出赢家时,就别用。
**Loop Until Done接到完为止** 痛点:你不知道矿里还要挖几轮。形状:只要“还有新发现?”为是就继续派工;连续空轮或完成条件出现就停。映射:`while` 包着 `agent`/`parallel`,用带 schema 的停止检查,再加硬性 `budget`,免得循环把家吃空。长挖可能暂停时,配上 journal 续跑。工作量已知时,固定 `pipeline` 更简单也更安全。
几种有了面孔之后,工具箱一眼就能看清:
| 模式 | 原语速写 | 什么时候伸手 |
|------|----------|--------------|
| Classify-And-Act | `agent` → 分支 → `agent` | 条目需要不同专家 |
| Fanout-And-Synthesize | `pipeline` / `parallel` → 合并 | 许多干净桌子,再一份摘要 |
| Adversarial Verification | 产出 → `parallel(verify)` → 过滤 | 答错很贵 |
| Generate-And-Filter | `parallel(gens)` → 量尺过滤 | 先要选项,再要品味 |
| Tournament | 两两裁判 `agent` 搭支架 | 排序/品味却没有锋利刻度 |
| Loop Until Done | `while` + 停止检查 + `budget` | 埋着不知多少活 |
组合是常态。深度调研常常叠成:分发 → 过滤 → 验证 → 汇总。我们的示例,已经是两个音符的一小段和弦。
## 让下一阶段接得住的答案 ## 让下一阶段接得住的答案
@@ -141,18 +162,22 @@ journal: [A ✓] [B ✓] [C ✓] [D ✓]
续跑: A 命中 → B 命中 → C 改过 → D 实跑 续跑: A 命中 → B 命中 → C 改过 → D 实跑
``` ```
## 跟着 `review-changes` 走一圈 ## 跟着 `review-changes` 走一圈——一种组合
四个维度共用一条两阶段路径——先铺开,再对抗验证,留下活下来的: 示例不是“一种模式”。它是 **Fanout-And-Synthesize**,里面嵌着 **Adversarial Verification**——结尾再轻轻做一层 generate-and-filter只留下 `isReal` 的 finding。
```text ```text
correctness ── 审计 ── 验证 ──┐ correctness ── 审计 ── 验证 ──┐
security ── 审计 ── 验证 ──┤── 确认过的问题 security ── 审计 ── 验证 ──┤── 确认过的问题
performance ── 审计 ── 验证 ──┤ performance ── 审计 ── 验证 ──┤
style ── 审计 ── 验证 ──┘ style ── 审计 ── 验证 ──┘
分发fanout 汇总synthesize
└── 每条 finding怀疑式验证 ──┘
``` ```
Review 让每个审计员坐自己的桌子,正确性的闲聊不至于淌进安全性。Verify 把每条 finding 交给不是作者的怀疑者。只留下真的,再按严重程度排好。那三种走偏,会感觉自己最爱的座位被撤了 `pipeline(DIMENSIONS, audit, verify)` 给每个维度自己的桌子,正确性的闲聊不至于淌进安全性。`verify` 里对验证 agent 做 `parallel`,就是对抗那一和弦。普通的列表过滤是汇总。`phase` 标出 Review 再 Verifyjournal 记住每次 `agent()`,暂停也不会重做审计
那三种走偏,会感觉自己最爱的座位被撤了:舰队不能在两个维度后收工,作者不当裁判,拓扑也不会在中途漂移。
```python ```python
async def sample_workflow(ctx, args): async def sample_workflow(ctx, args):
@@ -205,4 +230,4 @@ python s16_workflow_runtime/code.py resume # 同一 runId期待缓存命中
s16 讲一批活怎么跑。[s17 Goal Loop](../s17_goal_loop/) 在门口问另一个问题:该停,还是再来一轮?可重复的菜谱若还需要硬性的“做完”,可以和它一起用。 s16 讲一批活怎么跑。[s17 Goal Loop](../s17_goal_loop/) 在门口问另一个问题:该停,还是再来一轮?可重复的菜谱若还需要硬性的“做完”,可以和它一起用。
<!-- translation-sync: zh@v13, en@v13, ja@v13 --> <!-- translation-sync: zh@v14, en@v14, ja@v14 -->

View File

@@ -0,0 +1,159 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 720" font-family="system-ui, -apple-system, sans-serif" role="img" aria-labelledby="title description">
<title id="title">Six Workflow Patterns</title>
<desc id="description">A toolbox of six common dynamic workflow shapes: Classify-And-Act, Fanout-And-Synthesize, Adversarial Verification, Generate-And-Filter, Tournament, and Loop Until Done.</desc>
<defs>
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#888888"/>
</marker>
<marker id="arr-g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#22c55e"/>
</marker>
</defs>
<rect width="960" height="720" rx="8" fill="#ffffff"/>
<text x="480" y="28" text-anchor="middle" fill="#1a1a1a" font-size="18" font-weight="700">Six Workflow Patterns</text>
<text x="480" y="48" text-anchor="middle" fill="#888888" font-size="11">a toolbox - not a mandatory menu. Compose with agent / parallel / pipeline</text>
<!-- Panel frames: 2x3 -->
<!-- Row 1 -->
<rect x="20" y="64" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<rect x="330" y="64" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<rect x="640" y="64" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<!-- Row 2 -->
<rect x="20" y="380" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<rect x="330" y="380" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<rect x="640" y="380" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<!-- ===== 1. Classify-And-Act ===== -->
<text x="170" y="88" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Classify-And-Act</text>
<rect x="120" y="108" width="100" height="28" rx="4" fill="#fafafa" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="170" y="126" text-anchor="middle" fill="#1a1a1a" font-size="11">task</text>
<line x1="170" y1="136" x2="170" y2="158" stroke="#888888" stroke-width="1.5" marker-end="url(#arr)"/>
<path d="M170 162 L190 182 L170 202 L150 182 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="170" y="186" text-anchor="middle" fill="#1a1a1a" font-size="9">classifier</text>
<line x1="150" y1="192" x2="80" y2="230" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="170" y1="202" x2="170" y2="230" stroke="#22c55e" stroke-width="1.8" marker-end="url(#arr-g)"/>
<line x1="190" y1="192" x2="260" y2="230" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<circle cx="80" cy="255" r="22" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="80" y="258" text-anchor="middle" fill="#1a1a1a" font-size="10">A</text>
<circle cx="170" cy="255" r="22" fill="#ffffff" stroke="#22c55e" stroke-width="1.8"/>
<text x="170" y="258" text-anchor="middle" fill="#1a1a1a" font-size="10">B</text>
<circle cx="260" cy="255" r="22" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="260" y="258" text-anchor="middle" fill="#1a1a1a" font-size="10">C</text>
<text x="170" y="310" text-anchor="middle" fill="#888888" font-size="10">route to the right specialist</text>
<text x="170" y="328" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">agent ' branch ' agent</text>
<!-- ===== 2. Fanout-And-Synthesize ===== -->
<text x="480" y="88" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Fanout-And-Synthesize</text>
<rect x="430" y="108" width="100" height="28" rx="4" fill="#fafafa" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="480" y="126" text-anchor="middle" fill="#1a1a1a" font-size="11">task</text>
<line x1="450" y1="136" x2="400" y2="168" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="470" y1="136" x2="450" y2="168" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="490" y1="136" x2="510" y2="168" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="510" y1="136" x2="560" y2="168" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<circle cx="400" cy="190" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="450" cy="190" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="510" cy="190" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="560" cy="190" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<line x1="400" y1="206" x2="400" y2="232" stroke="#888888" stroke-width="1.2"/>
<line x1="450" y1="206" x2="450" y2="232" stroke="#888888" stroke-width="1.2"/>
<line x1="510" y1="206" x2="510" y2="232" stroke="#888888" stroke-width="1.2"/>
<line x1="560" y1="206" x2="560" y2="232" stroke="#888888" stroke-width="1.2"/>
<line x1="400" y1="232" x2="560" y2="232" stroke="#22c55e" stroke-width="3"/>
<text x="480" y="250" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">barrier</text>
<line x1="480" y1="252" x2="480" y2="272" stroke="#22c55e" stroke-width="1.5" marker-end="url(#arr-g)"/>
<circle cx="480" cy="298" r="22" fill="#ffffff" stroke="#22c55e" stroke-width="1.8"/>
<text x="480" y="302" text-anchor="middle" fill="#1a1a1a" font-size="9">synthesize</text>
<text x="480" y="340" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">parallel / pipeline ' merge</text>
<!-- ===== 3. Adversarial Verification ===== -->
<text x="790" y="88" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Adversarial Verification</text>
<circle cx="720" cy="200" r="36" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="720" y="204" text-anchor="middle" fill="#1a1a1a" font-size="11">worker</text>
<line x1="756" y1="180" x2="850" y2="140" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="756" y1="200" x2="850" y2="200" stroke="#22c55e" stroke-width="1.5" marker-end="url(#arr-g)"/>
<line x1="756" y1="220" x2="850" y2="260" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<circle cx="875" cy="140" r="20" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="875" y="144" text-anchor="middle" fill="#1a1a1a" font-size="9">verify</text>
<circle cx="875" cy="200" r="20" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="875" y="204" text-anchor="middle" fill="#1a1a1a" font-size="9">verify</text>
<circle cx="875" cy="260" r="20" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="875" y="264" text-anchor="middle" fill="#1a1a1a" font-size="9">verify</text>
<text x="790" y="310" text-anchor="middle" fill="#888888" font-size="10">independents stress-test the work</text>
<text x="790" y="328" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">agent ' parallel(verifiers)</text>
<!-- ===== 4. Generate-And-Filter ===== -->
<text x="170" y="404" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Generate-And-Filter</text>
<circle cx="70" cy="460" r="18" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="70" cy="510" r="18" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="70" cy="560" r="18" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="70" y="464" text-anchor="middle" fill="#1a1a1a" font-size="8">gen</text>
<text x="70" y="514" text-anchor="middle" fill="#1a1a1a" font-size="8">gen</text>
<text x="70" y="564" text-anchor="middle" fill="#1a1a1a" font-size="8">gen</text>
<rect x="105" y="448" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="460" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="498" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="510" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="548" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="560" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<line x1="120" y1="460" x2="155" y2="510" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="120" y1="510" x2="155" y2="510" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="120" y1="560" x2="155" y2="510" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<rect x="160" y="488" width="70" height="44" rx="4" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="195" y="506" text-anchor="middle" fill="#1a1a1a" font-size="10" font-weight="600">filter</text>
<text x="195" y="520" text-anchor="middle" fill="#888888" font-size="8">rubric+dedupe</text>
<line x1="230" y1="500" x2="260" y2="470" stroke="#22c55e" stroke-width="1.5" marker-end="url(#arr-g)"/>
<line x1="230" y1="520" x2="260" y2="550" stroke="#888888" stroke-width="1.2" stroke-dasharray="3,2" marker-end="url(#arr)"/>
<rect x="262" y="452" width="40" height="28" rx="3" fill="#fafafa" stroke="#22c55e" stroke-width="1.2"/>
<text x="282" y="470" text-anchor="middle" fill="#1a1a1a" font-size="9">best</text>
<rect x="262" y="538" width="40" height="28" rx="3" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.2"/>
<text x="282" y="556" text-anchor="middle" fill="#888888" font-size="8">drop</text>
<text x="170" y="620" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">parallel(gens) ' filter</text>
<text x="170" y="638" text-anchor="middle" fill="#888888" font-size="10">keep what survives the test</text>
<!-- ===== 5. Tournament ===== -->
<text x="480" y="404" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Tournament</text>
<circle cx="380" cy="450" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="430" cy="450" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="530" cy="450" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="580" cy="450" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="380" y="454" text-anchor="middle" fill="#1a1a1a" font-size="8">a</text>
<text x="430" y="454" text-anchor="middle" fill="#1a1a1a" font-size="8">b</text>
<text x="530" y="454" text-anchor="middle" fill="#1a1a1a" font-size="8">c</text>
<text x="580" y="454" text-anchor="middle" fill="#1a1a1a" font-size="8">d</text>
<line x1="380" y1="466" x2="395" y2="495" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="430" y1="466" x2="415" y2="495" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="530" y1="466" x2="545" y2="495" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="580" y1="466" x2="565" y2="495" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<path d="M405 500 L420 515 L405 530 L390 515 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.3"/>
<path d="M555 500 L570 515 L555 530 L540 515 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.3"/>
<text x="405" y="519" text-anchor="middle" fill="#1a1a1a" font-size="7">judge</text>
<text x="555" y="519" text-anchor="middle" fill="#1a1a1a" font-size="7">judge</text>
<line x1="405" y1="530" x2="460" y2="560" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="555" y1="530" x2="500" y2="560" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<path d="M480 564 L498 582 L480 600 L462 582 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="480" y="586" text-anchor="middle" fill="#1a1a1a" font-size="8">final</text>
<line x1="480" y1="600" x2="480" y2="618" stroke="#22c55e" stroke-width="1.5" marker-end="url(#arr-g)"/>
<rect x="452" y="620" width="56" height="20" rx="3" fill="#fafafa" stroke="#22c55e" stroke-width="1.2"/>
<text x="480" y="634" text-anchor="middle" fill="#1a1a1a" font-size="9">winner</text>
<text x="480" y="662" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">pairwise agent judges</text>
<!-- ===== 6. Loop Until Done ===== -->
<text x="790" y="404" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Loop Until Done</text>
<circle cx="790" cy="470" r="28" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="790" y="474" text-anchor="middle" fill="#1a1a1a" font-size="11">agent</text>
<line x1="790" y1="498" x2="790" y2="525" stroke="#888888" stroke-width="1.5" marker-end="url(#arr)"/>
<path d="M790 530 L812 552 L790 574 L768 552 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="790" y="548" text-anchor="middle" fill="#1a1a1a" font-size="8">new?</text>
<text x="790" y="560" text-anchor="middle" fill="#1a1a1a" font-size="8">findings</text>
<line x1="812" y1="560" x2="870" y2="560" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<rect x="872" y="548" width="40" height="24" rx="3" fill="#1a1a1a"/>
<text x="892" y="564" text-anchor="middle" fill="#ffffff" font-size="9">done</text>
<path d="M768 548 C720 548 720 470 762 470" fill="none" stroke="#22c55e" stroke-width="1.8" marker-end="url(#arr-g)"/>
<text x="730" y="512" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">yes - </text>
<text x="730" y="524" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">spawn</text>
<text x="790" y="620" text-anchor="middle" fill="#888888" font-size="10">stop when dry rounds appear</text>
<text x="790" y="638" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">while + agent + budget</text>
<text x="480" y="702" text-anchor="middle" fill="#888888" font-size="10">Script owns the topology; agents judge inside each step.</text>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,159 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 720" font-family="system-ui, -apple-system, sans-serif" role="img" aria-labelledby="title description">
<title id="title">Six Workflow Patterns</title>
<desc id="description">A toolbox of six common dynamic workflow shapes: Classify-And-Act, Fanout-And-Synthesize, Adversarial Verification, Generate-And-Filter, Tournament, and Loop Until Done.</desc>
<defs>
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#888888"/>
</marker>
<marker id="arr-g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#22c55e"/>
</marker>
</defs>
<rect width="960" height="720" rx="8" fill="#ffffff"/>
<text x="480" y="28" text-anchor="middle" fill="#1a1a1a" font-size="18" font-weight="700">Six Workflow Patterns</text>
<text x="480" y="48" text-anchor="middle" fill="#888888" font-size="11">a toolbox - not a mandatory menu. Compose with agent / parallel / pipeline</text>
<!-- Panel frames: 2x3 -->
<!-- Row 1 -->
<rect x="20" y="64" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<rect x="330" y="64" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<rect x="640" y="64" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<!-- Row 2 -->
<rect x="20" y="380" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<rect x="330" y="380" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<rect x="640" y="380" width="300" height="300" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5"/>
<!-- ===== 1. Classify-And-Act ===== -->
<text x="170" y="88" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Classify-And-Act</text>
<rect x="120" y="108" width="100" height="28" rx="4" fill="#fafafa" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="170" y="126" text-anchor="middle" fill="#1a1a1a" font-size="11">task</text>
<line x1="170" y1="136" x2="170" y2="158" stroke="#888888" stroke-width="1.5" marker-end="url(#arr)"/>
<path d="M170 162 L190 182 L170 202 L150 182 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="170" y="186" text-anchor="middle" fill="#1a1a1a" font-size="9">classifier</text>
<line x1="150" y1="192" x2="80" y2="230" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="170" y1="202" x2="170" y2="230" stroke="#22c55e" stroke-width="1.8" marker-end="url(#arr-g)"/>
<line x1="190" y1="192" x2="260" y2="230" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<circle cx="80" cy="255" r="22" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="80" y="258" text-anchor="middle" fill="#1a1a1a" font-size="10">A</text>
<circle cx="170" cy="255" r="22" fill="#ffffff" stroke="#22c55e" stroke-width="1.8"/>
<text x="170" y="258" text-anchor="middle" fill="#1a1a1a" font-size="10">B</text>
<circle cx="260" cy="255" r="22" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="260" y="258" text-anchor="middle" fill="#1a1a1a" font-size="10">C</text>
<text x="170" y="310" text-anchor="middle" fill="#888888" font-size="10">route to the right specialist</text>
<text x="170" y="328" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">agent ' branch ' agent</text>
<!-- ===== 2. Fanout-And-Synthesize ===== -->
<text x="480" y="88" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Fanout-And-Synthesize</text>
<rect x="430" y="108" width="100" height="28" rx="4" fill="#fafafa" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="480" y="126" text-anchor="middle" fill="#1a1a1a" font-size="11">task</text>
<line x1="450" y1="136" x2="400" y2="168" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="470" y1="136" x2="450" y2="168" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="490" y1="136" x2="510" y2="168" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="510" y1="136" x2="560" y2="168" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<circle cx="400" cy="190" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="450" cy="190" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="510" cy="190" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="560" cy="190" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<line x1="400" y1="206" x2="400" y2="232" stroke="#888888" stroke-width="1.2"/>
<line x1="450" y1="206" x2="450" y2="232" stroke="#888888" stroke-width="1.2"/>
<line x1="510" y1="206" x2="510" y2="232" stroke="#888888" stroke-width="1.2"/>
<line x1="560" y1="206" x2="560" y2="232" stroke="#888888" stroke-width="1.2"/>
<line x1="400" y1="232" x2="560" y2="232" stroke="#22c55e" stroke-width="3"/>
<text x="480" y="250" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">barrier</text>
<line x1="480" y1="252" x2="480" y2="272" stroke="#22c55e" stroke-width="1.5" marker-end="url(#arr-g)"/>
<circle cx="480" cy="298" r="22" fill="#ffffff" stroke="#22c55e" stroke-width="1.8"/>
<text x="480" y="302" text-anchor="middle" fill="#1a1a1a" font-size="9">synthesize</text>
<text x="480" y="340" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">parallel / pipeline ' merge</text>
<!-- ===== 3. Adversarial Verification ===== -->
<text x="790" y="88" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Adversarial Verification</text>
<circle cx="720" cy="200" r="36" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="720" y="204" text-anchor="middle" fill="#1a1a1a" font-size="11">worker</text>
<line x1="756" y1="180" x2="850" y2="140" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="756" y1="200" x2="850" y2="200" stroke="#22c55e" stroke-width="1.5" marker-end="url(#arr-g)"/>
<line x1="756" y1="220" x2="850" y2="260" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<circle cx="875" cy="140" r="20" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="875" y="144" text-anchor="middle" fill="#1a1a1a" font-size="9">verify</text>
<circle cx="875" cy="200" r="20" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="875" y="204" text-anchor="middle" fill="#1a1a1a" font-size="9">verify</text>
<circle cx="875" cy="260" r="20" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="875" y="264" text-anchor="middle" fill="#1a1a1a" font-size="9">verify</text>
<text x="790" y="310" text-anchor="middle" fill="#888888" font-size="10">independents stress-test the work</text>
<text x="790" y="328" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">agent ' parallel(verifiers)</text>
<!-- ===== 4. Generate-And-Filter ===== -->
<text x="170" y="404" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Generate-And-Filter</text>
<circle cx="70" cy="460" r="18" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="70" cy="510" r="18" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="70" cy="560" r="18" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="70" y="464" text-anchor="middle" fill="#1a1a1a" font-size="8">gen</text>
<text x="70" y="514" text-anchor="middle" fill="#1a1a1a" font-size="8">gen</text>
<text x="70" y="564" text-anchor="middle" fill="#1a1a1a" font-size="8">gen</text>
<rect x="105" y="448" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="460" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="498" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="510" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="548" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<rect x="105" y="560" width="14" height="10" rx="1" fill="#fafafa" stroke="#888888"/>
<line x1="120" y1="460" x2="155" y2="510" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="120" y1="510" x2="155" y2="510" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="120" y1="560" x2="155" y2="510" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<rect x="160" y="488" width="70" height="44" rx="4" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="195" y="506" text-anchor="middle" fill="#1a1a1a" font-size="10" font-weight="600">filter</text>
<text x="195" y="520" text-anchor="middle" fill="#888888" font-size="8">rubric+dedupe</text>
<line x1="230" y1="500" x2="260" y2="470" stroke="#22c55e" stroke-width="1.5" marker-end="url(#arr-g)"/>
<line x1="230" y1="520" x2="260" y2="550" stroke="#888888" stroke-width="1.2" stroke-dasharray="3,2" marker-end="url(#arr)"/>
<rect x="262" y="452" width="40" height="28" rx="3" fill="#fafafa" stroke="#22c55e" stroke-width="1.2"/>
<text x="282" y="470" text-anchor="middle" fill="#1a1a1a" font-size="9">best</text>
<rect x="262" y="538" width="40" height="28" rx="3" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.2"/>
<text x="282" y="556" text-anchor="middle" fill="#888888" font-size="8">drop</text>
<text x="170" y="620" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">parallel(gens) ' filter</text>
<text x="170" y="638" text-anchor="middle" fill="#888888" font-size="10">keep what survives the test</text>
<!-- ===== 5. Tournament ===== -->
<text x="480" y="404" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Tournament</text>
<circle cx="380" cy="450" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="430" cy="450" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="530" cy="450" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<circle cx="580" cy="450" r="16" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.2"/>
<text x="380" y="454" text-anchor="middle" fill="#1a1a1a" font-size="8">a</text>
<text x="430" y="454" text-anchor="middle" fill="#1a1a1a" font-size="8">b</text>
<text x="530" y="454" text-anchor="middle" fill="#1a1a1a" font-size="8">c</text>
<text x="580" y="454" text-anchor="middle" fill="#1a1a1a" font-size="8">d</text>
<line x1="380" y1="466" x2="395" y2="495" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="430" y1="466" x2="415" y2="495" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="530" y1="466" x2="545" y2="495" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="580" y1="466" x2="565" y2="495" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<path d="M405 500 L420 515 L405 530 L390 515 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.3"/>
<path d="M555 500 L570 515 L555 530 L540 515 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.3"/>
<text x="405" y="519" text-anchor="middle" fill="#1a1a1a" font-size="7">judge</text>
<text x="555" y="519" text-anchor="middle" fill="#1a1a1a" font-size="7">judge</text>
<line x1="405" y1="530" x2="460" y2="560" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<line x1="555" y1="530" x2="500" y2="560" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<path d="M480 564 L498 582 L480 600 L462 582 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="480" y="586" text-anchor="middle" fill="#1a1a1a" font-size="8">final</text>
<line x1="480" y1="600" x2="480" y2="618" stroke="#22c55e" stroke-width="1.5" marker-end="url(#arr-g)"/>
<rect x="452" y="620" width="56" height="20" rx="3" fill="#fafafa" stroke="#22c55e" stroke-width="1.2"/>
<text x="480" y="634" text-anchor="middle" fill="#1a1a1a" font-size="9">winner</text>
<text x="480" y="662" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">pairwise agent judges</text>
<!-- ===== 6. Loop Until Done ===== -->
<text x="790" y="404" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">Loop Until Done</text>
<circle cx="790" cy="470" r="28" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="790" y="474" text-anchor="middle" fill="#1a1a1a" font-size="11">agent</text>
<line x1="790" y1="498" x2="790" y2="525" stroke="#888888" stroke-width="1.5" marker-end="url(#arr)"/>
<path d="M790 530 L812 552 L790 574 L768 552 Z" fill="#ffffff" stroke="#22c55e" stroke-width="1.5"/>
<text x="790" y="548" text-anchor="middle" fill="#1a1a1a" font-size="8">new?</text>
<text x="790" y="560" text-anchor="middle" fill="#1a1a1a" font-size="8">findings</text>
<line x1="812" y1="560" x2="870" y2="560" stroke="#888888" stroke-width="1.2" marker-end="url(#arr)"/>
<rect x="872" y="548" width="40" height="24" rx="3" fill="#1a1a1a"/>
<text x="892" y="564" text-anchor="middle" fill="#ffffff" font-size="9">done</text>
<path d="M768 548 C720 548 720 470 762 470" fill="none" stroke="#22c55e" stroke-width="1.8" marker-end="url(#arr-g)"/>
<text x="730" y="512" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">yes - </text>
<text x="730" y="524" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">spawn</text>
<text x="790" y="620" text-anchor="middle" fill="#888888" font-size="10">stop when dry rounds appear</text>
<text x="790" y="638" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">while + agent + budget</text>
<text x="480" y="702" text-anchor="middle" fill="#888888" font-size="10">Script owns the topology; agents judge inside each step.</text>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB