Simplify backlog
engineering-docs-operations-simplify-backlog · in engineering/docs/operations · org-wide · updated 2026-06-01 10:19
Frontmatter
- lang
- en
- imported_at
- 2026-06-01T10:19:43.442Z
- source_path
- productgalaxy/docs/operations/SIMPLIFY-BACKLOG.md
- source_repo
- productgalaxy
Simplify backlog
Deferred from the first
/simplifypass (2026-05-25). Each item is a real find from one of the 3 review agents. We landed the 5 highest-leverage fixes inline + parked the bigger refactors here because they touch many files at once.Reports lived at
/tmp/simplify-{reuse,quality,efficiency}.md— re-spawn the agents to regenerate.
Landed in commit <simplify pass 1>
- ✅ BUG
apps/app/src/api/v1/audit-issues.ts:83—or(eq(x, b), eq(x, b))→or(eq(x, b), isNull(x)). Silently missed global taxonomies for audit_issues. - ✅ BUG
packages/db/src/schema/entity_links.ts— added'embed'toentityLinkRelationenum (referenced in notes.ts wikilink resolver but missing → runtime error on Obsidian![[note]]embeds). - ✅ DUPE deleted
apps/mcp/src/lib/jcs.ts; rewired the 2 import sites to@galaxy/db/jcs(which was already exported but the local copy lingered with a TODO). - ✅ PERF
apps/app/src/api/middleware/business-scope.ts— added in-memory TTL cache (5 min) for slug→id. Was a DB roundtrip per request before; now ~1 roundtrip per slug per 5 min. - ✅ LEAK
apps/app/src/api/middleware/idempotency.ts— added hourlysetIntervalGC (unref'd). Was only GC'd lazily on each request, so low-traffic memory grew unbounded.
Deferred — high leverage but multi-file (do in dedicated PRs)
A. Route-list factory (~600 LOC saved) — STILL DEFERRED
Every v1 GET list endpoint (audits, pm-tasks, pm-pipeline, abtests, comments, comment-insights, notes, tags, businesses, taxonomies) has the same skeleton:
- decode cursor →
(date,id)tuple - build WHERE from optional query filters
- ORDER BY (date, id) DESC + LIMIT N+1
- map rows → response shape via
rowToX(r, businessSlug) - envelope as
CursorPage<T>
Proposal: extract apps/app/src/api/middleware/list-factory.ts exporting a registerList({ router, path, table, rowMap, filters }) helper. Each list endpoint collapses from ~40 LOC to ~10.
Why still deferred: 60+ @ts-expect-error suppressions sit at .openapi(...) boundaries in close proximity to these routes (see §S). Re-positioning them risks invalidating dozens at once. Wait for upstream @hono/zod-openapi 1.5+ Handler-type fix before tackling.
B. ✅ DONE in 068d1ad — FK resolvers lifted to @galaxy/db/resolvers
loadBusinesses, resolveBusinessId, loadTaxonomies (now takes onRow callback), resolveTaxonomyId*, rememberTaxonomy, findMissingBusinessSlugs, tryResolveBusinessId, clearSharedResolverCaches live in packages/db/src/resolvers.ts. Each importer re-exports + adds LocalCaches for domain-specific state (audits: page/team/issue, pm: taxonomyByNameFa + team-by-name + pm_task/pm_pipeline, comments: issueBySlug).
C. ✅ DONE in 068d1ad — display-IDs lifted to @galaxy/db/display-ids
BIZ_PREFIX_MAP + bizPrefix() + pad3() consolidated. Fixed long-standing drift: 6 inline slug.slice(0,3).toUpperCase() shims (4 in apps/app + 2 in apps/mcp) used to yield TEL for televika while importers used TVK. Now both paths agree.
D. ✅ DONE in fb4455e — summaryAudit() shipped
summaryAudit({domain, entityId, after}) in @galaxy/db/audited-write; 18 importer phase-tail sites migrated. SummaryDomain closed union catches typos like audit_isssues.
E. ✅ DONE in d0d7d6b — Persian byte utilities lifted
countZWNJ, assertEnIsAscii, emptyToNull, slugify, parseDateUTC available from @galaxy/db/bilingual.
F. ✅ DONE in <this commit> — Limit const + CursorString adopted
packages/shared/src/common.ts exports CursorString + Limit + PaginationQuery + BusinessQuery. 13 inline 5-line limit: z.union(...).transform(...).pipe(...).default(50) declarations across 5 domain schemas collapsed to limit: Limit. Two outliers (notes' max(50) curated lists, comments' max(5000) ingest) intentionally inline.
G. ✅ DONE in 068d1ad — emitFieldAuditDeltas() shipped
6 PATCH/subtask handlers' 18-line for ... auditedWrite(...) ladders replaced. keyAliases covers FK-vs-slug remaps (phase_slug → phase_id); skipFields covers non-column fields (commit_message on notes).
H. ✅ DONE in <this commit> — entityLinkRelation type derived
notes.ts:1123-1124 + :1177-1179 hand-rolled 'wikilink' | 'embed' | … unions replaced with type EntityLinkRelation = (typeof schema.entityLinkRelation.enumValues)[number]. Adding a new variant in entity_links.ts now propagates automatically.
I. ✅ DONE — N+1 batched on all 3 list endpoints
- notes.ts: shipped in
ad1e490(hydrateLinkedEntitiesBatch) - audit-issues.ts: already batched at lines 199-234 (
inArrayjoins) - pm-tasks.ts: shipped in
<this commit>— newloadJoinMaps()+joinTaskRowWithMaps()collapse ~140 round-trips per page to 3 IN(...) queries.
J. ✅ DONE in <this commit> — importer INSERT batching
importers/audits/src/issues.ts: 159 audit_issues + N audit_issue_pages went from per-row INSERTs to 2 batched calls (one for issues, one for the M:N junction). Uses Postgresexcluded.*for the conflict SET clause.importers/pm/src/master.ts:upsertPmTaskreplaced with batchedupsertPmTasks(inputs); each phase (stories/tasks/tombstones) accumulates inputs and flushes once. Team auto-provisioning still inline (ordering-dependent).- ~460 importer round-trips collapsed to 4.
@galaxy/importer-commentswas already batched (500-row chunks).
K. ✅ DONE in fb4455e — extractBearer canonicalized
Single source in packages/auth/src/middleware.ts; apps/mcp/src/lib/jwt.ts re-exports as a back-compat shim. Follow-up: migrate the 2 callers off the shim and delete it.
L. ✅ DONE in <this commit> — createPgClient() factory shipped
packages/db/src/client.ts exports createPgClient({ mode }) with 4 modes (app / migrator / eval / script) covering all 4 callsites: client.ts, migrate.ts, scripts/eval/_eval-utils.ts, tools/issue-admin-jwt.ts. Argon2 params already lifted to @galaxy/db/argon2-params in d0d7d6b.
Deferred — low value (skip unless follow-on changes force it)
M. Trim narrating top-of-file comments — DEFERRED (judged not worth pursuing)
Re-reviewed in <this commit>: most "narrating" comments in routes are actually route-table summaries (e.g. notes.ts opens with a list of every endpoint + its idempotency/audit semantics) that serve as navigation aids in 1k+-line files. Trimming them risks information loss for marginal LOC savings. Future cleanup should be selective per-file rather than a blanket pass.
N. ✅ DONE — void inArray; void KIND_MAP; workarounds already removed
Grep finds zero hits. Cleaned up in earlier sprints.
O. <Card>/<CardHeader> wrapper noise in apps/app/src/app/admin/notes/page.tsx
Reviewed previously and judged not applicable — those Cards provide real visual structure (border, hover-affordance), not redundant nesting.
P. ✅ DONE — defensive rows.rows dance no longer present
Grep across apps/app/src + apps/mcp/src returns zero hits for Array.isArray.*rows.*rows or rows.rows. Cleaned up incrementally in earlier sprints.
Q. Hand-rolled error handling in notes-vault.ts
Reviewed previously and judged not applicable — the catch + problemJson(...) blocks return semantic per-call detail messages (not generic 500s); centralizing them would lose error context.
R. ✅ DONE in <this commit> — exactOptionalPropertyTypes: true enabled globally
Root tsconfig.json now has exactOptionalPropertyTypes: true. Required edits to keep typecheck clean across all 11 packages:
importers/comments/src/insights.ts: dropsource_comment_legacy_id: undefined(omit instead).importers/pm/src/relations.ts: type therelatedItems?: RelatedItem[] | undefinedarray entry explicitly.apps/mcp/src/index.ts: 2as nevercasts on the SDK'sStreamableHTTPServerTransport({ sessionIdGenerator: undefined, … })ctor +server.connect(transport)(SDK type signature gap).apps/app/src/lib/api-client.ts+ 5 admin-UI prop interfaces: widen?: Tto?: T | undefinedwhere callers pass already-extractedstring | undefinedvalues.
S. Suppressions now down to 52 (was 76) — Handler-type drift remains
After <this commit>:
- Removed 22
noUncheckedIndexedAccess + .returning()suppressions inapps/app/src/api/v1/{pm-tasks,notes}.tsviafirstRow()helper. - 52
@hono/zod-openapi 1.x Handler-type driftsuppressions remain. Verified upstream:@hono/zod-openapi1.4.0 is the latest release; the type bug persists. Drop blocked until 1.5+ ships. - 2 new
as nevermarkers on the MCP SDK transport (see R). Different class — SDK type gap, not a missing column-type narrowing.
T. ✅ DONE — apps/mcp Vitest 80/80 passing
Test helper rewired through the SDK's public discovery API. Verified in <this commit> + every recent commit.
How to revisit
Re-run /simplify periodically (or via the pre-commit hook). Each item above includes the file:line refs so the next pass can verify what's still outstanding.