Replies: 1 comment
|
Branch: Cross-link: sibling of #3945 (Things UI Universal Record Inspector — detail page) and #4005 (TableBase Coverage Dashboard & Enrichment Queue). #3998 is the listing-side counterpart to #3945's detail-side work. Consider treating these as siblings of one Things UI epic. — Discussion review 2026-04-08. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Things Listing Enhancements — Implementation Plan
TL;DR
The
/thingsuniversal index needs source_table filtering, verdict status indicators per row, a search pagination bug fix, and record-lookup support for 3 missing tables. This plan uses a LEFT JOIN approach (proven in grants/personnel) to add verdict data to the listing query in a single PR (~130 lines across 5 files). Coverage dots are explicitly excluded — generic metadata coverage is not actionable for a heterogeneous index. Phase 1 is the entire implementation, achievable in one session.Problem
Wiki maintainers using
/thingsto audit data quality across domains can't filter by source table or see which records are verified vs unchecked. The search endpoint inflates pagination totals during trigram fallback (line 275 of things.ts), and clicking "Record Data" on things from facts, resources, or research_areas tables produces a 400 error because those tables aren't in the record-lookup whitelist.Current State
things.tsGET/source_tablefilter; no verdict data in responsethings.tsGET/statsbySourceTablebreakdownthings.tsGET/searchline 275Math.max(ftsTotal, combined.length)record-lookup.tswhitelistfacts(composite key),resources,research_areasverification-join.tsthings-table.tsxProposed Approach
Modify the things listing query to LEFT JOIN
source_check_verdicts, add source_table filtering, fix the search bug, and fill record-lookup gaps — all in one PR.Verdict JOIN: Can't reuse
verdictJoinCondition()directly because it takes a fixedrecordTypestring, but things rows are heterogeneous. Instead, build a raw SQL CASE expression mappingthings.source_tableto verdictrecord_type:Listing row with verdict dot:
Key Decisions
parentThingId. Type-specific scorers on domain directory pages (orgs, grants, people) already provide meaningful coverage. Adding a coarser contradictory signal to/thingsis noise.Architecture
apps/wiki-server/src/routes/tablebase/things.tsapps/wiki-server/src/routes/tablebase/record-lookup.tsapps/web/src/app/things/types.tsapps/web/src/app/things/page.tsxapps/web/src/app/things/things-table.tsxapps/wiki-server/src/__tests__/things.test.tsImplementation — Single PR (1 session)
Goal: Source_table filtering works, verdict dots visible per row, search pagination correct, record-lookup handles all tables.
Backend (things.ts):
source_table: z.string().max(100).optional()toListQueryschemaeq(things.sourceTable, source_table)condition in listing handlerbySourceTableGROUP BY query to stats endpointftsTotalinstead ofMath.max(ftsTotal, combined.length)SOURCE_TABLE_TO_RECORD_TYPEconstant (12 entries, inline in things.ts)db.select().from(things)todb.select({ things, ...verdictSelectFields }).from(things).leftJoin(sourceCheckVerdicts, sql\...`)` with CASE expressionThingsJoinedRowinterface (mirroring grants.tsJoinedRowpattern)formatThingintoformatThingBase(t)for detail/children endpoints andformatThingWithVerdict(row)for listing endpointBackend (record-lookup.ts):
resourcesandresearch_areasto VALID_SOURCE_TABLES + TABLE_MAP (straightforward — both have text PKs)factswith composite key parsing: split sourceId on:, queryWHERE entity_id = ? AND fact_id = ?(following research_area_organizations pattern at line 106)entitiesto whitelist (already imported, one-line addition)Frontend (things-table.tsx):
<select>dropdown (not FilterChips — 15+ source tables is too many chips). Driven bystats.bySourceTable.SourceCheckDotfor rows whereSOURCE_TABLE_TO_RECORD_TYPEhas a mapping; empty for othersuseDirectoryUrlfilterFrontend (types.ts):
bySourceTable: Record<string, number>toThingsStatsResponseverdict?: string | null,verificationConfidence?: number | nulltoThingRowTests:
Quality gates:
pnpm buildpasses, all tests pass, Playwright render-audit passesExit criteria:
/things?source_table=grantsshows filtered results with verdict dots; search pagination totals are accurate;/things/[id]record data works for facts/resources/research_areas thingsScope Cuts
Quality & Verification
curl /api/things?source_table=grants&limit=5returns verdict fields;curl /api/things/statsincludes bySourceTable/thingsshows verdict dots + source_table dropdownRisks & Mitigations
idx_scv_pkunique index covers (record_type, record_id) prefix for nested-loop join. Monitor query plan post-deploy.formatThingBase()(for detail/children) andformatThingWithVerdict()(for listing), following the grants.tsJoinedRowpattern.entityId:factId) can't be used asWHERE id = ?AND field_name IS NULL(matching verdictJoinCondition pattern). Test confirms no row duplication.Open Questions
<select>vs FilterChips? Dropdown is more compact for 15+ source tables. FilterChips with counts are better for discoverability. Recommend dropdown with counts in option labels.Rejected Approaches
parentThingIdpresence penalizes top-level entities unfairly. Type-specific scorers on domain pages are the right tool for coverage.Red Team Log
Technical critic found 2 blocking issues:
verdictJoinCondition()can't handle dynamic CASE mapping → resolved by using inline raw SQL CASE expression instead of the helperformatThing()type breaks with LEFT JOIN row shape → resolved by splitting into base/verdict variants following grants.ts JoinedRow patternTechnical critic found 4 significant issues:
3. facts sourceId is composite key, not numeric PK → resolved by adding composite key parser (research_area_organizations pattern)
4. Search "correct total" unspecified → resolved: use ftsTotal (trigram supplements not paginated)
5. entities table also missing from record-lookup → added to the plan
6. Test/verification gaps (5 specific items) → added to test list
Scope critic recommendations adopted:
Tasks
All reactions