78 Commits
Author SHA1 Message Date
claude-botandClaude Opus 5.5 4145e023ff fix(encyclopedia): overviews borrow their sub-articles' sources each run and live as long as they have sub-articles
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
An overview's borrowed sources were a snapshot taken at creation: a
sub-article that left kept feeding it, a merge moved the borrowed notes
into the target, and losing the borrowed notes deleted the overview and
retired its natural slug while its sub-articles lived on.

Overviews now carry an overview mark (optional plan field, format
unchanged) and only their own sources; what they are written from is
derived every run from their current sub-articles (in turn, at most 12),
for staleness, fingerprints and the write. Note removal never deletes an
overview; one left without sub-articles is deleted when it has no own
sources (slug stays free) or becomes an ordinary article.

An overview proposal under a redirected or retired slug is dropped
instead of parenting the children under the redirect target. An overview
takes the parent most of its children have, none on a tie. The
consolidate prompt carries the no-concrete-names rule for titles and
slugs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 10:38:22 +01:00
claude-botandClaude Opus 5.5 6a1d51ec02 feat(encyclopedia): consolidation proposes overview articles; raise fold and consolidate caps
Consolidation could only link existing articles as parents, so subjects
whose natural parent had no article (heating, lighting, floors) stayed
flat. The consolidate reply may now propose new overview articles over
two or more group members. An overview is written from its children's
first sources (in turn, at most 12) and an article with sub-articles is
never folded for being thin. The prompts name floors EG/OG/DG/KG and
treat UG, KG and Keller as one floor.

MaxFoldsPerRun 5 -> 100 and MaxConsolidationsPerRun 60 -> 150: a
bootstrap plan of ~400 articles needs several passes and the calls are
small. Prompts.Version 9 re-asks remembered consolidation groups; the
plan format is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 10:25:01 +01:00
claude-botandClaude Opus 5.5 af7ca24819 fix(encyclopedia): a planning reply that repeats a property is unusable
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
JsonObject builds its dictionary on first access and throws ArgumentException
on a repeated key, which escaped reply validation and failed the whole run
(assign reply with titleEn twice). Parsing now rejects duplicates up front, so
the reply counts as unusable like any other malformed one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 08:11:52 +01:00
claude-botandClaude Opus 5.5 69a58988d6 fix(encyclopedia): a failed consolidation call is not repeated in later passes
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
The group stays unremembered and is asked again next run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:57:07 +01:00
claude-botandClaude Opus 5.5 d7de998821 fix(encyclopedia): stable consolidation groups, redirected slugs in assign, reset cleanup
Consolidation runs passes until one changes nothing; a changing reply ends
the pass and the next starts from the first seed, so the last pass's groups
are the ones the next run forms. Memory is pruned to that pass. A stable
neighbourhood after a merge is no longer asked again the next night.

Assign treats a redirected slug, proposed as new or referenced directly,
as its live target instead of dropping the note.

A plan reset deletes article files whose slug the new plan lacks.

The sub-articles heading has no id, so it cannot collide with a body
heading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:51:47 +01:00
claude-botandClaude Opus 5.5 179bc3bcbc feat(encyclopedia): consolidate nearby articles, plan hierarchy, room articles
Article vectors (titleDe | titleEn | scope, embedded locally, cosine in
memory) feed the assign candidates alongside the note-neighbour articles
and form the groups of a new consolidate step after assign: one bounded
call per group of up to 8 nearby articles, at most 60 per run, returning
merges (fold mechanics, redirects incl. public ones) and parent links
(no cycles anywhere in the plan). Groups are remembered by fingerprint
in _state.json.

PlannedArticle gains a parent; split children get the overview. The write
prompt marks main and sub-articles among its link targets (children
capped at 20); the article page shows the main article and the visible
sub-articles from the plan. Parent changes do not make articles stale.

The assign prompt also sends room notes to the room article; the write
prompt writes room articles from the room's angle.

