ContextNest vs Amazon Bedrock Knowledge Bases (vector + GraphRAG), v3.1

Misha Sulpovar, PromptOwl · benchmark run 2026-10-13 to 2026-10-14 · paper v3.1, 2026-10-28 (first draft 2026-10-14) · amends and extends the report of 2026-10-02 (reproduced unchanged in the Annex)

We compared ContextNest's search (ctx) with Amazon Bedrock Knowledge Bases, vector and GraphRAG, on four datasets: BEIR SciFact (300 queries), BEIR NFCorpus (323), MultiHop-RAG (529 with evidence) and VersionedDocs, a corpus of 180 Kubernetes documentation pages with their previous versions (541 questions, plus 155 paraphrases). The protocol was frozen before any Bedrock result; every later change is a dated amendment, and all of them are listed below. Both sides used the same embedder (Amazon Titan Text Embeddings v2), the same reranker (Cohere Rerank 3.5) and the same rerank budget. Answers were written by Claude Sonnet 4.6 and graded by one primary judge (Claude Opus 4.6) for every arm, checked by gpt-oss-120b; judges never saw the retrieved context. ctx with passage rerank scored higher NDCG@10 than Bedrock's best fair setup on SciFact, NFCorpus and VersionedDocs, each statistically significant. On MultiHop-RAG the two were level and the pre-registered parity rule was narrowly not met; answer accuracy there was 65.7% for ctx and 66.0% for Bedrock. Bedrock GraphRAG, at its best result count, trailed every other arm on retrieval and answered 39.0% of MultiHop-RAG questions correctly. With old copies stored next to new ones, Bedrock put a superseded version in the top 10 for 86% of VersionedDocs questions; ContextNest's versioned nest did so for none. SciFact and NFCorpus were used to choose ctx defaults, and MultiHop-RAG was used to fix ctx lexical scoring, so VersionedDocs is the only held-out comparison. Every ctx arm re-run so far on the released ctx 3.4.0 reproduced the release-candidate numbers exactly, with identical top-10 lists (keyword search on every dataset; hybrid on SciFact, NFCorpus and VersionedDocs; hybrid + passage rerank on SciFact). The remaining hybrid + rerank re-runs (NFCorpus, MultiHop-RAG, VersionedDocs) are in progress; any difference will be published as an update (A20). An audit found that only 278 of the 541 VersionedDocs questions describe a real change of fact (A21), so every VersionedDocs result is reported on both the full set and the validated subset; the conclusions hold on both, and on the validated subset Bedrock with rerank gave a stale answer to 17.4% of questions against 0.8% for ctx.

Released software. The engine changes this benchmark prompted shipped in @promptowl/contextnest-cli@3.4.0. Every ctx arm re-run so far on the released ctx 3.4.0 reproduced the release-candidate numbers exactly, with identical top-10 lists (keyword search on every dataset; hybrid on SciFact, NFCorpus and VersionedDocs; hybrid + passage rerank on SciFact). The remaining hybrid + rerank re-runs (NFCorpus, MultiHop-RAG, VersionedDocs) are in progress; any difference will be published as an update (A20). Before those changes (section 8), ctx 3.0.0 scored 0.604 NDCG@10 on SciFact.

  1. What changed since v2 and why
  2. Executive results
  3. Method
  4. Results: full tables
  5. GraphRAG analysis
  6. Governance results
  7. Cost
  8. What we fixed in ContextNest because of this
  9. Limitations
  10. Reproduce it
  11. Annex: the v2 report (2026-10-02), unchanged

1. What changed since v2 and why

The v2 report tested one question on 30 questions over 11 short documents. The reviewer's verdict was that it was "not a defensible conclusion". This table maps each request to what v3 does about it.

Requestv2 (2026-10-02)v3 (this paper)
"a defensible conclusion"No pre-registration; small synthetic corpus; our own questionsProtocol frozen 2026-10-13 before any Bedrock result. Parity defined in advance. 21 dated amendments, each disclosed with the numbers it affects. All arms published, including the ones ctx loses. Raw per-query runs and the scripts that produce every table.
"more data"30 questions on 6 documents4 datasets: 300 + 323 + 529 + 541 retrieval queries, plus 155 paraphrases, over 5,183 / 3,633 / 609 / 180 (+180 previous) documents. Answer grading on 300 MultiHop-RAG and 250 VersionedDocs questions per arm.
"MRR, NDCG, mAP"Hit rates with Wilson intervalsNDCG@10 (primary), MRR@10, MAP@10, Recall@20. Headline differences carry a 95% bootstrap CI and a paired randomization p-value.
"modern models" (no Amazon Nova)Nova Pro for answers and GraphRAG extraction; Mistral Large 3 judgeNo Nova anywhere. GraphRAG extraction: Claude Haiku 4.5. Answers: Claude Sonnet 4.6. Judges: Claude Opus 4.6 (primary), gpt-oss-120b (check). Reranker: Cohere Rerank 3.5. Embeddings: Titan Text Embeddings v2 (Bedrock Knowledge Bases rejected Cohere Embed v4; A16).
"at least parity" with Bedrock's GraphRAGGraphRAG on single-fact lookups, where a graph does little workGraphRAG on MultiHop-RAG, a published multi-hop benchmark and its intended case, and on VersionedDocs, at five result counts. Parity rule: the 95% CI of the per-query NDCG@10 difference (ctx − Bedrock) lies above −0.02. Also compared against Bedrock vector with rerank, which turned out to be Bedrock's strongest arm.
"the same LLM-as-a-judge for both"One judge, from a third model familyOne answer model and one primary judge for every arm. The judge sees the question, the gold answer and the system's answer, never the retrieved context. A second judge from another family gives Cohen's κ.
"other measurements to compare graphs"NoneEvidence-Complete@k (all gold evidence articles in the top k), Recall@20, distinct documents returned per query, Stale@10, indexing time and cost.

2. Executive results

