refactor(features,service,database,host,gateway,ui,voice,live,settings,wire): the packages name the unit of work a task (LUKE-369 4/7)

Merged
CH
4d ago
+8029-8068

Summary

LUKE-369, PR 4 of 7: identifiers and file names in the packages. Every package identifier, file, export subpath, gateway method, act kind, trace span, and tagged error that named the unit of work a plan now names it a task. For example:

  • Plan → Task and planId → taskId
  • plan-wire.ts → task-wire.ts, planning-view.ts → tasks-view.ts, and src/plans/ → src/tasks/
  • compose-planning.ts → compose-tasks.ts, planning.* gateway methods → tasks.*, and PlanArchived → TaskArchived
  • the web/startPlan span → web/startTask
  • the planner roles → brain / brain-worker, and brain-host/planning.ts → brain-host/brain.ts

The plan stays where it is the document: its notes, edits, revisions, page versions, template, markdown, scribe, and edit_plan. The database's SQL names stay until PR 6. A coding agent's apps-side renames are PR 5's. This PR changes in apps/ only what is needed to compile against the renamed packages.

The plan's wire mapping was dropped (orchestrator decision K)

The plan asked for wire struct fields keyed taskId in TypeScript and encoded as planId, via a key mapping on every wire struct. That approach was dropped. The service sends Type-shaped objects raw: about 100 hostedJsonResponse(status, body) calls serialize the object as it stands, and about 100 JSON.stringify calls in service, voice, host, and features do the same. Once a TS key differs from its wire key, every one of those sites would have to encode first or silently send taskId / tasks to released desktops. The client tests compare the sent body to a TS-keyed object, so they wouldn't catch it.

So the wire's own schemas keep the wire's spelling as their TS keys: planId, plan, plans, planless, planName, planner, and the plan.* frames. Everything else says task, and the code converts at the boundary. Each wire module with such keys carries one note that they are the wire's legacy spelling, to be renamed together with the wire in the follow-up, with no alias. wireKeys (#2835) keeps its one user, the coding agent's Start request.

How it was done, and what checked it

  • A throwaway AST codemod (.context/rename/, not committed) renamed identifier tokens only, never JSX text or a string's words. The only exceptions are the string values named above: gateway methods, act kinds, spans, tags, the end cause, and roles. A curated word map keeps the document's names, file renames were applied with import-specifier fixups, and a tsc-driven fixer swapped spellings wherever a consumer met a wire type.
  • JSON Schema goldens: every hosted wire golden is byte-identical. 221 goldens match their old files byte for byte. The only change is the file name, after the renamed export: plan-wire-planSummarySchema.json → task-wire-taskSummarySchema.json, and so on.
  • Three view goldens change one key, planId → taskId: coding-agent-view-codingAgentListParamsSchema, …StartParamsSchema, and …InboxParamsSchema. These are the renderer-to-host act payloads, the same build on both sides.
  • Bugs found and fixed while doing this, each the wire spelling restored where a renamed key would have left the process. tsc doesn't check keys inside a conditional spread or a generic Body, so the service and voice tests that decode answers through the wire schemas are what caught them:
    • tasks-app.ts: the task list and task answers would have gone out as { tasks } / { task }. They are now { plans } / { plan }, held with satisfies TaskListAnswer / TaskAnswer.
    • inbox-page.ts: the account inbox answer is back to plans / planless.
    • agent-notices.ts: the filtered planless list, and the answer kept when nothing waiting moved.
    • live-exchange.ts: the activity frame's planner key.
  • I also audited every object literal in packages that combines a spread with a renamed key, and every renamed key with no contextual type, against its target type.

String values that change, none of them stored or on the wire

  • GATEWAY_METHOD planning.* → tasks.*. The gateway is in-process.
  • ACT_KIND planning.* → tasks.*. These are IPC, same build.
  • Trace span names web/…Plan… → web/…Task….
  • Error tags PlanArchived / PlanAgentUnstopped → Task….
  • LIVE_SESSION_END_CAUSE.TASK_DELETED = task_deleted. It's only a log line.
  • AGENT_ROLE = brain / brain-worker. These are held in memory only, not persisted.

Stored values are untouched: conversations.kind = 'plan', plan-unreachable, MENTION_KIND's plan, luke://plan/… links, CODING_AGENT_BRIEF.PLAN, and the analytics APP_PANEL_TAB value plans.

Evidence

  • pnpm check:affected: exit 0.
  • pnpm --filter @luke/web test:store on a real Postgres 17: 74 files, 423 tests pass.
  • pnpm --filter @luke/web test:agent: brain-host 3/3, coder 3/3.
  • pnpm --filter @luke/web functions:rewrites --check: no change, since route files keep their plans/* keys.
  • Test fixtures that are wire JSON (frames, request bodies, fake service answers) keep the wire's spelling. Fixtures for internal and IPC shapes follow the rename.

Invariants

  • ./scripts/check.sh green. (CI)
  • JSON Schema goldens: the hosted wire is byte-identical; files are renamed after their exports, and three IPC view goldens change one key, explained above.
  • No behavior change beyond the renames, so no new behavior tests. The leaks above were caught by existing tests.
  • Gateway envelope goldens unchanged.
  • No new as, run, or raw async primitive. No discarded effect.
  • Test count unchanged.
  • Package exports follow the renamed files, and the CLAUDE.md/README path references in backticks follow them.
  • PRIVACY.md unchanged.

Notes

  • Not done here: many code comments still say "plan" in prose where they mean the task, and only backticked names and paths were updated. A comment-prose pass would touch hundreds of files by hand. I'm flagging it as a follow-up rather than growing this PR.
  • Stack: 1/7 (merged) → 2/7 → 2b/7 → 3/7 → 4/7 package identifiers → 5/7 app identifiers → 6/7 database.

🤖 Generated with Claude Code


Devin Review