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 only for exact public-API signatures and
file:linesource 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:
- Executable tests (they assert real behavior)
- Active runtime wiring (what the daemon actually constructs and registers)
- Implementation (the code that runs)
- Configuration and feature definitions (what is switched on)
- Schemas and persisted data contracts
- Rustdoc (author intent — weaker than the code it describes)
- Current architecture documents
- Generated summaries (this pack included)
- Historical documents (design notes, superseded proposals)
- 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
Okresult 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-webbut the repo isholger-ui— the holger main repo already has an egui crate namedholger-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.
(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.
(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.
(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.
(no entries)
Change-impact map
(no entries)
Task-to-file map
→ Crate/module map: ai-context-full.md.
(no entries)
CLI inventory
→ CLI command enums / parsers: ai-context-full.md.
(no entries)
Configuration and environment
→ Config structs: ai-context-full.md.
Main config (secrets never appear in the config file — see environment):
(no entries)
Environment variables:
(no entries)
Precedence (verified):
- Compiled defaults: gRPC-web door at {origin}/grpc; PAGE_SIZE 100; search limit 200.
- Build-time env (option_env!): HOLGER_GRPC_WEB_URL overrides the door URL; HOLGER_OIDC_ISSUER / HOLGER_OIDC_CLIENT_ID prefill the SSO settings.
- localStorage (operator settings): OIDC issuer + client id, saved from the login view — override the build-time prefill.
- 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.
(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) |