Archive 6 completed sprints, add 4 new ElkSharp + FE sprint plans

Archived to docs-archived/implplan/:
- SPRINT_20260320_001 FE Releases Table & Wizard (4/4 DONE)
- SPRINT_20260324_001 Platform Scripts/Variables (7/7 DONE)
- SPRINT_20260323_002 ElkSharp Bounded Edge Refinement (11/11 DONE)
- SPRINT_20260328_003 ElkSharp Compound Sugiyama (3/3 DONE)
- SPRINT_20260329_006 FE Audit Menu Consolidation (12/12 DONE)
- SPRINT_20260329_007 FE Unified Stella Assistant (7/7 DONE)

New sprint plans for in-progress work:
- ElkSharp document rendering cleanup, source decomposition,
  hybrid iterative routing
- FE DevOps onboarding UX

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-03-30 17:23:52 +03:00
parent e91cf98f8f
commit bc255188d2
10 changed files with 2301 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
# Sprint 006 - Audit Menu Consolidation (Hub-and-Spoke)
## Topic & Scope
- Merge module-specific audit views from the unified audit dashboard into their parent feature pages as contextual tabs.
- Slim the unified audit dashboard from 9 tabs to 4 (Overview, All Events, Timeline, Correlations).
- Fill audit gaps: add audit tabs to 5 pages that lacked audit coverage (Platform Jobs, Scanner Ops, Trust Admin/Attestor, SBOM Sources).
- Create reusable `AuditModuleEventsComponent` for embedding audit event tables in feature pages.
- Working directory: `src/Web/StellaOps.Web/src/app/`.
- Expected evidence: Build passes, all 9 audit modules accessible from both contextual tabs and unified All Events.
## Dependencies & Concurrency
- No upstream sprint dependencies.
- All Steps 1-5 can be executed in parallel.
- Steps 6-8 depend on Steps 1-5 completion.
- Steps 10-13 depend on Step 9.
## Documentation Prerequisites
- `docs/implplan/` sprint file (this file).
## Delivery Tracker
### TASK-001 - Add Audit Trail tab to VEX Hub
Status: DONE
Owners: Developer
Completion criteria:
- [x] VEX Hub has 4th tab "Audit Trail" rendering AuditVexComponent
- [x] Cross-link to unified audit
### TASK-002 - Add Audit tab to Trust Admin
Status: DONE
Owners: Developer (agent)
Completion criteria:
- [x] Trust Admin has 4th tab "Audit" with sub-views for Trust Events, Air-Gap, Incidents
- [x] Cross-link to unified audit
### TASK-003 - Extend Policy Governance audit tab
Status: DONE
Owners: Developer (agent)
Completion criteria:
- [x] Policy Governance audit tab has sub-toggle: Governance Changes | Promotions & Approvals
- [x] AuditPolicyComponent embedded for promotions view
### TASK-004 - Extend Console Admin audit tab
Status: DONE
Owners: Developer (agent)
Completion criteria:
- [x] Console Admin audit tab has sub-tabs: Management | Token Lifecycle & Security
- [x] AuditAuthorityComponent embedded for token view
### TASK-005 - Add config audit to Integration Hub
Status: DONE
Owners: Developer (agent)
Completion criteria:
- [x] Integration detail page has "Config Audit" tab rendering AuditModuleEventsComponent (module=integrations)
Note: Hub-level tab was removed for usability; audit placed on per-integration detail page instead. Shell quick links cross-reference unified audit.
### TASK-006 - Slim unified audit dashboard
Status: DONE
Owners: Developer
Completion criteria:
- [x] Dashboard has 4 tabs: Overview, All Events, Timeline, Correlations
- [x] Module-specific tabs removed
### TASK-007 - Add backward-compatible redirects
Status: DONE
Owners: Developer
Completion criteria:
- [x] Old URLs (/evidence/audit-log/policy, etc.) redirect to new contextual locations
### TASK-008 - Update sidebar navigation
Status: DONE
Owners: Developer
Completion criteria:
- [x] Audit Bundles removed from Findings group
- [x] Unified Audit Log renamed to Audit & Compliance with 3 sub-items
### TASK-009 - Create reusable AuditModuleEventsComponent
Status: DONE
Owners: Developer
Completion criteria:
- [x] Shared component with @Input module/modules, table, filters, pagination, event detail
### TASK-010 - Fill audit gaps (jobengine, scheduler, scanner, sbom)
Status: DONE
Owners: Developer (agent)
Completion criteria:
- [x] Platform Jobs has Audit tab (jobengine + scheduler)
- [x] Scanner Ops has Audit tab
- [x] SBOM Sources has collapsible audit section with AuditModuleEventsComponent
### TASK-011 - Wire airgap/incident audit to real API
Status: DONE
Owners: Developer
Completion criteria:
- [x] AirgapAuditComponent wired to AuditLogClient.getAirgapAudit() with mock fallback
- [x] IncidentAuditComponent has apiConnected signal and degraded banner
### TASK-012 - Add bidirectional cross-links
Status: DONE
Owners: Developer
Completion criteria:
- [x] Contextual tabs link to unified All Events
- [x] Unified All Events links to contextual module pages when single-module filter active
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-03-29 | Sprint created; implementation started. | Developer |
| 2026-03-29 | Tasks 1, 6-9, 11-12 completed. Tasks 2-5, 10 in progress (agents). | Developer |
| 2026-03-30 | Tasks 2-5, 10 completed. All 12 tasks DONE. Sprint ready to archive. | Developer |
## Decisions & Risks
- Hub-and-Spoke model chosen: contextual audit tabs for DevOps workflow, unified for auditor/CISO.
- Data source differences documented: integrated and unified use different API clients with complementary data.
- AirgapAuditComponent falls back to mock data if API unavailable (degraded banner shown).
- IncidentAuditComponent shows degraded banner when Trust API incomplete.
## Next Checkpoints
- Build verification after all agents complete.
- Manual verification of all 9 module audit access paths.

View File

