# Service operations Build with `make install test build`. `make test-integration` launches real Chromium inside the pinned upstream image; it needs Docker, not a host browser. Publish the tested image through the existing Forgejo OCI credential lane and read its digest back. `make render IMAGE_REFERENCE=forgejo.coulomb.social/coulomb/rapp-playwright@sha256:…` rejects floating tags. Never record a placeholder as a published digest. The initial package uses a single replica, Recreate updates, 100m CPU/256Mi requests, 1 CPU/1Gi limits, and a 2Gi local-path PVC. Artifacts expire after one hour; they are transient evidence, not a backup service. Consumers download what they need to retain. Recreate avoids a surge on the capacity-constrained single-node cluster and preserves the RWO volume. Before activation, confirm the node identity and current resource headroom, platform lifecycle ownership/admission, publication/pull access, and private consumer connectivity. Run `make server-dry-run IMAGE_REFERENCE=…`, inspect `kubectl diff -f .rendered/workload.yaml` on railiance01, then deploy the reviewed manifest with `make deploy IMAGE_REFERENCE=…`. No existing workload or policy needs relaxation. Platform confirmation is tracked in WP-0004-T01. For the first installation, after admission, run `make bootstrap-namespace IMAGE_REFERENCE=…` before the full server dry run. Kubernetes does not persist a dry-run Namespace, so namespace-scoped objects cannot be server-validated until the namespace exists. This bootstrap dry-runs and diffs only the reviewed Namespace before creating it. The full deployment also diffs before applying. The `playwright-consumer` Role grants only pod discovery and port-forward. Bind an approved existing user/group through the identity/platform owner. This repo does not mint credentials or silently bind all authenticated users. Callers with existing authorized Kubernetes access can use the documented port-forward. The pod has no service-account token and no cluster permissions. Readiness performs the authenticated-protocol preflight over pod loopback. It requires a successful browser launch; liveness checks the process only. The pod uses non-root UID/GID 1000, read-only root, dropped capabilities and RuntimeDefault seccomp. Tini reaps orphaned browser processes. Chromium's OS sandbox is disabled for this trusted-target pilot; it is not approved for hostile websites or mutually untrusted tenants. The HTTP/CONNECT origin gate, private-address checks, blocked workers/WebSockets, per-run process/context and resource limits cover the documented application-level boundary, not browser-kernel exploits. ## Verify and recover After establishing the consumer tunnel, `make verify-live TRIAL_OUT=.local/live-N` must produce four PNGs, focus/keyboard assertions and a receipt. Check the live container image and imageID against the published digest, PVC binding, deny-all ingress and ready replica. Exercise wrong run token, deliberate UI failure, unreachable target, cancellation and service restart; a passing health endpoint alone is insufficient. After restart, accepted nonterminal runs become `interrupted`; completed runs remain retrievable until expiry. A client disconnect does not cancel an accepted job, so all runs have enforced deadlines. Supervisor cancellation closes the browser; after two seconds it kills the recorded worker/browser process groups. Service shutdown drains/cancels bounded work. Corrupt receipts cause startup to fail closed; restore or quarantine the affected transient run directory through the owner, without exposing capability hashes or screenshots in logs. Rollback: retain the previous immutable image reference and rendered revision, review its schema compatibility, then run `make rollback IMAGE_REFERENCE=…`. Verify the replacement's imageID and repeat the trial. For the first release, test recovery by reapplying the same verified digest; do not call that proof of cross-version rollback. Once a second release exists, exercise an actual digest change and return to the reviewed release. No automated rollback migrates or deletes the PVC. V1 receipts are JSON; future incompatible formats require an explicit migration/rollback decision. Upgrade Playwright and its base image together, update the lockfile, repeat the unit/browser/client tests and consumer pilot, then publish a new immutable image. The Python client checks protocol v1 and does not install Playwright. ## Published release Release [0.1.0](../releases/0.1.0.json) is published and pull-verified. Use its immutable reference for rendering; registry publication is no longer blocked. The cluster-owned ingress now allows a bounded 600-second HTTPS request body; see [cause, rollout and verification](evidence/2026-10-13-publication.md). For subsequent publications, fetch the remote index with `docker buildx imagetools inspect --raw ` and hash the exact returned bytes. Require the expected digest, then pull that immutable reference with `sudo k3s crictl pull ` on railiance01 and verify its recorded repo digest. A successful upload alone does not establish node pull access. ## Repeatable consumer API acceptance After Platform establishes and verifies the caller's own identity, permission boundary and port-forward, run this from the provider checkout with Python 3.10+: ```sh python3 tools/verify_consumer.py --url http://127.0.0.1:18081 \ --expected-release forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441 \ --expected-location railiance01/playwright --out .local/consumer-acceptance-01 ``` Use a fresh output directory for each caller/run. Exit 0 means browser API checks passed; exit 3 means verification failed. `verification.json` lists checks and errors. The command verifies exact release/location, desktop/narrow PNG dimensions and hashed downloads, keyboard assertions, foreign-token receipt/artifact denial, failed-assertion evidence, private-target refusal and running-job cancellation. It submits only fixture jobs and one denied private-target request, cancels its own runs on exit and does not restart the service or alter access grants. Keep all `run.json` files private. Pair the result with Platform's native consumer identity/permission receipt for each real human and registered coding agent. The result deliberately says `identity_authentication_verified: false`: neither operator impersonation nor this browser check alone proves self-service access. Target-unreachable diagnostics, abrupt interruption/recovery, revocation/stream termination and cross-version rollback require their separate evidence. The command's local validation is retained in [evidence](evidence/2026-10-13-consumer-verifier.json).