Replaces the one-call article planner (which hit the 32k output cap on 1977 notes) with a stored plan that each run updates through bounded calls. Spec: docs/superpowers/specs/2026-10-26-encyclopedia-bounded-planning-design.md; plan: docs/superpowers/plans/2026-10-26-encyclopedia-bounded-planning.md.
What changes
articles/_plan.json is state: articles (with a one-line scope), note→article assignments, redirects, plus retired slugs and publicRedirects (added in review). Old format reads as "no plan" → first run bootstraps; old _state.json reads fine.
A run: diff notes → assign new notes in batches of ≤20 similar notes against ≤20 nearby articles (found via the existing per-note vector index) → split articles over 300k chars / 120 sources (≤120 sources in) → fold thin articles into a neighbour (≤10 candidates) → write stale articles with ≤10 nearby link targets. Every prompt is capped by a setting; nothing grows with the wiki.
Per-step caps per night (120 assign batches, 5 splits, 5 folds, 10 writes); a failed batch is remembered and not paid for again until its notes change; one transient model error skips only that call.
Thin articles awaiting a fold decision are not written yet (no money on pages that would vanish).
Addresses never break: split keeps the slug as overview; fold leaves a redirect (301). Anonymous readers follow a redirect only if the folded article was public at fold time and the final target is visible — otherwise the identical 404 of a missing slug. Retired slugs are never reused.
Endpoint answers 502 when the plan is empty after the run (so the CronJob goes red).
Tests:dotnet test Wiki.slnx green — Core 174, Application 219, Contracts 83, Host 160. Each task reviewed (spec + quality), whole-branch review + one fix wave re-reviewed.
Known residual (not fixed here): an Anthropic HttpClient timeout while waiting for response headers (MessagesTransport, 120 s) surfaces as TaskCanceledException, not HttpRequestException, so it bypasses the new per-call catch and fails that night's planning (staged work is committed). Follow-up: convert it in the transport like the stream-idle case.
Deploy notes: homelab sets Wiki__Encyclopedia__MaxArticles=0, so the first run only plans (no articles written) — then pick pilot slugs from _plan.json. Consider Wiki__Encyclopedia__MaxFoldsPerRun well above 5 (fold calls are ~1k tokens) so thin articles don't wait weeks for their fold decision.
Replaces the one-call article planner (which hit the 32k output cap on 1977 notes) with a stored plan that each run updates through bounded calls. Spec: `docs/superpowers/specs/2026-10-26-encyclopedia-bounded-planning-design.md`; plan: `docs/superpowers/plans/2026-10-26-encyclopedia-bounded-planning.md`.
**What changes**
- `articles/_plan.json` is state: articles (with a one-line scope), note→article assignments, redirects, plus `retired` slugs and `publicRedirects` (added in review). Old format reads as "no plan" → first run bootstraps; old `_state.json` reads fine.
- A run: diff notes → **assign** new notes in batches of ≤20 similar notes against ≤20 nearby articles (found via the existing per-note vector index) → **split** articles over 300k chars / 120 sources (≤120 sources in) → **fold** thin articles into a neighbour (≤10 candidates) → **write** stale articles with ≤10 nearby link targets. Every prompt is capped by a setting; nothing grows with the wiki.
- Per-step caps per night (120 assign batches, 5 splits, 5 folds, 10 writes); a failed batch is remembered and not paid for again until its notes change; one transient model error skips only that call.
- Thin articles awaiting a fold decision are not written yet (no money on pages that would vanish).
- Addresses never break: split keeps the slug as overview; fold leaves a redirect (301). Anonymous readers follow a redirect only if the folded article was public at fold time and the final target is visible — otherwise the identical 404 of a missing slug. Retired slugs are never reused.
- Endpoint answers 502 when the plan is empty after the run (so the CronJob goes red).
**Tests:** `dotnet test Wiki.slnx` green — Core 174, Application 219, Contracts 83, Host 160. Each task reviewed (spec + quality), whole-branch review + one fix wave re-reviewed.
**Known residual (not fixed here):** an Anthropic HttpClient timeout while waiting for response headers (MessagesTransport, 120 s) surfaces as TaskCanceledException, not HttpRequestException, so it bypasses the new per-call catch and fails that night's planning (staged work is committed). Follow-up: convert it in the transport like the stream-idle case.
**Deploy notes:** homelab sets `Wiki__Encyclopedia__MaxArticles=0`, so the first run only plans (no articles written) — then pick pilot slugs from `_plan.json`. Consider `Wiki__Encyclopedia__MaxFoldsPerRun` well above 5 (fold calls are ~1k tokens) so thin articles don't wait weeks for their fold decision.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- 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>
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>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Replaces the one-call article planner (which hit the 32k output cap on 1977 notes) with a stored plan that each run updates through bounded calls. Spec:
docs/superpowers/specs/2026-10-26-encyclopedia-bounded-planning-design.md; plan:docs/superpowers/plans/2026-10-26-encyclopedia-bounded-planning.md.What changes
articles/_plan.jsonis state: articles (with a one-line scope), note→article assignments, redirects, plusretiredslugs andpublicRedirects(added in review). Old format reads as "no plan" → first run bootstraps; old_state.jsonreads fine.Tests:
dotnet test Wiki.slnxgreen — Core 174, Application 219, Contracts 83, Host 160. Each task reviewed (spec + quality), whole-branch review + one fix wave re-reviewed.Known residual (not fixed here): an Anthropic HttpClient timeout while waiting for response headers (MessagesTransport, 120 s) surfaces as TaskCanceledException, not HttpRequestException, so it bypasses the new per-call catch and fails that night's planning (staged work is committed). Follow-up: convert it in the transport like the stream-idle case.
Deploy notes: homelab sets
Wiki__Encyclopedia__MaxArticles=0, so the first run only plans (no articles written) — then pick pilot slugs from_plan.json. ConsiderWiki__Encyclopedia__MaxFoldsPerRunwell above 5 (fold calls are ~1k tokens) so thin articles don't wait weeks for their fold decision.🤖 Generated with Claude Code
- 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>