Compare commits

...
@@ -0,0 +1,82 @@
# Agent Execution Contract — External Action Surface Binding
## Objective
Make the externally exposed ChatGPT Action surface use the already-verified immutable non-production staging runtime:
- staging runtime source: `2ec49005bde44f6981b14351500847d594e0276c`
- artifact SHA-256: `f67aed6cc0cce1f08197485c3eea204d3ef4d3989f44dc98e8ea2691e5886cbf`
- runtime mode: `IMMUTABLE_STAGING`
Do not modify production, main, release tags, or baseline registry.
## Current verified contradiction
Control-plane snapshot reports the repaired staging identity above and drift status PASS.
However the externally exposed Action surface still behaves like the old `341d276f18a24966f965eb3499a86c156f4b3c25-contract-overlay-v2` runtime:
- `getTagPublicationStatus("V2R2C1")` -> `invalid release version`
- `getReleaseConsistency(...)` -> `Gitea API URL must be HTTP(S)`
- `getReleaseSaga(nonexistent)` -> permission denied on `/var/lib/aios-gitops/silent-release`
Therefore the six functional repairs are verified in staging, but endpoint/runtime binding is stale.
## Required unattended execution
1. Collect facts before changing anything:
- actual process/container/systemd identity serving the external Action endpoint;
- its source commit/artifact/config digest;
- reverse proxy / service discovery / OpenAPI registration / plugin connector routing;
- health endpoints and current upstream target;
- `getRuntimeStatus` implementation source and why it resolves to the old overlay;
- control-plane snapshot source and why it resolves to the repaired staging runtime.
2. Identify the single source of truth for Action endpoint routing.
3. Switch only the non-production externally exposed Action surface to the verified repaired staging runtime/artifact.
4. Do not rebuild the six repairs unless the deployed artifact digest does not match the verified artifact above.
5. Restart/reload only the minimum affected non-production routing/action service.
6. Wait for health.
7. Execute the external Action smoke suite through the same interface used by ChatGPT, not by calling staging localhost/internal endpoints directly.
8. Restart the affected non-production service once more and repeat the external smoke suite.
9. If cutover breaks health or introduces a regression, automatically restore the previous Action-surface target and collect logs.
## External acceptance gates
All checks must be made through the externally exposed Action interface.
- `getRuntimeStatus` and control-plane snapshot describe the same staging runtime identity, or explicitly expose different layers with no ambiguous/stale source identity.
- `getTagPublicationStatus("V2R2C1")` returns structured state, not `invalid release version`.
- `getReleaseConsistency(V2R2C1, 998d30304787e31e5ae607c0bd86b5edb2b0e5ad, a8b906d1bc24088c19647e98de6a679268f6d0a2, approved_plan)` reaches consistency evaluation and does not fail on Gitea URL validation.
- `getReleaseSaga(nonexistent)` returns structured NOT_FOUND/empty semantics and never filesystem permission error.
- published `commitFilesGoverned` schema contains required `files`.
- governed two-file commit succeeds on isolated `agent/*` branch.
- terminal completed job reconcile is idempotent.
- large `getDiff` returns bounded/truncated structured output without transport exception.
- protected-ref write controls remain unchanged.
- `production_deployed=false`.
## Evidence
Commit a report at:
`reports/action-surface-binding-evidence-20260825.md`
Include:
- pre-cutover external runtime identity;
- routing/config root cause;
- exact files/configs changed;
- pre/post upstream target;
- process/service restart details;
- health results;
- all external Action smoke results before and after restart;
- rollback test or rollback readiness evidence;
- final external runtime source/artifact identity;
- confirmation production/main/tags/baseline were untouched.
## Completion rule
Do not mark SUCCEEDED merely because control-plane staging is healthy.
SUCCEEDED is allowed only when the same externally exposed Action endpoint used by ChatGPT passes all external acceptance gates after restart.
If the task API cannot represent NEEDS_REWORK, leave the task non-successful and record the required disposition in the evidence report. Do not forge task state or mutate the database directly.