# NapCatQQ Upstream Sync and Runtime Release Pipeline Design ## Background KT now carries a maintained `NapCatQQ` fork because QQ login, QR refresh, duplicate-login reset, and WebUI runtime state need source-level fixes. The production runtime image is a KT-derived Chinese desktop image: ```text kt-napcat-desktop-cn: ``` The current release loop still has a manual gap: 1. Build the `NapCatQQ` fork locally. 2. Stage the `NapCat.Shell` artifact with the API repository script. 3. Copy or build the Docker context on the NAS. 4. Verify the image. 5. Update API runtime image/profile values. 6. Push API/Admin and observe Jenkins/K8s. That is too easy to drift. It also does not answer a bigger operational question: when upstream `NapNeko/NapCatQQ` ships a new latest release, which upstream changes can KT safely sync, and which changes conflict with KT's forked login/runtime fixes? This design makes `NapCatQQ` its own release unit and adds a separate upstream release audit loop. The audit loop is read-only by default. It never merges upstream into KT automatically. Primary upstream metadata sources: - GitHub latest release REST API: `GET /repos/{owner}/{repo}/releases/latest`. - GitHub compare REST API: `GET /repos/{owner}/{repo}/compare/{basehead}`. - Local Git history checks: `git diff`, `git range-diff`, `git merge-tree`, and file-level hot-zone scans. ## Goals 1. Create an independent `NapCatQQ` Jenkins pipeline for fork validation and runtime image release. 2. Add a scheduled upstream latest-release audit that detects new upstream releases without automatically merging them. 3. Classify upstream changes as safe candidate, manual-review required, or blocked. 4. Produce auditable reports showing upstream deltas, KT fork patches, overlap files, hot-zone hits, and recommended action. 5. Build verified `kt-napcat-desktop-cn` images from selected KT fork refs. 6. Promote verified runtime images into API deployment through explicit parameters or promotion metadata, not ad hoc manifest edits. 7. Keep production release completion tied to online smoke evidence, not Jenkins/K8s success alone. ## Non-Goals - Do not bypass QQ/Tencent captcha, new-device verification, or account safety flows. - Do not auto-merge upstream `release-latest` into KT's maintained branch. - Do not push to the upstream `NapNeko/NapCatQQ` repository. - Do not treat OneBot heartbeat as QQ account login success. - Do not make the API repository own NapCat source patches. - Do not store GitHub tokens, Jenkins credentials, SSH keys, WebUI tokens, or Docker registry credentials in Git. - Do not automatically migrate existing production accounts to a new runtime image without explicit release confirmation. ## Repositories and Ownership ### `D:\MyFiles\KT\GitHub\NapCatQQ` Owns KT's NapCat source fork and source-level tests. Required remotes: ```text upstream = https://github.com/NapNeko/NapCatQQ.git origin = KT writable mirror or fork repository ``` The current local `origin` may point at upstream. The implementation must correct that before any Jenkins push path is enabled. Jenkins must refuse to push if `origin` resolves to `NapNeko/NapCatQQ`. Recommended long-lived branches: ```text kt/runtime-maintenance kt/sync/ kt/release/ ``` ### `D:\MyFiles\KT\Node\kt-template-online-api` Owns: - `scripts/napcat-desktop-cn-stage-build.mjs` - `ci/napcat-desktop-cn/Dockerfile` - `ci/napcat-desktop-cn/verify.sh` - API runtime image/profile parameters and deployment contract - API-side login/SSE safety guards The API repository should not commit `NapCat.Shell.zip` artifacts. ### Jenkins and NAS Docker Own: - Scheduled upstream release audit execution. - NapCat fork build/test execution. - NAS-local Docker image build and verification. - Runtime promotion metadata and deployment observation artifacts. ## Pipeline Overview ```mermaid flowchart TD Upstream["NapNeko/NapCatQQ latest release"] --> Audit["KT-NapCatQQ-Upstream-Sync"] Fork["KT NapCatQQ fork"] --> Audit Audit --> Report["Audit report artifact"] Audit --> Candidate["Optional kt/sync/ candidate branch"] Candidate --> Human["Human review and approval"] Fork --> Release["KT-NapCatQQ-Runtime-Release"] Human --> Release Release --> Image["kt-napcat-desktop-cn:"] Image --> ApiDeploy["API Jenkins deploy with runtime image/profile params"] ApiDeploy --> Observe["deploy-observation + online smoke"] ``` Two Jenkins jobs are required: ```text KT-NapCatQQ-Upstream-Sync KT-NapCatQQ-Runtime-Release ``` The upstream sync job is scheduled and read-only by default. The runtime release job is manually triggered, or triggered by an approved candidate branch. ## Upstream Sync Audit Job ### Trigger - Scheduled, for example once per day. - Manual trigger with `UPSTREAM_RELEASE_TAG` override. ### Inputs ```text UPSTREAM_REPO=NapNeko/NapCatQQ FORK_BRANCH=kt/runtime-maintenance LAST_ACCEPTED_UPSTREAM_BASE= UPSTREAM_RELEASE_TAG= CREATE_CANDIDATE_BRANCH=false by default ``` ### Steps 1. Fetch upstream metadata. - If `UPSTREAM_RELEASE_TAG` is empty, call GitHub latest release API. - Resolve the release tag to a peeled commit with `git ls-remote --tags upstream ^{}` or equivalent. - Record release name, tag, commit, published time, and release URL. 2. Fetch fork and upstream history. - Fetch `upstream`. - Fetch KT writable `origin`. - Checkout `FORK_BRANCH`. - Confirm working tree is clean. 3. Compute upstream delta. - `upstreamDelta = LAST_ACCEPTED_UPSTREAM_BASE..UPSTREAM_RELEASE_COMMIT` - Capture commits, changed files, rename/delete status, package lock changes, and hot-zone hits. 4. Compute KT fork patch set. - `forkPatch = LAST_ACCEPTED_UPSTREAM_BASE..FORK_BRANCH` - Capture KT-only commits and files. 5. Detect overlap and risk. - `overlapFiles = upstreamDelta.files intersect forkPatch.files` - `hotZoneFiles = upstreamDelta.files matching login/runtime/build patterns` - Run `git merge-tree` or an equivalent dry merge against the release commit. - Run `git range-diff` when a candidate rebase can be generated. 6. Classify the release. - `safe-candidate`: no hot-zone hit, no overlap with KT patch files, lockfile/build changes pass static checks. - `manual-review`: hot-zone touched, overlap touched, package/build graph changed, or range-diff is non-trivial. - `blocked`: dry merge conflicts, tests cannot install/build, artifact structure changed, or required upstream metadata cannot be verified. 7. Write artifacts. - Markdown human report. - JSON machine report. - File lists for upstream delta, fork patch, overlap, and hot zones. - Suggested next action. 8. Optionally create candidate branch. - Only allowed when classification is `safe-candidate` or manually requested. - Branch name: `kt/sync/`. - Candidate creation applies KT patches on top of upstream release without merging back to `FORK_BRANCH`. - Candidate branch must be pushed only to KT writable remote. - Candidate branch must never auto-merge. ### Hot Zones The audit treats these as high-risk areas: ```text packages/napcat-core/**/login* packages/napcat-core/**/qrcode* packages/napcat-shell/** packages/napcat-framework/** packages/napcat-webui-backend/**/QQLogin* packages/napcat-webui-backend/**/Data* packages/napcat-webui-backend/**/auth* packages/napcat-webui-frontend/** packages/napcat-adapter/** packages/napcat-onebot/** packages/napcat-vite/** package.json pnpm-lock.yaml tsconfig*.json vite*.ts ``` This list is intentionally conservative. If upstream changes login state, QR generation, WebUI auth, OneBot startup, or build packaging, the sync must go through human review. ### Audit Report Contract JSON artifact: ```json { "upstream": { "repo": "NapNeko/NapCatQQ", "releaseTag": "v0.0.0", "releaseCommit": "0000000000000000000000000000000000000000", "publishedAt": "2026-06-24T00:00:00Z", "releaseUrl": "https://github.com/NapNeko/NapCatQQ/releases/tag/v0.0.0" }, "fork": { "branch": "kt/runtime-maintenance", "headCommit": "0000000000000000000000000000000000000000", "lastAcceptedUpstreamBase": "0000000000000000000000000000000000000000" }, "classification": "manual-review", "reasonCodes": ["HOT_ZONE_CHANGED", "FORK_PATCH_OVERLAP"], "upstreamChangedFiles": [], "forkPatchFiles": [], "overlapFiles": [], "hotZoneFiles": [], "candidateBranch": null, "recommendedAction": "Review hot-zone changes before creating a candidate branch." } ``` The report must be safe to archive and share. It must not include tokens, secrets, private env files, QQ passwords, captcha tickets, or WebUI credentials. ## Runtime Release Job ### Trigger - Manual trigger with an approved source ref. - Optional upstream-sync trigger after a candidate branch is reviewed and approved. ### Inputs ```text NAPCAT_SOURCE_REF=kt/runtime-maintenance or kt/sync/ UPSTREAM_RELEASE_TAG= UPSTREAM_RELEASE_COMMIT= RUNTIME_PROFILE=desktop-cn-vN NAPCAT_BASE_IMAGE=mlikiowa/napcat-docker@sha256: API_REF=main PROMOTE_TO_API=false by default CANARY_ACCOUNT_ID= ``` `NAPCAT_BASE_IMAGE` must resolve to a digest before Docker build. If the user chooses to base on `mlikiowa/napcat-docker:latest`, the pipeline must first pull it, resolve its `RepoDigest`, and use the digest in the actual Docker build and release marker. ### Steps 1. Checkout `NapCatQQ`. - Use KT writable fork remote. - Checkout `NAPCAT_SOURCE_REF`. - Confirm clean tree. - Record fork commit. 2. Install and verify source. - `pnpm install --frozen-lockfile` - Focused login/runtime tests. - `pnpm run typecheck` - `pnpm run build:webui` - `pnpm run build:shell` - `pnpm run build:framework` 3. Checkout API repository as a build integration dependency. - Use `API_REF`. - Run the stage-build script with `--napcat-root`. - Ensure the staged `fork-artifact.json` contains: - upstream release tag - upstream release commit - last accepted upstream base - fork commit - dist sha256 - `napcat.mjs` sha256 - base image digest - Jenkins build URL 4. Build NAS-local Docker image. - Build from staged context. - Tag immutable image: ```text kt-napcat-desktop-cn:-kt. ``` - Tag promotion alias only after verify: ```text kt-napcat-desktop-cn: ``` 5. Verify image. - Run a temporary container. - Execute `/ci/napcat-desktop-cn/verify.sh`. - Verify locale, timezone, fonts, XDG paths, hidden Docker markers, fork marker, artifact hash, and critical runtime symbols. - Remove temporary container. - Inspect image ID and digest-like local image ID. 6. Archive release metadata. - `napcat-runtime-release.json` - Docker image inspect output. - `fork-artifact.json` - test summaries. 7. Optional API promotion. - If `PROMOTE_TO_API=true`, trigger API Jenkins with runtime image/profile parameters. - API deploy must update K8s runtime env through a controlled deployment parameter or generated manifest overlay. - API deploy must not require hand-editing `k8s/prod/api.yaml` for every runtime image. 8. Deployment observation and smoke. - Run API `deploy-observation`. - Verify API `/health/runtime`. - Verify K8s deployment generation, pod image, ready replicas, restart count, and logs. - For QQ login behavior, complete only after a real account smoke or a clearly documented manual-scan wait state. ## API Promotion Contract The API Jenkinsfile should gain optional parameters: ```text QQBOT_NAPCAT_IMAGE_OVERRIDE= QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE= ``` When set, the K8s deploy stage must apply these as runtime env values for the API deployment. The implementation may use a generated manifest overlay or `kubectl set env`, but it must leave secrets out of Git and record the effective values in deployment evidence. API tests must enforce: - Production no longer depends on `latest`. - The runtime image override path is explicit. - The default profile value is still a known safe fallback. - The API code does not silently downgrade to older runtime profiles. ## Data Flow ```mermaid sequenceDiagram participant Upstream as GitHub Upstream participant Sync as Upstream Sync Jenkins participant Fork as KT NapCatQQ Fork participant Release as Runtime Release Jenkins participant ApiRepo as API Repo participant Docker as NAS Docker participant ApiDeploy as API Jenkins Sync->>Upstream: read latest release metadata Sync->>Fork: fetch maintained branch Sync->>Sync: diff upstream delta vs KT fork patch Sync-->>Fork: optional kt/sync/ branch, never auto-merge Sync-->>Sync: archive audit report Release->>Fork: checkout approved source ref Release->>Release: test, typecheck, build webui/shell/framework Release->>ApiRepo: run stage-build script Release->>Docker: build and verify kt-napcat-desktop-cn image Release->>ApiDeploy: optional promote with image/profile params ApiDeploy-->>Release: rollout and smoke evidence ``` ## Error Handling - GitHub API rate limit or outage: mark audit as `blocked` with retry advice; do not infer latest release from stale data unless explicitly allowed. - Upstream release has no resolvable tag commit: mark `blocked`. - Fork writable remote points to upstream: fail before push. - Dirty workspace: fail before audit candidate or release. - Hot-zone overlap: mark `manual-review`; do not create or merge a candidate unless explicitly requested. - Dry merge conflict: mark `blocked`. - `pnpm install`, tests, typecheck, shell/framework build failure: mark runtime release failed; do not build or promote an image. - Docker base image cannot resolve to digest: fail before build. - `verify.sh` fails: remove verify container, keep artifacts, do not tag promotion alias. - API promotion deploy succeeds but online smoke fails: keep deployment evidence separate from functional completion and provide rollback steps. ## Rollback Runtime rollback is controlled by the API runtime image/profile values: 1. Identify the last verified runtime image/profile from release artifacts. 2. Trigger API Jenkins with previous `QQBOT_NAPCAT_IMAGE_OVERRIDE` and profile. 3. Observe K8s rollout. 4. Existing online NapCat containers are not automatically rebuilt. Account-level migration remains explicit because container rebuilds affect QQ device/login risk. ## Validation Strategy ### Upstream Sync Job Local/job validation: ```powershell pnpm --dir mcp/ktWorkflow run self-test git diff --check ``` Jenkins dry run must show: - Latest release metadata resolved. - Last accepted upstream base resolved. - Upstream delta file list. - Fork patch file list. - Overlap/hot-zone classification. - Report artifact paths. ### Runtime Release Job NapCatQQ: ```powershell corepack pnpm install --frozen-lockfile corepack pnpm --filter napcat-test run test -- loginQrcodeRefresh webuiLoginSourceWiring webuiQQLoginHandlers webuiLoginRuntime corepack pnpm run typecheck corepack pnpm run build:webui corepack pnpm run build:shell corepack pnpm run build:framework ``` API integration: ```powershell corepack pnpm exec jest test/modules/qqbot/napcat/napcat-desktop-cn-image.spec.ts test/modules/qqbot/napcat/runtime-protocol-profile.spec.ts --runTestsByPath --runInBand corepack pnpm run typecheck git diff --check ``` NAS image: ```bash docker build --build-arg NAPCAT_BASE_IMAGE="$NAPCAT_BASE_IMAGE_DIGEST" -t "$IMMUTABLE_TAG" -f "$STAGED_CONTEXT/ci/napcat-desktop-cn/Dockerfile" "$STAGED_CONTEXT" docker run -d --name "$VERIFY_CONTAINER" "$IMMUTABLE_TAG" docker exec "$VERIFY_CONTAINER" sh /ci/napcat-desktop-cn/verify.sh docker rm -f "$VERIFY_CONTAINER" docker tag "$IMMUTABLE_TAG" "$PROMOTION_TAG" ``` Online: - API `deploy-observation` passes. - API `/health/runtime` passes. - For login-runtime releases, a canary account either logs in successfully or reaches a clear captcha/new-device/manual-scan pending state with a fresh QR and correct SSE/Admin status. ## Completion Criteria - `NapCatQQ` has a standalone Jenkins release path. - A scheduled audit detects upstream latest releases and writes safe reports. - Upstream sync never auto-merges into KT maintenance branches. - Hot-zone conflicts are blocked or marked for manual review. - Runtime images are built from approved fork refs and verified inside containers. - API deployment consumes runtime image/profile through an explicit promotion contract. - Jenkins/K8s deployment evidence and online QQBot/NapCat smoke evidence are both captured before claiming a release complete.