Baseline vs. Full Conversion — the separation contract

Companion to /CLAUDE.md. Defines what lives where, why, and the rules that keep the converter-improvement loop and the full-stdlib goal from colliding again.

The three things

  1. Baseline stdlib — src/core/<pkg> Small, hand-finished, compiling subset of the Go standard library. This is what the behavioral tests and converter-improvement loop build against. It must always stay green.

  2. Full auto-conversion — src/go-src-converted/ (target location) The entire Go standard library (~305 packages) auto-converted by go2cs -stdlib. The ultimate goal, but work in progress — does not all compile yet.

  3. Runtime — src/core/golib/ Hand-written C# runtime (slice, map, channel, @string, builtin, ж<T>, type aliases). Shared by both baseline and full conversion. Never auto-overwritten — some of it (builtin, unsafe helpers, assembly-backed routines) can never be produced by transpilation.

Why they must stay separate

Both baseline and full emit into namespace go with <pkg>_package static partial classes. Referencing both from one C# project produces duplicate-type collisions. So they are kept in separate directories and never referenced together by a single project.

How the collision happened (history)

Commit Date Event
9792eeea2 2020-07-09 Hand-converted stub created at src/gocore/<pkg> (Tour-of-Go support).
(many) 2020–2025 Stub maintained/refined for years; it was the working library.
ba6fef6c9 2025-03-08 src/gocore renamed → src/core (path change only).
3426298eb 2025-05-05 01:51 Last clean baseline. Stub compiles; tests green.
6ca1c45b7 2025-05-05 01:59 “Initial standard library conversion” — full stdlib written on top of src/core, overwriting the hand-finished packages (2,359 files, +508k lines).
cc14584c7 2025-05-11 Full-conversion work; tagged full-conversion-2025-05.
2026-06-25 2026-06-25 Separation restored: full conversion relocated to src/go-src-converted/; old stub restored into src/core; converter fixes; green baseline.

The mistake was writing the full conversion into the same directory as the baseline instead of a separate one. “All 305 packages converted successfully” meant the transpiler did not crash — not that the emitted C# compiles. The overwrite replaced compiling fmt/time/etc. with large machine-generated versions, which stalled the test loop.

The project was originally designed with this separation (gocore manual subset + go-src-converted full auto-output), so restoring it realigns with the original design.

How it was resolved (2026-06-25)

The contract (rules going forward)

  1. src/core/<pkg> is curated and must compile. Treat it as hand-owned source. Do not bulk-overwrite it with -stdlib output.
  2. src/go-src-converted/ is the full-conversion target. All go2cs -stdlib runs write here via -go2cspath. It may be regenerated wholesale; nothing hand-edited lives here long-term (fixes belong in the converter or, for out-of-band pieces, in golib).
  3. golib is shared and never auto-generated. Both trees reference src/core/golib/golib.csproj.
  4. Promotion go-src-converted → core is DEFERRED (strategy correction, 2026-07-01). Earlier work promoted packages into core as they went green (compiling). That was premature — compiling is not operating. Promotion should happen only once a package’s converted Go unit tests pass (Phase 4), and may not be needed at all (see The corrected end-state below). Until then, core stays the small bootstrap stub the behavioral tests build against (chicken-and-egg — the tests need a working library to run, and go-src-converted compiling doesn’t yet mean it works). sync/atomic already living in core is fine — it remains a useful stub. Do not promote further on the basis of a clean compile. The converter is never pointed at the baseline directory.
  5. The canonical MANUAL files live in core and are copied BACK into go-src-converted. Files marked [module: GoManualConversion] (the converter skips re-converting them) and hand-written *_impl.cs files are hand-owned in src/core/<pkg>. For a full-conversion milestone to be complete, these must be overlaid into their matching src/go-src-converted/<pkg> locations — that overlaid tree (auto-output
    • manual/asm stubs) is the real final state. overlay.sh already re-copies the src/core manual files after the cs/csproj copy; during these final compiling stages, do this religiously.

The corrected end-state (2026-07-01) — compile first, operate later

The milestone is a clean C# COMPILE of the whole overlaid go-src-converted (auto-output + the manual/*_impl.cs/asm stubs) — not an operational one. Operational correctness is Phase 4 (converting + passing the Go unit tests). Getting there, for runtime:

So the loop no longer stops at the S1/CS0030 “architectural wall” — it sorts: convert the native-type ops, apply the managed-referent model, and stub the genuine raw-metal dragons with GoManualConversion.

Once the whole stdlib compiles and the converted Go tests pass, a versioned build can ship to NuGet; at that point the chicken-and-egg is gone and core can be dropped (behavioral tests reference NuGet) or replaced with prior operational go-src-converted source — TBD.

Regenerating the full conversion

Current Go converter (authoritative flags in src/go2cs/main.go):

# Whole stdlib into the separate target:
go2cs -stdlib -comments -go2cspath <repo>/src/go-src-converted

# Specific packages only (used when greening a closure bottom-up):
go2cs -stdlib -comments -go2cspath <repo>/src/go-src-converted fmt strings io sort time

Always pass -comments for stdlib conversion. It defaults off, but the converted C# is a derivative work — the per-file // Copyright … The Go Authors … BSD-style license header must be preserved, and the Go doc-comments keep the output readable. Without the flag, headers and comments are stripped.

-parallel 1..4 controls concurrency; output .csproj references are generated from detected imports.

Note on the <go2cspath>/core subdir: the stdlib converter writes packages to <go2cspath>/core/<pkg> (a hardcoded core subdir). To regenerate cleanly into src/go-src-converted you must either point -go2cspath so that subdir lands there, or convert to a temp dir and move. Don’t let it overwrite the baseline src/core packages.

The old stub as a fallback / reference

The last clean stub (3426298eb) is the source of today’s baseline. To inspect or recover individual files:

git worktree add ../go2cs-stub-ref 3426298eb      # browse the last clean baseline
git show 3426298eb:src/core/fmt/print.cs          # or per file

Stale tooling