KB-16F1

Claude — Wave A1: Agent Data image pin / compose reconcile / runtime env hardening (2026-07-17)

42 min read Revision 1
current-statewave-a1agent-datacompose-reconcileimage-pinenv-hardeningsecret-containmentdrift-file-vs-runtimevps-ssotzero-touchrollback-ready2026-07-17PASS_WITH_CROSS_SERVICE_AND_HISTORICAL_SECRET_BACKLOG

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.md rev 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/.envagent-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.envbả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 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ồi curl -H "api-key: ${QDRANT_KEY}"Qdrant key hiện trong ps//proc/<pid>/cmdline mỗi đêm. Đề xuất Wave sau: chuyển sang --header @file hoặc _QDRANT_KEY env + --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 ≡ live DIRECTUS_DB_PASSWORD.env PG_PASSWORD là mật khẩu DB Directus, đặt sai tên.
  • Live PG_PASSWORD (c1428d…) và live PG_USER/PG_DATABASE khô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_HOSTDIRECTUS_DB_HOST, PG_PORTDIRECTUS_DB_PORT ⇒ cùng một PG instance.
  • DIRECTUS_DB_USERDIRECTUS_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 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_registrysổ đă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 / evidencekhô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>

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à:

  1. Comment trong docker-compose.yml (commit cdf25ec) — mang đủ: lý do pin image, mìn AR fallback, drift .env vs runtime, lệnh deploy duy nhất được phép.
  2. 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 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_file từ 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 đượcvô 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.

Back to Knowledge Hub knowledge/current-state/reports/claude-wave-a1-agent-data-image-compose-env-hardening-2026-07-17.md