T-OSEH-long-running-services
Status: closed/done · Impact: medium · Complexity: medium
Two long-running capabilities cannot be plain request/response ops: the
status dashboard (a web server with a pidfile registry) and the lease
heartbeat loop. Port both onto the defineService descriptor T-NV49-op-path-substrate
lands — same noun/verb surface and help discoverability, lifecycle
dispatch instead of invokeOp’s output parsing. This task only consumes
the machinery; it adds none.
| Location | Role today |
|---|---|
plugin/scripts/status_dashboard.ts | hono + Bun.serve server; --detach/--stop/--list; pidfile + machine-global registry; prints URL/PID lines the skill passes through verbatim |
plugin/scripts/lease_heartbeat_loop.ts | signal-driven cadence loop over single-shot lease heartbeats; backgrounded + SIGTERMed by task-work |
plugin/skills/status-dashboard/SKILL.md | thin dispatcher over the script’s flags |
Proposed
Section titled “Proposed”services/dashboard/service.ts — defineService with lifecycle
{start, stop, list} (visible; list is machine-global, which is why
dashboard is a top-level noun) — and services/lease/heartbeat-service.ts
(start-only, hidden). URL/PID/table text preserved via the lifecycle
renderer; SERVICE_ERROR codes (already-running, stale pidfile,
port-in-use, SIGTERM-to-dead-pid) used.
Approach
Section titled “Approach”- Goldens:
--detachstart lines (URL/pid/logs/stop),--listtable,--stopoutput; heartbeat-loop start/heartbeat/stop marker sequence. - Port the dashboard body under
services/dashboard/with the service descriptor; lifecycle leaves render the text contracts. - Port the heartbeat loop as
services/lease/heartbeat-service.ts, keeping the single-shotlease heartbeatop untouched. - Lifecycle tests: dashboard start → list → stop via pidfile; heartbeat-loop start, observe ≥2 CAS-REPLACE heartbeats, clean SIGTERM stop (mirrors lease_integration AC-10).
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/lib/services/dashboard/service.ts | new | defineService + server body |
plugin/lib/services/lease/heartbeat-service.ts | new | start-only service |
plugin/scripts/status_dashboard.ts | modify | thins to forwarder until deletion |
plugin/scripts/lease_heartbeat_loop.ts | modify | same |
plugin/lib/services/dashboard/ | modify | lifecycle tests live here |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
sdlc dashboard start(detached) →list→stopround-trip works via pidfile; URL/PID lines byte-match goldens. - AC-2:
sdlc lease heartbeat-loop(hidden) starts, issues ≥2 CAS-REPLACE heartbeats, exits clean on SIGTERM. - AC-3: service lifecycle failures map to SERVICE_ERROR exit codes (already-running, stale pidfile cases tested).
- AC-4:
dashboardrenders as a visible top-level noun with three leaves; heartbeat-loop only under--advanced.
Out of scope
Section titled “Out of scope”- Dashboard features or UI changes.
- status-dashboard / task-work skill prose (T-QL5F-skill-prose-codemod).
- The defineService machinery itself (T-NV49-op-path-substrate).
Dependencies
Section titled “Dependencies”- T-NV49-op-path-substrate — defineService descriptor + the second walk traversal over service peers, fixture-proven first.
Discovery context
Section titled “Discovery context”- Resolves D-0007’s “long-running ops in the registry” open question via D-H7FS’s defineService; dashboard’s top-level placement is resolved design question (c).