Skip to content

WS-ART-001-03B3B3B: add bounded DOCX extraction - #234

Merged
abiorh-claw merged 4 commits into
mainfrom
codex/ws-art-001-03b3b3b-docx-extractor
Jul 31, 2026
Merged

WS-ART-001-03B3B3B: add bounded DOCX extraction#234
abiorh-claw merged 4 commits into
mainfrom
codex/ws-art-001-03b3b3b-docx-extractor

Conversation

@Abiorh001

@Abiorh001 Abiorh001 commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

WS-ART-001-03B3B3B PR Trust Bundle

Chunk

WS-ART-001-03B3B3B — DOCX Extractor (L1).

Goal and human-approved intent

Add deterministic, bounded DOCX text and table extraction after exact DOCX
classification and the merged OOXML security boundary. Preserve original
verified guide bytes as authoritative. This hidden chunk must not activate
AUTH, invoke guide sufficiency, add other formats, or touch contributor ZIPs.

What changed and why

  • Added an isolated DOCX adapter that emits compact sorted JSON blocks in
    document order with fixed paragraph, row, cell, and nested-table semantics.
  • Added a fixed omission schema for headers, footers, comments, deletions,
    passive objects, hidden text, and field instructions.
  • Advanced DOCX evidence to guide-extraction-v3 and bound omission facts to
    immutable persistence and replay checks.
  • Reused the existing worker-owned OOXML validator loader and kept both the
    validator and DOCX adapter imports confined to the isolated child.
  • Added focused tests, the existing hosted semantic lane assignment, and the
    exact storage-service contract.

Design chosen and alternatives rejected

The isolated worker composes the shared OOXML validator with the DOCX adapter
before descriptor-only seccomp. The adapter receives an explicit validator,
then parses only validated word/document.xml and bounded style facts. The
parent accepts only the exact result and omission schemas. Rejected alternatives
were upload-request parsing, direct provider access, a second OOXML validation
path, raw binary agent input, partial output, or generic document authority.

Scope control and product behavior

Only hidden guide-source extraction changes. There is no route, authorization
activation, Celery continuation, sufficiency invocation, provider read, guide
binding, submission, checker, review, contribution, payment, or reputation
change. Unsupported and malformed content remains a bounded internal artifact
outcome, not a guide-insufficiency decision.

Acceptance criteria proof

  • Paragraphs, hyperlinks, tabs, breaks, tables, cells, nested tables, and empty
    structures have exact canonical output tests.
  • Headers, footers, comments, tracked deletion/move-from content, passive
    objects, fields, direct/inherited style-hidden text, and document-default
    hidden text are omitted and recorded.
  • Active content and malformed XML fail through stable bounded outcomes.
  • Exact output-limit behavior returns no partial usable result.
  • The real isolated runner proves v3 policy, omission transport, and scratch
    cleanup; architecture tests prove worker-only adapter/validator imports.
  • Persistence tests bind canonical output and omission facts and reject obsolete
    policy evidence as a replay target.

Tests and checks

  • Ruff and approved extractor-dependency gate — pass.
  • Focused DOCX/OOXML/extraction/architecture/lane suite — 151 passed.
  • DOCX module coverage — 95.02 percent (9 tests).
  • Stale artifact contracts, stale wording, Markdown links, lane integrity, and
    git diff --check — pass.
  • Hosted Backend/Agent Gates retain DB-backed replay, repository-wide coverage,
    and semantic-lane proof; no local full-suite run was used.

Test delta and CI integrity

No test, assertion, lane, workflow, dependency rule, or coverage threshold was
removed, skipped, or weakened. Invalid result-shape fixtures carry valid
omission facts so they still reach their intended validation branches. The new
DOCX module joins the existing shared_foundations lane.

Reviewer results

Architecture, CI integrity, test delta, and docs pass. Security, QA, senior
engineering, product/ops, and reuse/dedup pass with only documented low risks.
All blocking deletion traversal, hidden-style cascade, isolated-runner, shared-
loader reuse, protocol-test, and documentation findings were repaired and
re-reviewed.

External review

CodeRabbit and hosted GitHub checks are pending on the PR head. Any valid
findings will be repaired and recorded before merge readiness is reported.

Remaining risks and follow-up

DOCX has a large visibility model; this chunk intentionally supports a bounded
subset and treats w:vanish presence conservatively, including explicit false
values. Future formats should reuse the same isolated result protocol without
growing duplicated schemas. PPTX/XLSX, durable sufficiency continuation, and
AUTH activation remain separate later chunks.

Human review focus and merge ownership

Review exact canonical ordering/separators, omission semantics, injected shared
OOXML validation, v3 replay identity, isolation, and absence of AUTH or
sufficiency activation. A human owns merge approval; the agent will not merge
this PR.

