rcf-lite 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/blueprints/application-api-rest/README.md +5 -1
- package/blueprints/application-api-rest/blueprint.json +1 -1
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-006.json +4 -4
- package/blueprints/application-api-rest/contributions/tacs/tac-306-application-api-rest-operability.json +9 -8
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2103.json +3 -3
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2108.json +27 -27
- package/blueprints/application-api-rest/docs/topics.md +2 -2
- package/blueprints/application-api-rest/guide/application-api-rest.md +5 -1
- package/blueprints/application-spa/assets/tc-templates/e2e.md +85 -0
- package/blueprints/application-spa/blueprint.json +24 -2
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1134.json +24 -0
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1135.json +24 -0
- package/blueprints/application-spa/docs/topics.md +2 -2
- package/blueprints/delivery-ci-workflows/assets/ci-provider-examples/github-actions/pull-request-checks.yml +69 -0
- package/blueprints/delivery-ci-workflows/assets/ci-provider-examples/notes.md +18 -0
- package/blueprints/delivery-ci-workflows/blueprint.json +301 -60
- package/blueprints/delivery-ci-workflows/contributions/user-stories/delivery-ci-workflows-us-6124.json +28 -0
- package/blueprints/delivery-ci-workflows/docs/topics.md +2 -2
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
- package/blueprints/email-smtp-resend/docs/topics.md +2 -2
- package/blueprints/observability-essentials/README.md +6 -2
- package/blueprints/observability-essentials/blueprint.json +133 -33
- package/blueprints/observability-essentials/contributions/adrs/adr-801-observability-essentials-health-probes.json +4 -4
- package/blueprints/observability-essentials/contributions/adrs/adr-802-observability-essentials-readiness-semantics.json +4 -4
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-001.json +4 -4
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-002.json +4 -4
- package/blueprints/observability-essentials/contributions/tacs/tac-801-observability-essentials-liveness-probe.json +10 -9
- package/blueprints/observability-essentials/contributions/tacs/tac-802-observability-essentials-readiness-probe.json +17 -11
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7101.json +12 -3
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7102.json +12 -3
- package/blueprints/observability-essentials/docs/topics.md +15 -8
- package/blueprints/observability-essentials/guide/observability-essentials.md +9 -3
- package/blueprints/observability-probe-endpoints/README.md +5 -1
- package/blueprints/observability-probe-endpoints/blueprint.json +116 -24
- package/blueprints/observability-probe-endpoints/contributions/adrs/adr-1503-observability-probe-endpoints-kubernetes-default.json +5 -5
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14102.json +11 -2
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14107.json +11 -2
- package/blueprints/observability-probe-endpoints/docs/topics.md +6 -6
- package/blueprints/observability-probe-endpoints/guide/observability-probe-endpoints.md +10 -0
- package/blueprints/persistence-data-d1/docs/topics.md +2 -2
- package/blueprints/persistence-data-sqlite/docs/topics.md +2 -2
- package/blueprints/security-auth-clerk/docs/topics.md +2 -2
- package/blueprints/security-auth-keycloak/docs/topics.md +2 -2
- package/blueprints/security-auth-magic-link/docs/topics.md +2 -2
- package/blueprints/security-auth-oauth2/docs/topics.md +2 -2
- package/blueprints/security-secrets-management/docs/topics.md +2 -2
- package/fixtures/canary-manifest.json +9 -9
- package/package.json +13 -1
- package/rcf/code-nodes/cn-070.json +12 -0
- package/rcf/code-nodes/cn-071.json +12 -0
- package/rcf/code-nodes/cn-072.json +12 -0
- package/rcf/code-nodes/cn-073.json +12 -0
- package/rcf/code-nodes/cn-074.json +19 -0
- package/rcf/code-nodes/cn-075.json +15 -0
- package/rcf/code-nodes/cn-076.json +14 -0
- package/rcf/fbs/fbs-020.json +18 -0
- package/rcf/fbs/fbs-021.json +18 -0
- package/rcf/fbs/fbs-022.json +18 -0
- package/rcf/fbs/fbs-023.json +18 -0
- package/rcf/fbs/fbs-024.json +24 -0
- package/rcf/fbs/fbs-025.json +25 -0
- package/rcf/fbs/fbs-026.json +27 -0
- package/rcf/fbs/fbs-027.json +25 -0
- package/rcf/prd.json +3 -2
- package/rcf/requirements/req-011.json +22 -0
- package/rcf/requirements/req-012.json +22 -0
- package/rcf/test-suites/ts-030.json +66 -0
- package/rcf/test-suites/ts-031.json +59 -0
- package/rcf/test-suites/ts-032.json +50 -0
- package/rcf/test-suites/ts-033.json +83 -0
- package/rcf/test-suites/ts-034.json +32 -0
- package/rcf/test-suites/ts-035.json +23 -0
- package/rcf/test-suites/ts-036.json +65 -0
- package/rcf/test-suites/ts-037.json +55 -0
- package/rcf/user-stories/us-1101.json +51 -0
- package/rcf/user-stories/us-1102.json +60 -0
- package/rcf/user-stories/us-1103.json +51 -0
- package/rcf/user-stories/us-1104.json +60 -0
- package/rcf/user-stories/us-1201.json +34 -0
- package/rcf/user-stories/us-1202.json +25 -0
- package/rcf/user-stories/us-1203.json +43 -0
- package/rcf/user-stories/us-1204.json +25 -0
- package/releases/releases.yaml +21 -1
- package/src/blueprint/index.js +1 -0
- package/src/blueprint/remove-resolution.js +104 -0
- package/src/blueprint/supersede.js +2 -2
- package/src/cli/blueprint.js +41 -0
- package/src/cli/doctor.js +257 -5
- package/src/cli/init.js +166 -0
- package/src/setup/playwright-checks.js +426 -0
- package/src/verify/cli/run.js +28 -0
- package/src/verify/engine/index.js +24 -4
- package/src/verify/engine/launcher.js +41 -10
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,42 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.18.0] - 2026-09-04
|
|
10
|
+
|
|
11
|
+
Core shelf probe-path alignment. One shelf blueprint owns the probe-path binding across the whole shelf: `observability-probe-endpoints` v1.1.0 is the sole `scope: global` claimant on `healthProbes` and `readinessSemantics` and gains an optional Kubernetes-profile `/startup` path (off by default, enabled per project by `probeInterface.options.kubernetes.startup.enabled: true`). `observability-essentials` v2.0.0 drops its two `scope: global` topic claims, drops the shipped `/healthz` and `/readyz` defaults from TAC-801/802 (`path` becomes required config with no default), and adds the stable-coded `PROBE_INTERFACE_PATHS_MISSING` boot refusal for essentials-alone projects that forget the config. `application-api-rest` v2.0.0 drops the literal `/healthz/live`, `/healthz/ready`, and `/healthz/startup` bindings from REQ-006, US-2108, TAC-306, and the US-2103 versioning exemption, deferring to the resolved probe path set the probe-endpoints blueprint emits via TAC-1501 `getExemptPathSet` (or to the project-supplied `probeInterface.paths` in the essentials-alone case). `rcf doctor` grows a `probe-path-owner` check that fires when more than one applied blueprint teaches probe paths, and `rcf define blueprint remove-resolution <adr-id>` is the paired remedy verb that drops a single `manifest.resolutions[]` entry by its `resolvedByAdrId`. Spec: `projects/rcf-lite-wsd/specs/rcf-lite-probe-path-alignment-spec-2026-09-04.md` (amendments A1 to A3). Chain: REQ-012 with US-1201/1202/1203/1204 and TS-034/035/036/037 on the rcf-lite own tree.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`rcf define blueprint remove-resolution <adr-id>`.** Drops a single `manifest.resolutions[]` entry by its `resolvedByAdrId`; writes nothing else and leaves the project-level ADR file at `rcf/adrs/<adr-id>.json` in place as historical context. Refuses exit 2 when `<adr-id>` is malformed or names no ADR on the project tree. Idempotent on re-run: when `<adr-id>` is a well-formed ADR id that still names an ADR on the tree but is no longer on any resolutions[] entry, prints `nothing to remove` and exits 0. This is the verb the `probe-path-owner` doctor check and spec section 9 name as the redundant-resolution remedy; before this change the message named a verb that did not exist. Chain: US-1204 with TS-037 on REQ-012 for the rcf-lite own tree; spec amendment A2 (2026-09-04, under the envelope after gate d-2026-09-04-016 finding 1); work item `w-2026-09-03-dave-021`.
|
|
16
|
+
|
|
17
|
+
- **Core shelf probe-path alignment (spec 2026-09-04).** One owner on the shelf for the probe-path binding. `observability-probe-endpoints` v1.1.0 is the sole shelf-wide `scope: global` claimant on `healthProbes` and `readinessSemantics` and adds an optional third Kubernetes-profile path `startup` (default `/startup`, off by default, enabled per project by `probeInterface.options.kubernetes.startup.enabled: true`) with paired ACs on US-14102 (AC-14102-4: three-path resolution) and US-14107 (AC-14107-4: three-entry auth-exempt list). `observability-essentials` v2.0.0 drops its `scope: global` claims on `healthProbes` and `readinessSemantics` (ADR-801 and ADR-802 become scope-local historical ADRs with a title change; content body stays for reader context per spec section 4), restates REQ-001/002 path-neutral, drops the `/healthz` and `/readyz` defaults from TAC-801/802 (`path` becomes required config with no shipped default), and gains AC-7101-4 and AC-7102-4 covering the stable-coded `PROBE_INTERFACE_PATHS_MISSING` boot refusal for essentials-alone projects. `application-api-rest` v2.0.0 drops the literal `/healthz/live`, `/healthz/ready`, and `/healthz/startup` bindings from REQ-006, US-2108 (all eight ACs), TAC-306, and US-2103 (versioning-exemption AC), deferring to the resolved probe path set that `observability-probe-endpoints` emits via TAC-1501 `getExemptPathSet` (or the project-supplied `probeInterface.paths` in the essentials-alone case). The three-way alignment is verified by `packages/rcf-lite/test/blueprint/probe-path-alignment.test.js`: 15 tests covering the nine assertions of spec section 7 across the six permutations of applying the three amended blueprints. `rcf doctor` gains a `probe-path-owner` check that fires when more than one applied blueprint teaches probe paths (spec section 9). Chain: REQ-012 with US-1201/1202/1203 and TS-034/035/036 on the rcf-lite own chain records the WHAT of the alignment for the dogfood tree. Trace: `projects/rcf-lite-wsd/specs/rcf-lite-probe-path-alignment-spec-2026-09-04.md` (sections 1 through 11); origin: Dex WSD escalation 2026-09-03; work item `w-2026-09-03-dave-021`.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **`observability-probe-endpoints`: 1.0.0 -> 1.1.0** (minor bump per blueprint-authoring section 8: additive, no scope:global topic change).
|
|
22
|
+
- **`observability-essentials`: 1.0.0 -> 2.0.0** (major bump: drops two `scope: global` topic claims and reshapes REQ/TAC bodies).
|
|
23
|
+
- **`application-api-rest`: 1.0.0 -> 2.0.0** (major bump: shape change to REQ-006 and US-2108 AC set removes literal probe paths).
|
|
24
|
+
|
|
25
|
+
### Migration notes
|
|
26
|
+
|
|
27
|
+
- A project that applied only `observability-essentials` v1.x: re-applying to v2.0.0 requires one line of configuration per environment (`probeInterface.paths.liveness` and `probeInterface.paths.readiness`) to satisfy the essentials boot wiring, unless the project also composes `observability-probe-endpoints` v1.1.0 or later (which supplies the paths automatically).
|
|
28
|
+
- A project that applied both `observability-essentials` v1.x and `observability-probe-endpoints` v1.0.0 with a project-level ADR superseding both on `healthProbes` and `readinessSemantics`: after re-apply, the resolutions are redundant historical context; `rcf doctor`'s `probe-path-owner` check flags them with the `rcf define blueprint remove-resolution` hint.
|
|
29
|
+
- A project that applied `application-api-rest` v1.x: FBSes and TCs that bind literal `/healthz/live`, `/healthz/ready`, or `/healthz/startup` strings need one edit each to bind the resolved path set; `rcf audit coverage --strict` catches project-side TCs that still hold the literal strings after re-apply.
|
|
30
|
+
|
|
31
|
+
## [0.17.0] - 2026-09-04
|
|
32
|
+
|
|
33
|
+
The e2e verification contract for browser-facing projects. Verify pins `@playwright/mcp@0.0.80` with a preflight print and a `--playwright-mcp-version` override for emergency use; the effective pin lands on the report's runStats. Doctor gains four browser-facing checks (`playwright-present`, `browser-present`, `playwright-mcp-reachable`, `playwright-mcp-redundant`) routed by an applied blueprint's `browserSurface`, with a one-line skip on API-only projects. Init writes a Playwright MCP entry only when no scope-visible signature exists, falling back to a distinctly named `playwright-rcf` project-scope entry when it cannot prove absence, and opt-out via `--no-playwright-mcp`. `application-spa` v1.4.0 and `delivery-ci-workflows` v2.2.0 ship the paired `browserSurface` stories and the illustrative e2e job as a documentation contract per spec 2026-09-03 amendment A2; the runtime materialiser lands in a follow-up train.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **`application-spa` v1.4.0 and `delivery-ci-workflows` v2.2.0: e2e as a declared test level.** The SPA blueprint's manifest carries a new top-level `browserSurface` object (`{ declared: true, routes: [...], themes: [...] }`) and contributes two browser-facing acceptance criteria via new stories `application-spa-US-1134` (icon renders on the home route across declared themes; binds `application-spa-REQ-011`) and `application-spa-US-1135` (unauthenticated visit to a protected route lands on the sign-in page; binds `application-spa-REQ-009`). A paste-in `assets/tc-templates/e2e.md` ships the `testLevel: e2e` test-case shape and names `rcf verify browser` as the driver seam so the same Playwright installation the invariants use drives the coverage anchor. The `delivery-ci-workflows` blueprint contributes `US-6124` binding `AC-6124-1` on the `e2e` elicited check: the materialised `pull-request-checks` workflow contains a distinct `e2e` job (runs `testLevel: e2e` cases against a local preview or a `--parity-env` runtime, uploads screenshots and HTML captures, writes `.rcf/reports/ci/e2e.json` with `checkKind: "e2e"`) iff at least one applied blueprint declares `.browserSurface.declared: true` and `checkSet.e2e` is not explicitly false. The illustrative GHA `pull-request-checks.yml` and the alternate-provider `notes.md` (GitLab CI, CircleCI, Buildkite, Jenkins) each ship the e2e job as a documented example. `browserSurface` lives on the source `blueprint.json` only: the applied blueprint record carries no new field (the `appliedBlueprintRecord` schema in rcf-schemas 0.5.1 is `additionalProperties: false`); doctor and any workflow-materialiser both read `browserSurface` from the applied record's `source` reference. See CONCERNS in the shipping PR: an additive schema field on `appliedBlueprintRecord` is a separate rcf-schemas release, deliberately outside this train. Trace: spec 2026-09-03, section 2; chain: `packages/rcf-lite/rcf/user-stories/us-1102.json` on REQ-011.
|
|
38
|
+
|
|
39
|
+
- **`rcf init` writes a Playwright MCP entry only when no scope-visible entry exists.** Detection is by command signature: any `mcpServers[<name>].args` string whose command tail matches `/^@playwright\/mcp(@|$)/` (spec 4.1). If the project-scope `.mcp.json` carries one, init leaves it alone and prints the key. Otherwise init shells out to `claude mcp list` (5-second timeout, text-output parser) and, if it finds a Playwright entry at any scope the harness reports, prints the scope and writes nothing. When init cannot prove the absence of a user-scope entry (no `claude` on PATH, non-zero exit, output unparseable) it writes a distinctly named `playwright-rcf` project-scope entry that shadows nothing by naming convention, and prints the `could not probe` notice explaining what it did and how to opt out. `rcf init --no-playwright-mcp` suppresses the write step entirely; the probe still runs so the print-out remains honest. Every probe is injectable via `deps.probeClaudeCodeMcp` for tests. Trace: spec 2026-09-03, section 4; chain: `packages/rcf-lite/rcf/user-stories/us-1104.json` on REQ-011.
|
|
40
|
+
|
|
41
|
+
- **`rcf doctor` checks Playwright and a browser on browser-facing projects.** `@playwright/mcp` and `playwright` are declared as optional peer dependencies (`peerDependenciesMeta.<pkg>.optional: true`) in `packages/rcf-lite/package.json` so npm and pnpm do not fail install when they are absent. Doctor adds four checks routed through `src/setup/playwright-checks.js`: `playwright-present` (`require.resolve('playwright', { paths: [projectRoot] })`), `browser-present` (system Chrome on PATH, then a Playwright-managed cache directory, then `npx --no-install @playwright/mcp browser-status --json` as a first-party fall-back), `playwright-mcp-reachable` (`npx --no-install @playwright/mcp --help`, 15-second diagnostic ceiling), and `playwright-mcp-redundant` (project-scope + user-scope shadowing, browser-facing only, no `--fix`). The three run only when at least one applied blueprint's source `blueprint.json` declares `browserSurface`; non-browser-facing projects print one skip line naming the three checks. Passing a Playwright check name to `--check` on an API-only project overrides the skip. All probes are injectable via `deps.*Impl` seams so the unit suite runs without any of these tools installed. Trace: spec 2026-09-03, section 3 + 4.5; chain: `packages/rcf-lite/rcf/user-stories/us-1103.json` on REQ-011.
|
|
42
|
+
|
|
43
|
+
- **Verify pins the Playwright MCP version.** `rcf verify run` no longer provisions `npx -y @playwright/mcp@latest`; the launcher composes the pin from an exported `PLAYWRIGHT_MCP_VERSION` constant in `packages/rcf-lite/src/verify/engine/launcher.js` and the DEFAULT_MCP_CONFIG is a `playwrightMcpConfig(PLAYWRIGHT_MCP_VERSION)` composition. Preflight prints `Playwright MCP: pinned to @playwright/mcp@<version>` on stderr; the effective pin (default or overridden) lands on the report as `run.runStats.playwrightMcpVersion` so a report re-render tells the operator which browser tooling this pass ran against. `--playwright-mcp-version <semver>` overrides the pin for one run (emergency use only), fires a loud stderr override notice, and refuses exit 2 with `--playwright-mcp-version expects a semver string, got '<value>'` on a non-semver value. Bump discipline: a pin change is a deliberate rcf-lite change, with its own commit, its own CHANGELOG line, and, where behaviour is affected, a re-run of the verify test set against the pinned tooling. Trace: `projects/rcf-lite-wsd/specs/rcf-lite-e2e-contract-spec-2026-09-03.md`, section 1; chain: `packages/rcf-lite/rcf/user-stories/us-1101.json` on REQ-011.
|
|
44
|
+
|
|
9
45
|
## [0.16.0] - 2026-09-03
|
|
10
46
|
|
|
11
47
|
External blueprint libraries complete. Phase 2c lands git and tarball fetchers with a checked-in on-disk cache so a fresh clone lists library blueprints without a re-fetch, and a refresh path that re-resolves annotated-tag or tarball digest and refuses on drift. Amendment A2 makes plain-path adds library-aware so an author's local edit loop stamps the same effective slug and identity a qualified add would. Amendment A3 adds a blueprint paragraph to the managed agent-instructions block so the agent conversationally offers blueprints and registered libraries and the operator chooses. A library-authoring standard doc plus a worked-example fixture binds the doc against the shipped tooling.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# application-api-rest blueprint (v2.0.0)
|
|
2
2
|
|
|
3
3
|
The second content blueprint on the rcf-build-lite blueprint mechanism (design brief v2, ratified; Phase 3 of the blueprint programme). Scope: a REST service, single deployable, versioned wire contract, no UI in scope. Composes with the application-spa blueprint by design, including two deliberate scope:global conflicts.
|
|
4
4
|
|
|
@@ -38,3 +38,7 @@ ADR-301 errorEnvelope, ADR-302 authModel, ADR-303 apiVersioning, ADR-304 logging
|
|
|
38
38
|
## Quality bar
|
|
39
39
|
|
|
40
40
|
OpenAPI 3.1 generated from source with three-axis drift validation in the build; three k8s probes with specified schemas, security-auth-magic-link and log-noise exclusions, and documented failure modes; four auth classes enforced in middleware with x-auth-class contract validation; RFC 7807 on every failure path including pre-routing ones; cursor pagination with write-stability; strict unknown-parameter rejection; idempotency-key replay semantics with declared TTL; per-class rate limits with honest Retry-After; structured JSON logs, RED metrics, and OpenTelemetry spans off one shared request context; forward-only migrations with named reverts and a live /v1/_meta report; secrets never logged, PII redacted by stated policy, TLS outside development, CORS deny-by-default. Every bar is carried by ACs in the doc set, not by this README.
|
|
41
|
+
|
|
42
|
+
## Breaking change in v2.0.0 (2026-09-04)
|
|
43
|
+
|
|
44
|
+
This blueprint no longer binds literal probe path strings. The three probe surfaces (liveness, readiness, startup) are served at the RESOLVED paths supplied by either the composed observability-probe-endpoints blueprint (Kubernetes profile default `/live`, `/ready`, and, when enabled, `/startup`; loadBalancer profile default `/health`) or by project configuration under `probeInterface.paths` in the essentials-alone case. REQ-006, US-2108 (all eight ACs), TAC-306, and US-2103 (versioning-exemption AC) were reshaped. Spec: `projects/rcf-lite-wsd/specs/rcf-lite-probe-path-alignment-spec-2026-09-04.md` section 5. Migration: project FBSes and TCs that bind literal `/healthz/live`, `/healthz/ready`, or `/healthz/startup` strings become one edit each to bind the resolved path set; `rcf audit coverage --strict` catches project-side TCs that still hold the literal strings after re-apply. See CHANGELOG.md.
|
package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-006.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"reqId": "application-api-rest-REQ-006",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
|
-
"title": "
|
|
5
|
-
"description": "The service exposes three probe endpoints.
|
|
4
|
+
"title": "Probe endpoints: liveness, readiness, and startup with specified schemas and exclusions (paths resolved by the composed observability-probe-endpoints blueprint or by project configuration)",
|
|
5
|
+
"description": "The service exposes three probe endpoints: liveness, readiness, and startup, with specified response schemas and exclusions. The liveness probe returns 200 whenever the process can serve any request and performs no dependency checks. The readiness probe returns 200 only when declared downstream dependencies (database, cache, queues) are reachable, and 503 with a body listing the failed checks otherwise. The startup probe returns 200 once initialisation (migrations, cache warm, config load) is complete and a non-200 with the pending steps before that. Each probe has a specified response schema, sits outside the auth middleware and rate limiter, is excluded from info-level metrics and log noise, and has a documented failure mode. The probe PATHS are supplied by the composed `observability-probe-endpoints` blueprint (Kubernetes profile default: `/live`, `/ready`, and, when enabled, `/startup`), or by project-level configuration under `probeInterface.paths` in the essentials-alone case; this blueprint does not bind literal paths. When probe-endpoints is composed the auth-middleware installer consumes the exempt path set that probe-endpoints emits and no other, so the auth-exempt entries exactly match the resolved probe path set.",
|
|
6
6
|
"category": "functional",
|
|
7
7
|
"domain": "operability",
|
|
8
8
|
"priority": "must",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"blueprint:application-api-rest",
|
|
12
12
|
"category:06-probe-endpoints"
|
|
13
13
|
],
|
|
14
|
-
"version": "
|
|
14
|
+
"version": "2.0.0",
|
|
15
15
|
"status": "approved",
|
|
16
16
|
"createdAt": "2026-08-19T10:00:00Z",
|
|
17
|
-
"updatedAt": "2026-
|
|
17
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
18
18
|
}
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
"tacId": "TAC-306-application-api-rest-operability",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"tadId": "TAD-001",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "approved",
|
|
7
|
-
"name": "Operability: probes, lifecycle, migrations, and the meta endpoint",
|
|
7
|
+
"name": "Operability: probes (at resolved paths), lifecycle, migrations, and the meta endpoint",
|
|
8
8
|
"purpose": "Owns what an orchestrator and an operator need from the outside: the three probe endpoints, the initialisation lifecycle they report on, the forward-only migration machinery, and the /v1/_meta version report.",
|
|
9
9
|
"responsibilities": [
|
|
10
|
-
"Serve
|
|
11
|
-
"Run the initialisation sequence (config load, migrations, cache warm) and expose its progress to the startup probe (AC-2108-4).",
|
|
10
|
+
"Serve the three probe surfaces (liveness, readiness, startup) at their resolved paths, with the specified schemas, exclusions, and documented failure modes; the path resolution is delegated to observability-probe-endpoints when composed (Kubernetes profile default /live, /ready, and, when enabled, /startup) or to project-level probeInterface.paths configuration when composed with observability-essentials alone (application-api-rest-REQ-006).",
|
|
11
|
+
"Run the initialisation sequence (config load, migrations, cache warm) and expose its progress to the resolved startup probe when the startup path is bound (AC-2108-4).",
|
|
12
12
|
"Register and execute declared readiness checks against downstream dependencies, reporting per-check results in the ready body (AC-2108-2, AC-2108-3).",
|
|
13
13
|
"Apply migrations strictly forward with named reverts and deterministic ordering (application-api-rest-REQ-014).",
|
|
14
|
-
"Serve /v1/_meta reporting the live schema version and application version, sourced from the migration record, under a declared auth class (application-api-rest-US-2118)."
|
|
14
|
+
"Serve /v1/_meta reporting the live schema version and application version, sourced from the migration record, under a declared auth class (application-api-rest-US-2118).",
|
|
15
|
+
"Consume the resolved probe path set (produced by observability-probe-endpoints via TAC-1501 getExemptPathSet or derived from project probeInterface.paths configuration) as the exact auth-exempt list for the probe surfaces; refuse any hand-authored auth-exempt entry that duplicates or diverges from the resolved set (AC-2108-5)."
|
|
15
16
|
],
|
|
16
17
|
"internalStructure": "A lifecycle coordinator owning initialisation state, a check registry the readiness probe iterates, and the migration runner; probe handlers are thin reads over this state, never performing work themselves.",
|
|
17
18
|
"interfaces": [
|
|
@@ -23,7 +24,7 @@
|
|
|
23
24
|
{
|
|
24
25
|
"name": "probe endpoints",
|
|
25
26
|
"kind": "http",
|
|
26
|
-
"description": "The three
|
|
27
|
+
"description": "The three probe surfaces (liveness, readiness, startup) at their resolved paths, and /v1/_meta, with their specified response schemas. The path resolution is delegated to observability-probe-endpoints or to project-level probeInterface.paths configuration; this TAC binds NO literal path strings for the probe surfaces from v2.0.0."
|
|
27
28
|
}
|
|
28
29
|
],
|
|
29
30
|
"dependencies": [
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"description": "Probe outcomes land in the dedicated probe metric."
|
|
41
42
|
}
|
|
42
43
|
],
|
|
43
|
-
"tradeoffs": "Probe handlers reading pre-computed state (rather than checking dependencies inline) keeps probes cheap and non-amplifying under orchestrator polling, at the cost of a bounded staleness window in readiness reporting; the check interval is the tuning knob and is declared configuration.",
|
|
44
|
+
"tradeoffs": "Probe handlers reading pre-computed state (rather than checking dependencies inline) keeps probes cheap and non-amplifying under orchestrator polling, at the cost of a bounded staleness window in readiness reporting; the check interval is the tuning knob and is declared configuration. Path resolution is delegated so a project can compose the api-rest blueprint with either observability-probe-endpoints (elicit-and-adapt path set) or observability-essentials alone (project-supplied path set) without editing this TAC; the v2.0.0 breaking change is exactly this delegation.",
|
|
44
45
|
"createdAt": "2026-08-19T10:00:00Z",
|
|
45
|
-
"updatedAt": "2026-
|
|
46
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
46
47
|
}
|
package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2103.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"usId": "application-api-rest-US-2103",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"reqId": "application-api-rest-REQ-003",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "approved",
|
|
7
7
|
"title": "Path-versioned contract with announced deprecation and a stated drop policy",
|
|
8
8
|
"asA": "API consumer maintaining a long-lived integration",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"description": "Every business endpoint lives under a major-version path prefix (/v1/...); only the probe endpoints and the documentation endpoints sit outside it.",
|
|
15
15
|
"given": "the generated OpenAPI path inventory",
|
|
16
16
|
"when": "paths are checked for the version prefix",
|
|
17
|
-
"then": "every path is version-prefixed except
|
|
17
|
+
"then": "every path is version-prefixed except the resolved probe paths, /openapi.*, and /docs",
|
|
18
18
|
"testable": true,
|
|
19
19
|
"scope": "runtime"
|
|
20
20
|
},
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"TAC-304-application-api-rest-resource-layer"
|
|
60
60
|
],
|
|
61
61
|
"createdAt": "2026-08-19T10:00:00Z",
|
|
62
|
-
"updatedAt": "2026-
|
|
62
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
63
63
|
}
|
package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2108.json
CHANGED
|
@@ -2,62 +2,62 @@
|
|
|
2
2
|
"usId": "application-api-rest-US-2108",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"reqId": "application-api-rest-REQ-006",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "approved",
|
|
7
|
-
"title": "Liveness, readiness, and startup probes that tell the orchestrator the truth",
|
|
7
|
+
"title": "Liveness, readiness, and startup probes that tell the orchestrator the truth, at the resolved paths",
|
|
8
8
|
"asA": "platform operator running the service under Kubernetes",
|
|
9
|
-
"iWant": "three probe endpoints that each answer their one question honestly and cheaply",
|
|
9
|
+
"iWant": "three probe endpoints (at their resolved paths) that each answer their one question honestly and cheaply",
|
|
10
10
|
"soThat": "the orchestrator restarts, routes, and rolls out instances on real signals",
|
|
11
11
|
"acceptanceCriteria": [
|
|
12
12
|
{
|
|
13
13
|
"id": "AC-2108-1",
|
|
14
|
-
"description": "GET
|
|
15
|
-
"given": "a running instance with a deliberately unreachable database",
|
|
16
|
-
"when": "
|
|
14
|
+
"description": "GET on the resolved liveness path returns 200 with the specified response schema whenever the process can serve any request, and performs no dependency checks whatsoever.",
|
|
15
|
+
"given": "a running instance with a deliberately unreachable database and the liveness path resolved either by observability-probe-endpoints (Kubernetes profile default /live) or by project configuration",
|
|
16
|
+
"when": "the resolved liveness path is called",
|
|
17
17
|
"then": "it returns 200 against the specified schema, unaffected by the dependency outage",
|
|
18
18
|
"testable": true,
|
|
19
19
|
"scope": "runtime"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"id": "AC-2108-2",
|
|
23
|
-
"description": "GET
|
|
24
|
-
"given": "an instance with all declared dependencies reachable",
|
|
25
|
-
"when": "
|
|
23
|
+
"description": "GET on the resolved readiness path returns 200 only when every declared downstream dependency check (database, cache, queues) passes.",
|
|
24
|
+
"given": "an instance with all declared dependencies reachable and the readiness path resolved (Kubernetes profile default /ready) or supplied by project configuration",
|
|
25
|
+
"when": "the resolved readiness path is called",
|
|
26
26
|
"then": "it returns 200 with the specified schema listing each check as passing",
|
|
27
27
|
"testable": true,
|
|
28
28
|
"scope": "runtime"
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"id": "AC-2108-3",
|
|
32
|
-
"description": "GET
|
|
33
|
-
"given": "an instance with one declared dependency down",
|
|
34
|
-
"when": "
|
|
32
|
+
"description": "GET on the resolved readiness path returns 503 with a body enumerating the failed checks by name when any declared dependency is unreachable.",
|
|
33
|
+
"given": "an instance with one declared dependency down and the readiness path resolved as above",
|
|
34
|
+
"when": "the resolved readiness path is called",
|
|
35
35
|
"then": "it returns 503 and the body names the failing check while still listing the passing ones",
|
|
36
36
|
"testable": true,
|
|
37
37
|
"scope": "runtime"
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"id": "AC-2108-4",
|
|
41
|
-
"description": "GET
|
|
42
|
-
"given": "an instance mid-initialisation and the same instance after initialisation",
|
|
43
|
-
"when": "
|
|
41
|
+
"description": "GET on the resolved startup path returns 200 only after initialisation (migrations applied, cache warmed, config loaded) completes, and a non-200 with the pending steps before that. The startup path is available when the composed observability-probe-endpoints blueprint enables it via `probeInterface.options.kubernetes.startup.enabled: true` or the project supplies `probeInterface.paths.startup` in configuration.",
|
|
42
|
+
"given": "an instance mid-initialisation and the same instance after initialisation, with the startup path resolved (Kubernetes profile default /startup when enabled) or supplied by project configuration",
|
|
43
|
+
"when": "the resolved startup path is called in each state",
|
|
44
44
|
"then": "the mid-initialisation call is non-200 naming pending steps; the post-initialisation call is 200",
|
|
45
45
|
"testable": true,
|
|
46
46
|
"scope": "runtime"
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
"id": "AC-2108-5",
|
|
50
|
-
"description": "All three probes sit outside the auth middleware and outside rate limiting:
|
|
51
|
-
"given": "a running instance",
|
|
52
|
-
"when": "each probe is called with no credentials at sustained frequency",
|
|
53
|
-
"then": "every call is answered on probe semantics alone, never with an auth or rate-limit status",
|
|
50
|
+
"description": "All three probes sit outside the auth middleware and outside rate limiting: the auth-middleware installer consumes exactly the resolved probe path set (the same list observability-probe-endpoints emits via TAC-1501 getExemptPathSet, or the exact set derived from `probeInterface.paths` in the essentials-alone case), so each probe succeeds with no credentials and is never 401, 403, or 429; adjacent routes never fall under the same exemption.",
|
|
51
|
+
"given": "a running instance with the resolved probe path set exposed to the auth-middleware installer",
|
|
52
|
+
"when": "each probe is called with no credentials at sustained frequency AND an adjacent user-traffic route is also called unauthenticated",
|
|
53
|
+
"then": "every probe call is answered on probe semantics alone, never with an auth or rate-limit status; the adjacent route returns the auth middleware unauthenticated response",
|
|
54
54
|
"testable": true,
|
|
55
55
|
"scope": "runtime"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"id": "AC-2108-6",
|
|
59
|
-
"description": "Probe requests do not appear in info-level request logs and are excluded from RED endpoint metrics; probe outcomes are recorded under their own dedicated metric.",
|
|
60
|
-
"given": "a period of steady probe traffic",
|
|
59
|
+
"description": "Probe requests (at their resolved paths) do not appear in info-level request logs and are excluded from RED endpoint metrics; probe outcomes are recorded under their own dedicated metric.",
|
|
60
|
+
"given": "a period of steady probe traffic on the resolved probe paths",
|
|
61
61
|
"when": "info-level logs and endpoint metrics are inspected",
|
|
62
62
|
"then": "probe requests appear in neither, and the dedicated probe-outcome metric carries their results",
|
|
63
63
|
"testable": true,
|
|
@@ -65,18 +65,18 @@
|
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
"id": "AC-2108-7",
|
|
68
|
-
"description": "
|
|
69
|
-
"given": "the generated OpenAPI document",
|
|
68
|
+
"description": "The generated OpenAPI document names the three probe surfaces (liveness, readiness, startup) and their resolved paths, plus each probes success and failure schemas and its documented failure mode; the resolved paths are computed at documentation-generation time from the composed observability-probe-endpoints blueprint or from project configuration.",
|
|
69
|
+
"given": "the generated OpenAPI document produced for a project that has resolved its probe paths",
|
|
70
70
|
"when": "the three probe entries are read",
|
|
71
|
-
"then": "each declares its success and failure schemas and its documented failure mode",
|
|
71
|
+
"then": "each declares its success and failure schemas and its documented failure mode; every entry path is the resolved path (no legacy literal probe-path prefix appears in the generated document)",
|
|
72
72
|
"testable": true,
|
|
73
73
|
"scope": "runtime"
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
"id": "AC-2108-8",
|
|
77
|
-
"description": "Readiness reflects recovery: when a failed dependency becomes reachable again,
|
|
77
|
+
"description": "Readiness reflects recovery: when a failed dependency becomes reachable again, GET on the resolved readiness path returns to 200 without a process restart.",
|
|
78
78
|
"given": "an instance whose dependency outage has been restored",
|
|
79
|
-
"when": "
|
|
79
|
+
"when": "the resolved readiness path is called after restoration",
|
|
80
80
|
"then": "it returns 200 without the process having restarted",
|
|
81
81
|
"testable": true,
|
|
82
82
|
"scope": "runtime"
|
|
@@ -86,5 +86,5 @@
|
|
|
86
86
|
"TAC-306-application-api-rest-operability"
|
|
87
87
|
],
|
|
88
88
|
"createdAt": "2026-08-19T10:00:00Z",
|
|
89
|
-
"updatedAt": "2026-
|
|
89
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
90
90
|
}
|
|
@@ -28,14 +28,14 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
28
28
|
| hello-panel (walkthrough exemplar) | 4101-4899 | 4xx | doc-reserved; teaching exemplar in `packages/rcf-lite/docs/blueprint-authoring-walkthrough.md`, not shipped as a blueprint directory | `operatorPanel` |
|
|
29
29
|
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
30
30
|
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
31
|
-
| observability-essentials | 7101-7899 | 8xx | shipped
|
|
31
|
+
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
32
32
|
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.0 | `secretsSource` |
|
|
33
33
|
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
34
34
|
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
35
35
|
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
36
36
|
| deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.0.0 | `deploymentTarget` |
|
|
37
37
|
| persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
38
|
-
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.
|
|
38
|
+
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
|
|
39
39
|
|
|
40
40
|
Suffix-family ids (ADR, TAC): SPA numbers in the 2xx range, this package takes 3xx (ADR-301 to ADR-308, TAC-301 to TAC-306); the next blueprint should take 4xx.
|
|
41
41
|
|
|
@@ -26,7 +26,7 @@ Any project whose primary surface is an HTTP API meant to be consumed by clients
|
|
|
26
26
|
|
|
27
27
|
## What a good outcome looks like
|
|
28
28
|
|
|
29
|
-
Attack the finished service from the outside and try to catch it lying: fetch /docs and call an endpoint straight from the spec, send garbage JSON, reuse an idempotency key with a different body, hammer a public endpoint past its limit, kill the database and watch
|
|
29
|
+
Attack the finished service from the outside and try to catch it lying: fetch /docs and call an endpoint straight from the spec, send garbage JSON, reuse an idempotency key with a different body, hammer a public endpoint past its limit, kill the database and watch the resolved readiness path tell the truth while the resolved liveness path stays up, grep the logs for the bearer token you just used. A build that honours this doc set answers every one of those correctly. That is the measure: what an integrating client and an on-call engineer get out of the box.
|
|
30
30
|
|
|
31
31
|
## Your decisions that remain open
|
|
32
32
|
|
|
@@ -39,3 +39,7 @@ Attack the finished service from the outside and try to catch it lying: fetch /d
|
|
|
39
39
|
## Cost honesty
|
|
40
40
|
|
|
41
41
|
This doc set makes an API slower to declare done, on purpose: 117 criteria is the price of "no endpoint ships undocumented, unmeasured, or unguarded". If you are prototyping a throwaway integration, that price is wrong; skip the blueprint rather than opting out of half of it. If other people's code will call this service, the price is the product.
|
|
42
|
+
|
|
43
|
+
## Composing with observability-probe-endpoints and observability-essentials (v2.0.0)
|
|
44
|
+
|
|
45
|
+
From v2.0.0 this blueprint no longer binds literal probe path strings. The three probe surfaces (liveness, readiness, startup) are served at the RESOLVED paths supplied by either the composed observability-probe-endpoints blueprint (Kubernetes profile default `/live`, `/ready`, and, when enabled, `/startup`; `loadBalancer` profile default `/health`) or by project configuration under `probeInterface.paths` in the essentials-alone case. The auth-middleware installer consumes exactly the exempt path set that observability-probe-endpoints emits via TAC-1501 `getExemptPathSet` (or the exact set derived from `probeInterface.paths` in the essentials-alone case); adjacent routes never fall under the same exemption. The generated OpenAPI document names each probe surface and its resolved path at documentation-generation time. The three-way composition invariants live in `packages/rcf-lite/test/blueprint/probe-path-alignment.test.js`.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# e2e test-case template (application-spa blueprint)
|
|
2
|
+
|
|
3
|
+
A paste-in shape for a `testLevel: e2e` test suite plus one test case bound
|
|
4
|
+
to a browser-facing acceptance criterion contributed by this blueprint.
|
|
5
|
+
Copy the fenced blocks into your project chain, fill in the placeholders,
|
|
6
|
+
and author the pointed-to test file under `tests/e2e/`.
|
|
7
|
+
|
|
8
|
+
This template is the driver-seam contract between blueprint-contributed
|
|
9
|
+
browser-facing ACs and the project's e2e suite. It uses the same
|
|
10
|
+
`rcf verify browser` driver seam the browser-verify pack uses, so the
|
|
11
|
+
same Playwright installation the invariants drive against also drives
|
|
12
|
+
the e2e case (one browser, two responsibilities).
|
|
13
|
+
|
|
14
|
+
## What this covers, and what it does not
|
|
15
|
+
|
|
16
|
+
- **Covers:** the AC end to end at a user-observable browser surface. One
|
|
17
|
+
test case per AC. Sits in the project chain as coverage that
|
|
18
|
+
`rcf audit coverage --strict` reads, and runs in the pull-request-checks
|
|
19
|
+
`e2e` CI job the delivery-ci-workflows blueprint materialises.
|
|
20
|
+
- **Does not cover:** every rendering variation the browser-verify
|
|
21
|
+
invariants already cover. If the concern is "is the CSP stamped
|
|
22
|
+
correctly?" or "does the layout reflow at 360px?", write it as an
|
|
23
|
+
invariant on the browser-verify TAC, not as a project e2e test.
|
|
24
|
+
|
|
25
|
+
## Test-suite shape
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"tsId": "TS-N01-application-spa-e2e",
|
|
30
|
+
"prdId": "PRD-001",
|
|
31
|
+
"reqId": "application-spa-REQ-011",
|
|
32
|
+
"version": "1.0.0",
|
|
33
|
+
"status": "draft",
|
|
34
|
+
"title": "Application e2e",
|
|
35
|
+
"description": "End-to-end test cases against the shipped application, driven by a real browser through the browser-verify driver seam. One test case per browser-facing AC.",
|
|
36
|
+
"testLevel": "e2e",
|
|
37
|
+
"testCases": [
|
|
38
|
+
{
|
|
39
|
+
"id": "TC-N01-nav-renders-home-signed-in",
|
|
40
|
+
"description": "Primary-nav icon renders at the expected size on the home route in a real browser across the SPA blueprint's declared themes",
|
|
41
|
+
"acCoverage": ["application-spa-AC-1134-1"],
|
|
42
|
+
"testPointer": "tests/e2e/nav.spec.js::navRendersOnHomeSignedIn",
|
|
43
|
+
"scope": "deployed"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"createdAt": "<ISO-8601>",
|
|
47
|
+
"updatedAt": "<ISO-8601>"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Test file shape (Playwright, project-owned)
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
// tests/e2e/nav.spec.js
|
|
55
|
+
// Driven through the same Playwright installation the browser-verify TAC
|
|
56
|
+
// uses. `rcf verify browser <fbs-id>` covers the invariant sweep on this
|
|
57
|
+
// page; this file covers the AC end to end.
|
|
58
|
+
|
|
59
|
+
import { test, expect } from '@playwright/test';
|
|
60
|
+
|
|
61
|
+
test('nav renders on home signed in', async ({ page }) => {
|
|
62
|
+
await page.goto('/');
|
|
63
|
+
const icon = page.locator('[data-nav-icon="primary"]');
|
|
64
|
+
await expect(icon).toBeVisible();
|
|
65
|
+
const box = await icon.boundingBox();
|
|
66
|
+
// Read from the project's iconAlias size token for the primary-nav slot.
|
|
67
|
+
expect(box.width).toBe(24);
|
|
68
|
+
expect(box.height).toBe(24);
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## The driver seam, in one sentence
|
|
73
|
+
|
|
74
|
+
The e2e test drives the app through the same Playwright installation that
|
|
75
|
+
the browser-verify pack drives, so the invariant sweep and the coverage
|
|
76
|
+
anchor run against the same shipped runtime and the same headless browser.
|
|
77
|
+
When `@playwright/mcp` is pinned in `rcf verify run`, the same pin is what
|
|
78
|
+
CI installs to run this file.
|
|
79
|
+
|
|
80
|
+
## Non-goal
|
|
81
|
+
|
|
82
|
+
The e2e case is the coverage anchor for one AC. It is not the place to
|
|
83
|
+
enumerate every rendering variation the browser-verify invariants already
|
|
84
|
+
cover, and it is not a substitute for a `rcf verify run` pass at the ship
|
|
85
|
+
gate. Both run in CI; neither replaces the other.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "application-spa",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"category": "application",
|
|
5
5
|
"contributions": [
|
|
6
6
|
{
|
|
@@ -273,6 +273,16 @@
|
|
|
273
273
|
"kind": "us",
|
|
274
274
|
"path": "user-stories/application-spa-us-1133.json"
|
|
275
275
|
},
|
|
276
|
+
{
|
|
277
|
+
"id": "application-spa-US-1134",
|
|
278
|
+
"kind": "us",
|
|
279
|
+
"path": "user-stories/application-spa-us-1134.json"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"id": "application-spa-US-1135",
|
|
283
|
+
"kind": "us",
|
|
284
|
+
"path": "user-stories/application-spa-us-1135.json"
|
|
285
|
+
},
|
|
276
286
|
{
|
|
277
287
|
"id": "TAC-201-application-spa-app-shell",
|
|
278
288
|
"kind": "tac",
|
|
@@ -383,5 +393,17 @@
|
|
|
383
393
|
"kind": "adr",
|
|
384
394
|
"path": "adrs/adr-209-application-spa-telemetry-naming.json"
|
|
385
395
|
}
|
|
386
|
-
]
|
|
396
|
+
],
|
|
397
|
+
"browserSurface": {
|
|
398
|
+
"declared": true,
|
|
399
|
+
"routes": [
|
|
400
|
+
"/",
|
|
401
|
+
"/sign-in",
|
|
402
|
+
"/dashboard"
|
|
403
|
+
],
|
|
404
|
+
"themes": [
|
|
405
|
+
"light",
|
|
406
|
+
"dark"
|
|
407
|
+
]
|
|
408
|
+
}
|
|
387
409
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "application-spa-US-1134",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "application-spa-REQ-011",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Primary-nav icon renders at the expected size across declared themes on the home route in a browser (e2e)",
|
|
8
|
+
"asA": "operator relying on the iconography discipline the application-spa blueprint declares",
|
|
9
|
+
"iWant": "an end-to-end test that a real browser navigating the home route of the shipped application observes the primary-navigation icon rendered at the expected size across every theme declared on the blueprint's browserSurface",
|
|
10
|
+
"soThat": "the iconography discipline (application-spa-REQ-011: one icon set, consistent construction, semantic aliases) is verified end-to-end at a user-observable surface rather than assumed from component-library conformance alone",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-1134-1",
|
|
14
|
+
"description": "The icon at the primary navigation slot renders at the expected size across all declared themes when the app loads its home route in a browser. Verification navigates a real browser through the same production entry-point construction the app ships (no header-stripping harness, no app.inject substitute), reads the rendered icon's computed bounding box, and asserts it equals the blueprint's iconAlias size token for that slot. A rendered box that resolves to the browser default (or to zero) refuses ship with a per-theme diagnostic naming the observed and expected sizes.",
|
|
15
|
+
"given": "the application booted through its production entry point with the primary navigation registered on the home route",
|
|
16
|
+
"when": "a real browser loads / in each theme declared on the blueprint's browserSurface and getBoundingClientRect() is read for the primary-nav icon",
|
|
17
|
+
"then": "the icon's rendered box equals the iconAlias size token for the primary-nav slot in every theme; a mismatch, a zero-size box, or a missing icon refuses ship with a per-theme diagnostic",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "deployed"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"createdAt": "2026-09-03T17:00:00Z",
|
|
23
|
+
"updatedAt": "2026-09-03T17:00:00Z"
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "application-spa-US-1135",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "application-spa-REQ-009",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Unauthenticated visit to a protected route lands on the sign-in page in a browser (e2e)",
|
|
8
|
+
"asA": "operator relying on the auth-surface discipline the application-spa blueprint declares",
|
|
9
|
+
"iWant": "an end-to-end test that a real browser making an unauthenticated request against a protected route in the shipped application lands on the sign-in page rather than the protected surface",
|
|
10
|
+
"soThat": "the arrival-and-auth discipline (application-spa-REQ-009: landing, sign-in, sign-out, expiry, recovery, onboarding, deep-link redirects) is verified end-to-end at a user-observable surface. Verify's auth-smoke pass is adversarial and complementary; this e2e case is the coverage anchor.",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-1135-1",
|
|
14
|
+
"description": "An unauthenticated visit to a protected route lands on the sign-in page in a browser. Verification navigates a real browser (fresh context, no persisted session, no injected cookies) to a protected route the blueprint declares under browserSurface.routes, and asserts the browser's final URL path is the sign-in route rather than the protected route. The check drives the same server construction the production entry point boots (no header-stripping harness, no app.inject substitute). A landing path equal to the requested route, or to any other page, refuses ship with a diagnostic naming the requested, landed and expected sign-in paths.",
|
|
15
|
+
"given": "the application booted through its production entry point with a protected route and a sign-in route both registered",
|
|
16
|
+
"when": "a real browser with no session state navigates to the protected route",
|
|
17
|
+
"then": "the browser's final URL path equals the sign-in route path; any other landing (protected route rendered without auth, arbitrary other page, error page) refuses ship with a diagnostic naming requested, landed and expected paths",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "deployed"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"createdAt": "2026-09-03T17:00:00Z",
|
|
23
|
+
"updatedAt": "2026-09-03T17:00:00Z"
|
|
24
|
+
}
|
|
@@ -33,14 +33,14 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
33
33
|
| hello-panel (walkthrough exemplar) | 4101-4899 | 4xx | doc-reserved; teaching exemplar in `packages/rcf-lite/docs/blueprint-authoring-walkthrough.md`, not shipped as a blueprint directory | `operatorPanel` |
|
|
34
34
|
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
35
35
|
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
36
|
-
| observability-essentials | 7101-7899 | 8xx | shipped
|
|
36
|
+
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
37
37
|
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.0 | `secretsSource` |
|
|
38
38
|
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
39
39
|
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
40
40
|
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
41
41
|
| deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.0.0 | `deploymentTarget` |
|
|
42
42
|
| persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
43
|
-
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.
|
|
43
|
+
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
|
|
44
44
|
|
|
45
45
|
SPA v1.1.0 stays on the LOW end of its band: v1.0.0 occupied US-1101 through US-1128; v1.1.0 adds US-1129 and US-1130, leaving headroom above 1130 for future minor bumps and for project-side stories that mechanically derive to the 11xx numeric range.
|
|
46
46
|
|
|
@@ -72,3 +72,72 @@ jobs:
|
|
|
72
72
|
path: .rcf/reports/ci/
|
|
73
73
|
if-no-files-found: warn
|
|
74
74
|
retention-days: 30
|
|
75
|
+
|
|
76
|
+
# e2e job (delivery-ci-workflows v2.2.0, application-spa v1.4.0):
|
|
77
|
+
# documentation contract per spec 2026-09-03 amendment A2. rcf-lite ships
|
|
78
|
+
# no workflow-materialiser at this train, so this block is copy-paste
|
|
79
|
+
# documentation for browser-facing projects, not runtime output. A
|
|
80
|
+
# non-browser project deletes this whole `e2e:` block (from the comment
|
|
81
|
+
# above down to the last step of the job) before committing; a browser
|
|
82
|
+
# project keeps it. The runtime iff wiring, which will add or omit this
|
|
83
|
+
# job based on `manifest.blueprints[].source.browserSurface.declared` on
|
|
84
|
+
# any applied blueprint AND
|
|
85
|
+
# `.rcf/config/delivery-ci-workflows.json:checkSet.e2e` not being
|
|
86
|
+
# explicitly false, lands in a follow-up train with its own TS entry.
|
|
87
|
+
#
|
|
88
|
+
# The job runs the project's testLevel: e2e cases against a local preview
|
|
89
|
+
# (or a --parity-env runtime) driven through the same Playwright
|
|
90
|
+
# installation `rcf verify browser` uses, uploads screenshots and HTML
|
|
91
|
+
# captures as workflow artefacts, and writes .rcf/reports/ci/e2e.json with
|
|
92
|
+
# `checkKind: "e2e"` so the aggregate pipeline report renders the e2e row
|
|
93
|
+
# separately from unit and integration.
|
|
94
|
+
e2e:
|
|
95
|
+
if: ${{ true }}
|
|
96
|
+
runs-on: ubuntu-latest
|
|
97
|
+
permissions:
|
|
98
|
+
contents: read
|
|
99
|
+
steps:
|
|
100
|
+
- name: checkout
|
|
101
|
+
uses: actions/checkout@v4
|
|
102
|
+
|
|
103
|
+
# @@RCF-SUB-PKG-MGR-SETUP-BEGIN@@
|
|
104
|
+
- name: setup pnpm
|
|
105
|
+
uses: pnpm/action-setup@v4
|
|
106
|
+
with:
|
|
107
|
+
version: 9
|
|
108
|
+
|
|
109
|
+
- name: setup node
|
|
110
|
+
uses: actions/setup-node@v4
|
|
111
|
+
with:
|
|
112
|
+
node-version: 24
|
|
113
|
+
cache: pnpm
|
|
114
|
+
# @@RCF-SUB-PKG-MGR-SETUP-END@@
|
|
115
|
+
|
|
116
|
+
# @@RCF-SUB-PKG-MGR-INSTALL-BEGIN@@
|
|
117
|
+
- name: install dependencies
|
|
118
|
+
run: pnpm install --frozen-lockfile
|
|
119
|
+
# @@RCF-SUB-PKG-MGR-INSTALL-END@@
|
|
120
|
+
|
|
121
|
+
# rcf-lite pins @playwright/mcp so the same browser tooling drives the
|
|
122
|
+
# e2e suite and `rcf verify browser`. Install the browser locally.
|
|
123
|
+
- name: install playwright browser
|
|
124
|
+
run: pnpm exec playwright install chromium --with-deps
|
|
125
|
+
|
|
126
|
+
# The project-owned e2e runner. It spawns whichever runner the project
|
|
127
|
+
# realises (Playwright test, Node --test with the browser-verify seam,
|
|
128
|
+
# Cypress, etc.), writes .rcf/reports/ci/e2e.json with checkKind:
|
|
129
|
+
# "e2e", and exits non-zero on any failing case.
|
|
130
|
+
- name: run e2e suite
|
|
131
|
+
run: node scripts/rcf-ci-e2e.js
|
|
132
|
+
|
|
133
|
+
- name: upload e2e browser artefacts
|
|
134
|
+
if: always()
|
|
135
|
+
uses: actions/upload-artifact@v4
|
|
136
|
+
with:
|
|
137
|
+
name: pull-request-checks-e2e-artefacts
|
|
138
|
+
path: |
|
|
139
|
+
.rcf/reports/ci/e2e.json
|
|
140
|
+
playwright-report/
|
|
141
|
+
test-results/
|
|
142
|
+
if-no-files-found: warn
|
|
143
|
+
retention-days: 30
|