diff --git a/carve_test.go b/carve_test.go index 5cbf0b3..9e71e0d 100644 --- a/carve_test.go +++ b/carve_test.go @@ -65,7 +65,12 @@ func TestToHTML_Table(t *testing.T) { if err != nil { t.Fatalf("ToHTML error: %v", err) } - if !strings.Contains(out, "") || !strings.Contains(out, "") || !strings.Contains(out, "") { + // A header cell carries scope="col". The expectation here used to be a bare + //
A1, which is what the engine emitted before the corpus grew the + // attribute; a hand-written expectation like this one is the part of the + // suite that cannot notice the artifact moving under it, which is why the + // corpus job exists beside it. + if !strings.Contains(out, "") || !strings.Contains(out, ``) || !strings.Contains(out, "") { t.Fatalf("expected table markup, got %q", out) } } @@ -116,29 +121,33 @@ type mismatchError struct{ out string } func (e *mismatchError) Error() string { return "unexpected output: " + e.out } // nativeCarveBin locates the native carve-rs CLI for byte-identical checks. -// It is skipped (not failed) when the binary is unavailable, so the suite -// still runs in environments without a carve-rs checkout. +// It is skipped (not failed) when no binary is named, so the suite still runs +// in environments without a carve-rs checkout - CI is one of them, and skips +// this check on every run. +// +// CARVE_BIN IS THE ONLY ROUTE, and the reason is what this check asserts. It +// says "the wasm renders what the native engine renders", which is a statement +// about ONE engine revision: the native side has to be the revision +// internal/wasm/REV names, or a mismatch says nothing about this module. The +// helper used to fall back to two hardcoded target/ paths and then to `carve` +// on PATH, none of which is that revision by construction - a long-lived +// checkout's target/ holds whatever it last built, on whatever branch it was +// on. +// +// It failed exactly that way while this rebuild was being prepared: a stale +// local build predating the header cell growing scope="col" reported a byte +// mismatch on tables against a wasm the corpus proved correct. A check that +// picks its own reference off the filesystem cannot tell "the wasm is wrong" +// from "the thing I found is old", and it reported the first. Skipping until a +// caller vouches for a binary is the honest default; the corpus job, whose +// reference is the spec, is the drift gate either way. func nativeCarveBin(t *testing.T) string { t.Helper() if env := os.Getenv("CARVE_BIN"); env != "" { return env } - candidates := []string{ - // Static-capable checkout (proto/div-label-fallback, the engine the - // committed wasm is built from) is preferred so the static byte-check - // can run; fall back to a plain main checkout for the interactive check. - "/tmp/carve-rs-static/target/release/carve", - "/media/mark/data/work/git/carve-rs/target/release/carve", - } - for _, c := range candidates { - if _, err := os.Stat(c); err == nil { - return c - } - } - if p, err := exec.LookPath("carve"); err == nil { - return p - } - t.Skip("native carve binary not found; set CARVE_BIN to enable byte-identical check") + t.Skip("CARVE_BIN not set; build the carve CLI from the carve-rs revision in " + + "internal/wasm/REV and point CARVE_BIN at it to enable the byte-identical check") return "" } diff --git a/corpus_population_test.go b/corpus_population_test.go index 4538873..9811d09 100644 --- a/corpus_population_test.go +++ b/corpus_population_test.go @@ -28,12 +28,21 @@ import ( // markup-carve/pandoc-carve. // // So the reference is the corpus's SOURCE, not the corpus. tests/corpus is -// generated from the `::: compare` blocks in docs/examples/{core,extensions, -// edge-cases}.md (see tests/corpus/README.md and scripts/generate-corpus.mjs in -// the spec repository); the generator refuses to write a corpus where the two -// disagree. Both live in the same spec checkout CI already clones, one -// directory away from CARVE_SPEC_CORPUS - the same route corpus_ast_test.go -// already uses to read resources/ast-schema.json. +// generated from the `::: compare` blocks in resources/examples/{core, +// extensions,edge-cases}.md (see tests/corpus/README.md and +// scripts/generate-corpus.mjs in the spec repository); the generator refuses to +// write a corpus where the two disagree. Both live in the same spec checkout CI +// already clones, one directory away from CARVE_SPEC_CORPUS - the same route +// corpus_ast_test.go already uses to read resources/ast-schema.json. +// +// THE PAGES MOVED, AND THIS HELPER DID NOT. They lived under docs/examples/ +// until markup-carve/carve#1194 made them generated sources and filed them +// beside the other generator inputs in resources/. Because the path is read at +// run time and the miss is fatal, the corpus job stopped comparing anything at +// all rather than comparing against a stale count - the right failure, but it +// masked every real divergence behind it until the path moved too. The route +// corpus_ast_test.go takes to resources/ast-schema.json is now the same route +// this helper takes, which is one fewer place for the two to disagree. // // Counting the source rather than recording a number also means there is no // literal left to go stale: adding an example moves the expectation on the next @@ -59,7 +68,7 @@ var compareMarkerRun = regexp.MustCompile(`^:{3,}`) // keeps the two counts equal by construction instead of by luck. func declaredCorpusSize(t *testing.T, corpusDir string) int { t.Helper() - examplesDir := filepath.Join(corpusDir, "..", "..", "docs", "examples") + examplesDir := filepath.Join(corpusDir, "..", "..", "resources", "examples") declared := 0 for _, page := range specExamplePages { path := filepath.Join(examplesDir, page) @@ -110,7 +119,7 @@ func requireWholeCorpus(t *testing.T, corpusDir string, got int, what string) { declared := declaredCorpusSize(t, corpusDir) if got != declared { t.Fatalf("%s: %d, but the spec's example pages declare %d. Every ::: compare block in "+ - "docs/examples/{core,extensions,edge-cases}.md becomes one corpus pair, so a difference "+ + "resources/examples/{core,extensions,edge-cases}.md becomes one corpus pair, so a difference "+ "means the corpus at %s is not the one those pages describe - a truncated or stale "+ "checkout, a wrong CARVE_SPEC_CORPUS, or a corpus that needs regenerating "+ "(npm run corpus:build in the spec repository). It does not mean this run was clean.", diff --git a/internal/wasm/REV b/internal/wasm/REV index 6f0c905..fb1cc20 100644 --- a/internal/wasm/REV +++ b/internal/wasm/REV @@ -1 +1 @@ -9130a7c70249a44bc68bf39eab30b5f92ae1d1b7 +98de7874ad2e81f69e57764562c83f4918522ac2 diff --git a/internal/wasm/carve.wasm b/internal/wasm/carve.wasm index 46c0199..e30244d 100755 Binary files a/internal/wasm/carve.wasm and b/internal/wasm/carve.wasm differ diff --git a/internal/wasm/carve.wasm.sha256 b/internal/wasm/carve.wasm.sha256 index a84b442..29cd143 100644 --- a/internal/wasm/carve.wasm.sha256 +++ b/internal/wasm/carve.wasm.sha256 @@ -1 +1 @@ -14c52b3ce196ec36b1352ffadaaa4df07f67344ceb49c0a501ebb5fe266330bd carve.wasm +fd3691e29e6e841282a14cab1f2aa4ec419b52615e3f3422fcee23284fb583c9 carve.wasm
A1