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>
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>
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>
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>
- 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>
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>
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>