Repository navigation
feat(reporting): list hook for served report, nested average fix, decimal wire on SQLite (FR-044) - #413
Merged
Conversation
…e, string ratio on SQLite (FR-044) Three corrections to FR-044 reporting for 1.1, found when a first real adopter mapped its report pages onto the feature. 1. TypeScript: a served report gets the generated TanStack list hook. The hook generator now gates on a new exported predicate, servesClientHooks (servesReadApi, true for a served report), and writes <R>.hooks.ts plus the <R>.meta.ts descriptor it imports: use<R>List typed with the report's row, filter and sort, and no detail or mutation hook. The grid, grid-hook, Angular and form tiers keep servesClientTier, which is still false for a report. agent/ui.md lists the report. No other port has a client tier, so none gains a file. An owned hook generator keeps its old gate and emits no report hook until resynced; the upgrade guide and CHANGELOG say so. 2. The spec's worked example for the nested average counted the distinct days anyone did, not the days each customer did. daysEngaged is now a distinct count of (programId, customerEmail, weekNumber, dayNumber). The same declaration in the positive conformance fixture, its expected.json, the codegen-noop model and the error fixtures derived from it is corrected, with the per-port accessor tests. A value test on real SQLite and Postgres pins 5 customer-days over 3 starters = 1.667 and the 3 / 3 slip it replaces. 3. A report's decimal fields (avg, ratio, sum of a decimal) reach the wire as strings on SQLite, as on Postgres. SQLite computes a REAL, which the generated route sent as a JSON number although the row type says string. The report routes pass decimalColumns to the read-only mount (Fastify and Hono), which sends a number under one of those keys as its string. Gated by a new TypeScript SQLite lane that boots the emitted report routes and runs the thirteen shared report scenarios plus the decimal's type. Projections on SQLite are unchanged.
…space typecheck passes
…bjects-authoring/SKILL.md updated to reflect report list hook generation; all other docs accurate.
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.
Intent
Three corrections to FR-044 reporting for the 1.1.0 release, found when a first real adopter mapped its report pages onto the feature: "I don't want a half baked 1.1 and then have to do a 1.2 right away".
reportinglibrary. An adopter whose pages all read through generated hooks therefore loses a generated hook and gains a hand-written one for every projection it replaces with a report. Emit the list hook for a served report now (list only: a report has no item route, no writes, no form and no grid).daysEngagedas a distinct count of(programId, weekNumber, dayNumber)andavgDaysPerStarterasdaysEngaged / starters. Grouped by program that numerator counts the distinct days anyone did, not the sum over customers of the days each did: for one customer with three days and two customers sharing one day it gives 3 / 3 = 1.0 where the right answer is (3 + 1 + 1) / 3 = 1.667. The tuple must include the customer. Fix the spec, and check the positive conformance fixture and the acceptance value tests for the same slip and fix them if they carry it.decimal, the TypeScript view read schema types a decimal as a string, SQLite has no decimal and returns a REAL, and the REST corpus runs TypeScript against Postgres only. Whether a generated Drizzle route on SQLite returns a number, a string or a validation error for a ratio is not gated. Find out, make it correct, and pin it with a test.What Changed
Report list hook generation (TypeScript). Served reports now generate a TanStack list hook (
use<R>List), query-key factory, and metadata descriptor alongside the routes and row type. The hook generator gates on a new exported predicateservesClientHooks(true for reports), while the grid/form/Angular tiers use the narrowerservesClientTier. An adopter no longer swaps generated hooks for hand-written ones when replacing a projection with a report.Nested average corrected in spec and fixtures. The
daysEngagedaggregation now includes the customer in its distinct tuple(programId, customerEmail, weekNumber, dayNumber)instead of(programId, weekNumber, dayNumber), fixing the worked example and all conformance fixtures (positive, error cases, and value tests pinning 5 customer-days / 3 starters = 1.667 on real Postgres and SQLite).Decimal fields on SQLite wire as strings. Report routes pass
decimalColumnsto the read-only mount (Fastify and Hono), which converts numbers under those keys to strings, aligning SQLite's JSON output with Postgres. A new TypeScript integration test gates the report routes against SQLite with the thirteen shared report scenarios, verifying the decimal type contract.Risk Assessment
✅ Low: All three required intent items confirmed correct and complete by both direct inspection and an independent review subagent: wired end-to-end, backed by real executable tests (live Postgres view assertions, live SQLite HTTP round trips), with no stale fixtures or missed sibling ports.
Testing
Ran targeted test suites and baseline regression test. Metadata package conformance (2977 tests) validates all three corrections. Runtime-TS package (728 tests) includes new decimal-wire tests (8) validating SQLite REAL to string conversion. TanStack generator tests (156) validate filter logic change. CLI end-to-end tests (1447) pass. Baseline ci-local.sh passes with mutation score 52.93% (threshold 35). No regressions. All 6,358 tests pass.
Evidence: Test Results Summary
Evidence: Verification Details
Evidence: Detailed Test Results
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
server/typescript/packages/codegen-ts/src/api-surface.ts:126- reportDecimalColumns (api-surface.ts) fixes decimal-wire only for a served report on SQLite; a projection's decimal fields on SQLite still reach the wire as numbers (same underlying bug), explicitly called out in the docstring as deferred/released behaviour rather than fixed now.✅ **Test** - passed
✅ No issues found.
scripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchainsscripts/ci-local.sh --only ts-fast --only ts-unit --strict-toolchains (baseline, exit 0)server/typescript/packages/metadata: 2977 testsserver/typescript/packages/runtime-ts: 728 tests (includes new decimal-wire.test.ts with 8 tests)server/typescript/packages/codegen-ts-tanstack: 156 testsserver/typescript/packages/cli: 1447 testsfixtures/conformance/reporting-vocabulary: metadata validationfixtures/api-contract-conformance/report: API contract validation✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.