Retrieval: headline comparison per dataset (NDCG@10)

"Bedrock best" is the strongest fair Bedrock arm on that dataset: vector + Cohere Rerank 3.5 (B2) on the BEIR and MultiHop-RAG sets, and vector with a status=current metadata filter (B1-filter) on VersionedDocs, since B2 there returns superseded versions in 90% of top-10 lists. "ctx" is ctx hybrid + passage rerank (C3p).

DatasetRole for ctxBedrock bestctx (C3p)Difference [95% CI]pParity ruleGraphRAG (best count)
SciFactdevelopment (A7)0.7340.770+0.035
[+0.015, +0.058]
0.0008met; ctx betternot run
NFCorpusdevelopment (A7)0.3410.361+0.020
[+0.007, +0.033]
0.0013met; ctx betternot run
MultiHop-RAGdev for lexical (A8); C3p post-hoc (A17)0.7950.787−0.008
[−0.025, +0.009]
0.3482not met0.529
10 results
VersionedDocsheld-out0.8270.902+0.075
[+0.047, +0.102]
0.0000met; ctx better0.594
5 results
VersionedDocs, paraphrasedheld-out0.7230.770+0.048
[−0.001, +0.096]
0.0620met; not significant—
VersionedDocs, validated items (278)held-out (A21)0.8210.898+0.077
[+0.038, +0.117]
0.0000met; ctx better—
VersionedDocs, paraphrased, validated (91)held-out (A21)0.7420.790+0.048
[−0.022, +0.116]
0.1924not met—

GraphRAG was not run on the BEIR sets (A9). p = paired randomization test, as reported by make_results.py (0.0000 means no permutation reached the observed difference). Source: results/final.md.

MultiHop-RAG, plainly: the lower CI bound is −0.025 and the rule needs it above −0.020, so parity is not established there. Neither is a Bedrock advantage (p = 0.3482). The answer-level result on the same dataset is a tie.

Answers (Claude Sonnet 4.6 answers; Claude Opus 4.6 judge)

Dataset (sample)ArmCorrectStaleMissingWrong
MultiHop-RAG (300)Bedrock vector + rerank (B2)66.0%0.0%25.7%5.3%
ctx, engine passages (C3pass)65.7%0.0%25.7%5.3%
Bedrock GraphRAG, 10 results39.0%0.0%54.7%3.7%
VersionedDocs (250)Nest feeding Bedrock (F1)74.4%1.2%14.8%8.8%
ctx, engine passages (C3pass)73.2%2.0%17.2%6.4%
Bedrock vector + rerank (B2)64.0%13.6%5.6%4.8%
Bedrock GraphRAG, 5 results54.8%12.0%20.4%6.4%

Hedged answers make up the remainder of each row; full rows, including the superseded whole-document ctx arm, are in section 4. Judge agreement (Cohen's κ, primary vs check): 0.7462 on MultiHop-RAG, 0.8781 on VersionedDocs.

Stale versions (VersionedDocs, old and new copies both present)

ArmStale@10Stale answers
Bedrock vector, no filter (B1)0.863not graded
Bedrock vector + rerank (B2)0.90013.6%
Bedrock GraphRAG, 5 results0.70812.0%
Bedrock + status=current filter (B1-filter)0.000not graded
Nest feeding Bedrock (F1)0.0001.2%
ctx, versioned nest (C3p / C3pass)0.0002.0%
ctx, old copies stored as plain files (flat C1)0.861not graded

Validated items only (A21). On the 278 questions whose answer really changed, the pattern is the same and the stale-answer gap is wider:

ArmStale@10Correct answersStale answers
Bedrock vector, no filter (B1)0.903not gradednot graded
Bedrock vector + rerank (B2)0.94656.8%17.4%
Bedrock GraphRAG, 5 results0.76345.5%16.7%
Bedrock + status=current filter (B1-filter)0.000not gradednot graded
Nest feeding Bedrock (F1)0.00073.5%0.8%
ctx, versioned nest (C3p / C3pass)0.00077.3%0.8%
ctx, old copies stored as plain files (flat C1)0.910not gradednot graded

Answer rates are on the 132 questions of the 250-question answer sample that pass the audit; Stale@10 on all 278.

Stale@10 = share of questions whose top 10 contains the superseded version of the gold page. The flat ctx arm leaks like Bedrock does: the advantage comes from versioning, not from the search engine.

3. Method

Datasets

DatasetDocsQueries scoredRelevanceRole for ctx
BEIR SciFact5,183300binarydevelopment set for ctx defaults (A7)
BEIR NFCorpus3,633323gradeddevelopment set for ctx defaults (A7)
MultiHop-RAG609529 (of a frozen 600-query sample, seed 13; 71 no-evidence queries excluded from retrieval, A1)gold evidence listdevelopment set for ctx lexical scoring (A8); passage rerank post-hoc (A17)
VersionedDocs180 current + 180 previous541, plus 155 paraphrasesgold page; gold and stale factsheld-out
BEIR FiQA-201857,638—binarypre-registered as held-out; not run (see Limitations)

VersionedDocs. Built from public git history of kubernetes/website content/en/docs: current 51675a5 (2026-10-13) against previous fb49b3e (2024-10-12). 180 pages exist in both with a changed fact-bearing sentence (A2). A model generated 1,250 questions in two passes; a validator kept 541 (56.7% dropped), requiring that the gold fact appears only in the current page and the stale fact only in the previous one, and rejecting questions that copy the page's wording. 155 strict paraphrases (no 4+-letter word from the page except names) have a query-term overlap of 0.353 against 0.796 for their originals (A14). The model's questions are a known risk; see Limitations.

Question validity (A21). A 50-item spot-check found that many generated items do not test a real change: the "change" is rewording, a typo fix or a rename of the same thing, or the gold or stale fact does not answer the question. All 541 items were then audited by Claude Sonnet 4.6 against four criteria (natural single-answer question answered by the current page; gold fact answers it; stale fact is what the previous page said; the answer genuinely changed). 278 of 541 pass (91 of the 155 paraphrases). The audit agrees with the spot-check on 39 of 50 items overall and 44 of 50 on "changed"; the spot-check was also model-made, not a human hand-check. NDCG is defined by the page a question is about, so it stays meaningful on every item; the answer-level stale label is only meaningful on valid items. Every VersionedDocs table is reported on both sets.

Arms

ArmWhat it is
BM25Reference: BM25 with stemming.
B1Bedrock Knowledge Base, vector, S3 Vectors store, Titan v2 (1024-d), default chunking, no reranker.
B2B1 + Cohere Rerank 3.5 over its top 100 chunks, one call per query.
B3Bedrock Knowledge Base GraphRAG on Neptune Analytics (16 m-NCU), CHUNK_ENTITY_EXTRACTION with Claude Haiku 4.5, Titan v2. Run at 5, 10, 20, 50 and 100 results (A18). MultiHop-RAG and VersionedDocs only (A9).
B1-filterVersionedDocs: B1 with a status=current metadata filter on every object.
F1VersionedDocs: a Bedrock vector Knowledge Base (Titan v2) fed only the nest's current published snapshot.
C1ctx lexical search (BM25, Porter stemming).
C2ctx hybrid: lexical + Titan v2 embeddings, weighted reciprocal rank fusion 1 : 2.
C3pC2 + Cohere Rerank 3.5 over the best ~300-token passage of each of the top 100 documents, one call of ≤100 passages per query: the same budget as B2 (A17).
C3 (superseded)C2 + rerank over whole documents (top 50). Published for transparency.
flat C1 / C2VersionedDocs: ctx with previous versions stored as separate plain files, as Bedrock stores them.

All arms return a ranked list of document ids; chunk hits collapse to their parent document at their best rank. Every arm received identical text (frontmatter stripped; title + body). The ctx arms were measured on the release candidate (engine commit 9e1ab02) and re-run on the published @promptowl/contextnest-cli@3.4.0 (A20; status in section 8).

Models

RoleModelNote
Embeddings, both sidesAmazon Titan Text Embeddings v2, 1024-dCohere Embed v4 was rejected by Bedrock Knowledge Bases (A16)
Rerank, both sidesCohere Rerank 3.5Same budget: one call of ≤100 items per query
GraphRAG extractionClaude Haiku 4.5AWS-documented GraphRAG extraction model (A3)
Answers, every armClaude Sonnet 4.6, temperature 06,000-character context budget, filled in rank order (A4, A19)
Primary judge, every armClaude Opus 4.6Labels CORRECT / STALE / HEDGED / MISSING / WRONG; never sees context
Check judgeOpenAI gpt-oss-120bCohen's κ against the primary is reported

The answer model is the same for every arm, so a same-family bias in the judge would apply to every arm alike and cancel in arm-to-arm differences.

Metrics and statistics

Protocol amendments

The full text is in PROTOCOL.md. Every amendment that changes a reported number is marked.

#DateChangeAffects reported numbers
A110-13MultiHop-RAG: 71 no-evidence queries in the frozen 600 are scored for answers only; retrieval uses 529.Yes: MultiHop query count
A210-13VersionedDocs: 180 qualifying pages, not ~200; validator not loosened.Yes: corpus size
A310-13GraphRAG extraction = Claude Haiku 4.5 (AWS-supported). It was accepted; no Nova fallback fired.Yes: all GraphRAG numbers
A410-13Same 6,000-character answer context budget for every arm.Yes: all answer numbers
A510-13Cross-system recall reported at 20, not 100.Yes: recall columns
A610-13Embeddings at 1024 dimensions on both sides.Yes
A710-13SciFact and NFCorpus become development sets for ctx defaults (stemming, boosts, fusion weight 1 : 2).Yes: SciFact and NFCorpus are not held-out
A810-13MultiHop-RAG inspection found MiniSearch's coordination factor; removing it makes ctx lexical a plain BM25 sum and boosts go to 1. MultiHop-RAG is reclassified as a development set for ctx lexical scoring.Yes: MultiHop ctx numbers are not held-out
A910-14Cost scope: GraphRAG on MultiHop-RAG and VersionedDocs only; FiQA local only; answers on a 300-question MultiHop subset.Yes: which arms exist
A1010-14Model lineup: Opus 4.6 primary judge for every arm; gpt-oss-120b check judge; Mistral and DeepSeek dropped.Yes: all answer numbers
A1110-14Evidence-Complete@k added for MultiHop-RAG.Yes: new metric (section 5)
A1210-14Budget: hard cap $140 enforced by the harness ledger.No
A1310-14Merged a parallel lab; Cohere Embed v4 fusion re-check; 1 : 2 kept. Preliminary Cohere numbers only.No (preliminary context only)
A1410-14VersionedDocs final: 541 questions, 155 strict paraphrases.Yes: query counts
A1510-14Answers only on the arms the claims rest on; VersionedDocs answers on a stratified 250; F1 becomes a vector KB on the current snapshot.Yes: answer samples; F1 design
A1610-14Primary embedder = Titan v2 on both sides, because Bedrock KB rejected Cohere Embed v4.Yes: all embedding arms
A1710-14Prompted by B2's MultiHop-RAG score: ctx reranks ~300-token passages, same budget as B2. C3p on MultiHop-RAG is post-hoc; VersionedDocs is the held-out test.Yes: C3p everywhere; MultiHop C3p is post-hoc
A1810-14GraphRAG result-count sensitivity: reported at every tested count, best count as headline. The MultiHop-RAG graph was rebuilt with the same configuration for the sweep.Yes: GraphRAG headline (favours Bedrock)
A1910-14Answer harness correction: ctx context had been whole documents truncated at 6,000 characters. Corrected arm C3pass uses the passages the engine returns. Both published; C3pass is the ctx figure.Yes: ctx answer numbers
A2010-28ctx arms re-run on the released contextnest-cli@3.4.0; every finished arm is identical to the release candidate (three rerank arms still running). Four reporting fixes: GraphRAG extraction per document, the first Neptune graph added to the spend total, paraphrase Stale@10 now measured, README embedder.Yes: ctx provenance; paraphrase Stale@10; cost total
A2110-28Post-hoc item-validity audit of all 541 VersionedDocs questions (Claude Sonnet 4.6, calibrated on a 50-item spot-check): 278 valid. Every VersionedDocs result reported on the full and the validated set.Yes: new validated-subset rows; full-set rows unchanged

4. Results: full tables

Every number in this section is copied from results/final.md, which make_results.py generates from the raw runs in runs/.

SciFact (300 queries, 5,183 documents), development set

ArmNDCG@10MRR@10MAP@10Recall@20
BM25 (reference)0.6900.6560.6420.866
Bedrock KB vector, Titan v2 (B1)0.6820.6460.6360.863
Bedrock KB vector + Cohere Rerank 3.5 (B2)0.7340.7080.6960.883
ctx keyword (C1)0.6620.6300.6170.849
ctx hybrid, Titan v2 (C2)0.7280.6970.6820.907
ctx hybrid + passage rerank (C3p)0.7700.7410.7310.927

C3p − B2 NDCG@10 = +0.035, 95% CI [+0.015, +0.058], p = 0.0008. Parity rule met.

NFCorpus (323 queries, 3,633 documents), development set

ArmNDCG@10MRR@10MAP@10Recall@20
BM25 (reference)0.3270.5280.1210.181
Bedrock KB vector, Titan v2 (B1)0.3250.5390.1170.182
Bedrock KB vector + Cohere Rerank 3.5 (B2)0.3410.5580.1260.190
ctx keyword (C1)0.3270.5280.1240.180
ctx hybrid, Titan v2 (C2)0.3510.5650.1340.201
ctx hybrid + passage rerank (C3p)0.3610.5800.1420.214

C3p − B2 NDCG@10 = +0.020, 95% CI [+0.007, +0.033], p = 0.0013. Parity rule met.

MultiHop-RAG (529 queries, 609 documents), development set for ctx lexical; C3p post-hoc

ArmNDCG@10MRR@10MAP@10Recall@20
BM25 (reference)0.7350.7960.6190.947
Bedrock KB vector, Titan v2 (B1)0.6850.7600.5690.935
Bedrock KB vector + Cohere Rerank 3.5 (B2)0.7950.8740.7000.954
ctx keyword (C1)0.7060.7880.5910.934
ctx hybrid, Titan v2 (C2)0.7040.7640.5870.957
ctx hybrid + passage rerank (C3p)0.7870.8570.6920.975
ctx hybrid + whole-doc rerank (C3, superseded)0.7630.8490.6580.972
Bedrock GraphRAG, 5 results0.4770.6450.3800.489
Bedrock GraphRAG, 10 results0.5290.6180.4140.626
Bedrock GraphRAG, 20 results0.5070.4930.3660.762
Bedrock GraphRAG, 50 results0.3320.3140.2070.852
Bedrock GraphRAG, 100 results (pre-registered)0.1690.1930.0960.610

C3p − B2 NDCG@10 = −0.008, 95% CI [−0.025, +0.009], p = 0.3482. Parity rule not met. On this set plain BM25 (0.735) also beats Bedrock vector without rerank (0.685).

VersionedDocs (541 queries, 180 documents + 180 previous versions), held-out

ArmNDCG@10MRR@10MAP@10Recall@20Stale@10
Bedrock KB vector, old+new copies (B1)0.6920.6190.6190.9460.863
Bedrock + status=current filter (B1-filter)0.8270.7870.7870.9780.000
Bedrock + Cohere Rerank 3.5 (B2)0.7920.7380.7380.9690.900
Nest feeding Bedrock (F1)0.8380.7990.7990.9830.000
Bedrock GraphRAG, 5 results0.5940.5280.5280.7870.708
Bedrock GraphRAG, 10 results0.5660.4680.4680.8670.797
Bedrock GraphRAG, 100 results (pre-registered)0.2020.1300.1300.7430.447
ctx nest keyword (C1)0.8070.7620.7620.9700.000
ctx nest hybrid (C2)0.7780.7250.7250.9700.000
ctx nest hybrid + whole-doc rerank (C3, superseded)0.8010.7670.7670.9240.000
ctx nest hybrid + passage rerank (C3p)0.9020.8830.8830.9630.000
ctx, old copies as plain files, keyword (flat C1)0.6780.6020.6020.9460.861
ctx, old copies as plain files, hybrid (flat C2)0.6430.5650.5650.9430.843

C3p − B1-filter NDCG@10 = +0.075, 95% CI [+0.047, +0.102], p = 0.0000. Parity rule met; ctx significantly better. Each question has one gold page, so MRR@10 and MAP@10 coincide.

VersionedDocs, paraphrased questions (155 queries)

ArmNDCG@10MRR@10MAP@10Recall@20
Bedrock KB vector, old+new copies (B1)0.6190.5520.5520.865
Bedrock + status=current filter (B1-filter)0.7230.6760.6760.916
Bedrock + Cohere Rerank 3.5 (B2)0.6790.6190.6190.897
Nest feeding Bedrock (F1)0.7350.6880.6880.935
ctx nest keyword (C1)0.4560.3980.3980.748
ctx nest hybrid (C2)0.6110.5560.5560.806
ctx nest hybrid + passage rerank (C3p)0.7700.7370.7370.890

C3p − B1-filter NDCG@10 = +0.048, 95% CI [−0.001, +0.096], p = 0.0620. Parity rule met; not significant. Lexical-only ctx (C1) falls to 0.456 when the question shares little wording with the page: this is where embeddings earn their place. Stale@10 on paraphrases (now measured, A20): Bedrock B1 0.742, B2 0.781; B1-filter, F1 and every nest arm 0.000.

VersionedDocs, validated items only (278 queries, A21)

ArmNDCG@10MRR@10Recall@20Stale@10
Bedrock KB vector, old+new copies (B1)0.6730.5950.9420.903
Bedrock + status=current filter (B1-filter)0.8210.7800.9780.000
Bedrock + Cohere Rerank 3.5 (B2)0.7680.7050.9680.946
Nest feeding Bedrock (F1)0.8280.7870.9820.000
Bedrock GraphRAG, 5 results0.5900.5260.7730.763
Bedrock GraphRAG, 10 results0.5500.4500.8600.835
Bedrock GraphRAG, 100 results (pre-registered)0.1740.1070.7340.439
ctx nest keyword (C1)0.8180.7700.9750.000
ctx nest hybrid (C2)0.7950.7430.9750.000
ctx nest hybrid + passage rerank (C3p)0.8980.8770.9640.000
ctx, old copies as plain files, keyword (flat C1)0.6690.5870.9640.910
ctx, old copies as plain files, hybrid (flat C2)0.6590.5810.9600.892

C3p − B1-filter NDCG@10 = +0.077, 95% CI [+0.038, +0.117], p = 0.0000. Parity rule met; ctx better.

VersionedDocs, paraphrased, validated items only (91 queries, A21)

ArmNDCG@10MRR@10Recall@20Stale@10
Bedrock KB vector, old+new copies (B1)0.6190.5440.8790.802
Bedrock + status=current filter (B1-filter)0.7420.6960.9230.000
Bedrock + Cohere Rerank 3.5 (B2)0.6750.6080.9120.857
Nest feeding Bedrock (F1)0.7550.7060.9560.000
ctx nest keyword (C1)0.4740.4090.8130.000
ctx nest hybrid (C2)0.6630.6080.8460.000
ctx nest hybrid + passage rerank (C3p)0.7900.7560.9120.000

C3p − B1-filter NDCG@10 = +0.048, 95% CI [−0.022, +0.116], p = 0.1924. Parity rule not met on this subset: 91 questions are too few to bound the difference at −0.02.

Answers, full rows

Claude Sonnet 4.6 answers at temperature 0 from a 6,000-character context; Claude Opus 4.6 labels; gpt-oss-120b check labels. κ is per arm; "mean ctx chars" is the context actually supplied.

DatasetArmnCorrectStaleHedgedMissingWrongκMean ctx chars
MultiHop-RAGB230066.0%0.0%3.0%25.7%5.3%0.76366000
GraphRAG best (10 results)30039.0%0.0%2.7%54.7%3.7%0.7086000
C3pass30065.7%0.0%3.3%25.7%5.3%0.7336000
VersionedDocsB225064.0%13.6%12.0%5.6%4.8%0.82766000
GraphRAG best (5 results)25054.8%12.0%6.4%20.4%6.4%0.88665747
C3p, whole-document context (harness artifact, A19)25046.8%0.4%0.4%48.8%3.6%0.92065928
C3pass25073.2%2.0%1.2%17.2%6.4%0.85765880
F125074.4%1.2%0.8%14.8%8.8%0.84886000

All-answer agreement: MultiHop-RAG κ 0.7462, raw agreement 0.8522, 133 disagreements; VersionedDocs κ 0.8781, raw agreement 0.9312, 86 disagreements. The MultiHop-RAG sample is stratified by question type from the frozen 600 (seed 13) and includes no-evidence questions (35 of 300, the null_query items in bedrock/out/multihop.sample300.qids). The VersionedDocs sample is stratified by change type (seed 13).

The A19 correction, stated plainly. The first ctx answer run fed the model the opening 6,000 characters of whole documents, while Bedrock arms fed retrieved ~300-token chunks. VersionedDocs pages average 16.6k characters, so the model mostly saw the top of the top page: 46.8% correct and 48.8% missing, despite the best retrieval. The engine returns each hit's best-matching passage in --json, which is what an agent receives. C3pass uses those passages under the same 6,000-character budget. We publish both rows; the amendment was written before the corrected result.

5. GraphRAG analysis

Result-count sensitivity

The protocol pre-registered GraphRAG at 100 results, Bedrock's maximum. At that setting it scored 0.169 NDCG@10 on MultiHop-RAG. As the requested count falls, it improves, peaking at 10 results on MultiHop-RAG and at 5 on VersionedDocs. At high counts, graph-expanded chunks displace the best direct hits (A18). We report every count and use the best one as the headline, which favours Bedrock.

Bedrock GraphRAG NDCG@10 by number of results requested MultiHop-RAG: 0.477 at 5, 0.529 at 10, 0.507 at 20, 0.332 at 50, 0.169 at 100. VersionedDocs: 0.594 at 5, 0.566 at 10, 0.202 at 100. Reference: Bedrock vector plus rerank on MultiHop-RAG, 0.795. 0.0 0.2 0.4 0.6 0.8 5 10 20 50 100 Results requested (numberOfResults) NDCG@10 Bedrock vector + rerank, MultiHop-RAG: 0.795 MultiHop-RAG (best 0.529 at 10) VersionedDocs (best 0.594 at 5)
Bedrock GraphRAG NDCG@10 by requested result count. VersionedDocs was run at 5, 10 and 100 only. Source: results/final.md.

Evidence-Complete@k on MultiHop-RAG (A11)

A graph is meant to help assemble evidence spread across several articles. Evidence-Complete@k is the share of the 529 questions whose top k contains every gold evidence article. The table also shows how many distinct documents each arm returned per question, since GraphRAG's chunks collapse to few documents.

ArmEvidence-Complete@5Evidence-Complete@10Docs returned (mean)
BM25 (reference)0.43860.6635100.0
Bedrock vector (B1)0.37430.565233.7
Bedrock vector + rerank (B2)0.52360.699433.7
ctx keyword (C1)0.39320.591799.8
ctx hybrid (C2)0.38560.6011100.0
ctx hybrid + passage rerank (C3p)0.53120.7032100.0
Bedrock GraphRAG, 5 results0.14560.14562.7
Bedrock GraphRAG, 10 results0.26470.30254.4
Bedrock GraphRAG, 20 results0.23250.45187.4
Bedrock GraphRAG, 50 results0.06240.249515.1
Bedrock GraphRAG, 100 results0.00950.045427.2

Not in final.md: produced by the harness scorer, bedrock/bx score.py multihop B1 B2 B3 C1 C2 C3p bm25 /lab/runs/multihop_k{5,10,20,50}.B3.json --ks 2 4 5 10 (output in bedrock/out/scores/multihop.json). Its NDCG@10 column reproduces final.md for every arm, which checks the run files. Not significance-tested.

Reading it

6. Governance results

VersionedDocs asks: when a page changes and the old version is still stored, does the old answer reach the model? Each question's gold fact exists only in the current page, and its stale fact only in the previous one.

For a Bedrock team the practical reading: if you already run Bedrock, a nest in front of it removes the filter you would otherwise maintain, and in this test answered best. If you run ctx alone, you get the same governance and, on this corpus, better retrieval (0.902 vs 0.827).

7. Cost

Measured: what this benchmark cost

The harness ledger (bedrock/out/spend.jsonl) records every billable call at AWS list price (us-east-1, fetched 2026-10-13). ./bx plan.py spend reports TOTAL committed $56.59 for the 10-13/14 run (A20 added the first MultiHop graph the harness had missed), of which:

Activity$
Answer generation and judging (Converse)21.39
Spend before the ledger existed (Cohere Rerank for local C3 runs $7.60, VersionedDocs generation $6.01, Cohere Embed v4 $1.00)14.61
GraphRAG ingestion, MultiHop-RAG (two full builds)9.09
GraphRAG ingestion, VersionedDocs4.22
Rerank (B2)3.91
Neptune graph-hours counted by the harness (2.42 h + 2.20 h)2.22
Vector ingestion and retrieval calls< 0.10

Correction (A20). The harness first counted only two graph lifetimes. Measured lifetimes from progress.log: MultiHop-RAG graph 03:11 to 05:29 UTC (about 2.3 h), VersionedDocs graph 06:21 to 08:33 (about 2.2 h), MultiHop-RAG rebuild 10:53 to 13:18 (about 2.4 h), at $0.48/h. The first graph is now in the ledger, which brings the total to $56.59. The 2026-10-28 additions were the validity audit ($4.72) and the re-run on the released build (Titan v2 embeddings and Cohere rerank, a few dollars).

Indexing (measured)

CorpusSystem$Wall clock
MultiHop-RAG, 609 docsBedrock GraphRAG (Haiku 4.5 extraction + Titan v2)4.55 / build7,535 s; 7,432 s
VersionedDocs, 360 docsBedrock GraphRAG4.227,011 s
MultiHop-RAG / VersionedDocs / SciFact / NFCorpusBedrock vector KB ingestion (S3 Vectors)< 0.05624 / 561 / 1,785 / 1,257 s
SciFact, 5,183 docsctx embed, Titan v2< 0.05462 s
NFCorpus, 3,633 docsctx embed, Titan v2< 0.05364 s
VersionedDocs flat, 360 docsctx embed, Titan v2< 0.0519 s

GraphRAG extraction per document = $9.0908 ÷ (2 × 609) = $0.0075 on MultiHop-RAG (~2.6k tokens per document). cost_report.py now divides by both builds (A20). Its ctx rows for MultiHop-RAG and VersionedDocs read "0 s", which reflects an incremental re-run over an existing index, not a cold build, so they are not cited. Bedrock vector ingestion times include Knowledge Base sync polling.

Projected monthly cost

Same formulas and assumptions as cost_report.py, with the extraction rate corrected to $0.0075 per document: 51,000 reads a month (the nest TCO model's mid-market case: 200 people × 5 questions a day × 21 days, plus 20 agents × 10 runs × 5 reads × 30 days), 10% of documents changing per month, 2,600 tokens per document. Reranking ($102/month at 51,000 reads) is included on both sides. Answer-generation tokens are excluded because they are the same whichever retriever feeds them.

DocumentsBedrock vector, S3 VectorsBedrock vector, OpenSearch ServerlessBedrock GraphRAGctx, Community Nest hostingctx, CLI only
1,000$102$452$453$141$102
10,000$102$452$460$141$102
100,000$103$453$528$142$103

Fixed floors: Neptune Analytics minimum 16 m-NCU = $0.48/h ≈ $350/month while the graph exists; OpenSearch Serverless 2-OCU floor ≈ $350/month (a NextGen collection can scale to zero, per the TCO node). Community Nest hosting: Lightsail 4 GB ($24) + managed PostgreSQL ($15). Excluded: the Community Nest self-hosted license ($10 per person per month, 30-person minimum, per the TCO node), which applies only to a self-hosted team server; the ctx CLI and engine are free.

The honest cost conclusion.

Script for the corrected figures

# same constants and formulas as cost_report.py; two corrections
ext = 9.0908 / (2 * 609)                      # ledger "ingest graph:multihop" covers two builds of 609 docs
hours = {"MultiHop graph 1": 2.3, "VersionedDocs graph": 2.2, "MultiHop rebuild": 2.4}
nep = sum(hours.values()) * 0.48              # 6.9 h, $3.31
missing = 2.3 * 0.48                          # first MultiHop graph, not in plan.py TOTAL: $1.10
total = 55.48 + missing                       # $56.58
READS, CHURN, TOK = 51_000, 0.10, 2_600
TITAN, RR, OSS, NEPM, HOST = 0.02, 2.00, 350.0, 16*0.03*730, 24+15
rerank = READS/1000*RR
for n in (1_000, 10_000, 100_000):
    ch = n*CHURN; emb = ch*TOK/1e6*TITAN; qe = READS*30/1e6*TITAN
    s3 = emb+qe+rerank; oss = s3+OSS; graph = s3+NEPM+ch*ext; ctx_hosted = HOST+s3
# -> 1k: 102 / 452 / 453 / 141   10k: 102 / 452 / 460 / 141   100k: 103 / 453 / 528 / 142

8. What we fixed in ContextNest because of this

The released ctx 3.0.0 (@promptowl/contextnest-engine@3.0.0, pinned in the lab image) scored 0.604 NDCG@10 on SciFact (results/gate.md), against 0.690 for plain BM25. That was a real gap in our product, and the benchmark found it. These changes shipped in ctx 3.4.0 (PromptOwl/ContextNest#190). They were developed on branch misha/retrieval-modes of PromptOwl/ContextNest, commits through 9e1ab02, the release candidate measured here.

ChangeCommitEvidence
Porter stemming at index and query time15830c6SciFact 0.604 → 0.630 with stemming alone (gate.md)
Field boosts from title 3 / tags 2 / description 1.5 to all 115830c6, c9d72d0The large title boost cost about 0.04 NDCG@10 on SciFact; once coordination was removed, any title boost hurt (A7, A8)
Removed MiniSearch's coordination factor: plain BM25 sumc9d72d0MultiHop-RAG lexical 0.657 → 0.706 (found on MultiHop-RAG, hence A8)
Hybrid lexical + semantic, weighted reciprocal rank fusion 1 : 2d3745d8, b81eb2dChosen on SciFact and NFCorpus from a 1:1 / 1:1.5 / 1:2 / 1:3 sweep (A7)
Passage-level rerank: one call of ≤100 passages per query, each document's best ~300-token window chosen locally8499db4, 9e1ab02Same budget as Bedrock B2. VersionedDocs (held-out) 0.801 → 0.902; MultiHop-RAG (post-hoc) 0.763 → 0.787 (A17)
Transport and throttling retries for embedding and rerank callsed318b0, a997f32Reliability under Bedrock throttling during the runs
Search returns each hit's best passage in --json9e1ab02What an agent receives; the basis of C3pass (A19)

Shipped-only rule. The protocol counts only shipped ctx code (section 2 of PROTOCOL.md). The first measurements used the release candidate (commit 9e1ab02); every arm is being re-run on the published @promptowl/contextnest-cli@3.4.0. Every arm finished so far is identical to the release candidate; the hybrid + rerank arms for NFCorpus, MultiHop-RAG and VersionedDocs are still running (A20). The search code between the two differs only in hardening (configuration checks, index file format, retry budget) and whitespace folding in exact-title matching.

9. Limitations

10. Reproduce it

We would like you to rerun it on your own corpus, with your own embedder, extraction model, answer model and judge. Your data stays in your AWS account and on your machine. If ctx loses on your data, we want to know where.

Annex: the v2 report (2026-10-02), unchanged

Reproduced as delivered. Its conclusions are superseded where v3 measures the same thing, and section 1 maps each objection to v3. Two statements in it are out of date: "semantic seed selection designed, not shipped" (hybrid semantic search shipped in ctx 3.4.0; see section 8) and "Paraphrase recall on large corpora: weaker, lexical" (see the paraphrase table in section 4).

When documents change: a stale-version retrieval test of Amazon Bedrock GraphRAG and ContextNest

Misha Sulpovar, PromptOwl · live run 2026-10-02

Executive summary

We tested one question on a live Amazon Bedrock Knowledge Base with GraphRAG on Neptune Analytics and on ContextNest (ctx): when a document changes, does the superseded answer still reach the model? Both systems got the same text and the same 30 plain-English questions. We scored the text each system actually returned, and separately the answers a model wrote from it.

What this is not: a GraphRAG benchmark. The questions are single-fact lookups over 11 short documents, so the graph does little work, and n is small (30 questions clustered on 6 documents). It answers the stale-version question and gives you a harness to answer the parity question on your own corpus, with your own judge.

Results

All rates are over 30 questions, with 95% Wilson intervals. "At matched depth" means ContextNest's results were cut, per question, to the number of results and characters Bedrock returned for that question, because Bedrock returns chunks and ContextNest returns whole documents.

Retrieval, k=3 (rates over 30 questions; 95% Wilson interval in brackets)

ArmGold doc retrievedCurrent fact in contextStale fact in contextResults returned (mean)
Bedrock, previous versions only (scorer check)28/300/30 [0–11%]28/30 [79–98%]1.0
Bedrock, after overwrite + re-sync29/30 [83–99%]29/30 [83–99%]0/30 [0–11%]1.4
Bedrock, previous copies alongside, no filter20/30 [49–81%]20/30 [49–81%]23/30 [59–88%]1.8
Bedrock, previous copies alongside, status=current filter29/30 [83–99%]29/30 [83–99%]0/30 [0–11%]1.4
ContextNest, versioned (own depth, 3 documents)30/30 [89–100%]30/30 [89–100%]0/30 [0–11%]3.0
ContextNest, previous copies as plain files (own depth)28/30 [79–98%]28/30 [79–98%]29/30 [83–99%]3.0

At k=10 every arm except the scorer check retrieves the current document on 30/30. The unfiltered arms then carry stale content on 30/30 (Bedrock and ContextNest alike), and the filtered and versioned arms on 0/30.

ContextNest at Bedrock's depth, k=3. Per question, ContextNest's results were cut to the number of results Bedrock returned for that question (gold doc), and its text to the number of characters Bedrock returned (facts). This is the like-for-like row.

ComparisonGold doc retrievedCurrent fact in contextStale fact in context
Bedrock, after update29/30 [83–99%]29/30 [83–99%]0/30 [0–11%]
ContextNest versioned, matched to it28/30 [79–98%]27/30 [74–97%]0/30 [0–11%]
Bedrock, previous copies alongside, no filter20/30 [49–81%]20/30 [49–81%]23/30 [59–88%]
ContextNest plain-file copies, matched to it23/30 [59–88%]22/30 [56–86%]24/30 [63–90%]

Answers, k=3. Each arm's retrieved context went to Amazon Nova Pro with the same prompt, and Mistral Large 3 graded every answer by the version it finally commits to (CURRENT, STALE, HEDGED for no commitment, MISSING, WRONG). All 180 answers were graded under that one rubric with no hand edits. Prompts, answers and verdicts ship with the results.

Arm (k=3)CURRENTSTALEHEDGEDMISSINGWRONG
Bedrock, previous versions only (scorer check)0/30 [0%–11%]25/30 [66%–93%]0/303/302/30
Bedrock, after overwrite + re-sync27/30 [74%–97%]1/30 [1%–17%]0/301/301/30
Bedrock, previous copies alongside, no filter13/30 [27%–61%]13/30 [27%–61%]1/302/301/30
Bedrock, previous copies alongside, status filter28/30 [79%–98%]0/30 [0%–11%]0/301/301/30
ContextNest, versioned27/30 [74%–97%]0/30 [0%–11%]0/300/303/30
ContextNest, previous copies as plain files17/30 [39%–73%]10/30 [19%–51%]2/300/301/30

What it means

On these questions this test cannot separate the two retrievers. At matched depth they are within two questions of each other, with 4 of 30 questions disagreeing on the gold document in both directions, and answer accuracy is the same within one question (27 to 28 of 30 across the three clean arms). We don't claim either is better at retrieval.

What separates them is what happens to the old answer. Any retriever pointed at a store that holds old and new copies side by side will surface the old one some of the time; both did here, at nearly the same rate. Bedrock fixes that with a metadata attribute and a filter that your ingestion pipeline has to set correctly on every file, forever. ContextNest fixes it in the data model: a change is a new version of the same document, retrieval returns the current one, and the previous one is still there through ctx history and ctx reconstruct when someone needs to know what the answer used to be.

One difference this corpus can't measure: ContextNest returns whole documents, and at its own depth it had the current fact in context on 30 of 30. On long documents, whole-document context can keep together facts that chunking splits, such as a rule and its exception in different sections. Every document here is under about 350 tokens, so each was a single Bedrock chunk and there was nothing for chunking to split; answer accuracy was also the same. Whole documents only help when the set is current. In the plain-file arm they put both versions in front of the model, which then hedged or picked the stale one more often. Testing this properly needs long, multi-section documents and Bedrock's hierarchical chunking as well as the default. The harness reports context size per arm, so any accuracy gain shows up next to its token cost.

So the useful question is less GraphRAG against ContextNest and more whether version discipline is something you build into each client's pipeline, or something the knowledge layer does by default and keeps a record of. The two compose: build the graph from a nest's approved, current snapshot and you get both.

Comparison matrix

Bedrock Knowledge Bases (GraphRAG)ContextNest engine (ctx, open source)Community Nest (server + UI)
Retrieval on these questions29/30 after update (k=3)28/30 at Bedrock's depth; 30/30 at its ownsame engine
Plain-English searchvector + graphfull-text; semantic seed selection designed, not shippedselector-based context endpoint (selector + hops)
Paraphrase recall on large corporaembeddings help (not tested here)weaker, lexicalsame as engine
Superseded content after an updatepurged on overwrite + re-syncnot retrievable once a new version is publishedsame
Old copies alongside current onesleaks without a filter (23/30 here); 0/30 with a status metadata filter you maintainleaks if stored as plain files (24/30 at matched depth here); excluded when modelled as versionssame
Version historynot in the index; S3 versioning is available separatelyctx history, ctx reconstruct <doc> <version>versions endpoint with approved version per document
Integrity evidenceCloudTrail logs API calls; no content hash chainhash-chained versions, ctx verify; ctx drift scan for edits made outside the toolsame, server-side
Approval before content becomes canonnot native; any pipeline can gate S3 uploadssingle-user publishreview queue with separation of duties enforced server-side
Record of what an agent readnot nativeno local read log; --agent/--session attribute writes in ctx historyworkflow plane records each read for replay (built, behind a feature flag)
Graph edgesextracted by an LLM, rebuilt for changed documentswritten as [[links]], versioned with the document, followed with --hopssame
Data formatAWS-managed indexMarkdown + YAML on disk, Obsidian-compatible; engine AGPL-3.0, spec Apache-2.0same, with export and import
Running cost beyond hostingNeptune graph floor, LLM extraction on changed documents, query embeddingnonenone (self-hosted Community Edition needs a license key)

Cost

Both systems need hosting. The difference is what sits on top.

What ContextNest adds beyond retrieval

Engine (shipped)

Community Nest (shipped)

Built, not generally available: a plugin framework for source connectors (registry, OAuth for Google, Microsoft and custom providers, scheduled pull, webhooks; in review), and the workflow plane (behind a feature flag).

Not built: real-time co-editing, self-hosted SSO (hosted SSO exists), semantic seed selection (designed, not shipped).

Method

ArmWhat it models
Bedrock, previous onlyscorer check: stale should fire, current should not
Bedrock, after updatesame S3 keys overwritten with current versions and re-synced
Bedrock, historyprevious versions added under archive/ next to current, no filter
Bedrock, history + filtersame index, retrieve filtered on status=current
ContextNest, versionedprevious = v1, current = v2 of the same document
ContextNest, flatsame, plus previous versions as separate plain documents under archive/

Limits

How this version differs from our first draft

An earlier draft of this test had scoring errors that our own red-team found:

This version fixes all four, adds a filtered Bedrock arm and a ContextNest flat arm so both systems are tested with and without their best practice, and adds answer-level grading.

Run it on your corpus

The harness is attached as stale-retrieval-harness-v2.tar.gz; its README covers setup.