#3342·Archon

fix(web): saving a workflow from the builder destroys the author's comments and YAML anchors

Author: WirasmCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbugarea: workflowsarea: webarea: server

Problem

Loading an existing workflow into a builder and saving it overwrites the author's file with a document reconstructed from the parsed WorkflowDefinition. Everything the definition does not carry is destroyed: comments, YAML anchors and aliases, block scalars, and line formatting. The rewritten file is also a single flow-style line — archon-review.yaml comes back as 4243 characters on one line.

PUT /api/workflows/:name serializes with Bun.YAML.stringify(definition) (packages/server/src/routes/api.ts:4440) and writes the result to the existing file path (packages/server/src/routes/api.ts:4462). Both builders save through it: the console builder (packages/web/src/experiments/console/builder/BuilderConnected.tsx:251) and the legacy builder (packages/web/src/components/workflows/WorkflowBuilder.tsx:301).

Why

YAML anchors are the only mechanism a workflow author has for declaring one output_format schema and reusing it across nodes. Our own delivery pack depends on it: .archon/workflows/sdlc/deliver/archon-deliver.yaml:75 defines &green_gate and aliases it at lines 293, 368 and 482, with &ci_state at 408 aliased at 436. A builder save silently expands each alias into an independent copy, reintroducing exactly the drift the anchor exists to prevent — and the author gets no indication it happened.

Comments are how the bundled packs explain their gates and their non-obvious wiring. A save strips all of them. A single-line flow document also makes the file unreadable in a diff and hostile to a merge.

Why now: the console is the default UI and /builder/:name is a live route (packages/web/src/experiments/console/ConsoleApp.tsx:78). We are also telling users publicly that anchors are the supported way to share a schema across nodes, so a surface that quietly undoes them is a contradiction we should not ship.

Desired outcome

Saving an existing workflow from either builder preserves the parts of the file the builder did not change. Comments and anchors survive a no-op save, and the saved file stays block-style and diff-readable.

Acceptance

  • Open .archon/workflows/sdlc/deliver/archon-deliver.yaml in the builder, save without editing, and git diff on that file is empty.
  • After that save the file still has one &green_gate definition and three *green_gate aliases, not four independent copies.
  • Comments present before a save are present after it.
  • The saved file is block style — no single-line flow document.
  • Changing one field on one node changes only that region of the file.
  • A workflow with no comments and no anchors still saves as it does today.

Evidence

Reproduction

  1. Run the server and open /builder/archon-deliver against a project whose workflows include the sdlc pack.
  2. Save without making any edit.
  3. git diff .archon/workflows/sdlc/deliver/archon-deliver.yaml.

Measured directly against the save path's serializer (bun 1.4.2):

$ bun -e 'const p = Bun.YAML.parse(await Bun.file(".archon/workflows/sdlc/review/archon-review.yaml").text());
          const out = Bun.YAML.stringify(JSON.parse(JSON.stringify(p)));
          console.log(out.split("\n").length, "lines,", out.length, "chars")'
1 lines, 4243 chars

The anchor loss comes from the JSON hop, not from the serializer:

Bun.YAML.parse keeps alias identity     nodes[0].output_format === nodes[1].output_format  → true
Bun.YAML.stringify(parsed)              → emits &output_format / *output_format
Bun.YAML.stringify(JSON round-trip)     → two independent duplicated copies

The definition crosses HTTP as JSON (saveWorkflowBodySchema), so the shared identity that Bun.YAML.parse preserved is already gone before the server serializes. Comments are never carried at all — the parsed definition has no place to hold them.

The single-line output is a missing argument rather than a Bun limitation: Bun.YAML.stringify(value, null, 2) emits block style.

Environment

  • Archon version or commit: a7e300b2a
  • Platform or adapter: web (console builder and legacy builder)
  • Database: SQLite
  • OS: macOS (Darwin 25.6.0), bun 1.4.2

Constraints and related work

  • Must remain true: the save path validates with parseWorkflow before writing (packages/server/src/routes/api.ts:4445); a save can never write a file that no longer loads.
  • Must remain true: the refusal to overwrite a bundled default (packages/server/src/routes/api.ts:4458) stays.
  • Related: a community question about sharing one output_format schema across several nodes. The answer is YAML anchors, which is what this bug destroys.
  • Solution steering: Hint — the formatting half is one argument to Bun.YAML.stringify, but that fix alone does not preserve comments or anchors. The preservation half needs a decision about whether the builder edits the existing file text rather than regenerating the whole document. Do not let the cheap formatting fix close this issue.