From cd95b39e0e387d3f8961ec40d3a59f918bdd99f5 Mon Sep 17 00:00:00 2001 From: Code Queue Review Date: Fri, 22 May 2026 17:55:01 +0000 Subject: [PATCH] docs: clarify durable runtime readiness boundary --- docs/reference/dev-runtime-boundary.md | 34 ++++++++++++++++++++++++++ internal/cloud/server.test.mjs | 4 +++ scripts/cloud-api-runtime-smoke.mjs | 2 ++ 3 files changed, 40 insertions(+) diff --git a/docs/reference/dev-runtime-boundary.md b/docs/reference/dev-runtime-boundary.md index 84c50073..f54cbdc1 100644 --- a/docs/reference/dev-runtime-boundary.md +++ b/docs/reference/dev-runtime-boundary.md @@ -84,6 +84,40 @@ this agreement offline. A live pass still requires `/health/live` to report `db.ready=true`, `db.connected=true`, and `liveDbEvidence=true` with secret values redacted. +## Durable Runtime Readiness Contract + +DB live readiness and durable runtime readiness are separate gates. A +`/health/live` payload with `db.connected=true` and `db.liveDbEvidence=true` +only proves that the Cloud API reached the DEV DB endpoint without exposing +secret values. It does not prove that runtime writes are persisted through a +durable store. + +When health reports: + +- `runtime.adapter: "memory"` +- `runtime.durable: false` +- `runtime.status: "degraded"` + +the Cloud API is using the process-local runtime store in +`internal/db/runtime-store.mjs`. Gateway sessions, box resources, operations, +audit events, and evidence records accepted through the runtime can be lost on +pod restart, redeploy, or scale-out, and cannot be treated as durable M3/M4/M5 +evidence. Users may see accepted operations or evidence disappear after a +runtime replacement, and agent-loop/MVP acceptance must remain degraded or +blocked even if the DB connection layer is green. + +Readiness reports must keep these dimensions distinct: + +| Dimension | Green condition | Degraded/blocking condition | +| --- | --- | --- | +| DB live | `db.ready=true`, `db.connected=true`, `db.liveDbEvidence=true` | Missing env, failed connection, disabled probe, or no `liveDbEvidence` | +| Runtime durability | `runtime.durable=true` with a durable adapter | `runtime.adapter="memory"` or `runtime.durable=false` | + +Do not declare DEV-LIVE complete while `runtime.adapter="memory"` or +`runtime.durable=false`, even when DB live readiness is connected. The next +fix boundary is a durable runtime store and migration path; documenting or +testing this contract must not mutate runtime state or PROD. + ## Runtime Substitution Ban UniDesk services, provider-gateway, backend-core, microservice proxies, local diff --git a/internal/cloud/server.test.mjs b/internal/cloud/server.test.mjs index 652572bc..b8e5a570 100644 --- a/internal/cloud/server.test.mjs +++ b/internal/cloud/server.test.mjs @@ -117,6 +117,10 @@ test("cloud api health reports DB env presence and live connection classificatio assert.equal(payload.db.evidence, "live_db_tcp_connection_ready"); assert.equal(payload.db.safety.liveDbEvidence, true); assert.equal(payload.db.safety.liveDbConnectedEvidence, true); + assert.equal(payload.runtime.adapter, "memory"); + assert.equal(payload.runtime.durable, false); + assert.equal(payload.runtime.status, "degraded"); + assert.match(payload.runtime.reason, /process-local/u); assert.equal(payload.db.redaction.valuesRedacted, true); assert.equal(payload.db.redaction.endpointRedacted, true); assert.equal(payload.db.redaction.secretMaterialRead, false); diff --git a/scripts/cloud-api-runtime-smoke.mjs b/scripts/cloud-api-runtime-smoke.mjs index 2c2c3091..855eb1f0 100644 --- a/scripts/cloud-api-runtime-smoke.mjs +++ b/scripts/cloud-api-runtime-smoke.mjs @@ -92,8 +92,10 @@ async function run() { assert.equal(health.body.db.connectionResult, "not_attempted_missing_env"); assert.equal(health.body.db.ready, false); assert.deepEqual(health.body.db.missingEnv, ["HWLAB_CLOUD_DB_URL", "HWLAB_CLOUD_DB_SSL_MODE"]); + assert.equal(health.body.runtime.adapter, "memory"); assert.equal(health.body.runtime.durable, false); assert.equal(health.body.runtime.status, "degraded"); + assert.match(health.body.runtime.reason, /process-local/u); logOk("health degraded DB contract"); const v1 = await requestJson(`${baseUrl}/v1`);