← Blog

Graft v3.9: Quality Polish

4 min read
graftcompilerllmadversarial-debateclaude

Graft is a domain-specific language for defining LLM agent pipelines. The compiler takes .gft files and generates Claude Code harness structures — contexts, agents, hooks, and orchestration files. Development uses an adversarial debate harness where multiple AI agents independently analyze, critique, and converge before implementation.

v3.9 is the final v3.x release. Three rounds, ~9 agent calls, 26 new tests (890 total). Two long-standing items closed, zero MEDIUM/HIGH tech debt remaining. The v3.x series is complete.

What This Version Adds

Edge transforms on conditional edges. Since v3.3, transforms on conditional edges produced a SCOPE_TRANSFORM_CONDITIONAL warning — the compiler acknowledged them but didn't apply them. v3.9 implements full support. Transforms run after condition evaluation, before target execution:

edge Planner -> Router
  when(Router.output.type == "research"): Researcher
    | select(findings, confidence)
  when(Router.output.type == "ready"): Writer
    | filter(quality >= 0.8)
  else: Fallback

The ConditionalEdgeInfo interface bundles branches and transforms together. Multi-hop chains apply transforms per-hop independently — each hop evaluates its condition, then applies its transforms before passing data to the next hop.

Estimator diagnostic specialization. BUDGET_CHAIN_CYCLE and BUDGET_CHAIN_DEPTH replace the overloaded BUDGET_EXCEEDED code for chain-specific warnings. IDE tooling can now distinguish between actual budget violations and chain estimation diagnostics.

Fallback cost in worst-case estimation. For retry_then_fallback strategies, the worst-case estimate now includes the fallback node's cost.

TD-01 resolved: AST-based import-path filtering. The collectRenameLocations function's from\s+"([^"]*)" regex — flagged across 4 consecutive retros — replaced with getImportPathRanges() / isInImportPath() using AST-based offset checks.

The Debate That Mattered

R1: Transform ordering (A3-Skeptic, score 7). The critical question: when do transforms run relative to condition evaluation? If transforms run before the condition, the condition evaluates transformed data — wrong. If transforms run after target execution, the target receives untransformed data — also wrong. A3 flagged this ordering risk at score 7, while A2 proposed the ConditionalEdgeInfo interface at score 8. The converged design places transforms after condition evaluation and before target execution — the only correct position.

The reviewer found 2 missing tests: transform-on-cycle and transform+fallback alias interaction. Both were test-only gaps — the runtime handled these cases correctly. Fixed in 1 debug cycle.

R-PROC-19: Tech Debt Carry Limit

R-PROC-19 was proposed in the v3.8 retro: items carried across 3+ retros must be explicitly prioritized. TD-01 hit the 4-retro threshold and was mandated for inclusion in v3.9.

Result: TD-01 was resolved in a DIRECT round, merged with 2 other small items via R-PROC-12. Without R-PROC-19, TD-01 would likely have been deferred to v4.0. The carry-limit mechanism works.

v3.x Series: By the Numbers

10 versions. 44 rounds. ~119 agent calls. 514 tests added.

| Metric | v3.0 Start | v3.9 End | Delta | |--------|-----------|----------|-------| | Tests | 477 | 890 | +413 | | Ratchets | ~175 | ~235 | +60 | | Source lines | ~4,200 | 6,086 | +1,886 | | LSP features | 0 | 8 | +8 | | Error codes | 18 | 30+ | +12 | | Tech debt (HIGH/MED) | 0 | 0 | 0 | | First-try pass rate | -- | 88.6% | 39/44 |

Stats

| Metric | Value | |--------|-------| | Tests | 890 (26 new) | | Ratchets | ~235 | | Rounds | 3 (1 MEDIUM, 1 DIRECT, 1 TEST-ONLY) | | Agent calls | ~9 | | NEEDS_CHANGES | 1 (R1: 2 missing tests) | | Tech debt closed | TD-01 (carried 4 retros) | | Feature gaps closed | SCOPE_TRANSFORM_CONDITIONAL (since v3.3) |

Try It

npm install -g @graft-lang/graft
graft compile myflow.gft
graft check myflow.gft
graft run myflow.gft --input '{"query": "hello"}'

Source: github.com/JSLEEKR/graft

Built with Claude Opus 4.6 via Claude Code. April 2026.