Skip to content

Turn collected bundles into cited insights - #38

Merged
NiclasDev63 merged 3 commits into
knowledge-syncfrom
claude/github-issue-14-08796d
Sep 1, 2026
Merged

NiclasDev63 merged 3 commits into
knowledge-syncfrom
claude/github-issue-14-08796d

Conversation

@NiclasDev63

Copy link
Copy Markdown
Contributor

Closes #14. Bases on the epic branch knowledge-sync, not main.

The two model stages of the funnel. Collected bundles flow through triage — cheap tier, 15 bundles per call via Inngest event batching keyed by organization — which routes each bundle to the topics whose scope covers it and scores documentation-worthiness. Survivors go to extraction, a capable model that re-authors the conversation into durable claims.

How the acceptance criteria are met

  • Triage batches and routes on scope. batchEvents: { maxSize: 15, key: event.data.organizationId } — one model call per batch, and the key keeps one org's bundles from being judged against another's topics. A discarded bundle is settled with its outcome and its content pruned; title/url survive so the feed can still name it.
  • Insights are re-authored and cited. keepableInsights drops any claim whose citations aren't in the set of URLs the bundle actually contained — the model never gets to invent a link. A claim with no surviving citation is dropped entirely.
  • Thresholds in one place. thresholds.ts holds every number the funnel judges by. Below-threshold results are never stored and never surfaced.
  • Metered. Each extraction runs inside fundGeneration with the new KNOWLEDGE_EXTRACT credit action (migration + enum + pricing + top-up catalogue + i18n labels). BYOAI orgs are carved out, matching chat and ingestion. PAYMENT_REQUIRED records UNFUNDED and keeps the content so the nightly sweep retries after a top-up — it is not a silent failure.
  • Pruned, and visible. Content is deleted in the same transaction that writes the claims, so pruning can't outrun storage. The topic feed lists insights with their citation links, plus per-source counts and a READING state for bundles still in the funnel.

Notes

  • Model ids are never handed to the model — triage and extraction address topics and bundles by 1-based position in the prompt. A cheap model miscopies a 25-char cuid often enough that every slip landed as a wrong verdict.
  • Batched functions can't use Inngest's onFailure (it sees one event of the fifteen), so the last attempt records its own failure. Otherwise fourteen bundles sit in the feed looking like they're still being read.
  • An unparseable reply is treated as a transient failure, not a verdict — settling it would prune a real conversation over a stray token.
  • Prompts live on disk in apps/app/knowledge-prompts/, following the skills pattern. All third-party text enters through the existing tagged-passage injection boundary.

Verification

  • pnpm check — 32/32 tasks pass (typecheck, lint, format).
  • pnpm test:unit — 2772 pass, 20 skipped.
  • Not run: the opt-in live-DB funnel e2e (extract/e2e-live-db.test.ts), which needs E2E_DATABASE_URL. The local Postgres here is password-protected. Run it before merging the epic:
    E2E_DATABASE_URL=postgres://… pnpm -C apps/app exec vitest run src/features/knowledge/server/extract/e2e-live-db.test.ts
    

🤖 Generated with Claude Code

Triage batches fifteen bundles per model call on the cheap tier, routes each
to the topics whose scope covers it, and scores how worth documenting the
discussion was. Survivors go to extraction, which re-authors the conversation
into claims a reader can act on without opening the pull request.

A claim is kept only if the bundle can back it: prose, confidence above the
floor, and at least one citation whose URL was already in front of the model.
Everything the funnel judges by lives in one file.

Each extraction is metered as KNOWLEDGE_EXTRACT against the credit ledger.
Running out is recorded as UNFUNDED rather than swallowed, so the nightly
sweep retries it once the organization has topped up.

Bundle content is pruned in the same transaction that stores the claims read
out of it — id, hash and outcome survive so the feed can still name a pull
request nothing was learned from.

Closes #14

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 31, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated
startup-app Ignored Ignored Sep 1, 2026 11:45am UTC
startup-web Ignored Ignored Sep 1, 2026 11:45am UTC

Request Review

NiclasDev63 and others added 2 commits September 1, 2026 13:43
Collected bundles now flow through two model stages. Triage batches fifteen
per call on a cheap model, routes each bundle to the topics whose scope
matches, and scores documentation-worthiness; survivors go to extraction,
which re-authors the conversation into standalone claims. Anything the model
does not settle keeps its content and comes round again on the nightly sweep.

Both stages address topics by their position in the prompt rather than by
cuid: a cheap model miscopies a 25-character id often enough that every slip
landed as an outcome, filing a bundle under the wrong topic for good.

A claim is kept only if it cites a URL that appears in the bundle it was read
from, so a model cannot invent a link, and only if its confidence clears the
floor. Every number the funnel judges by lives in one file.

Both stages spend `KNOWLEDGE_EXTRACT` through `meteredGenerateText`, a wrapper
that resolves the model, spares an organization on its own endpoint, charges,
and refunds a failure — the four things every call site used to do by hand.
Reading the reply happens inside that funded window, so an organization is
never left charged for a generation whose result was thrown away. An
organization out of credits gets the standard refusal and its bundles wait.

Settling a bundle prunes its conversation in the same write, guarded on
`processedAt: null` so a late triage cannot overwrite a finished extraction.
The topic feed lists the claims with their citation links.

Closes #14

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@NiclasDev63
NiclasDev63 merged commit 0c56aa5 into knowledge-sync Sep 1, 2026
4 checks passed
@NiclasDev63
NiclasDev63 deleted the claude/github-issue-14-08796d branch September 5, 2026 17:00
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