The plan file gets version 3: the v2 plan reads as no plan, its state is
dropped, and the next run bootstraps. Prompts.Version 8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:36:59 +01:00
claude-botandClaude Opus 5.5 e9ffad448f fix(encyclopedia): room for thinking, merge duplicate new slugs, header timeouts retryable
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 11:43:24 +01:00
claude-botandClaude Opus 5.5 bf274fb5a3 fix(house): anonymous readers follow only redirects public at fold time
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ArticleQueries serves anonymous readers only the redirects listed in
publicRedirects, so a retired slug whose article was not public (or a chain
through one) answers the usual 404, identical to a missing slug. Signed-in
readers follow every redirect. Body links of the anonymous view resolve
through the same filtered set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 10:17:54 +01:00
claude-botandClaude Opus 5.5 4706e49fd7 fix(encyclopedia): planning survives model errors, thin articles wait for fold
- A text-model HttpRequestException skips its assign batch (not remembered),
  split or fold article; only embedding/index failures end planning.
- Neighbour timeouts (TaskCanceledException, run not cancelled) count as
  service down.
- Thin articles with a nearby article and no keep at their inputs are not
  written until their fold decision; split children of the run are not
  folded.
- NearestAsync widens its query up to 8x the batch size, then fills from
  the open notes in slug order.
- Deleted articles' slugs (and redirects to them) stay reserved in
  _plan.json "retired"; a note left without articles is unassigned, not
  skipped.
- Fold records whether the folded article was public in both languages
  ("publicRedirects"); repointed redirects keep their flag.
- Assigned counts only notes assigned to an article.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 10:17:38 +01:00
claude-botandClaude Opus 5.5 61af595614 fix(house): redirect lookup survives store failures
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:57:07 +01:00
claude-botandClaude Opus 5.5 41a54a5844 feat(house): follow article redirects
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:50:55 +01:00
claude-botandClaude Opus 5.5 b41bee9743 feat(encyclopedia): reconcile through bounded assign, split and fold
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:42:32 +01:00
claude-botandClaude Opus 5.5 7a6cfc5124 feat(encyclopedia): writer links only to bounded targets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:24:12 +01:00
claude-botandClaude Opus 5.5 2d94f9a8d8 feat(encyclopedia): fold thin articles into a neighbour
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:21:32 +01:00
claude-botandClaude Opus 5.5 ad45fe4ac2 feat(encyclopedia): split oversized articles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:21:16 +01:00
claude-botandClaude Sonnet 5.5 a5322e71d2 fix(encyclopedia): tighten assign tests and first-paragraph handling
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 09:16:24 +01:00
claude-botandClaude Sonnet 5.5 e4384a2c54 feat(encyclopedia): assign notes in bounded batches
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 09:13:40 +01:00
claude-botandClaude Opus 5.5 348f8e4f75 test(encyclopedia): cover self-hit exclusion and ranking before cap
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:11:24 +01:00
claude-botandClaude Opus 5.5 45c76ac4ba feat(encyclopedia): nearby articles through the note index
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:09:36 +01:00
claude-botandClaude Opus 5.5 13d5495899 feat(encyclopedia): state v2 with per-batch and keep memory
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:07:19 +01:00
claude-botandClaude Opus 5.5 996ff182c0 feat(encyclopedia): plan v2 model with assignments and redirects
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:04:49 +01:00
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 ca12438ebb fix(encyclopedia): leak-check slugs and titles, keep planned titles stable
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
A scanner hit in the slug or titles, or the German leak check flagging them, makes the article private in both languages. The plan prompt forbids concrete identifiers in titles and slugs and keeps existing titles; prompt version 5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:10:09 +01:00
claude-botandClaude Opus 5.5 3f5c41a075 fix(host): answer an anonymous request for a private article with the missing-article 404
The 404 offers anonymous readers the login back to the requested path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:08:34 +01:00
claude-botandClaude Opus 5.5 6a9d8204a0 fix(anthropic): fail a stalled response stream after an idle timeout
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:06:32 +01:00
claude-botandClaude Opus 5.5 8314424f8b fix(core): detect IPv4 network prefixes written as .x, .*, .0/NN or a trailing dot
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:04:43 +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 Opus 5.5 cf75cef563 fix(host): mark wiki links outside Markdig's own code spans, reject link-like targets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 09:07:35 +01:00
claude-botandClaude Opus 5.5 4d94c9ef9a fix(host): allowlist article link targets, resolve wiki links before parsing, lock on leftovers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 08:59:41 +01:00
claude-botandClaude Opus 5.5 87f88a0fb6 feat(host): article markdown rendering with redaction, infobox, TOC, mermaid
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 08:47:58 +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
claude-botandClaude Opus 5.5 dad8c4bb63 fix(encyclopedia): symmetric frontmatter quoting, trimmed plan titles, commit before unexpected writer failure
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:16:02 +02:00
claude-botandClaude Opus 5.5 ff0c07ec76 feat(encyclopedia): incremental reconciler with single-commit writes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:08:30 +02:00
claude-botandClaude Opus 5.5 8532e0e0c5 fix(encyclopedia): renumbered leak check, escaped notes, images private, fenced replies
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:00:12 +02:00
claude-botandClaude Opus 5.5 9d95ae17b0 feat(encyclopedia): write, leak-check and translate pipeline
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 20:53:16 +02:00
claude-botandClaude Opus 5.5 469cbf6bd2 fix(encyclopedia): compact plan JSON, sanitized note lines, robust state read
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:43:29 +02:00
claude-botandClaude Opus 5.5 13de42b838 feat(encyclopedia): article-set planning and attempt memory
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:40:49 +02:00
claude-botandClaude Opus 5.5 1ac1495a4d feat(anthropic): long-form text model port with typed unavailability
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:37:25 +02:00
claude-botandClaude Opus 5.5 572d38ef31 fix(store): map missing binary to FileNotFound, harden text read and fakes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:34:05 +02:00
claude-botandClaude Opus 5.5 d6953db0e9 feat(store): multi-file commit, text and binary read by path
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:31:46 +02:00
claude-botandClaude Opus 5.5 2a80cb20af fix(core): leak scanner covers renner.uno forms, normalized addresses, more paths and entity domains
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 17:27:28 +02:00
claude-botandClaude Opus 5.5 ab41ef8088 feat(core): deterministic leak scanner for public article text
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 14:00:41 +02:00
claude-botandClaude Opus 5.5 013e6cd1e2 fix(core): only ASCII space and tab count as structural whitespace
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 13:56:27 +02:00
claude-botandClaude Opus 5.5 8c25e93cfb fix(core): container lines in any fence and stray closers redact the rest
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 13:52:12 +02:00
claude-botandClaude Opus 5.5 b8e48b7d16 fix(core): fail closed where the body scanner and CommonMark disagree
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 13:45:33 +02:00
claude-botandClaude Opus 5.5 23db9e9240 feat(core): article body format and private-block redaction
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 13:33:25 +02:00
claude-botandClaude Opus 5.5 c2cffcb291 feat(core): Article document kind under articles/<lang>/
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 13:26:53 +02:00
hermes-bot 50fb31b950 fix(auth): the wiki-index BasicAuth credentials read the API again
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
#14 put the read API behind a session or an API key. External agents
reach the wiki through wiki-index.renner.uno with BasicAuth only, and
since #14 they got 401: a regression.

