Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
63f5cc5
week_8: Module C (The Librarian) — reconcile the queue mirror with Mo…
PRAteek-singHWY Aug 12, 2026
fb48443
week_8: Module C (The Librarian) — envelope sink, and the rule that g…
PRAteek-singHWY Aug 12, 2026
b5b2e21
week_8: Module C (The Librarian) — the consumed_at write-back
PRAteek-singHWY Aug 12, 2026
9e39c41
week_8: Module C (The Librarian) — wire the C.4 safety seam into deci…
PRAteek-singHWY Aug 12, 2026
fa27e08
week_8: Module C (The Librarian) — component factory for the orchestr…
PRAteek-singHWY Aug 12, 2026
d916c65
week_8: Module C (The Librarian) — live queue runner + CLI
PRAteek-singHWY Aug 12, 2026
344fd22
week_8: fail the eval harness when the C.0 boundary rejects everything
PRAteek-singHWY Aug 12, 2026
bf53f8c
week_8: address CodeRabbit on #1011 — naive consumed_at, honest run s…
PRAteek-singHWY Aug 12, 2026
ae1ce26
week_8b: Module C (The Librarian) — package docs, final metrics, and …
PRAteek-singHWY Aug 12, 2026
32a5f95
week_8b: fix the regression gate's dependency install
PRAteek-singHWY Aug 12, 2026
63faf0b
week_8b: address CodeRabbit on #1012 — checkout credentials, diagram …
PRAteek-singHWY Aug 12, 2026
058ace6
week_8: Module C (The Librarian) — decision_queue, the C -> D handoff
PRAteek-singHWY Aug 13, 2026
29cc50b
week_8: address CodeRabbit on #1011 — project the highest link confid…
PRAteek-singHWY Aug 13, 2026
0ff8729
week_8: address CodeRabbit on #1011 — poison rows, blank run id, cros…
PRAteek-singHWY Aug 14, 2026
69c44c3
week_8: address the remaining CodeRabbit findings on #1011
PRAteek-singHWY Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/librarian_regression.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Librarian Regression Gate
# Module C's accuracy gate. The unit suite proves the code runs; this proves the
# pipeline still *decides* correctly over the golden set.
#
# Deliberately hermetic: no DB, no API key, no model download. The semantic
# reports (C.1 recall, C.2 top-1, the C.3 ECE gate, C.4 decision accuracy) need
# live CRE vectors and are measured locally — seeding a candidate pool from
# golden text offline is the leakage the hub firewall exists to strip, so a CI
# job that "measured" them would be measuring nothing.
#
# What this gate does catch is the failure that actually bit us: a Module B
# schema change silently rejecting every row at the C.0 boundary, which used to
# leave the explicit gate with nothing to count and still exit 0.

on:
pull_request:
paths:
- 'application/utils/librarian/**'
- 'application/tests/librarian/**'
- 'scripts/evaluate_librarian.py'
- '.github/workflows/librarian_regression.yml'
push:
branches: [main]
paths:
- 'application/utils/librarian/**'
- 'application/tests/librarian/**'
- 'scripts/evaluate_librarian.py'

permissions:
contents: read

jobs:
regression:
name: Librarian Regression Gate
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
# This job only reads the tree; leaving the token in .git/config would
# expose it to anything the test run executes.
persist-credentials: false

- uses: actions/setup-python@v5
with:
python-version: '3.12.3'
Comment thread
PRAteek-singHWY marked this conversation as resolved.

- name: Install python dependencies
# Installed straight into the runner's interpreter rather than through
# `make install-python`: that target builds a venv (needing an apt
# `virtualenv` the other workflows install first) and then runs
# `playwright install`, neither of which a hermetic librarian run uses.
# The steps below call `python` directly, so a venv the job never
# activates would leave them running against a bare interpreter.
run: |
pip install --upgrade pip setuptools
pip install -r requirements-dev.txt

- name: Librarian unit suite
run: python -m unittest discover -s application/tests/librarian -p '*_test.py' -t .