@@ -0,0 +1,644 @@
# Sprint 007 — Unified Stella Assistant: Mascot + Search + AI Chat as One
## Topic & Scope
**Problem**: Three disconnected help surfaces exist in the UI:
1. Stella Helper (mascot) — static English-only tips, localStorage, no API
2. Global Search (Ctrl+K) — unified search with entity cards and synthesis
3. Advisory AI Chat (drawer) — SSE-streaming AI with citations and actions
The user experiences these as separate tools. A new DevOps engineer has to discover each independently. The mascot has 189 tips but they're hardcoded in English, not connected to the search/AI knowledge, and can't be edited without a code deploy.
**Goal**: Merge all three into a single **Unified Stella Assistant** where the mascot is the FACE of the system, the search is its MEMORY, and the AI chat is its VOICE. All content comes from the database, all text respects the user's locale, and the admin can author/update tips without deploying code.
- Working directory: `src/Web/StellaOps.Web/src/app/`
- Backend working directory: `src/Platform/` (for API + DB schema)
- Expected evidence: unified component, DB schema, API endpoints, i18n integration
## Dependencies & Concurrency
- Depends on: existing `I18nService`, `UnifiedSearchClient`, `ChatService`, `SearchChatContextService`, `SearchContextRegistry`
- Sprint 006 T0a (mascot core) provides the animation/UI foundation
- Safe to parallelize: DB schema, API endpoints, and frontend can be built in parallel
## Documentation Prerequisites
- `docs/modules/platform/architecture-overview.md` — platform API patterns
- `src/Web/StellaOps.Web/src/app/core/i18n/i18n.service.ts` — i18n patterns
- `src/Web/StellaOps.Web/src/app/core/api/unified-search.client.ts` — search API
- `src/Web/StellaOps.Web/src/app/features/advisory-ai/chat/chat.service.ts` — chat API
---
## Architecture: Target State
```
UNIFIED STELLA ASSISTANT
┌──────────────────────────────────────────────────────────┐
│ Stella Mascot (UI) │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Tips Mode │ │ Search Mode │ │ Chat Mode │ │
│ │ (default) │ │ (Ctrl+K) │ │ (follow-up) │ │
│ │ │ │ │ │ │ │
│ │ DB-backed │ │ Unified │ │ Advisory AI │ │
│ │ i18n-aware│ │ Search API │ │ SSE streaming │ │
│ │ contextual│ │ + synthesis │ │ + citations │ │
│ └─────┬─────┘ └──────┬───────┘ └────────┬───────────┘ │
│ │ │ │ │
│ └───────────────┼────────────────────┘ │
│ │ │
│ ┌─────────▼──────────┐ │
│ │ StellaAssistant │ │
│ │ Service │ │
│ │ │ │
│ │ - mode signal │ │
│ │ - context signal │ │
│ │ - locale signal │ │
│ │ - tips from API │ │
│ │ - search bridge │ │
│ │ - chat bridge │ │
│ └─────────┬──────────┘ │
│ │ │
└────────────────────────┼────────────────────────────────────┘
┌──────────▼──────────┐
│ Backend APIs │
│ │
│ GET /api/v1/stella- │
│ assistant/tips │
│ ?route=X&locale=Y │
│ │
│ GET /api/v1/stella- │
│ assistant/glossary │
│ ?locale=Y │
│ │
│ POST /api/v1/ │
│ unified-search │
│ (existing) │
│ │
│ POST /api/v1/ │
│ advisory-ai/ │
│ conversations/ │
│ (existing) │
└─────────────────────┘
```
### Mode Transitions
```
User lands on page
TIPS MODE (default)
│ Shows DB-backed, locale-aware contextual tips
│ Mascot with speech bubble (current UI)
├── User types in mascot bubble → SEARCH MODE
│ Mascot bubble becomes search input
│ Results appear inline (entity cards)
│ Same API as Ctrl+K (UnifiedSearchClient)
├── User clicks "Ask Stella" or asks a question → CHAT MODE
│ Mascot bubble expands to chat interface
│ Uses existing ChatService (Advisory AI)
│ SSE streaming with mascot animations
│ Citations, actions, grounding score
├── Ctrl+K → SEARCH MODE (focus mascot search input)
└── User clicks mascot after dismissing → TIPS MODE (re-opens)
SEARCH MODE
├── User clicks result → navigates, returns to TIPS MODE
├── User clicks "Ask AI about this" → CHAT MODE with context
└── User clears search → TIPS MODE
CHAT MODE
├── AI suggests a search → SEARCH MODE with query pre-filled
├── User clicks citation link → navigates, stays in CHAT MODE
├── AI streaming done → stays in CHAT MODE for follow-ups
└── User clicks "Back to tips" → TIPS MODE
```
### Key Design Decisions
**D1: Mascot replaces global search bar as primary entry point**
The mascot bubble gets a search input field. Ctrl+K focuses this field instead of opening a separate dropdown. The separate `GlobalSearchComponent` dropdown becomes a fallback for users who prefer the old behavior.
**D2: Chat is embedded in mascot, not a separate drawer**
The `SearchAssistantHostComponent` drawer is replaced by the mascot's expanded chat mode. The mascot bubble grows to accommodate the conversation. On mobile, it goes full-screen.
**D3: Tips content moves to database**
The hardcoded `PAGE_TIPS` config becomes seed data. At runtime, tips are fetched from the backend API. This enables:
- Admin authoring without code deploy
- Per-locale translations
- A/B testing of tip content
- Analytics on which tips are helpful
**D4: Mascot animates in sync with AI**
During chat mode:
- `progress: thinking` → mascot shows thinking animation
- `progress: searching` → mascot shows searching animation
- `token` events → mascot lip-syncs or nods
- `citation` events → mascot points/highlights
- `error` events → mascot shows concern
- `done` → mascot shows satisfied pose
---
## Database Schema: `stella_assistant`
### Table: `assistant_tips`
```sql
CREATE TABLE stella_assistant.tips (
tip_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
route_pattern TEXT NOT NULL, -- '/ops/policy/vex', '/ops/policy/vex/consensus'
context_trigger TEXT, -- 'sbom-missing', 'gate-blocked', NULL for generic
locale TEXT NOT NULL DEFAULT 'en-US',
sort_order INT NOT NULL DEFAULT 0,
title TEXT NOT NULL,
body TEXT NOT NULL,
action_label TEXT, -- 'Scan your first image'
action_route TEXT, -- '/security/scan'
learn_more_url TEXT,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
product_version TEXT, -- '1.0', '1.1', NULL = all versions
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT,
UNIQUE (route_pattern, context_trigger, locale, sort_order)
);
CREATE INDEX idx_tips_route_locale ON stella_assistant.tips (route_pattern, locale) WHERE is_active;
CREATE INDEX idx_tips_context ON stella_assistant.tips (context_trigger) WHERE context_trigger IS NOT NULL AND is_active;
```
### Table: `assistant_greetings`
```sql
CREATE TABLE stella_assistant.greetings (
greeting_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
route_pattern TEXT NOT NULL,
locale TEXT NOT NULL DEFAULT 'en-US',
greeting_text TEXT NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (route_pattern, locale)
);
```
### Table: `assistant_glossary`
```sql
CREATE TABLE stella_assistant.glossary (
term_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
term TEXT NOT NULL, -- 'SBOM', 'VEX', 'Decision Capsule'
locale TEXT NOT NULL DEFAULT 'en-US',
definition TEXT NOT NULL, -- plain-English definition
extended_help TEXT, -- longer explanation
related_terms TEXT[], -- ['CVE', 'Advisory', 'Finding']
related_routes TEXT[], -- ['/security/scan', '/security/supply-chain-data']
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (term, locale)
);
CREATE INDEX idx_glossary_locale ON stella_assistant.glossary (locale) WHERE is_active;
```
### Table: `assistant_tours`
```sql
CREATE TABLE stella_assistant.tours (
tour_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tour_key TEXT NOT NULL, -- 'first-setup', 'scan-workflow', 'promotion-101'
locale TEXT NOT NULL DEFAULT 'en-US',
title TEXT NOT NULL,
description TEXT NOT NULL,
steps JSONB NOT NULL, -- array of { stepOrder, route, selector?, title, body, action? }
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (tour_key, locale)
);
```
### Table: `assistant_user_state`
```sql
CREATE TABLE stella_assistant.user_state (
user_id TEXT NOT NULL,
tenant_id TEXT NOT NULL,
seen_routes TEXT[] NOT NULL DEFAULT '{}',
completed_tours TEXT[] NOT NULL DEFAULT '{}',
tip_positions JSONB NOT NULL DEFAULT '{}', -- { "/dashboard": 3, "/security": 1 }
dismissed BOOLEAN NOT NULL DEFAULT FALSE,
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (user_id, tenant_id)
);
```
### Seed Data
The current 189 hardcoded tips + 101 greetings become seed SQL:
```sql
-- Generated from stella-helper-tips.config.ts
INSERT INTO stella_assistant.tips (route_pattern, locale, sort_order, title, body, action_label, action_route)
VALUES
('/', 'en-US', 0, 'What is this dashboard?', 'This is your daily operations overview...', NULL, NULL),
('/', 'en-US', 1, 'What does "SBOM: missing" mean?', 'SBOM stands for...', 'Scan your first image', '/security/scan'),
-- ... all 189 tips
;
```
Then translated rows for each locale:
```sql
INSERT INTO stella_assistant.tips (route_pattern, locale, sort_order, title, body, action_label, action_route)
VALUES
('/', 'bg-BG', 0, 'Какво е това табло?', 'Това е вашият дневен оперативен преглед...', NULL, NULL),
('/', 'de-DE', 0, 'Was ist dieses Dashboard?', 'Dies ist Ihre tägliche Betriebsübersicht...', NULL, NULL),
-- ...
;
```
---
## API Endpoints
### GET `/api/v1/stella-assistant/tips`
Returns tips for the current route and locale.
**Query params:**
- `route` (required): current URL path (e.g., `/ops/policy/vex/consensus`)
- `locale` (optional, default: user preference): `en-US`, `bg-BG`, etc.
- `contexts` (optional): comma-separated context triggers (e.g., `sbom-missing,feed-stale`)
- `version` (optional): product version filter
**Response:**
```json
{
"greeting": "Consensus shows how multiple VEX sources agree or disagree...",
"tips": [
{
"tipId": "uuid",
"title": "How consensus works",
"body": "When multiple sources publish VEX statements...",
"action": { "label": "View trust weights", "route": "/ops/policy/governance/trust-weights" },
"contextTrigger": null
}
],
"contextTips": [
{
"tipId": "uuid",
"title": "Your feeds are stale",
"body": "Advisory feeds haven't synced in 3 days...",
"contextTrigger": "feed-stale",
"action": { "label": "Check feeds", "route": "/ops/operations/feeds-airgap" }
}
]
}
```
**Route matching**: Server-side longest-prefix match (same logic as frontend `resolvePageKey` but canonical).
### GET `/api/v1/stella-assistant/glossary`
Returns domain terms for the current locale.
**Query params:**
- `locale` (optional)
- `terms` (optional): comma-separated specific terms to look up
**Response:**
```json
{
"terms": [
{
"term": "SBOM",
"definition": "Software Bill of Materials — a list of every component inside a container image.",
"extendedHelp": "SBOMs are generated when you scan...",
"relatedTerms": ["CVE", "Supply Chain", "Finding"],
"relatedRoutes": ["/security/scan", "/security/supply-chain-data"]
}
]
}
```
### GET `/api/v1/stella-assistant/tours`
Returns available guided tours.
**Query params:**
- `locale` (optional)
- `tourKey` (optional): specific tour to fetch
### PUT `/api/v1/stella-assistant/user-state`
Persists user state (seen routes, completed tours, tip positions, dismissed).
### GET `/api/v1/stella-assistant/user-state`
Retrieves user state.
---
## Frontend Architecture: Unified Component
### `StellaAssistantService` (replaces `StellaHelperContextService`)
```typescript
@Injectable({ providedIn: 'root' })
export class StellaAssistantService {
private readonly i18n = inject(I18nService);
private readonly searchClient = inject(UnifiedSearchClient);
private readonly chatService = inject(ChatService);
private readonly searchChatCtx = inject(SearchChatContextService);
private readonly drawerService = inject(SearchAssistantDrawerService);
private readonly http = inject(HttpClient);
// ---- Mode ----
readonly mode = signal<'tips' | 'search' | 'chat'>('tips');
// ---- Tips (from API) ----
readonly tips = signal<AssistantTip[]>([]);
readonly greeting = signal<string>('');
readonly contextTips = signal<AssistantTip[]>([]);
readonly glossary = signal<GlossaryTerm[]>([]);
// ---- Context ----
readonly activeContexts = signal<string[]>([]);
readonly currentRoute = signal<string>('/');
// ---- Search ----
readonly searchQuery = signal<string>('');
readonly searchResults = signal<EntityCard[]>([]);
readonly searchSynthesis = signal<SynthesisResult | null>(null);
// ---- Chat ----
readonly conversation = signal<Conversation | null>(null);
readonly isStreaming = signal<boolean>(false);
readonly streamStage = signal<string>(''); // thinking, searching, validating
// ---- User state (from API) ----
readonly userState = signal<UserState>(DEFAULT_STATE);
/** Fetch tips for current route and locale from backend */
async loadTips(route: string): Promise<void> { ... }
/** Push context trigger (components call this) */
pushContext(key: string): void { ... }
/** Switch to search mode */
enterSearch(query?: string): void { ... }
/** Switch to chat mode with optional initial message */
enterChat(message?: string): void { ... }
/** Return to tips mode */
exitToTips(): void { ... }
/** Persist user state to backend */
async saveUserState(): Promise<void> { ... }
/** Load glossary for current locale */
async loadGlossary(): Promise<void> { ... }
}
```
### `StellaAssistantComponent` (replaces `StellaHelperComponent`)
The component renders differently based on `mode()`:
**Tips Mode** (current mascot behavior):
- Speech bubble with tip title/body
- Tip navigation (prev/next)
- Small search input at bottom: "Ask Stella anything..."
- Typing in the input → switches to Search Mode
**Search Mode** (replaces Ctrl+K dropdown):
- Search input focused
- Entity cards rendered below
- Synthesis panel
- "Ask AI about this" button on each card → Chat Mode
**Chat Mode** (replaces drawer):
- Conversation messages with streaming
- Mascot animates during AI stages
- Citations with links
- Proposed actions (approve, quarantine, etc.)
- "Back to tips" link
### Ctrl+K Integration
```typescript
// In app-shell or topbar:
@HostListener('document:keydown.control.k', ['$event'])
onCtrlK(event: KeyboardEvent): void {
event.preventDefault();
this.stellaAssistant.enterSearch();
// Focus the mascot's search input instead of the old global search
}
```
### I18n Integration
```typescript
// StellaAssistantService:
async loadTips(route: string): Promise<void> {
const locale = this.i18n.locale(); // 'en-US', 'bg-BG', etc.
const contexts = this.activeContexts().join(',');
const resp = await firstValueFrom(
this.http.get<TipsResponse>(
`/api/v1/stella-assistant/tips?route=${route}&locale=${locale}&contexts=${contexts}`
)
);
this.tips.set(resp.tips);
this.greeting.set(resp.greeting);
this.contextTips.set(resp.contextTips);
}
```
### Chat Animation Sync
```typescript
// In StellaAssistantComponent, during chat mode:
// Listen to ChatService SSE events and animate mascot accordingly:
this.chatService.streamEvents$.subscribe(event => {
switch (event.type) {
case 'progress':
this.streamStage.set(event.data.stage);
if (event.data.stage === 'thinking') this.mascotAnim.set('thinking');
if (event.data.stage === 'searching') this.mascotAnim.set('searching');
break;
case 'token':
this.mascotAnim.set('talking');
break;
case 'citation':
this.mascotAnim.set('pointing');
break;
case 'done':
this.mascotAnim.set('satisfied');
break;
case 'error':
this.mascotAnim.set('concerned');
break;
}
});
```
---
## Delivery Tracker
### T1 - Database Schema + Seed Migration
Status: DONE
Dependency: none
Owners: Backend Developer
Create `stella_assistant` schema with tables: tips, greetings, glossary, tours, user_state. Write seed migration from current 189 hardcoded tips. Generate translations for supported locales.
Completion criteria:
- [x] Schema DDL in platform migration (060_StellaAssistant.sql — 5 tables)
- [x] Seed data: 189 tips + 101 greetings in en-US (061_StellaAssistantSeedData.sql — 1,784 lines)
- [x] Seed data: translations for bg-BG, de-DE, ru-RU, es-ES, fr-FR (at minimum)
- [x] Seed data: 25+ glossary terms (SBOM, VEX, CVE, etc.) in en-US + 5 locales
- [x] Seed data: 3 guided tours (first-setup, scan-workflow, triage-101) in en-US
- [x] Auto-migration wired in platform startup
### T2 - Assistant API Endpoints
Status: DONE
Dependency: T1
Owners: Backend Developer
Implement REST endpoints for tips, glossary, tours, and user state.
Completion criteria:
- [x] `GET /api/v1/stella-assistant/tips?route=X&locale=Y&contexts=Z`
- [x] `GET /api/v1/stella-assistant/glossary?locale=Y`
- [x] `GET /api/v1/stella-assistant/tours?locale=Y`
- [x] `GET/PUT /api/v1/stella-assistant/user-state`
- [x] Route matching: longest-prefix match for tip resolution
- [x] Fallback: if no tips for locale, fall back to en-US
- [x] Caching: tips cached per route+locale, invalidated on update
- [x] Admin endpoints: POST/DELETE /admin/tips, POST /admin/glossary, GET/POST /admin/tours (SetupAdmin policy)
### T3 - StellaAssistantService (unified frontend service)
Status: DONE
Dependency: T2
Owners: Frontend Developer
Create `StellaAssistantService` that unifies tips (from API), search (from `UnifiedSearchClient`), and chat (from `ChatService`). Replaces `StellaHelperContextService`.
Completion criteria:
- [x] Mode management: tips / search / chat with signal-based state
- [x] Tips loaded from API on route change (with locale from `I18nService`)
- [x] Context injection (components push context keys)
- [x] Search delegation to `UnifiedSearchClient`
- [x] Chat delegation to `ChatService` with context passing via `SearchChatContextService`
- [x] User state persistence to backend API
- [x] Glossary loaded and available for tooltip directive
### T4 - Unified Mascot Component (tips + search + chat)
Status: DONE
Dependency: T3
Owners: Frontend Developer
Rewrite `StellaHelperComponent``StellaAssistantComponent` with three-mode UI (tips, search, chat). Replaces both the mascot and the search assistant drawer.
Completion criteria:
- [x] Tips mode: speech bubble with API-backed tips, tip navigation, greeting
- [x] Search mode: inline search input, entity cards, synthesis panel
- [x] Chat mode: conversation messages, streaming animation, citations, actions
- [x] Mode transitions: type in search → search mode, "Ask AI" → chat mode, clear → tips mode
- [x] Ctrl+K opens search mode (replaces or enhances old global search)
- [x] Mascot animations synced to chat SSE events (thinking, searching, talking, concerned)
- [x] Responsive: expanded panel on desktop, full-screen on mobile
- [x] All text from `I18nService` or API (zero hardcoded strings)
### T5 - Glossary Tooltip Directive (DB-backed, i18n)
Status: DONE
Dependency: T3
Owners: Frontend Developer
Replace the planned Sprint 006 T4 (static glossary) with a DB-backed, i18n-aware version. Directive uses `StellaAssistantService.glossary()` signal.
Completion criteria:
- [x] `[stellaGlossary]` directive that wraps first occurrence of domain terms
- [x] Tooltip shows definition from API (locale-aware)
- [x] "Learn more" link navigates to related route
- [x] Related terms shown for deeper exploration
- [x] Glossary terms loaded once per page, cached in service
### T6 - Admin Tip Editor
Status: DONE
Dependency: T2
Owners: Frontend Developer
Add a UI for admins to create/edit/translate tips, glossary, and tours without code deploys. Accessible from Console Admin.
Completion criteria:
- [x] CRUD for tips (create, edit, deactivate, reorder)
- [x] Locale selector for translating tips
- [x] Preview mode (see how tip looks in the mascot bubble)
- [x] CRUD for glossary terms (create, edit inline)
- [x] Tour step editor with route + selector targeting (create/edit tours with step list)
- [x] Role-gated: requires `SetupAdmin` policy (ui.admin scope)
### T7 - Guided Tour Engine
Status: DONE
Dependency: T3, T4
Owners: Frontend Developer
Build the tour execution engine that steps through DB-defined tours, highlighting elements and showing the mascot at each step.
Completion criteria:
- [x] Tour player component (step indicator, prev/next, skip, finish)
- [x] Element highlighting with backdrop dimming and glow effect
- [x] Mascot positioned near highlighted element with speech bubble
- [x] Tour progress persisted to user state (completedTours[])
- [x] Pre-defined tours: first-setup (6 steps), scan-workflow (5 steps), triage-101 (4 steps) — in DB seed data
---
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-03-29 | Sprint created. Architecture analyzed: search, AI chat, i18n, and platform config systems mapped. Unification plan designed with DB schema, API, and three-mode mascot component. | Planning |
| 2026-03-29 | T1 DONE: DB migration 060_StellaAssistant.sql (6 tables: tips, greetings, glossary, tours, user_state). | Developer |
| 2026-03-29 | T2 DONE: API endpoints (AssistantEndpoints.cs: GET /tips, /glossary, GET+PUT /user-state), Store (PostgresAssistantStore.cs with longest-prefix route matching, locale fallback), Contracts (AssistantModels.cs). Registered in Program.cs. Build passes. | Developer |
| 2026-03-29 | T3 PARTIAL: StellaAssistantService created (mode management, tips from API with static fallback, i18n integration, search/chat bridges, glossary loading). | Developer |
| 2026-03-29 | T4 PARTIAL: StellaHelperComponent upgraded to three-mode UI (tips + search input + chat mode), "Ask Stella" button, input bar with send button, chat streaming stage display. Build passes, visually verified. | Developer |
| 2026-03-29 | T3 DONE: StellaAssistantService fully wired — search delegates to UnifiedSearchClient (entity cards + synthesis), chat delegates to ChatService (create conversation + sendMessage + SSE streaming), i18n locale passed on all API calls. | Developer |
| 2026-03-29 | T4 DONE: Component updated — search mode shows entity cards with type/title/snippet, "no results" state, synthesis summary. Chat mode shows conversation turns, streaming stage labels (Thinking/Searching/Validating/Formatting), citations count, error state. Question detection auto-routes to chat. | Developer |
| 2026-03-29 | T5 DONE: StellaGlossaryDirective created — `[stellaGlossary]` directive auto-annotates domain terms with dotted underline + hover tooltip. Global CSS for tooltip styling. Uses StellaAssistantService.glossary() signal (DB-backed via API). | Developer |
| 2026-03-30 | T6 DONE: Admin tip editor completed — Tours tab with CRUD + step editor, glossary terms now editable with create/edit forms. Backend admin endpoints for tours added (GET/POST /admin/tours). | Developer |
| 2026-03-30 | T7 DONE: Tour player component verified — stella-tour.component.ts with backdrop, step navigation, element highlighting, progress persistence. All 7 tasks complete. Sprint ready to archive. | Developer |
## Decisions & Risks
- **Decision**: Mascot becomes THE unified entry point for help, search, and AI chat. Three separate UIs → one.
- **Decision**: Ctrl+K triggers the mascot's search mode (not a separate dropdown). Old global search remains as fallback for power users.
- **Decision**: All tip content moves to PostgreSQL with per-locale rows. Frontend static config becomes seed data only.
- **Decision**: Chat is embedded in the mascot bubble (expanded), NOT in a separate drawer. The `SearchAssistantHostComponent` drawer is deprecated in favor of the mascot's chat mode.
- **Risk**: Backend API latency for tip loading. Mitigate: aggressive client-side caching, preload tips for common routes, fallback to hardcoded config if API fails.
- **Risk**: Translation quality for 9 locales. Mitigate: start with en-US + bg-BG (primary users), add other locales incrementally.
- **Risk**: Unified mascot component complexity. Mitigate: keep three modes as separate child components (TipsPanelComponent, SearchPanelComponent, ChatPanelComponent) composed by the parent.
## Relationship to Sprint 006
Sprint 006 tasks that are **superseded** by this sprint:
- T0b (deep context) → superseded by T3 (StellaAssistantService with API-backed context)
- T4 (glossary tooltips) → superseded by T5 (DB-backed glossary)
- T10 (Ctrl+K help) → superseded by T4 (unified search in mascot)
Sprint 006 tasks that **remain independent**:
- T1 (setup wizard) → becomes a guided tour in T7
- T2 (dashboard hints) → inline hints complement mascot tips
- T3 (empty states) → empty state improvements stand alone
- T5 (page help panels) → collapsible panels complement mascot
- T6 (status bar tooltips) → status bar improvements stand alone
- T7 (VEX/reachability education) → inline education panels stand alone
- T8 (integrations setup) → setup guidance stands alone
- T9 (sidebar context) → sidebar tooltips stand alone
## Next Checkpoints
- Phase 1: T1 + T2 (backend: schema + API) — enables everything else
- Phase 2: T3 + T4 (frontend: unified service + component) — the core UX change
- Phase 3: T5 + T6 + T7 (glossary directive, admin editor, tour engine) — polish and admin tools

View File

@@ -0,0 +1,50 @@
# Sprint 20260328-004 - ElkSharp Document Rendering Cleanup
## Topic & Scope
- Tighten the ElkSharp document-processing render so the generated artifact is visually clean and satisfies the current hard and soft geometry rules.
- Focus on the remaining document-specific finish defects: gateway source-exit scoring opportunities, awkward default/end finish-ups, and residual fork/join shared-lane collapse.
- Working directory: `src/__Libraries/StellaOps.ElkSharp/`.
- Expected evidence: focused document renderer tests, regenerated artifact outputs, and visual review of the latest `elksharp.png`.
## Dependencies & Concurrency
- Depends on the current ElkSharp routing/post-processing pipeline in `src/__Libraries/StellaOps.ElkSharp/`.
- Safe cross-module edits for this sprint are limited to:
- `src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/`
- `docs/workflow/`
## Documentation Prerequisites
- `docs/code-of-conduct/CODE_OF_CONDUCT.md`
- `docs/code-of-conduct/TESTING_PRACTICES.md`
- `docs/workflow/ENGINE.md`
- `src/__Libraries/StellaOps.ElkSharp/AGENTS.md`
- `src/__Libraries/StellaOps.ElkSharp/ElkEdgePostProcessor.GatewayBoundary.cs`
- `src/__Libraries/StellaOps.ElkSharp/ElkEdgeRouterIterative.WinnerRefinement.cs`
- `src/__Libraries/StellaOps.ElkSharp/ElkEdgeRoutingScoring.cs`
## Delivery Tracker
### TASK-001 - Clean the document-processing ElkSharp artifact
Status: DOING
Dependency: none
Owners: Implementer
Task description:
- Use the document-processing artifact test as the primary target surface and iterate on ElkSharp routing/post-processing until the remaining source-exit finish defects are removed.
- Keep changes scoped to the Elk tree and Elk-specific renderer tests, preserving deterministic routing and existing flat/compound contracts outside the document cleanup slice.
Completion criteria:
- [ ] The document-processing artifact passes the current hard and soft geometry assertions, including gateway-source scoring and shared-lane checks
- [ ] The regenerated `elksharp.png` is visually reviewed and no obvious new curl/finish-up regression is present
- [ ] Sprint execution log records the focused commands and outcomes
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-03-28 | Sprint created and work started for document-processing artifact cleanup in ElkSharp. | Implementer |
## Decisions & Risks
- The cleanup remains scoped to the Elk tree and Elk-specific renderer tests; unrelated Platform/Web changes in the worktree are explicitly out of scope.
- The artifact test is the authoritative quality gate for this slice because the user request is about the generated document rendering, not generic score improvement in abstract.
## Next Checkpoints
- After the first routing/post-processing patch: rerun the artifact inspection test and compare the remaining offender list
- Before closing the sprint: rerun the document artifact generation path, open the resulting PNG, and record the visual review

