chore(articles): hygiene pass — shared-ai actor + lib/sync-db + metrics (#5,#7,#11)

#5 — SYSTEM_ARTICLES_IMPORT_WORKER hoisted into @mana/shared-ai
   The worker built its actor inline, bypassing the SystemSource union
   that's the blessed list for system-write principals. Now uses
   makeSystemActor(SYSTEM_ARTICLES_IMPORT_WORKER) like every other
   server-side system writer (mission-runner, projection, …).

#7 — sync-db helper hoisted out of mcp/ into lib/
   Implementation moved to apps/api/src/lib/sync-db.ts; mcp/sync-db.ts
   is a re-export shim so existing MCP imports keep working. Articles
   bulk-import + future modules import from lib/ directly — no more
   "articles depending on mcp" layering smell.

#11 — Prometheus metrics for the worker
   New counters + histogram in lib/metrics.ts under
   mana_api_articles_import_*:
     - ticks_total{result=processed|skipped|error}
     - items_total{result=extracted|error|consent_wall|cancelled}
     - extract_duration_seconds (histogram, 0.25–30s buckets)
     - jobs_completed_total{result=done}
     - pickup_gc_rows_total
   Worker tick + extractor instrumented at the right transition points.
   Steady-state pickup_gc_rows_total > 0 over time signals a stuck
   consumer somewhere — useful operator alert.

Plan: docs/plans/articles-bulk-import.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-29 01:06:15 +02:00
parent 93545f8516
commit 59373c0d57
8 changed files with 245 additions and 122 deletions

View file

@ -42,6 +42,17 @@ export const SYSTEM_MISSION_RUNNER = 'system:mission-runner';
* it from the user-write codepath.
*/
export const SYSTEM_BOOTSTRAP = 'system:bootstrap';
/**
* Server-side bulk-article-import worker (apps/api). Picks up
* articleImportItems with state='pending', runs Readability, drops
* the extracted payload into articleExtractPickup, flips item state.
* Every state-transition write the worker does is attributed to this
* principal so the Workbench timeline + revert path can group
* background-import writes under one identity.
*
* Plan: docs/plans/articles-bulk-import.md.
*/
export const SYSTEM_ARTICLES_IMPORT_WORKER = 'system:articles-import-worker';
export type SystemSource =
| typeof SYSTEM_PROJECTION
@ -49,7 +60,8 @@ export type SystemSource =
| typeof SYSTEM_MIGRATION
| typeof SYSTEM_STREAM
| typeof SYSTEM_MISSION_RUNNER
| typeof SYSTEM_BOOTSTRAP;
| typeof SYSTEM_BOOTSTRAP
| typeof SYSTEM_ARTICLES_IMPORT_WORKER;
/** Legacy sentinels for records that pre-date the identity-aware actor
* shape. Read-path normalization maps missing fields to these. */
@ -153,6 +165,8 @@ function defaultSystemDisplayName(source: SystemSource): string {
return 'Mission-Runner';
case SYSTEM_BOOTSTRAP:
return 'Bootstrap';
case SYSTEM_ARTICLES_IMPORT_WORKER:
return 'Artikel-Import';
}
}

View file

@ -23,6 +23,7 @@ export {
SYSTEM_STREAM,
SYSTEM_MISSION_RUNNER,
SYSTEM_BOOTSTRAP,
SYSTEM_ARTICLES_IMPORT_WORKER,
LEGACY_USER_PRINCIPAL,
LEGACY_AI_PRINCIPAL,
LEGACY_SYSTEM_PRINCIPAL,