# holger-ui — AI context (compact)
> **Read this file first.** It is the primary context for reasoning about this
> repository. Use the companion [ai-context-full.md](ai-context-full.md) **only** for exact public-API
> signatures and `file:line` source lookup — do not load it for routine work.
>
> Generated summaries **never override active code**. Before changing behavior,
> inspect the referenced implementation and its tests.
## Snapshot
| Field | Value |
|---|---|
| Repository | holger-ui |
| Source revision | `11f89df5141d328237d43c8cbed2b8997715b639` |
| Working tree | Clean |
| Reproducible snapshot | Reproducible |
| Generation mode | development |
| Generator version | kvasir 0.2.1 |
| Maintained metadata | `.nornir/ai-context.toml` |
| Generated at | 2026-08-14T10:39:59+02:00 _(source: commit)_ |
| Category | Count | Included items |
|---|---|---|
| Cargo workspace packages | 1 | holger-ui-web |
| Detached Rust packages | 0 | — |
| Packages with indexed API surface | 1 | 1 workspace + 0 detached |
| Binary targets | 1 | [[bin]] + src/main.rs + src/bin/* |
| Library targets | 0 | packages with src/lib.rs |
The indexed count (1) is the 1 workspace members that expose a `src/` tree plus 0 detached package(s) (own `[workspace]`, indexed for their API but outside the dependency graph). Detached packages **are** in the API index; they are **not** in the workspace dependency graph.
## AI source-of-truth hierarchy
When sources disagree, trust the higher item. Strongest first:
1. Executable tests (they assert real behavior)
2. Active runtime wiring (what the daemon actually constructs and registers)
3. Implementation (the code that runs)
4. Configuration and feature definitions (what is switched on)
5. Schemas and persisted data contracts
6. Rustdoc (author intent — weaker than the code it describes)
7. Current architecture documents
8. Generated summaries (this pack included)
9. Historical documents (design notes, superseded proposals)
10. Inferred intent (weakest — a guess)
State explicitly:
- Exported code does not prove runtime registration.
- A configured feature may be disabled.
- A documented follow-up is not implemented.
- A model proposal is not an approved action.
- An `Ok` result may still contain partial failures.
- Degraded operation must not be mistaken for full operation.
## System summary
| Field | Value |
|---|---|
| Purpose | Web operator console for holger (the airgap-first artifact registry): a Leptos/WASM SPA speaking gRPC-web straight to the server's tonic-web door. proto/holger.proto is the entire contract — no REST layer, no BFF. |
| System role | Browser client covering holger's full service surface: repositories, browse, search, artifact detail (download/SBOM/properties), upload, promote, replicate, and auth (bearer paste + OIDC PKCE). |
| Language | Rust → wasm32-unknown-unknown (Leptos 0.8 CSR, trunk build) |
| Major binaries | holger-ui-web (wasm; served as static files from dist/) |
| Primary runtime components | grpc.rs: the one place that knows the server URL, builds the seven generated service clients, and attaches the bearer credential via a tonic interceptor.; app.rs: the routed views — every view is a shareable URL that fetches what it needs from its address alone.; oidc.rs: OIDC authorization-code + PKCE (S256 via SubtleCrypto); the resulting access token lands in the same store as a pasted one.; Trunk dev loop: trunk serve on :8090 proxying /grpc → a local holger-server on :50051. |
**Non-goals (explicit):**
- No REST/BFF layer — the browser speaks gRPC-web to holger directly; adding a middle tier reverses the design.
- No client-side authorization — roles are the server's RBAC mapping; the console only displays refusals.
- No font/JS CDN — the console must render identically inside an airgap.
- Not the egui operator app — that is `holger-ui` (server/ui) in the holger main repo; this repo is the web console only.
## AI reasoning warnings
Short operational cautions for interpretation (one line each):
- A crate existing does not prove it is runtime-wired.
- A pure function may require a daemon caller before it becomes active.
- A configured detector may not be scheduled.
- Candidate data never means Trusted.
- Trusted normality never overrides an explicit deny.
- Monitoring means elevated attention, not guilt.
- An agent proposal is not approval.
- Action approval is not successful execution.
- Notification success is not incident truth.
- Missing Matrix/webhook/email means degraded delivery, not failed triage.
- Semantic search may be unavailable while structured/full-text search still works.
- MCP failure should not imply core agent failure.
- Audit append failure may intentionally block a protected action.
- Audit self-consistency is not authenticity without an out-of-band trust root.
- Generated docs are weaker evidence than code.
- Model output is untrusted until validated.
- Stateful detectors depend on persisted ordering and snapshot semantics.
- "follow-up" or "planned" rustdoc is not implementation.
- proto/holger.proto is VENDORED — the copy in the holger main repo (nordisk/holger on git.gunnar.rs) is the source of truth. Refresh with `cp ../holger/proto/holger.proto proto/` and commit the diff; build.rs regenerates stubs from the local copy only.
- tonic here is 0.14 (codegen-only, no transport) while holger's server is tonic 0.13 — DELIBERATE skew; the gRPC-web wire protocol is independent of either side's tonic version. Do not 'fix' by downgrading.
- The crate is `holger-ui-web` but the repo is `holger-ui` — the holger main repo already has an egui crate named `holger-ui` (server/ui); the names must never collide in a workspace or patch table.
- The gRPC-web door mounts under /grpc (dev: Trunk proxy; prod: reverse proxy) because Trunk matches whole path segments — a bare /holger.v1. prefix never matches the real first segment holger.v1.AdminService. A production host must ALSO fall back to index.html for unknown paths (SPA routing).
- CORS is deliberately NOT opened on the holger server — deployments are same-origin behind a proxy. HOLGER_GRPC_WEB_URL pointing at a foreign origin requires CORS at that proxy instead.
- The theme uppercases h3/dt via CSS text-transform — element.innerText reflects the TRANSFORMED text, so text assertions in browser-driven tests must match case-insensitively (this bit our own regression suite).
- Property state never refetches: SetPropertyResponse returns the coordinate's full map and the table renders THAT. The SBOM resource, by contrast, refetches after attach — the hosted bytes are the truth, not an optimistic echo.
- The search checksum axis forces the server to hash candidate artifacts — it is the one expensive query axis; the placeholder says so and the UI must keep saying so.
- The bearer token lives in sessionStorage (XSS-readable by design tradeoff, documented in grpc.rs); there are no cookies and thus no CSRF surface. Log out removes it; a reload keeps it; closing the tab drops it.
- OIDC PKCE callbacks are only honored when THIS tab has a pending attempt, and the verifier is consumed one-shot on success OR failure — a forged callback burns the attempt. The IdP must allow the console origin as redirect URI and for CORS on its token endpoint.
- Every mutation surface shows the server's refusal VERBATIM (RBAC, promote seal, quarantine) — the console adds no client-side authorization and must not start rephrasing server messages.
## Runtime wiring map
A crate or function existing is **not** proof of wiring. Status uses the runtime vocabulary.
> → Runtime entry points & constructors: [ai-context-full.md](ai-context-full.md#api-reference).
_(no entries)_
## Capability matrix
Support and limitations only (the security rationale lives in the invariants).
_(no entries)_
## Non-negotiable invariants
The authoritative invariant list. Strength uses the invariant vocabulary.
> → Enforcement APIs: [ai-context-full.md](ai-context-full.md#api-reference).
_(none declared)_
## Security-sensitive code map
Maps a concern to its authoritative invariant (above) — enforcement and tests are not restated here.
_(no entries)_
## Failure semantics
An `Ok` result may still contain partial failures; degraded operation is not full operation.
> → Error/Result types: [ai-context-full.md](ai-context-full.md#api-reference).
_(no entries)_
## Trust and lifecycle
State transitions and which states affect detection/enforcement (implementation locations live in the invariants).
_(no entries)_
**Human gates (propose vs act):**
_(no entries)_
## State and persistence
> → Persistence types: [ai-context-full.md](ai-context-full.md#storage-search-query).
_(no entries)_
## Change-impact map
_(no entries)_
## Task-to-file map
> → Crate/module map: [ai-context-full.md](ai-context-full.md#crate-and-module-map).
_(no entries)_
## CLI inventory
> → CLI command enums / parsers: [ai-context-full.md](ai-context-full.md#runtime-and-cli).
_(no entries)_
## Configuration and environment
> → Config structs: [ai-context-full.md](ai-context-full.md#core-contracts).
**Main config** (secrets never appear in the config file — see environment):
_(no entries)_
**Environment variables:**
_(no entries)_
**Precedence** (verified):
1. Compiled defaults: gRPC-web door at {origin}/grpc; PAGE_SIZE 100; search limit 200.
2. Build-time env (option_env!): HOLGER_GRPC_WEB_URL overrides the door URL; HOLGER_OIDC_ISSUER / HOLGER_OIDC_CLIENT_ID prefill the SSO settings.
3. localStorage (operator settings): OIDC issuer + client id, saved from the login view — override the build-time prefill.
4. sessionStorage (per-tab credential): the bearer token — set by either login form, attached to every call by the one interceptor in grpc.rs.
**Dependencies** (full workspace graph + external hotspots are in the full pack):
1 workspace crates, 0 deduplicated workspace edges, 15 external dependencies. External hotspots and full coupling are in [ai-context-full.md](ai-context-full.md#central-external-dependency-hotspots).
_(no entries)_
## Tests inventory
Derived totals: **7 unit** test fns across 1 files, **3 integration** test fns.
## Incomplete work and current limitations
_No incomplete-work markers found (no `TODO`/`FIXME`/`todo!`/`unimplemented!`/`#[ignore]`)._
## Documentation and wiring mismatches
_None: no status contradictions, and every declared invariant has enforcement locations._
## Size and generation metadata
Measured for the compact pack (excludes this footer):
| Metric | Value |
|---|---|
| Bytes | 10518 |
| Lines | 209 |
| Words | 1525 |
| Approx tokens (chars/4) | 2630 |
| Token budget | 13% of 20000 |
| Duplicate-sentence ratio | 0.000 (max 0.000) |
| Duplicate-row ratio | 0.000 (max 0.000) |