Skip to content

Finalize and compose extraction outcomes - #89

Merged
Khamel83 merged 28 commits into
mainfrom
codex/wayfinder-s3-extraction-finalization
Jul 28, 2026
Merged

Finalize and compose extraction outcomes#89
Khamel83 merged 28 commits into
mainfrom
codex/wayfinder-s3-extraction-finalization

Conversation

@Khamel83

Copy link
Copy Markdown
Owner

Summary

  • add immutable extraction plans/outcomes, closed finalization truth tables, and receipt-bearing durable acceptance
  • enforce exactly-once Persist structured extraction rejection reasons for Atlas callers #57 classification, bounded private traces, cache authority/origin identity, and safe first/retry projections
  • compose retrieval clusters only from exact durable accepted extraction projections, with artifact reuse and cross-plan integrity
  • separate archive lookup from durable authority-consumed creation authorization
  • add migration 0007 plus a real-PostgreSQL-derived recovery schema contract covering tables, columns, constraints, indexes, defaults, and deparsed definitions

Verification

  • controller task-focused suite — 184 passed, 7 skipped
  • controller recovery/status — 122 passed, 4 skipped
  • controller full suite — 1499 passed, 42 skipped
  • real disposable PostgreSQL contract, migration rollback, and concurrency checks passed
  • scoped Ruff and git diff --check passed
  • independent full-range review — Approved, no findings

Stack and gates

Resolves #88
Parent: #58

AI-generated implementation and PR description; independently reviewed and controller-verified.

@github-actions

Copy link
Copy Markdown

Fast review (openai/gpt-oss-20b:free, automated)

  • No obvious syntax or formatting issues found.

@github-actions

Copy link
Copy Markdown

Deep review (inclusionai/ling-3.0-flash:free, automated)

Architecture concerns

  • SQLiteArchiveCreationAuthorizationStore opens a new sqlite3.connect() per consume() call — each consume acquires its own file handle and transaction, risking contention under concurrent extraction and depending on WAL mode for cross-connection durability, which isn't configured.
  • The _submit_and_fetch compatibility wrapper silently routes through create_archive, which now always raises ArchiveCreationPolicyRejected when called without an authorization — a behavioral change hidden behind a private function that no caller should reach.
  • _validate_creation_authorization compares bounded_target != url with raw string equality after splitting the URL, so http://example.com and http://example.com/ (or a canonicalized form) won't match — authorization can fail non-obviously.
  • ExtractionCache is now coupled to an acceptance_repository with an optional attribute check (getattr(..., loader, None)) — if the repository interface evolves, the silent early-return path makes failures difficult to detect.

Runtime edge cases

  • Cache identity canonicalization falls back to re-hashing plan.normalized_url when normalized_url_identity is missing — if that field is populated inconsistently, the same extraction produces different cache keys and silently misses.
  • In put, the identity round-trip ExtractionCacheIdentity.from_accepted(content) != url compares against the identity object used as key; if JSON sort_keys or field insertion order drifts at any point, valid entries become permanently ineligible.
  • consume returns False for any exception during authority.verify or store.consume — swallowing the original exception with raise ... from error in create_archive masks root causes but the bare Exception catch there also traps programming errors like attribute typos.
  • The cache has no max size and no TTL background eviction; entries expire only on lazy get hits, so a burst of distinct normalized URLs grows memory without bound.

Performance issues

  • canonical_bytes() serializes the full identity dict to JSON + SHA-256 on every cache lookup (both _key and the durable reload inside put), making hot retrieval path O(n) in identity fields rather than a lightweight hash.
  • Precomputing and storing canonical_bytes() or its hash on ExtractionCacheIdentity would eliminate repeated serialization overhead.
  • SQLiteArchiveCreationAuthorizationStore's per-call connection pattern is fine for low throughput, but under concurrent extraction it will serialize on file locks rather than sharing a single connection — a connection pool or module-level sqlite3.connect(..., check_same_thread=False) with explicit locking would reduce overhead.
  • The consume method hashes the target URL with SHA-256 on every call even though the target is already provided as a plain string; hashing is fast but wasteful when a direct comparison on the target itself would suffice for the uniqueness constraint.

…traction-finalization

# Conflicts:
#	tests/test_provider_evidence.py
@github-actions

Copy link
Copy Markdown

Fast review (openai/gpt-oss-20b:free, automated)

(no response from model)

@Khamel83
Khamel83 merged commit df0d59b into main Jul 28, 2026
10 checks passed
@Khamel83
Khamel83 deleted the codex/wayfinder-s3-extraction-finalization branch July 28, 2026 21:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement S3 extraction finalization and retrieval composition

1 participant