S125-INVESTIGATE — Claude Verification Report
S125-INVESTIGATE — Xác minh findings từ Re-Audit 3 agents
Agent: Claude | Date: 2026-03-15 | Loại: CHỈ ĐIỀU TRA — không sửa code/data
BẢNG TỔNG HỢP 11 FINDINGS
| # | Finding | Agent báo | Status | Evidence |
|---|---|---|---|---|
| 1 | DOT-109..112 thiếu runtime trên VPS | GPT | CONFIRMED | Scripts exist in git repo only. find /opt/incomex -name '*truth-gate*' = empty. Deploy workflow copies Nuxt build, not dot/bin/ scripts. PG functions (deprecate/retire) work but bash wrappers not on VPS. |
| 2 | CHECK 9 không chạy | GPT | FALSE POSITIVE | CHECK 9 lives in sync-check.yml (file name ≠ workflow name). gh run list --workflow="Health Check" --limit 5 → all SUCCESS. Last scheduled: 2026-03-15T12:50 GREEN. |
| 3A | Nuxt fields count_b/count_c/cross_check | GPT | FALSE POSITIVE | grep count_b|count_c|cross_check index.vue → NOT FOUND. These fields were removed in S116. GPT hallucinated or read stale code. |
| 3B | Nuxt status enum sai ('mở','đang_xử_lý') | GPT | CONFIRMED | [entityType]/index.vue line 174: status: { _in: ['mở', 'đang_xử_lý'] }. DB has only open, archived. Per-entity issues panel always returns empty. |
| 4A | Agent Data API mở không auth | GPT | CONFIRMED (PARTIAL) | POST /chat: 200 without key (can query knowledge). GET /kb/list: 200 (lists all docs). POST /documents: 401 (write protected). DELETE: 401. Read endpoints exposed, write protected. |
| 4B | Directus flows public | GPT | CONFIRMED | GET /flows: 200, returns 100 flows with operations data. GET /items/system_issues: 200 (leaks error data). GET /items/v_registry_counts: 200 (acceptable). GET /items/directus_users: 403 (blocked). |
| 4C | PG superuser thừa | GPT | CONFIRMED | workflow_admin role has rolsuper=true, rolcanlogin=true. This is a non-standard superuser role beyond the expected postgres. |
| 5A | deprecate_entity() RETURNING bug | Claude | CONFIRMED (MINOR) | RETURNING $3 in EXECUTE returns the 3rd bind param. At that point $3 = v_collection (original name), so it actually returns correctly BY ACCIDENT. But the code overwrites v_collection with the RETURNING result, making it confusing. Works but fragile. |
| 5B | v_all_entity_codes thiếu 3 tables | Claude | CONFIRMED | VIEW definition missing: table_proposals (CAT-014), checkpoint_instances (CAT-015), registry_changelog (CAT-016). These tables have entities with codes but are invisible to entity validation. |
| 5C | 119 dead links | Claude+GPT | CONFIRMED | audit_dead_links() → 119 rows, all severity=error. Sample: FK relationships (workflow_steps→checkpoint_sets, workflows→parent_workflow) pointing to non-existent entity codes in entity_dependencies. Real data integrity issues. |
| 5D | count drift meta vs reg | GPT | CONFIRMED (PARTIAL) | CAT-016: meta=1397, reg=1403 (drift -6). CAT-017: meta=738, reg=707 (drift 31 = archived issues not counted by reg trigger which counts only open). 17/20 OK, 2 drift explained. |
CHI TIẾT TỪNG NHÓM
1. DOT-109..112 — CONFIRMED: Scripts not deployed
What exists:
dot_toolsDB records: 4 entries withscript_path = dot/bin/dot-*✅- PG functions:
deprecate_entity(),retire_entity()✅ - Git repo (local): 4 bash scripts in
dot/bin/✅ - VPS filesystem: NOTHING ❌
Root cause: The Deploy workflow (deploy-vps.yml) runs rsync of the Nuxt build output (.output/), not the full repo. dot/bin/ scripts are in the repo but never deployed to VPS.
Impact:
- DOT-109 (truth-gate): Can only run from developer machine via SSH, not from VPS directly
- DOT-110 (coverage-inspector): Same
- DOT-111 (deprecate): Bash wrapper not on VPS, but PG function
deprecate_entity()works via psql - DOT-112 (retire): Same — PG function
retire_entity()works via psql
Registry vs reality: Registry says script_path=dot/bin/dot-production-truth-gate but that path doesn't exist on VPS. This is a registry-reality mismatch.
2. CHECK 9 — FALSE POSITIVE: Running correctly
GPT likely ran gh run list without --workflow="Health Check" filter, or the workflow name sync-check.yml vs display name "Health Check" caused confusion.
Evidence: Health Check runs every 6 hours (cron), last 5 runs all SUCCESS, CHECK 9 returns "OK (20 collections tracked, DOT=112, taxonomy=55)".
3B. Status Enum Bug — CONFIRMED
The file web/pages/knowledge/registries/[entityType]/index.vue line 174 still uses the pre-S122 Vietnamese status values 'mở' and 'đang_xử_lý'. S122 migrated all statuses to English (open, archived) but this page was NOT updated.
Impact: When users navigate to a specific entity type page (e.g., /knowledge/registries/system_issue), the issues panel at the bottom always shows empty even though there are 707 open issues. This is a "rỗng giả" — appears empty but data exists.
4A. Agent Data API — CONFIRMED PARTIAL
| Endpoint | Auth required? | Risk |
|---|---|---|
| POST /chat | NO | Anyone can query the knowledge base |
| GET /kb/list | NO | Anyone can list all document IDs |
| GET /health | NO | Acceptable (standard health check) |
| POST /documents | YES (401) | Write protected ✅ |
| DELETE /documents | YES (401) | Delete protected ✅ |
Read endpoints are open. An attacker can enumerate all knowledge documents and query the AI chat endpoint without authentication.
4B. Directus Public Access — CONFIRMED
| Collection | Public? | Risk |
|---|---|---|
| flows | YES (100 flows + operations) | Leaks internal automation architecture |
| system_issues | YES | Leaks error diagnostics |
| v_registry_counts | YES | Low risk (operational counts) |
| directus_users | NO (403) | ✅ |
| entity_labels | NO (403) | ✅ |
| taxonomy | NO (403) | ✅ |
Flows exposure: Public can see all 100 flow names, their operations, and configuration. This reveals the entire automation architecture.
4C. PG Superuser — CONFIRMED
workflow_admin role has superuser privileges. This is likely a legacy role from the Agency OS template. It can bypass all PG security, modify any table, and drop databases.
5A. deprecate_entity RETURNING — CONFIRMED MINOR
The EXECUTE statement does RETURNING $3 where $3 is the v_collection variable. The RETURNING result is stored back INTO v_collection. This works by coincidence because $3 contains the collection name at that point. But the pattern is confusing and fragile — if someone changes the USING parameter order, it breaks silently.
5D. Count Drift — EXPLAINED
- CAT-016 (changelog): meta_catalog.record_count=1397 vs v_registry_counts=1403. Drift=6. Cause: meta_catalog record_count is a manual/snapshot field, while v_registry_counts uses realtime PG trigger. New changelog entries arrived between last meta_catalog refresh and now.
- CAT-017 (system_issues): meta_catalog=738 (total) vs v_registry_counts=707 (open only). Drift=31 = exactly the 31 archived issues. The custom count trigger only counts status='open'. This is BY DESIGN but meta_catalog doesn't reflect the filtered count.
PHÁT HIỆN MỚI (ngoài 11 findings)
NEW-1: meta_catalog.record_count not auto-refreshed
meta_catalog has a record_count column that is manually maintained (or refreshed by dot-catalog-sync). v_registry_counts has realtime PG triggers. The two can drift. This dual-source-of-truth for counts is confusing.
NEW-2: system_issues entity_type filter uses Vietnamese values
Line 174 uses entity_type: { _eq: entityType.value } which maps to Directus entity_type (e.g., 'system_issue'). But the filter also checks status in Vietnamese. If someone fixes the status enum, they must also verify entity_type mapping works correctly.
TÓM TẮT
| Category | CONFIRMED | FALSE POSITIVE | PARTIAL |
|---|---|---|---|
| Runtime/Deployment | 1 | 0 | 0 |
| Monitoring | 0 | 1 | 0 |
| Code Bugs | 1 | 1 | 0 |
| Security | 0 | 0 | 3 |
| PG Logic | 1 | 0 | 1 |
| Data Integrity | 1 | 0 | 1 |
| Total | 4 | 2 | 5 |
Priority fix order:
- 🔴 Status enum bug (3B) — affects user-visible UI
- 🔴 DOT scripts not deployed to VPS (1) — registry-reality mismatch
- 🟡 Agent Data read endpoints open (4A) — security
- 🟡 Directus flows public (4B) — info disclosure
- 🟡 v_all_entity_codes missing 3 tables (5B) — data completeness
- 🟡 PG superuser workflow_admin (4C) — security posture
- 🟡 119 dead links (5C) — data integrity
- 🟢 deprecate_entity RETURNING (5A) — code quality
- 🟢 meta_catalog count drift (5D) — explained by design