Story 22.7 is Epic 22's acceptance layer. Pass 1 covers elasticsql and softclient4es-web only — softclient4es-arrow and softclient4es-jdbc cannot compile until core 0.24.0-SNAPSHOT and a matching softclient4es-extensions snapshot are published, so the execution matrix, the capability declarations and the version-matrix doc rows are deferred to a pass 2 (listed at the bottom).
What pass 1 delivers
The corpus replay becomes a SERIES. Story 21.6's CorpusReplaySpec is extended, not forked: a second baseline (baseline-pre-epic22.csv, measured at 40c8c63e — the first parent of the first Epic-22 merge, verified both ways), a tracked series.csv with one row per measured tree, the epic22 and rejected_by_design owners, and a code-pinned scoring partition of the twelve corpus statements Epic 22 owns.
The measured headline:
[22.7] corpus replay: SCORES 64/99 (was 56 after Epic 21, 12 before it); 64/75 of the statements
we intend to answer; 24 capability probes excluded from scoring; Epic 22 rows: 8 of 12 scored
fixed; stories 22.2 / 22.3 / 22.6 corpus credit: 0 / 0 / 0. 91 PARSE — the 27-row difference is
never counted.
Both denominators, always; the three zero-credit stories named in the same breath, because no captured BI statement uses their constructs and their evidence is the exact-oracle and DuckDB-oracle suites, not the corpus.
Two of the twelve rows are deliberately NOT scored. tableau.mysql.w1.019 and tableau.sql92.wx.009 wrap a fully-quoted qualifier inside the derived body, and every merged sibling witness executes a bare index name — so nothing anywhere has measured that spelling. They are epic22 / residual with a code pin whose failure message says what to do when the measurement lands. Not fixed (a declaration whose only evidence is an unrun test), and not a local: defect slug (that would publish a failure nobody has seen).
Documentation. Two new reference sections — Subqueries and derived tables and Common table expressions — in documentation/sql/dql_statements.md and its web twin, the largest piece of the Epic-22 sweep that the two open docs PRs had not yet covered. Every published SQL statement in them is parse-probed as published.
Defects found and fixed here
- The scoreboard's historical number was derived from a baseline file, and a verdict file cannot answer a scoring question. It had already diverged: 81 statements parsed at the pre-Epic-22 tree, 60 of them non-probe, against a published Epic-21 headline of 56. The summary now reads its history from
series.csv and says so.
tableau.sql92.wx.012 is refused for its missing correlation name, not for ROWNUM — ROWNUM resolves as an ordinary identifier and round-trips, which is the hazard, not the refusal. The pin's text carried the refuted claim.
select.json: syntax[23]'s bare "(parentheses optional)" read as licensing the whole-operation wrap, which is rejected; and limitations[] never said that a correlated subquery needs the relational engine. All 31 syntax[] lines hand-probed — command syntax[] is never probed by the build (HELP-1a).
- A stale owner with zero rows (
epic22a_derived_table) left alive in TableauLiveReplaySpec.
known_limitations.md used elastic as the example catalog qualifier in four places, and dql_statements.md in eight — banned since story 20.3, because the qualifier a BI tool emits is the cluster name.
New engine limitations found by the documentation probe, now published
- 🔴 A scalar or quantified subquery is accepted only as the RIGHT operand of its comparison.
WHERE (SELECT COUNT(*) …) > 5 is rejected as Unbalanced parentheses — a message naming nothing — while WHERE 5 < (SELECT …) is accepted. Published with the rewrite in both repos and in the help corpus. The message itself is unfixed and unowned.
- A CTE may not shadow the index it reads (
WITH orders AS (SELECT … FROM orders)), refused by name — a planned doc sentence claiming otherwise was false.
- A derived table's correlation name takes no column list (
AS d (x)).
- The
NOT IN + NULL rule has a carve-out that fails the other way: the engine detects the NULL by re-running the body with an IS NULL filter, and under a GROUP BY body Elasticsearch's terms aggregation drops the missing-value group, so the NULL is invisible and rows come back that the rule says should not. Now documented on all three surfaces.
Verification
sql/test 1330/1330 · CorpusReplaySpec 17/17 · core/testOnly *HelpCorpusSpec *ReplKeywordsSpec 33/33 after core/clean · CI lint line byte-for-byte green · + compile green · web npm ci + astro build 46 pages with dist/** greps confirming the new sections rendered.
Twelve gate mutations, all RED, control green either side — including the three added after an independent review: G9 now reads story 22.1's own literals (it compared against a local copy, which could only ever agree with itself), the published total is pinned in compiled code (a two-cell CSV edit previously passed every gate but the one the README says can never be the guard), and the pre-Epic-22 no-regression gate is defended by a cross-file invariant rather than a row count.
ParserSpec ×10: 842 ms → 827 ms median (ranges 807–878 → 792–878, overlapping ⇒ no signal). Apple-silicon macOS, Zulu 11. No timing assertion.
Deferred to pass 2
- Raise
supportsSubqueriesIn{Comparisons,Exists,Ins,Quantifieds} on both transports (lead-ruled) plus the agreement-spec rows.
- The arrow fixture widening and the corpus acceptance rows E1–E12 / sidecar rows; E5 measured and pinned, then the two held-back rows resolved.
- The sibling execution matrix across five clients and four majors.
- The jdbc testkit row and the ANSI-92 pin text.
- The version-matrix documentation rows — claims the matrix has not yet produced.
- The epic close-out issue; this pass does not complete the epic.
Story 22.7 is Epic 22's acceptance layer. Pass 1 covers elasticsql and softclient4es-web only —
softclient4es-arrowandsoftclient4es-jdbccannot compile until core0.24.0-SNAPSHOTand a matchingsoftclient4es-extensionssnapshot are published, so the execution matrix, the capability declarations and the version-matrix doc rows are deferred to a pass 2 (listed at the bottom).What pass 1 delivers
The corpus replay becomes a SERIES. Story 21.6's
CorpusReplaySpecis extended, not forked: a second baseline (baseline-pre-epic22.csv, measured at40c8c63e— the first parent of the first Epic-22 merge, verified both ways), a trackedseries.csvwith one row per measured tree, theepic22andrejected_by_designowners, and a code-pinned scoring partition of the twelve corpus statements Epic 22 owns.The measured headline:
Both denominators, always; the three zero-credit stories named in the same breath, because no captured BI statement uses their constructs and their evidence is the exact-oracle and DuckDB-oracle suites, not the corpus.
Two of the twelve rows are deliberately NOT scored.
tableau.mysql.w1.019andtableau.sql92.wx.009wrap a fully-quoted qualifier inside the derived body, and every merged sibling witness executes a bare index name — so nothing anywhere has measured that spelling. They areepic22/residualwith a code pin whose failure message says what to do when the measurement lands. Notfixed(a declaration whose only evidence is an unrun test), and not alocal:defect slug (that would publish a failure nobody has seen).Documentation. Two new reference sections — Subqueries and derived tables and Common table expressions — in
documentation/sql/dql_statements.mdand its web twin, the largest piece of the Epic-22 sweep that the two open docs PRs had not yet covered. Every published SQL statement in them is parse-probed as published.Defects found and fixed here
series.csvand says so.tableau.sql92.wx.012is refused for its missing correlation name, not forROWNUM—ROWNUMresolves as an ordinary identifier and round-trips, which is the hazard, not the refusal. The pin's text carried the refuted claim.select.json:syntax[23]'s bare "(parentheses optional)" read as licensing the whole-operation wrap, which is rejected; andlimitations[]never said that a correlated subquery needs the relational engine. All 31syntax[]lines hand-probed — commandsyntax[]is never probed by the build (HELP-1a).epic22a_derived_table) left alive inTableauLiveReplaySpec.known_limitations.mdusedelasticas the example catalog qualifier in four places, anddql_statements.mdin eight — banned since story 20.3, because the qualifier a BI tool emits is the cluster name.New engine limitations found by the documentation probe, now published
WHERE (SELECT COUNT(*) …) > 5is rejected asUnbalanced parentheses— a message naming nothing — whileWHERE 5 < (SELECT …)is accepted. Published with the rewrite in both repos and in the help corpus. The message itself is unfixed and unowned.WITH orders AS (SELECT … FROM orders)), refused by name — a planned doc sentence claiming otherwise was false.AS d (x)).NOT IN+NULLrule has a carve-out that fails the other way: the engine detects theNULLby re-running the body with anIS NULLfilter, and under aGROUP BYbody Elasticsearch'stermsaggregation drops the missing-value group, so theNULLis invisible and rows come back that the rule says should not. Now documented on all three surfaces.Verification
sql/test1330/1330 ·CorpusReplaySpec17/17 ·core/testOnly *HelpCorpusSpec *ReplKeywordsSpec33/33 aftercore/clean· CI lint line byte-for-byte green ·+ compilegreen · webnpm ci+astro build46 pages withdist/**greps confirming the new sections rendered.Twelve gate mutations, all RED, control green either side — including the three added after an independent review: G9 now reads story 22.1's own literals (it compared against a local copy, which could only ever agree with itself), the published total is pinned in compiled code (a two-cell CSV edit previously passed every gate but the one the README says can never be the guard), and the pre-Epic-22 no-regression gate is defended by a cross-file invariant rather than a row count.
ParserSpec×10: 842 ms → 827 ms median (ranges 807–878 → 792–878, overlapping ⇒ no signal). Apple-silicon macOS, Zulu 11. No timing assertion.Deferred to pass 2
supportsSubqueriesIn{Comparisons,Exists,Ins,Quantifieds}on both transports (lead-ruled) plus the agreement-spec rows.