DEV Community

Cover image for Dynamic Workflows: Critical Analysis (pt. II) (feat. Fable)
Really Him
Really Him

Posted on

Dynamic Workflows: Critical Analysis (pt. II) (feat. Fable)

[NOTE: This is a follow-up to this post where I began to develop a hermeneutic critique of the Claude Code Workflow tool from the perspective of a user who just wants the feature to work.]

"Loop-until-dry": A Recipe for Disaster

The Claude Workflow tool definition has substantially migrated out of the definition, and into a built-in Claude Code Skill, which is not publicly available for users to review. This makes it very difficult to implement tooling that attempts to leverage dynamic workflows: it's rather hard to know whether the design you have in mind will cohere with the bundled Skill or conflict with it.

One concept that comes up in the workflow-authoring Skill is: adversarial review/verification. This is a useful pattern (in theory), because it forces Claude to submit its plans to a critic before committing to them, and if the critic can identify any issues, then Claude must revise the plan, and repeat the cycle. As a result (so the reasoning goes), at the end of the process, the plan will be strengthened in virtue of having had its defects exposed.

This is a genuinely useful strategy that is often employed when making decisions in the "real world" - that's why scholarly journals use peer review, for example. But a strategy that is effective in the context of human interaction becomes a guaranteed failure mode when blindly applied to coding agents.

I asked Claude Fable 5.1 to perform an adversarial review on the workflow-authoring Skill. This is how it turned out:

REALLY HIM
I did loop until dry the other day. It went on for, like, an hour because, you know, you're not naive: what happens when you ask an agent, "review something"? Do you find any errors? How likely is it that they will say no errors? They will invent things more likely than to say, "yeah, it's fine."

FABLE
Here is my own pass over the built-in reference, treating each pattern as a claim and asking how it fails in practice. Your loop-until-dry experience is not an outlier. Several of these patterns share the same defect.

The finder prior is never addressed

Every discovery pattern in the reference assumes an agent asked "find bugs" will eventually say "none." That assumption is wrong, and it is the root of most of the waste.

  • Loop-until-dry. A finder prompted to find things is rewarded by its training for finding things. Given the same corpus and the same prompt, successive rounds are near-independent samples from the same distribution, not a search that exhausts a space. The dedup step compares keys, and a reworded duplicate is a fresh key. So "two consecutive rounds return nothing new" is a condition the process almost never reaches. Termination comes from the budget or the agent cap, which is what your hour-long run was. The reference adds no honesty valve ("an empty list is valid and preferred"), no narrowing of scope per round, and no exclusion of already-seen regions. Without those it is a random-sampling loop with a stopping rule that cannot fire.
  • Completeness critic. Same defect, one level up. A critic asked "what's missing?" always finds something, so "what it finds becomes the next round of work" is an infinite tail generator with no bound and no ranking by consequence.
  • Loop-until-count. The opposite failure. Repeated identical prompts return overlapping bugs, so the counter fills with duplicates and stops early with false confidence. There is no dedup in the example.
  • Loop-until-budget. The only well-bounded loop, and it is bounded by being broke, not by being done. It spends to the ceiling by construction.

Adversarial verify is weaker than it looks

The example spawns three refuters with the identical prompt, the identical claim text, and no evidence or tools.

  • Correlated votes. Three samples from the same model with the same input are not independent skeptics. A majority of correlated votes is roughly one vote with false confidence attached.
  • Blind refutation. The refuter receives the claim as a string. It cannot check the code, so it refutes on plausibility or rubber-stamps. "Default to refuted if uncertain" makes the outcome a coin toss over prompt wording rather than a judgment over evidence.
  • Attrition kills valid claims. The survival rule is two non-refuted votes among the survivors. If two of three verifiers die, which the reference says happens and tells you to filter away, the claim cannot survive regardless of merit. Dead agents and refuting agents have the same effect. That is a concrete bug in the reference's own example.
  • The rubric shapes what reaches verification. In this morning's run, nothing reached the confirm phase because the assessor prompts capped everything at "concern." A verify pass only verifies what upstream labels chose to send. The reference presents verification as a filter on findings, but its real input is the labeling rules, which it never discusses.

The reference does mention perspective-diverse verify, which is the right idea. It should be the default, and each verifier should be handed the evidence and the tools to reproduce, with survival requiring a citation, not a vote.

Scale and cost are treated as one thing

  • "Thoroughly audit" means more finders and 3 to 5 votes. Multiplicity on the same corpus produces duplicates and multiplies verify spend. Thoroughness comes from partitioning by file, subsystem, or lens, which is a different axis the reference does not name.
  • "Token cost is not a constraint" under ultracode. Combined with loop-until-dry, a five-vote verify, and Fable inheritance, that sentence is the complete recipe for a run that costs an hour and a million tokens and reports the same six findings three times.
  • Single-currency cost model. Pipeline is the default because it minimizes wall-clock. The reference never mentions that a pipeline has no stop-safe point, so an interrupted run forfeits everything behind its slowest item. Your TOPOLOGY-COSTS doc covers this. The harness reference does not.
  • Model inheritance "almost always correct." Covered earlier. It is correct for cheap main models and wrong for the case that costs the most.

The largest omission: empty versus failed

The reference says agent() returns null on death and tells you to filter it out. It never distinguishes "found nothing" from "did not run." That single conflation corrupts every pattern above: a dead finder counts as a dry round, a dead verifier counts as a refutation, a dead assessor in a gate looks like a pass.

The Rebuttal

It wouldn't be very honest of me to ask for a one-sided critique and then present it as "Fable's Opinion", so I then asked Claude to present the other side of the argument:

REALLY HIM
ok so i asked you to take on an adversarial stance against the Skill guidance, so to be fair, I will now ask you to defend the Skill just as vigorously.

FABLE

Taken as a brief for the defense, the reference holds up better than my prosecution allowed. The strongest argument is about what kind of document it is.

It is an API reference, and it is a good one

The reference's job is to teach the primitives and their traps: agent returns text unless you pass a schema, parallel is a barrier and pipeline is not, stages take thunks not promises, meta must be a pure literal, Date.now breaks resume, a dead agent resolves to null and you must filter it, budget is a hard ceiling. Every one of those is a mistake a first-time author makes, and every one is stated once, correctly, with a runnable line. Judged as the document it is, it is dense, accurate, and unusually candid about failure modes. Most tool docs never tell you what returns null. The patterns section says, in its own words, "these patterns aren't exhaustive, compose novel harnesses when the task calls for it." They are sketches of control flow, three lines each. Criticizing Try to refute: ${claim} for not passing evidence is criticizing a three-line illustration for not being the thirty-line prompt the author is expected to write. The reference shows where the prompt goes. Filling it is the author's job, and the reference says so.

The patterns I attacked are defensible on their own terms

Loop-until-dry replaces while count < N, which is strictly worse for unknown-size discovery, and the reference says why: counters miss the tail. Non-termination is real, and the reference fences it three ways in the same section: a concurrency cap, a 1000-agent backstop, and the budget primitive presented right beside it with the explicit warning that an unguarded loop runs to the cap. An hour-long run is a run launched without a budget directive. The reference told the reader how to set one. And the composed example's note, dedup against seen rather than confirmed so judge-rejected findings don't reappear, shows the authors thought about convergence harder than a sketch requires. The finder prior is a prompt problem, and the prompt string is the one thing the author fully controls.

Adversarial verify with default-to-refute is a deliberate asymmetry, not carelessness. A plausible-but-wrong finding forwarded to a human costs trust; a lost true finding costs one bug. The reference names that trade. Correlated votes still cut single-sample variance, and two-of-three catches exactly the temperature outlier that a lone verifier would ship. The very next bullet says to use distinct lenses when a finding can fail more than one way, which is the fix I demanded as if it were missing. The attrition arithmetic is one line the author owns, and the null convention that makes it fixable is documented.

Empty versus failed is not absent from the harness. It is in the type: a dead agent is null, an honest-empty result is {findings: []}. The reference states the null case and tells you to handle it. What it lacks is a paragraph of methodology, and that paragraph belongs in a methodology document. Your AUTHORING.md is that document. A tool reference that duplicated it would be longer, would drift, and would still not be loaded on the by-name path.

Model inheritance is the right default for the case the reference is written for: an inline script authored mid-task by a model that cannot reliably tier its own stages. Guessing wrong per stage is a worse failure than uniform. The text says "only set it when highly confident," which is a default with an override, not a prohibition. The Fable problem is a pricing artifact of one main-session model, and a pricing rule belongs in a launch hook, which is where you put it.

Pipeline by default is the single most valuable instruction in the document. Barrier-by-default is the natural mistake, because everyone's mental model is Promise.all. The reference gives a smell test and a short list of the only justifications for a barrier. Resume loss is real and second-order; idle-time waste happens on every run, interruption on some.

Ultracode is gated on an explicit opt-in confirmed by a system reminder. "Token cost is not a constraint" is the user's stated preference in that mode, and the same section still says to stay in the loop between phases and to go solo on trivial work. It is not a runaway directive.

The evidence from this session favors it

This morning's run was a script built entirely on these primitives. Seven agents, none dead, the null convention correctly handled by the dead-assessor logic, a security finding reproduced against the venv, and eight conditions a release manager can act on. Everything we diagnosed afterward was fit-to-repo and launch-path, and the editorial guidance that would have caught the fit problem was in this reference. It was not loaded, which is a trigger-design question, and a defensible one: the document is a few thousand tokens, and loading it on every turn of every session to serve the reuse case would tax the common case. The tool description keeps the invariants; the reference carries the rest.

So the honest verdict from both sides: the content is sound for authoring from scratch, its sketches need the prompts and valves your plugin already supplies, and the two documents are complementary rather than in conflict. The failure was delivery, not doctrine.

The Verdict

Well, dear reader: what do you think? Having seen Fable's critique of the current Workflow architecture, as well as its defense, which side do you find more convincing?

Top comments (1)

Collapse
 
raknaos profile image
Baptiste Le Bouquin

The loop-until-dry observation matches what I've seen, and I'd push it one step further: the failure isn't just that the critic invents errors, it's that a critic with no independent access to ground truth can only generate plausible-sounding objections. Two instances of the same model debating a plan converge on a kind of stylistic polish — the plan reads better and is not measurably safer. Peer review works for journals because reviewers repeat the experiments, or at least could. An LLM critic that only re-reads the plan can't repeat anything.

The runs where adversarial review actually caught something for me were the ones where the critic was pointed at artifacts — test output, logs, a diff — rather than the plan document. Signal from execution beats opinion about intent, same reason fuzzing finds things code review doesn't. The tricky part is that "review the plan" is the cheap pattern to wire up, so that's the one everyone ships.

On migrating the workflow definition into a bundled Skill: it hurts in a second way you didn't spell out. When the definition isn't public, you can't tell whether your custom harness conflicts with the bundled one or merely duplicates it, so your own tooling silently diverges from an implementation you can't diff against. Have you found any way to introspect what the bundled skill actually instructs, or is it genuinely opaque from the outside?