# Project Rules These rules describe the mandatory workflow for JWeBot changes. They are not advice; future changes must either follow them or document an explicit user exception. ## Release Discipline - Version format is `alpha X.Y.Z.MMDD`. - Patch changes increment `Z`; minor version changes require explicit user approval. - A release change must update: - `VERSION`; - root `pyproject.toml`; - every package `pyproject.toml`; - every package `__version__`; - `README.md`; - `CHANGELOG.md`. - Do not mark production complete merely because code was committed. Production is complete only after staging, cutover, acceptance, observation, and backup restore checks pass. ## Mandatory Pre-Production Gates Before touching production runtime files on production host: 1. Local working tree must be understood and intentionally staged. 2. Local gate must pass: ```sh PATH="$PWD/.venv/bin:$PATH" ./tools/check-local.sh ``` 3. Upload a clean staging snapshot using Git-tracked files only. 4. Verify staging file hashes against the local tree. 5. Run the complete production host gate with: ```sh PATH=/opt/wechat-local-ocr/venv/bin:$PATH ./tools/check-local.sh ``` 6. Verify WeChat is logged in and the ready main window is at least `700x500`. 7. Verify OCR queues are empty. 8. Verify Edge SQLite `PRAGMA quick_check` returns `ok`. ## Production Cutover - Use only `deploy/scripts/deploy-jwebot-production.sh` for normal production cutover. - The deployer must record both root and user systemd topology, runtime files, configuration, and an online SQLite backup. - The deployer must disable legacy system OCR services and keep the active production topology to: ```text jwebot-edge.service wechat-ocr-adaptive-recorder.service ``` - Never skip Edge health, adaptive restart stability, queue, WeChat ready, or SQLite gates. - If any gate fails, confirm rollback state before retrying. ## Backup And Restore - Pre-deploy and post-deploy baselines must include runtime files, systemd units, environment/configuration, service states, and an online SQLite backup. - Local and router Restic snapshots must be restored into isolated directories. - Restore validation requires: - `sha256sum -c SHA256SUMS`; - SQLite `PRAGMA quick_check`; - no restore into live paths during validation. ## GUI Delivery - The guarded sender must validate the selected group before drafting and after drafting. - The sender may click a scaled send-button coordinate first, but must retain a fallback path and visual confirmation. - Any GUI send optimization must keep: - GUI lock acquisition; - tokenized draft/send protocol; - group fingerprint revalidation; - uncertain-delivery quarantine; - privacy-safe per-step telemetry. ## Telemetry And Reports - Latency work must preserve or improve per-step telemetry. - The following stages must be visible when relevant: - OCR capture and scan; - queue wait and process; - Edge routing; - fast ACK preparation, GUI send, confirmation, and end-to-end latency; - provider generation; - final GUI delivery; - `gui.send.step`, `gui.bridge.step`, and `gui.send.total`. - Reports must separate p50/p95 for DeepSeek and OpenClaw when both are used. - Reports must describe fixed waits, polling intervals, screenshot captures, VNC input actions, and fallback paths in plain Chinese. - Telemetry must not log message body, sender name, raw group id, reply text, secrets, environment values, or provider payloads. ## Plugin Rules - Registered slash commands must be declared in the ownership inventory. - Prefer reviewed plugin descriptors plus generated adapters for new commands. - Run `tools/sync-local-extensions.py --check` after plugin inventory changes. - Plugin code must not access GUI, raw SQLite/Ledger, shell, SSH, Docker, environment secrets, or unrestricted network. - Runtime command ownership freezes at startup. Do not mutate command ownership during request handling. ## Access Rules - External production access uses an operator-provided SSH host alias. - Root access is obtained by logging in as `jwebot` and then running `su -`. - Do not enable direct root SSH or loosen the jump key `no-port-forwarding` restrictions without explicit user approval.