rcf-lite 0.15.0 → 0.17.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 +27 -0
- 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/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/fixtures/canary-manifest.json +101 -1
- package/guidance/harness-template.md +9 -0
- package/guidance/managed/agent-instructions-block.hash +1 -1
- package/guidance/managed/agent-instructions-block.md +9 -0
- 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/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/prd.json +3 -2
- package/rcf/requirements/req-011.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/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/releases/releases.yaml +21 -1
- package/src/blueprint/index.js +22 -0
- package/src/blueprint/library-cache.js +143 -0
- package/src/blueprint/library-fetcher-git.js +347 -0
- package/src/blueprint/library-fetcher-tarball.js +379 -0
- package/src/blueprint/shelf-resolver.js +100 -7
- package/src/blueprint/supersede.js +2 -2
- package/src/cli/blueprint-library.js +397 -80
- package/src/cli/blueprint.js +1 -0
- package/src/cli/doctor.js +182 -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
|
@@ -4,6 +4,33 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Pre-1.0, breaking changes are signalled by a minor version bump.
|
|
6
6
|
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.17.0] - 2026-09-04
|
|
10
|
+
|
|
11
|
+
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.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`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.
|
|
16
|
+
|
|
17
|
+
- **`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.
|
|
18
|
+
|
|
19
|
+
- **`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.
|
|
20
|
+
|
|
21
|
+
- **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.
|
|
22
|
+
|
|
23
|
+
## [0.16.0] - 2026-09-03
|
|
24
|
+
|
|
25
|
+
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.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- **External blueprint libraries phase 2c: git and tarball fetchers + on-disk cache.** `rcf define blueprint library add` now accepts `git+<url>#<annotated-tag-or-sha>` and tarball URLs (with `--sha256 <hex>` for the pin). Fetched content lands under `rcf/.blueprint-libraries/<libraryPrefix>/<libraryRef>/`, checked into git as ordinary tree content so a fresh clone can `rcf define blueprint list` without a re-fetch (spec section 4.4). Floating branches (`main`, `master`, `HEAD`, `latest`, `develop`, `trunk`) refuse categorically; lightweight tags refuse with a diagnostic pointing at annotation as the fix; a tarball digest mismatch refuses the fetch and writes nothing. `rcf define blueprint library refresh <prefix>` re-resolves the tag's peeled commit (git) or re-downloads and re-verifies the digest (tarball) and refuses on drift per spec sections 6.4 / 9.12. `rcf define blueprint library remove <prefix>` now drops the on-disk cache for network sources. Zero new runtime dependencies: the git side shells out to the ambient `git` CLI; the tarball side uses built-in `fetch()`, `zlib`, and a bundled minimal POSIX-ustar parser. Auth remains out of scope for v1 (spec section 9.4): ambient git access is the model, no-access is definitive.
|
|
30
|
+
- **Amendment A2: library-aware local path (2026-09-03).** `rcf define blueprint add <path>` now walks up from the target directory looking for `library.json`; on a hit the resolver requires the target to sit at `<library-root>/blueprints/<slug>` and stamps the same effective slug and identity a qualified `<prefix>:<slug>` add would after registration. Library-qualified addressing and plain-path addressing now produce identical slugs and stamped ids. A path with no `library.json` in any ancestor keeps the phase-1 route unchanged, byte-for-byte. The trade-off (spec: an unregistered local library bypasses review-on-add) is accepted because the alternative kills the "author now, test now" loop; the `local` provenance warning on apply is the mitigation.
|
|
31
|
+
- **Amendment A3: blueprint paragraph in the managed agent-instructions block (2026-09-03).** New paragraph inside the "How to talk to your operator" section teaches the plain-language shape: agent enumerates blueprints and registered libraries and offers one that fits; the operator chooses, the agent never picks; qualified names and command lines belong in files and `rcf` output, not in the conversation. Hash regenerated via `scripts/gen-managed-artefacts.mjs`; harness template mirrored automatically.
|
|
32
|
+
- **Library authoring standard doc.** `packages/rcf-lite/docs/library-authoring.md` documents the library shape, `library.json` field contract, prefix and band rules, the local-path authoring loop (A2), registration, refresh / drift, and interaction with core. Ships with a minimum-viable worked-example library at `test/fixtures/library-authoring-example/` (prefix `wla`, one blueprint with one REQ and one ADR) that doubles as the fixture body for `test/blueprint/library-authoring-example.test.js`; the fixture binds the doc against the shipped tooling so a drift in either trips the suite.
|
|
33
|
+
|
|
7
34
|
## [0.15.0] - 2026-08-31
|
|
8
35
|
|
|
9
36
|
Same-evening fix wave on top of 0.14.0. Four PRs closing off the WSD-handover surface: durable library-ownership stamping on applied records (paired with `@stravica-ai/rcf-schemas` 0.5.1), `blueprint supersede --incoming` accepting the same source forms as `add`, the review-on-add card gaining its section 8.1 global-topics and prefix-check lines, and the `delivery-ci-workflows` v2.1 additive shape resolving the four P1 findings from the second dogfood run.
|
|
@@ -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
|
+
}
|
|
@@ -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
|
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
The blueprint ships one illustrative provider example (GitHub Actions, four workflow files under `github-actions/`). Every mainstream provider hosts the same workflow set by translating four points per workflow and keeping the Node entry-point invocations unchanged. These notes are read alongside `guide/delivery-ci-workflows.md`, not instead of it.
|
|
4
4
|
|
|
5
|
+
## The e2e job (v2.2.0)
|
|
6
|
+
|
|
7
|
+
When a project applies at least one blueprint declaring `.browserSurface.declared: true` on its source `blueprint.json` (for example `application-spa` v1.4.0), the workflow-materialiser adds an `e2e` job to `pull-request-checks`. The GitHub Actions shape ships in `github-actions/pull-request-checks.yml`. Every provider hosts the same job by translating four points:
|
|
8
|
+
|
|
9
|
+
1. **Trigger.** Same trigger as the check-set job on the same workflow; the e2e job is a peer, not a separate workflow.
|
|
10
|
+
2. **Browser tooling install.** After Node + package-manager setup, install a Playwright browser: `npx playwright install chromium --with-deps` (or the provider's equivalent). rcf-lite pins `@playwright/mcp` for `rcf verify`; the same browser installation drives the project's e2e suite.
|
|
11
|
+
3. **Runner invocation.** `node scripts/rcf-ci-e2e.js` (the project-owned e2e runner; writes `.rcf/reports/ci/e2e.json` with `checkKind: "e2e"`).
|
|
12
|
+
4. **Browser-artefact upload.** Upload screenshots and HTML captures alongside the per-gate report so a failing run has visible evidence.
|
|
13
|
+
|
|
14
|
+
The four provider translations follow the same substitution shape as the check-set job:
|
|
15
|
+
|
|
16
|
+
- **GitLab CI.** Add an `e2e` job in `.gitlab-ci.yml`; `image: mcr.microsoft.com/playwright:v1.50.0-noble` or install chromium via `apt-get` then `npx playwright install`; invoke `node scripts/rcf-ci-e2e.js`; upload with `artifacts: { when: always, paths: [.rcf/reports/ci/e2e.json, playwright-report/, test-results/] }`.
|
|
17
|
+
- **CircleCI.** Add an `e2e` job in `.circleci/config.yml`; `- browser-tools/install-browser-tools` orb + `npx playwright install chromium`; invoke as above; `store_artifacts: { path: playwright-report }` plus `store_artifacts: { path: .rcf/reports/ci/e2e.json }`.
|
|
18
|
+
- **Buildkite.** Add an `e2e` step; install chromium via the pipeline setup hook or a Docker plugin (`docker#v5.0.0`); invoke as above; `artifact_paths: [".rcf/reports/ci/e2e.json", "playwright-report/**", "test-results/**"]`.
|
|
19
|
+
- **Jenkins.** Add an `e2e` stage; install chromium via `sh 'npx playwright install chromium --with-deps'`; invoke as above; `archiveArtifacts artifacts: '.rcf/reports/ci/e2e.json, playwright-report/**, test-results/**', allowEmptyArchive: true`.
|
|
20
|
+
|
|
21
|
+
Projects that apply no browser-facing blueprint delete the `e2e` job from the workflow (or the materialiser omits it on regeneration); the workflow reads byte-identical to a 2.1 project in that case.
|
|
22
|
+
|
|
5
23
|
## The workflow set the matrix materialises
|
|
6
24
|
|
|
7
25
|
Which workflow files exist depends on `workflowShape`:
|