feat(inbox): Door B flow against an injected guard gate (Phase 2 step 3)
`process_inbox(inbox_dir, bundle_dir, ingested_at, *, okf_type, gate)`: per dropped file, bytes -> extract_text -> guard gate -> render -> collision gate -> write -> index link. Returns an InboxResult whose four buckets (persisted / quarantined / rejected / failed) are disjoint and complete, so a file that vanished shows up as a missing entry rather than as nothing. The guard is INJECTED rather than imported. The library calls no guard function and makes no security decision: the Gate adapter returns a GateDecision carrying the guard's own disposition value and the sanitized text, and the flow only branches on it. That keeps the core dependency-free while B2 (the guard's CI channel) is still open, and lets the persist and refuse branches run deterministically against a test double. Decisions taken with the operator this session: - What is persisted is the gate's SANITIZED text, not the extracted text. Screening one string and writing another would make the verdict a statement about bytes nobody kept. `sanitize` is exported by the guard precisely for callers composing the checklist themselves, so this is sanctioned API, not a reimplementation. Door B has no model call, so the fenced text the bookends produce for a transform is never persisted. - Quarantine is reported apart from rejection. QUARANTINE_REVIEW means "hold for human review" — an operator queue — where FAIL_SECURE is a decision. No quarantine directory in v1; that stays an extension point. Fails closed by construction: only the guard's non-blocking floor (`warn`) persists, so a renamed member, a future disposition or an adapter typo lands in `rejected` rather than being guessed safe. One bad file never aborts the run. Only three conditions fail the whole run, and each is wrong for every file at once: an invalid `ingested_at`, a reserved `okf_type`, and a missing inbox directory. New code `inbox_slug_collision`: two dropped files reducing to one generated name are BOTH refused. Persisting one would let iteration order decide the winner, and overwriting would lose the other's content. Phase 1 primitives are reused, never duplicated, so four helpers become package-internal names (write_bytes, link_in_index, parse_frontmatter, INDEX_NAME) and link_in_index learns to append to an empty index — Door A always seeds its index with bundle_summary, but Door B has no summary to invent and must not open with a blank line.
This commit is contained in:
parent
b7f5ce3800
commit
d812a839be
6 changed files with 763 additions and 18 deletions
|
|
@ -15,6 +15,11 @@ what it is given. The guard-calling persist gates arrive with Doors B and C.
|
|||
|
||||
Door A (spec-based ingestion) public surface: materialize_bundle plus the
|
||||
typed error hierarchy rooted in IngestError.
|
||||
|
||||
Door B (bundle inbox) public surface: process_inbox plus its result types.
|
||||
Its persist gate is INJECTED -- the caller supplies a Gate adapter over
|
||||
llm-ingestion-guard and process_inbox obeys the verdict; the library imports
|
||||
no guard function itself and makes no security decision of its own.
|
||||
"""
|
||||
|
||||
from .errors import (
|
||||
|
|
@ -27,6 +32,15 @@ from .errors import (
|
|||
SourceError,
|
||||
)
|
||||
from .extract import extract_text
|
||||
from .inbox import (
|
||||
BlockedFile,
|
||||
FailedFile,
|
||||
Gate,
|
||||
GateDecision,
|
||||
InboxResult,
|
||||
PersistedFile,
|
||||
process_inbox,
|
||||
)
|
||||
from .manifest import (
|
||||
Extraction,
|
||||
FileSource,
|
||||
|
|
@ -40,20 +54,27 @@ from .materialize import IngestResult, materialize_bundle
|
|||
__version__ = "0.3.2"
|
||||
|
||||
__all__ = [
|
||||
"BlockedFile",
|
||||
"Extraction",
|
||||
"ExtractionError",
|
||||
"FailedFile",
|
||||
"FileSource",
|
||||
"Gate",
|
||||
"GateDecision",
|
||||
"HttpSource",
|
||||
"InboxResult",
|
||||
"IngestError",
|
||||
"IngestResult",
|
||||
"Manifest",
|
||||
"ManifestError",
|
||||
"MaterializationError",
|
||||
"NetworkGateError",
|
||||
"PersistedFile",
|
||||
"RenderError",
|
||||
"SourceError",
|
||||
"SqlSource",
|
||||
"extract_text",
|
||||
"load_manifest",
|
||||
"materialize_bundle",
|
||||
"process_inbox",
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue