# Platform Evidence Input Mapping v1

Status: active first-slice mapping (PF-EVIDENCE-INPUTS-001)
Owner: Platform Architecture / Operations
Last updated: 2026-06-01

## Purpose

Map existing CI, UAT, security, guard, and release artifacts into the platform
evidence bundle API so production-readiness evidence can be recorded without
inventing a second release checklist.

This mapping does not make every producer blocking. It gives each producer a
stable payload shape that can later become a release gate.

## Evidence Producers

| Producer | First artifact | `evidence_type` | Default result source | Proves invariants |
|---|---|---|---|---|
| CI contract/build/test jobs | GitLab/GitHub job URL or local command artifact | `ci` | `PLATFORM_EVIDENCE_CI_RESULT` | `PLATFORM-AUDIT-001`, `PLATFORM-OUTBOX-001` when relevant |
| Platform-foundation guard report | `tmp/platform-foundation-guards/summary.json` | `guard_report` | pass when no unapproved high/critical findings, otherwise partial | boundary discipline and ownership-map conformance |
| Demo/UAT automation | `dist/uat/**/results.jsonl` report path or URL | `uat` | `evidence_result` in UAT JSONL, or `PLATFORM_EVIDENCE_UAT_RESULT` when supplied | `GPUAAS-*`, `APP-*`, and `PLATFORM-*` invariant IDs named by the UAT job |
| Security scans | SAST/DAST/govulncheck/image scan summary artifact | `security_scan` | `PLATFORM_EVIDENCE_SECURITY_RESULT` | authz, secrets, dependency, and image posture evidence |
| Deployment smoke/release scripts | deploy/smoke job URL or manifest artifact | `deployment_smoke` | `PLATFORM_EVIDENCE_DEPLOY_RESULT` | environment readiness, rollback, and capacity posture |

## Payload Helper

`scripts/ci/platform_evidence_payload.sh` writes:

- `bundle.json`: request body for `POST /api/v1/v3/platform/evidence/bundles`;
- `items.json`: evidence item request bodies for
  `POST /api/v1/v3/platform/evidence/bundles/{bundle_id}/items`;
- `release-gates.json`: computed gate posture for review/readiness;
- `README.md`: producer-facing notes for the generated payload directory.

The helper does not contact a live API by default. Release/UAT jobs should
upload the generated directory as an artifact first. API submission can be added
after auth/token flow and environment promotion policy are settled.

`release-gates.json` is intentionally generated before live submission. It lets
release reviewers see whether the current bundle is clean, missing evidence,
partially accepted with debt, blocked, or failed without reading raw CI/UAT
logs.

`scripts/ci/platform_status_snapshot.sh` writes the first Status/Ops component
feed from those artifacts:

- `component-status-summary.json`: reviewable rows for evidence gates,
  platform-foundation guard posture, outbox relay lag, NATS DLQ backlog, and
  money-domain health for billing worker, webhook/payment processing, and
  rating/ledger posting, plus runtime-trust health for cert and secret
  rotation;
- `component-status-ingest.sql`: dry-run/live upsert for
  `platform_status_component_status`.

This keeps Status/Ops useful before a dedicated collector exists. Live upsert is
opt-in with `PLATFORM_STATUS_SNAPSHOT_INGEST=1`, `DATABASE_URL`, and `psql`.

Money-domain rows are intentionally emitted even when their source artifacts are
missing. In that case the status is `unknown` with
`details.missing_artifact = "money-domain status metrics"`, which keeps billing
and payment observability gaps visible in the same read model as release gates.

| Component | Variables | Default posture |
|---|---|---|
| `billing-worker` | `PLATFORM_STATUS_BILLING_WORKER_LAG_SECONDS`, `PLATFORM_STATUS_BILLING_WORKER_CONSUMER_PENDING`, `PLATFORM_STATUS_BILLING_WORKER_FAILED_ACCRUALS`, optional `PLATFORM_STATUS_BILLING_WORKER_STATUS`, optional `PLATFORM_STATUS_BILLING_WORKER_EVIDENCE_HREF` | healthy when lag, pending events, and failed accruals are within thresholds; unknown when all are absent |
| `webhook-worker` | `PLATFORM_STATUS_WEBHOOK_FAILURES`, `PLATFORM_STATUS_PAYMENT_STUCK_SESSIONS`, optional `PLATFORM_STATUS_WEBHOOK_WORKER_STATUS`, optional `PLATFORM_STATUS_WEBHOOK_WORKER_EVIDENCE_HREF` | healthy when webhook failures and stuck payment sessions are within thresholds; unknown when both are absent |
| `rating-ledger` | `PLATFORM_STATUS_UNRATED_USAGE_RECORDS`, `PLATFORM_STATUS_UNPOSTED_RATED_LINES`, `PLATFORM_STATUS_LEDGER_RECONCILIATION_FAILURES`, optional `PLATFORM_STATUS_RATING_LEDGER_STATUS`, optional `PLATFORM_STATUS_RATING_LEDGER_EVIDENCE_HREF` | healthy when unrated usage, unposted rated lines, and ledger reconciliation failures are within thresholds; unknown when all are absent |
| `runtime-cert-rotation` | `PLATFORM_STATUS_CERT_MIN_REMAINING_DAYS`, `PLATFORM_STATUS_CERT_RENEWAL_FAILURES`, `PLATFORM_STATUS_CERT_GRACE_EXCEPTIONS`, optional `PLATFORM_STATUS_CERT_ROTATION_STATUS`, optional `PLATFORM_STATUS_CERT_ROTATION_EVIDENCE_HREF` | healthy when cert remaining days, renewal failures, and grace exceptions are within thresholds; unknown when all are absent |
| `secret-rotation` | `PLATFORM_STATUS_SECRET_MAX_AGE_DAYS`, `PLATFORM_STATUS_SECRET_ROTATION_FAILURES`, `PLATFORM_STATUS_SECRET_GRACE_EXCEPTIONS`, optional `PLATFORM_STATUS_SECRET_ROTATION_STATUS`, optional `PLATFORM_STATUS_SECRET_ROTATION_EVIDENCE_HREF` | healthy when secret age, rotation failures, and grace exceptions are within thresholds; unknown when all are absent |

Each row supports threshold overrides using the same variable prefix plus a
`*_DEGRADED_*` or `*_UNHEALTHY_*` suffix. For example,
`PLATFORM_STATUS_BILLING_WORKER_LAG_DEGRADED_SECONDS` and
`PLATFORM_STATUS_BILLING_WORKER_LAG_UNHEALTHY_SECONDS` tune billing worker lag
grading for a specific environment.

Runtime-trust rows use the same threshold pattern. For example,
`PLATFORM_STATUS_CERT_REMAINING_DEGRADED_DAYS`,
`PLATFORM_STATUS_CERT_REMAINING_UNHEALTHY_DAYS`,
`PLATFORM_STATUS_SECRET_AGE_DEGRADED_DAYS`, and
`PLATFORM_STATUS_SECRET_AGE_UNHEALTHY_DAYS` tune cert/secret posture for a
specific environment.

## Gate Inputs

| Gate ID | Inputs | Result rule |
|---|---|---|
| `ci` | `PLATFORM_EVIDENCE_CI_SOURCE_URI`, `PLATFORM_EVIDENCE_CI_ARTIFACT_PATH`, `PLATFORM_EVIDENCE_CI_RESULT` | missing when no CI source/artifact exists; otherwise uses the supplied/default result |
| `guard-report` | `PLATFORM_EVIDENCE_GUARD_JSON` | pass when no unapproved high/critical findings exist; partial when such findings exist |
| `uat` | `PLATFORM_EVIDENCE_UAT_SOURCE_URI`, `PLATFORM_EVIDENCE_UAT_ARTIFACT_PATH`, `PLATFORM_EVIDENCE_UAT_INVARIANTS` | missing when no UAT source/artifact exists; otherwise parses `results.jsonl` under the artifact path and preserves pass/fail/partial/blocked/missing state unless an explicit result is supplied |
| `security` | `PLATFORM_EVIDENCE_SECURITY_SOURCE_URI`, `PLATFORM_EVIDENCE_SECURITY_ARTIFACT_PATH` | missing when no scan source/artifact exists; otherwise uses the supplied/default result |
| `deployment-smoke` | `PLATFORM_EVIDENCE_DEPLOY_SOURCE_URI`, `PLATFORM_EVIDENCE_DEPLOY_ARTIFACT_PATH` | missing when no deployment smoke source/artifact exists; otherwise uses the supplied/default result |
| `capacity-posture` | `PLATFORM_EVIDENCE_CAPACITY_POSTURE`, `PLATFORM_EVIDENCE_REQUIRE_CAPACITY` | pass when capacity posture is supplied; missing when required but absent; otherwise not applicable |
| `residual-risk` | `PLATFORM_EVIDENCE_RESIDUAL_RISK`, `PLATFORM_EVIDENCE_APPROVED_RESIDUAL_RISK` | pass when no residual risk exists or residual risk is explicitly approved; partial when residual risk lacks approval |

