Each governance sub-component had its own h2 title + subtitle that
duplicated the tab label and the parent "Policy Governance" context.
Removed the redundant headers from 13 tab components while preserving
action buttons (Configure Budget, Add Weight, New Profile, etc.) as
standalone right-aligned action bars.
Detail sub-routes (risk-profile-editor, conflict-resolution-wizard)
keep their titles since they are not tab panels.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New test suite: navigation-restructure.e2e.spec.ts (26 tests, 7 groups)
Group 1 - Sidebar structure (7 tests):
- Dashboard ungrouped and first
- Release Control has Deployments, Releases, Environments
- Policy group has 5 items (no Release Gates)
- Security group has no Reports
- Operations has no Policy or Trust Analytics
- Audit & Evidence has Trust (not Trust Audit)
Group 2 - Releases unified page (5 tests):
- Title is "Release Control"
- Has Releases + Versions tabs
- Default tab is Releases
- Versions tab changes button to New Version
- /releases/versions redirects to ?tab=versions
Group 3 - Deployments page (7 tests):
- Has Pipeline + Approvals tabs (no Table/Correlations)
- No redundant context chips
- Approvals tab has gate summary cards + Gate Type column + search
- No Angular errors
Group 4 - Route redirects (2 tests):
- /security/reports → /security
- /triage/audit-bundles → /evidence/bundles
Group 5 - Page content consistency (6 tests):
- Dashboard, Vulnerabilities, Scheduled Jobs, Notifications, Audit Log headings correct
- No NG02100 errors on Audit Log
Group 6 - Diagnostics (1 test):
- NOT RUN labels (not NOT RAN)
Group 7 - Breadcrumbs (2 tests):
- Operations breadcrumb not duplicated
- Says "Operations" not "Ops"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Product rationale: Users asking "why is my release blocked?" had to check
3 places (Policy > Release Gates, Deployments > Approvals, Release Detail > Gates).
Now the Deployments Approvals tab is the single surface for all blocking
information with action capability.
Approvals tab enriched:
- Summary cards: Pending Approvals, Gate Failures, Gates Passed counts
- Table columns: Release, Promotion, Gate Type, Status, Reason, Requested, Actions
- Gate Type column shows approval/policy/security/freeze/dependency
- Reason column explains blocking status
- Contextual action: "Policy" link to policy packs when gates are blocking
- Approve/Reject buttons for pending human approvals
Policy sidebar:
- Release Gates removed from Policy group (5 items → 4: Packs, Governance,
Simulation, VEX & Exceptions, Audit)
- /ops/policy/gates redirects to /releases/deployments?view=approvals
- Sub-routes (gates/catalog, gates/simulate, etc.) retained for deep links
- Policy shell subtitle updated to remove "release gates" mention
No functionality loss — policy authors use Simulation to test rules and
Audit to review change history. The gate evaluation impact on releases
is now visible in context where operators can act on it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Approvals tab:
- Default gate toggles all OFF (shows all approvals, not just "gated" type)
- Add search input field that filters by release name, version, environment,
requestedBy, and status
- Approve/Reject buttons now visible for all pending approvals (gate filter
was hiding them by defaulting to only "gated" type)
Versions tab:
- Hide the ReleaseListComponent's own header (title + page-action-outlet)
when embedded=true, eliminating the duplicate "New Version" button
- Parent Release Control page already provides the header and dynamic button
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pending actions lane:
- Only visible on Pipeline tab (not Approvals), uses showPendingLane computed
- Exit animation now works: pendingLaneHidden signal delays @if removal until
the 250ms CSS collapse animation completes
- Re-shows when switching back to Pipeline tab
Approvals tab:
- Replaced horizontal card scroll with a proper sortable table
- Columns: Release, Promotion (source → target), Status, Urgency, Gates, Requested, Actions
- Shows requestedAt date + requestedBy in the Requested column
- Approve/Reject/View buttons inline in the Actions column
- Empty state message when no approvals match gate filters
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Title: "Release Control" (encompasses both tabs)
- Subtitle changes per tab:
- Releases tab: "Promotion pipeline with gate status, risk posture, and evidence for every release."
- Versions tab: "Sealed digest-first version catalog across standard and hotfix lanes."
- Create button changes per tab:
- Releases tab: "New Release" → /releases/new
- Versions tab: "New Version" → /releases/versions/new
- Uses Angular effect() to reactively update pageAction when activeTab changes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both pages used self-closing <stella-page-tabs ... /> with content rendered
as sibling elements OUTSIDE the component. This caused an empty tabpanel
with content floating below on the page background.
Fix: wrap tab-conditional content INSIDE <stella-page-tabs>...</stella-page-tabs>
so it projects into the tabpanel slot. Now the tab bar and its content share
the same visual container with the correct border and background.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The "Approve (1)" action on the Releases table was a link navigating to
/releases/approvals (a separate page). Users expected an inline confirmation
to approve the release directly.
Now shows an app-confirm-dialog with the release name, then calls the
approval decision API (POST /api/v1/approvals/{id}/decision) and refreshes
the release list on success.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Revert to /api/v1/approvals (not /api/v1/release-orchestrator/approvals).
The gateway routes /api/v1/approvals/* → JobEngine, which registers the
/decision endpoint via ReleaseControlV2Endpoints.PostApprovalDecision().
The /api/v1/release-orchestrator/approvals/{id}/approve endpoints are
the classic routes from ApprovalEndpoints.cs — both work but the v1
/decision endpoint is the canonical one that supports approve/reject/
defer/escalate actions via a single body parameter.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Approval API fix:
- Frontend was calling /api/v1/approvals/{id}/decision (wrong URL)
- Backend registers at /api/v1/release-orchestrator/approvals/{id}/approve
- Updated queueBaseUrl and detailBaseUrl to match actual backend routes
- Changed approve/reject to POST /{id}/approve and /{id}/reject (not /decision)
Pending actions animation:
- Add CSS keyframe animations for pending-lane enter (fade-in) and exit (collapse)
- onTabChange('approvals') now triggers exit animation (250ms) before switching tab
- Pending lane smoothly collapses when user clicks "View all"
AGENTS.md — No Mockups Convention:
- All UI must connect to real backend endpoints
- Never create mock/stub implementations unless explicitly requested
- Error states must be surfaced to user, never silently swallowed
- If backend endpoint doesn't exist, mark task BLOCKED
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Releases page:
- Rename "Pipeline" tab → "Releases" (first tab should match page name)
- Default activeTab from 'pipeline' → 'releases'
- Fix embedded ReleaseListComponent also clearing parent's pageAction on destroy
Deployments page:
- Approve/reject now show error banner when API fails instead of silently swallowing
(the demo env returns 404 for approval endpoints, making buttons appear broken)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: stella-page-tabs used urlParam="tab" while the component also
read the "view" query param via a manual queryParamMap subscriber. When
stella-page-tabs wrote ?tab=X to the URL, the subscriber re-read the stale
?view= param and reset viewMode back, causing tabs to appear frozen and
approve/reject button clicks to be swallowed by the stale state.
Fix:
- Change stella-page-tabs urlParam from "tab" to "view" so both the
component and the tab widget use the same query parameter
- Guard the manual subscriber to only update viewMode if it actually
differs, preventing feedback loops
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BC1 — Fix "Operations > Operations > ..." duplicate breadcrumb:
- Set breadcrumb to empty string on /ops/operations parent route
and /ops/operations (overview) route, so only the top-level
"Operations" breadcrumb from /ops renders. Affects 7 pages:
Feeds, Signals, Jobs, Diagnostics, Notifications, Watchlist, overview.
EC1 — Export Center delete confirmation:
- Replace window.confirm() with app-confirm-dialog variant="danger"
- Names the export profile being deleted in confirmation message
- Follows the destructive action convention from AGENTS.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Unify the Releases page with Pipeline + Versions tabs:
- Add stella-page-tabs with Pipeline (default) and Versions tabs
- Pipeline tab shows the existing release pipeline table
- Versions tab renders the ReleaseListComponent (version catalog) inline
- /releases/versions redirects to /releases?tab=versions for bookmarks
- Updated subtitle to "Versions, deployments, approvals, and promotion pipeline."
The Versions sidebar item was already removed in Phase A. This completes
the unification — one place for all release-related views.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bundles route moved to /evidence/bundles:
- Add /evidence/bundles and /evidence/bundles/new routes loading existing
TriageAuditBundlesComponent and TriageAuditBundleNewComponent
- /triage/audit-bundles and /triage/audit-bundles/new redirect to new paths
Security Reports merged into Security Posture:
- /security/reports redirects to /security (Security Posture page)
- Add Print/PDF button directly on Security Posture page header
- Reports page component retained for backward compat but no longer in sidebar or routes
All old routes have redirects to prevent bookmark breakage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major IA restructure based on product-level analysis of Stella Ops core
workflows (release lifecycle, policy gates, evidence chain, security posture).
New 7-group structure (was 5):
- Dashboard: new ungrouped home link (no group header)
- Release Control: Deployments, Releases, Environments (moved from Ops)
- Security: Vulnerabilities, Security Posture (+children), Scan Image
(Reports removed — will merge into Posture in Phase B)
- Policy: NEW GROUP — Packs, Governance, Simulation, VEX & Exceptions,
Release Gates, Policy Audit (promoted from buried Operations item)
- Operations: slimmed from 11→8 items (Hub, Jobs, Scripts, Signals,
Diagnostics, Notifications, Feeds, Watchlist)
- Audit & Evidence: Overview, Capsules, Replay, Export, Audit Log,
Bundles (route fixed to /evidence/bundles), Trust (merged name)
- Settings: unchanged
Rationale:
- Policy is a release-blocking gate with 6 deep sub-workflows — not an ops utility
- Environments define the promotion graph — belongs in Release Control
- Trust Audit + Trust Analytics merged into single "Trust" item
- Reports removed (duplicated Security Posture content)
- Versions removed from sidebar (will merge into Releases as tab in Phase C)
- Dashboard link ensures users can always navigate home without logo click
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
U2 — Promote button three-state model:
- showPromote: visible only when a next promotion target exists
- canPromote: enabled only when deployed + no blocking gates
- promoteDisabledReason: tooltip explaining why promotion is disabled
- Added .rdp__btn--disabled style (opacity + pointer-events)
W1 — Script delete confirmation:
- Replace window.confirm() with app-confirm-dialog variant="danger"
- Names the script being deleted in the confirmation message
W2 — Script description tooltip:
- Add [title] binding to truncated description text in scripts table
V1 — Remove duplicate "Profile" h2 in User Preferences tab panel
X1 — Breadcrumb root "Ops" → "Operations" to match sidebar group label
AGENTS.md — Three new mandatory conventions:
- Destructive Action Convention: all deletes/revokes must use app-confirm-dialog
- Truncated Text Convention: all text-overflow:ellipsis elements must have [title]
- Promote Button Convention: three-state (hidden/disabled/enabled) model
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Empty states:
- Audit Log "Recent Events" table: show "No audit events recorded yet." when empty
- Audit Log "All Events" table: show "No events match the current filters." when empty
Descriptions:
- Jobs & Queues: trim verbose 4-line description to single line
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Naming consistency:
- Dashboard heading "Mission Board" → "Dashboard" to match breadcrumb/title
- Vulnerabilities page: "Artifact workspace" → "Vulnerabilities" (heading, breadcrumb, route title)
- Doctor checks: "NOT RAN" → "NOT RUN" (grammar fix)
- Doctor pack categories: add label overrides for "servicegraph" → "Service Graph" and "binaryanalysis" → "Binary Analysis"
- Release digest placeholder: "digest-unavailable" → "Pending digest"
Bug fixes:
- Register locale data for all 8 supported locales (bg-BG, de-DE, ru-RU, es-ES, fr-FR, uk-UA, zh-TW, zh-CN) to fix NG02100 InvalidPipeArgument errors on Audit Log and other pages using Angular built-in pipes
- Null-safe json/number pipes in audit-log components (audit-log-table, audit-event-detail, audit-integrations, audit-export)
- Approval version fallback: use empty string instead of releaseName to prevent duplicate text in approval cards
- Approval card template: hide version span when it matches the release name
Layout/UX:
- stella-page-tabs: enable horizontal scroll on desktop (was mobile-only), prevents tab wrapping on Diagnostics (11 tabs), Audit Log (9 tabs)
- Triage date formatting: use DateFormatService for locale-aware dates instead of bare toLocaleString()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add nginx proxy blocks for /api/v1/release-orchestrator/,
/api/v1/release-control/, /api/v2/releases/, /api/v1/releases/,
/api/v1/registries/ in Dockerfile.console
- All release UI calls now reach JobEngine (401 not 404)
- Registry search reaches Scanner service
- Pipeline page uses ReleaseManagementStore (real API, no mock data)
- Deployment wizard uses BundleOrganizerApi for create/seal
- Inline version/hotfix creation in deployment wizard wired to API
- Version detail shows "not found" error instead of blank screen
- Version wizard has promotion lane + duplicate component detection
- Sprint plan for 41 missing backend endpoints created
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: the | slice pipe was used in the template but SlicePipe
was not in the standalone component's imports array. This caused
Angular's resolveDirective to throw 'Cannot read factory' on every
change detection cycle, preventing mock version cards from rendering
and breaking the Continue button validation.
Also: removed unused RouterModule import, converted computed signals
to methods for PlatformContextStore-dependent values, added
platformCtx.initialize() in constructor.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create unified releases pipeline page with decision capsules
(Deploy, Approve, Review Gates, View Evidence, Promote)
- Replace raw select filters with app-filter-bar on releases and activity pages
- Dashboard: single-column layout with Pending Actions card (pipeline + action
badges), 4-column status lane (Vuln Summary + Feed Status | SBOM Health |
Env Health | Environments at Risk), loading skeleton, reduced-motion support
- Sidebar: Dashboard at Release Control root, flat menu items
(Releases, Versions, Approvals, Activity), remove Promotions/Hotfixes
- Metric card labels: proper font size with ellipsis + title tooltip
- Badge cap changed from 99+ to 9+
- Action badges on sidebar: blocked gates, critical findings, failed runs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add UseIdentityEnvelopeAuthentication() to Authority service, fixing
/console/tenants 403. Authority was the last service missing it.
- Add ui.preferences.read and ui.preferences.write to OIDC scope request
in config.json and PlatformServiceOptions, fixing preferences/language 403.
The scopes existed in Authority but were never requested by the frontend.
All services now have identity envelope middleware:
Gateway, Platform, Scanner, JobEngine, Timeline, Integrations,
Concelier, Authority (8/8 complete)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix 1 (CRITICAL): BackendProbeService now auto-recovers from "unreachable".
When probe fails, schedules retry every 10s (max 5 attempts). Guard
re-probes before redirecting if probe was previously reachable. This
fixes ALL 9 guarded route groups that redirected to /setup mid-session.
Fix 2: wasEverAuthenticated latch now persists in sessionStorage instead
of class field. Survives page reloads (F5), cleared on logout.
Fix 3: Console-admin routes now use requireAnyScopeGuard with ui.admin
bypass instead of plain requireAuthGuard. Admin user can access all
/console-admin/* pages (tenants, clients, tokens, branding).
Fix 4: Governance sub-tab routerLinks changed from relative to absolute
paths. Clicking Trust Weights, Staleness, etc. now stays on governance
instead of navigating to random pages.
Fix 5: Integration empty-state buttons show proper display names
("Runtime Host" not "runtimehost", "SCM Integration" not "scm").
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- integration-hub-ui.component.spec: fix integrationId → id property
- orphan-revival-regression: fix index signature access for getViewMode
- integration-detail-page.spec: fix mock Integration type
- Install @vitest/browser-playwright for test runner
- Sprint 025 FE-CLN-004: DONE — build verified, cleanup confirmed clean,
test runner Karma→Vitest migration is infrastructure not regression
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend (Scanner .NET):
- New ScanPolicyEndpoints.cs with GET/POST/PUT/DELETE /api/v1/scan-policies
- In-memory ConcurrentDictionary storage (no migration needed)
- Auth: scanner:read for list, orch:operate for mutations
- Registered in Scanner Program.cs
Frontend (Angular):
- New scan-policy.component.ts with table view, inline create/edit form,
enable/disable toggle, dynamic rules (type/severity/action)
- Route added at /security/scan-policies in security-risk.routes.ts
Gateway route already exists in router-gateway-local.json.
Sprint 002: all 7 tasks now DONE.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
flicker, pack creation, export tooltip, audit guidance
Sprint A: Harbor fixture now returns realistic search results (7 repos)
and artifact digests (3 versions with tags). Release creation wizard
Step 2 now shows actual images to select.
Sprint B: Scan polling caps at 60 polls (3 min). Shows timeout banner
with guidance link to Scheduled Jobs and "Keep Waiting" button.
Sprint C: /console/profile route now renders InsufficientPermissions
component instead of 404. Shows user/tenant, guidance, and nav links.
Catches all 24 guard redirect dead-ends.
Sprint D: Event stream chip no longer flickers DEGRADED during context
reloads. Loading state treated as connected (transient, not error).
Sprint E: Policy Packs empty state now has inline Create Pack form.
Calls existing PolicyApiService.createPack() backend endpoint.
Sprint F: Diagnostics Export button shows disabled tooltip "Run a
diagnostic check first" when no results available.
Sprint G: Audit Log shows guidance text when all module counts are 0.
Lists automatically captured event types. Confirms audit is active.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: AuthSessionStore.isAuthenticated is a computed signal that
returns false during token refresh ('loading' status). Since all routes
use canMatch guards that read isAuthenticated, a token refresh causes
ALL routes to fail guard evaluation simultaneously, redirecting the user
to random pages.
Fix: Add wasEverAuthenticated latch that stays true once set. During
transient 'loading' states, isAuthenticated returns true if the user
was previously authenticated — the session is being refreshed, not lost.
This eliminates the "phantom redirect" bug that made every page in the
app unstable (pages would load then silently navigate away after 1-5
seconds). Verified stable on /setup/identity-access and /evidence/audit-log
with 12-second wait after navigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Policy Packs: show "No policy packs configured" with description and
link to overview when pack list is empty
- Shadow Mode: add prerequisite text below disabled Enable/View Results
buttons — "Shadow mode requires at least one active policy pack" with
link to Packs tab. Applied to both indicator and dashboard components.
- JobEngine: show guidance "No jobs have been submitted yet..." when all
counts are 0, auto-hides when jobs appear
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical fixes:
- Replace router.navigateByUrl() with Location.replaceState() in
PlatformContextUrlSyncService to prevent re-evaluating canMatch guards
during query param sync. This was causing random page redirects across
all routes when auth session signals hadn't settled yet.
- Fix exception scope mismatch: Authority issues 'exceptions:read' (plural)
but guards checked 'exception:read' (singular). Aligned to plural form.
- Fix admin scope bypass: guards checked 'admin' scope but token has
'ui.admin'. Now both are accepted as superuser bypass.
- Remove duplicate scope entries in description map.
UX polish (from fix agents):
- Integration detail: formatActor() truncates raw user ID hashes to
"User 9a2d0730..." instead of showing full 32-char hex string.
- Dashboard feed status: show "Not checked yet" instead of "0 healthy"
when no advisory source health checks have run.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bug: canSubmit computed() used plain string imageRef which computed()
can't track. Submit button was permanently disabled.
Fix: Changed imageRef to signal(''), updated template to use
[ngModel]="imageRef()" (ngModelChange)="imageRef.set($event)",
updated all class references to imageRef() for reads and .set() for writes.
Bug: Scan submit called /scanner/api/v1/scans/ (console nginx prefix)
instead of /api/v1/scans/ (gateway route).
Fix: Removed /scanner/ prefix from all API URLs.
KNOWN ISSUE: Scanner service needs identity envelope middleware (same
as Concelier fix) — ReverseProxy strips JWT, scanner returns 400
"tenant required". The scan submission reaches the scanner but auth
fails. Fix requires adding the same pre-auth envelope middleware
pattern to the Scanner service.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The scan route was added to security.routes.ts which isn't loaded by the
app router. The app loads security-risk.routes.ts at /security/*. Added
the scan route to security-risk.routes.ts so /security/scan resolves.
Verified: Scan Image page loads at /security/scan with heading, image
input, and submit button. 111/111 canonical routes passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
S5-T02: Dashboard 3-column layout with real APIs
- CSS Grid: security posture (1/3) | environments + actions (2/3)
- Left column: Vulnerability Summary (from VULNERABILITY_API getStats()),
SBOM Health (from computed sbomStats), Advisory Feed Status (from
SourceManagementApi getStatus())
- Right column: mission summary strip (4 cards), promotion pipeline
(env card grid), environments at risk table, quick links
- Footer: platform health bar with status dots
- Real API calls with independent loading states and catchError defaults
- Refresh button re-fetches all data
- Responsive: collapses to single column on mobile
- Welcome guide still spans full width when no environments
- Removed old: reachabilityStats signal, nightlyOpsSignals signal,
NightlyOpsSignal interface, TitleCasePipe/UpperCasePipe imports
S5-T03: Security reports as downloadable exports
- New shared utility: download-helpers.ts (downloadCsv, downloadJson)
- Risk Report tab: "Export CSV" + "Generate PDF" (print-friendly CSS)
- VEX Ledger tab: "Export VEX Decisions" as JSON download
- Evidence Export tab: explainer + "Open Export Center" link
- Tests updated: 6 new test cases for export functionality
All 6 sprints now complete. Angular build: 0 errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sprint 4 — Sidebar restructure (S4-T01+T02):
5 groups: Release Control, Security, Operations, Audit & Evidence, Setup & Admin
Groups 4+5 collapsed by default for new users
Operations extracted from Release Control into own group
Audit extracted from Security into own group
groupOrder and resolveMenuGroupLabel updated
Approvals badge moved to section-level
Sprint 2 — Demo data badges (S2-T04+T05):
Backend: isDemo=true on all compatibility/seed responses in
PackAdapterEndpoints, QuotaCompatibilityEndpoints, VulnerabilitiesController
Frontend: "(Demo)" badges on Usage & Limits page quotas
Frontend: "(Demo)" badges on triage artifact list when seed data
New PlatformItemResponse/PlatformListResponse with IsDemo field
Sprint 6 — Audit emission infrastructure (S6-T01+T02):
New shared library: src/__Libraries/StellaOps.Audit.Emission/
- AuditActionAttribute: [AuditAction("module", "action")] endpoint tag
- AuditActionFilter: IEndpointFilter that auto-emits UnifiedAuditEvent
- HttpAuditEventEmitter: POSTs to Timeline /api/v1/audit/ingest
- Single-line DI: services.AddAuditEmission(configuration)
Timeline service: POST /api/v1/audit/ingest ingestion endpoint
- IngestAuditEventStore: 10k-event ring buffer
- CompositeUnifiedAuditEventProvider: merges HTTP-polled + ingested
Documentation: docs/modules/audit/AUDIT_EMISSION_GUIDE.md
Angular build: 0 errors. .NET builds: 0 errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sprint 4:
S4-T04: Empty state guidance for sparse pages
- Unknowns: graceful "No unknown components" with "Scan an Image" link
(replaces API error message)
- Evidence Capsules: enhanced with "Create your first release" guidance
S4-T05: Canonical route cleanup
- All /administration/* routes now redirect to /setup/* canonical
- /admin/* redirects to /setup instead of /administration
- 8 admin-only routes migrated to /setup/* (identity-providers, offline,
configuration-pane, security-data, workflows, ai-preferences)
- Sidebar nav config updated to /setup/identity-providers
- Settings routes updated to /setup/* targets
Sprint 6:
S6-T03: Record Decision as modal overlay
- Both decision-drawer and decision-drawer-enhanced converted from
sliding drawer to centered fixed-position modal (z-index 1000)
- Semi-transparent backdrop, click-outside-to-close, scrollable body
- Max width 480/520px, max height 90vh
S6-T04: Topology wizard skip agent step
- "Skip — assign agent later" button when no agents available
- Deploy Agent guidance with CLI command
- Next button shows "Next (without agent)" when skipping
- Done summary shows "None (skipped)" for agent
- agentSkipped signal in wizard service
Angular build: 0 errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>