Summary by CodeRabbit

  • New Features

    • Added deterministic DOCX extraction for paragraphs and tables.
    • Added canonical JSON output with omission details for hidden, deleted, and unsupported content.
    • Added immutable persistence and replay validation for extracted DOCX content.
    • Added bounded output handling and clear errors for malformed or unsupported documents.
  • Documentation

    • Documented the DOCX extraction contract, output format, omission behavior, and size limits.
  • Tests

    • Added comprehensive coverage for DOCX extraction, security limits, deterministic output, and isolated processing.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Abiorh001, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1ba5852c-294a-4902-ab1e-4aa736096097

📥 Commits

Reviewing files that changed from the base of the PR and between 878f08b and 1ec13db.

📒 Files selected for processing (7)
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/chunks/WS-ART-001-03B3B3B-docx-extractor.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B3B-external-review-response.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B3B-internal-review-evidence.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B3B-pr-trust-bundle.md
  • backend/app/modules/artifacts/guide_docx.py
  • backend/tests/test_guide_docx.py
  • docs/spec_artifact_storage_service.md
📝 Walkthrough

Walkthrough

This change adds bounded DOCX extraction through the isolated worker, canonical JSON output, omission metadata, policy guide-extraction-v3, persistence/replay validation, and focused tests and review records.

Changes

DOCX extraction

Layer / File(s) Summary
DOCX contract and result schema
.agent-loop/initiatives/.../WS-ART-001-03B3B3B-docx-extractor.md, backend/app/modules/artifacts/guide_extraction.py, docs/spec_artifact_storage_service.md
Defines canonical DOCX blocks, omission facts, the 4 MiB limit, and policy guide-extraction-v3.
Bounded DOCX extraction and worker wiring
backend/app/modules/artifacts/guide_docx.py, backend/app/modules/artifacts/guide_extraction_worker.py, backend/tests/test_artifact_architecture.py
Validates OOXML, extracts paragraphs and tables, omits unsupported content, maps bounded failures, and confines the adapter to the isolated worker.
Extraction result and persistence binding
backend/app/modules/artifacts/guide_extraction.py, backend/app/modules/artifacts/guide_extraction_service.py, backend/tests/test_guide_bindings.py
Validates omission metadata, persists extractor-provided facts, and rejects replay results with mismatched facts.
Focused tests and review evidence
backend/tests/test_guide_docx.py, backend/tests/test_guide_extraction.py, backend/scripts/run_test_lanes.py, .agent-loop/initiatives/.../reviews/*
Covers deterministic output, omissions, security failures, output limits, worker envelopes, test-lane assignment, and review status.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant guide_extraction_worker
  participant validate_ooxml
  participant extract_docx
  participant guide_extraction_service
  guide_extraction_worker->>validate_ooxml: Validate DOCX payload
  guide_extraction_worker->>extract_docx: Extract validated DOCX
  extract_docx-->>guide_extraction_worker: Return canonical output and omission_facts
  guide_extraction_worker-->>guide_extraction_service: Return extraction result with policy v3
  guide_extraction_service->>guide_extraction_service: Persist and compare omission_facts
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the workstream item and the primary change: bounded DOCX extraction.
Description check ✅ Passed The description covers the change, intent, design, scope, acceptance criteria, tests, review status, risks, and merge ownership.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/ws-art-001-03b3b3b-docx-extractor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Abiorh001

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
backend/tests/test_guide_docx.py (1)

276-283: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert the complete omission-fact shape after the cross-process round trip.

This test is the only proof that omission facts survive the isolated-child JSON protocol. It checks two keys. The nine-key shape is asserted only in-process at Line 122.

A partial assertion here would not detect a parent that drops or renames keys during result parsing. Assert the full mapping so the wire contract is proven end to end.

💚 Proposed test strengthening
     assert (result.status, result.policy_version) == ("extracted", "guide-extraction-v3")
     assert result.canonical_output == ('{"blocks":[{"text":"visible","type":"paragraph"}]}')
-    assert result.omission_facts["tracked_deletions"] is True
-    assert result.omission_facts["omitted"] is True
+    assert result.omission_facts == {
+        "truncated": False,
+        "omitted": True,
+        "headers": False,
+        "footers": False,
+        "comments": False,
+        "tracked_deletions": True,
+        "embedded_objects": False,
+        "hidden_text": False,
+        "field_instructions": False,
+    }
     assert list(tmp_path.iterdir()) == []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_guide_docx.py` around lines 276 - 283, Strengthen the
cross-process assertion in GuideExtractionRunner().extract by comparing
result.omission_facts against the complete nine-key omission-fact mapping
already asserted in the in-process test around the existing omission-facts
coverage. Preserve the current protocol and result assertions while ensuring the
full mapping, including all keys and values, is validated after JSON round-trip
parsing.
backend/app/modules/artifacts/guide_docx.py (1)

295-298: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Resolve part names through the casefolded map to match the validator.

Line 296 builds names with casefold(). Lines 297 and 298 then read with the exact lowercase literals "word/document.xml" and "word/styles.xml". validate_ooxml in backend/app/modules/artifacts/guide_ooxml.py compares required markers after casefold(), so it accepts a package that stores word/Document.xml. The adapter then raises KeyError and reports malformed/docx_document_unavailable.

The outcome stays bounded and fail-closed, so this is not a security or data-loss defect. It is an asymmetry between the validator contract and the adapter. Map each casefolded name to the stored name and read that name.

♻️ Proposed refactor
-        with zipfile.ZipFile(BytesIO(payload)) as archive:
-            names = frozenset(info.filename.casefold() for info in archive.infolist())
-            document = archive.read("word/document.xml")
-            styles = archive.read("word/styles.xml") if "word/styles.xml" in names else None
+        with zipfile.ZipFile(BytesIO(payload)) as archive:
+            stored = {info.filename.casefold(): info.filename for info in archive.infolist()}
+            names = frozenset(stored)
+            document = archive.read(stored["word/document.xml"])
+            styles = (
+                archive.read(stored["word/styles.xml"])
+                if "word/styles.xml" in stored
+                else None
+            )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/app/modules/artifacts/guide_docx.py` around lines 295 - 298, Update
the archive handling around the names map in the DOCX adapter to resolve
required parts case-insensitively: map each casefolded filename to its original
stored filename, then use those mapped names for reading document.xml and the
optional styles.xml. Preserve the existing missing-part behavior and continue
passing the resolved content to the validator.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/app/modules/artifacts/guide_docx.py`:
- Around line 237-254: Update _table_text to obtain rows and cells through the
same content-control-aware traversal used by _contained_blocks, so
w:sdt/w:sdtContent wrappers are unwrapped for both row-level and cell-level
structures while preserving existing paragraph/table handling and omission
tracking. Add a focused test covering wrapped rows and wrapped cells, including
the expected canonical text and omitted state.
- Around line 222-234: Bound recursive traversal depth across _contained_blocks,
_table_text, and the walk helper in _paragraph_text by adding a shared depth
parameter and incrementing it on recursive calls. When the fixed maximum depth
is exceeded, raise or propagate the existing malformed-input handling so deeply
nested documents produce a deterministic malformed outcome rather than
RecursionError/parser_failure; preserve normal traversal behavior below the
limit.

---

Nitpick comments:
In `@backend/app/modules/artifacts/guide_docx.py`:
- Around line 295-298: Update the archive handling around the names map in the
DOCX adapter to resolve required parts case-insensitively: map each casefolded
filename to its original stored filename, then use those mapped names for
reading document.xml and the optional styles.xml. Preserve the existing
missing-part behavior and continue passing the resolved content to the
validator.

In `@backend/tests/test_guide_docx.py`:
- Around line 276-283: Strengthen the cross-process assertion in
GuideExtractionRunner().extract by comparing result.omission_facts against the
complete nine-key omission-fact mapping already asserted in the in-process test
around the existing omission-facts coverage. Preserve the current protocol and
result assertions while ensuring the full mapping, including all keys and
values, is validated after JSON round-trip parsing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2bbd7415-51c5-488d-bbec-67b403bbf1b2

📥 Commits

Reviewing files that changed from the base of the PR and between 2f441e9 and 878f08b.

📒 Files selected for processing (16)
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/STATUS.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/chunks/WS-ART-001-03B3B3B-docx-extractor.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B3B-external-review-response.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B3B-internal-review-evidence.md
  • .agent-loop/initiatives/WS-ART-001-immutable-artifact-storage/reviews/WS-ART-001-03B3B3B-pr-trust-bundle.md
  • backend/app/modules/artifacts/guide_docx.py
  • backend/app/modules/artifacts/guide_extraction.py
  • backend/app/modules/artifacts/guide_extraction_service.py
  • backend/app/modules/artifacts/guide_extraction_worker.py
  • backend/scripts/run_test_lanes.py
  • backend/tests/fixtures/guide_extraction_probe_worker.py
  • backend/tests/test_artifact_architecture.py
  • backend/tests/test_guide_bindings.py
  • backend/tests/test_guide_docx.py
  • backend/tests/test_guide_extraction.py
  • docs/spec_artifact_storage_service.md

Comment thread backend/app/modules/artifacts/guide_docx.py Outdated
Comment thread backend/app/modules/artifacts/guide_docx.py
@Abiorh001

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@abiorh-claw
abiorh-claw self-requested a review July 31, 2026 16:07
@abiorh-claw
abiorh-claw merged commit a1b3fd0 into main Jul 31, 2026
7 of 8 checks passed
@abiorh-claw
abiorh-claw deleted the codex/ws-art-001-03b3b3b-docx-extractor branch July 31, 2026 17:18
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.

2 participants