kt-template-online-api/docs/superpowers/specs/2026-06-24-napcatqq-upstream-sync-runtime-release-pipeline-design.md

456 lines
16 KiB
Markdown

# 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:<profile>
```
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/<upstream-release-tag>
kt/release/<runtime-profile>
```
### `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/<tag> candidate branch"]
Candidate --> Human["Human review and approval"]
Fork --> Release["KT-NapCatQQ-Runtime-Release"]
Human --> Release
Release --> Image["kt-napcat-desktop-cn:<profile>"]
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=<commit recorded from previous release marker>
UPSTREAM_RELEASE_TAG=<optional manual override>
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 <tag>^{}` 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/<release-tag>`.
- 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/<tag>
UPSTREAM_RELEASE_TAG=<tag recorded in audit>
UPSTREAM_RELEASE_COMMIT=<commit recorded in audit>
RUNTIME_PROFILE=desktop-cn-vN
NAPCAT_BASE_IMAGE=mlikiowa/napcat-docker@sha256:<digest>
API_REF=main
PROMOTE_TO_API=false by default
CANARY_ACCOUNT_ID=<optional>
```
`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:<upstream-tag>-kt.<jenkins-build>
```
- Tag promotion alias only after verify:
```text
kt-napcat-desktop-cn:<runtime-profile>
```
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/<tag> 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.