Harden live route ownership verification

This commit is contained in:
master
2026-03-10 17:27:26 +02:00
parent 6ef5ff5b43
commit bb8327087d
2 changed files with 30 additions and 9 deletions

View File

@@ -20,7 +20,7 @@
## Delivery Tracker
### FE-RELEASE-ENV-001 - Restore canonical Releases ownership for environment inventory
Status: DOING
Status: DONE
Dependency: none
Owners: QA, 3rd Line Support, Product Manager, Architect, Developer
Task description:
@@ -28,20 +28,23 @@ Task description:
- The old release-orchestrator environment pages are not safe to restore: they are placeholder-heavy, contain stale links, and would reintroduce broken actions. The correct fix is to keep the working topology-backed inventory/detail pages and mount them directly under Releases.
Completion criteria:
- [ ] `/releases/environments` and `/releases/environments/:environmentId` resolve under `/releases/*` without redirecting to Operations.
- [ ] Legacy release environment aliases redirect to `/releases/environments`.
- [ ] Route ownership specs and live ownership harness match the restored contract.
- [ ] Rebuilt live web passes the canonical route sweep with zero failed routes.
- [x] `/releases/environments` and `/releases/environments/:environmentId` resolve under `/releases/*` without redirecting to Operations.
- [x] Legacy release environment aliases redirect to `/releases/environments`.
- [x] Route ownership specs and live ownership harness match the restored contract.
- [x] Rebuilt live web passes the canonical route sweep with zero failed routes.
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-03-10 | Sprint created after the live canonical Playwright sweep dropped to a single failure: `/releases/environments` redirected to `/ops/operations/environments`. Root-cause audit confirmed the redirect was architectural drift, not a component/runtime failure. | Developer |
| 2026-03-10 | Restored `/releases/environments` and `/releases/environments/:environmentId` as Releases-mounted topology surfaces, retargeted the legacy release environment aliases to `/releases/environments`, and updated the route-ownership test/harness expectations to match the canonical contract. | Developer |
| 2026-03-10 | `npx ng test --watch=false --progress=false --ts-config tsconfig.spec.json --include src/app/routes/route-surface-ownership.spec.ts` passed `5/5`; `npm run build` passed; the rebuilt bundle was synced into `compose_console-dist`; `node ./scripts/live-frontdoor-canonical-route-sweep.mjs` passed `111/111`; `node ./scripts/live-route-surface-ownership-check.mjs` passed with `failedActionCount=0` and `runtimeIssueCount=0`. | QA |
## Decisions & Risks
- Decision: supersede the earlier Operations-only redirect decision from `SPRINT_20260310_028_FE_route_surface_ownership_alignment.md`; the canonical Releases contract wins because the live route matrix and Pack 22 both depend on `/releases/environments`.
- Decision: do not revive `features/release-orchestrator/environments/**` in this slice. Those components remain non-canonical and need separate revival work if they are ever to return.
- Risk: the route-ownership Playwright harness still contains stale expectations for `/setup/notifications` and release environment aliases. It must be updated together with the route change or it will produce false failures.
- Decision: keep the topology-backed environment inventory/detail pages as the shared implementation behind both Releases and Operations rather than forking a second environment inventory surface.
- Decision: hardened `live-route-surface-ownership-check.mjs` to retry watchlist return-label checks when the trust shell briefly reports the blank `StellaOps` transition title; direct Playwright repro proved the underlying product flow was healthy and the prior failure was a harness race.
## Next Checkpoints
- Land the Releases route and legacy alias contract update.

View File

@@ -190,6 +190,16 @@ async function runSidebarCheck(page) {
}
async function runWatchlistLabelCheck(page, returnTo, expectedLabel) {
const evaluate = async () => {
const labelVisible = await page.getByText(`Return to ${expectedLabel}`, { exact: false }).first().isVisible().catch(() => false);
const snapshot = await captureSnapshot(page, `watchlist-return:${expectedLabel}`);
return {
ok: labelVisible,
snapshot,
};
};
await page.goto(
`https://stella-ops.local/setup/trust-signing/watchlist/alerts?${scopeQuery}&alertId=alert-001&scope=tenant&tab=alerts&returnTo=${encodeURIComponent(returnTo)}`,
{
@@ -199,14 +209,22 @@ async function runWatchlistLabelCheck(page, returnTo, expectedLabel) {
);
await settle(page);
const labelVisible = await page.getByText(`Return to ${expectedLabel}`, { exact: false }).first().isVisible().catch(() => false);
let result = await evaluate();
if (
!result.ok
&& new URL(page.url()).pathname === '/setup/trust-signing/watchlist/alerts'
&& (result.snapshot.title === 'StellaOps' || !result.snapshot.heading)
) {
await page.waitForTimeout(2_000);
result = await evaluate();
}
return {
kind: 'watchlist-return',
route: page.url(),
ok: labelVisible,
ok: result.ok,
expectedLabel,
snapshot: await captureSnapshot(page, `watchlist-return:${expectedLabel}`),
snapshot: result.snapshot,
};
}