search and ai stabilization work, localization stablized.

This commit is contained in:
master
2026-02-24 23:29:36 +02:00
parent 4f947a8b61
commit b07d27772e
766 changed files with 55299 additions and 3221 deletions

View File

@@ -85,6 +85,9 @@ Implemented in `src/AdvisoryAI/StellaOps.AdvisoryAI/KnowledgeSearch/KnowledgeSea
## API contract
### Search
- `POST /v1/advisory-ai/search`
- Legacy notice: endpoint emits deprecation metadata and points to unified replacement `POST /v1/search/query`.
- Authorization: `advisory-ai:operate` (or `advisory-ai:admin`).
- Filter validation: `filters.type` allowlist is strictly enforced (`docs`, `api`, `doctor`); unsupported values return HTTP 400.
- Request:
- `q` (required), `k`, `filters.type|product|version|service|tags`, `includeDebug`.
- Response:
@@ -93,6 +96,40 @@ Implemented in `src/AdvisoryAI/StellaOps.AdvisoryAI/KnowledgeSearch/KnowledgeSea
### Rebuild
- `POST /v1/advisory-ai/index/rebuild`
- Rebuilds AKS deterministically from local docs/specs/doctor metadata.
- Authorization: `advisory-ai:admin`.
## Localization runtime contract
- AdvisoryAI WebService localization is enabled through `AddStellaOpsLocalization(...)`, embedded service bundles (`Translations/*.advisoryai.json`), and `AddRemoteTranslationBundles()`.
- Locale behavior follows backend contract: `X-Locale` -> `Accept-Language` -> default locale.
- Supported service locales for this rollout slice: `en-US`, `de-DE`.
- Remote translation bundles are enabled when Platform base URL is configured via `STELLAOPS_PLATFORM_URL`, `Platform:BaseUrl`, or `StellaOps:Platform:BaseUrl`.
- Localized validation keys used by both `POST /v1/advisory-ai/search` and `POST /v1/search/query`:
- `advisoryai.validation.q_required`
- `advisoryai.validation.q_max_512`
- `advisoryai.validation.tenant_required`
## Unified search interoperability
- Unified endpoint: `POST /v1/search/query`.
- Query validation: `q` is required and capped at 512 characters.
- Tenant validation: unified and AKS search endpoints now require tenant context (`X-StellaOps-Tenant` or `X-Tenant-Id`) and bind tenant into backend search filters.
- Unified filter allowlists are enforced server-side:
- Supported `filters.domains`: `knowledge`, `findings`, `vex`, `policy`, `platform`.
- Supported `filters.entityTypes`: `docs`, `api`, `doctor`, `finding`, `vex_statement`, `policy_rule`, `platform_entity`.
- Unsupported domain/entity filter values are rejected with HTTP 400; they are not silently broadened to an unfiltered query.
- Unified index lifecycle:
- Manual rebuild endpoint: `POST /v1/search/index/rebuild`.
- Optional background refresh loop is available via `KnowledgeSearchOptions` (`UnifiedAutoIndexEnabled`, `UnifiedAutoIndexOnStartup`, `UnifiedIndexRefreshIntervalSeconds`).
- Unified ingestion adapters now ingest from deterministic snapshot files (findings/vex/policy) plus platform catalog projection, replacing hardcoded sample chunks.
- Default snapshot paths:
- `src/AdvisoryAI/StellaOps.AdvisoryAI/UnifiedSearch/Snapshots/findings.snapshot.json`
- `src/AdvisoryAI/StellaOps.AdvisoryAI/UnifiedSearch/Snapshots/vex.snapshot.json`
- `src/AdvisoryAI/StellaOps.AdvisoryAI/UnifiedSearch/Snapshots/policy.snapshot.json`
- Ranking determinism:
- Freshness boost is disabled by default and only applies when `UnifiedFreshnessBoostEnabled` is explicitly enabled.
- Ranking no longer depends on ambient wall-clock time unless that option is enabled.
- Query telemetry:
- Unified search emits hashed query telemetry (`SHA-256` query hash, intent, domain weights, latency, top domains) via `IUnifiedSearchTelemetrySink`.
- Web fallback behavior: when unified search fails, `UnifiedSearchClient` falls back to legacy AKS (`/v1/advisory-ai/search`) and maps grouped legacy results into unified cards (`diagnostics.mode = legacy-fallback`).
## Web behavior
Global search now consumes AKS and supports:
@@ -143,7 +180,219 @@ stella advisoryai index rebuild --json
dotnet test src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj
```
## Search improvement sprints (G1G10) — testing infrastructure guide
Ten search improvement sprints (SPRINT_20260224_101 through SPRINT_20260224_110) were implemented as a batch. This section documents how to set up infrastructure and run the full test suite.
### Sprint inventory
| Sprint | Gap | Topic | Module(s) |
| --- | --- | --- | --- |
| 101 | G5 | FTS English stemming + trigram fuzzy | AdvisoryAI (backend) |
| 102 | G1 | ONNX semantic vector encoder | AdvisoryAI (backend) |
| 103 | G2 | Cross-domain live-data adapters | AdvisoryAI (backend) |
| 104 | G3 | LLM-grounded synthesis engine | AdvisoryAI (backend) |
| 105 | G4 | Search onboarding + guided discovery + "Did you mean?" | FE + AdvisoryAI |
| 106 | G6 | Search personalization (popularity boost, role-based bias, history) | AdvisoryAI + FE |
| 107 | G7 | Search → Chat bridge ("Ask AI" button) | FE |
| 108 | G8 | Inline result previews (expandable entity cards) | AdvisoryAI + FE |
| 109 | G9 | Multilingual search (de/fr/es/ru FTS, language detection, localized doctor seeds) | AdvisoryAI + FE |
| 110 | G10 | Search feedback loop (thumbs up/down, quality dashboard, query refinements) | AdvisoryAI + FE |
### Test projects and files
All backend tests live in a single test project:
```
src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj
```
Key test files added by the search sprints:
| File | Coverage | Type |
| --- | --- | --- |
| `Integration/UnifiedSearchSprintIntegrationTests.cs` | All 10 sprints (87 tests) — endpoint auth, domain filtering, synthesis, suggestions, role-based bias, multilingual detection, feedback validation | Integration (WebApplicationFactory) |
| `Integration/KnowledgeSearchEndpointsIntegrationTests.cs` | AKS endpoints: auth, search, localization, rebuild | Integration (WebApplicationFactory) |
| `KnowledgeSearch/FtsRecallBenchmarkTests.cs` | G5-005: FTS recall benchmark (12 tests, 34-query fixture) | Benchmark |
| `KnowledgeSearch/FtsRecallBenchmarkStore.cs` | In-memory FTS store simulating Simple vs English modes | Test harness |
| `KnowledgeSearch/SemanticRecallBenchmarkTests.cs` | G1-004: Semantic recall benchmark (13 tests, 48-query fixture) | Benchmark |
| `KnowledgeSearch/SemanticRecallBenchmarkStore.cs` | In-memory vector store with cosine similarity search | Test harness |
| `UnifiedSearch/UnifiedSearchServiceTests.cs` | G8: Preview generation (7 tests) | Unit |
Test data fixtures (auto-copied to output via `TestData/*.json` glob in .csproj):
- `TestData/fts-recall-benchmark.json` — 34 queries across exact/stemming/typos/short/natural categories
- `TestData/semantic-recall-benchmark.json` — 48 queries across synonym/paraphrase/conceptual/acronym/exact categories
### Prerequisites to run
**Detailed infrastructure setup guide**: `src/AdvisoryAI/__Tests/INFRASTRUCTURE.md` — covers 4 tiers (in-process, live database, ONNX model, frontend E2E) with exact Docker commands, connection strings, extension requirements, and config examples.
**No external infrastructure needed for the in-process test suite.** All integration tests use `WebApplicationFactory<Program>` with stubbed services. Benchmarks use in-memory stores. No PostgreSQL, no Docker, no network access required.
Run the full suite:
```bash
dotnet test "src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj" -v normal
```
Run only the search sprint integration tests:
```bash
dotnet test "src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj" \
--filter "FullyQualifiedName~UnifiedSearchSprintIntegrationTests" -v normal
```
Run only the FTS recall benchmark:
```bash
dotnet test "src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj" \
--filter "FullyQualifiedName~FtsRecallBenchmarkTests" -v normal
```
Run only the semantic recall benchmark:
```bash
dotnet test "src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj" \
--filter "FullyQualifiedName~SemanticRecallBenchmarkTests" -v normal
```
**For live database tests** (e.g., full AKS rebuild + query against real Postgres with pg_trgm/pgvector):
```bash
# Start the dedicated AKS test database
docker compose -f devops/compose/docker-compose.advisoryai-knowledge-test.yml up -d
# Wait for health check
docker compose -f devops/compose/docker-compose.advisoryai-knowledge-test.yml ps
# Prepare sources and rebuild index
stella advisoryai sources prepare --json
stella advisoryai index rebuild --json
# Run tests with the Live category (requires database)
dotnet test "src/AdvisoryAI/__Tests/StellaOps.AdvisoryAI.Tests/StellaOps.AdvisoryAI.Tests.csproj" \
--filter "Category=Live" -v normal
```
Or use the full CI testing stack:
```bash
docker compose -f devops/compose/docker-compose.testing.yml --profile ci up -d
```
### Database extensions required for live tests
The AKS knowledge test database init script (`devops/compose/postgres-init/advisoryai-knowledge-test/01_extensions.sql`) must enable:
- `vector` (pgvector) — for `embedding_vec vector(384)` columns and cosine similarity
- `pg_trgm` — for trigram fuzzy matching (`similarity()`, GIN trigram indexes)
These are already configured in the compose init scripts. If setting up a custom test database:
```sql
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
```
### Migrations required for search sprints
The search sprints added several migrations under `src/AdvisoryAI/StellaOps.AdvisoryAI/Storage/Migrations/`:
| Migration | Sprint | Content |
| --- | --- | --- |
| `004_fts_english_config.sql` | G5 (101) | `body_tsv_en` tsvector column + GIN index, pg_trgm extension + trigram indexes |
| `005_search_feedback.sql` | G10 (110) | `search_feedback` + `search_quality_alerts` tables |
| `005_search_analytics.sql` | G6 (106) | `search_events` + `search_history` tables |
| `007_multilingual_fts.sql` | G9 (109) | `body_tsv_de`, `body_tsv_fr`, `body_tsv_es`, `body_tsv_ru` tsvector columns + GIN indexes |
All migrations are idempotent (IF NOT EXISTS guards). They run automatically via `EnsureSchemaAsync()` at service startup.
### Frontend tests
Frontend changes span `src/Web/StellaOps.Web/`. To run Angular unit tests:
```bash
cd src/Web/StellaOps.Web
npm install
npm run test:ci
```
For E2E tests (requires the full stack running):
```bash
cd src/Web/StellaOps.Web
npx playwright install
npm run test:e2e
```
Relevant E2E config: `src/Web/StellaOps.Web/playwright.e2e.config.ts`.
### InternalsVisibleTo
The production assembly `StellaOps.AdvisoryAI` grants `InternalsVisibleTo` to `StellaOps.AdvisoryAI.Tests` (see `src/AdvisoryAI/StellaOps.AdvisoryAI/Properties/AssemblyInfo.cs`). This allows tests to access `internal` types including:
- `IVectorEncoder`, `DeterministicHashVectorEncoder`, `OnnxVectorEncoder`
- `ISynthesisEngine`, `SynthesisTemplateEngine`, `CompositeSynthesisEngine`, `LlmSynthesisEngine`
- `IntentClassifier`, `QueryLanguageDetector`, `MultilingualIntentKeywords`, `DomainWeightCalculator`
- `SearchAnalyticsService`, `SearchQualityMonitor`
- `WeightedRrfFusion`, `UnifiedSearchService`
- `IKnowledgeSearchStore`, `KnowledgeChunkRow`
### Key interfaces to stub in integration tests
| Interface | Purpose | Typical stub behavior |
| --- | --- | --- |
| `IKnowledgeSearchService` | AKS search | Return hardcoded results per query |
| `IKnowledgeIndexer` | AKS index rebuild | Return fixed summary counts |
| `IUnifiedSearchService` | Unified search | Return entity cards with domain filtering |
| `IUnifiedSearchIndexer` | Unified index rebuild | Return fixed summary |
| `ISynthesisEngine` | AI synthesis | Return template-based synthesis |
| `IVectorEncoder` | Embedding generation | Use `DeterministicHashVectorEncoder` or `EmptyVectorEncoder` |
| `IKnowledgeSearchStore` | FTS/vector storage | Use `DeterministicBenchmarkStore` or `FtsRecallBenchmarkStore` |
### Test categories and filtering
Use `[Trait("Category", TestCategories.XXX)]` to categorize tests. Key categories:
- `Unit` — fast, in-memory, no external deps (default for most tests)
- `Integration` — uses `WebApplicationFactory` or test containers
- `Performance` — benchmarks (FTS recall, semantic recall)
- `Live` — requires running database (skip in standard CI)
Filter examples:
```bash
# All except Live
dotnet test ... --filter "Category!=Live"
# Only integration
dotnet test ... --filter "Category=Integration"
# Specific test class
dotnet test ... --filter "FullyQualifiedName~FtsRecallBenchmarkTests"
```
### Localized doctor seeds
Doctor check content is available in 3 locales:
- `doctor-search-seed.json` — English (base, 8 checks)
- `doctor-search-seed.de.json` — German (de-DE)
- `doctor-search-seed.fr.json` — French (fr-FR)
The `KnowledgeIndexer.IngestDoctorAsync()` method auto-discovers locale files via `DoctorSearchSeedLoader.LoadLocalized()` and ingests locale-tagged chunks alongside English. This enables German/French FTS queries to match doctor check content.
### Configuration options added by search sprints
All in `KnowledgeSearchOptions` (`src/AdvisoryAI/StellaOps.AdvisoryAI/KnowledgeSearch/KnowledgeSearchOptions.cs`):
| Option | Default | Sprint | Purpose |
| --- | --- | --- | --- |
| `FtsLanguageConfig` | `"english"` | G5 | Primary FTS text search config |
| `FuzzyFallbackEnabled` | `true` | G5 | Enable pg_trgm fuzzy fallback |
| `MinFtsResultsForFuzzyFallback` | `3` | G5 | Threshold for fuzzy activation |
| `FuzzySimilarityThreshold` | `0.3` | G5 | pg_trgm similarity cutoff |
| `VectorEncoderType` | `"hash"` | G1 | `"hash"` or `"onnx"` |
| `OnnxModelPath` | `"models/all-MiniLM-L6-v2.onnx"` | G1 | Path to ONNX model file |
| `LlmSynthesisEnabled` | `false` | G3 | Enable LLM-grounded synthesis |
| `SynthesisTimeoutMs` | `5000` | G3 | LLM synthesis timeout |
| `LlmAdapterBaseUrl` | `null` | G3 | LLM adapter service URL |
| `LlmProviderId` | `null` | G3 | LLM provider selection |
| `PopularityBoostEnabled` | `false` | G6 | Enable click-weighted ranking |
| `PopularityBoostWeight` | `0.1` | G6 | Popularity boost factor |
| `RoleBasedBiasEnabled` | `false` | G6 | Enable scope-based domain weighting |
| `FtsLanguageConfigs` | `{}` | G9 | Per-locale FTS config map |
## Known limitations and follow-ups
- YAML OpenAPI ingestion is not included in MVP.
- End-to-end benchmark against live Postgres-backed AKS service is planned as a follow-up CI lane.
- Optional external embedding providers can be added later without changing API contracts.
- ONNX model file (`all-MiniLM-L6-v2.onnx`, ~80MB) must be provisioned separately for deployments opting into `VectorEncoderType=onnx`. Air-gap bundles must include the model.
- Doctor seed localization covers de-DE and fr-FR only. Other locales (es-ES, ru-RU, bg-BG, etc.) use English fallback.
- Search quality dashboard deferred items: low-quality results table, top queries table, 30-day trend chart (require additional backend aggregation queries).
- Periodic `SearchQualityMonitor` background job not yet wired (zero-result alerting runs on-demand via metrics endpoint).

View File

@@ -235,16 +235,36 @@ public interface IBaselineResolver
* `offline kit import <tar>` — upload the kit to onâ€prem services (Concelier/Excititor).
* `offline kit status` — list current seed versions.
### 2.8 Utilities
* `config set/get` — endpoint & defaults.
* `whoami` — short auth display.
* `version` — CLI + protocol versions; release channel.
* `tools policy-dsl-validate <paths...> [--strict] [--json]`
* `tools policy-schema-export [--output <dir>] [--repo-root <path>]`
* `tools policy-simulation-smoke [--scenario-root <path>] [--output <dir>] [--repo-root <path>] [--fixed-time <ISO-8601>]`
### 2.9 Aggregation-only guard helpers
### 2.8 Utilities
* `config set/get` — endpoint & defaults.
* `whoami` — short auth display.
* `version` — CLI + protocol versions; release channel.
* `tools policy-dsl-validate <paths...> [--strict] [--json]`
* `tools policy-schema-export [--output <dir>] [--repo-root <path>]`
* `tools policy-simulation-smoke [--scenario-root <path>] [--output <dir>] [--repo-root <path>] [--fixed-time <ISO-8601>]`
### 2.8.1 User locale preference commands
* `tenants locale list [--tenant <id>] [--json]`
* Fetches tenant-visible locale catalog from Platform `GET /api/v1/platform/localization/locales`.
* Provides the canonical locale set used by both CLI and UI selection controls.
* Supports deterministic text output or JSON payload (`locales`, `count`) for automation.
* `tenants locale get [--tenant <id>] [--json]`
* Fetches the authenticated actor's persisted locale preference from Platform `GET /api/v1/platform/preferences/language`.
* Resolves tenant context from `--tenant`, then `STELLAOPS_TENANT`, then active tenant profile.
* Prints deterministic text output by default (`tenant`, `locale`, `updated`) and optional JSON payload for automation.
* `tenants locale set <locale> [--tenant <id>] [--json]`
* Writes the authenticated actor's persisted locale preference through Platform `PUT /api/v1/platform/preferences/language`.
* Supported locale set is service-validated (`en-US`, `de-DE`, `bg-BG`, `ru-RU`, `es-ES`, `fr-FR`, `uk-UA`, `zh-TW`, `zh-CN`); CLI pre-validates against the platform locale catalog when available.
* This command shares the same preference record consumed by the Web shell locale selector so locale choice follows the user across Web and CLI sessions.
### 2.9 Aggregation-only guard helpers
* `sources ingest --dry-run --source <id> --input <path|uri> [--tenant ... --format table|json --output file]`

View File

@@ -59,11 +59,18 @@ The edge metadata system provides explainability for graph relationships:
- **EdgeReason** enum: `Unknown`, `SbomDependency`, `StaticSymbol`, `RuntimeTrace`, `PackageManifest`, `Lockfile`, `BuildArtifact`, `ImageLayer`, `AdvisoryAffects`, `VexStatement`, `PolicyOverlay`, `AttestationRef`, `OperatorAnnotation`, `TransitiveInference`, `Provenance`.
- **EdgeVia** record: Describes how the edge was discovered (method, version, timestamp, confidence in basis points, evidence reference).
- **EdgeExplanationPayload** record: Full explanation including reason, via, human-readable summary, evidence list, provenance reference, and tags.
- **EdgeProvenanceRef** record: Source system, collection timestamp, SBOM digest, scan digest, attestation ID, event offset.
- **EdgeTileWithMetadata** record: Extends `EdgeTile` with `Explanation` property containing the full metadata.
## 4) Storage considerations
- **EdgeExplanationPayload** record: Full explanation including reason, via, human-readable summary, evidence list, provenance reference, and tags.
- **EdgeProvenanceRef** record: Source system, collection timestamp, SBOM digest, scan digest, attestation ID, event offset.
- **EdgeTileWithMetadata** record: Extends `EdgeTile` with `Explanation` property containing the full metadata.
### 3.3) Localization runtime contract (Sprint 20260224_002)
- Graph API now initializes localization via `AddStellaOpsLocalization(...)`, `AddTranslationBundle(...)`, `AddRemoteTranslationBundles()`, `UseStellaOpsLocalization()`, and `LoadTranslationsAsync()`.
- Locale resolution order for API messages is deterministic: `X-Locale` header -> `Accept-Language` header -> default locale (`en-US`).
- Translation layering is deterministic: shared embedded `common` bundle -> Graph embedded bundle (`Translations/*.graph.json`) -> Platform runtime override bundle.
- This rollout localizes selected error paths (for example, edge/export not found, invalid reason, and tenant/auth validation text) for `en-US` and `de-DE`.
## 4) Storage considerations
- Backed by either:
- **Relational + adjacency** (PostgreSQL tables `graph_nodes`, `graph_edges`, `graph_overlays`) with deterministic ordering and streaming exports.

View File

@@ -13,6 +13,7 @@ Provide a single, deterministic aggregation layer for cross-service UX workflows
- Aggregate quota usage across Authority, Gateway, Orchestrator, and storage backends.
- Persist onboarding progress and tenant setup milestones.
- Persist dashboard personalization and layout preferences.
- Persist authenticated user language preference for shared Web/CLI locale selection.
- Provide global search aggregation across entities.
- Provide global context selectors (region/environment/time window) and per-user persistence for Pack 22 top-bar context.
- Provide Pack 22 release read-model projections for list/detail/activity/approvals queue views.
@@ -43,6 +44,8 @@ Provide a single, deterministic aggregation layer for cross-service UX workflows
### Preferences
- GET `/api/v1/platform/preferences/dashboard`
- PUT `/api/v1/platform/preferences/dashboard`
- GET `/api/v1/platform/preferences/language`
- PUT `/api/v1/platform/preferences/language`
- GET `/api/v1/platform/dashboard/profiles`
- GET `/api/v1/platform/dashboard/profiles/{profileId}`
- POST `/api/v1/platform/dashboard/profiles`
@@ -50,11 +53,24 @@ Provide a single, deterministic aggregation layer for cross-service UX workflows
### Global search
- GET `/api/v1/search` (alias to `/api/v1/platform/search`)
- GET `/api/v1/platform/search`
- Legacy notice: both endpoints now emit deprecation metadata (`Deprecation`, `Sunset`, `Link`, `Warning`) and are being replaced by Unified Search `POST /api/v1/search/query`.
### Metadata
- GET `/api/v1/platform/metadata`
- Response includes a capabilities list for UI bootstrapping; analytics capability is reported only when analytics storage is configured.
### Localization
- GET `/platform/i18n/{locale}.json` (anonymous, cacheable UI translation bundle)
- GET `/api/v1/platform/localization/bundles/{locale}`
- GET `/api/v1/platform/localization/bundles/{locale}/{namespace}`
- GET `/api/v1/platform/localization/locales` (catalog used by Web and CLI locale selectors)
- PUT `/api/v1/platform/localization/bundles`
- DELETE `/api/v1/platform/localization/strings/{locale}/{key}`
- Backend locale resolution contract: `X-Locale` -> `Accept-Language` -> default locale.
- Runtime bundle layering consumed by backend services: shared embedded `common` -> service embedded bundle -> Platform override bundle.
- Platform ships locale-complete `ui` and `platform` namespace bundles for `en-US`, `de-DE`, `bg-BG`, `ru-RU`, `es-ES`, `fr-FR`, `uk-UA`, `zh-TW`, `zh-CN`; shared localization library now provides `common` bundles for the same locale set.
- Bundled locales currently shipped: `en-US`, `de-DE`, `bg-BG`, `ru-RU`, `es-ES`, `fr-FR`, `uk-UA`, `zh-TW`, `zh-CN`.
## API surface (v2)
### Global context
@@ -108,11 +124,12 @@ Provide a single, deterministic aggregation layer for cross-service UX workflows
- Alias usage telemetry is emitted as deterministic event keys (`alias_<method>_<route_pattern>`) with tenant hash metadata only.
## Data model
- `platform.dashboard_preferences` (dashboard layout, widgets, filters)
- `platform.dashboard_preferences` (dashboard layout, widgets, filters, optional user `locale` preference key)
- `platform.dashboard_profiles` (saved profiles per tenant)
- `platform.onboarding_state` (step state, timestamps, actor)
- `platform.quota_alerts` (per-tenant quota alert thresholds)
- `platform.search_history` (optional, user-scoped, append-only)
- `platform.translations` (tenant + locale scoped translation override store)
- `platform.context_regions` (global region selector inventory)
- `platform.context_environments` (global environment selector inventory with region linkage)
- `platform.ui_context_preferences` (tenant + actor scoped region/environment/time-window selections)

View File

@@ -31,6 +31,13 @@ The service operates strictly downstream of the **Aggregation-Only Contract (AOC
Non-goals: policy authoring UI (handled by Console), ingestion or advisory normalisation (Concelier), VEX consensus (Excititor), runtime enforcement (Zastava).
### 1.1 · Localization runtime contract (Sprint 20260224_002)
- Policy Gateway now initializes StellaOps localization with `AddStellaOpsLocalization(...)`, `AddTranslationBundle(...)`, `AddRemoteTranslationBundles()`, `UseStellaOpsLocalization()`, and `LoadTranslationsAsync()`.
- Locale resolution order for request-facing strings is deterministic: `X-Locale` header -> `Accept-Language` header -> default locale (`en-US`).
- Translation sources are layered deterministically: shared embedded `common` bundle -> Policy embedded bundle (`Translations/*.policy.json`) -> Platform runtime override bundle.
- The rollout localizes selected request validation and readiness responses for `en-US` and `de-DE`.
---
## 2·High-Level Architecture

View File

@@ -222,9 +222,16 @@ POST /reports { imageDigest, policyRevision? } → { r
GET /catalog/artifacts/{id} → { meta }
GET /healthz | /readyz | /metrics
```
See docs/modules/scanner/byos-ingestion.md for BYOS workflow, formats, and troubleshooting.
### Report events
See docs/modules/scanner/byos-ingestion.md for BYOS workflow, formats, and troubleshooting.
### 4.1 Localization runtime contract (Sprint 20260224_002)
- Scanner.WebService initializes localization via `AddStellaOpsLocalization(...)`, `AddTranslationBundle(...)`, `AddRemoteTranslationBundles()`, `UseStellaOpsLocalization()`, and `LoadTranslationsAsync()`.
- Locale resolution order is deterministic: `X-Locale` header -> `Accept-Language` header -> configured default locale (`en-US`).
- Translation source layering is deterministic: embedded shared `common` bundle (library) -> embedded Scanner bundle (`Translations/*.scanner.json`) -> Platform runtime overrides fetched through the remote provider.
- Current localized API responses in this rollout are provided for `en-US` and `de-DE` (for example, slice query validation and not-found responses).
### Report events
When `scanner.events.enabled = true`, the WebService serialises the signed report (canonical JSON + DSSE envelope) with `NotifyCanonicalJsonSerializer` and publishes two Redis Stream entries (`scanner.report.ready`, `scanner.scan.completed`) to the configured stream (default `stella.events`). The stream fields carry the whole envelope plus lightweight headers (`kind`, `tenant`, `ts`) so Notify and UI timelines can consume the event bus without recomputing signatures. Publish timeouts and bounded stream length are controlled via `scanner:events:publishTimeoutSeconds` and `scanner:events:maxStreamLength`. If the queue driver is already Redis and no explicit events DSN is provided, the host reuses the queue connection and auto-enables event emission so deployments get live envelopes without extra wiring. Compose/Helm bundles expose the same knobs via the `SCANNER__EVENTS__*` environment variables for quick tuning.

View File

@@ -301,8 +301,8 @@ export interface NotifyDelivery {
## 9) Accessibility, i18n & theming
* **A11y**: WCAG 2.2 AA; keyboard navigation, focus management, ARIA roles; colorcontrast tokens verified by unit tests.
* **I18n**: Angular i18n + runtime translation loader (`/locales/{lang}.json`); dates/numbers localized via `Intl`.
* **Languages**: English default; Bulgarian, German, Japanese as initial additions.
* **I18n**: runtime translation loader from Platform (`/platform/i18n/{locale}.json`) with embedded offline fallback bundles (`en-US`, `de-DE`, `bg-BG`, `ru-RU`, `es-ES`, `fr-FR`, `uk-UA`, `zh-TW`, `zh-CN`); locale selectors in topbar and `/settings/language` use Platform locale catalog (`GET /api/v1/platform/localization/locales`) with local fallback when catalog lookup is unavailable; fallback selection prefers the requested locale family first, then `en-US`; dates/numbers localized via `Intl`. Authenticated locale changes from both topbar selector and dedicated settings route (`/settings/language`) are written to Platform user preferences (`GET/PUT /api/v1/platform/preferences/language`) so preference is shared across Web and CLI sessions, with localStorage used as offline fallback.
* **Languages**: English default; German, Bulgarian, Russian, Spanish, French, Ukrainian, Chinese (Traditional), Chinese (Simplified).
* **Theming**: dark/light via CSS variables; persisted in `prefers-color-scheme` aware store.
* **Branding**: tenant-scoped theme tokens and logo pulled from Authority `/console/branding` after login.