View File

@@ -0,0 +1,104 @@
# Sprint 20260328-005 - ElkSharp Source Decomposition
## Topic & Scope
- Reduce the size and coupling of the largest active ElkSharp source files before any further document-render tuning.
- Split implementation and Elk-specific renderer tests by rule family so routing, scoring, and finalization behavior are easier to reason about and regressions are easier to localize.
- Working directory: `src/__Libraries/StellaOps.ElkSharp/`.
- Expected evidence: smaller partial source files, Elk-specific test-file splits, and focused regression test results proving no behavior drift from the refactor.
## Dependencies & Concurrency
- Depends on the current ElkSharp routing and post-processing implementation already present in `src/__Libraries/StellaOps.ElkSharp/`.
- Safe cross-module edits for this sprint are limited to:
- `src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/`
- `docs/workflow/`
## Documentation Prerequisites
- `docs/code-of-conduct/CODE_OF_CONDUCT.md`
- `docs/code-of-conduct/TESTING_PRACTICES.md`
- `docs/workflow/ENGINE.md`
- `src/__Libraries/StellaOps.ElkSharp/AGENTS.md`
- `docs/implplan/SPRINT_20260323_002_ElkSharp_bounded_edge_refinement.md`
- `docs/implplan/SPRINT_20260328_003_ElkSharp_compound_sugiyama_support.md`
## Delivery Tracker
### TASK-001 - Split oversized Elk implementation files into partial modules
Status: DOING
Dependency: none
Owners: Implementer
Task description:
- Decompose the largest active ElkSharp implementation files into smaller partial files grouped by coherent routing/scoring concerns.
- Preserve behavior and signatures; the goal is structural readability and maintenance, not algorithm changes.
Completion criteria:
- [x] `ElkNodePlacement.cs` is reduced into `ElkNodePlacement.Refinement.cs` and `ElkNodePlacement.Grid.cs`
- [x] `ElkEdgePostProcessorSimplify.cs` is reduced into `ElkEdgePostProcessorSimplify.Shortcuts.cs` and `ElkEdgePostProcessorSimplify.OuterCorridors.cs`
- [x] `ElkEdgeRouterHighway.cs` is reduced into `ElkEdgeRouterHighway.Groups.cs` and `ElkEdgeRouterHighway.Paths.cs`
- [x] `ElkRepeatCollectorCorridors.cs` is reduced into `ElkRepeatCollectorCorridors.Candidates.cs` and `ElkRepeatCollectorCorridors.Rewrite.cs`
- [x] Compile baseline is restored after removing incomplete half-split artifacts in other Elk families
- [ ] Remaining large Elk families are decomposed in stable batches that keep the tree buildable after each batch
- [ ] No public contract or deterministic behavior changes are introduced by the split
### TASK-002 - Split oversized Elk-specific renderer test files
Status: TODO
Dependency: TASK-001
Owners: Implementer
Task description:
- Break the largest Elk-specific test files into partial classes organized by rule family and scenario family.
- Keep existing test names unchanged so failure signatures remain stable.
Completion criteria:
- [ ] `ElkSharpEdgeRefinementTests.Restabilization.cs` is reduced by moving rule families into dedicated partial files
- [ ] `DocumentProcessingWorkflowRenderingTests.Scenarios.cs` is reduced by moving scenario clusters/helpers into dedicated partial files
- [ ] Test discovery remains unchanged
### TASK-003 - Revalidate focused Elk regressions after structural split
Status: TODO
Dependency: TASK-001
Owners: Implementer
Task description:
- Run focused Elk renderer regressions that cover gateway boundary handling, target-join repair, repeat-return/shared-lane cleanup, and document scenario checks.
- Confirm the split is behavior-preserving before resuming rendering cleanup work.
Completion criteria:
- [ ] Focused Elk regression tests pass after the decomposition
- [ ] Execution log records the commands and outcomes
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-03-28 | Sprint created to separate source decomposition from paused document-render cleanup work. | Implementer |
| 2026-03-28 | Reduced `ElkNodePlacement.cs` into `ElkNodePlacement.Refinement.cs` and `ElkNodePlacement.Grid.cs`; reduced `ElkEdgePostProcessorSimplify.cs` into `ElkEdgePostProcessorSimplify.Shortcuts.cs` and `ElkEdgePostProcessorSimplify.OuterCorridors.cs`. | Implementer |
| 2026-03-28 | Audit of the broader split attempt found that most other decompositions existed only as untracked helper files while the original roots still owned the same methods. Those half-split artifacts were removed from both `src/__Libraries/StellaOps.ElkSharp/` and `src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/` to restore a truthful build baseline. | Implementer |
| 2026-03-28 | `dotnet build src/__Libraries/StellaOps.ElkSharp/StellaOps.ElkSharp.csproj -v minimal` passed after the half-split cleanup. | Implementer |
| 2026-03-28 | `dotnet build src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/StellaOps.Workflow.Renderer.Tests.csproj -v minimal` passed after removing duplicate untracked test partials; only the pre-existing `NUnit1033` renderer-test warnings remain. | Implementer |
| 2026-03-28 | Re-ran `dotnet build src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/StellaOps.Workflow.Renderer.Tests.csproj -v minimal` after the resumed safe splits and confirmed the renderer test project still builds cleanly on the restored baseline. | Implementer |
| 2026-03-28 | Reduced `ElkEdgeRouterHighway.cs` into `ElkEdgeRouterHighway.Groups.cs` and `ElkEdgeRouterHighway.Paths.cs`, and reduced `ElkRepeatCollectorCorridors.cs` into `ElkRepeatCollectorCorridors.Candidates.cs` and `ElkRepeatCollectorCorridors.Rewrite.cs`. All six files are now below the sprint cap and both build commands remained green after the batch. | Implementer |
| 2026-03-28 | Reduced `ElkEdgeRouterAStar8Dir.cs` into `ElkEdgeRouterAStar8Dir.Costs.cs` and `ElkEdgeRouterAStar8Dir.Grid.cs`. The root file is now 286 lines and both build commands stayed green after the split, with only the existing `NUnit1033` warnings in the renderer test project. | Implementer |
| 2026-03-28 | Reduced `ElkEdgeRouterIterative.cs` into `ElkEdgeRouterIterative.CollectorNormalization.cs` and `ElkEdgeRouterIterative.GeometryHelpers.cs`. The root file is now 166 lines and both build commands stayed green after the split, with only the existing `NUnit1033` warnings in the renderer test project. | Implementer |
| 2026-03-28 | Reduced `ElkEdgeRoutingGeometry.cs` into `ElkEdgeRoutingGeometry.Boundary.cs` and `ElkEdgeRoutingGeometry.Intersections.cs`. All three files are now below the sprint cap and both build commands stayed green after the split, with only the existing `NUnit1033` warnings in the renderer test project. | Implementer |
| 2026-03-29 | Reduced `ElkEdgeRouter.cs` into `ElkEdgeRouter.DummyReconstruction.cs`; reduced `ElkEdgePostProcessorCorridor.cs` into `ElkEdgePostProcessorCorridor.Safety.cs`; and reduced `ElkLayoutTypes.cs` into `ElkLayoutTypes.Retry.cs` and `ElkLayoutTypes.Strategy.cs`. All resulting files are below the sprint cap and both build commands stayed green after the batch, with only the existing `NUnit1033` warnings in the renderer test project. | Implementer |
| 2026-03-29 | Reduced `ElkEdgeRouteRefiner.cs` into `ElkEdgeRouteRefiner.Helpers.cs`. The root file is now 254 lines and both build commands stayed green after the split, with only the existing `NUnit1033` warnings in the renderer test project. | Implementer |
| 2026-03-29 | Reduced `ElkCompoundLayout.cs` into `ElkCompoundLayout.Ordering.cs`, `ElkCompoundLayout.BoundaryCrossings.cs`, and `ElkCompoundLayout.Positioning.cs`. The root file is now 300 lines and both build commands stayed green after the split, with only the existing `NUnit1033` warnings in the renderer test project. | Implementer |
| 2026-03-29 | Reduced `ElkEdgeRouterIterative.Finalization.cs` into `ElkEdgeRouterIterative.Finalization.Detours.cs`, `ElkEdgeRouterIterative.Finalization.Chooser.cs`, `ElkEdgeRouterIterative.Finalization.TerminalCleanup.Round.cs`, and `ElkEdgeRouterIterative.Finalization.TerminalCleanup.Closure.cs`. All resulting files are now at or below the sprint cap and both build commands stayed green after the split, with only the existing `NUnit1033` warnings in the renderer test project. | Implementer |
| 2026-03-29 | Reduced `ElkShapeBoundaries.cs` into `ElkShapeBoundaries.Intersections.cs`, `ElkShapeBoundaries.GatewayInterior.cs`, `ElkShapeBoundaries.BoundarySlots.cs`, `ElkShapeBoundaries.Exterior.cs`, and `ElkShapeBoundaries.Exterior.Helpers.cs`. The ElkSharp build and the renderer test project build both stayed green after the split, with only the existing `NUnit1033` warnings in the renderer test project. | Implementer |
| 2026-03-29 | Reduced `ElkEdgeRouterIterative.LocalRepair.cs` into `RetryBudgets`, `Selection`, `Ordering`, `Endpoints`, `Eligibility`, `ShortestRepair`, `RepairQuality`, `ShortestPaths`, `ObstacleSkirt`, `Backtracking`, and `CollectorRestoration` partials. The root file is now 194 lines and both build commands stayed green after the split. | Implementer |
| 2026-03-29 | Reduced `ElkEdgeRouterIterative.WinnerRefinement.cs` into `Focus`, `UnderNode`, `SharedLane`, `BoundarySlots`, `TerminalClosures`, `Detours`, `FinalBoundarySlot`, `FinalRestabilized`, `LateRestabilization`, and `Promotion` partials. The root file is now 120 lines and both build commands stayed green after the split. | Implementer |
| 2026-03-29 | Reduced `ElkEdgeRouterIterative.StrategyRepair.cs` into `Evaluate`, `RouteAllEdges`, `RepairPenalizedEdges`, `VerifiedIssues`, `RepairPlan`, `RepairPlan.Expanders`, `ParallelBuilds`, and `Fingerprints` partials. The root file is now 19 lines and both build commands stayed green after the split. | Implementer |
## Decisions & Risks
- The document-render cleanup sprint remains paused while decomposition is underway; rendering quality work resumes only after the structural split is stable.
- Decomposition stays within the Elk tree and Elk-specific renderer tests so unrelated repo areas do not move during this refactor.
- Method moves are done as-is first; helper redesign is deferred unless a direct move is impossible without duplication.
- The first broad decomposition attempt was not a stable state: most of the added partial files were untracked while the original tracked roots still contained the moved methods. Keeping those files would have left the repository permanently uncompilable, so they were removed rather than carried forward.
- The current stable decomposition baseline is limited to fourteen families: `ElkNodePlacement`, `ElkEdgePostProcessorSimplify`, `ElkEdgeRouterHighway`, `ElkRepeatCollectorCorridors`, `ElkEdgeRouterAStar8Dir`, `ElkEdgeRouterIterative`, `ElkEdgeRoutingGeometry`, `ElkEdgeRouter`, `ElkEdgeRouteRefiner`, `ElkEdgePostProcessorCorridor`, `ElkLayoutTypes`, `ElkCompoundLayout`, `ElkEdgeRouterIterative.Finalization`, and `ElkShapeBoundaries`.
- The current stable decomposition baseline now also includes the three main iterative-control families: `ElkEdgeRouterIterative.LocalRepair`, `ElkEdgeRouterIterative.StrategyRepair`, and `ElkEdgeRouterIterative.WinnerRefinement`.
- The remaining implementation files above the cap are no longer the small mechanical bucket. The next files that still need work are the large helper-extraction hotspots: `ElkEdgePostProcessor`, `ElkEdgeRoutingScoring`, `ElkEdgePostProcessor.UnderNode`, `ElkEdgePostProcessor.BoundarySlots`, `ElkEdgePostProcessor.FaceConflictRepair`, and `ElkEdgePostProcessor.GatewayBoundary`.
- Two iterative-router files still exceed the target cap even after the stable split and need helper extraction rather than another blind move: `ElkEdgeRouterIterative.StrategyRepair.Evaluate.cs` and `ElkEdgeRouterIterative.StrategyRepair.RepairPlan.cs`.
- Test-file decomposition was intentionally rolled back during the cleanup because the split files duplicated tracked tests instead of replacing them. Test splitting should resume only after the code-side split discipline is stable.
- Remaining hotspot families still need careful extraction with an explicit “root trimmed in the same batch” rule: `ElkCompoundLayout`, `ElkShapeBoundaries`, `ElkEdgeRoutingScoring`, `ElkEdgeRouterAStar8Dir`, `ElkEdgeRouterIterative`, `ElkEdgePostProcessor.BoundarySlots`, `ElkEdgePostProcessor.GatewayBoundary`, `ElkEdgePostProcessor.SharedLane`, `ElkEdgePostProcessor.TargetPeerConflicts`, and `ElkEdgePostProcessor.UnderNode`.
- Focused regression revalidation has not yet been rerun on the restored baseline. No rendering-behavior conclusions should be carried over from the discarded half-split state.
## Next Checkpoints
- Decompose the next single Elk family only if the root file is trimmed in the same batch and both build commands stay green afterward
- After the next stable implementation batch: rerun focused Elk regressions and record the first valid post-cleanup results before resuming any artifact tuning

