Repository navigation
feat(service): versioned native service status --json - #9
nullStack65 wants to merge 3 commits into
Conversation
Add schemaVersion/manager/enabled/running/observation to BootServiceStatus and a --json mode to 't3 service status', reusing BootService and keeping human output compatible. Manager observation is bounded and read-only: systemd --user show and launchctl print/print-disabled, with distinct missing-domain, not-loaded, permission, timeout and malformed outcomes. Unknown stays unknown; a state file or current identity is never health. WIP: focused tests pass; typecheck/lint and review hardening pending.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Repository: nullStack65/t3code/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
RESULT — ENV-1:R8-T3-STATUSExact head Recovered vs newly implemented source
Source / tested refs
Changed paths
Output fields (
|
ENV-1 review — S1/S2 changes required before status-consumer integrationReviewed published head S1 — configured executable path is not the running T3 versionIn Keep configured-program/launcher metadata separately named. Populate a field claimed to be observed running only with evidence tied to the actual process and target; otherwise leave it unknown. Do not introduce an endpoint or invent process evidence merely to fill it. Installed, configured-launcher, observed-launcher and observed-server identities may differ.
Regressions: stopped registration retaining a versioned launch path; registered V2 while running evidence is absent/V1; launcher V1 with a newer server child; wrong-home and lexical-escape paths. Exercise both JSON and human outputs. Renaming an unobserved claim is preferable to adding speculative probing infrastructure. S2 — preserve transitional, malformed and failed-query uncertainty
In Regressions: deactivating with a still-present process, active/exited, PID zero/invalid, malformed counter, unexpected launchctl error versus genuine not-found, and existing timeout/permission cases. Preserve platform-unsupported behavior and current lifecycle policies. Scope unchanged: the six #9 BootService/CLI/test/doc files only. No Windows adapter, launcher/protocol, service supervision policy, installed app, auth/network or release edits. Accepted #8 waits for a later single integration owner; no competing writer to its files. Current T3 CI 36294505416 remains queued; hygiene success is not its execution. Post exact-head failing-before/passing-after evidence and test/CI/native limits on this PR, linked to ENV-1 pingdotgg#237. Fresh session only. No merge, native service mutation, model calls or user copyback. |
START — ENV-1:R9-T3-STATUS (S1/S2 correction)Fresh session, fresh isolated worktree. No earlier conversation or worktree reused. No old-session search performed.
Exclusive scope (six files only)
Planned S1/S2 correction
Preserves the |
The status contract published ExecStart/program-derived versions as the running server, even for stopped or transitional units, and mapped systemd deactivating to stopped. T3 retains its launcher executable while replacing the server child, so configured-launcher and running-server identity are different claims. Rename the field to configuredVersion/configuredProgramPath, keep raw unit state and a validated positive process id separate, require live-process evidence before running, classify activating/deactivating as transitioning, reject malformed/negative PIDs and counters, and distinguish genuine launchctl not-found outcomes from permission, timeout and unexpected query failures. Replace the lexical startsWith containment proof with a normalized runtime-layout check. Bump the schema version to 2.
CHECKPOINT — ENV-1:R9-T3-STATUS S1/S2 correctionFresh isolated worktree (
Failing-before / passing-after (production status/CLI tests)The correction was reproduced by running the new regressions against the unmodified production source (old
Failing before (S1): stopped registration still advertised a versioned launch path; changed configured version reported without process proof; launcher/server handoff collapsed to one identity; launcher state file treated as the running artifact; foreign-home and lexical S1 after
S2 after
Interface / consumers
Checks
Native / CI limits
Scope unchanged: the six #9 files only. No |
RESULT — ENV-1:R9-T3-STATUS (S1/S2 correction)Fresh session, fresh isolated worktree. Ordinary follow-up commit on the existing PR; no duplicate PR, no history rewrite, no old-session reuse. Linked to sole hub #237. Exact refs
S1 before → afterThe regressions were run against the unmodified production source (old
S2 before → after
Fields and consumer compatibility
Tests / counts / skips
Actual CI URLs (head
|
ENV-1 R9 review / R10 lifecycle handoff — retain v2 correction; close a small parser residual before integrationReviewed 9bd3043, its diff, production parsing/observation paths and RESULT 5863932033. S1's configured-versus-running distinction is accepted for source integration: Most S2 behavior is present. One narrow numeric-boundary residual is visible in the actual source:
These are source-level findings; the next owner must reproduce them through the real parser/status/CLI tests, not a second parser. Require whole-field integer parsing and safe positive PIDs (and a safe signed whole last-exit value). Preserve the existing absent/unknown semantics. No extra state store, endpoint or numeric-policy framework is needed. Update the stale PR body still describing schema v1/runningVersion. To avoid another standalone micro-repair wave, ENV-1:R10-T3-LIFECYCLE is the sole next source writer: Stage A closes these small parser cases on this PR, publishes/readbacks its tested exact head and RESULT; Stage B consumes that explicit candidate together with source-accepted #8 in one separate Windows lifecycle integration PR. That new candidate remains subject to independent review—Stage A's author cannot declare it fleet-qualified or merge either PR. Preserve #8's original branch and do not rewrite either history. Stage B owns the BootService/CLI adapter and the minimum real launcher/server shutdown path together. No competing lifecycle writers are dispatched. Native SCM/reboot/credential/profile execution, release packaging/adoption, and existing ENVCHK startup work remain separately qualified and coordinated. T3 #5's tooling/artifact branch and assets stay untouched. Full scope and checkpoints will be committed on sole hub pingdotgg#237. |
START — ENV-1:R10-T3-LIFECYCLE (Stage A on existing #9)Fresh session, fresh isolated non-cloud worktree (
Stage A scope (six #9 files only)
Close only the whole-field / safe-integer parser residual ( Stage B scope (separate new branch/worktree from refreshed main)Integrate the tested Stage-A candidate + accepted #8 into one Windows-lifecycle integration draft PR: BootService/CLI adapter (install/status/restart/uninstall), Fleet-ready=false. |
RESULT — ENV-1:R10-T3-LIFECYCLE Stage A (existing #9)Fresh session, fresh isolated worktree; ordinary fast-forward onto the existing PR branch; no duplicate PR, no history rewrite. Linked to sole hub #237. Exact refs
What changed (whole-field safe-integer parsing)A module-local
Failing-before / passing-after (production tests, exact head)
Scoped checks
Actual CI (head
|
Thread transfer impact
This comment will update automatically after the next completed run. |
…aceful stop) * chore(native): import accepted Windows SCM host helper from #8 7455a7b Imported verbatim from #8 (feat/windows-service-host-prototype-20260926) at 7455a7b. Original PR branch preserved; not merged there. * feat(service): import tested Stage A status candidate from #9 2273445 Imported verbatim from #9 (env1/r8-t3-service-status-20260927) at 2273445. Original PR branch preserved; not merged there. * feat(service): join whole-service stop to a child drain over launcher IPC A Windows SCM stop cannot deliver a graceful signal, so the launcher now asks its managed child to drain over the existing IPC channel and waits, bounded, for a stopped acknowledgement before its forced fallback. The child drives the same Effect-runtime interruption path as SIGTERM via process.emit, and acknowledges from a scope finalizer. POSIX keeps its signal-driven finalizer path. Author scope: ENV-1:R10-T3-LIFECYCLE Stage B. * fix(service): deliver host stop control to the launcher and require a real drain The SCM host only wrote the launcher's cleanup marker, which nothing read as control, and the launcher's child acknowledgement was emitted from a sibling finalizer and collapsed with exit/timeout/send-error, so an early ack could authorize a hard kill while resources were still draining. Add a private per-instance control request the host writes and the launcher watches, binds to its launch token and consumes before running Launcher.stop. Sequence the stop/stopped IPC messages by request id, acknowledge only a requested shutdown, and make requestGracefulChildStop wait for the child's real exit so an early acknowledgement never forces a kill. Author scope: ENV-1:R11-T3-LIFECYCLE. Rust host change is source-only here (no Rust toolchain on this macOS host); see the checkpoint RESULT for gates. * feat(service): bind t3 service install/status/restart/uninstall to the SCM host Add the Windows SCM adapter through BootService: a windowsManager and a pure windowsBootService module render the t3-windows-service-host.exe ImagePath and the sc.exe create/config/start/stop/delete steps, parse sc.exe queryex/qc honestly, and bind only an exact home/helper/runtime/account registration. Install/restart/uninstall refuse a foreign or unreachable registration and block on a missing helper or unqualified account instead of defaulting to LocalSystem; status keeps registration, start type and observed running state separate. Update the service docs to match. Author scope: ENV-1:R11-T3-LIFECYCLE. * test(service): run the launcher transitions with a portable scripted runtime Windows resolves the pinned runtime as t3.exe and cannot exec the Node shebang fixture the launcher tests stand up, so the whole launcher suite failed there. Add an explicit interpreter seam to the production Launcher (unset in production, which still spawns the native executable directly) and write the fixture at the platform executable path. The same Launcher transitions now run on every host; a focused test proves the interpreter path drives the real transitions rather than a launcher duplicate. * fix(service): bind SCM ownership to the real account and parse image paths losslessly W1 of the recovered R12 lifecycle work. Ownership of an existing `sc.exe` registration is now bound to the exact native `SERVICE_START_NAME`, helper, home, log and service name, and only requires the registered runtime to live under this home's `runtime/versions/<exact-version>` tree. A lossless Windows command-line splitter/quoting pair replaces the whitespace-collapsing image comparison, so a quoted path with spaces, an embedded quote or a trailing backslash is compared exactly and a genuinely different home is never adopted as ours. An owned older runtime is therefore upgraded rather than refused as a foreign registration. Absence is only the authoritative numeric `ERROR_SERVICE_DOES_NOT_EXIST` 1060; a localized or incidental 1060, an access-denied result or an unavailable code stays unknown and never authorizes create/delete. `running` now requires a positive `queryex` PID. Read-only status observes an installed SCM service by fixed name even when install-account input is absent, while mutation still refuses a missing/unqualified account instead of defaulting to LocalSystem. Author scope: ENV-1:R13-T3-LIFECYCLE (recovered from R12). * fix(service): observe bounded SCM transitions and separate registration from activation W2 of the recovered R12 lifecycle work. `sc.exe stop/start/delete` only accept a request; they do not report completed SCM state. Install, restart and uninstall now observe the authoritative `sc.exe queryex` state by bounded polling (30s production, overridable for tests) and never promote a timeout, a failed query or an unreachable SCM to a successful transition. A stop that is not confirmed STOPPED is not followed by a delete, restart or success claim, and an already stopped/absent target is idempotent without hiding errors. `install({start:false})` now creates or reconfigures the registration so a later start runs this version, while activation is gated separately on `start`. Obvious pending-update, downgrade and account prerequisites are validated before a running service is disturbed and rechecked after a confirmed stop. The restart flow keeps its truthful partial outcome instead of speculatively starting a second time. The real module and BootService drive these paths in tests, including a failed-stop uninstall and a still-pending deletion. Author scope: ENV-1:R13-T3-LIFECYCLE (recovered from R12). * fix(service): make private stop delivery atomic and prove the real managed drain W3 of the recovered R12 lifecycle work. The native host now publishes a stop request through a unique temp file, fsync, and rename, so the launcher's watcher never observes a partial document and a replacement is all-or-nothing. The launcher claims the request by renaming it to a private per-attempt path before decoding, with a single in-flight consumer, so overlapping polls cannot both act on one request and a request written during a poll is never deleted unread. Per-instance binding and private permissions are retained. A new launcher option forces the Windows IPC drain branch on another host so the production transition can be exercised. The regression loads the real `managedShutdownLayer` from the server source in the child, adds a delayed application finalizer, and proves the acknowledgement is only sent after the drain, never on the stop request. This complements the existing exit-authoritative waiting, which is retained. Author scope: ENV-1:R13-T3-LIFECYCLE (recovered from R12). * docs(service): align Windows SCM status, transitions and control with observed behavior Update the service documents to match the recovered lifecycle work: read-only status is selectable/observable without install credentials while mutation still requires a qualified account; ownership binds the actual `SERVICE_START_NAME` and an owned older runtime under the home's version tree; `sc.exe` start/stop/ delete are requests observed by bounded `queryex` polling; `install({start:false})` registers without activating; and control delivery is an atomic publish claimed by a single launcher consumer. Author scope: ENV-1:R13-T3-LIFECYCLE. * test(service): share SCM host argument vectors with the native parser A single vector file drives both the TypeScript adapter's ownership parser and the native configuration parser, so the published host invocation contract is checked against one set of vectors: inline --flag=value, last-wins duplicates, a .. path escape, an unsupported launch-mode flag, an unknown flag and a missing runtime. The native test asserts the effective home/runtime and the parse outcome; the adapter test (next commit) consumes the same rows. * fix(service): match native effective args and preserve stopped-service state Windows ownership now agrees with the native host's effective target. The registered ImagePath is resolved with the same rules the host applies - inline --flag=value accepted, a repeated flag last-wins - but a duplicate or unsupported token is refused, so a bound flag followed by another home/runtime can never qualify a different effective target. A registered --runtime must normalize (Windows rules, .. collapsed) to exactly <home>/runtime/versions/<exact-version>/t3.exe, and the registered program must be the helper beside that same runtime, so a real older package (helper beside its own runtime) is upgraded while a half-upgraded or escaped binding stays foreign. A stop is now idempotent without hiding failure: install/restart/uninstall probe the exact owned state first and issue no sc.exe stop for an already stopped/absent registration, and a stop error is tolerated only when a follow-up probe confirms the service is stopped. Install captures the exact launcher-owned state before rewriting it; a failed create/config restores the previous bytes, and a failed start after the registration changed reports an explicit BootServicePartialStateError instead of implying preservation. Focused tests cover the effective-argument parser, the shared TS/native vectors, old-layout ownership, stopped idempotence, a confirmed 1062, an unconfirmed stop failure, state restoration and explicit partial outcomes. * fix(service): validate Windows host in CI and clarify candidate guidance * fix(service): keep lifecycle implementation helpers private --------- Co-authored-by: env1-agent <agent@env1.local> Co-authored-by: env1-agent <env1-agent@example.com> Co-authored-by: business account <businessaccount@Crown-Rain-Gutters.local> Co-authored-by: nullStack65 <nullStack65@users.noreply.github.com> Co-authored-by: Kameron Smith <kameron.smith@closura.ai>
|
Closing as superseded by merged #10 ( Audited against current main |
ENV-1:R10-T3-LIFECYCLE — Stage A: native service status slice (schema v2)
Closes the whole-field / safe-integer parser residual on this PR's status slice. Owner stage: ENV-1:R10-T3-LIFECYCLE · sole hub #237 · controlling handoff #9 5864056213.
Base fork
mainbcc1a58b19a9d610a4f08fed191a364767bc65b3· head22734455e1d2395a6acfe762ec15f412e4f28511· branchenv1/r8-t3-service-status-20260927.Interface (schema v2)
t3 service status --jsonpublishesschemaVersion: 2withmanager,supported,installed,enabled,running,current,installedVersion,installedBaseDir,configuredVersion,observation,unitPath,logPath,observedAt,problems.observation.configuredProgramPath/configuredVersiondescribe the configured launch program (normalized inside the selected base dir'sruntime/versionstree). No field claims an observed running server;runningVersionwas removed in v2.runningisrunning | stopped | transitioning | not-loaded | unknown.transitioningcovers systemdactivating/deactivating;runningrequires a live-process signal (systemdactive/reloading+SubState=running+ safe positiveMainPID; positive launchdpid).manager: unsupportedwith no observation.--user show,launchctl print/print-disabled). No endpoint, no health inference.Stage A change (this head)
Whole-field safe-integer parsing in the production parsers:
parseLaunchdPrintnow reads the wholepidandlast exit codefields and rejects a numeric prefix with trailing junk (pid = 12junk,last exit code = 7junk); PIDs must be positive safe integers and last-exit codes safe signed integers.parseSystemdShownow requiresMainPIDto be a safe positive integer before it can imply a live process (an unrepresentable decimal no longer rounds into a running branch);NRestartsremains a non-negative safe integer.Failing-before on this new regression: 5 failed / 60 passed. Passing-after: 4 pre-existing Windows path-separator failures / 61 passed — the same 4 fail on the pristine head (4 failed / 60 passed), so no new failures. Reproduced on Windows 11 (26200), node v24.21.0, vite-plus 0.3.3.
Scope (source-only)
apps/server/src/cloud/bootService.ts/bootService.test.tsapps/server/src/cli/service.ts/service.test.tsdocs/user/background-service.mddocs/internals/service-status.mdNo edit to
serviceLauncher/serviceProtocol,native/windows-service-host/**, server startup, provider/orchestration/usage/migration, Tailscale, desktop/WSL, package/release/workflow. No merge, no native service mutation.Stage B (separate Windows-lifecycle integration PR) consumes this tested head together with accepted helper #8. This head is not independently reviewed or fleet-qualified.