Skip to content

refactor(service): split service.ts into platform leaves - #4492

Merged
lidge-jun merged 3 commits into
devfrom
codex/260913-split-service
Sep 13, 2026
Merged

lidge-jun merged 3 commits into
devfrom
codex/260913-split-service

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

src/service.ts was 5558 lines holding every OS service backend at once: launchd, systemd, the Windows Scheduler pipeline, Windows task XML generation, ownership and auth guards, health probing, install/uninstall/repair orchestration, diagnostics, and CLI argument parsing. This splits it into twelve leaves under src/service/ and leaves the original path as a 30-line facade re-exporting all 141 previously exported names, so no consumer and none of the eight test files that name the path is edited.

The four module-level test seams stay single-instance, which is the invariant that matters most here: querySchtasksForTests and finalizeHooks in windows-scheduler.ts, ownedWindowsSchedulerStages in windows-ops.ts, and uninstallServiceHooksForTests in orchestration.ts. Each has exactly one declaration site and every reader imports from that module, so the setXForTests helpers that tests/service/service.test.ts resets in afterEach still reach the binding production code reads.

One line is not verbatim and is deliberate. Three sites resolved paths from import.meta.dir, which changes meaning one directory down. state.ts now exports serviceSourceDir = dirname(import.meta.dir) and those three sites consume it, reproducing the original src/ anchoring exactly.

structure/manifest.json gains src/service/ in runtime.md's documents list and structure/runtime.md names the new leaves, because scripts/structure-ssot.ts fails on a new top-level src/ area that no doc claims and names.

Second of a three-PR stack, on top of the storage/cleanup.ts split.

Verification

  • Local product suite, typecheck, and build were NOT RUN by operator instruction. Hosted CI on the stack tip is the proof.
  • Export parity checked mechanically: 141 exported by the original, 141 re-exported by the facade, none missing and none added.
  • All 276 baseline top-level declarations resolve to exactly one leaf. Comment-normalized body comparison leaves four hits: one is a block-boundary artifact and three are the intentional serviceSourceDir substitution described above.
  • Every relative import specifier re-anchored for the new depth and verified to resolve; no duplicate declaration across the leaf set; no leaf imports the facade; no src/lab/ import.
  • Adversarial static review caught two real defects that this PR fixes: 60 relative import specifiers had been carried down verbatim and no longer resolved, and constants as fsConstants was dropped from state.ts's node:fs import.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Pure-move split of src/service.ts (5558 lines) into src/service/ leaves: state (paths/install-state), guards (ownership/auth/manager-command), health (port resolution + serving checks), launchd, systemd, windows-scheduler (schtasks + elevation finalize), windows-taskxml (task XML build/verify), windows-ops (Windows install/stop/uninstall + stage tracking), repair, orchestration (install/uninstall/stop dispatch), diagnostics, cli (arg parsing/dispatch). src/service.ts is now a facade re-exporting every original export. One semantic-preserving adjustment: import.meta.dir at the old file depth is carried by serviceSourceDir in state.ts.
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 13, 2026 07:56
@coderabbitai

coderabbitai Bot commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • ^dev$
  • ^preview$

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 464fffcd-defb-4152-b9ec-3f9e8f73151b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 13, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-13T08:02:50.062766Z 11e1179 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Deterministic hygiene checks failed.

  • missing_regression_test — Behavior changed under src/ or gui/src/ without a test change. Add focused coverage or obtain test-exception-approved.

@github-actions github-actions Bot added intake: hygiene-blocked Deterministic PR hygiene checks failed chore Maintenance, CI, tests, refactors, or build changes (not a user-facing bug or feature). labels Sep 13, 2026
@github-actions

github-actions Bot commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed.

Hygiene

✅ Deterministic PR hygiene checks passed.

@github-actions
github-actions Bot marked this pull request as draft September 13, 2026 07:57
@lidge-jun

Copy link
Copy Markdown
Owner Author

test-exception-approved applied — rationale

This PR is a pure-move refactor with zero behavior change: the original file stays as a facade re-exporting every name it exported before, so no consumer and no test is edited. The hygiene gate counts any non-comment change under src/ as a behavior change, which is correct as a default and does not fit a relocation.