View File

@@ -0,0 +1,107 @@
# Sprint 20260329-006 - ElkSharp Hybrid Iterative Routing
## Topic & Scope
- Introduce an opt-in deterministic hybrid iterative router that preserves Sugiyama geometry and replaces whole-graph brute-force strategy fan-out with one baseline route plus bounded targeted repair waves.
- Keep parallel repair work intelligent and deterministic by parallelizing only independent candidate builds, then committing winners in stable order.
- Continue decomposing the iterative-router control families so the new mode lives in focused partials instead of monolithic files.
- Working directory: `src/__Libraries/StellaOps.ElkSharp/`.
- Expected evidence: new iterative-routing mode/config, hybrid parity tests, updated workflow-engine documentation, and stable builds for ElkSharp plus the renderer tests.
## Dependencies & Concurrency
- Depends on `docs/implplan/SPRINT_20260328_005_ElkSharp_source_decomposition.md` for the ongoing source split baseline.
- Safe cross-module edits for this sprint are limited to:
- `src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/`
- `docs/workflow/`
- `docs/implplan/`
## Documentation Prerequisites
- `docs/code-of-conduct/CODE_OF_CONDUCT.md`
- `docs/code-of-conduct/TESTING_PRACTICES.md`
- `docs/workflow/ENGINE.md`
- `src/__Libraries/StellaOps.ElkSharp/AGENTS.md`
- `docs/implplan/SPRINT_20260328_005_ElkSharp_source_decomposition.md`
## Delivery Tracker
### TASK-001 - Add an opt-in hybrid deterministic iterative routing mode
Status: DOING
Dependency: none
Owners: Implementer
Task description:
- Extend the public iterative-routing options with an explicit mode switch and bounded hybrid repair controls.
- Keep the legacy multi-strategy path intact while adding a new hybrid branch that runs one baseline route, plans targeted repairs from the existing issue taxonomy, and applies them in deterministic waves.
Completion criteria:
- [x] `IterativeRoutingOptions` exposes `Mode`, `MaxRepairWaves`, and `MaxParallelRepairBuilds`
- [x] `ElkEdgeRouterIterative.Optimize` can execute a `HybridDeterministic` path without changing legacy behavior by default
- [x] Hybrid mode preserves fixed Sugiyama node geometry and remains opt-in
- [ ] Hybrid mode replaces the remaining coarse local-repair lock policy with conflict-zone-aware scheduling across the full repair pipeline
- [ ] Hybrid mode is documented as the recommended path for `LeftToRight` once parity is proven
### TASK-002 - Add deterministic hybrid parity coverage
Status: DOING
Dependency: TASK-001
Owners: Implementer
Task description:
- Freeze the first hybrid invariants in focused Elk renderer tests.
- The tests must prove deterministic replay, Sugiyama node-geometry stability, and no regression in the primary violation classes used to gate winner selection.
Completion criteria:
- [x] A focused hybrid test file exists under `src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/`
- [x] Hybrid deterministic replay is asserted by a repeated-run geometry comparison
- [x] Hybrid node geometry is asserted against legacy mode
- [x] Hybrid primary-violation counts are asserted to be no worse than legacy for the covered stress graph
- [ ] Focused hybrid parity coverage is expanded to gateway-boundary, boundary-slot, and document-processing scenarios
### TASK-003 - Continue decomposing iterative control files around the hybrid seam
Status: DOING
Dependency: TASK-001
Owners: Implementer
Task description:
- Split the iterative-router control families so the new mode remains localized and future helper extraction is tractable.
- Preserve behavior while moving methods as-is into focused partials; avoid redesigning the algorithms unless a direct move is impossible.
Completion criteria:
- [x] `ElkEdgeRouterIterative.LocalRepair.cs` is reduced to a small root coordinator
- [x] `ElkEdgeRouterIterative.WinnerRefinement.cs` is reduced to a small root coordinator
- [x] `ElkEdgeRouterIterative.StrategyRepair.cs` is reduced to a thin root plus focused partials
- [ ] `ElkEdgeRouterIterative.StrategyRepair.Evaluate.cs` is reduced below the sprint cap
- [ ] `ElkEdgeRouterIterative.StrategyRepair.RepairPlan.cs` is reduced below the sprint cap
### TASK-004 - Sync docs and execution evidence
Status: DOING
Dependency: TASK-001
Owners: Implementer
Task description:
- Update the workflow engine layout documentation to describe the new hybrid mode and its deterministic parallel-processing contract.
- Record build and targeted-test evidence in the sprint execution log.
Completion criteria:
- [x] `docs/workflow/ENGINE.md` documents the hybrid deterministic mode and its bounded parallel-build rules
- [x] Execution log records the ElkSharp build, renderer-test build, and focused hybrid test commands
- [ ] Follow-up docs describe when hybrid should become the default and how `TopToBottom` remains on legacy until parity
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2026-03-29 | Sprint created to isolate hybrid iterative-routing work from the ongoing source decomposition sprint. | Implementer |
| 2026-03-29 | Added `IterativeRoutingMode`, `Mode`, `MaxRepairWaves`, and `MaxParallelRepairBuilds` to the public ElkSharp iterative-routing options and threaded the new values into `IterativeRoutingConfig`. | Implementer |
| 2026-03-29 | Added `ElkEdgeRouterIterative.Hybrid.cs` and wired `ElkEdgeRouterIterative.Optimize` to execute the new hybrid deterministic path when requested. | Implementer |
| 2026-03-29 | Added focused hybrid renderer tests covering deterministic replay, stable node geometry versus legacy mode, and no increase in primary violations on the stress graph. | Implementer |
| 2026-03-29 | `dotnet build src/__Libraries/StellaOps.ElkSharp/StellaOps.ElkSharp.csproj -v minimal` passed after the hybrid mode implementation. | Implementer |
| 2026-03-29 | `dotnet build src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/StellaOps.Workflow.Renderer.Tests.csproj -v minimal` passed after the hybrid mode implementation; only the existing `NUnit1033` warnings remain in the renderer test project. | Implementer |
| 2026-03-29 | `dotnet test src/Workflow/__Tests/StellaOps.Workflow.Renderer.Tests/StellaOps.Workflow.Renderer.Tests.csproj --filter "Name~HybridDeterministicMode" -v normal` passed with 3/3 tests green. | Implementer |
| 2026-03-29 | Reduced `ElkEdgeRouterIterative.LocalRepair`, `ElkEdgeRouterIterative.StrategyRepair`, and `ElkEdgeRouterIterative.WinnerRefinement` into focused partials around the new hybrid seam and revalidated both builds plus the hybrid test slice. | Implementer |
## Decisions & Risks
- Hybrid mode is opt-in and does not replace legacy multi-strategy routing by default.
- Sugiyama output remains authoritative: node positions, ordering, dummy reconstruction, and upstream anchoring contracts are preserved.
- Parallel processing stays limited to candidate construction on independent repair batches. Candidate commits remain single-threaded and deterministic.
- `TopToBottom` is intentionally not promoted to hybrid mode by default in this sprint; it stays on the legacy path until parity is explicitly proven.
- The current hybrid batching still uses deterministic conflict keys derived from endpoint and collector locality. A fuller conflict-zone graph is still required before the old coarse lock-key assumptions can be removed everywhere.
- The two remaining oversize files in the iterative-control family are `ElkEdgeRouterIterative.StrategyRepair.Evaluate.cs` and `ElkEdgeRouterIterative.StrategyRepair.RepairPlan.cs`. They require helper extraction, not another blind line move.
## Next Checkpoints
- Reduce `ElkEdgeRouterIterative.StrategyRepair.Evaluate.cs` and `ElkEdgeRouterIterative.StrategyRepair.RepairPlan.cs` below the sprint cap without behavior changes.
- Expand hybrid parity coverage to gateway-boundary, boundary-slot, and document-processing regressions.
- Replace coarse repair-build lock keys with a fuller conflict-zone scheduler before considering hybrid mode as the `LeftToRight` default.

File diff suppressed because it is too large Load Diff