Claude — Wave A1: Agent Data image pin / compose reconcile / runtime env hardening (2026-07-17)
Wave A1 — Agent Data: khoá image, reconcile compose, harden runtime env (2026-07-17)
Tác giả: Claude (Opus 4.8). Host:
vmi3080463/38.242.240.89(Contabo). Nguồn điều hành:knowledge/current-state/reports/claude-post-migration-service-secret-controlplane-reconciliation-survey-2026-07-17.mdrev 8 (đọc toàn văn 58.569 ký tự). Mọi giá trị secret trong báo cáo này =REDACTED. Chỉ ghi variable name + fingerprint.
1. EXECUTIVE VERDICT
PASS_WITH_CROSS_SERVICE_AND_HISTORICAL_SECRET_BACKLOG
Agent Data đã được reconcile và recreate thành công: image pin đúng, 27/27 env name khớp, 27/27 credential fingerprint PRE == POST (không đổi một giá trị nào), healthy, 10/10 service khác zero-touch, Balo guard 37/37 PASS.
Không tuyên bố đã đóng secret exposure: mọi secret Agent Data dùng đều cross-service (còn phải nằm trong docker/.env cho service khác), và git history/backup cũ vẫn chứa credential đang hoạt động.
Verdict độc lập
AGENT_DATA_RECONCILIATION = PASS
BACKUP_PROPAGATION_CONTAINMENT = PASS
LOCAL_PLAINTEXT_CONTAINMENT = PARTIAL_CROSS_SERVICE_AND_HISTORICAL
VPS_SSOT_GIT_SAFETY = PASS
NORMATIVE_UPDATE = READY_NOT_APPLIED_NO_DOT
OPENAI_ROTATION_READINESS = READY
QDRANT_ROTATION_READINESS = READY (cần recreate qdrant ở wave sau)
SM_MATERIALIZATION_READINESS = OWNER_DECISION_REQUIRED
DIRECTUS_ROTATION_DEPENDENCY = IDENTIFIED
🔴 Phát hiện quan trọng nhất — mìn thứ hai, chưa từng có trong KB
Survey rev8 §13.1 đề xuất Wave B2: "vá compose agent-data: 10 env PG_/DIRECTUS_DB_". Nếu làm đúng như đề xuất đó — tức nối ${PG_PASSWORD} từ docker/.env — agent-data sẽ mất xác thực PostgreSQL.
Đo thật bằng keyed-HMAC (không đọc giá trị):
docker/.env PG_PASSWORD FP 3a548523055bdea0
live container PG_PASSWORD FP c1428d6da81f3ea6 *** DRIFT ***
docker/.env DB_PASSWORD FP 3a548523055bdea0 ← TRÙNG với .env PG_PASSWORD
live DIRECTUS_DB_PASSWORD FP 3a548523055bdea0
⇒ docker/.env PG_PASSWORD thực chất đang chứa mật khẩu DB của Directus, không phải mật khẩu PG mà agent-data dùng. Mật khẩu PG thật của agent-data (c1428d6da81f3ea6) không tồn tại trong bất kỳ file nào trên host — nó chỉ nằm trong container đang chạy.
Đây là mìn nằm dưới mìn image: pin image xong mà lấy env từ .env thì vẫn gãy. Chỉ luật §10 của mission (giá trị phải lấy từ container sống) mới bắt được.
Hệ quả DR: trước mission này, 9 biến
PG_*/DIRECTUS_DB_*chỉ tồn tại trong RAM của 1 container. Mất container = mất vĩnh viễn. File/etc/incomex/agent-data.envlà bản khai báo đầu tiên trong lịch sử của các giá trị đó.
2. LIVE STATE MEASURED (Gate 0 — đo, không nhận từ ai)
CPU 6 vCPU RAM 11 GiB (4.5 used / 7.2 available)
Disk / 96G, 84G used, 12G avail, 88% Inode 9%
Docker Compose v5.0.2 Docker Server 29.2.1 (containerd snapshotter)
Agent Data PRE:
| Trường | Giá trị đo |
|---|---|
| Container ID | 4220cc88116e… |
| StartedAt | 2026-05-19T08:26:16Z (8 tuần, healthy) |
| Running image ID | sha256:9acd6050329029fd6382d431a2d7bb3931b6c4e47a15d750b9affb40d2b0d927 |
| Config.Image | agent-data-local:latest |
| Compose labels | project=docker, service=agent-data, config_files=/opt/incomex/docker/docker-compose.yml |
| Memory | 2684354560 B = 2560 MiB · MemSwap 5120 MiB |
| Cmd | bash -lc "uvicorn agent_data.server:app --host 0.0.0.0 --port ${PORT:-8080} --workers 2" (từ image) |
| Mounts | 1 bind: credentials/google-credentials.json:ro |
| Network | docker_incomex, aliases [incomex-agent-data, agent-data] |
| Env names | 27 = 7 image-provided + 10 compose-declared + 10 runtime-only |
| Ports / GroupAdd / CapAdd / SecurityOpt | none / null / null / null |
⚠️ Đính chính công cụ so với memory/KB
docker compose v5.0.2 KHÔNG có --no-interpolate. Memory cũ ghi "so compose PHẢI --no-interpolate" — flag đó đã bị gỡ. Cách an toàn hiện tại là đọc raw YAML (sed/awk), vì raw YAML không render secret nào cả — an toàn hơn --no-interpolate chứ không kém.
3. OWNER DECISIONS APPLIED
| # | Quyết định Owner | Áp dụng thế nào |
|---|---|---|
| 1 | VPS là SSOT source/config/deploy | Không lấy gì từ GitHub; /opt/incomex không remote (đã đo) |
| 2–3 | GitHub không deploy; 5 workflow ghi-VPS giữ disabled | Xác minh lại READ-ONLY: 5/5 disabled_manually |
| 4 | SM = credential authority / recovery | Không đọc payload SM; không đổi SM |
| 5 | A1 dùng protected local env file | /etc/incomex/agent-data.env |
| 6–8 | Không xây SM materialization, không đổi/xoay credential | 27/27 fingerprint PRE==POST |
| 9 | Compose phải tái tạo đúng runtime trước recreate | Reconcile trước, recreate sau |
| 10 | Mọi mutation có baseline/bundle/backup/rollback | §5, §24 |
| 11 | Chỉ recreate đúng Agent Data | --no-deps, zero-touch 10/10 |
| 12 | Mọi thay đổi đảo ngược được | ROLLBACK.sh |
| 13 | Balo + bridge đã được Owner duyệt | Guard 37/37 sau mutation |
4. GIT SAFETY GATE = PASS
/opt/incomex branch feat/s177-sprint1-round-a HEAD(PRE) 7c60ccd remote: KHÔNG CÓ
dirty PRE: 15 M + 88 ??
Phân loại đường deployment của Agent Data:
| Path | Trạng thái | Xử lý |
|---|---|---|
docker/docker-compose.yml |
TRACKED_CLEAN (live == HEAD) | ⇒ không cần baseline commit |
docker/.env |
GITIGNORED (.gitignore:50) |
byte-exact backup |
docker/credentials/google-credentials.json |
GITIGNORED | byte-exact backup |
⇒ 0 UNKNOWN trên đường deployment Agent Data ⇒ không HOLD.
15 M + 88 ?? = UNRELATED_WORK (lark-client, dot/, claude-kb compose, .bak/.pre-*, evidence dirs). Không stage. Sau mutation vẫn nguyên 15 M + 88 ?? — đã kiểm.
Chỉ dùng git add <exact-path>. Không -A, không ., không pull/reset/checkout/restore/clean, không rewrite history.
5. CHECKPOINT / BUNDLES / BACKUPS
Checkpoint: /root/wave-a1-checkpoint-20260717T093500Z (root:root 0700, ngoài mọi git root, ngoài mọi backup glob — đã kiểm).
bundle/opt-incomex-PRE-20260717T093500Z.bundle f279677dc5ab9aa5210f1a3abfdb50e36a088f840f3930191f955cd71615de1b
bundle/opt-incomex-CONTAINMENT-20260717T093500Z.bundle 7b094165e6d9b19c8bdf4ecf722e536653043f9f3a9f79e442a27c1936fedc53
bundle/opt-incomex-CANDIDATE-20260717T093500Z.bundle e3997e38d59e8360edc3c289c1c3a07d7766bf80b8f01b69b50411257850f167
bundle/opt-incomex-POST-20260717T093500Z.bundle b2954a34dd25f1961720153388f526eb300caeb9ac9c5924865578043c45051c
Cả 4 git bundle verify → "The bundle records a complete history" PASS.
Byte-exact backup (root:root 0600):
backup/docker-compose.yml.PRE 5dc4237af760235c361818307a519e827e81200a8a5310cfcb8d233375c6a167
backup/backup-to-gdrive.sh.PRE 454dac00d84de40572f0675e55f7ea6c1997df95cdc0fa06ed6398cefd8ecbb3
backup/dotenv.PRE (docker/.env — hash giữ root-only, không ghi vào KB)
backup/agent-data.env.PRE (protected env file — hash giữ root-only)
backup/google-credentials.json.PRE
6. docker/.env SCOPE + CONSUMER MAP
Phân loại: PROJECT_LEVEL_COMPOSE_ENV (30 biến, root:root 0600, gitignored)
Không phải file riêng Agent Data. Bằng chứng: nuôi postgres/directus/nuxt/qdrant và scripts/cron-env.sh (. /opt/incomex/docker/.env) cấp env cho ~8 cron DOT.
Consumer map — mọi secret Agent Data đều CROSS_SERVICE
Biến .env |
Agent Data dùng làm | Consumer khác | Lớp |
|---|---|---|---|
AGENT_DATA_API_KEY |
API_KEY |
directus L89, nuxt L156, claude-kb | CROSS_SERVICE |
OPENAI_API_KEY |
OPENAI_API_KEY |
agent-api-executor (orphan), cron | CROSS_SERVICE |
QDRANT_LOCAL_API_KEY |
QDRANT_API_KEY |
qdrant L51 (QDRANT__SERVICE__API_KEY) |
CROSS_SERVICE |
DIRECTUS_ADMIN_TOKEN |
DIRECTUS_ADMIN_TOKEN |
nuxt L152, cron dot-orphan-scan | CROSS_SERVICE |
PG_PASSWORD |
(KHÔNG dùng — xem §1 drift) | postgres L24 POSTGRES_PASSWORD |
CROSS_SERVICE |
DB_PASSWORD |
DIRECTUS_DB_PASSWORD |
directus | CROSS_SERVICE |
⇒ §9.2 áp dụng cho 100%: không gỡ được biến nào khỏi docker/.env. docker/.env KHÔNG được sửa trong wave này (byte-exact như PRE).
⇒ LOCAL_PLAINTEXT_CONTAINMENT = PARTIAL_CROSS_SERVICE theo thiết kế, không phải thiếu sót.
AGENT_DATA_ONLY = rỗng. UNKNOWN_CONSUMER = rỗng.
7. BACKUP PROPAGATION CONTAINMENT = PASS
Vector đã chặn (mutation ĐẦU TIÊN, trước atomic block)
backup-to-gdrive.sh cron 37 20 * * * → Drive root, tar.gz trần, không mã hoá, rclone remote scope = drive (toàn quyền Drive cá nhân).
Bước [3/5] khớp -name ".env*" ⇒ 10 file plaintext vào Drive mỗi đêm:
docker/.env ← 30 biến, TOÀN BỘ secret của stack
docker/.env.bak.20260318T075608 ┐
docker/.env.bak.20260318T075911 │
docker/.env.bak.20260404 ├ 6 bản sao secret cũ
docker/.env.bak.20260517T021349Z │
docker/.env.bak.20260517T030513Z │
docker/.env.bak.s174-fix-04 ┘
docker/.env.mysql-backup-20260313
docker/agent-data-repo/.env.example
docker/agent-data-repo/.env.working
Sửa (exclude hẹp, 1 dòng, commit 1f36dbb):
-find /opt/incomex/docker -maxdepth 2 \( -name "docker-compose*" -o -name ".env*" -o -name "*.yml" -o -name "*.yaml" \) \
+find /opt/incomex/docker -maxdepth 2 \( -name "docker-compose*" -o -name "*.yml" -o -name "*.yaml" \) \
Chứng minh:
find mới khớp .env → 0 file (PASS)
bash -n OK
perms 755 root:root giữ nguyên
docker-compose*/*.yml vẫn được backup ⇒ job an toàn vẫn chạy, DR config không mất
Không xoá backup cũ (§12.1)
Protected env file /etc/incomex/agent-data.env KHÔNG thuộc backup set nào — đã kiểm: chỉ /etc/letsencrypt được copy từ /etc, không có job nào chạm /etc/incomex.
🔴 Vector CHƯA chặn — backlog Owner (ngoài phạm vi A1, có chủ đích)
| Vector | Nội dung | Vì sao chưa xử lý |
|---|---|---|
backup-to-gdrive.sh [4/5] |
cp -rL /etc/letsencrypt/live/ ⇒ TLS private key thật lên Drive |
Của nginx, không phải credential Agent Data; tắt có thể hỏng DR ⇒ Owner quyết |
backup-to-gdrive.sh [1/5] |
PG dump đầy đủ | DATA_BACKUP hợp lệ theo thiết kế |
backup-to-gdrive.sh [5/5] |
cp -r /opt/incomex/scripts/* ⇒ reconcile-{knowledge,tasks}.py chứa DIRECTUS_ADMIN_PASSWORD |
Credential thuộc Wave Directus (§16.5); và giá trị vẫn đi qua vector dưới ⇒ exclude ở đây không đóng được lỗ |
code-backup-to-gdrive.sh 4×/ngày |
tar nuxt-repo + agent-data-repo kèm .git (473 member); 2 file reconcile-*.py TRACKED+IN HEAD |
Giá trị nằm trong git objects ⇒ exclude working-tree vô nghĩa; phải rotate + rewrite history |
git-push-gh-daily-v2.sh 2×/ngày |
force-push cùng repo lên GitHub | idem |
🔴 Thêm một defect hygiene của chính script backup (không do mission tạo): dòng 31
QDRANT_KEY=$(grep QDRANT_LOCAL_API_KEY .env | cut -d= -f2-)rồicurl -H "api-key: ${QDRANT_KEY}"⇒ Qdrant key hiện trongps//proc/<pid>/cmdlinemỗi đêm. Đề xuất Wave sau: chuyển sang--header @filehoặc_QDRANT_KEYenv +--config -.
8. RUNNING IMAGE + STALE FALLBACK PROOF
docker inspect incomex-agent-data --format '{{.Image}}'
→ sha256:9acd6050329029fd6382d431a2d7bb3931b6c4e47a15d750b9affb40d2b0d927
Compose PRE:
image: ${AGENT_DATA_IMAGE:-asia-southeast1-docker.pkg.dev/github-chatgpt-ggcloud/agent-data/agent-data-test:latest}
Đo thật (không suy luận):
AGENT_DATA_IMAGE trong .env : 0 hit
AGENT_DATA_IMAGE trong shell env : 0 hit
env_file trong block agent-data : 0 hit
⇒ FALLBACK ÁP DỤNG. Xác nhận trực tiếp:
$ docker compose config --images agent-data
qdrant/qdrant:latest
asia-southeast1-docker.pkg.dev/.../agent-data-test:latest ← 4 tháng tuổi
$ docker images | grep agent-data-test
asia-southeast1-.../agent-data-test:latest 9421cd9c4303 4 months ago 1.51GB ← CÓ TRONG CACHE
⇒ docker compose up -d agent-data hôm nay ⇒ không pull, không fail, chạy code sai 4 tháng, IM LẶNG. Mìn của survey được xác nhận bằng lệnh trực tiếp, không chỉ suy luận.
9. BUILD / PULL PREVENTION
build: trong block agent-data → 0 hit (image-only, không có rebuild path)
docker compose up --help → hỗ trợ --no-build, --pull never, --no-deps, --dry-run
Compose thêm pull_policy: never (phòng thủ tầng 2, độc lập với flag CLI).
Bằng chứng không build / không pull: image CreatedSince không đổi trước/sau; tag agent-data-vps-prod do mission tạo từ image ID local, không có network fetch.
10. IMMUTABLE IMAGE PIN
Không dùng repo digest: RepoDigests của image này là agent-data-local@sha256:9acd… — digest local, không phải registry digest kéo được (AR API disabled). ⇒ dùng phương án 2 (§13): immutable local tag từ exact running image ID.
docker tag sha256:9acd6050… agent-data-vps-prod:9acd60503290-20260717
PROOF: docker image inspect agent-data-vps-prod:9acd60503290-20260717 --format '{{.Id}}'
→ sha256:9acd6050329029fd6382d431a2d7bb3931b6c4e47a15d750b9affb40d2b0d927 == expected
PIN_PROOF = PASS
Không xoá image cũ (§28). Fallback AR 9421cd9c4303 vẫn còn — giờ vô hại vì compose không còn tham chiếu, nhưng chưa được xoá (Wave D5).
11. COMPOSE PRE/POST PARITY
Diff đúng 1 hunk @@ -104,24 +104,45 @@ ⇒ không service nào khác bị chạm.
| Trường | PRE | POST | Kết quả |
|---|---|---|---|
| image | ${AGENT_DATA_IMAGE:-…AR fallback} |
agent-data-vps-prod:9acd60503290-20260717 |
FIXED |
| pull_policy | (không có) | never |
ADDED |
| mem_limit | 1536m |
2560m (= 2684354560 B đo thật) |
FIXED |
| env: 10 PG_/DIRECTUS_DB_ | thiếu | qua env_file |
FIXED |
secret interpolation ${…} |
4 biến | 0 | FIXED |
| entrypoint/cmd/user/workdir | image-provided | identical | parity |
| mounts / networks / ports / healthcheck / restart / logging | — | identical | parity |
POST contract đo lại: Cmd, Entrypoint(null), WorkingDir(/app), User(``), Memory 2684354560, MemSwap 5368709120, Restart unless-stopped, Logging json-file 50m×3 (từ /etc/docker/daemon.json), 1 bind ro, docker_incomex + 2 alias, Ports {} — tất cả identical PRE.
12. ENVIRONMENT NAME INVENTORY PRE/POST
NAME_SET_MATCH = PASS (PRE 27 names == POST 27 names, diff rỗng)
| Lớp | Số | Nguồn sau A1 |
|---|---|---|
| SECRET | 6 | /etc/incomex/agent-data.env |
| CONN | 8 | /etc/incomex/agent-data.env |
| LITERAL | 6 | compose environment: |
| IMAGE | 7 | image sha256:9acd6050… |
6 literal được fingerprint-verify khớp live trước khi ghi (không đoán): PORT, APP_ENV, QDRANT_URL, QDRANT_COLLECTION, GOOGLE_APPLICATION_CREDENTIALS, DIRECTUS_URL → 6/6 MATCH.
13. CREDENTIAL FINGERPRINT PRE/POST
Phương pháp: HMAC-SHA256 khoá ngẫu nhiên 32 byte sinh trong tmpfs (/dev/shm, root 0600), dùng chung PRE+POST, đã shred sau verification. Không dùng plain SHA (password entropy thấp). Khoá không vào report/KB/Git/evidence.
VAR_NAME CLASS PRE_FP POST_FP MATCH VALUE
API_KEY SECRET c797a987be790641 c797a987be790641 true REDACTED
OPENAI_API_KEY SECRET 34474707f7679caf 34474707f7679caf true REDACTED
QDRANT_API_KEY SECRET 90c4742f446d434a 90c4742f446d434a true REDACTED
DIRECTUS_ADMIN_TOKEN SECRET fc8a5a813b4a227a fc8a5a813b4a227a true REDACTED
PG_PASSWORD SECRET c1428d6da81f3ea6 c1428d6da81f3ea6 true REDACTED
DIRECTUS_DB_PASSWORD SECRET 3a548523055bdea0 3a548523055bdea0 true REDACTED
PG_HOST / PG_PORT / PG_USER / PG_DATABASE CONN … true REDACTED
DIRECTUS_DB_{HOST,PORT,USER,DATABASE} CONN … true REDACTED
PORT/APP_ENV/QDRANT_URL/QDRANT_COLLECTION/GOOGLE_…/DIRECTUS_URL LITERAL true REDACTED
GPG_KEY/LANG/PATH/PYTHON* IMAGE … true REDACTED
Kiểm bằng máy (không nhìn mắt):
vars compared : 27
missing in POST : none
extra in POST : none
fingerprint MISMATCH : none
PRE_POST_FINGERPRINT_MATCH = PASS
SECRET_VALUE_CHANGE = NO
14. DRIFT_FILE_VS_RUNTIME — 4 drift
.env NAME LIVE NAME .env FP LIVE FP VERDICT
AGENT_DATA_API_KEY API_KEY c797a987be790641 c797a987be790641 MATCH
OPENAI_API_KEY OPENAI_API_KEY 34474707f7679caf 34474707f7679caf MATCH
QDRANT_LOCAL_API_KEY QDRANT_API_KEY 90c4742f446d434a 90c4742f446d434a MATCH
DIRECTUS_ADMIN_TOKEN DIRECTUS_ADMIN_TOKEN fc8a5a813b4a227a fc8a5a813b4a227a MATCH
DB_PASSWORD DIRECTUS_DB_PASSWORD 3a548523055bdea0 3a548523055bdea0 MATCH
DB_USER DIRECTUS_DB_USER 406f0d9437cd84e9 406f0d9437cd84e9 MATCH
DB_DATABASE DIRECTUS_DB_DATABASE 406f0d9437cd84e9 406f0d9437cd84e9 MATCH
PG_PASSWORD PG_PASSWORD 3a548523055bdea0 c1428d6da81f3ea6 *** DRIFT ***
POSTGRES_PASSWORD PG_PASSWORD b3d8b55cfc8acfdf c1428d6da81f3ea6 *** DRIFT ***
POSTGRES_USER PG_USER fd225970c5b88fee 1c4771940750a2a8 *** DRIFT ***
POSTGRES_DB PG_DATABASE bae2acd5167bbe01 9da829e7bd25e7a4 *** DRIFT ***
Xử lý theo §10: live-container value thắng; không sửa consumer khác; không ghi raw value.
Suy ra (từ fingerprint, không đọc giá trị):
.env PG_PASSWORD≡.env DB_PASSWORD≡ liveDIRECTUS_DB_PASSWORD⇒.env PG_PASSWORDlà mật khẩu DB Directus, đặt sai tên.- Live
PG_PASSWORD(c1428d…) và livePG_USER/PG_DATABASEkhông khớp biến nào trong.env⇒ agent-data nối PG bằng role/db riêng, giá trị chỉ có trong container. PG_HOST≡DIRECTUS_DB_HOST,PG_PORT≡DIRECTUS_DB_PORT⇒ cùng một PG instance.DIRECTUS_DB_USER≡DIRECTUS_DB_DATABASE.
Kiểm tra riêng: .env.working (TRACKED trong git HEAD)
QDRANT_AUTH_HEADER embedded value FP 609e15273a01d9da
live QDRANT_API_KEY FP 90c4742f446d434a
VERDICT = not the live key
⇒ ✅ Không phải credential đang hoạt động (key cũ/stale). Giảm nhẹ phạm vi historical exposure.
15. PROTECTED ENV FILE CONTRACT
path /etc/incomex/agent-data.env
owner root:root mode 0600 size 1309 B vars 14
dir /etc/incomex root:root mode 0700
tạo umask 077 · mkstemp cùng filesystem · write+flush+fsync · chmod 0600 · chown 0:0 · os.replace (atomic)
nguồn giá trị trích TRỰC TIẾP từ container ĐANG CHẠY (docker inspect → pipe → file)
Giá trị chưa từng đi qua argv / stdout / terminal / evidence. Helper root-only /root/wave-a1-bin/wa1-env-extract.py (0700), không chứa secret literal.
Không đọc payload Secret Manager (§4).
16. PROOF: env file NGOÀI Git / Drive / web / evidence / KB / build context
| Ràng buộc | Bằng chứng |
|---|---|
| Ngoài mọi git root | git roots đo được: /opt/incomex, /opt/incomex/docker/{agent-data,nuxt}-repo, /opt/incomex/dot, /var/lib/incomex/ui-preview-notebook.git, /opt/incomex/git/ui-preview.git → /etc/incomex không thuộc cái nào; git check-ignore báo lỗi 128 vì path nằm ngoài repo hoàn toàn |
| Ngoài Drive backup | code-backup chỉ đóng docker/{nuxt,agent-data}-repo; backup-to-gdrive chỉ chạm /opt/incomex/docker (maxdepth 2), *nginx*, /etc/letsencrypt, /opt/incomex/scripts/*. Từ /etc chỉ letsencrypt được copy — /etc/incomex không |
| Ngoài web root | nginx phục vụ /usr/share/nginx/{static,mcp-writes} (trong container) |
| Ngoài evidence/KB | evidence chỉ chứa name + fingerprint; scan CLEAN |
| Ngoài Docker build context | service agent-data không có build: ⇒ không tồn tại build context |
| Không script/cron nào tham chiếu | grep -rn "/etc/incomex" trên scripts/, cron.d/, crontab → 0 hit |
| Bền qua reboot | /etc trên /dev/sda1 |
17. IN-FLIGHT JOB / KB DEPENDENCY GATE
ingest / reindex / vector-audit đang chạy → 0
process liên quan → chỉ dot-balo-reconcile-bridge (daemon) + nuxt node (không phải job Agent Data)
KB indexing / batch import / maintenance → không
agent-data logs PRE → chỉ MCP traffic (chính phiên Claude này)
⇒ không WAIT_FOR_SAFE_WINDOW. Không force-stop gì.
Phiên Claude này phụ thuộc agent-data qua MCP/KB ⇒ rollback đã được lưu local + không phụ thuộc KB trước khi mutate (§18).
18. ATOMIC EXECUTION PROOF
Khối chạy liền, không handoff giữa chừng:
containment (.env* khỏi Drive) → commit 1f36dbb
→ extract live env → /etc/incomex/agent-data.env + fingerprint PRE
→ drift check (.env vs runtime)
→ immutable tag + PIN_PROOF
→ reconcile compose → verify 6 literal khớp live
→ rollback assets (trước mutation)
→ candidate commit cdf25ec + bundle verify
→ §20 validation 17/17
→ dry-run (chỉ agent-data)
→ RECREATE
→ image verify → fingerprint POST → zero-touch → smoke → Balo guard
Rollback dựng trước recreate: $CK/rollback/ROLLBACK.sh (0700) + agent-data-rollback.yml, grep external deps → 0 (không KB/MCP/GitHub/network). Bản sao trên laptop Owner.
⚠️ Lệnh SSH bọc recreate bị timeout 2 phút ở vòng chờ health (không phải lỗi deploy — container đã
Started). Tôi không dừng khối: kiểm tra state ngay lập tức ở lệnh kế tiếp và hoàn tất toàn bộ verification. Ghi nhận minh bạch.
19. SINGLE-SERVICE RECREATE PROOF
docker compose config --services # → qdrant agent-data postgres directus nuxt nginx
docker compose config --services | grep -x agent-data # tên chính xác từ effective compose
docker compose up -d --no-deps --no-build --pull never agent-data
--no-deps là bắt buộc — đo thật:
KHÔNG --no-deps → plan có: incomex-qdrant Running / Waiting / Healthy (bị kéo vào plan)
CÓ --no-deps → plan chỉ có: incomex-agent-data Recreate/Recreated/Starting/Started
Dry-run trước khi chạy thật: chỉ agent-data. Cảnh báo orphan incomex-agent-api-executor xuất hiện nhưng không dùng --remove-orphans ⇒ executor không bị xoá (đã xác nhận UNCHANGED).
Kết quả:
Container incomex-agent-data Recreate → Recreated → Starting → Started
20. ZERO-TOUCH PROOF (10/10 service khác)
So container ID và StartedAt PRE vs POST:
incomex-agent-api-executor UNCHANGED (id+StartedAt identical)
incomex-claude-kb UNCHANGED
incomex-claude-mcp UNCHANGED
incomex-directus UNCHANGED
incomex-nginx UNCHANGED
incomex-nuxt UNCHANGED
incomex-qdrant UNCHANGED
pg-restore-test-20260520T031054Z UNCHANGED
postgres UNCHANGED
uptime-kuma UNCHANGED
incomex-agent-data *** CHANGED *** 4220cc88116e → 09188c72f327 (đúng chủ đích)
Balo bridge: socket+service active; ActiveEnterTimestamp Fri 2026-07-17 01:32:28 CEST == PRE ⇒ không restart
21. POST-RECREATE VERIFICATION
IMAGE_MATCH expected sha256:9acd6050329029fd6382d431a2d7bb3931b6c4e47a15d750b9affb40d2b0d927
actual sha256:9acd6050329029fd6382d431a2d7bb3931b6c4e47a15d750b9affb40d2b0d927 PASS
Config.Image agent-data-vps-prod:9acd60503290-20260717
Status running Health healthy
RestartCount 0 OOMKilled false
Memory 2684354560 MemSwap 5368709120
StartedAt 2026-07-17T09:45:44Z
NAME_SET 27 == 27 FINGERPRINTS 27/27 match
22. SMOKE TESTS — 8/8 PASS
1. /info HTTP 200 agent-data-langroid v0.1.0
/health HTTP 200 status=healthy, langroid_available=true
2. PG_CONNECT OK → (1,) ← dùng PG_* từ protected env file
3. DIRECTUS_DB_CONNECT OK → (1,)
4. QDRANT_READ OK → ['production_documents','iu_core_iu_chunks']
5. OPENAI_AUTH OK → models.list = 125 models (phép thử rẻ nhất, không tạo data)
6. DIRECTUS_API OK → HTTP 200 /users/me
7. LOG_SECRET_SCAN CLEAN (0 hit / 200 dòng cuối)
8. RestartCount=0 OOMKilled=false Health=healthy
Log khởi động (bằng chứng mạnh nhất cho §14):
PostgreSQL probe OK (13ms)
Qdrant probe OK: 19903 vectors (269ms)
Startup complete. Overall: healthy
PG->Qdrant vector sync listener started
Application startup complete.
⇒ PostgreSQL probe OK chứng minh trực tiếp rằng lấy giá trị từ container sống là đúng: nếu dùng ${PG_PASSWORD} của .env, dòng này sẽ FAIL.
Không thiếu PG_*, không thiếu DIRECTUS_DB_*, không thiếu OpenAI/Qdrant var, không restart loop, không lỗi auth mới.
KB/MCP restored: list_documents ✅ · full read (get_document_chunk) ✅ · search_knowledge semantic ✅ — cả 3 qua đúng agent-data vừa recreate.
BALO_ONE_CLICK_GUARD|PASS|checks=37 (37/37, khớp baseline).
23. NO-SECRET-IN-ARGV / LOG / EVIDENCE PROOF
Mission trước đã từng để secret lọt vào argv (grep -rlF -- "$V"). Wave này coi đó là lỗi chặn và không tái phạm:
✅ Không echo/print giá trị secret
✅ Không đưa secret vào command arguments — value đi docker inspect → pipe → file, chưa từng qua argv
✅ grep pattern qua FILE + `grep -f` (không literal trong argv)
✅ Không ghi raw `docker inspect ... Env`
✅ Không đọc /proc/*/environ
✅ Không chạy `docker compose config` không lọc (chỉ `--images` / `--services` / `--quiet`)
✅ Không đọc payload Secret Manager
✅ Report/KB/Git/evidence: 0 password/token/key
✅ ssh non-interactive ⇒ không HISTFILE (bash_history mtime 2026-06-28, trước mission)
Kiểm sau mission:
argv scan (ps -eo args) CLEAN
/dev/shm sạch (HMAC key đã shred)
/tmp mission temp 0 file
evidence scan CLEAN
commit scan (1f36dbb cdf25ec) CLEAN
File cố ý chứa secret (theo thiết kế, có kiểm soát):
/etc/incomex/agent-data.env root:root 0600 (dir 0700)
$CK/backup/{dotenv,agent-data.env,google-credentials}.PRE root:root 0600 (dir 0700)
Cả hai ngoài Git, ngoài Drive, ngoài web, ngoài evidence công khai. Không sinh bản sao secret mới ngoài 2 nhóm này.
24. GIT COMMITS & BUNDLES
7c60ccd (PRE, không đổi)
1f36dbb backup(gdrive): stop nightly plaintext .env* upload to Google Drive [1 file, 1 dòng]
cdf25ec compose(agent-data): pin production image, reconcile runtime contract,
single secret source [1 file, +29/-7]
Mỗi commit: exact staged list (1 file) · đọc toàn bộ staged diff · --check CLEAN · secret scan CLEAN · git add <exact-path> (không -A/.).
branch feat/s177-sprint1-round-a HEAD cdf25ec
remote KHÔNG CÓ ⇒ GIT_PUSH bất khả thi về mặt cấu trúc
unrelated work 15 M + 88 ?? giữ nguyên PRE == POST
25. NORMATIVE / CANONICAL STATUS
🔴 ĐÍNH CHÍNH SURVEY rev8 §1 + §8(9,10) + §9 — blocker #1 của survey là category error
Survey ghi: "normative_registry thiếu entry cho nút Balo đang LIVE — 47 rows, 0 row balo ⇒ MISSING_COVERAGE, cần Owner duyệt trước Wave A".
Đo schema thật:
$ \d normative_registry
code, article_number, name, version, status, category, scope_summary, kb_path,
enacted_session, council_score, composition_level, species_code, doc_type,
doc_level, parent_code, department, enacted_at, retired_at, superseded_by,
priority_offset, valid_from, valid_until, auto_expire, sections(jsonb),
content_hash, is_legacy_import, valid_period
$ SELECT doc_type, count(*) ... GROUP BY doc_type;
constitution -> 2
law -> 45 (tổng 47)
sample: NRM-CON-HP (Hiến pháp Kiến trúc Hệ thống Incomex) · NRM-LAW-00 (Luật Thực thể
Được Quản trị) · NRM-LAW-01 (11 Nguyên tắc Cấm Vi phạm) …
⇒ normative_registry là sổ đăng ký VĂN BẢN pháp quy (Hiến pháp + Luật, doc_level 1–2, code NRM-CON-*/NRM-LAW-*), không phải sổ ghi quyết định vận hành.
- Proposed entry §9 của survey có field
subject / decision / required_controls / forbidden / evidence— không field nào tồn tại trong bảng. - Bảng có 0 row về balo, và cũng 0 row về agent-data / compose / image / nginx / deployment. Không riêng gì Balo.
- ⇒ "0 row Balo" không phải lỗ hổng coverage; đó là nhầm phạm trù. Kỳ vọng một quy tắc nút UI nằm trong sổ Hiến pháp/Luật giống như tìm runbook triển khai trong hiến pháp.
DOT có tồn tại (dot-nrm-draft/enact/amend/retire/lifecycle, ghi normative_registry hợp lệ), nhưng:
dot-nrm-draft v1.0.0 — Import normative documents from manifest (Cấp B)
Usage: dot-nrm-draft --manifest <path>
Nó import văn bản pháp quy theo manifest, không thể biểu diễn entry §9. Dùng nó sẽ phải khai sinh một văn bản cấp law (có council_score, enacted_session, doc_level) — là hành vi lập pháp, vượt xa thẩm quyền agent và vượt phạm vi A1.
NORMATIVE_REGISTRY_UPDATE = READY_NOT_APPLIED_NO_DOT
Lý do: không có DOT an toàn cho LOẠI entry này, và tiền đề của survey cần Owner xem lại.
Cần Owner quyết (không phải agent): quy tắc vận hành (Balo one-click, image pin, cấm up -d trần, cấm --remove-orphans, nguồn secret) nên sống ở đâu? Registry hiện tại không có chỗ cho chúng. 3 lựa chọn: (a) thêm doc_type mới cho văn bản vận hành; (b) lập sổ riêng operational_registry; (c) chấp nhận canonical KB doc + comment trong compose là nơi ghi nhận (hiện trạng).
Không rollback technical PASS vì việc này (đúng §29.7).
Canonical §15/§16 (Balo)
Canonical balo-thuc-the-quy-dinh.md rev 17 đã có §16 (SỬA ĐỔI 2026-07-17) bãi bỏ phần cấm của §15 ⇒ nút Balo đã được phủ ở tầng canonical. Guard 37/37 PASS sau mutation. Không đổi runtime Balo. Không mở rộng phạm vi.
Tài liệu hiện hành đã cập nhật
Không tồn tại runbook deploy nào tham chiếu AGENT_DATA_IMAGE / compose up (grep trên /opt/incomex/docs/ → 0 hit) ⇒ nơi ghi nhận hợp lệ là:
- Comment trong
docker-compose.yml(commitcdf25ec) — mang đủ: lý do pin image, mìn AR fallback, drift.envvs runtime, lệnh deploy duy nhất được phép. - Báo cáo này trong KB.
26. LOCAL PLAINTEXT CONTAINMENT = PARTIAL_CROSS_SERVICE_AND_HISTORICAL
Không tuyên bố đã đóng exposure. Lý do cụ thể:
| Còn tồn tại | Chi tiết |
|---|---|
| Cross-service | 6/6 secret Agent Data vẫn phải nằm trong docker/.env cho postgres/directus/nuxt/qdrant/claude-kb/claude-mcp + ~8 cron. Protected file là bản sao cùng giá trị, không thay thế |
| Historical — git | DIRECTUS_ADMIN_PASSWORD nằm trong git objects của agent-data-repo (commit 4acebbc, 2026-04-05, 2 file reconcile-*.py TRACKED+IN HEAD) và đã ở GitHub branch vps-daily-* |
| Historical — Drive | 56 bản remote (14 ngày) của code-backup + 14 bản vps-backup vẫn chứa .env plaintext (không xoá backup cũ theo §12.1); Drive Trash 13.9 GiB |
| Stale copies | 7 × docker/.env.bak* + .env.mysql-backup vẫn trên đĩa (Wave C4) |
| Phạm vi rò rỉ (KB ĐÚNG) | PASSWORD 19 file · TOKEN 34 file · UNION 46 file |
| rclone scope | scope = drive — token backup đọc/xoá được toàn bộ Drive cá nhân (Wave C5 → drive.file) |
ROTATION_REQUIRED_TO_CLOSE_HISTORICAL_EXPOSURE = TRUE
Xoay DIRECTUS_ADMIN_PASSWORD không đủ — phải kèm rewrite git history, nếu không giá trị vẫn tiếp tục lên Drive/GitHub trong .git objects.
✅ Điểm sáng đo được: .env.working (TRACKED trong HEAD) không chứa Qdrant key đang hoạt động.
27. ROTATION READINESS (chỉ lập, KHÔNG xoay)
Wave A1 không tạo/xoay/thu hồi bất kỳ credential nào, không thêm/huỷ SM version, không materialize từ SM.
| Readiness | Giá trị | Căn cứ |
|---|---|---|
OPENAI_ROTATION_READINESS |
READY | agent-data hết bị chặn (image pin + contract tái tạo được). Xoay phải cập nhật cả /etc/incomex/agent-data.env và docker/.env (executor + cron), rồi recreate agent-data bằng lệnh §19 |
QDRANT_ROTATION_READINESS |
READY (agent-data không còn là nút thắt) | Nhưng phải recreate cả qdrant (QDRANT__SERVICE__API_KEY, parity PASS) — ngoài phạm vi A1 |
SM_MATERIALIZATION_READINESS |
OWNER_DECISION_REQUIRED | Owner §2.6 cấm xây ở A1. ⚠️ Rủi ro thật: không service nào đọc SM; SM và .env có thể đã lệch từ 2026-05-22; 31/32 secret chưa từng xoay ⇒ SM chưa chắc restore được đúng giá trị đang chạy. Đặc biệt: live PG_PASSWORD/PG_USER/PG_DATABASE của agent-data không khớp biến .env nào ⇒ nhiều khả năng cũng không có trong SM. Cần đối chiếu SM↔runtime trước khi coi SM là recovery source |
DIRECTUS_ROTATION_DEPENDENCY |
IDENTIFIED | DIRECTUS_ADMIN_PASSWORD (≠ DIRECTUS_ADMIN_TOKEN, khác loại/khác consumer) không có consumer agent-data ⇒ xoay được độc lập, nhưng phải kèm rewrite history. DIRECTUS_ADMIN_TOKEN có consumer agent-data + nuxt + cron ⇒ giờ đã READY |
28. DISK BEFORE/AFTER
PRE : 96G total, 84G used, 12G avail, 88%
POST: 96G total, 84G used, 12G avail, 88%
Không cleanup Docker (§28): 0 rmi, 0 prune, 0 volume rm, 0 builder prune. Giữ nguyên: exact production image, immutable pin, image rollback pre-*, 4 bundle, backup, evidence. Chỉ tạo file tạm trong tmpfs và đã shred.
Bundles chiếm ~44 MB trong /root — chấp nhận được với 12G headroom. Không HOLD_DISK_HEADROOM_REQUIRED (wave này không pull/build nên không cần headroom lớn).
29. ROLLBACK COMMANDS
ssh contabo '/root/wave-a1-checkpoint-20260717T093500Z/rollback/ROLLBACK.sh'
Thủ công:
CK=/root/wave-a1-checkpoint-20260717T093500Z
cp -a $CK/backup/docker-compose.yml.PRE /opt/incomex/docker/docker-compose.yml
install -m 0600 -o root -g root $CK/backup/agent-data.env.PRE /etc/incomex/agent-data.env
cd /opt/incomex/docker
docker compose -f docker-compose.yml -f $CK/rollback/agent-data-rollback.yml \
up -d --no-deps --no-build --pull never agent-data
docker inspect incomex-agent-data --format '{{.Image}}' # phải == sha256:9acd6050…
🔴 Cảnh báo thiết kế rollback: khôi phục mỗi compose PRE là KHÔNG đủ và nguy hiểm — compose PRE resolve image AR cũ (có sẵn cache) ⇒ chạy code sai 4 tháng im lặng. Vì vậy rollback bắt buộc kèm override
agent-data-rollback.yml(pin image +env_filetừ backup). Nói cách khác: compose PRE chưa bao giờ mô tả được runtime PRE — đó chính là bug mà wave này sửa.
Bản sao rollback nằm trên laptop Owner (WAVE-A1-ROLLBACK.md), không phụ thuộc KB/MCP.
30. REMAINING WAVES
A2 Owner quyết: nơi sống của quy tắc VẬN HÀNH (registry hiện chỉ chứa Hiến pháp/Luật) ← MỚI, thay blocker #1 cũ của survey
A3 Owner quyết Drive/GitHub vector còn lại: TLS private key + PG dump + reconcile-*.py + code-backup 4×/ngày
A4 Xoay độc lập, không chờ ai: VPS_SSH_KEY · gh PAT (.git-token) · Contabo API · (Lark đã xoay)
A5 Bỏ dòng env VPS_SSH_KEY L433 của Health Check 227044705 (khai mà không dùng, đang FAIL)
A6 Số phận incomex-agent-api-executor (orphan có label compose; --remove-orphans sẽ xoá)
B Reconcile service còn lệch: nginx (mount ui-preview + claude_mcp_net), postgres/directus (claude_mcp_net)
C1 ĐỐI CHIẾU SM ↔ runtime TRƯỚC khi coi SM là recovery source ← nâng ưu tiên (xem §27)
C2 Xoay DIRECTUS_ADMIN_TOKEN / PG / Qdrant / OpenAI (giờ đã hết bị chặn)
C3 Rewrite git history 2 file reconcile-*.py — nếu không, C2 không đóng được exposure
C4 Xoá 7 .env.bak* + .env.mysql-backup; .git-token → nguồn an toàn
C5 Thu hẹp rclone scope: drive → drive.file
C6 Sửa hygiene backup-to-gdrive.sh dòng 31 (Qdrant key vào argv mỗi đêm)
D Dọn storage có chọn lọc (build cache 6.7G → volume dry-run 9.6G → image stale); D5 image AR giờ đã an toàn để xoá (compose không còn tham chiếu); D6 TUYỆT ĐỐI giữ nuxt-ssr:latest
E Sizing theo 11 GiB/6 vCPU thật · bật logging API (hiện KHÔNG BIẾT ai đọc secret nào) · GCP decommission · restore drill
31. EVIDENCE PATHS
CHECKPOINT /root/wave-a1-checkpoint-20260717T093500Z (root:root 0700)
backup/ docker-compose.yml.PRE · dotenv.PRE · agent-data.env.PRE
· backup-to-gdrive.sh.PRE · google-credentials.json.PRE · *.sha256
bundle/ PRE · CONTAINMENT · CANDIDATE · POST (+ bundles.sha256) — cả 4 verify PASS
evidence/ agent-data.{image-id,container-id,startedat}.PRE · pinned-{tag,image-id}
· env-names.{PRE,POST} · all-services.{PRE,POST}
rollback/ ROLLBACK.sh (0700) · agent-data-rollback.yml
HELPER /root/wave-a1-bin/{wa1-env-extract.py,wa1-drift.py} (0700, không chứa secret)
PROTECTED /etc/incomex/agent-data.env (root:root 0600, dir 0700)
LAPTOP scratchpad/WAVE-A1-ROLLBACK.md
COMMITS 1f36dbb (containment) · cdf25ec (compose reconcile)
LỆNH ĐO docker inspect --format (names only, cut -d= -f1) · docker compose config --images/--services/--quiet
· docker compose --dry-run up -d --no-deps --no-build --pull never agent-data
· gh api repos/{web-test,agent-data-test}/actions/workflows/<id> (GET only, từ laptop)
· docker exec postgres psql -tAc "SELECT …" (READ ONLY)
32. SECRET PAYLOAD = REDACTED PROOF
Báo cáo này chứa: variable name, fingerprint (HMAC-SHA256 truncated 16 hex, khoá ngẫu nhiên đã huỷ), và REDACTED. Không password / token / API key / connection string / hash xác thực / TLS key.
Fingerprint không đảo ngược được và vô dụng ngoài phiên này: khoá HMAC 32 byte ngẫu nhiên chỉ tồn tại trong tmpfs và đã shred. Chúng chỉ chứng minh quan hệ bằng/khác giữa các giá trị tại thời điểm đo.
33. FACTS NEXT AGENT MAY RELY ON
✅ Agent Data image ID production = sha256:9acd6050329029fd6382d431a2d7bb3931b6c4e47a15d750b9affb40d2b0d927
✅ Immutable pin = agent-data-vps-prod:9acd60503290-20260717 (compose dùng nó, + pull_policy: never)
✅ Fallback AR agent-data-test:latest = 9421cd9c4303 CÒN trong cache — compose KHÔNG còn tham chiếu
✅ Lệnh deploy DUY NHẤT: docker compose up -d --no-deps --no-build --pull never agent-data
✅ docker compose = v5.0.2 → CÓ --no-build/--pull/--no-deps/--dry-run · KHÔNG có --no-interpolate
✅ Không --no-deps ⇒ qdrant bị kéo vào plan (chỉ Running/Healthy, nhưng vẫn nên tránh)
✅ /etc/incomex/agent-data.env = nguồn secret DUY NHẤT của agent-data (14 var, root:root 0600)
✅ agent-data KHÔNG còn đọc docker/.env (0 interpolation trong block)
✅ docker/.env = PROJECT_LEVEL, 30 var, KHÔNG đổi, vẫn nuôi 5 service + ~8 cron qua cron-env.sh
🔴 docker/.env PG_PASSWORD = mật khẩu DB Directus (đặt SAI TÊN) — KHÔNG phải PG password của agent-data
🔴 PG_PASSWORD/PG_USER/PG_DATABASE thật của agent-data KHÔNG có trong file nào ngoài
/etc/incomex/agent-data.env và $CK/backup/agent-data.env.PRE ⇒ mất 2 file này = mất vĩnh viễn
✅ normative_registry = 47 rows = 2 constitution + 45 law. KHÔNG chứa quy tắc vận hành nào.
"0 row Balo" là NHẦM PHẠM TRÙ, không phải coverage gap.
✅ dot-nrm-draft = importer văn bản theo manifest, KHÔNG dùng được cho entry §9 của survey
✅ .env.working (TRACKED) chứa Qdrant key CŨ, KHÔNG phải key đang chạy
✅ 5/5 workflow ghi-VPS vẫn disabled_manually (xác minh lại 2026-07-17)
✅ /opt/incomex KHÔNG có remote ⇒ push bất khả thi; HEAD = cdf25ec
✅ Balo guard = 37/37 PASS sau mutation; bridge socket không restart
✅ Qdrant: 19903 vector, collections = production_documents, iu_core_iu_chunks
34. ASSUMPTIONS NEXT AGENT MUST NOT MAKE
❌ ĐỪNG vá compose bằng ${PG_PASSWORD} từ .env như survey §13.1 B2 đề xuất — SẼ GÃY PG AUTH
❌ ĐỪNG giả định .env khớp runtime — đã đo 4 DRIFT
❌ ĐỪNG restore compose PRE rồi recreate mà không có rollback override — chạy image sai 4 tháng IM LẶNG
❌ ĐỪNG chạy docker compose up -d trần · ĐỪNG --remove-orphans (xoá executor)
❌ ĐỪNG dùng --no-interpolate — compose v5.0.2 không có flag đó (đọc raw YAML thay thế)
❌ ĐỪNG coi normative_registry là nơi ghi quy tắc vận hành — nó chỉ chứa Hiến pháp + Luật
❌ ĐỪNG coi "0 row Balo" là blocker cần Owner duyệt trước Wave A — tiền đề sai
❌ ĐỪNG tin Secret Manager restore được production — chưa đối chiếu; live PG creds có thể KHÔNG có trong SM
❌ ĐỪNG coi xoay DIRECTUS_ADMIN_PASSWORD là đóng được lỗ — giá trị nằm trong git objects
❌ ĐỪNG xoá /etc/incomex/agent-data.env hoặc $CK/backup/agent-data.env.PRE — 9 giá trị chỉ có ở đó
❌ ĐỪNG xoá image nuxt-ssr:latest (AR API disabled ⇒ không pull lại được)
35. PROOF OF SCOPE
GIT_PUSH=NO (repo KHÔNG có remote — bất khả thi về cấu trúc)
GITHUB_WORKFLOW_MUTATION=NO (chỉ GET; 5/5 vẫn disabled_manually)
GCP_MUTATION=NO (không gọi gcloud; không đọc payload SM)
SECRET_VALUE_CHANGE=NO (27/27 fingerprint PRE==POST)
SECRET_ROTATION=NO
SECRET_REVOKE=NO
DB_DIRECT_WRITE=NO (chỉ SELECT + \d, read-only)
OTHER_SERVICE_RECREATE=NO (10/10 UNCHANGED: id + StartedAt)
DOCKER_CLEANUP=NO (0 rmi / prune / volume rm / builder prune)
Mutation đã thực hiện, đúng 3:
1. scripts/backup-to-gdrive.sh 1 dòng (containment .env* khỏi Drive) commit 1f36dbb
2. docker/docker-compose.yml 1 hunk (pin image + env_file + mem) commit cdf25ec
3. /etc/incomex/agent-data.env file mới (protected, ngoài Git)
+ docker tag (immutable pin, không pull/build) + recreate DUY NHẤT agent-data
DỪNG sau báo cáo. Không tự soạn hoặc thực hiện Wave A2/A3.