## Submission Helper

`scripts/ci/platform_evidence_submit.sh` validates the generated payloads and
prints the planned API requests by default.

Live submission is opt-in and requires all of:

- `PLATFORM_EVIDENCE_SUBMIT=1`;
- `PLATFORM_EVIDENCE_API_BASE_URL`;
- `PLATFORM_EVIDENCE_BEARER_TOKEN`.

The helper creates the evidence bundle first, extracts `bundle.bundle_id`, and
then submits each item with an idempotency key. It is intended for CI/release
automation after the target environment has an approved ops-write token flow.
Until then, generated payload artifacts remain the reviewable evidence handoff.

## Required Environment

| Variable | Meaning | Default |
|---|---|---|
| `PLATFORM_EVIDENCE_OUTPUT_DIR` | output directory | `dist/platform-evidence` |
| `PLATFORM_EVIDENCE_SOURCE_COMMIT` | source commit under review | `git rev-parse HEAD` |
| `PLATFORM_EVIDENCE_RELEASE_BRANCH` | release or lane branch | current git branch |
| `PLATFORM_EVIDENCE_ENVIRONMENT_PROFILE` | target environment profile | `platform-control` |
| `PLATFORM_EVIDENCE_PRODUCT_SCOPE` | `gpuaas`, `app-platform`, `platform-shared-service`, or `cross-product` | `cross-product` |
| `PLATFORM_EVIDENCE_CHANGE_SUMMARY` | human release/change summary | latest commit subject |

## Optional Evidence Inputs

| Variable | Evidence item |
|---|---|
| `PLATFORM_EVIDENCE_GUARD_JSON` | guard report JSON path; defaults to `tmp/platform-foundation-guards/summary.json` when present |
| `PLATFORM_EVIDENCE_CI_SOURCE_URI` | CI job/pipeline URL for the `ci` item |
| `PLATFORM_EVIDENCE_UAT_SOURCE_URI` | UAT artifact path or URL for the `uat` item |
| `PLATFORM_EVIDENCE_SECURITY_SOURCE_URI` | security summary artifact path or URL for the `security_scan` item |
| `PLATFORM_EVIDENCE_DEPLOY_SOURCE_URI` | deployment smoke artifact path or URL for the `deployment_smoke` item |

Each optional item has a matching result variable:

- `PLATFORM_EVIDENCE_CI_RESULT`;
- `PLATFORM_EVIDENCE_UAT_RESULT`;
- `PLATFORM_EVIDENCE_SECURITY_RESULT`;
- `PLATFORM_EVIDENCE_DEPLOY_RESULT`.

Valid results are `pass`, `fail`, `partial`, `blocked`, `missing`, and
`not_applicable`.

Additional gate-policy variables:

- `PLATFORM_EVIDENCE_REQUIRE_CAPACITY`: set to `1` or `true` when capacity,
  ring, canary, or reserve posture is required for this change;
- `PLATFORM_EVIDENCE_APPROVED_RESIDUAL_RISK`: set to `1` or `true` when the
  residual risk statement has an explicit owner approval.

## Product Invariant Mapping

Jobs should set `PLATFORM_EVIDENCE_CI_INVARIANTS` as a comma-separated list
when a CI artifact proves a named invariant from
`Platform_Evidence_Status_Slice_v1.md`.

UAT automation should prefer artifact-native mapping. Each
`dist/uat/**/results.jsonl` record may include:

- `evidence_result`: one of `pass`, `fail`, `partial`, `blocked`, `missing`,
  or `not_applicable`;
- `invariants`: the exact product/platform invariants proved or attempted by
  that check.

`scripts/ci/platform_evidence_payload.sh` discovers those JSONL files
recursively when `PLATFORM_EVIDENCE_UAT_ARTIFACT_PATH` points at a UAT artifact
directory. It unions the invariant IDs and computes the UAT item result from
the most severe record. `PLATFORM_EVIDENCE_UAT_INVARIANTS` remains available as
an explicit override for older producers, but new UAT jobs should write the
mapping into the artifact itself.

Examples:

- `GPUAAS-LAUNCH-001,GPUAAS-CONNECT-001`;
- `APP-CONTRACT-001,APP-LAUNCH-001`;
- `PLATFORM-AUDIT-001,PLATFORM-OUTBOX-001`.

Missing invariant coverage should remain visible as missing or partial evidence.
Do not encode broad "UAT passed" evidence without naming what product invariant
the UAT actually proved.