- name: Golden-set decision gate
# Non-zero on: a failed explicit-slice gate (C.0.5 must be 100%), or a
# C.0 boundary that rejected the whole dataset.
run: |
python scripts/evaluate_librarian.py \
--dataset application/tests/librarian/fixtures/golden_dataset.json
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ standards_cache.sqlite
!AGENTS.md
!docs/faq.md
!docs/Mid_eval_blog_gsoc2026/module_B_mideval_blog.md
!application/utils/librarian/README.md
!docs/gsoc_2026_module_c/*.md

### Dev DBDumps
*.sql
Expand Down
83 changes: 78 additions & 5 deletions application/cmd/cre_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,11 +1032,23 @@ def run(args: argparse.Namespace) -> None: # pragma: no cover
if args.upstream_sync:
download_graph_from_upstream(args.cache_file)
if args.run_librarian or args.librarian_dry_run:
run_librarian(
cache_file=args.cache_file,
dry_run=args.librarian_dry_run or not args.run_librarian,
source_jsonl=args.librarian_source,
)
# --run_id selects the live path: drain Module B's knowledge_queue for
# that run. Without it, the fixture walk-through stays the default so
# the pre-W8 command keeps behaving the way it always has.
run_id = (getattr(args, "run_id", "") or "").strip()
if run_id:
run_librarian_live(
cache_file=args.cache_file,
pipeline_run_id=run_id,
dry_run=args.librarian_dry_run,
envelopes_out=args.librarian_envelopes_out,
)
else:
run_librarian(
cache_file=args.cache_file,
dry_run=args.librarian_dry_run or not args.run_librarian,
source_jsonl=args.librarian_source,
)


def ai_client_init(database: db.Node_collection):
Expand Down Expand Up @@ -1238,6 +1250,67 @@ def run_librarian(
)


def run_librarian_live(
cache_file: str,
pipeline_run_id: str,
dry_run: bool = False,
envelopes_out: Optional[str] = None,
) -> None:
"""Module C entrypoint against Module B's live queue (W8).

The counterpart to ``--run_noise_filter``: where ``run_librarian`` walks a
JSONL fixture and logs shortlists, this drains the ``knowledge_queue`` rows
Module B wrote for ``pipeline_run_id`` through C.0->C.4 and stamps
``consumed_at`` on the ones it finished. Prints the ``RunSummary`` as JSON
on stdout so the OIE orchestrator can read it, exactly as Module B does.

Still writes no links: the graph/review writers are W8b. What a real run
does write is the envelopes (as JSONL, to ``envelopes_out``) and one column
on B's queue. Those two go together — retiring a row whose envelope was
discarded would lose the chunk — so a non-dry run requires an output path.
``dry_run`` writes neither.

Ops note: unchanged from ``run_librarian`` — opt-in CLI only, not on the
Procfile, not wired into the web app or the worker. It calls the paid
embedding API, so a deployment never triggers it on its own.
"""
from datetime import datetime, timezone

from application.utils.librarian.config_loader import load_config
from application.utils.librarian.envelope_sink import (
JsonlEnvelopeSink,
NullEnvelopeSink,
)
from application.utils.librarian.factory import build_components
from application.utils.librarian.queue_runner import run_librarian_queue

sink = JsonlEnvelopeSink(envelopes_out) if envelopes_out else NullEnvelopeSink()
if not dry_run and envelopes_out is None:
raise SystemExit(
"--run_librarian --run_id needs --librarian_envelopes_out <path>: a "
"real run marks queue rows consumed, so the envelopes it built have "
"to land somewhere first. Add --librarian_dry_run to run without "
"writing anything."
)

cfg = load_config()
database = db_connect(path=cache_file)
components = build_components(database, config=cfg)

# The CLI boundary is the one place a clock read belongs; everything below
# takes `at` as an argument so a run stays reproducible.
summary = run_librarian_queue(
database.session,
pipeline_run_id,
components,
cfg,
at=datetime.now(timezone.utc),
sink=sink,
dry_run=dry_run,
)
print(summary.to_json())


def regenerate_embeddings(db_url: str) -> None:
"""Wipe all embedding rows, then rebuild (CRE + every node type) like ``--generate_embeddings``."""
from application.prompt_client import prompt_client as prompt_client
Expand Down
16 changes: 16 additions & 0 deletions application/tests/librarian/config_loader_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def test_defaults_when_env_unset(self):
self.assertEqual(cfg.top_k_retrieval, 20)
self.assertEqual(cfg.top_k_rerank, 5)
self.assertEqual(cfg.link_threshold, 0.8)
# 1.0 is the identity transform: an honestly *uncalibrated* softmax,
# rather than a temperature nobody fitted.
self.assertEqual(cfg.temperature, 1.0)
self.assertEqual(cfg.batch_size, 32)
self.assertEqual(cfg.ece_target, 0.10)
self.assertEqual(cfg.conformal_alpha, 0.10)
Expand All @@ -34,6 +37,7 @@ class TestConfigLoaderOverrides(unittest.TestCase):
"CRE_LIBRARIAN_TOP_K_RETRIEVAL": "50",
"CRE_LIBRARIAN_TOP_K_RERANK": "10",
"CRE_LIBRARIAN_LINK_THRESHOLD": "0.7",
"CRE_LIBRARIAN_TEMPERATURE": "1.208",
"CRE_LIBRARIAN_BATCH_SIZE": "64",
"CRE_LIBRARIAN_ECE_TARGET": "0.05",
"CRE_LIBRARIAN_CONFORMAL_ALPHA": "0.20",
Expand All @@ -47,6 +51,7 @@ def test_env_overrides_apply(self):
self.assertEqual(cfg.top_k_retrieval, 50)
self.assertEqual(cfg.top_k_rerank, 10)
self.assertAlmostEqual(cfg.link_threshold, 0.7)
self.assertAlmostEqual(cfg.temperature, 1.208)
self.assertEqual(cfg.batch_size, 64)
self.assertAlmostEqual(cfg.ece_target, 0.05)
self.assertAlmostEqual(cfg.conformal_alpha, 0.20)
Expand All @@ -65,6 +70,17 @@ def test_link_threshold_above_one_raises(self):
with self.assertRaises(ValueError):
load_config()

def test_non_positive_temperature_raises(self):
"""T divides the logits, so zero or negative is undefined, not merely a
bad setting — the same guard TemperatureScaler applies."""
for value in ("0", "-1.5", "nan"):
with self.subTest(value=value):
with mock.patch.dict(
os.environ, {"CRE_LIBRARIAN_TEMPERATURE": value}, clear=True
):
with self.assertRaises(ValueError):
load_config()

def test_negative_top_k_retrieval_raises(self):
with mock.patch.dict(
os.environ, {"CRE_LIBRARIAN_TOP_K_RETRIEVAL": "-1"}, clear=True
Expand Down
Loading
Loading