Tarik Moussa
cd42e9abc8
fix(F-09): address review-gate findings — resource leak + idempotency
...
- mathpix.py + figures.py: wrap fitz page-loop in try/finally so
doc.close() is guaranteed even on exception (no file-handle leak)
- ingest.py: DELETE FROM formulas/figures WHERE paper_id before re-insert
so --rich re-ingest is idempotent (BIGSERIAL has no natural UNIQUE key;
ON CONFLICT DO NOTHING was a no-op)
Gate: 158 passed, ruff clean, mypy clean
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-14 02:23:21 +02:00
Tarik Moussa
1df9be6563
feat(F-09): rich parsing — formula + figure extraction
...
- codex/parsing/mathpix.py: pix2tex (local, CPU) primary + MathPix API
optional; bbox heuristic h>15px, math-char-count>5; singleton model cache
- codex/parsing/figures.py: pymupdf embedded-image extraction → PNG;
caption detection via proximity + "Figure/Fig./Abbildung" prefix
- codex/models.py: FormulaChunk + FigureChunk dataclasses (R-10/R-11)
- codex/ingest.py: --rich flag wires formula+figure extraction post-ingest
- codex/cli.py: search_app sub-typer (paper + formula subcommands),
--rich flag on ingest; wiki_app from F-12 preserved intact
- codex/config.py: mathpix_app_id/key, pix2tex_fallback, figures_dir
- infra/schema.sql: formulas + figures tables with HNSW pgvector indexes
- pyproject.toml: pymupdf>=1.24, pix2tex>=0.1.4
- tests/parsing/test_mathpix.py + test_figures.py: 31 tests (mock pix2tex
+ MathPix HTTP, real pymupdf on synthetic PDF)
Gate: 158 passed, ruff clean, mypy clean (20 files)
Requirements: R-10 R-11 R-12 R-13 R-14 → done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-14 01:16:24 +02:00
Tarik Moussa
d2f9141a5c
fix(cli): remove F-09 spillover from F-12 branch, keep only wiki group
...
cli.py and config.py were accidentally contaminated with uncommitted F-09
changes (search_app restructure, rich ingest, mathpix/figures settings).
This restores both files to main-baseline + F-12-only additions:
- cli.py: wiki_app group (compile/list/check), restore @app.command search
- config.py: wiki_dir, wiki_llm_model, wiki_llm_url, wiki_top_k only
All 127 tests green, ruff+mypy clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 20:28:22 +02:00
Tarik Moussa
4d361fd8dc
feat(cli): wiki compile/list/check command group (F-12)
...
Adds codex wiki compile/list/check Typer subgroup to cli.py.
Adds wiki_dir, wiki_llm_model, wiki_llm_url, wiki_top_k settings
to config.py (F-12 section only).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 20:22:55 +02:00
Tarik Moussa
aee00515f4
feat(wiki): concept schema loader + concepts.yaml (F-12)
...
Adds wiki/concepts.yaml (5 curated seeds: discrete-conformal-map,
circle-packing, lobachevsky-function, discrete-yamabe-flow,
hyperideal-tetrahedron) and codex/wiki.py with full load_concepts()
implementation (Concept dataclass, YAML parser, graceful empty list).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-13 20:22:51 +02:00
Tarik Moussa
2acb2ee213
feat(cli): wire all commands via Typer (ingest, search, discover, provenance, ask-stub)
...
- Implement all CLI commands as specified in F-07: ingest, search, and discover subcommands (leads, citing, cited-by, cocited), and provenance subcommands (scan, add-link, links, bib).
- Add ask command stub that exits with code 1 (not yet implemented).
- Implement comprehensive tests with mocked dependencies (no real DB/API calls).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com >
2026-06-05 07:22:03 +02:00
Tarik Moussa
7675f63188
feat(discover,provenance): graph discovery queries + @cite scan + code_links + bib export
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-05 07:13:01 +02:00
Tarik Moussa
5344975bb1
feat(ingest): end-to-end idempotent ingest pipeline
...
Implements codex/ingest.py with:
- OpenAlex primary / Semantic Scholar fallback metadata fetch
- Abstract dense embedding (zero-vector for missing abstracts)
- Idempotent paper upsert (ON CONFLICT DO UPDATE)
- Source file parsing (.tex via latex_to_text, .pdf via nougat + grobid)
- Chunk deletion + bulk re-insert with dense embeddings
- Citation merge from OpenAlex/S2 API and GROBID PDF refs (dedup via set)
- 7 tests covering basic, tex, pdf, not-found, idempotent, arxiv-fallback,
and no-abstract scenarios (all mocked, offline)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-05 07:04:12 +02:00
Tarik Moussa
fbf8949579
feat: merge F-04 embed layer (BGE-M3 dense+sparse via FlagEmbedding)
2026-06-05 06:56:17 +02:00
Tarik Moussa
c33fd9d697
feat: merge F-03 parsing layer (LaTeX, Nougat, GROBID)
...
Review-Gate: APPROVE (Opus, cold, 2 passes)
23 tests, ruff+mypy clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-05 06:48:49 +02:00
Tarik Moussa
52737abe3d
fix(sources): correct OpenAlex ID prefixing, citations endpoint, S2 rate-limit
...
Review-Gate findings:
- openalex: bare DOIs/arXiv IDs need doi:/arxiv: prefix (bare IDs 404);
add _resolve_id(); fix fetch_citations to use referenced_works field
instead of non-existent /works/{id}/references endpoint.
- semanticscholar: wait_fixed(1) was inter-retry only; add per-request
monotonic rate-limiter (_rate_limit()) before each httpx call.
Add _is_retryable() filter so 404s don't burn 5 retry slots.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-04 23:49:35 +02:00
Tarik Moussa
1698f7dcad
feat(embed): BGE-M3 dense+sparse via FlagEmbedding (ADR-0002)
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-06-04 23:48:06 +02:00
Tarik Moussa
d1ffea1c1c
fix(parsing): case-insensitive arXiv idno match; fix tmp_path types; add extract_structure test
...
Review-Gate finding: GROBID emits type="arXiv" (camel-case), not "arxiv".
XPath literal match silently returned empty strings for all real responses.
Fix: iterate idno elements and compare .lower() == "arxiv".
Test fixture updated to reflect real GROBID output (type="arXiv").
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-04 23:47:18 +02:00
Tarik Moussa
b7f19b6e2c
feat(sources): OpenAlex, SemanticScholar, arXiv API clients
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-04 23:31:15 +02:00
Tarik Moussa
c6a428d335
feat(parsing): LaTeX, Nougat, GROBID parsers with chunking
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-04 23:30:58 +02:00
Tarik Moussa
b52a6a7412
fix: add @app.callback so codex --help exits 0
...
Bare Typer() with no commands raised RuntimeError at runtime.
Callback makes the entry point callable without exposing F-07 logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-04 11:26:35 +02:00
Tarik Moussa
1dd7a4bea3
fix: add cli.py stub so entry point resolves before F-07
...
Review-Gate finding: pyproject.toml [project.scripts] referenced
codex.cli:app which was absent; uv run codex raised ModuleNotFoundError.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-04 11:25:17 +02:00
Tarik Moussa
e7ac7766a5
feat: initial project scaffold
...
pyproject.toml (Python 3.12, uv), codex/ package (config, db, models),
infra/ (docker-compose + schema), .env.example, .gitignore, README.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-04 11:19:10 +02:00