Skip to content

fix: bounded micro-batch local embedding and one-hop multi-anchor exclusion - #230

Merged
stone16 merged 3 commits into
mainfrom
codex/fix-qwen-document-batch-timeout
Aug 3, 2026
Merged

fix: bounded micro-batch local embedding and one-hop multi-anchor exclusion#230
stone16 merged 3 commits into
mainfrom
codex/fix-qwen-document-batch-timeout

Conversation

@stone16

@stone16 stone16 commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Two defects surfaced by the Qwen measured-acceptance run against the real corpus, fixed here (both discovered under issue #147's acceptance work; see ADR-0102):

  1. Bounded local-embedding inference (micro-batch size 1) with warm preload. Model load happens once in the provider constructor, outside every per-call deadline. Each document is embedded via per-fragment micro-batches (_LOCAL_EMBEDDING_MICRO_BATCH_SIZE = 1 — note: NOT 8-fragment batches; the effective per-fragment deadline is the full 30s call budget) under the unchanged 30-second per-call rail, with the hash-verified profile identity on every call. Fail-closed at both layers: a failing batch stops the document with a content-free typed failure and no partial Revision is ever published. A singleton batch that still exceeds the deadline yields a closed refusal for that document (BoundedCallTimedOut is currently sealed under the unsupported_document_shape refusal category — a deliberate, disclosed conflation pending a dedicated category decision).

  2. One-hop expansion multi-anchor exclusion — Runtime authorization-path change. Migration 20260803_0055 replaces the SECURITY DEFINER one-hop expansion function so the exclusion applies against the request's FULL anchor set (previously each candidate was only checked against its own anchor, so an authorized other main anchor could be returned and the Runtime guard at materialized.py raised). The Runtime raise remains in place as defense-in-depth. The migration also adds GRANT DELETE ON file_publication_recovery to the definer role. A live HTTP regression reproduces the original multi-anchor defect (verified to fail on the downgraded function and pass on the fixed one).

Verification (builder + independent E-230 review): lint / strict typecheck / 2582 unit / 135 catalog + governance / integration slice green; warm-preload mutation kills 8 of 9 pinned tests; deployed function body byte-equivalent to the migration on the live database.

Coordinator note: this PR body was corrected after independent review found the original record understated the security-relevant migration and misstated the batch size.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds distinct timeout and document-refusal contracts for local embeddings, persists acquired-document refusals through a protected database function, and updates one-hop graph resolution to exclude the complete requested anchor set.

Changes

Embedding refusal flow

Layer / File(s) Summary
Local embedding timeout contract
adapters/_bounded_call.py, adapters/embeddings.py, engine/supply/..., tests/unit/test_local_qwen_embedding_provider.py
Bounded calls now distinguish timeouts from unavailable backends. Local Qwen embedding performs warmup, uses single-item document batches, and raises EmbeddingDocumentRefused for document timeouts.
Acquired document refusal cleanup
migrations/versions/20260803_0054_bounded_embedding_refusal.py, engine/persistence/file_imports.py, engine/persistence/schema_security_manifest.yaml, tests/integration/test_fragment_embeddings.py, tests/unit/test_schema_security_manifest.py
File imports record unsupported-document-shape refusals through a lease-bound database function. The function validates the lease, deletes acquired recovery state, and marks the job failed. Integration tests verify generic refusal output and absent vectors.

One-hop anchor resolution

Layer / File(s) Summary
Full anchor-set resolver behavior
migrations/versions/20260803_0055_exclude_full_one_hop_anchor_set.py, tests/integration/test_one_hop_graph_http_sdk.py
The one-hop resolver now excludes all requested anchors while retaining authorization, pagination, and row-security checks. The HTTP SDK test verifies evidence from multiple authorized roots.

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.26% 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two main changes: bounded local embedding micro-batches and one-hop multi-anchor exclusion.
✨ 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/fix-qwen-document-batch-timeout

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a892dd2de

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread adapters/embeddings.py Outdated
thread_name="context-engine-local-embedding",
in_flight_lock=self._inference_lock,
)
for raw_vector in raw_vectors:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate cardinality for each encoded batch

stometa, when individual backend responses have incorrect counts that cancel across batches—for example, seven vectors for the first eight inputs and two for the final input—the concatenated list still has the expected total length, so the final validate_embedding_batch accepts it and persists shifted or unrelated Fragment embeddings. Validate each raw_vectors result against its corresponding batch so every wrong-cardinality response fails closed as required by ADR-0102.

AGENTS.md reference: AGENTS.md:L23-L27

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 97daac1d23

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread adapters/embeddings.py
Comment on lines +295 to +298
self._reduce_vectors(
(_LOCAL_EMBEDDING_WARMUP_TEXT,),
self._encode_model_inputs([_LOCAL_EMBEDDING_WARMUP_TEXT]),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep warmup behind the inference deadline

stometa, if the model wedges during its first inference, this direct _encode_model_inputs call makes provider construction—and therefore process startup—hang indefinitely instead of returning the generic bounded failure required by ADR-0102 clause 6. Run the warmup through invoke_bounded with the same lock and deadline, or remove it.

AGENTS.md reference: AGENTS.md:L23-L27

Useful? React with 👍 / 👎.

Comment thread adapters/embeddings.py
Comment on lines +359 to +363
except BoundedCallTimedOut:
if document and len(batch) == 1:
raise EmbeddingDocumentRefused(
"Embedding document is outside provider bounds"
) from None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep transient document timeouts recoverable

stometa, whenever a valid single-fragment inference exceeds 30 seconds because the host is overloaded or the backend stalls transiently, this converts the timeout into EmbeddingDocumentRefused; the worker then deletes the acquired recovery state and permanently reports unsupported_document_shape, even though a retry may succeed. ADR-0102 clause 6 explicitly classifies timeouts as provider unavailability that leaves acquired publication recoverable, so reserve terminal document refusal for a deterministic input-bound check rather than elapsed time.

AGENTS.md reference: AGENTS.md:L23-L27

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f9b9942aa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +55 to +56
OR requested_compilation_refusal_category <>
'unsupported_document_shape'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject NULL embedding-refusal categories

stometa, when a worker invokes this SECURITY DEFINER function with a valid acquired lease but a NULL category, PostgreSQL evaluates the <> expression to NULL and the IF does not return. The function then deletes the recoverable checkpoint and permanently fails the job while storing no unsupported_document_shape category, bypassing the function's sole admitted refusal reason; use a NULL-safe comparison such as IS DISTINCT FROM.

Useful? React with 👍 / 👎.

@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: 4

🧹 Nitpick comments (3)
tests/integration/test_one_hop_graph_http_sdk.py (2)

119-162: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider collapsing _RootOnlyCandidateIndex into _MultipleRootCandidateIndex.

_RootOnlyCandidateIndex at lines 75-116 is now the single-root case of this class. The three methods are identical except for the candidate tuple. One class removes about 40 duplicated lines and keeps the two tests on one seam implementation.

Keep _RootOnlyCandidateIndex only if you want the single-root name to document intent at the call sites.

♻️ Proposed consolidation
-class _RootOnlyCandidateIndex:
-    """Submit only the main-path root; graph structure is not index authority."""
-
-    def __init__(self, root: CandidateRef) -> None:
-        self.root = root
+class _MultipleRootCandidateIndex:
+    """Submit authorized main-path roots; graph structure is not index authority."""
+
+    def __init__(self, roots: tuple[CandidateRef, ...]) -> None:
+        self.roots = roots

Then call _MultipleRootCandidateIndex((root,)) at the existing single-root call site and delete the duplicated class.

🤖 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 `@tests/integration/test_one_hop_graph_http_sdk.py` around lines 119 - 162,
Consolidate the duplicate _RootOnlyCandidateIndex implementation into
_MultipleRootCandidateIndex by deleting the former class and updating its
single-root call site to construct _MultipleRootCandidateIndex with a
one-element tuple, while preserving the existing test behavior.

746-750: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the one-hop exclusion, not just resource-ref presence.

_MultipleRootCandidateIndex submits both first and second as requested anchors. Both resource refs reach delivered_resources through the main path, so these assertions pass whether second is returned as a one-hop neighbor of first or excluded. Count the evidence items and assert second is not emitted as a graph-expanded neighbor of first, or assert that each delivered fragment ref appears exactly once.

🤖 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 `@tests/integration/test_one_hop_graph_http_sdk.py` around lines 746 - 750,
Update the assertions around delivered_resources in the one-hop graph test to
verify the exclusion behavior, not merely resource-ref presence. Count the
evidence items or otherwise inspect their fragment refs so the test proves
second is not emitted as a graph-expanded neighbor of first, while preserving
validation that the requested anchors are delivered.

Source: Coding guidelines

tests/unit/test_local_qwen_embedding_provider.py (1)

251-264: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert that a lock-contended call is not a document refusal.

EmbeddingDocumentRefused subclasses EmbeddingProviderUnavailable, so both pytest.raises blocks pass for either exception. The distinction is important: a document refusal permanently fails the import job through _refuse_acquired_embedding_document, while provider unavailability produces a retryable interruption. The second call here is rejected by the in-flight lock and must stay retryable.

Add a negative assertion so the test proves the classification.

💚 Proposed test strengthening
     started = monotonic()
-    with pytest.raises(EmbeddingProviderUnavailable):
+    with pytest.raises(EmbeddingProviderUnavailable) as first_failure:
         provider.embed_documents(("document text",))
     first_elapsed = monotonic() - started
 
     started = monotonic()
-    with pytest.raises(EmbeddingProviderUnavailable):
+    with pytest.raises(EmbeddingProviderUnavailable) as second_failure:
         provider.embed_documents(("document text",))
     second_elapsed = monotonic() - started
     release.set()
 
+    assert not isinstance(second_failure.value, EmbeddingDocumentRefused)
+    assert type(first_failure.value) is EmbeddingProviderUnavailable
     assert first_elapsed < 0.5
     assert second_elapsed < 0.5
     assert model.calls == 2
🤖 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 `@tests/unit/test_local_qwen_embedding_provider.py` around lines 251 - 264,
Strengthen the two pytest.raises checks around provider.embed_documents in the
lock-contention test to assert the raised exception is specifically
EmbeddingProviderUnavailable and not its EmbeddingDocumentRefused subclass.
Preserve the existing timing and model.calls assertions while proving the
contended second call remains retryable.
🤖 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 `@adapters/embeddings.py`:
- Around line 294-302: Update the warmup encode in
LocalQwenEmbeddingProvider.__init__ to invoke _encode_model_inputs through
invoke_bounded, passing self._inference_lock and the same timeout configuration
used for other model calls; keep the existing _reduce_vectors flow and
EmbeddingProviderUnavailable error translation intact.

In `@engine/persistence/schema_security_manifest.yaml`:
- Around line 8868-8869: Correct the schema manifest’s DELETE authority by
removing it from the file_import_job declaration and adding it to
file_publication_recovery for context_engine_worker_lease_definer. Add
context_worker_refuse_acquired_embedding_document to
file_publication_recovery.functionOnlyMutation.databaseFunctions and add
file_publication_recovery to fail_file_import.atomicWrites. Confirm the manifest
versioning convention and advance manifestVersion beyond 44.0.0 if required.

In `@migrations/versions/20260803_0054_bounded_embedding_refusal.py`:
- Around line 102-104: The recovery-row DELETE authorization must be restricted
to exactly one row with checkpoint='acquired'. Update
context_worker_refuse_acquired_embedding_document and the corresponding
policy/command entry in engine/persistence/schema_security_manifest.yaml at
lines 8868-8869 to enforce that predicate, and update
context_worker_fail_file_import_with_category to capture the DELETE row count
and return true only when exactly one acquired recovery row was deleted.

In `@tests/integration/test_fragment_embeddings.py`:
- Around line 396-427: Extend the test covering
context_worker_refuse_acquired_embedding_document to assert the scenario’s
file_publication_recovery row is deleted, not merely that the job is failed and
vectors are absent. Also inspect the captured traceback or error output and
assert it does not contain the provider detail string “provider document detail
must not escape”, while preserving the existing refusal and job-state
assertions.

---

Nitpick comments:
In `@tests/integration/test_one_hop_graph_http_sdk.py`:
- Around line 119-162: Consolidate the duplicate _RootOnlyCandidateIndex
implementation into _MultipleRootCandidateIndex by deleting the former class and
updating its single-root call site to construct _MultipleRootCandidateIndex with
a one-element tuple, while preserving the existing test behavior.
- Around line 746-750: Update the assertions around delivered_resources in the
one-hop graph test to verify the exclusion behavior, not merely resource-ref
presence. Count the evidence items or otherwise inspect their fragment refs so
the test proves second is not emitted as a graph-expanded neighbor of first,
while preserving validation that the requested anchors are delivered.

In `@tests/unit/test_local_qwen_embedding_provider.py`:
- Around line 251-264: Strengthen the two pytest.raises checks around
provider.embed_documents in the lock-contention test to assert the raised
exception is specifically EmbeddingProviderUnavailable and not its
EmbeddingDocumentRefused subclass. Preserve the existing timing and model.calls
assertions while proving the contended second call remains retryable.
🪄 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: c7519a2d-2129-4c6b-bc96-fb0c545a6300

📥 Commits

Reviewing files that changed from the base of the PR and between bc86c22 and 4f9b994.

📒 Files selected for processing (12)
  • adapters/_bounded_call.py
  • adapters/embeddings.py
  • engine/persistence/file_imports.py
  • engine/persistence/schema_security_manifest.yaml
  • engine/supply/__init__.py
  • engine/supply/embeddings.py
  • migrations/versions/20260803_0054_bounded_embedding_refusal.py
  • migrations/versions/20260803_0055_exclude_full_one_hop_anchor_set.py
  • tests/integration/test_fragment_embeddings.py
  • tests/integration/test_one_hop_graph_http_sdk.py
  • tests/unit/test_local_qwen_embedding_provider.py
  • tests/unit/test_schema_security_manifest.py

Comment thread adapters/embeddings.py
Comment on lines +294 to +302
try:
self._reduce_vectors(
(_LOCAL_EMBEDDING_WARMUP_TEXT,),
self._encode_model_inputs([_LOCAL_EMBEDDING_WARMUP_TEXT]),
)
except Exception:
raise EmbeddingProviderUnavailable(
"Embedding provider is unavailable"
) from None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Bound the warmup encode with invoke_bounded.

The model load on Line 283 is deadline-bounded. The warmup encode on Lines 295-298 is not. If the sentence-transformers backend stalls during the first encode, LocalQwenEmbeddingProvider.__init__ blocks with no deadline and no recovery. Every other model call in this class goes through invoke_bounded. Apply the same bound here.

Note that the warmup runs after invoke_bounded released self._inference_lock, so passing the lock again is safe.

🛡️ Proposed fix to bound the warmup call
         self._model: Any = model
         try:
             self._reduce_vectors(
                 (_LOCAL_EMBEDDING_WARMUP_TEXT,),
-                self._encode_model_inputs([_LOCAL_EMBEDDING_WARMUP_TEXT]),
+                invoke_bounded(
+                    partial(
+                        self._encode_model_inputs,
+                        [_LOCAL_EMBEDDING_WARMUP_TEXT],
+                    ),
+                    timeout_seconds=_LOCAL_EMBEDDING_TIMEOUT_SECONDS,
+                    thread_name="context-engine-local-embedding",
+                    in_flight_lock=self._inference_lock,
+                ),
             )
-        except Exception:
+        except Exception:  # noqa: BLE001
             raise EmbeddingProviderUnavailable(
                 "Embedding provider is unavailable"
             ) from None
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
self._reduce_vectors(
(_LOCAL_EMBEDDING_WARMUP_TEXT,),
self._encode_model_inputs([_LOCAL_EMBEDDING_WARMUP_TEXT]),
)
except Exception:
raise EmbeddingProviderUnavailable(
"Embedding provider is unavailable"
) from None
try:
self._reduce_vectors(
(_LOCAL_EMBEDDING_WARMUP_TEXT,),
invoke_bounded(
partial(
self._encode_model_inputs,
[_LOCAL_EMBEDDING_WARMUP_TEXT],
),
timeout_seconds=_LOCAL_EMBEDDING_TIMEOUT_SECONDS,
thread_name="context-engine-local-embedding",
in_flight_lock=self._inference_lock,
),
)
except Exception: # noqa: BLE001
raise EmbeddingProviderUnavailable(
"Embedding provider is unavailable"
) from None
🧰 Tools
🪛 Ruff (0.16.0)

[warning] 299-299: Do not catch blind exception: Exception

(BLE001)

🤖 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 `@adapters/embeddings.py` around lines 294 - 302, Update the warmup encode in
LocalQwenEmbeddingProvider.__init__ to invoke _encode_model_inputs through
invoke_bounded, passing self._inference_lock and the same timeout configuration
used for other model calls; keep the existing _reduce_vectors flow and
EmbeddingProviderUnavailable error translation intact.

Comment on lines +8868 to +8869
"UPDATE",
"DELETE acquired recovery only through context_worker_refuse_acquired_embedding_document"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

The DELETE authority is recorded against the wrong table.

context_worker_refuse_acquired_embedding_document never deletes from file_import_job. It only runs UPDATE public.file_import_job (migration Lines 105-112). The DELETE it performs targets public.file_publication_recovery (migration Lines 102-104), and the migration grants DELETE ON TABLE public.file_publication_recovery to the definer (migration Lines 31-33).

Three declarations are now wrong:

  • Line 8869 grants file_import_job a DELETE authority that no migration grants and no code exercises. This overstates the privilege surface of the most sensitive job table.
  • The file_publication_recovery entry (Lines 9057-9061) still lists only SELECT, INSERT, UPDATE for context_engine_worker_lease_definer, so the real DELETE grant is undeclared.
  • file_publication_recovery.functionOnlyMutation.databaseFunctions (Lines 9039-9044) omits context_worker_refuse_acquired_embedding_document, and fail_file_import.atomicWrites (Lines 706-708) omits file_publication_recovery.

Move the DELETE declaration to the table it applies to and record the new mutation path there. Also confirm whether manifestVersion must advance past 44.0.0 for this change.

🔒️ Proposed manifest corrections
         "context_engine_worker_lease_definer": [
           "SELECT",
           "INSERT",
-          "UPDATE",
-          "DELETE acquired recovery only through context_worker_refuse_acquired_embedding_document"
+          "UPDATE"
         ],

Then update the file_publication_recovery entry:

       "functionOnlyMutation": {
         "databaseFunctions": [
           "context_worker_acquire_file_publication",
           "context_worker_prepare_file_publication",
           "context_worker_index_file_publication",
-          "context_worker_activate_recoverable_file_publication"
+          "context_worker_activate_recoverable_file_publication",
+          "context_worker_refuse_acquired_embedding_document"
         ],
         "context_engine_worker_lease_definer": [
           "SELECT",
           "INSERT",
-          "UPDATE"
+          "UPDATE",
+          "DELETE acquired checkpoint only through context_worker_refuse_acquired_embedding_document"
         ]

And the fail_file_import operation:

       "atomicWrites": [
-        "file_import_job"
+        "file_import_job",
+        "file_publication_recovery"
       ]
🤖 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 `@engine/persistence/schema_security_manifest.yaml` around lines 8868 - 8869,
Correct the schema manifest’s DELETE authority by removing it from the
file_import_job declaration and adding it to file_publication_recovery for
context_engine_worker_lease_definer. Add
context_worker_refuse_acquired_embedding_document to
file_publication_recovery.functionOnlyMutation.databaseFunctions and add
file_publication_recovery to fail_file_import.atomicWrites. Confirm the manifest
versioning convention and advance manifestVersion beyond 44.0.0 if required.

Comment on lines +102 to +104
DELETE FROM public.file_publication_recovery AS recovery
WHERE recovery.organization_id = requested_organization_id
AND recovery.job_id = requested_job_id;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Confirm existing RLS policies, grants, and manifest declarations for file_publication_recovery.
set -euo pipefail

echo "== migrations touching file_publication_recovery =="
rg -n -C 8 'file_publication_recovery' --glob 'migrations/**/*.py' \
  | rg -n 'POLICY|ROW LEVEL SECURITY|FORCE|GRANT|REVOKE|DELETE|CREATE TABLE'

echo "== manifest declaration =="
rg -n -A 70 '"name": "file_publication_recovery"' engine/persistence/schema_security_manifest.yaml

Repository: stone16/context-engine

Length of output: 212


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate migration file =="
fd -a '20260803_0054_bounded_embedding_refusal\.py' . || true

echo "== migrations containing file_publication_recovery or context_worker_refuse_acquired_embedding_document =="
rg -n -i 'file_publication_recovery|context_worker_refuse_acquired_embedding_document|context_engine_worker_lease_definer' migrations engine -g '*.py' -g '*.yaml' | sed -n '1,220p'

echo "== migration file line count and relevant snippets =="
if [ -f migrations/versions/20260803_0054_bounded_embedding_refusal.py ]; then
  wc -l migrations/versions/20260803_0054_bounded_embedding_refusal.py
  sed -n '80,125p' migrations/versions/20260803_0054_bounded_embedding_refusal.py | cat -n
fi

echo "== schema_security_manifest relevant sections =="
rg -n -A 90 '"name": "file_publication_recovery"|name: file_publication_recovery|file_import_job' engine/persistence/schema_security_manifest.yaml | sed -n '1,260p'

Repository: stone16/context-engine

Length of output: 44627


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== bounded_embedding_refusal migration =="
sed -n '1,145p' migrations/versions/20260803_0054_bounded_embedding_refusal.py | cat -n

echo "== file_publication_recovery manifest section =="
sed -n '8870,9045p' engine/persistence/schema_security_manifest.yaml | cat -n

echo "== file_import_job definer section around DELETE comment =="
sed -n '8800,8885p' engine/persistence/schema_security_manifest.yaml | cat -n

echo "== all file_publication_recovery policy names in manifest =="
python3 - <<'PY'
import re, pathlib
path=pathlib.Path("engine/persistence/schema_security_manifest.yaml")
text=path.read_text()
# simple state machine around table entries is not needed; grab lines mentioning file_publication_recovery policies
for line in open(path):
    if "file_publication_recovery_file_import_definer" in line or "file_publication_recovery" in line and "POLICY" in line:
        print(line.rstrip())
PY

Repository: stone16/context-engine

Length of output: 18672


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== context_worker_fail_file_import migration around acquire/delete policy =="
rg -n -A 120 -B 25 'context_worker_fail_file_import' migrations/versions/20260803_0054_bounded_embedding_refusal.py | cat -n

echo "== all file_import_job RLS definer policies in migration files =="
rg -n -A 4 'file_import_job_.*definer_(select|insert|update|delete)|file_import_job .* FOR (SELECT|INSERT|UPDATE|DELETE) .* FOR PUBLIC|GRANT SELECT, INSERT, UPDATE, DELETE' migrations/versions/*.py | sed -n '1,260p'

echo "== all CREATE POLICY lines in migration files with file_publication_recovery and file_import_job =="
rg -n -C 6 'CREATE POLICY .*file_(publication_recovery|import_job).*definer|CREATE POLICY file_publication_recovery.*FOR DELETE|CREATE POLICY file_import_job.*FOR DELETE' migrations/versions/*.py | sed -n '1,260p'

echo "== read-only Python parser of PLpgSQL RETURN FOUND assignment and UPDATE target =="
python3 - <<'PY'
from pathlib import Path
p=Path("migrations/versions/20260803_0054_bounded_embedding_refusal.py")
s=p.read_text()
start=s.index("CREATE FUNCTION")
end=s.index("END; $function$")
body=s[start:end]
print("contains RETURN FOUND:", "RETURN FOUND;\n" in body)
print("contains assignment to FOUND variable:", "FOUND :=" in body or "Found :=\n" in body)
print("contains DELETE from acquisition table:", "DELETE FROM public.file_publication_recovery" in body)
print("contains UPDATE target with FOR UPDATE before RETURN FOUND:", "UPDATE public.file_import_job AS job" in body[s.find("RETURN FOUND;"):])
PY

Repository: stone16/context-engine

Length of output: 237


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== context_worker_fail_file_import in migration files =="
rg -n -C 40 'context_worker_fail_file_import' migrations engine | sed -n '1,260p'

echo "== RLS policies for file_publication_recovery and file_import_job definers =="
rg -n -C 6 'file_(publication_recovery|import_job)_(migrator|file_import|.*definer|.*acquisition).*FOR' migrations -g '*.py' | sed -n '1,320p'

echo "== grant lines with DELETE on recovery or import tables =="
rg -n 'GRANT .*DELETE.*ON TABLE (public\.)?file_(publication_recovery|import_job)|GRANT SELECT, INSERT, UPDATE, DELETE (ON TABLE (public\.)?)?file_import_job|GRANT SELECT, INSERT, UPDATE(, DELETE| FROM _DEFINER| ON file_publication_recovery)' migrations/versions -g '*.py' | sed -n '1,260p'

echo "== read-only Python parser of control-flow comments =="
python3 - <<'PY'
from pathlib import Path
p=Path("migrations/versions/20260803_0054_bounded_embedding_refusal.py")
text=p.read_text()
print("DELETE from public.file_publication_recovery:", "DELETE FROM public.file_publication_recovery" in text)
print("UPDATE public.file_import_job AS job:", "UPDATE public.file_import_job AS job" in text)
idx = text.index("RETURN FOUND;")
last_statement = text[text.rfind(";", 0, idx):idx+1]
print("last control-flow statement before RETURN FOUND:", repr(last_statement.strip()))
PY

Repository: stone16/context-engine

Length of output: 28488


🌐 Web query:

PostgreSQL FORCE ROW LEVEL SECURITY implicit USING policy default deny if no matching policy

💡 Result:

In PostgreSQL, when Row Level Security (RLS) is enabled on a table, the system enforces a default-deny policy if no specific policies are defined [1][2]. This means that if RLS is enabled but no policies have been created, no rows will be visible or modifiable by anyone subject to RLS [1][3]. The command ALTER TABLE... FORCE ROW LEVEL SECURITY does not change this default-deny behavior; rather, it extends the enforcement of existing RLS policies to the table owner [1][4]. By default, PostgreSQL table owners are exempt from RLS policies [1][5]. Using FORCE ROW LEVEL SECURITY ensures that the table owner is also subject to these policies, which is a common best practice for production environments to prevent accidental data access or modification by highly privileged roles [4]. In summary: 1. RLS Enabled (ENABLE ROW LEVEL SECURITY): Standard users are subject to RLS; table owners are typically exempt [1][6]. 2. Default-Deny: If RLS is enabled but no policy exists, all rows are effectively hidden/locked for those subject to RLS [1][2]. 3. FORCE ROW LEVEL SECURITY: This option forces the table owner to be subject to the same RLS policies as other users, ensuring that no user (including the owner) can bypass the defined restrictions [1][4]. Superusers and roles with the BYPASSRLS attribute are always exempt from RLS, regardless of whether FORCE ROW LEVEL SECURITY is enabled [1][6].

Citations:


Add DELETE authorization only for the acquired recovery row. context_worker_refuse_acquired_embedding_document deletes where recovery.checkpoint = 'acquired', but context_worker_fail_file_import_with_category uses RETURN FOUND after deleting the lock-row and updating file_import_job. A broad recovery DELETE policy or a DELETE grant on file_publication_recovery alone can make that path return true without deleting exactly one acquired recovery. Narrow the policy/command to the acquired checkpoint and use an explicit row-count comparison before returning.

📍 Affects 2 files
  • migrations/versions/20260803_0054_bounded_embedding_refusal.py#L102-L104 (this comment)
  • engine/persistence/schema_security_manifest.yaml#L8868-L8869
🤖 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 `@migrations/versions/20260803_0054_bounded_embedding_refusal.py` around lines
102 - 104, The recovery-row DELETE authorization must be restricted to exactly
one row with checkpoint='acquired'. Update
context_worker_refuse_acquired_embedding_document and the corresponding
policy/command entry in engine/persistence/schema_security_manifest.yaml at
lines 8868-8869 to enforce that predicate, and update
context_worker_fail_file_import_with_category to capture the DELETE row count
and return true only when exactly one acquired recovery row was deleted.

Comment on lines +396 to +427
with pytest.raises(FileImportRefused, match="File import is unavailable"):
_run(
_worker(
scenario,
guarded_worker_engine,
_BoundedDocumentRefusalProvider(),
),
scenario,
scenario.token,
)

engine = create_database_engine(migration_configuration)
try:
with engine.connect() as connection:
job = connection.execute(
text(
"""
SELECT state, compilation_refusal_category
FROM file_import_job
WHERE organization_id = :organization_id
AND job_id = :job_id
"""
),
{
"organization_id": scenario.organization_id,
"job_id": scenario.prepared.job_id,
},
).one()
assert tuple(job) == ("failed", "unsupported_document_shape")
finally:
engine.dispose()
assert _stored_vectors(migration_configuration, scenario) == ()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Assert that the acquired recovery row is deleted.

The purpose of context_worker_refuse_acquired_embedding_document is to clear the acquired file_publication_recovery checkpoint and seal the job. This test verifies the job state and the absence of vectors, but never verifies the deletion. A DELETE that removes zero rows would still pass every current assertion, because RETURN FOUND reflects the later UPDATE. See the related concern on migrations/versions/20260803_0054_bounded_embedding_refusal.py Lines 102-104.

Also assert that the provider message does not reach the traceback. _embedding_document raises from None, and the double deliberately carries "provider document detail must not escape".

💚 Proposed additional assertions
-    with pytest.raises(FileImportRefused, match="File import is unavailable"):
+    with pytest.raises(
+        FileImportRefused, match="File import is unavailable"
+    ) as failure:
         _run(
             _worker(
                 scenario,
                 guarded_worker_engine,
                 _BoundedDocumentRefusalProvider(),
             ),
             scenario,
             scenario.token,
         )
+    assert failure.value.__cause__ is None
 
     engine = create_database_engine(migration_configuration)
     try:
         with engine.connect() as connection:
             job = connection.execute(
                 text(
                     """
                     SELECT state, compilation_refusal_category
                     FROM file_import_job
                     WHERE organization_id = :organization_id
                       AND job_id = :job_id
                     """
                 ),
                 {
                     "organization_id": scenario.organization_id,
                     "job_id": scenario.prepared.job_id,
                 },
             ).one()
+            recovery_rows = connection.execute(
+                text(
+                    """
+                    SELECT count(*)
+                    FROM file_publication_recovery
+                    WHERE organization_id = :organization_id
+                      AND job_id = :job_id
+                    """
+                ),
+                {
+                    "organization_id": scenario.organization_id,
+                    "job_id": scenario.prepared.job_id,
+                },
+            ).scalar_one()
         assert tuple(job) == ("failed", "unsupported_document_shape")
+        assert recovery_rows == 0
     finally:
         engine.dispose()
🤖 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 `@tests/integration/test_fragment_embeddings.py` around lines 396 - 427, Extend
the test covering context_worker_refuse_acquired_embedding_document to assert
the scenario’s file_publication_recovery row is deleted, not merely that the job
is failed and vectors are absent. Also inspect the captured traceback or error
output and assert it does not contain the provider detail string “provider
document detail must not escape”, while preserving the existing refusal and
job-state assertions.

@stone16 stone16 changed the title fix: bound local embedding document batches fix: bounded micro-batch local embedding and one-hop multi-anchor exclusion Aug 3, 2026
@stone16
stone16 merged commit c709740 into main Aug 3, 2026
2 checks passed
@stone16
stone16 deleted the codex/fix-qwen-document-batch-timeout branch August 3, 2026 02:26
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.

1 participant