KB-3DE3

OGV-2C R2 — Write Gate + Test Teardown — Implementation Report (2026-05-07)

7 min read Revision 1
ogv-2cwrite-gatereport

OGV-2C R2 — Write Gate + Test Teardown — Implementation Report

Date: 2026-05-07 Commit: a40b217 on /opt/incomex/docker/agent-data-repo (main) Status: Deployed, verified against production API.

1. Discovery findings

Item Value
Container incomex-agent-data
Framework FastAPI
Write entrypoint (REST) POST /documentscreate_document (server.py:1278)
Write entrypoint (MCP) upload_document tool (server.py:2678) builds DocumentCreate and calls create_document directly. Single chokepoint — gate placed once.
Update entrypoint PUT /documents/{doc_id:path} (server.py:1389) — gate NOT applied (would require existing doc, doc_id is fixed; out of scope for write-gate-on-creation)
Payload schema DocumentCreate{document_id: str, content: DocumentContent{mime_type, body}, metadata: DocumentMetadata, ...}. Field is document_id and content.body, NOT path/content.
Error helper _error(status, code, message, **details) → FastAPI HTTPException with detail={code,message,details}. Used as-is.
Env config APP_ENV=production. No prior test-mode flag → introduced new KB_TEST_MODE (default false; values 1/true/yes enable).
Existing tests None inside container.
Top-level prefixes in production (live count) knowledge(1801), registries(222), operations(105), reports(4 stale), tham-khao(2 stale), ''(3 stale). Allowlist = knowledge/, operations/, registries/.

No assumption deviations triggered a STOP. Schema-field difference (document_id vs path) was adapted in code and tests per Addendum A1.

2. Code changes

File: agent_data/server.py (host: /opt/incomex/docker/agent-data-repo/, container: /app/)

  • Added module-level constants _OGV2C_VALID_PREFIXES, _OGV2C_BARE_PATH_REGEX and helper _ogv2c_validate_write(document_id, body) immediately after _error() (line 1078).
  • Modified create_document body (server.py:1283) to invoke the gate immediately after _ensure_pg():
doc_id = payload.document_id
# OGV-2C write gate
_ogv2c_validate_write(doc_id, getattr(payload.content, "body", None))

84 lines added, 0 removed. No other functions touched. Read/delete/search/move/MCP-non-upload paths untouched.

3. Rules — implementation status

Rule Status Notes
R1 — block test/ unless KB_TEST_MODE=true Implemented Default false; documented in code docstring + here.
R2 — block inline- prefix Implemented Single chokepoint catches REST + MCP.
R3 — top-level prefix allowlist Implemented Allowlist: knowledge/, operations/, registries/. reports/ deliberately not added per Addendum A4.
R4 — bare-path / file-URL content Implemented Whole-content match against ^file:///, ^/Users/[A-Za-z]…. Short-content (<500) match against `^(file:///

4. Test results (8 cases) — against live API

Case Path HTTP Verdict
POS-1 knowledge/dev/test-gate-pos.md 200 PASS
POS-2 operations/tasks/test-gate-pos.md 200 PASS
POS-3 knowledge/test-gate-report.md (long body mentioning /tmp/foo, /Users/nmhuyen, file:///opt/data) 200 PASS
NEG-1 test/should-block.md 422 (R1) PASS
NEG-2 inline-should-block 422 (R2) PASS
NEG-3 random-root-doc 422 (R3) PASS
NEG-4 knowledge/test-gate-leak.md body=file:///Users/nmhuyen/.gemini/tmp/session.txt 422 (R4) PASS
NEG-5 reports/drift.md 422 (R3) PASS

HTTP codes captured via curl -w "%{http_code}" per Addendum A2.

5. Deploy method

scp server.py contabo:/opt/incomex/docker/agent-data-repo/agent_data/
docker cp .../server.py incomex-agent-data:/app/agent_data/server.py
docker restart incomex-agent-data
cd /opt/incomex/docker/agent-data-repo
git add agent_data/server.py        # specific file, not -A
git commit -m "OGV-2C: write gate ..."   # → a40b217

Container ready (/api/health returned healthy) before tests ran.

6. Post-deploy API evidence

Negative responses (excerpt, all returned detail={code, message, details} envelope):

  • NEG-1: {"code":"INVALID_ARGUMENT","message":"Path under 'test/' prefix is rejected in production. Set KB_TEST_MODE=true to allow.","details":{"document_id":"test/should-block.md","rule":"OGV-2C-R1"}}
  • NEG-2: {"code":"INVALID_ARGUMENT","message":"Path with 'inline-' prefix is rejected.","details":{"document_id":"inline-should-block","rule":"OGV-2C-R2"}}
  • NEG-3 / NEG-5: {"code":"INVALID_ARGUMENT","message":"Document path must start with one of: knowledge/, operations/, registries/","details":{"rule":"OGV-2C-R3"}}
  • NEG-4: {"code":"INVALID_ARGUMENT","message":"Document body is a bare file path / URL, not a real document.","details":{"rule":"OGV-2C-R4"}}

Positive responses returned {"id":"…","status":"created","revision":1} with HTTP 200.

7. Rollback

Not triggered. Path documented in prompt: git revert a40b217 && docker cp + docker restart incomex-agent-data. Verified deploy is forward-compatible — no schema/DB changes, no other call sites.

8. Pre-existing KB documents

Did NOT cleanup/move/delete any pre-existing KB document in this session. The 4 stale reports/* docs and 2 tham-khao/* docs found during prefix histogram remain untouched. They will simply be blocked from future creation by R3 (gate enforces creation only; existing rows unaffected).

9. OGV-2C test docs cleanup

The 3 positive test docs (POS-1/POS-2/POS-3) were deleted via the existing DELETE /documents/{doc_id:path} endpoint:

DELETE knowledge/dev/test-gate-pos.md       → 200
DELETE operations/tasks/test-gate-pos.md    → 200
DELETE knowledge/test-gate-report.md        → 200
GET knowledge/dev/test-gate-pos.md          → 404
GET operations/tasks/test-gate-pos.md       → 404
GET knowledge/test-gate-report.md           → 404

Confirmed cleaned up. Delete API not modified.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/reports/ogv-2c-write-gate-implementation-report-2026-05-07.md