The service now checks `Authorization: Basic` itself against the same
htpasswd lines Traefik's wiki-api-basic-auth middleware uses
(Auth:Basic:UsersPath: a file, or a mounted Secret directory where every
visible key is read, as Traefik reads every key of an Opaque Secret).
This is a credential check in the service, not trust in a proxy: the
header proves nothing unless the password matches the hash.

- Hash formats Traefik accepts: bcrypt ($2a$/$2b$/$2y$, BCrypt.Net-Next
  4.2.1), Apache MD5 ($apr1$, implemented here and checked against the
  Traefik docs example and `openssl passwd -apr1`), SHA1 ({SHA}). Any
  other format authenticates nobody.
- The identity is a machine named after the BasicAuth user.
- Policy "read" accepts it; "write" stays API-key only, and the UI stays
  OIDC only.
- A verified (user, password, hash) triple is cached in memory, so bcrypt
  costs once per process.
- With no UsersPath configured the scheme authenticates nobody, so this
  image is safe before the deployment mounts the Secret.

Tests: all three hash formats read the API; a wrong password, an unknown
user, an empty password and a user found only in a hidden Secret entry
are 401; BasicAuth cannot write and does not open the UI.
2026-10-19 14:06:55 +00:00
hermes-bot 4820bc9f6d fix(auth): redirect URI from the request host, no PublicOrigin setting
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Auth:Oidc:PublicOrigin was a hand copy of the Ingress host. Traefik routes on
the Host header and Authentik matches redirect URIs strictly, so the URI is
https://<request host>/signin-oidc; https because TLS ends at Traefik and
browsers only reach the wiki over https.
2026-10-19 09:45:56 +00:00