Skip to content

test: cover untested FR-044 reporting features across conformance corpora - #423

Merged
dmealing merged 3 commits into
mainfrom
fm/mo-1-1-0-report-coverage
Oct 11, 2026
Merged

dmealing merged 3 commits into
mainfrom
fm/mo-1-1-0-report-coverage

Conversation

@dmealing

@dmealing dmealing commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds test reports to MetaObjects' own test metadata that exercise FR-044 reporting features the existing corpora did not, and makes them pass in every port.

  • fixtures/persistence-conformance/canonical/meta.fitness.json: 9 reports become 21, plus one new entity (Session) so a two-hop path and a to-one @spine through it exist.
  • persistence-conformance: 10 new report query scenarios (19 report scenarios in all), run on all five ports against Postgres, and on SQLite, MySQL 8.4 and D1 wherever a port has those lanes (test(integration-tests): run report scenarios on SQLite, MySQL and D1 across ports #421).
  • api-contract-conformance/report/: model grows to four entities (Invoice, Category, Product, Sale) and nine reports (eight served); 6 new scenarios (22 in all), run on all five ports in the generated lane.
  • fixtures/cube-model/: goldens regenerated with the repo's own tool (12 new cubes, 1 new view); the live Cube lane covers the new reports on Postgres and, new in this branch, on MySQL 8.4 (all 21 served reports; seed.mysql.sql extended to match).
  • Derived artifacts (schema.postgres.sql, report-shapes.json, the C# Generated/*.g.cs, the Kotlin tables/*View.kt, cube goldens) were regenerated, not hand-edited.

Coverage inventory

Legend: P = persistence-conformance scenario, A = api-contract report/ scenario, C = cube-model corpus/live lane. "before" is what the corpora exercised at the start of this branch.

FR-044 element before after (new coverage)
@agg count / sum P A C unchanged
@agg avg P (BIGINT) + float/double/decimal (P report-numeric-types), currency (P report-time-grains-extended)
@agg min / max P (numeric) + timestamptz, naive timestamp, date (P report-time-min-max); float/double/decimal; currency; long (P report-all-types-breakdown)
@distinct count P + distinct uuid (P report-time-min-max, report-tph-base-filter)
measure.ratio P A C unchanged
@default on measures P (0 on empty totals / spine) + negative -1 on avg and 0 on decimal max over an EMPTY table (P report-negative-default); -1 under a no-match scope (P report-filter-operators); defaulted vs undefaulted sum on a spine (P report-multi-hop)
inline measure @filter operators eq, in (P) + isNull true/false, lt, a two-operator range, like ANDed with a segment, ne (P report-measure-filters, report-filter-operators); A filter-on-filtered-measure
segment.filter in a report P A C (one eq) + or of like and eq, in list (P report-filter-operators)
report @filter relative P30D + in, lt, ne, and with a segment, a filter no row meets (P report-filter-operators); relative PT1H mixed with ne (P report-all-types-breakdown); discriminator ne on a TPH base (P report-tph-base-filter)
dimension.attribute, to-one, one hop P A C unchanged
dimension.attribute, multi-hop @via none P report-multi-hop, A list-multi-hop, C
dimension.attribute through the entity's own reference none P report-self-reference, C
dimension.attribute over bool / enum / int-backed nullable enum / date / uuid string only P report-all-types-breakdown; A filter-boolean-dimension, filter-uuid-dimension, filter-on-string-dimension (like)
dimension.time grains month, week + day, quarter, year (P report-time-grains-extended, A list-two-grains), hour and date (P report-time-min-max); several grains of one column at once
relative-date filter value P30D + PT1H
@spine one hop + two hops (P report-multi-hop, A, C ProgramSessions view)
totals report, no dimensions P A C + numeric types, empty table, empty scope
TPH base as @from none P report-tph-base-filter

Port defects found

None in a product port. Every new scenario passed in all five ports once the fixture and the per-port test harnesses understood the new shapes. Harness gaps fixed (test code only, no shipped behaviour):

  • Seam lanes' in-memory report repositories: uuid operand coercion (Java) and the like operator (Python).
  • Java persistence runner: a field.date filter operand is parsed to LocalDate, as the other ports' runners already coerce to the column's native type.
  • C# persistence runner: the same coercion to DateOnly.
  • Kotlin SQLite lane: a field.date filter operand is coerced by the column type (SQLite spells a DATE column's type as TEXT), and the report-time-min-max seed spells its timestamps in the form the SQLite driver's date_string_format parses (seed only; expect blocks unchanged).
  • Engine lanes from test(integration-tests): run report scenarios on SQLite, MySQL and D1 across ports #421: the MySQL adopter tables gain the tables the new reports read (nodes, sessions, measurements, auths, all_types); the api-contract MySQL schema gains the new Invoice/Category/Product columns; a naive (@localTime) timestamp keeps its zone-less wire form in engine-wire.ts; two scenarios no longer rest on engine-specific NULL ordering (report-self-reference) or a Postgres-only clock expression (report-all-types-breakdown).
  • Cube: the live lane's seed gains the in-scope Intro programs LiveIntroPrograms needs; two Cube-vs-view differences are kept as executed known differences (ProgramsEmptyScope answers null where the view answers 0/-1; ProgramsOverTime declares a rollup Cube never matches).
  • A stray codegen-ts/test/tmp-typed-create-sqlite-* directory that fix(verify,cli): verify --docs catches orphan model pages; hand-rolled-aggregate advice names object.report #420 committed by accident is removed.
  • TypeScript SQLite convergence test: a view recreated around the already-known blocked inet table change is the same residue as that change.

No CHANGELOG line: nothing shipped changed.

Testing

  • scripts/ci-local.sh --quick green. The full run was green except the Kotlin SQLite lane; after the harness fix above, the Java, Python, C#, Kotlin (SQLite and MySQL) and TypeScript (Postgres, SQLite, MySQL, D1) integration lanes were each re-run green, and the Cube live lane passes.
  • No-mistakes gate: runs 1 and 2 failed on infrastructure (a stray tmp dir on main, and the test step's evidence phase timing out); run 3 was authorized by the maintainer and is the last. Total gate runs: 3. Run 3 passed its baseline tests and finished with an approved test exception: the agent's live-evidence phase reported 'inconclusive' (it drove the TypeScript lanes live and the Cube lane 27/27, and asked for the Java, Kotlin, Python and C# lanes to be run). Those lanes were run locally before the gate and are green, as listed above.

…el and every port

Adds 12 reports to the canonical fitness model (and a Session entity) and
grows the api-contract report corpus to four entities and nine reports, so
the report corpora exercise vocabulary they did not before: multi-hop and
self-referencing dimensions, day/quarter/year/hour/date time grains,
min/max/avg/count-distinct over more column types, negative and decimal
measure defaults over an empty table, measure filters on the remaining
operators, segment and report filters combining like/in/or/ne, a two-hop
@spine, and a TPH base as @from.

- persistence-conformance: 10 new report query scenarios, all five ports
- api-contract-conformance/report: 6 new scenarios (22 in all), all five ports
- cube-model goldens and the live Cube lane cover the new reports
- committed derived artifacts regenerated with the repo's own tools
- test-harness fixes only: date and uuid operand coercion in the Java and C#
  runners, `like` and uuid in the seam lanes' in-memory report repositories,
  and the SQLite convergence test's known inet residue
- removes a stray generated temp directory committed in #420, which turned
  the ts build + typecheck gate red on main

No product port defect was found, so no CHANGELOG entry.
… and the MySQL Cube lane

The engine lanes added in #421 now run all 19 report scenarios. The MySQL adopter tables gain
the nodes, sessions, measurements, auths and all_types tables, the api-contract MySQL schema
gains the disputed/category/sku columns, and the MySQL Cube lane covers all 21 served reports.
A naive timestamp keeps its wall clock without a zone suffix on the SQLite and D1 wire form;
two scenarios no longer depend on engine-specific NULL ordering or on a Postgres-only clock
expression.
…e and read min/max timestamps there

The Kotlin SQLite lane spells a DATE column's SQL type as TEXT, so the string
operand of a date filter reached Exposed uncoerced; key the coercion on the column
type as well. The report-time-min-max seed now spells its timestamps in the form the
SQLite driver's date_string_format parses (fixture seed only; expect blocks unchanged).
@dmealing
dmealing merged commit 86bbadb into main Oct 11, 2026
1 check passed
@dmealing
dmealing deleted the fm/mo-1-1-0-report-coverage branch October 11, 2026 03:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant