Skip to content

feat(curator): nightly local curation with safe auto-apply - #21

Merged
philtief merged 3 commits into
mainfrom
feat/local-curator
Sep 29, 2026
Merged

philtief merged 3 commits into
mainfrom
feat/local-curator

Conversation

@philtief

Copy link
Copy Markdown
Owner

Problem

The store records about 240 sessions but has 19 curated pages. Nothing turns sessions into pages unless an agent is prompted during a session. The remote curator job needs Lakebase and never ran in production.

Change

A new optional package and console script, wikibricks-curator. The core library still never calls a model.

wikibricks-curator propose --base-url https://<workspace>/ai-gateway/openai/v1 \
  --profile <databricks-cli-profile> [--projects 3] [--dry-run] [--no-apply]
  • For each of the top curation-backlog projects (feat(curation): report projects with new sessions and no updated page #17), build_request collects the living page, covering and related pages, and the new sessions' user and assistant messages only. Tool output and reasoning stay out, capped at 40 messages and 30,000 characters.
  • One call per project goes to an OpenAI-compatible chat-completions endpoint, default system.ai.glm-5-3-flash, with reasoning_effort: low. It uses the standard library only, with no Lakebase, SDK or job. The token comes from WIKIBRICKS_GATEWAY_TOKEN or databricks auth token --profile.
  • The remote curator prompt is reused, plus a local addendum: one living page per project at topics/<project> or its existing covering topics/ page, with sections Current state, Decisions, Open issues and Key facts. Only create_page, update_page and add_link are allowed.
  • The reply goes through the existing build_patches (moved in refactor(remote): move build_patches into a psycopg-free module #20) and is stored with the new store_manifest. apply_run(policy="safe") then applies it automatically.
  • Safety:
    • An update that drops more than half of a page's text is forced to high risk and waits for review.
    • wiki_index shows _meta/curation-review while patches have no receipt.
    • Page history is versioned, so every applied change can be undone.
    • A cursor per project prevents re-proposing the same sessions.
    • A dry run writes nothing.
  • Tolerance found in acceptance:
    • Links from a page created in the same reply are dropped (curate links it later).
    • Neutral defaults fill fields that carry no content, and unknown keys are dropped.
    • An invalid reply is retried once.

Verification

  • 239 tests pass, and Ruff is clean. uv.lock is unchanged. The curator tests cover evidence selection across UTC offsets, gateway calls (keyword timeout, reasoning_effort, parsing, HTTP errors), create, update, shrink guard, review entry, errors, retries, dry runs, the CLI, packaging and idempotent store_manifest.
  • Acceptance with real GLM 5.3 Flash on a copy of the live store:
    • First run: 3 projects, 3 of 3 applied.
    • Failures found: they motivated the fixes above. Without reasoning_effort: low, all 8,192 output tokens went to reasoning. A positional timeout was sent as the request body. There were same-run links and an omitted risk_class.
    • After the fixes: 8 of 8 projects applied with 0 errors, taking 100 s for 6 projects.
    • Pages: new topics/ pages for 7 projects, plus an update to topics/agent-atlas (4,684 to 5,651 characters, citing 8 messages). All have the four sections and dated facts, and a secret-pattern scan found nothing.
  • Known limits:
    • Generic working folders (~/code, the emails folder) get project pages too.
    • Applied pages are labelled created_by = remote-curator, which the apply path hard-codes for all curation runs.

GLM 5.3 Flash wrote the implementation in two steps. Review fixed the gateway call, timestamp comparison, per-project event loading, dry-run cursor writes and the guard crash. The acceptance fixes came from real model runs.

This pull request and its description were written by Isaac.

philtief and others added 3 commits September 29, 2026 09:36
New optional package `wikibricks_curator` (stdlib only, no psycopg or
Databricks SDK; the core library does not import it).

- `build_request` turns one curation-backlog item into a bounded request:
  the project's living page (first covering `topics/` page, else
  `topics/<project>`), covering and related pages in the shape
  `build_patches` expects, and only user/assistant messages from the
  project's sessions after the page update or cursor, newest kept first,
  capped at 40 events and 30,000 characters.
- `chat_json` calls an OpenAI-compatible chat-completions endpoint with
  the remote curator's message layout and JSON parsing; `resolve_token`
  reads WIKIBRICKS_GATEWAY_TOKEN or `databricks auth token --profile`.

Implemented by GLM 5.3 Flash; timestamp comparison across UTC offsets
and per-project event loading fixed in review.

Co-authored-by: Isaac <no-reply@databricks.com>
`wikibricks-curator propose --base-url URL --profile P` sends each of the
top backlog projects' new session text to one model (default GLM 5.3
Flash) and turns the reply into a local curation run.

- Keeps one living page per project (`topics/<project>` or the existing
  covering topics page) through a local prompt addendum on top of the
  remote curator prompt; only create_page, update_page and add_link.
- Auto-applies low-risk groups with the existing `safe` policy. Updates
  that would drop more than half of a page's text are forced to high risk
  and wait for review; `wiki_index` lists pending review runs.
- `store_manifest` stores a run locally; `pull_manifests` now uses it.
- A cursor per project stops the same sessions from being proposed twice.

Implemented by GLM 5.3 Flash. Review fixed the gateway call (positional
timeout sent as the request body; `reasoning_effort: low`, without which
GLM 5.3 Flash spends all 8,192 output tokens on reasoning), a dry run
that advanced the cursor, and a guard that crashed on pages without a
summary.

Co-authored-by: Isaac <no-reply@databricks.com>
Acceptance runs against GLM 5.3 Flash on a copy of the live store showed
three failure modes; each lost a whole project run:

- A link from the living page created in the same reply: build_patches
  only knows existing pages. Such links are now dropped and counted;
  `curate` adds mention links once the page exists.
- Omitted fields with no content value (risk_class, tags, source_ids,
  target_path, group; title/summary/body on links) get neutral defaults,
  and unknown keys are dropped. Page proposals without content still fail.
- An undecodable or invalid reply is retried once.

After the fixes: 8 of 8 projects applied, 0 errors, 100 s for 6 projects.

Co-authored-by: Isaac <no-reply@databricks.com>
@philtief
philtief merged commit 44a72f0 into main Sep 29, 2026
3 checks passed
@philtief philtief mentioned this pull request Sep 29, 2026
@philtief
philtief deleted the feat/local-curator branch September 29, 2026 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant