Imported from A158Coke/WotbTools (
.github/AGENTS.md). Install upstream withnpx skills add A158Coke/WotbTools --skill .github. Copyright stays with the author.
Workflow ownership
The repository has one pull-request routing entry point and service-owned production workflows. Application owners run only when owned inputs change on main, cancel older runs for the same service, recheck main immediately before publishing latest (deploy/check-latest-main.sh), and deploy that service's latest. All production owners declare identical owned inputs in both on.push.paths and PRODUCTION_INPUT_PATHS. deploy/check-production-freshness.sh checks source ancestry and owned inputs; manual dispatch requires exact current main, and an owner that force-updates its transport ref (asset-origin.yml) additionally requires the exact current main immediately before that mutation (PRODUCTION_REQUIRE_EXACT_MAIN=1). Host mutations use the host-level flock; do not restore the removed Release/Build/Deploy/Tofu reusable-workflow DAG.
ci-gate.ymlis the only PR entry point and ownsCI / Required Gate. It verifies PR identity, routes changed paths to reusable owner CI workflows, and aggregates affected results. Each OpenTofu root validates only when its owner is affected; validation runsfmt,init -backend=false,validate, and root safety fixtures only. PR CI has no production credentials, SSH, image push, production state, plan, or apply. The three data-update workflows remain separate and can dispatch CI for the exact open PR head.business-api.yml,frontend.yml,keycloak.yml, andai-service.ymlown their individual application image and deploy pipelines. TX images use TCR; Yecao images use GHCR. Each owner publisheslatestonly while its owned inputs are unchanged on current main (exact current main, or main advanced elsewhere) and deploys that service'slatest; if newer main changed its owned inputs the run is superseded — it skipslatestand deploy without failing, and the newer run publishes. Business API runs read-only consumer-side dependency probes before mutation. Keycloak retains its runtime, OpenTofu, and final verification chain. Replay parsing runs in the browser: there is no parser-worker, RabbitMQ, or MinIO owner, and none may be reintroduced (scripts/ci/test-workflow-contract.shasserts their absence).caddy.ymlis the independent TX gateway owner. It stages and validates Caddy configuration/assets, reconciles only the gateway, refreshes frontend trusted-peer state when needed, and verifies TLS, redirects, and required routes. It does not build an application image or depend on database/admin credentials.business-postgres.ymlandkeycloak-postgres.ymlown their TX runtime and host-local OpenTofu root.observability.ymlowns Yecao observability runtime and Grafana dashboard OpenTofu. Keep each provider, state, secrets, plan guard, and readiness check scoped to its owner.komodo-controller.ymlis the bootstrap and break-glass owner for the Komodo control plane; it is the only workflow permitted to read the TencentCloud DNSPod credentials. GitHub Actions owns controller reconciliation, Docker Compose owns the Yecao Core/Mongo runtime (deploy/komodo), and OpenTofu owns only the controller DNS record (infra/tofu/komodo). Komodo must never own its own Core lifecycle. Public ingress stays with the independentcaddy.ymlowner, which publisheskomodo.wotbtools.com, proves the WireGuard upstream first, and then requires the public answer to equal the private one — it reads no Komodo release pin, anddeploy/komodo/**is not a Caddy-owned input. Workload adoption remains a later phase. Declarative Komodo resources live ininfra/komodo/resources/**(K4.1), owned by no production workflow: that path routes only to the non-productiondeploymentPR gate, which runsscripts/ci/test-komodo-resources.py, and it must never be added to the controller'son.push.paths/PRODUCTION_INPUT_PATHS(a resource TOML change may not reconcile Core/Mongo/DNS). The single narrow exception isinfra/komodo/resources/asset-origin.toml, which is also an input of the asset-origin source-transport gate (see theasset-origin.ymlbullet): that gate may mutate only the asset-owned transport pair (GitHub pointer branch + Gitee transport branch), and must not apply ResourceSync, mutate Komodo resources, or deploy the Stack. No other file under the resource tree is a production input. The sync is applied by a human in the UI only:managed = false,delete = false,webhook_enabled = false.komodo-periphery.ymlis the independent owner of every Komodo Periphery agent (deploy/periphery), one host per job in a strict chain:reconcile_yecao→reconcile_tx1→reconcile_tx2, eachneedsthe previous one so an established host is always proven before a new host is mutated. GitHub Actions owns each agent's systemd lifecycle; Komodo Core owns only the Server relationship and never installs, restarts, or manages the agent that connects to it. There is exactly one lifecycle implementation (lib.sh/install.sh/verify.sh/reconcile.share target-agnostic) and the per-host differences live in revieweddeploy/periphery/targets/<target>/target.envdata:connect_as, the host's own mutation lock (/opt/wotb/.deploy.lockfor Yecao,/opt/wotb-tx/.deploy.lockfor TX1,/opt/wotb-tx2/.deploy.lockfor TX2, never a Periphery-only lock), the staging root (/opt/periphery,/opt/wotb-tx/periphery,/opt/wotb-tx2/periphery) and the privilege model (root, orsudofor a non-root SSH account, which re-executes throughsudo -nand preserves only the generic credential). Each job verifies the pinned release artifact's SHA256 and stages only the verified bytes plus that host's own profile — no host downloads a binary and no host receives another host's profile. Every agent is outbound only (core_addresses = ["http://10.20.0.2:9120"],connect_as= its target,server_enabled = false), so no listener exists on:8120, and the effective config is verified byte-for-byte against the target's reviewed config. The one generic bootstrap variable isKOMODO_PERIPHERY_ONBOARDING_KEY(the workflow maps each host's own secret into it; the scripts never know a host-specific secret name): it reaches Periphery only through the transient/run/komodo/periphery-bootstrap.env, is never persisted, and is not required once the durable/etc/komodo/keys/onboarding-completemarker exists — completion is never inferred fromkeys/periphery.key, which v2.3.3 generates at startup even when onboarding fails, and a failed bootstrap stops the service so no process keeps the credential. A missing marker with no credential fails closed instead of re-onboarding, and Yecao's deleted secret must never be referenced again. The Alibaba asset host (ali-sh-asset-01) is not part of this automated chain: its Periphery agent is manually bootstrapped and manually lifecycle-managed today, is already onboarded and healthy, andinfra/komodo/resources/servers.tomlonly declares the existing Server so ResourceSync can adopt it by name. Automating the Alibaba/mainland Periphery lifecycle is intentionally deferred; no Alibaba SSH secret or reusable Periphery workflow exists in this repository.deploy/periphery/**is owned by this workflow alone and must not trigger the Komodo controller or the Caddy gateway.asset-origin.ymlowns only the mainland source-transport gate for the Komodo Stackwotbtools-asset-origin; it does not deploy the Stack or mutate Komodo resources. It checks out and freezes the triggeringmainevent SHA, serializes transport mutation throughproduction-gitee-mirror, publishes that exact frozen commit to the derived GitHubasset-originpointer branch (contents: write, nothing else) and then to the asset-ownedA158Coke/WotbtoolsGiteeasset-originbranch using the existing Gitee credential, and finally requires Giteerefs/heads/asset-originto equal that SHA before rollout may continue. The GitHub pointer branch is required because the pinned Frontend/Business mirror action force-pushes every GitHub branch to Gitee with--prune; a Gitee-only ref would be deleted, while a source branch is carried. It never touches shared Giteemain, which the Frontend/Business API mirrors own and whose movement must not change the asset deploy source. Because it force-updates its transport ref, it declaresPRODUCTION_INPUT_PATHSequal to its trigger paths and runsdeploy/check-production-freshness.shwithPRODUCTION_REQUIRE_EXACT_MAIN=1immediately beforegit push --force, so bothpushandworkflow_dispatchfail closed without mutating the ref when the frozenSOURCE_SHAis no longer exact currentmain.infra/komodo/resources/asset-origin.tomlis the only resource-tree input, and the Stack pinsbranch = "asset-origin"(never sharedmain). ResourceSync remains human-applied and the Stack keepsdeploy = false; deploying it is a manual Komodo action.android-release.yml,database-backup.yml,cleanup-images.yml,prod-diagnostics.yml, andtx-runtime-check.ymlkeep their independent release, backup, cleanup, diagnostics, and TX read-only runtime-gate responsibilities.tx-runtime-check.ymlis manual-only, uses repository-level Actions secrets / variables, serializes withproduction-maintenance, requires the exact currentmain, and copies only the four verifier/helper scripts from that checked-out SHA into an ephemeral/tmp/wotb-tx-runtime-check-<run>-<attempt>bundle. It derives the Frontend/Business API image refs from the running containers, executes the staged verifier againstWOTB_TX_DIR=/opt/wotb-txunder the production host lock, and cleans the temporary bundle afterward. It must never stage production Compose/config/data, deploy, recreate, stop, apply OpenTofu, or change DNS.android-offload-probe.ymlis the manual link-health probe for the Android offload path (runner → COS → TX1 → Tsinghua drive): dispatch-only, uses repository-level Actions secrets / variables, serialized withproduction-maintenanceand mutually excluded withandroid-release(job-level concurrency group — both write the same Seafile repository), pinned to the exact currentmain, and it only creates and then deletes its own_offload-probe-<run>.binscratch object on the drive plusandroid/probe/*on the release COS bucket; verified absence is mandatory, so a probe that cannot delete its own scratch object fails instead of staying green. It must never touch release state (tag, staging evidence, productionversion.json, origin seed), and its drive protocol must stay in sync withandroid-release.yml's upload step.update-tankopedia.yml,update-equipment.yml, andupdate-crew-skills.ymlremain independent automation entry points. Preserve their contents/PR/actions permissions and exact-head CI dispatch protocol; do not fold them into production workflows.
Change rules
-
Every new PR selects at least one
area/*label fromdeploy/observability/dev-metrics/area-taxonomy.json; multiple areas are allowed. The PR gate emits an advisory for missing or unknown areas. Extend the taxonomy through an explicit reviewed change, never an ad hoc label. -
Before changing a workflow, read its real scripts and the relevant
deploy/AGENTS.md/OpenTofu contracts. Keep CI commands consistent with local commands and the pinned JDK/Node versions. -
Do not place credentials in workflow files. Scope
secrets.*,vars.*, and job permissions to the job that consumes them. TX production jobs use the existing repository-level Actions secrets / variables; do not invent an unconfigured Yecao environment. -
Main-triggered production workflows must reject non-ancestor sources and changes to owned inputs before expensive work, then recheck immediately before staging or host mutation as applicable. Application workflows also recheck immediately before publishing
latest: unchanged owned inputs on current main publish; changed owned inputs mark the run superseded (check-latest-main.shexit 10 →latest_published=false, downstream smoke/deploy skipped, run stays green). Same-service runs still cancel older ones when new main arrives. Manual dispatch must remain pinned to the exact currentmainSHA. Keep TX and Yecao host locks held across runtime mutation, OpenTofu plan/apply/second-plan, and verification where the service contract requires it. -
OpenTofu ownership stays with the matching standalone root workflow. PR validation never reads production state or creates an authenticated production plan. Main workflows re-plan locally and apply the exact guarded saved plan.
-
Keep the stable
CI / Required Gateas the only required PR check. Do not add heavy, non-gating jobs to every change or duplicate PR test suites inside production deployment workflows. -
Do not restore discarded PR #380 content or architecture. It is not a source for this plan.
Workflow inventory (39)
ci-gate.yml, 15 reusable ci-<owner>.yml workflows, business-api.yml, frontend.yml, frontend-replica.yml, caddy.yml, keycloak.yml, ai-service.yml, business-postgres.yml, keycloak-postgres.yml, observability.yml, alloy-tx.yml, komodo-controller.yml, komodo-periphery.yml, asset-origin.yml, production-worker.yml, tx-runtime-check.yml, android-release.yml, android-offload-probe.yml, database-backup.yml, cleanup-images.yml, prod-diagnostics.yml, update-tankopedia.yml, update-equipment.yml, and update-crew-skills.yml.
The one-off tx-gitee-build-path-validation.yml benchmark is retired: Business API and Frontend own the production Gitee exact-SHA build/TCR publication path. Deleted workflow files can retain historical Actions runs; those records are not active entry points. Keep reusable owner CI, release, deployment, data-update and recurring/manual operations workflows based on their responsibility, not their run count.
