| id | 240 | |
|---|---|---|
| title | cuelite phase 4 — drop cuelang.org and enable tinygo | |
| status | ✅ | |
| model | opus | |
| summary | With every surface flipped, delete cue/cuelite's CUE delegation and remove cuelang.org/go from go.mod; replace the tinygo-incompatible sync.Map.CompareAndDelete in internal/lint/runcache.go; get the standard-Go WASM build under the plan-215 budget (the tinygo build still fails on unimplemented os.* calls — criterion unmet); update the engine-api page and the layering map. | |
| depends-on |
|
Remove cuelang.org/go entirely. Make the WASM artifact fit
the plan-215 budgets on the standard-Go and tinygo toolchains.
Phase 4 of plan 218. It is reachable once surfaces A–D are flipped, so nothing delegates to CUE anymore.
This phase is sized opus, not sonnet. The original sonnet
estimate assumed task 1 was a delegation deletion. The phase-2
audit corrected that: the standing cuelang.org/... dependency
is the parser and AST, so task 1 is now writing a hand-rolled
CUE-subset parser and lexer (the grammar plus the underscore and
escape rules) and re-pointing the evaluator at it. That is the
largest and most error-prone task in the cuelite series, well
above the sonnet band.
- Replace the SYNTAX FRONTEND. After the phase-2/3 flips the only
remaining non-test
cuelang.org/...use is the parser and AST:compile.goimportscue/parser,cue/ast,cue/literal, andcue/token;eval.goimportscue/astandcue/token; andevalrow.go(the surface-C row evaluator, plan 239) imports all four. The evaluator already walks an in-house value model, so this task swaps the AST it walks. Write a hand-rolled CUE-SUBSET parser (the front-matter/row-expr grammar only: structs, fields, lists, the bounds and disjunction operators, comparisons, the singleif/forcomprehensions, the row-expr\(…)interpolation across the plain, raw, and multiline dialects, the+/*operators, calls, and string/number/bool/null literals with CUE underscore and escape rules) producing an in-house syntax tree, then re-pointcompileExpr/evalExprandparseRowExpr/evalRowat it.literal.Unquote,literal.ParseQuotes, and thetokenconstants are replaced by the new parser's own lexer. This is the last and largest CUE dependency to remove; it is the bulk of the phase. - Delete the CUE delegation from
cue/cueliteand removecuelang.org/gofromgo.modandgo.sum. Confirm no non-test file importscuelang.org/.... - Delete
internal/cuelitetest(or port its corpus to pure in-house self-tests with no oracle). Its non-test filescuelitetest.go(the schema/data oracle) andexpr.go(the surface-C row-expr oracle plan 239 added) importcuelang.org/gofor the direct-CUE oracle path, so they must go beforecuelang.org/gocan leavego.mod. Once every surface is flipped, the in-house path and the oracle are no longer two implementations to diff — the oracle's whole purpose ends — so the harness is removed rather than kept. Its oracle-backed test files (cuelitetest_test.go,fuzz_validate_test.go,bench_test.go,factor_gate_test.go, and the surface-Cexpr_test.go/expr_unit_test.go) go with it. - Migrate or delete the remaining TEST-ONLY
cuelang.org/...imports —go.modremoval needs the build graph clean of CUE in test files too, not only non-test files. The current set is:internal/schema/shortcuts_test.go(importscue/cuecontextto compile its shortcut CUE — rewrite against the cuelite façade or drop the direct-CUE assertion), andcue/cuelite's own oracle-backed tests (value_test.go,coverage4_test.go,coverage5_test.go,coverage6_test.goimportcue/cuecontext,cue/ast,cue/token, orcue/errors). Port each to in-house assertions or the new parser's tree before the module leaves. Re-rungrep -rl cuelang.org/ --include=*_test.gountil it is empty. - Replace
sync.Map.CompareAndDeletein runcache.go with a mutex-guarded map, red/green. - Get the standard-Go and
tinygo build -target wasm ./cmd/mdsmith-wasmbuilds passing; tighten size_test.go to the new budgets. - Update the
engine-api page
and the
cue/entry in the layering map.
-
cuelang.org/gois absent fromgo.modandgo.sum; NO file importscuelang.org/...— test files included (internal/schema/shortcuts_test.goandinternal/extract/cue_diff_test.gomigrated off CUE, and thecue/cuelitetests rebuilt on the in-house syntax tree), since a test-only import alone keeps the module in the build graph.cockroachdb/apdand protobuf are dropped as orphaned transitives. -
internal/cuelitetestis deleted; its corpus is ported to oracle-free in-house self-tests (cue/cuelite/corpus_test.go,rowcorpus_test.go), its fuzzers to engine-only smoke fuzzers (fuzz_test.go), and its CUE-relative factor gate to an absolute allocs/op guard (bench_test.go). No package importscuelang.org/...from a non-test file. - Standard-Go WASM artifact ≤ 18 MB — measured ~11.2 MB raw /
~2.8 MB gzipped;
cmd/mdsmith-wasm/size_test.goasserts the tightened ceilings (14 MiB raw / 4 MiB gzip). -
tinygo build -target wasm ./cmd/mdsmith-wasmsucceeds and is ≤ 8 MB. Theos.Chmod,os.SameFile, andos.Symlink/filepath.EvalSymlinkscalls are now behind build-tagged seams (plan 247).TestTinyGoWASMArtifactSizeBudgetasserts the 8 MB ceiling; thetinygo-wasmCI job enforces it. -
Capabilities()is unchanged —methods_test.go/smoke_test.goassert the WASM proxy advertises the same capability set as the native session. - All tests pass:
go test ./...(and-raceclean on the affected packages). -
go tool golangci-lint runreports no issues — the tools/go.mod golangci-lint needs Go ≥ 1.25.8; the dev container has 1.25.0, so the CIlintjob is the verifier, green on main.
The parser (task 1) emits an in-house syntax tree. It does not mimic
cue/ast. The cue/cuelite/syntax package defines node types. They use
the same names the three consumers already switched on. So re-pointing
compile.go, eval.go, and evalrow.go was a near-mechanical import
swap.
One divergence from CUE's tree is deliberate. Interpolation.Elts
carries already-decoded string fragments. The scanner decodes them
across the three dialects. So evalRowInterpolation reads them direct.
The token and literal calls map to the in-house token set,
syntax.Unquote, and syntax.IsBytesLiteral.
Conformance was proven before the oracle was deleted. The frontend was
flipped first. The internal/cuelitetest differential harness then ran
green over the corpus, the fuzz seeds, the real schemas, and the
row-expr suite. Only then was the harness deleted, with its corpus
ported to engine-only pinned tests.