# Architecture and maintenance [简体中文快速入口](architecture.zh.md) · This is the canonical contract; the Chinese page is a short task-oriented guide, not a second copy. ## Purpose `@cningan/dsh-startup-check` provides `plugin_check` to detect `@cningan` plugin breakage before a user restarts DSH. It runs only when called; it is not a watcher, health monitor, restart mechanism, or hot-reload path. The companion `plugin-fault-diagnosis` skill explains what to do after a failed check. ## Diagnostic domains and change routes | Domain | Contract / when to use | Main files | |---|---|---| | Static preflight | Always checks `lib/*.js` syntax, package structure, every `@cningan` reference in `cordis.patch.yml`, and config-tree assembly. `target` narrows the plugin. | `lib/index.js` | | Host boot | `live:true` starts a separate `dsh --profile web --port 0 --no-open` instance and confirms shutdown. | `lib/index.js`, `lib/smoke.js` | | Page render | `page:true` implies live; headless Edge/Chrome over CDP records exceptions, console errors, and non-empty render evidence. | `lib/page-smoke.js` | | Process audit | `sweep:true` audits DSH processes without booting; may also accompany live/page. | `lib/instances.js` | | Diagnosis playbook | Troubleshooting instructions served as a bundled Skill while this plugin is loaded. | `assets/plugin-fault-diagnosis.md`, `lib/index.js` | | Tests and release | Source checks/tool-body regression and npm release procedure. | `package.json`, `test/tool-body-selftest.mjs`, `docs/releasing.md` | Update this contract when a check, parameter, result meaning, file responsibility, or safety boundary changes. Do not maintain a second object map or separate architecture map. ## Safety invariants - Static checks read the inspected Web profile; they do not rewrite its config. The running DSH Web host is never restarted or killed by this plugin. - Live smoke uses OS-assigned `--port 0` and `--no-open`, has bounded boot/shutdown timeouts, and passes cancellation to subprocesses. It currently inherits the host `~/.dsh`; a leaked smoke can therefore share sessions/storages, so shutdown confirmation is part of the contract. - Process matching is by executable identity and exact DSH entry point, never a substring like `dsh` in an arbitrary command line. Hosts and transient commands are never killed. - `killStray:true` may target only positively identified `--port 0` smoke processes created by this run or older than 300 seconds. It validates an exact PID and re-reads the process table to verify the result; recent foreign smokes are report-only. - The page check uses a throwaway browser profile. Missing/unavailable browser or process-table access means `not tested`, not a plugin failure or a clean pass. - Instance enumeration and the page-browser install probe are Windows-specific. The page observation window is fixed at 15 seconds. ## Integration contracts that regressions must preserve - Every `ctx.subprocess.spawn` call supplies an explicit `cwd`. - Collected subprocess output is consumed with non-destructive `readFrom(offset)`, not `finalize()`. - `tested:false` stays distinct from a failing plugin; infrastructure absence must not be reported as a plugin defect. - The smoke/process engines live once in `lib/smoke.js` and `lib/instances.js` with `spawn` injected by the caller. `lib/page-smoke.js` uses direct Node filesystem/network primitives because no equivalent `ctx.*` temporary-directory/WebSocket contract exists; migrate it if DSH adds one. ## Verification Run the repository's machine-checkable source and tool-body checks: ```powershell npm test ``` The tool-body self-test invokes the real `execute()` in a fresh Node process. When adding or renaming files under `lib/`, update its explicit copy list. `npm test` does not replace host integration: use `plugin_check` static checks after plugin source changes, and opt into live/page/sweep only when that runtime check is specifically needed. ## Known limits - `page:true` recognizes common Edge/Chrome paths only; unsupported/missing browser is skipped, not failed. - Page observation is fixed to 15 seconds; the tool does not expose an override. - `lib/instances.js` uses Windows PowerShell/WMI; other platforms cannot provide the same process-table guarantee. - Live smoke inherits `~/.dsh` today. Moving it to an isolated home is a product decision, not current behavior. - The `cordis.patch.yml` reference scan is regex-based rather than YAML-aware. A commented example resembling `name: '@cningan/…'` may be reported as an active package reference; interpret the exact detail in context and keep a regression test when changing the scanner. - Tool check labels/details are currently Chinese; there is no localization layer.