Weekly digest
Every day the Dev environment turns the last seven days of Kafka activity into a short bilingual summary: topic cards, KIP proposals by stage, and a headline, each sentence citing the records it is based on. Language models write the text; deterministic rules decide what may be published.
The pipeline
Input
DigestRun steps
Digest cron Prod off
Runs 40 minutes after the Dev publication; waits 15 minutes at a time, at most 4 times, while a publication is still running.
Sources: apps/data-publisher-worker/wrangler.development.jsonc, docs/runbooks/cloudflare-data-publisher.md
The day's snapshot
The digest pins one published release and never calls GitHub, Jira or the mailing list itself, so a run can be reproduced from its input.
Sources: docs/specs/014-topic-digest/spec.md
Select candidates
Threads with at least one human record in the 7 days ending at the release time; bot records are ignored.
Sources: packages/reference-pipeline/src/digest/candidates.ts
Classify by topic
@cf/cloudflare/clef-flash answers one multiple-choice question per thread: 12 topics (releases, clients, streams, KRaft, security, …) or routine maintenance.
- Thresholds
- routine section ≥ 0.6; a topic below 0.35 becomes Uncategorized
- Cache
- keyed by the classifier input and revision: an unchanged thread is not asked again
Score and place
Score = Σ 0.5^(age in days / 3.5) / k over human records, where k is the author's nth record in the thread, so one person repeating themselves counts less. Each thread lands in exactly one place: a card, routine or Uncategorized.
Sources: packages/reference-pipeline/src/digest/candidates.ts, packages/reference-pipeline/src/digest/mixing.ts
Summarize
@cf/meta/llama-3.3-70b-instruct-fp8-fast writes up to 3 sentences per card, 1 per KIP row, then a headline and 3 highlights. It only sees the selected threads, and every sentence must cite them, e.g. (KAFKA-PR-23829, closed).
- Prompt
digest-prompts@4(D98, 2026-10-20): status-faithful wording; "would" or "is proposed" for open, discussed or voted items
Sources: packages/reference-pipeline/src/digest/prompts.ts, apps/data-publisher-worker/src/digest/workers-ai.ts
Validate every sentence
Deterministic checks drop a sentence instead of publishing it: wrong length, no citation, a citation outside the inputs, a status word the source does not support ("merged" for an open PR, "verified" without a [RESULT] thread), a stance word ("objected", "rejected"), or a second proposal in one line. A card left empty shows "AI summary unavailable".
- Last run
- 1 unparsable model output, 1
status:verified, 1status:fixed - Tense rule
- D97 on Dev since 2026-10-20: completion forms need a final cited item;
tense:closed,tense:partialfor[k/N]PRs; a modal earlier in the clause exempts
Translate to zh-Hant
@cf/qwen/qwen3-30b-a3b-fp8 translates the validated English in batches of 60. Identifiers, citations and links are swapped for placeholders first; if one is lost, the item stays in English and is labelled "Not translated".
- Status guard
- D99: on a status mismatch the item keeps English, counts
translate:status-drift, and is not cached - Glossary
kafka-glossary@1(D100): offloading → 卸載, telemetry → 遙測, …
Sources: packages/reference-pipeline/src/digest/protect.ts, packages/reference-pipeline/src/digest/translation.ts, packages/reference-pipeline/src/digest/profiles.ts
Write both locales
en.json, then zh-Hant.<hash>.json, then the pointer, so the site never shows a translation without its source.
Neuron ledger
Every model call is charged to a daily ledger before it is made; over 5,000 estimated neurons a UTC day the run stops. A second limit sits in AI Gateway: 60 requests an hour and $2 a month.
Sources: packages/reference-pipeline/src/digest/estimate.ts, docs/runbooks/cloudflare-data-publisher.md
English digest
What the quality gate reviews: cards, KIP block, headline and highlights, each sentence with its citations.
Sources: docs/specs/014-topic-digest/spec.md
Traditional Chinese
Item-for-item translation of the English digest.
Sources: docs/specs/014-topic-digest/spec.md
This week Dev only
Top to bottom: headline, window and stats, up to 3 highlights, KIP proposals by stage (discuss, vote, implementing), topic cards, then Uncategorized and Routine collapsed.
Quality gate not passed
A human labels one real week sentence by sentence; bun run digest -- eval counts the errors. Prod is enabled only when the thresholds are met.
- English
status-mismatch0,overbroad-stance0 (fixed); others set by the owner- Translation
- D102, decided 2026-10-20:
status-drift0,omission0,term-error≤ 2 per week
Sources: packages/reference-pipeline/src/digest/eval.ts, packages/reference-pipeline/scripts/digest.ts
Run numbers are from the Dev run of 2026-10-19 22:47 UTC (/health digest.lastRun, read 2026-10-20). Prod has the digest off.
Models run on Cloudflare Workers AI through AI Gateway (a proxy that adds rate and spend limits). The split of work is deliberate: a small, cheap classifier answers a multiple-choice question per thread; the large model writes only from the threads it was given; a third model translates. Ranking, placement and validation are plain code (Spec 014).
Why rules check the model
A design review of a real week of output (the week of 2026-10-08) found sentences that claimed a pull request was merged while it was still open, and that attributed objections nobody made. Prompting alone does not prevent this, so every sentence is checked against the source records before publication, and a failing sentence is dropped rather than repaired (validate.ts):
| Rejection | What it catches |
|---|---|
length | empty or over 240 characters |
no-cites, cite-outside-inputs | a sentence with no citation, or citing a record the model was not given |
status:<word> | "merged", "landed", "fixed" without a merged PR or resolved Jira issue; "released", "shipped" without an [ANNOUNCE]; "verified", "accepted" without a [RESULT] or [ANNOUNCE] thread |
stance:<word> | "objected", "rejected", "pushed back" and similar, which overstate a discussion |
other-proposal | a second KIP in a line about one proposal |
tense:<form>, tense:closed, tense:partial | a completion form ("is added", "gets implemented", "now supports") when no cited item is final (a merged PR, a resolved Jira issue, a [RESULT] or [ANNOUNCE] thread); when a cited item is closed; or when the only final items are partial PRs ([1/N]) and the sentence does not say "first step" or "part k of" |
The tense rule (D97, merged in PR #101 on 2026-10-20, running on Dev) exempts a form when a modal ("would", "will", "may", …) comes before it in the same clause, so "would be added" passes. The summarizer prompt was revised at the same time to ask for status-faithful wording (D98, digest-prompts@4); because the prompt revision is part of the cache key, the next Dev run (22:47 UTC) regenerates every sentence.
Translation status guard and glossary
- Status guard (D99). The Chinese status word inside the citation parentheses must match the English one (open → 仍在進行, merged → 已合併, closed → 已關閉, proposed → 已提出, discussing → 討論中, resolved → 已解決, voting → 投票中, plus listed variants). Words are matched longest first, so 投票進行中 is "voting", never "open". On a mismatch the item keeps its English text labelled "Not translated", the run counts
translate:status-drift, and the translation is not cached, so the next run tries again; there is no retry in the same run (translation.ts). - Glossary (D100).
kafka-glossary@1fixes terms the model got wrong on Dev or that must stay stable: offloading → 卸載, telemetry → 遙測, assignor → 指派器, rebalance → 再平衡; share group and KRaft stay in English. The glossary revision is part of the translation cache key (profiles.ts).
Quality gate before Prod
The digest reaches Prod only after a human labels one real week and the evaluation meets the thresholds (Spec 014, Behavior 31).
- Error classes for English sentences:
status-mismatch,misattribution,invented-claim,overbroad-stance. - Translation error classes (D101):
status-drift,term-error,omission; a labelled sentence can carry them, andevalalso runs the status guard over every translated sentence. - Fixed thresholds: zero
status-mismatchand zerooverbroad-stance. Thresholds for the other two classes and for recall of important threads (an example in the spec is recall ≥ 0.8) are the owner's to set. - Translation thresholds (D102, decided by the owner on 2026-10-20):
status-drift0,omission0,term-errorat most 2 per labelled week; a labels file may override them. - Golden set: a labels file in the repository; today it holds the five negatives from the 2026-10-08 review and no important-thread labels yet (topic-digest-labels.v0.json).
- Evaluation:
bun run digest -- eval(offline, no network) reports kept and dropped sentences by reason, whether every labelled error was rejected, and recall;bun run digest -- measurefails when a run would exceed its neuron, call or read limits (scripts/digest.ts, eval.ts).
Status as of 2026-10-20: the gate has not passed, so the digest runs on Dev only; DIGEST_ENABLED is unset on Prod (docs/feature-map.md).
Known limitations
- The tense rule only knows the listed forms: "X lands" or "X is in trunk" is not caught; the golden set is the backstop.
- The status guard compares the set of statuses, not which status belongs to which citation, so swapped statuses for two items pass; the
status-driftlabel catches them. - The older status-word rule also drops modal sentences such as "would be released" (issue #104, open).
- Known false positive (issue #104): a sentence starting "Now <noun>", such as "Now logs are structured", matches
now logs, because several of the listed verbs are also nouns. - On the Dev week of 2026-10-20 the tense rule dropped 5 card and proposal sentences and 1 highlight, all stating unfinished work as done; both recorded weeks are committed test fixtures, so the rule's precision is reproducible offline (Spec 014, D97).
Cost
| Item | Value | Source |
|---|---|---|
| Daily cap | 5,000 estimated neurons per UTC day (Dev and Prod) | estimate.ts |
| Estimate | price table × 1.28, calibrated against the tokens Workers AI reported | Spec 014 |
| Last Dev run | 29 model calls, 1,637 estimated neurons, 99 s (2026-10-19 22:47 UTC) | Dev /health |
| Gateway | 60 requests an hour, $2 a month; a refused call ends the run as limited | runbook |
Caches keyed by input and revision mean an unchanged thread is neither classified nor summarised again; changing a prompt invalidates them, so the next run costs close to a cold run. bun run digest -- measure puts a cold run with digest-prompts@4 at 2,215 price-table neurons, about 2,835 estimated, within the 5,000 cap.