Skip to content

Cut workflow-design to a minimal shape: settled as a new additive workflow (workflow-authoring), not an in-place rename #321

Description

@m2ux

Summary

A full workflow-design update pass and a bare two-agent "apply the anti-pattern catalogue and the design principles to this diff" sweep were run against the same branch, in the same session, hours apart. The bare sweep found more real defects for roughly a third of the tokens. This issue proposes cutting workflow-design down to what earned its keep.

This is not a claim that structure is worthless — the workflow's audit stages found three genuine High defects, and two of its planning activities each produced one load-bearing insight. It is a claim that the current shape spends most of its budget on delivery overhead and on artifacts nobody reads.

The measurement

Both runs targeted workflow/work-package-review-mode-friction-271 (PR #274). Token figures are harness-reported subagent totals.

workflow-design pass 1 Two bare sweeps
Worker dispatches 12 2
Subagent tokens ~1,430,000 ~410,000
Wall clock ~2h ~40m
High findings 3 8
Cost per High ~477k ~51k

Per-activity breakdown of the workflow run: discover-session 58k · initialize-session 43k · resolve-target 33k · dispatch-client-workflow 42k · intake-and-context 152k · requirements-refinement 160k · impact-analysis 108k · scope-and-draft 177k · quality-review 192k · validate-and-commit 92k + 142k · post-update-review 231k.

All three of the workflow's High findings came from its two audit stages. The four planning activities consumed ~600k and produced no High findings — though see "what we would lose" below, because two of them produced insights that prevented a wrong fix.

Artifacts: 17 files, 106KB, six with no reader

Produced by the run, by size:

03-assumptions-log.md 13.7K · 06-scope-manifest.md 9.5K · 01-deferred-items.md 8.5K · 10-post-update-review.md 8.3K · README.md 7.5K · 06-draft-attestation.md 7.4K · 10-principle-findings.md 7.3K · 03-design-specification.md 7.1K · 05-impact-analysis.md 7.0K · 01-structural-inventory.md 5.2K · 10-anti-pattern-findings.md 5.0K · 08-conformance-findings.md 4.2K · 08-verified-findings.md 3.5K · 01-format-conventions.md 3.4K · 08-expressiveness-findings.md 3.0K · 06-file-review-note.md 3.0K · 06-drafting-plan.md 2.4K

The six in bold — 25KB, about a quarter of the total — were never read by the user, never cited in any decision, and never consumed by a downstream step. Each still cost a technique load, a persist step, verify-artifact-conforms checking, and a Progress table row.

Artifacts that demonstrably earned their place: the deferred register (became #319), the findings satellites (their content drove the fix cycle), the scope manifest and assumptions log (both fed real Gate 2 decisions — the manifest caught a four-files-not-three discrepancy), and the planning README (the one thing a human navigates).

Three causes, largest first

1. Per-dispatch re-delivery dominates the budget

dispatch-activity's workers-need-full-delivery requires each worker to be a fresh context with no prior deliveries — correct for isolation, but it means all 12 workers re-pull the operations bundle, their activity, their step techniques and their resources before doing any work. The meta orchestrator bundle alone serialises to ~50KB. Twelve fresh contexts × (bundle + activity + techniques + resources) accounts for most of the 1M-token gap against two dispatches.

This is architectural rather than incidental: activity count is the primary cost driver, largely independent of how much work each activity does.

2. Splitting the audit by lens structurally prevents the best findings

quality-review runs six audit techniques, each scoped to one dimension, each persisting its own satellite. post-update-review repeats five of them. The bare sweep instead gave one agent the entire diff.

That difference is not cosmetic — it decided what was findable. Two of the most serious defects live between files and could not be seen by any single-lens pass:

  • A review type could contradict its own summary: work-package/workflow.yaml:335 adds review_type as a checkpoint-set variable while update-pr/post-review-comment.md:34 still asserted the cap was inherited "with no separate variable" — so a supplied approve skipped the derivation and would post an approving review over a Request-Changes body.
  • 13-submit-for-review.yaml re-rendered the review summary after the user approved it and before posting it "verbatim", while the committed artifact kept the pre-refresh links — spanning a step order and two technique rules.

Both were missed by the in-workflow audits and found by the sweep.

3. The machinery carries its own bug population

Seven of the ten items in this run's deferred register are defects in workflow-design's own definitions: D-1 (mode-gating disagreement across three surfaces), D-2 (seed inventory gap), D-4 and D-7 (artifact_content bound to names with no producer, so the string resolves as a literal and the step would persist the variable's name), D-8 (two UNRESOLVED technique inputs), D-9 (nine restated defaults), D-10 (a canon rule that, read literally, makes verify-artifact-conforms fail by construction).

D-4 and D-7 are the sharpest: every worker that hit them reported spending effort working around them. The workflow's own persist machinery is a tax on the workflow's own runs.

Compounding this, four attestation gates auto-resolved without reaching the user (#317), including one that waved through three removals under an outcome clause reading "every flagged removal is one the user consciously approved". Where the ceremony exists to record human consent, it was recording consent nobody gave.

What the sweep did differently, beyond being smaller

These are replicable and belong in whatever replaces the audit stages:

  1. Attribution against base was mandatory. Every candidate was checked with git show origin/workflows:<path>; inherited content was reported separately. This eliminated the re-litigation of pre-existing noise that consumed effort in earlier passes.
  2. Known items were excluded up front. The prompt listed already-tracked findings, so zero effort went to rediscovery.
  3. Negatives had to be evidenced. "Entries applied that pass, where a plausible exposure existed" — which is exactly what the in-workflow rule-hygiene passes lacked. They reported 0 findings twice while never reading a technique ## Rules section, the surface where two real defects were later found by hand.
  4. One context held the whole surface, enabling the cross-file findings above.

Planning outcome — this supersedes the original proposal below

Full record: .engineering/artifacts/planning/2026-07-28-workflow-design-slim-down — six corpus maps, three competing architectures, three judge verdicts, the implementation plan, two adversarial passes.

The proposal as originally written below was tested and lost. Three target architectures were designed independently and scored by three judges, one lens each. The framing that took this issue literally — the scope/draft/audit/land rename and 17→5 — scored lowest on all three lenses:

Proposal Canon Migration Efficacy Total
value-preserving 8 7 8 23
delivery-first 6 5 7 18
minimal-cut (this issue, literally) 4 4 5 13

The settled shape

Original proposal Settled
Activities 9 → 4, renamed 9 → 4, ids preserved (intake-and-context, scope-and-draft, quality-review, validate-and-commit), sparse prefixes 01/06/08/09 kept
Techniques not addressed 37 → 23 (19 retired, 5 added)
Artifacts 17 → 5 17 → 6
Delivery not addressed one whole-surface audit-canon sweep replacing six per-lens passes
Migration in-place rewrite + delete additive, on a new workflow id

Renaming the activities was the single worst idea in the original proposal. Prefix and id renumbering buys cosmetics and pays for it in the @-column of 32 live planning folders, and — see below — in stranded sessions.

Migration is additive, not in place

The original plan rewrote workflow-design's activity files and deleted five. That bricks 21 of 32 running sessions: readActivityRaw matches the filename-derived id with no fallback (src/loaders/workflow-loader.ts:570, error at :615), and validateActivityTransition returns null on an empty valid set (src/utils/validation.ts:45), so next_activity succeeds silently — the failure only surfaces when get_activity throws. 19 of the 21 sit at retrospective.

Instead: author the slim design as a new workflow, workflow-authoring v1.0.0, and leave workflow-design untouched. Sessions drain naturally. Registration needs nothing but the directory — discovery is a readdir + isDirectory() scan, and workflow.yaml never enumerates its activities, which is what lets the migration land one activity at a time (S1–S8, each leaving a validating workflow terminated at __terminal__).

Retirement is gated on a drain-to-zero trigger: a committed census script that recurses triggeredWorkflows[i].state, an append-only drain log, and a ≥90-day abandonment policy — because nobody is obliged to finish the 19 parked sessions, so zero must be reachable, not merely measurable.

This dissolves the Critical plus four other findings. Its honest cost: ~18 technique files must be duplicated, because workflow-design's techniques are flat files with no group segment and therefore have no cross-workflow address. The 154 KB canon does not need duplicating — cross-workflow resource refs work, provided the link is authored in the relative .md form the loader projects.

Blocking defect, to be fixed in the authored YAML

transitionTo is "Recorded and returned, not engine-applied" (src/schema/activity.schema.ts:50). So selecting remediate does not move the session: the worker continues through the rest of the activity, presents the commit gate anyway, writes COMPLETE.md on a non-terminal pass, and removes the worktree the remediation round then needs to author into. Five further defects are listed in the planning record; all are fixable during authoring.


Original proposal — superseded, retained for the record

Activities: 9 → 4

New Absorbs Emits
scope intake-and-context, requirements-refinement, pattern-analysis, impact-analysis change surface, binding constraints, open judgements
draft scope-and-draft the edits
audit quality-review, post-update-review one findings register; bounded fix cycle; blocking gate on Critical
land validate-and-commit, retrospective Gate 2, commit, push, PR, close-out

Artifacts: 17 → 5

Keep: planning README (Progress + links), scope record (surface + constraints + open judgements, replacing design-specification + assumptions-log + impact-analysis + scope-manifest), findings register (one file replacing six satellites), deferred register, COMPLETE.md.

Drop: format-conventions, structural-inventory, drafting-plan, file-review-note, draft-attestation, verified-findings.

The test an artifact must pass

A named reader and a decision it feeds. If neither exists, it does not get written. Attestation records specifically are redundant: the session trace already holds every checkpoint response, and get_trace resolves it at close-out.

Audit stage design

One whole-surface sweep, not per-lens passes. Carry over the four properties above: mandatory base attribution, known-items exclusion, evidenced negatives, single context over the whole diff. A bounded fix cycle and a blocking gate on Critical — blocking, because the current gate sat in activity-level decisions evaluated at exit, so a Critical finding was announced and attested anyway.

What we would lose, and how to protect it

Honest accounting — two planning activities did earn their keep, once each:

  • requirements-refinement established that closing the orphan input was a re-target, not a rename: .engineering/ is a nested checkout on branch engineering while the parent sits on main, so binding to a parent-repo path yields exactly the value the technique forbids hardcoding. Without that, the fix would have been wrong.
  • impact-analysis found the change surface was four files not three, and that the obvious fix name would shadow declared I/O and introduce fresh drift.

Both are constraint discovery, and both are cheap to ask for directly. The merged scope activity should demand them explicitly — "what does this change actually target, what constrains the fix, what must a human decide" — rather than relying on four activities to surface them incidentally.

Gate 2 stays. It caught the four-files discrepancy and disposed two open judgements. The judgement trail stays too, inside the scope record rather than as a separate log.

Suggested validation

Before committing to the cut, re-run the same branch through the proposed 4-activity shape and compare against both baselines in the table above. The target is ≤500k tokens — roughly the sweep cost plus drafting — with no loss in High findings. If the slimmed shape cannot match 8 Highs, the gap identifies what genuinely needed the ceremony.

A finding that generalises beyond this issue

anti-patterns.md has 13 ## sections, and AP-126/127/128/129 sit inside ## Authoring Guidance (MR) rather than in an anti-pattern family section. Any catalogue walk that enumerates ## *Anti-Patterns families therefore drops them silently — including AP-128 and AP-129, the two entries the slim-down most depends on. That is a reliability problem for every catalogue sweep, including the bare sweep that motivated this issue.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions