05-c1-endpoint-no-mutation-deploy-path-proof-2026-06-22.md
05 — G3b: C1 no-mutation endpoint — actual source located, minimal additive patch
Biggest hardening win: the executor source was "not in this checkout" in the prior package. This turn I located and read it live (read-only) inside the running container, so the C1 endpoint is now a precise minimal patch against real code, not a hand-wave.
1. Actual source & deploy mechanism (live, read-only)
SSOT note (see 00a): the executor source SSOT is
/opt/incomex/deploy/agent-api-executor/on the VPS — hostmain.pysha09cdd867…== container/app/main.pysha09cdd867…(identical), proving the deploy dir is authoritative. The C1 patch in this package isLOCAL_STAGING_NOT_SSOT, to be operator-applied there + rebuilt.
- Container
incomex-agent-api-executor, imageagent-api-executor-local:v1, Up 2 weeks (healthy),8090->8090. - Source/deploy SSOT dir:
/opt/incomex/deploy/agent-api-executor/(Dockerfile,main.py,verifier.py,llm_client.py,requirements.txt,fixtures/). Edit here → rebuild → redeploy. docker inspect:WORKDIR=/app,CMD=[uvicorn main:app --host 0.0.0.0 --port 8090], no bind mounts (source baked into the image)./app:main.py(167 lines),verifier.py,llm_client.py,requirements.txt,fixtures/dot_kg_explain_fixture_v1.json. Read in full viadocker exec … cat(read-only).- Deploy path = rebuild image + redeploy container (operator/deploy-pipeline; DOT-approved deploy, not a
dot-*CLI). No new container/port.
2. It is already generic & fail-closed (reused unchanged)
main.py header, verbatim: "generic: keyed by dot_code; not hardwired to dot:kg. Add a fixture + contract row to support another agent_api DOT." The full fail-closed envelope is reused unmodified:
_assert_runtime_dry_run_only()→ 409 unless execute=false/real=false/dry_only=true (live gates already satisfy this).mode==REAL_RUN→ 403 "REAL_RUN not permitted";mode∉{PLAN_ONLY,DRY_RUN}→ 400; emptycorrelation_id→ 400.output_namespacemust startDRYRUN-NS:→ else 400.writes_db:falseon every path;/healthzreports gates +writes_db:false.
3. Minimal additive patch (design staged: patches/executor-main-py-c1.additive-design.md)
Only 3 additive changes; nothing existing is modified except one dict entry:
- FIXTURE_MAP += 1 line
"FIXTURE:dot:c1:vocab:v1": "dot_c1_vocab_fixture_v1.json"; ship the fixture (payloads/c1_vocab_fixture_v1.json) into/app/fixtures/. _produce()C1 branch keyed onexpected_producer_output.kind=="canonical_vocab_manifest"→_produce_c1_vocab(): readapr_action_types(status=active)read-only, build C-sorted manifest, computecser-v1sha256, return{manifest, manifest_hash, operation_count:14, writes_db:false}. KG path byte-for-byte unchanged.verifier.pycheck_c1_vocab_output(): set-equality vs the 14 authority codes + count==14 + hash present +writes_db is False. Pure (no DB/network/writes).
4. Contract surface (per macro §3.4)
- route name: reuse
POST /dispatch(distinguished bydot_code=DOT_C1_VOCAB_BUILD+fixture_ref=FIXTURE:dot:c1:vocab:v1). - input contract: existing
DispatchRequest{dot_code, fixture_ref, correlation_id, mode}. - output contract (DRY_RUN):
{produced:{manifest, manifest_hash, operation_count:14, writes_db:false}, verifier:{pass}, writes_db:false}. - REAL_RUN rejection: inherited 403 (unchanged).
- DRY_RUN readiness: PLAN_ONLY returns
{validated:true, writes_db:false}with only change #1 (fixture present) — producer not invoked; full manifest needs #2/#3. - health check:
GET /healthz(existing) used as post-deploy gate.
5. Rollback / revert (per macro §3.4)
Additive only → rollback = redeploy agent-api-executor-local:v1 (KG path unchanged ⇒ clean revert). Post-deploy regression check: re-run a KG PLAN_ONLY dispatch, assert identical to pre-deploy.
6. STOP conditions
- C1 producer able to open a writable transaction in DRY_RUN → STOP (must be read-only role).
- KG dispatch output changes post-patch → STOP (non-additive regression).
MOCK_PRODUCER=trueon a bound endpoint → STOP.
7. Verdict
G3b = path PROVEN. Real source located; minimal no-mutation handler designed against it; route/input/output/REAL_RUN-refusal/DRY_RUN-readiness/health/rollback all specified. No broad rewrite, no mega endpoint, C1-only. Deploy remains operator/deploy-scope (the one irreducible non-CLI step) — disclosed, not hidden.