Adding a new focused test here would be the wrong artifact. The oracle for a pure move is the existing suite for the moved subsystem, unchanged, which is exactly what proves the relocation preserved behavior. Those suites run on the stack tip (#4493).

Fidelity was verified statically instead, and the checks found real defects rather than rubber-stamping: every baseline top-level declaration resolves to exactly one leaf with a comment-normalized identical body, the facade's export set matches the baseline exactly, every module-level mutable binding and test hook has a single declaration site, and every relative import specifier resolves. Local product suite, typecheck, and build were NOT RUN by operator instruction.

@lidge-jun lidge-jun added the test-exception-approved Maintainer approved a non-automated regression-test exception label Sep 13, 2026
@github-actions
github-actions Bot marked this pull request as ready for review September 13, 2026 07:58
@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 66 / 80

설명
이 PR은 god-file round 1의 두 번째 장입니다. 지금 dev의 src/service.ts는 약 5558줄에 launchd, systemd, Windows Scheduler, 작업 XML, 소유권/인증 가드, 헬스 확인, 설치/제거/수리, 진단, CLI 인자 파싱이 한곳에 있습니다. 이 변경은 그 내용을 src/service/ 아래 열두 leaf(state, guards, health, launchd, systemd, windows-scheduler, windows-taskxml, windows-ops, repair, orchestration, diagnostics, cli)로 옮기고, 원래 src/service.ts는 141개 공개 이름을 그대로 다시보내는 facade(약 30줄)로 남깁니다. 여덟 개 테스트가 이 경로를 문자열로 가리키더라도 파일을 고치지 않아도 됩니다.

여기서 제일 위험한 실패는 "테스트 훅 싱글톤이 둘로 갈라지는 것"입니다. 타입체크로는 안 잡힙니다. PR은 querySchtasksForTests/finalizeHooks(windows-scheduler.ts), ownedWindowsSchedulerStages(windows-ops.ts), uninstallServiceHooksForTests(orchestration.ts)를 각각 한 모듈에만 두고, tests/service/service.test.ts의 afterEach가 건드리는 바인딩이 실제 생산 코드와 같게 유지한다고 말합니다. 이 계약이 깨지면 Windows 설치/제거 테스트가 가짜로 통과하거나, 반대로 실제 훅이 안 리셋됩니다.

한 줄은 일부러 바꿨습니다. 원래 세 곳이 import.meta.dir으로 경로를 잡았는데, 파일이 한 디렉터리 내려가면 의미가 바뀝니다. state.ts가 serviceSourceDir = dirname(import.meta.dir)을 내보내고 그 세 곳이 그걸 쓰게 해서, 예전처럼 src/ 기준으로 고정합니다. 또 상대 import 60개가 leaf 깊이에 맞게 다시 잡혔고, state.ts에서 빠졌던 constants as fsConstants도 복구했다고 적혀 있습니다.

구조 문서도 같이 갑니다. src/service/는 새 top-level src 구역이라 scripts/structure-ssot.ts가 문서로 주장하지 않으면 실패합니다. 그래서 structure/manifest.json과 structure/runtime.md에 영역과 leaf 이름을 넣었습니다. grace undocumented로 우회하지 않은 점도 맞습니다.

우선순위 66은 cleanup(#4491)보다 파일이 크고 플랫폼 훅이 많아서 실수 비용이 더 크기 때문입니다. 그래도 사용자 기능 추가는 아니고, open-PR 경합 0인 타이밍의 분할이라 전략 점수는 높습니다. base는 #4491 브랜치(codex/260913-split-storage-cleanup)이고, 로컬 스위트는 안 돌렸으며 hygiene은 역시 missing_regression_test로 막혀 있습니다. tip(#4493) CI가 진짜 증명입니다.

src/service.ts facade - 141개 이름 재수출. 테스트 경로 문자열 유지.

src/service/state.ts serviceSourceDir - import.meta.dir 한 단계 내려간 뒤에도 src/ 앵커 유지. 여기가 틀리면 CLI/런타임 경로가 leaf 안으로 꺾입니다.

심볼 테스트 훅 네 개 - 선언이 한곳인지, setXForTests가 생산 바인딩을 치는지 tip CI의 tests/service/service.test.ts가 최종 확인.

structure/manifest.json / runtime.md - 새 src/service/ 문서화. ssot 게이트용.

심볼 hygiene missing_regression_test - 순수 이동 + 기존 스위트 오라클 vs 게이트 규칙 충돌. #4491과 동일.

메인테이너의 판단이 필요한 지점

  • serviceSourceDir 치환을 "허용된 비-verbatim"으로 확정할지(본문은 이미 의도라고 함).
  • refactor(storage): split cleanup.ts into cohesive leaf modules #4491 머지 직후 이 브랜치를 dev에 리베이스할지, tip까지 묶어서 올릴지.
  • Windows/macOS/Linux 서비스 스위트를 tip에서 반드시 통과시킨 뒤에만 머지할지.

너의 추천
#4491 다음에 머지할 두 번째 장으로 두세요. tip(#4493) CI에서 service 테스트가 초록인지 확인한 뒤 아래에서 위로 올리세요. hygiene은 export-parity 또는 service facade 스모크로 푸는 편이 낫습니다.

이 댓글은 grok-bot이 작성했습니다

@github-actions github-actions Bot removed the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 13, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11e11795cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/service/systemd.ts
import { writeServiceDefinitionFile } from "./windows-ops";

/** The `--port <n>` baked into the installed systemd user unit. Linux only. */
export function systemdListenPort(deps: { readUnit?: () => string } = {}): number | null {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include service leaves in lifecycle path filters

After this split, a subsequent change confined to src/service/systemd.ts or another src/service/*.ts leaf will not match either the pull-request/push filters in .github/workflows/service-lifecycle.yml:6-34 or the release gate regex in .github/workflows/release.yml:223-225, because both recognize only the exact src/service.ts path. Such service changes will therefore skip the cross-platform lifecycle workflow, and a release will not require a successful lifecycle run for them; add src/service/** consistently to both mechanisms.

Useful? React with 👍 / 👎.

Comment thread src/service.ts
process.exitCode = 1;
}
}
rem

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Retarget source-oracle tests after splitting the module

Making src/service.ts a barrel leaves existing source-oracle tests reading a file that no longer contains the implementation they assert on. Focused runs confirmed failures in tests/server/startup-prompt.test.ts:191, tests/service/systemd-install-cleanup-hardening.test.ts:6, and tests/windows/windows-deploy-close-regressions.test.ts:68; many additional assertions in tests/service/service.test.ts use the same path. Retarget each oracle to the relevant leaf module, or aggregate the leaf sources explicitly, so the full test gate is not unconditionally red and the assertions remain effective.

AGENTS.md reference: AGENTS.md:L220-L225

Useful? React with 👍 / 👎.

…eaves [skip ci]

Hosted CI on the stack tip went red because source-contract tests still
read the 30-line facade at src/service.ts. Point each assertion at the
owning leaf so the existing oracles keep their original strings, slices,
and negative matches. Import-specifier depth is the only assertion text
that changed, because the leaves sit one directory lower.
@github-actions github-actions Bot removed the test-exception-approved Maintainer approved a non-automated regression-test exception label Sep 13, 2026
@lidge-jun lidge-jun added the test-exception-approved Maintainer approved a non-automated regression-test exception label Sep 13, 2026
… [skip ci]

Hosted CI shard 2/4 still read src/service.ts from launchd-repair.test.ts.
Point each slice at the owning leaf and keep the original assertion strings.
@github-actions github-actions Bot removed the test-exception-approved Maintainer approved a non-automated regression-test exception label Sep 13, 2026
@lidge-jun lidge-jun added the test-exception-approved Maintainer approved a non-automated regression-test exception label Sep 13, 2026
Base automatically changed from codex/260913-split-storage-cleanup to dev September 13, 2026 09:02
@lidge-jun
lidge-jun merged commit a9a17b4 into dev Sep 13, 2026
9 checks passed
@lidge-jun
lidge-jun deleted the codex/260913-split-service branch September 13, 2026 09:02
@lidge-jun

Copy link
Copy Markdown
Owner Author

Closed as already landed on dev via #4495 (merge commit 6aaab49). The service split commits are ancestors of origin/dev.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Maintenance, CI, tests, refactors, or build changes (not a user-facing bug or feature). test-exception-approved Maintainer approved a non-automated regression-test exception

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant