[mache-cc1a70][mache-cc631a] Validate against an LLO candidate, and check the artifact not just the producer - #634
Merged
Conversation
jamestexas
enabled auto-merge (squash)
August 21, 2026 19:52
…n the gated tests mache has exactly one leyline override, MACHE_LEYLINE_BINARY, which production's ResolveBinary consults before every pinned tier (#574). The gated test resolvers did not: lltest called leyline.CachedPinnedBinary directly, so they resolved the pin or SKIPPED regardless of what the override said. The consequence was that mache could not be validated against an unreleased ley-line-open at all. Pointing the override at a release candidate moved `mache build` onto the candidate while TestLeylineSchema_MatchesPinnedBinary and every other pinned gate went on testing the pin — or skipped, since the conformance test additionally asserts pin == leylineSchemaVersion before re-deriving. The only available sequence was release, discover drift, fix, which is the sequence the pin exists to replace. decideBinary now checks leyline.OverrideBinary first, exactly as production does. Unset, nothing changes: same cache resolution, same skip, still never downloads. Set, the resolver reports that binary's own version and marks the run as an override, so the conformance test turns its pin assertion into a report and says a diff is the candidate's re-derivation worklist rather than drift from the pin. A named-but-unusable override FAILS rather than skips. Skipping is right for the default path — no cached pin means there is nothing to test — but naming a binary states an intent, and silently testing nothing would report success for a validation that never ran. That choice is returned as data (decision.fatal) rather than made inline, because it is unobservable through a real *testing.T whose Fatalf terminates the test asserting it; reporting is then one visible branch behind a four-method TestingT that *testing.T already satisfies, so no call site changes. Two duplications removed rather than added, both surfaced by the smell gate against a first version of this change that invented a SECOND env var and a second version parser: - leyline.OverrideBinary is exported instead of reimplemented. Its contract was already the one wanted here — explicit opt-in, logs on use, fails loudly on a bad path, never a fallback. - leyline.ExtractSemver is exported instead of copied. "Read leyline's version" now has one implementation. Also adds an end-to-end gate that runs mache's write path against an arena a REAL leyline produced rather than a fixture mache shaped itself. It runs against the pin by default, so it is a standing check on the shipped projection, and against a candidate under the override. Built ley-line-open's projection-v4 branch and ran both against it. The complete re-derivation worklist, measured rather than asked for: _ast + blob_ord INTEGER nodes parent_id TEXT -> GENERATED ALWAYS AS (...) VIRTUAL node_defs + node_kind, start_byte, end_byte, start_row, start_col, end_row, end_col node_refs + the same seven Nothing removed; _ast keeps every span column, so existing fallbacks stay valid. The occurrence columns carry the same names as _ast, so graph.RefRangeOf can read a span off node_refs instead of joining the 3.15M-row _ast table. The generated expression the real binary emits is byte-identical to the one implemented in mache-bc6ca3, and the producer e2e reproduces that bead's failure exactly — `cannot INSERT into generated column "parent_id"`. That branch also reports version 0.18.2, byte-identical to the release whose schema it changes, so the exact-version pin accepts it. Filed upstream as ley-line-open-cbd3c9. Every new assertion falsified by mutation.
…clares Nothing read _meta.projection_schema_version — grep returned zero hits. mache validated the leyline BINARY by exact version pin and the artifact not at all, so a .db that was copied, cached, or built by a different leyline was accepted unchecked. The pin alone is demonstrably insufficient, confirmed by building the thing rather than by reading code: ley-line-open's projection-v4 branch reports `leyline 0.18.2 (open)` — byte-identical to the release whose schema it changes — so leylineVersionMatchesPin accepts it while it emits projection-v4. Filed as ley-line-open-cbd3c9. Reading the shape the FILE declares closes that, because it is a property of the artifact rather than of whatever claimed to produce it. ProjectionVersion reads what the file declares; warnUnknownProjection runs at OpenSQLiteGraph as one indexed single-row lookup — constant cost, so it does not disturb Open's laziness guarantee (mache-b094fa). It WARNS rather than refusing. Every bump so far has been additive for readers — v4 adds columns and converts one to generated, removing nothing, verified against a real v4 arena — and mache's readers already probe per column via ColumnExists. A hard failure would reject arenas mache can in fact read, including for library callers assembling many projections at once, where one newer shard would sink the whole corpus. When a projection appears that mache genuinely cannot read, that is the moment to refuse it by name, the way RequireProps refuses exactly the stale-props case and nothing else. Absence is the common case, not an error, and this was checked rather than assumed: v0.18.0 / v0.18.1 / v0.18.2 carry no PROJECTION_SCHEMA_VERSION constant, so every RELEASED leyline writes an arena with no projection row, as does `mache build`. A row present but empty also reads as undeclared — the DDL is `value TEXT NOT NULL`, and NOT NULL is not non-empty. That case was found by mutation: `return v, true` survived the first version of the test. Every new assertion falsified by mutation.
jamestexas
force-pushed
the
feat/mache-cc1a70-rc-validation
branch
from
August 21, 2026 20:15
4e40f2c to
d5425af
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes
mache-cc1a70andmache-cc631a. Together they make "validate mache against an ley-line-open release candidate, before either side ships" possible — which it was not.1. The gated tests ignored the override production already honours
mache has exactly one leyline override,
MACHE_LEYLINE_BINARY, which production'sResolveBinarychecks before every pinned tier (#574). Its contract is already the right one: explicit opt-in, logs on use, fails loudly on a bad path, never a fallback.internal/lltestdidn't consult it. It calledleyline.CachedPinnedBinary()directly, so it resolved the pin or skipped, regardless. Setting the override therefore pointedmache buildat a candidate whileTestLeylineSchema_MatchesPinnedBinaryand every other pinned gate went on testing the pin — or skipped, since the conformance test additionally assertspin == leylineSchemaVersionbefore re-deriving. The only sequence available was release → discover drift → fix, which is the sequence the pin exists to replace.decideBinarynow checksleyline.OverrideBinaryfirst, exactly as production does. Unset, nothing changes: same cache resolution, same skip, still never downloads. Set, the resolver reports that binary's own version and flags the run as an override, so the conformance test turns its pin assertion into a report and states that a diff is the candidate's re-derivation worklist rather than drift.A named-but-unusable override fails rather than skips. Skipping is right for the default path — no cached pin means there is nothing to test — but naming a binary states an intent, and silently testing nothing reports success for a validation that never ran. That choice is returned as data (
decision.fatal) rather than made inline, because it is unobservable through a real*testing.TwhoseFatalfterminates the test asserting it.I got the design wrong first, and the gate caught it
My first version invented a second env var (
MACHE_TEST_LEYLINE_BIN) and a second leyline-version parser.duplicate_definitionsflagged both against the existingMACHE_LEYLINE_BINARYandextractSemver. It was right — reinventing the override would have left two knobs with two contracts for one job. Nowleyline.OverrideBinaryandleyline.ExtractSemverare exported and reused; "read leyline's version" has one implementation.Also deleted
lltest.PinnedBinaryOrSkip, an exported wrapper whose only remaining caller was in its own file.untested_functionflagged it; deleting beat writing a test for a two-line delegation.2. mache validated the producer, never the artifact
grep projection_schema_versionreturned zero hits. mache gated on the leyline binary's version and checked the artifact not at all, so a.dbthat was copied, cached, or built by somebody else's leyline was accepted unchecked.The pin alone is demonstrably insufficient, and I confirmed that by building the thing rather than reading code: ley-line-open's projection-v4 branch reports
leyline 0.18.2 (open)— byte-identical to the release whose schema it changes — soleylineVersionMatchesPinaccepts it while it emits projection-v4. Filed upstream asley-line-open-cbd3c9.ProjectionVersionreads what the file declares;warnUnknownProjectionruns atOpenSQLiteGraphas one indexed single-row lookup — constant cost, soOpen's laziness guarantee (mache-b094fa) is undisturbed.It warns rather than refuses. Every bump so far has been additive for readers — verified against a real v4 arena — and mache's readers already probe per column via
ColumnExists. A hard failure would reject arenas mache can in fact read, including for library callers assembling many projections, where one newer shard would sink the corpus. When a projection appears that mache genuinely cannot read, that is the moment to refuse it by name, the wayRequirePropsrefuses exactly the stale-props case.Absence is the common case, checked rather than assumed: v0.18.0/v0.18.1/v0.18.2 carry no
PROJECTION_SCHEMA_VERSIONconstant at all, so every released leyline writes an arena with no projection row, as doesmache build. A row present but empty also reads as undeclared — the DDL isvalue TEXT NOT NULL, and NOT NULL is not non-empty. Mutation found that one:return v, truesurvived the first version of the test.What this immediately found
Built ley-line-open's projection-v4 branch and ran both new gates against it. The complete re-derivation worklist, measured rather than asked for:
_ast+ blob_ord INTEGERnodesparent_id TEXT→GENERATED ALWAYS AS (…) VIRTUALnode_defs+ node_kind, start_byte, end_byte, start_row, start_col, end_row, end_colnode_refs+the same sevenNothing removed;
_astkeeps every span column, so existing fallbacks stay valid. The occurrence columns carry the same names as_ast, sograph.RefRangeOfcan read a span straight offnode_refsinstead of joining the 3.15M-row_asttable — which answers a question I had open with LLO without needing a reply.The producer e2e reproduces
mache-bc6ca3's failure exactly (cannot INSERT into generated column "parent_id"), and the generated expression the real binary emits is byte-identical to the one implemented in #633.One baseline line, and why
god_filefires atcount >= 10 AND count > 3 * mu. Adding a few small files lowered the mean enough to pulltestdata/snapshots/medium-rust-rosary/src/dsse.rs— untouched, unchanged — over the bar. Grandfathered as a single line, consistent with the 24 sibling fixtures already in the baseline.The underlying problem is filed as
mache-f41b43: on main, 24 of 26god_filefindings are vendored testdata, so the fixture corpus is setting the threshold for mache's own code.fan_out_skewalready excludes generated code for exactly this reason.Verification
task testgreen (36 packages,TEST_RC=0),task smells0. Both gates pass against the pin and produce the worklist above against the candidate. Every new assertion falsified by mutation.🤖 Generated with Claude Code
https://claude.ai/code/session_01TtGhz7QzUHZi52a3FeNtEs