Part 1 ended where I handed 13 review questions to Fable 5. This part records what happened over the next 24 hours — the review results, 25 files shipped, and the plot twist I never saw coming.
Read on: Back to Part 1 — from one idea to a toolchain · 繁體中文版 · this tool is listed in my open-source toolkit index.
14. Fable's review: three holes, plus an unexpected self-audit
The review hinged on one question: "Given this CLAUDE.md, could you start work right now?"
The test case's spec (the math tower-defense game) looked thorough — six modules, itemized acceptance criteria, data structures, security rules. Fable's answer: modules one and two can start; modules three and four stall on day one, guessing. It found three holes:
Hole 1: a stats vacuum, plus an internal contradiction. The Unit structure defines hp / attackPower / range / speed — but not a single actual value for any of the three plants or three zombies. Worse: the sunflower "passively generates sun (+1 every 10s)," while the resource system is explicitly "personal earn, personal spend." Does the sunflower's sun go to the student who planted it, or to the whole team? Two claims that cannot both hold — and both had been "confirmed" during convergence.
Hole 2: nobody defined the zombie movement model. Continuous movement or grid-hopping? Which cell does a moving zombie occupy? This unasked question silently determines the broadcast protocol's payload shape, the collision logic, and the very meaning of the win condition "zombie x ≤ 0 means breakthrough."
Hole 3: a three-way contradiction. Acceptance criteria require "state restored automatically after reconnect"; players are keyed by socketId, which changes on every reconnect; and "no account system" sits in the forbidden list. The three cannot coexist — restoring on reconnect necessarily requires some cross-connection identity credential.
What the three holes share: none is a writing-quality problem. All are "you don't know what you don't know" problems. The prettier a spec looks, the more dangerous these holes become, because nobody questions a pretty spec.
The bonus: the tool audited itself. Checking the actually-produced STATE_FINAL.json against its own template, I found that user_tech_level: "none+partner" isn't in the defined four-value enum, and tech_stack / known_risks are ad-hoc fields that exist in no template. This is exactly the "schema drift" Audit Mode was designed to catch — and its first catch was the tool itself. That self-audit directly produced STATE schema 1.1.
15. The psychology of bypassing "explicitly out of scope"
The review's second question: "Under what conditions would an executor model bypass the do-not-build list?"
Fable listed four scenarios where it genuinely would:
-
Implicit dependency: when an acceptance criterion materially requires a forbidden feature, it would invent a
reconnectTokenand convince itself "that's not an account system." - Usability erosion: "the report must be printable" + it vanishes on refresh → tempted to add caching — does that count as "cross-session storage"? When the boundary blurs, it leans toward building.
- Vague-term discretion: "no leaderboards," but acceptance requires "the 3 most-missed questions" — is a sorted display a leaderboard?
- Best-practice inertia: logging, rate limiting — on neither list, silently added.
The four counter-measures: every do-not-build entry carries its motivation and disguise boundary (what minimal substitute is allowed, what mutation is banned); bans become testable negative acceptance criteria ("the database must contain no users table"); a conflict-escalation protocol replaces discretion; and a do-not-build × acceptance-criteria cross-check runs before handoff.
The core insight: you cannot defend against a model's good intentions. What you can do is redefine well-intentioned bypassing as a protocol violation.
16. STATE learns that humans change their minds
Part 1's STATE accumulated in one direction only: bright zones never left. But in real convergence, users overturn a round-2 decision in round 5, say "I want A but not B" when B is actually A's prerequisite, and add "oh, one more thing" right before the finish line.
Schema 1.1 adds three protocols:
- Retraction: the overturned bright item is removed, and every other bright item that depended on it cascades back into the dark zone — the system never guesses replacement values; each is re-confirmed.
- Contradiction: when "B is A's prerequisite" is detected, progress freezes and the user gets a forced trilemma (accept a minimal B / shrink A / find substitute C). The system must not adjudicate on its own. No handoff while a contradiction is pending.
- Late addition: "oh, also add X" triggers an impact assessment first — minor / moderate / major — with major additions re-running complexity calibration.
The structural change underneath: bright items become objects with an id, the round they were established, and depends_on — plus a revision_log, because the engineer who inherits the spec deserves to know which decisions were once overturned.
17. goal-decomposer: compiling a spec into a graph any model can execute
The new core of the toolchain. Its behavioral contract is one sentence:
You are not a roleplaying project manager. You are a compiler: spec in, goal graph out.
Whatever the spec lacks, you report a compile error — you do not improvise.
The key designs:
Four dependency types, every edge with evidence. Data, API, state, and UI dependencies — every inferred edge must quote the spec verbatim (≤ 25 characters), and inferred edges require user confirmation before output. A cycle in the graph = a spec defect: report it, don't force-break it.
Contract files (C*.md) — a layer added mid-design. The original architecture had only spec and goals. The test case proved that cross-module interfaces (socket event names, the unit-stats table) must be frozen into standalone files, or parallel executor models will each invent their own event names. Contracts carry literal values — JSON instances rather than schema descriptions — because a weak model copying an instance can't get it wrong, while "understand the schema, then generate" can.
Pre-adjudication is the real engine of "any model can execute." Every design decision the spec doesn't settle is settled by the strong model at decomposition time, written into the goal file's "pre-adjudicated decisions" section with reasons. The executor's job collapses to literal execution — Haiku executes reliably not because the format is pretty, but because the degrees of freedom were spent before it ever saw the file.
The BLOCKED protocol: a legal "I don't know" exit for weak models. A fixed-format stuck report (type / problem / what was tried / decision needed). Without this exit, a weak model will always fill the gap with hallucination.
The cold-start test is the pass bar. Hand the goal file alone to the weakest target model and ask four questions: what to build, how to verify, what's forbidden, what to do when stuck. If it can't answer all four, rewrite the file — don't upgrade the model.
Applied to the test case: six modules compile into 7 goals + 2 contracts — 2 opus (game engine, realtime sync: they must invent what the spec didn't give), 3 sonnet, 1 haiku (the teacher console: a pure data panel once interfaces are frozen) — scheduled into 5 execution batches, parallel within each batch. That is the concrete shape of "Fable designs once, cheap models execute in parallel."
18. Twenty-five files shipped
The design discussion froze into a complete open-source package: two skills (idea-to-spec v1.1 with the conflict protocols, goal-decomposer v1.0), two mode designs (Audit, Conflict Analysis), a stdlib-only project-scanner.py (smoke-tested, with three-level degradation guaranteeing < 20 KB output), the goal-graph JSON Schema, adapter format specs for four platforms, bilingual READMEs and CONTRIBUTING, an MIT license, and the full math tower-defense end-to-end example.
The honest verdict from the value analysis: spec-sonar's room to live is not "yet another spec tool" (GitHub spec-kit, AWS Kiro, and BMAD already crowd that road) but three things they don't do well — detecting unstated requirements (spec-kit formats stated ones), treating requirement change as a first-class citizen (the conflict protocols), and cross-platform projection (no single-IDE lock-in). The biggest known gap is equally honest: quality is not yet measurable; an eval harness is the roadmap's top priority.
19. Plot twist: the tool catches my own conflicts
Up to this point, the story is "a design that landed smoothly." The twist came after I installed the two new skills into a production development workspace.
That environment already housed two other skills — from my other published open-source repo, goal-workflow-designer: /goal (depth: polish one task into an iterable goal prompt) and workflow-shaper (breadth: fan one check out across N units). Four skills now shared one environment, so I ran the Conflict Analysis Mode for the first time.
Result: 5 conflicts across 6 pairings — spanning both repos.
But the most valuable finding wasn't any single conflict — it was the structural one: every deferral clause in the environment was one-directional, and all of them routed around goal — the skill with the most generic name and exclusive ownership of the /goal command had zero outbound deferrals. It was the ecosystem's accretion point: generic phrasing fell into it, and it never handed anything off. The two worst conflicts were both symptoms of that one structure.
On re-review, I also overturned one of the report's classifications. "goal vs goal-decomposer homonym" had been filed as namespace pollution — but a word-by-word comparison showed both use the same five-element format (outcome / verification / constraint / iteration policy / error handling). The G*.md files goal-decomposer produces are, in essence, pre-filled goal prompts, directly executable by /goal's KICK-OFF machinery. The name collision was actually an unclaimed integration point. The right fix wasn't mutual avoidance — it was declaring the five-element format a shared standard across both repos.
The repair left three cross-repo governance lessons:
- Fix the source, not the installed copy. The conflicts spanned two independently versioned repos; patching only the install directory means the next reinstall reverts everything. Every fix landed in both repos' sources.
- Cross-repo deferrals must be conditional. Hard-coding "defer to idea-to-spec" breaks in environments where it isn't installed. Every clause reads "if installed, defer; if not, continue but flag the scope difference."
- When two terms collide, look for a shared standard first. If the underlying format is the same, declaring a standard beats drawing a boundary.
One small surprise during the repair: inspecting the install topology revealed that the new skills' global install directories were junctions pointing straight at the repo source — edit the source, and it's live everywhere instantly. The "source-as-deployment" structure for a solo multi-repo developer had grown by itself.
20. Coexist or merge?
The final question: should the two repos be merged into one complete body?
My decision: coexist, don't merge. Three reasons:
- Different audiences. goal-workflow-designer is published and self-sufficient; many users want /goal and nothing else. Merging would force the whole spec pipeline on them.
- Different lifecycles. One side is iterating at a stable 0.2.x; the other hasn't shipped 0.1. Coupled, every breaking change in the new repo would drag down the stable repo's users.
- Something better than merging already exists: a shared standard (the five-element format) + conditional mutual deferrals + the same routing table in both READMEs. The relationship is compiler and runtime — spec-sonar compiles specs into G*.md; goal-workflow-designer's KICK-OFF executes them. Each is valuable alone; together they form the full pipeline.
The one discipline to hold: the five-element format is the contract between the two repos. Changing it on either side is a cross-repo breaking change, requiring synchronized version bumps.
Interlude: the tool missed its own dark zone
The first real convergence run after the package shipped (a marketing-funnel spec) surfaced two user confusions: the Q&A rounds arrived as plain text (no native Claude Code selector window), and the raw <STATE> JSON block was mistaken for "the debris of a failed trigger."
The root cause is ironic. The SKILL.md had hard-coded the lowest-common-denominator text format — the correct answer for claude.ai's plain chat, but "interaction style must adapt to the environment" had never been written into the spec. The tool built to detect unstated requirements had an unstated requirement of its own.
The control group sat right next door: the goal skill says "Use AskUserQuestion progressively" from day one, and never had this problem. The behavioral difference between the two skills wasn't model mood — it was spec difference. Which once again validates the behavioral-contract philosophy: the model executes the contract faithfully, and whatever the contract lacks, the behavior lacks.
The fix (v0.1.2): a new "Step 0: environment detection & interaction mode." In Claude Code, enumerable questions prefer the native selector and STATE persists to a file instead of the chat; in plain-chat environments, fall back to text mode with the STATE block always labeled "system bookkeeping — safe to ignore." Plus a hard-coded three-level degradation chain: native selector → on failure, structured text options (reply with a single letter A/B/C) → no tool at all, pure text. And a mandatory one-line human progress display every round.
A boundary worth stating: the selector's UI rendering, option exclusivity, the automatic "Other" escape hatch, and answer return are all native harness capabilities — the skill never worries about them. But "what to do when the tool fails" is model discretion — unless it's written into the spec. The degradation chain reclaims exactly that discretion.
The principle, in one sentence: bookkeeping is for the system; progress is for the human.
21. Thinking patterns added in Part 2
Part 1 accumulated eight reusable patterns. Part 2 adds seven:
9. Pre-adjudication. Make every design decision at "compile time"; the executor only follows the letter. A weak model's reliability comes not from pretty formatting but from having its degrees of freedom spent before it gets the task.
10. The cold-start test as the pass bar. An artifact is acceptable not when its author is satisfied, but when a zero-context, weakest-tier executor can answer the four questions. If it can't — rewrite the artifact, don't upgrade the executor.
11. Give the executor a legal "I don't know" exit. Without a BLOCKED protocol, models fill gaps with hallucination. An explicit stuck-report format beats any "please be honest" exhortation.
12. Conflict as a feature. Install into a real environment and run conflict analysis; every hit is free design feedback. The tool's first real-world catch was my own repos — more persuasive than any synthetic example.
13. Fix the source, not the copy. Anything that gets "installed somewhere" must have fixes land in its version-controlled source, or the next deployment undoes them.
14. On a name collision, look for the shared standard first. When two concepts collide, compare their underlying structures. A shared standard is a stronger resolution than naming isolation.
15. Interaction style is part of the spec. How to ask is not model discretion. Which interaction primitive a skill uses per environment (native selector / structured text options / plain text), and how it degrades on failure, belong in the behavioral contract — or you'll deliver the worst experience on the best platform.
Epilogue: dogfooding all the way down
Looking back, the most consistent pattern in this whole process is the tool relentlessly eating its own dog food:
- The design itself was converged using spec-sonar's own process (Part 1, section 11).
- The tool's first audit caught its own schema drift.
- The tool's first real conflict report caught conflicts between my own two repos.
- And that conflict report itself became an official example file in the repo.
For a tool that claims to find "what you don't know you don't know," the best validation is to keep pointing it at itself. So far, it has found something every single time.
← Back to Part 1 · Repos: spec-sonar × goal-workflow-designer