Logo Xantham

Toolchain: Fantomas / Fabulous.AST version constraints (breadcrumb)

Status: known blocker for the LEGACY monolith path only; RESOLVED for partitioned emission. The upgrade paths below remain verified dead ends (2026-06-30) — and are now unnecessary.

CORRECTION (2026-07-03, byte-level diagnosis on the partitioned units): the "residual ~34 error" class was TWO defects, and only one was Fantomas's.

  1. The <deprecated>/<br/> doc-comment cascade was OURS, not Fantomas's. Upstream JSDoc arrives with \r\n; normalizeDocString (TypeRender.Render.fs) split on "\n" alone, leaving a bare \r MID-LINE once <br/> was appended (...keywords:\r<br/>). The F# lexer treats the lone \r as a line terminator, so the remainder fell out of the /// comment and parsed as code — FS0010 at an apparently-innocent doc line. That is why the class "did not isolate" (minimal repros typed by hand carried no \r) and why <br/> looked load-bearing (its removal moved the invisible \r). Fixed at the render tier (CR normalization in normalizeDocString); the class is gone on BOTH paths.
  2. The multi-line generic layout bug (closing > outdented one column) IS Fantomas 7.0.1's — but it only triggers when an annotation exceeds the line width. Partitioned emission avoids it entirely: Gen.runWith { FormatConfig.Default with MaxLineLength = 100000 } (Emission.fs) keeps long annotations on one line. The earlier "raising MaxLineLength is cosmetic" verdict was measured before the \r defect was separated — with \r fixed, the wide format eliminates the layout half too. The legacy monolith keeps the default width (gate stability) and retires with Phase 1.

The pin

The generator (src/Xantham.Generator) formats its output via Fabulous.AST 2.0.0-pre06, which pulls Fantomas.Core 7.0.1 transitively. Fantomas is not a direct reference.

Fabulous.AST 2.0.0-pre06  ->  Fantomas.Core [7.0.1]   (exact/bracketed pin)

Why you cannot simply upgrade Fantomas

There is a real formatting bug in Fantomas 7.0.1: a multi-line generic type used as a tupled abstract-method parameter (e.g. workflowName: U2<...> * ...) can be laid out so the closing > lands at an offside-invalid column, and <deprecated>/<br/> doc-comment blocks in a large module rec trip F#'s XML-doc / offside parser (FS0058 / FS0010 / FS0550 cascades). The upstream fix is Fantomas 8.0.0-alpha-003 (issue #3043: "multiline type inside a signature gets extra indentation to avoid compiler error").

That fix is unreachable from this project. Verified:

Attempt

Outcome

Bump Fabulous.AST to pre07 / pre08

Both also hard-pin Fantomas.Core [7.0.1] — no Fabulous.AST release ships against Fantomas 8. pre08 additionally requires FSharp.Core >= 10.1.300, which this project cannot resolve (a transitive constraint caps it at 10.0.101) → TypeInitializationException: Fabulous.AST.TypeLongIdent at runtime.

Override Fantomas.Core -> 8.0.0-alpha-* directly, keep Fabulous.AST pre06

MissingMethodException: BindingNode..ctor at runtime — Fabulous.AST is compiled against the exact Fantomas 7.0.1 SyntaxOak ABI; the BindingNode constructor signature changed in Fantomas 8. ABI-locked.

Raise Fantomas MaxLineLength (via CodeFormatter.FormatOakAsync with a custom FormatConfig)

Cosmetic only — collapses the multi-line layout but the net error count is unchanged (committed 34/strict-off-10 == MaxLineLength=1024 34/strict-off-10). Reverted.

Remove the inserted <br/> doc-line joins

Catastrophic<br/> is load-bearing for multi-line doc structure; removing it merges doc lines and explodes to ~3200 errors.

What the residual errors actually are

Against a faithful FS-error harness the fresh agents@0.17.1 surface shows 34 errors under default (F# 8+) settings, 10 under --strict-indentation- / LangVersion=7.0:

When to revisit

Revisit only when a Fabulous.AST release ships built against Fantomas ≥ 8.0.0 (check its .nuspec Fantomas.Core dependency range — it must not be [7.0.1]). At that point:

  1. Bump Fabulous.AST in src/Xantham.Generator/Xantham.Generator.fsproj.
  2. Expect a small API migration — pre08 already renamed AbstractMemberModifiers -> MemberDefnModifiers (one line in Generator/TypeRender.Render.fs, Documentation.renderForAbstractMember).
  3. Ensure FSharp.Core can resolve to whatever the new Fabulous.AST requires (pre08 wanted >= 10.1.300) — otherwise you get TypeInitializationException at runtime.
  4. Re-run the FS-error harness; the strict-indentation + doc-comment cascades should clear.

Type something to start searching.