Skip to content

refactor(jobs): give RunJobResult one definition in jobs/store.ts (#tech-debt) - #1086

Merged
selfcontained merged 1 commit into
mainfrom
agt_f827974dfc59/job-debt-collector-6e1a8fd7
Sep 14, 2026
Merged

selfcontained merged 1 commit into
mainfrom
agt_f827974dfc59/job-debt-collector-6e1a8fd7

Conversation

@selfcontained

Copy link
Copy Markdown
Owner

What

RunJobResult — the POST /api/v1/jobs/run response shape — was declared twice:

  • apps/server/src/jobs/service.ts:57 (the producer)
  • apps/web/src/hooks/use-jobs.ts:22, a hand-copied duplicate (consumed at use-jobs.ts:105 as api<RunJobResult>(...))

The two copies were field-for-field identical once resolved: server status: JobRunRecord["status"] = web JobRunStatus, server report: JobRunRecord["report"] = web JobReport | null. No client drift. Web kept its own copy because type-importing service.ts would pull the server graph (AgentManager etc.) into web's TS program.

This PR moves the declaration verbatim into apps/server/src/jobs/store.ts, next to the job wire types (JobRunRecord, JobRunStatus, JobWithLatestRun, ...) that use-jobs.ts already type-imports, and lists it in that file's "imported type-only by the web client" comment. service.ts now imports it from ./store.js; use-jobs.ts deletes its copy and adds it to its existing store type import. 3 files, types only, no runtime change.

Why it's tech debt

Two hand-maintained declarations of one wire contract — a server-side field change would compile cleanly on the web side and silently drift.

Deliberate choices / exclusions

  • No re-exports. Neither old export had an importer anywhere (grep -rn RunJobResult apps packages): service.ts's was only used inside service.ts, and web's was only used inside use-jobs.ts. The backlog entry suggested service.ts re-export it; that would add a dead re-export, so it doesn't.
  • Home: jobs/store.ts, not packages/shared. A standing ruling (architecture-review 1065/1220) says a wire contract belongs in packages/shared. Doing that for RunJobResult alone would drag JobRunStatus + JobReport and its closure (JobReportTask, JobReportError, JobReportLog, JobReportStatus, JobTaskStatus) into packages/shared while their sibling JobRunRecord stayed in store.ts, splitting the jobs contract across two homes. Moving the whole jobs wire contract is a separate, larger sweep (one of ten web modules that type-import server paths). Put to the reviewer as a question.
  • JobStats in use-jobs.ts has no named server counterpart (route-inline) — left alone.

Validation

  • pnpm run check, pnpm run finalize:web — pass
  • Unit: server 187 files passed / 1 skipped (3321 tests), web 130 / 1924, browser-extension 9 / 60
  • pnpm run test:e2e — 198 passed / 12 skipped, first try
  • Compiler probe (types-only change, so no test to fail): temporarily changed store.ts's runId: string to number and added a web-side type constraint on RunJobResult["runId"]. Baseline 0 errors; with the probe, web failed (use-jobs.ts TS2344) and server failed at all three service.ts return sites (TS2322). Reverted. Both sides now resolve the single declaration.

Next run

Continues the tech-debt backlog (next focus recorded in the Brain).

🤖 Generated with Claude Code

…ech-debt)

The POST /api/v1/jobs/run response type was declared twice: once in
apps/server/src/jobs/service.ts and once as a hand-copied duplicate in
apps/web/src/hooks/use-jobs.ts. Web could not type-import it from
service.ts without dragging the server graph into its TS program.

Move the declaration verbatim into jobs/store.ts next to the job wire
types web already type-imports, import it in service.ts, and delete the
web copy in favour of the store.ts import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@selfcontained
selfcontained merged commit 53624a7 into main Sep 14, 2026
1 check passed
@selfcontained
selfcontained deleted the agt_f827974dfc59/job-debt-collector-6e1a8fd7 branch September 14, 2026 09:13
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