Preserve live scope across evidence and registry flows
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# Sprint 20260309_015 - Live Scope Preservation Follow-ups
|
||||
|
||||
## Topic & Scope
|
||||
- Repair user-visible scope loss uncovered by live Playwright after the runtime-fault rebuild.
|
||||
- Keep tenant and region context stable when users move between evidence-thread and integration-admin actions.
|
||||
- Working directory: `src/Web/StellaOps.Web/**`.
|
||||
- Expected evidence: focused Angular specs, rebuilt web bundle, live Playwright changed-surfaces recheck.
|
||||
|
||||
## Dependencies & Concurrency
|
||||
- Depends on `SPRINT_20260309_014_Platform_live_runtime_fault_repair.md` because the backend/runtime repair must be stable before UI scope regressions are meaningful.
|
||||
- Safe parallelism: avoid unrelated search and shell work already in flight; stage only evidence-thread, registry-admin, Playwright harness, and sprint-doc files.
|
||||
|
||||
## Documentation Prerequisites
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/code-of-conduct/CODE_OF_CONDUCT.md`
|
||||
- `docs/code-of-conduct/TESTING_PRACTICES.md`
|
||||
|
||||
## Delivery Tracker
|
||||
|
||||
### TASK-015-001 - Preserve scope on changed-surface action flows
|
||||
Status: DONE
|
||||
Dependency: none
|
||||
Owners: QA, Developer
|
||||
Task description:
|
||||
- Fix changed-surface actions that drop tenant and region query scope during navigation, then tighten the live Playwright harness so the same regressions fail immediately.
|
||||
|
||||
Completion criteria:
|
||||
- [x] Evidence thread "Back to Search" keeps active scope query params.
|
||||
- [x] Registry admin tab navigation keeps active scope query params.
|
||||
- [x] Focused Angular specs and live Playwright changed-surfaces verification pass.
|
||||
|
||||
## Execution Log
|
||||
| Date (UTC) | Update | Owner |
|
||||
| --- | --- | --- |
|
||||
| 2026-03-09 | Sprint created after live changed-surfaces Playwright reported scoped actions navigating without tenant/region query preservation. | Codex |
|
||||
| 2026-03-09 | Root causes confirmed in `EvidenceThreadViewComponent.onBack()` and registry-admin tab links. Added focused feature-spec coverage, rebuilt `dist/stellaops-web/browser`, synced the live `compose_console-dist` volume, and re-ran `live-frontdoor-changed-surfaces.mjs`; Playwright now records tenant/region-preserving URLs for `back-to-search` and `audit-tab`. | Codex |
|
||||
|
||||
## Decisions & Risks
|
||||
- This sprint treats scope-preservation regressions as product defects even when the destination page still renders, because silent context loss breaks reproducibility and link sharing.
|
||||
- Feature specs remain excluded from the default Angular test target to keep routine unit runs lightweight; targeted UI feature coverage for this slice is registered in `tsconfig.spec.features.json` and executed explicitly.
|
||||
|
||||
## Next Checkpoints
|
||||
- Next defect cluster from the same live Playwright sweep: release-investigation `deploy-diff` still lands in a `Missing Parameters` state, and `change-trace` still renders with `No Change Trace Loaded`.
|
||||
@@ -83,6 +83,7 @@ const surfaceConfigs = [
|
||||
selector: 'main button:has-text("Back to Search")',
|
||||
expectedUrlPattern: '/evidence/threads',
|
||||
expectedTextPattern: /evidence threads/i,
|
||||
requiredUrlFragments: ['tenant=', 'regions='],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -115,6 +116,7 @@ const surfaceConfigs = [
|
||||
selector: 'a[href*="/registry-admin/audit"], button:has-text("Audit")',
|
||||
expectedUrlPattern: '/registry-admin/audit',
|
||||
expectedTextPattern: /audit/i,
|
||||
requiredUrlFragments: ['tenant=', 'regions='],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -389,7 +391,9 @@ async function verifySurfaceActions(context, surface) {
|
||||
const bodyText = await collectBodyText(page);
|
||||
const headingText = firstMatchingHeading(action.expectedTextPattern, headings);
|
||||
const finalUrl = page.url();
|
||||
const hasRequiredUrlFragments = (action.requiredUrlFragments ?? []).every((fragment) => finalUrl.includes(fragment));
|
||||
const ok = finalUrl.includes(action.expectedUrlPattern)
|
||||
&& hasRequiredUrlFragments
|
||||
&& matchesPattern(action.expectedTextPattern, headings, bodyText);
|
||||
|
||||
results.push({
|
||||
|
||||
@@ -89,6 +89,7 @@ describe('EvidenceThreadViewComponent', () => {
|
||||
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/evidence/threads'], {
|
||||
queryParams: { purl: 'pkg:oci/acme/api@sha256:abc123' },
|
||||
queryParamsHandling: 'merge',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -87,7 +87,8 @@ export class EvidenceThreadViewComponent implements OnInit, OnDestroy {
|
||||
onBack(): void {
|
||||
const purl = this.returnPurl();
|
||||
void this.router.navigate(['/evidence/threads'], {
|
||||
queryParams: purl ? { purl } : {},
|
||||
queryParams: purl ? { purl } : undefined,
|
||||
queryParamsHandling: 'merge',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterLink, provideRouter } from '@angular/router';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { REGISTRY_ADMIN_API } from '../../core/api/registry-admin.client';
|
||||
import { RegistryAdminComponent } from './registry-admin.component';
|
||||
|
||||
describe('RegistryAdminComponent', () => {
|
||||
const registryAdminApiStub = {
|
||||
listPlans: () => of([]),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [RegistryAdminComponent],
|
||||
providers: [
|
||||
provideRouter([]),
|
||||
],
|
||||
})
|
||||
.overrideComponent(RegistryAdminComponent, {
|
||||
set: {
|
||||
providers: [{ provide: REGISTRY_ADMIN_API, useValue: registryAdminApiStub }],
|
||||
},
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
it('merges the active query scope across registry admin tabs', () => {
|
||||
const fixture = TestBed.createComponent(RegistryAdminComponent);
|
||||
fixture.detectChanges();
|
||||
|
||||
const links = fixture.debugElement
|
||||
.queryAll(By.directive(RouterLink))
|
||||
.map((debugElement) => debugElement.injector.get(RouterLink));
|
||||
|
||||
expect(links.length).toBe(2);
|
||||
expect(links.every((link) => link.queryParamsHandling === 'merge')).toBeTrue();
|
||||
});
|
||||
});
|
||||
@@ -49,6 +49,7 @@ type TabType = 'plans' | 'audit';
|
||||
class="registry-admin__tab"
|
||||
[class.registry-admin__tab--active]="activeTab() === 'plans'"
|
||||
routerLink="plans"
|
||||
queryParamsHandling="merge"
|
||||
role="tab"
|
||||
[attr.aria-selected]="activeTab() === 'plans'"
|
||||
>
|
||||
@@ -58,6 +59,7 @@ type TabType = 'plans' | 'audit';
|
||||
class="registry-admin__tab"
|
||||
[class.registry-admin__tab--active]="activeTab() === 'audit'"
|
||||
routerLink="audit"
|
||||
queryParamsHandling="merge"
|
||||
role="tab"
|
||||
[attr.aria-selected]="activeTab() === 'audit'"
|
||||
>
|
||||
|
||||
12
src/Web/StellaOps.Web/tsconfig.spec.features.json
Normal file
12
src/Web/StellaOps.Web/tsconfig.spec.features.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "./tsconfig.spec.json",
|
||||
"include": [],
|
||||
"files": [
|
||||
"src/test-setup.ts",
|
||||
"src/app/core/api/first-signal.client.spec.ts",
|
||||
"src/app/core/console/console-status.service.spec.ts",
|
||||
"src/app/features/policy-simulation/simulation-dashboard.component.spec.ts",
|
||||
"src/app/features/registry-admin/registry-admin.component.spec.ts",
|
||||
"src/app/features/evidence-thread/__tests__/evidence-thread-view.component.spec.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user