Commit Graph
18 Commits
Author SHA1 Message Date
claude-botandClaude Opus 5.5 61c424aac6 feat: schedules move to cluster CronJobs
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
The service no longer schedules work itself. POST /api/v1/encyclopedia/run
syncs and runs the encyclopedia; it answers 502 when the run fails or the
text model stopped it, so a CronJob shows a failed run as a failed Job.
The sync loop keeps its startup sync and the webhook trigger; the 30-min
interval is a CronJob calling POST /api/v1/sync.

Removed: EncyclopediaBackgroundService, Encyclopedia RunAt/TimeZone,
Wiki:Sync IntervalSeconds/RetrySeconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 07:35:24 +01:00
claude-botandClaude Opus 5.5 82d70e4c60 feat(host): house encyclopedia pages with anonymous public view
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 09:27:40 +01:00
claude-botandClaude Sonnet 5.5 5b625a241f fix(host): make encyclopedia schedule tests deterministic and harden the loop
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 21:24:07 +02:00
claude-botandClaude Sonnet 5.5 a99b8c9f06 feat(host): run the encyclopedia nightly after a sync
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 21:20:22 +02:00
hermes-bot 0ecf1aaac5 feat(auth): humans sign in with OIDC; no header names a user
ci/woodpecker/push/test Pipeline was successful
The ProxyHeader scheme took the username from X-Authentik-Username for any
peer inside Auth:ReverseProxy:TrustedProxies. The deployment set that to
the whole pod CIDR (a hand copy of the Talos podSubnets), so every pod the
network policies let reach :8080 (Hermes, Gitea, Traefik, all of ai and
monitoring) could claim any human's name on the Facts page and on saved
answers. Authentik's proxy provider sends no signed identity header, so the
header cannot be verified at all.

Humans now sign in with OpenID Connect against Authentik: a public client
with PKCE, the username is preferred_username from the ID token, whose
signature is checked against the provider's JWKS. Nothing about the
network path or the request headers names a user any more.

- Auth:Oidc:Authority, ClientId and PublicOrigin are required; the host
  refuses to start without them. PublicOrigin builds the redirect URI,
  because TLS ends at Traefik and the request scheme is http.
- UI pages, static assets and the Blazor hub need a session (fallback
  policy); an anonymous browser is redirected to the provider.
- The read API (/api/v1 reads, /ask, /questions, /rank, /status) needs a
  session or an API key (policy "read") and answers 401, never a redirect.
  Before, it was anonymous and relied on the gate, BasicAuth or network
  policy in front.
- Writes still need an API key (policy "write").
- /health, /ready and the HMAC-signed /webhook stay anonymous.
- ProxyHeaderAuthenticationHandler and Auth:ReverseProxy are removed.

Tests: an in-process OpenID provider issues RS256 ID tokens. They cover
the PKCE challenge and redirect URI, the full code flow ending in a
session named after the token's user, rejection of a token signed by a
foreign key, the Authentik header signing in nobody, and 401s for
credential-less API calls.
2026-10-19 09:44:58 +00:00
claude-botandClaude Fable 5.1 8b8e56d1b2 feat(facts): one text box; the drafter turns a statement into a raw source
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
IFactDrafter port: a statement in, title/content/tags out. Anthropic
implements it over the transport the answer model already uses (extracted
into MessagesTransport). RecordStatementUseCase drafts, sets the person as
source, keeps the statement verbatim in the body and deposits through the
existing use case. The Facts page is the text box and the receipt; the API
shape for machines is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-25 08:55:45 +02:00
claude-botandClaude Fable 5.1 09ec2cf1d9 feat(ui): Facts page deposits a raw source under the signed-in user
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Same DepositFactUseCase as POST /api/v1/facts, attributed as a human
identity from the Authentik proxy header. Cascading authentication state
carries the principal into the Blazor circuit; without a signed-in user
the form is replaced by a notice. Lists the raw sources awaiting the
nightly distill.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-25 08:24:00 +02:00
claude-botandClaude Fable 5.1 707c5f50a7 Merge branch 'feat/answer-model' into feat/lab
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
Both phases register their use cases and map their endpoints in the same host
files. The lab host test asserted exactly one labelled query, which held only
while no other test in the shared fixture wrote to output/; it now checks the
seeded query is among the rows.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 16:53:49 +02:00
claude-botandClaude Fable 5.1 e6f5c80a3a feat(questions): answer questions from wiki evidence with an answer model
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
POST /api/v1/questions runs ask (rank + judge), selects the paragraphs that
carry probability mass, and streams one answer-model call over them. Below
the coverage gate no model is called and the response names the gap. With
save: true (signed-in user or API key) the answer lands in output/ as a
synth-shaped document with sources, confidence and the answering model.

The Answers page streams the same use case and lists saved answers.
Anthropic is the first IAnswerModel adapter; the answer model is chosen per
request or from Wiki:AnswerModels:Active.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 16:42:18 +02:00
claude-botandClaude Sonnet 5 23c891db8f feat(lab): rank evaluation use case, API and Lab page
Adds EvaluateUseCase, the C# port of bin/wiki_rank_eval.py: every output/
document with a question and a sources list labels a query, gold is the
cited slugs that still exist as wiki notes, and RankUseCase ranks each
one to report recall@k, hit-rate@k, MRR and a one-hop recall variant that
also credits a gold note reachable from a top-k note by wikilink or
related:. Exposes it as POST /api/v1/lab/eval (write-policy) and a new
/lab page for running it against any registered embedding model and
comparing runs side by side.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 16:39:53 +02:00
claude-botandClaude Fable 5.1 35887a9cbf facts: POST /api/v1/facts deposits a raw source through the store, attributed to the API key
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 16:29:06 +02:00
claude-botandClaude Fable 5.1 34cf91ebaf ask: wiki_ask.py as a use case and POST /api/v1/ask; judges from configuration
Rank every query, unite the top notes into one context under a per-document
and a total budget, expand context choices over paragraph or document ids
plus NONE, add the covered gate, judge context choices alone and the rest
batched, attach the answering paragraphs' text. A missing TypeSafe key is a
call-time error shown in status, not a startup failure.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 13:57:17 +02:00
claude-botandClaude Fable 5.1 2cd171d3c5 read api: notes with links, backlinks and resolved sources; tags; raw queue; reports
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 13:45:55 +02:00
claude-botandClaude Fable 5.1 6ff8d4bce6 store port: get and create documents; depositing a fact is a use case
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
The fact sink was a second adapter over the same backend. INoteStore
gains CreateAsync (DocumentExistsException on a taken path); the raw
note's shape, slug and collision numbering live in DepositFactUseCase;
GiteaRepository only moves text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 13:37:20 +02:00
claude-botandClaude Fable 5.1 fe6a284c6c gitea: one repository adapter serving both the note-store and the fact-sink port
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
Two classes over the same backend showed as two adapters on the status
page. One GiteaRepository, one HttpClient, one health entry; the host
lists an adapter once even when it serves several ports.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 13:30:17 +02:00
claude-botandClaude Fable 5.1 14b858bcfc host: endpoint tests; keep status-code pages off API responses; merge the three adapters
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 11:44:12 +02:00
claude-botandClaude Fable 5.1 af58249bc5 host: composition root, health/ready/status, /rank and /webhook, auth handlers, MudBlazor status page, Dockerfile, CI pipelines
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 11:33:56 +02:00
claude-botandClaude Fable 5.1 30f2dec1f2 chore: solution scaffold (net10.0, ports-and-adapters layout, MudBlazor host, xunit)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 11:19:40 +02:00