feat(extract): Door B extraction registry (Phase 2 step 1)
First, guard-independent step of Phase 2: a stdlib-only registry mapping a dropped file's extension to its text extractor, with the fail-fast gates that keep binary parsing out of core. `extract_text(filename, data)` dispatches (case-insensitively) to: - `md`/`txt` — utf-8-sig passthrough (BOM never leaks, baseline parity with Door A's read_csv); - `csv` — the Phase 1 `render_table` (renderer reused, not duplicated); - `json` — verbatim inside `render_fenced_block`; - `html`/`htm` — text via `html.parser`, `script`/`style` stripped, tags as word boundaries (spec B3: adequate for v1, richer is out of scope). `pdf`/`docx`/`xlsx` are `[extract]`-gated; until that extra ships a parser they fail fast with a typed error naming the extra — never a silent skip, never a bundled parser in core. New `ExtractionError(IngestError)` carries four stable codes (`extractor_unknown`, `extractor_extra_missing`, `extractor_decode_error`, `extractor_empty_csv`); a non-UTF-8 file is a typed corrupt-input failure, never a leaked UnicodeDecodeError. `extract_text` returns text content only — LF framing and concept frontmatter are the materializer's job (step 2). No runtime dependency and no guard call yet (the guard pin and 0.4.0 land with the persist gate in steps 4–5). TDD: test_extract.py + the four codes in the test_error_codes.py registry precede the implementation; mypy --strict, ruff, and the `sanitize|quarantine|lexicon` boundary grep-gate all clean; the Phase 1 golden suite still passes byte-for-byte. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HBbjgS5A55RVavoyjJC4FX
This commit is contained in:
parent
99c899f4ed
commit
db93de4aef
5 changed files with 301 additions and 0 deletions
|
|
@ -18,6 +18,7 @@ typed error hierarchy rooted in IngestError.
|
|||
"""
|
||||
|
||||
from .errors import (
|
||||
ExtractionError,
|
||||
IngestError,
|
||||
ManifestError,
|
||||
MaterializationError,
|
||||
|
|
@ -25,6 +26,7 @@ from .errors import (
|
|||
RenderError,
|
||||
SourceError,
|
||||
)
|
||||
from .extract import extract_text
|
||||
from .manifest import (
|
||||
Extraction,
|
||||
FileSource,
|
||||
|
|
@ -39,6 +41,7 @@ __version__ = "0.3.2"
|
|||
|
||||
__all__ = [
|
||||
"Extraction",
|
||||
"ExtractionError",
|
||||
"FileSource",
|
||||
"HttpSource",
|
||||
"IngestError",
|
||||
|
|
@ -50,6 +53,7 @@ __all__ = [
|
|||
"RenderError",
|
||||
"SourceError",
|
||||
"SqlSource",
|
||||
"extract_text",
|
||||
"load_manifest",
|
||||
"materialize_bundle",
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue