Skip to content

feat(rag): govern reference-free RAG scoring requests - #613

Closed
seonghobae wants to merge 13 commits into
mainfrom
feat/rag-governed-observation-contract
Closed

feat(rag): govern reference-free RAG scoring requests#613
seonghobae wants to merge 13 commits into
mainfrom
feat/rag-governed-observation-contract

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Buyer-visible gap

Issue #607 identifies a missing measurement boundary for reference-free RAG evaluation. Protected main has reusable Assessment/Rubric/Scoring contracts and psychometric calibration primitives, but no canonical adapter that preserves query revision, system configuration versus stochastic run, generated-response identity, retrieval-run identity, evidence regime, and candidate visibility in one governed request.

Test-first implementation

This branch began with an intentional RED contract in tests/test_scoring_rag_request.py, then added the minimal validation/marshalling implementation in python/fast_mlsirm/scoring/rag.py while reusing the authoritative shared ScoringRequest. Valid review findings were repaired test-first: caller metadata is allowlisted (evaluation_split only), package-managed RAG provenance cannot be spoofed, raw question/context/answer/source content cannot be smuggled under arbitrary metadata keys, and shared identity projects respondent_id=system_run_id while preserving a distinct generated response_id and system_configuration_id.

Bounded contract

  • evidence regimes: prompt_only, retrieved_context, pooled_corpus, authoritative_corpus, human_anchor;
  • candidate visibility: candidate_blind or candidate_visible_crossfit;
  • system configuration, stochastic run, generated response, retrieval run, and query revision remain distinct identities;
  • query revision maps to the shared task-revision axis and query testlet to the shared task-family axis;
  • governed provenance participates in the canonical request fingerprint;
  • malformed semantic enums/fingerprints fail closed;
  • raw question/context/answer/source text is absent from the governed builder and caller-metadata surface; and
  • numerical RAG metrics, provider SDKs, thresholds, retrieval, LLM inference, persistence, and truth adjudication remain out of scope.

Python owns validation/provenance marshalling only. Future likelihood, calibration, hierarchical, DIF, uncertainty, or other psychometric arithmetic remains Rust-owned.

Scientific boundary

Reference-free is not truth-free. Grounded generation, answer relevance, retrieval relevance, evidence utilization, coverage/completeness proxies, citation attribution, robustness, and answerability/abstention remain distinct constructs. A retrieved-context evidence regime alone cannot authorize world-correctness, absolute retrieval-recall, fairness, or deployment-validity claims. Canonical architecture/traceability changes belong to #604 rather than a competing documentation PR.

Exact-current identity and evidence

Freshly revalidated against GitHub state for this update:

  • protected main: 8db4bf358b0a469915d6c5e336054f4a4f9c6b46;
  • exact source head: 754f0716b072e551d682adca2639801aaad2e68b;
  • compare_commits(main, head): ahead, merge base exactly current protected main, with only four net product paths: the RAG implementation, its tests, doctoring, and changelog fragment;
  • exact-head Security Scan: success;
  • exact-head SAST Semgrep: success;
  • exact-head CI run 31328633599: Rust/PyO3, package/reinstall/release acceptance, GPU-smoke and fuzz succeed; Python reaches the complete suite and fails only tests/test_changelog_fragment_contract.py::test_repository_changelog_is_rendered_from_current_fragments because CHANGELOG.md has not yet been regenerated from docs/changelog.d/607-rag-scoring-request-boundary.md;
  • a bounded exact-current-head source-writer handoff already exists for the deterministic changelog synchronization; do not race it or repeat an equivalent request while the head remains unchanged.

Any older body text or comments naming fdf0559... are predecessor/historical claims and are not exact-current-head evidence.

Remaining Draft gate

Keep Draft. The next source mutation must render/check the authoritative changelog without changing the RAG contract, then require fresh unchanged-head full CI/Security/SAST, current-head automated review, zero valid unresolved findings, and the repository's actual approval/branch-protection policy. If the head or protected base moves, discard predecessor acceptance evidence and refetch from scratch.

Advances #607.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02b90c1f-bd2e-4cf4-98c4-26fdc3e10de9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a governed RAG scoring adapter. It validates evidence, visibility, metadata, and fingerprints, maps RAG identities to canonical scoring axes, attaches managed provenance, and creates criterion-level ScoringRequest objects without raw text.

Changes

RAG scoring adapter

Layer / File(s) Summary
RAG contract and metadata
python/fast_mlsirm/scoring/rag.py
Adds evidence-regime and candidate-visibility enums. Validates and freezes caller metadata. Rejects reserved provenance keys and exports the adapter API.
Canonical request construction
python/fast_mlsirm/scoring/rag.py
Adds build_rag_scoring_request, which validates inputs, assembles managed provenance, and maps RAG identities to a criterion-level ScoringRequest.
Contract and identity validation
tests/test_scoring_rag_request.py
Tests shared scoring axes, provenance serialization, raw-text exclusion, stochastic run identity, fingerprint inputs, reserved metadata rejection, and revision consistency.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RAGCaller
  participant build_rag_scoring_request
  participant ScoringRequest
  RAGCaller->>build_rag_scoring_request: RAG identities, enums, fingerprints, and response
  build_rag_scoring_request->>ScoringRequest: construct criterion-level request
  ScoringRequest-->>RAGCaller: canonical ScoringRequest
Loading

Possibly related issues

  • ContextualWisdomLab/fast-mlsirm issue 607: Directly covers the governed RAG scoring-request contract implemented by this change.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 and concisely describes the main change: adding governance for reference-free RAG scoring requests.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rag-governed-observation-contract

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.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease on this Draft branch only if a final refetch still shows exact head efb9fedac24f5d06a5d7eb0a8d3816381d2be0f7 over protected main 7516031df533d1131572eb07b6e3a86b04d12793; abort without writing if either moved or another writer is active.

Strict red-green scope for issue #607 first slice:

  1. Run only tests/test_scoring_rag_request.py first and confirm the intended RED reaches the missing production boundary fast_mlsirm.scoring.rag; do not treat unrelated setup/fixture/import-environment failure as valid RED.
  2. Implement the smallest provider-neutral python/fast_mlsirm/scoring/rag/ adapter that makes that contract GREEN by reusing the existing authorized ScoringRequest. Python may validate and marshal only: no RAG metric arithmetic, thresholds, LLM/provider calls, raw query/context/answer/source text, new likelihood, or parallel rubric/scoring schema.
  3. Preserve exact semantics in the tests: evidence-regime and candidate-visibility enums, system configuration distinct from stochastic run, query revision mapped to shared task revision, query testlet mapped to task family, package-managed system/retrieval/query fingerprints, identity-bearing metadata, reserved-key rejection, and stable fail-closed enum/fingerprint errors.
  4. Keep the parent fast_mlsirm.scoring.__all__ pinned unless the existing public-surface contract explicitly requires a versioned change; the new subpackage may own its own __all__.
  5. Add complete public/private production docstrings and focused statement/branch coverage. After focused GREEN, add concise doctoring grounded in the primary RAGAS (EACL 2024), ARES (NAACL 2024), and RAGChecker research plus an authoritative docs/changelog.d/607-* fragment. Do not edit PRD/TRD/ARCHITECTURE/ADR/UML/ERD/traceability files while canonical documentation PR docs: establish canonical product and architecture baseline #604 owns that writer lease.
  6. Run the focused RAG test, the relevant shared scoring request/authorization tests, changelog fragment contract as applicable, compile/docstring/coverage checks, and git diff --check. Commit only this bounded request-contract slice. Keep Draft; do not mark Ready, approve, merge, change dependencies/workflows/version, or expand into observation/calibration/provider integration stages.

If any test expectation conflicts with an established protected-main shared scoring invariant, preserve the established invariant and make the narrowest test/API correction with an explicit reason rather than forking the shared contract.

Copy link
Copy Markdown
Contributor Author

@opencode-agent One current RED-contract correction is required before implementing the adapter. Protected-main docs/scoring_facets_calibration_handoff.md defines the person axis as one respondent or system run, identified by respondent_id, and permits exactly one response artifact per respondent–task-revision cell. The current test maps respondent_id = system_configuration_id and response_id = system_run_id; two stochastic runs of one configuration on the same query would therefore collide in the existing facets assembler as two response artifacts for one respondent–task cell.

Preserve the existing calibration contract:

  • map exact system_run_id (or an explicitly governed composite run identity) to shared ScoringRequest.respondent_id;
  • require a separate descriptive response_id for the generated answer artifact and map it to ScoringRequest.response_id;
  • retain system_configuration_id plus its fingerprint as package-managed identity-bearing RAG metadata for future hierarchical/group analysis, not as the current person axis;
  • add a regression proving two runs of one configuration/query produce distinct respondent identities while retaining the same configuration metadata and can later enter the shared many-facet design without a respondent–task response conflict;
  • state that mapping query_testlet_id to task_family_id is a logical grouping/audit label in this slice, not evidence that a testlet random effect has been fitted.

Correct the fail-first test/API before production implementation so RED specifies the existing shared scoring/calibration semantics rather than creating a parallel incompatible RAG interpretation. Keep every other bounded scope instruction unchanged.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease on this Draft branch only if a final refetch still shows exact head d2a1a429732aa12f0484c45159e96209b2446d7e and protected main exactly 8db4bf358b0a469915d6c5e336054f4a4f9c6b46; abort without writing if either moved or another writer receipt/source mutation appears. The earlier handoff bound to 7516031... is stale.

Current exact-head CI 31320814477, Security Scan 31320814446, and SAST 31320814447 are all successful; the latest test-only fix aligns query_testlet_id with the rubric-declared task family. Complete the bounded first #607 slice rather than opening a second RAG schema:

  1. Reconcile the one newly integrated protected-main commit (🧪 Add tests for Luce Spectral Ranking (LSR) #590) non-destructively; preserve the RAG source/tests exactly unless the focused merge-state tests prove a real conflict.
  2. Add concise method doctoring for the current request/provenance boundary only, grounded in primary RAGAS (EACL 2024), ARES (NAACL 2024), and RAGChecker evidence. Keep claims construct-specific: reference-free is not truth-free, retrieved-context evidence does not prove world correctness/absolute recall, and no provider/metric threshold/validity claim is authorized here.
  3. Add the authoritative changelog fragment for this bounded request contract, then run the repository renderer --update and --check so protected-main notes and all live fragments are retained.
  4. Run pytest -q tests/test_scoring_rag_request.py plus the shared scoring authorization/request contracts, changelog contract, docstring/coverage checks and git diff --check; then run the full relevant suite. Preserve Python as validation/marshalling only and the existing shared ScoringRequest authority.
  5. Refresh the PR body from the final exact head/base/evidence. Keep Draft for fresh exact-head automated review; do not add RAG metric arithmetic, LLM/provider calls, raw query/context/answer/source text, persistence, parallel rubrics/scoring schemas, dependencies/workflows/version/release changes, or canonical PRD/TRD/ADR/UML/ERD edits owned by docs: establish canonical product and architecture baseline #604.

@seonghobae
seonghobae marked this pull request as ready for review August 9, 2026 16:05

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed.

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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@python/fast_mlsirm/scoring/rag.py`:
- Around line 50-96: Update _rag_metadata in
python/fast_mlsirm/scoring/rag.py#L50-L96 to validate caller metadata against a
non-content schema or explicit allowlist, rejecting raw answer, query, context,
or source text even under unreserved keys while preserving package-managed
provenance fields. Add rejection tests for these raw-content cases in
tests/test_scoring_rag_request.py#L99-L136.
- Around line 109-112: Update python/fast_mlsirm/scoring/rag.py lines 109-112 to
add a separate response_id input while retaining system_configuration_id as
package-managed metadata; in the request construction at lines 171-180, map
respondent_id to system_run_id, response_id to response_id, and include the
configuration identifier in managed metadata. Update
tests/test_scoring_rag_request.py lines 83-95 to assert these corrected
identities, and lines 139-154 to verify distinct runs produce distinct
respondent identities for the same configuration.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f808ae08-fa98-4df3-9238-d9230cbda08a

📥 Commits

Reviewing files that changed from the base of the PR and between 7516031 and d2a1a42.

📒 Files selected for processing (2)
  • python/fast_mlsirm/scoring/rag.py
  • tests/test_scoring_rag_request.py

Comment thread python/fast_mlsirm/scoring/rag.py
Comment thread python/fast_mlsirm/scoring/rag.py
@seonghobae
seonghobae marked this pull request as draft August 9, 2026 16:11

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease only if a final refetch still shows Draft source head e76d0680e88bc90bb2e8514a5fd3c30b880a0067 and protected main exactly 8db4bf358b0a469915d6c5e336054f4a4f9c6b46; abort without writing if either moves or another source-writer receipt appears.

CodeRabbit's two current-head findings are valid against issue #607's canonical hierarchy (system configuration -> stochastic run -> query/testlet observations) and no-raw-content numerical-artifact boundary. Test commit e76d068... is intentionally RED-first and adds the narrow contracts for both findings. GitHub CI 31323194982 is queued, so do not infer RED from queue state: first run pytest -q tests/test_scoring_rag_request.py locally and require the intended production-boundary failures before changing production. If the focused tests do not fail for the missing response_id/identity projection and unrestricted caller metadata, stop without a production write and report the discrepancy.

Then implement only the smallest GREEN in python/fast_mlsirm/scoring/rag.py plus the same test file:

  1. add a distinct generated-answer response_id; project system_run_id to shared respondent_id, response_id to shared response_id, and retain system_configuration_id plus its fingerprint as package-managed provenance so repeated runs remain nested under one configuration without collapsing generated responses;
  2. replace arbitrary RAG caller metadata with a small explicit non-content allowlist appropriate to measurement context (at minimum preserve the existing evaluation_split; language/domain/query-type identifiers are acceptable if normalized as descriptive identifiers). Reject any non-allowlisted key with stable non-reflective unsupported_rag_metadata evidence; do not attempt heuristic content inspection;
  3. extend managed-key spoof protection to rag_system_configuration_id; update the existing axis/provenance/stochastic-run tests so they agree with the new hierarchy rather than retaining the predecessor mapping;
  4. preserve the shared ScoringRequest factory, evidence/visibility semantics, fingerprints, criterion granularity, no provider calls, no numerical ownership, no raw query/context/answer/source fields, and all process-control exceptions from shared validators;
  5. run the focused RAG tests to GREEN, then relevant scoring safety/serialization tests and coverage/docstring checks. Add a bounded changelog fragment/doctoring only if required by the repository's existing feature contract, render/check managed CHANGELOG.md, and reconcile current protected main non-destructively before final full exact-head CI/security/SAST/review evidence.

Keep Draft. Do not weaken either CodeRabbit finding, add a second scoring hierarchy, add provider/RAGAS dependencies, alter Rust numerical kernels, touch #604, approve/merge/release, or broaden the slice beyond issue #607 stage 1.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review exact current head 91f6c1854fbb91ef91ff67069f5b8e5e29914f19. The two prior actionable findings were repaired test-first on this head: caller RAG metadata is now explicitly allowlisted to prevent raw-content smuggling, and the canonical identity projection now uses respondent_id=system_run_id plus a distinct generated-answer response_id, with system configuration retained as managed provenance. Exact-head CI 31324089738, Security Scan 31324089732, and SAST 31324089748 are successful. Treat predecessor review evidence as stale and report only current-head findings.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@seonghobae, I will review the current head 91f6c1854fbb91ef91ff67069f5b8e5e29914f19. I will evaluate only findings that apply to this head.

⚠️ Action not completed

Review rate limited.

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.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review exact current reconciled head fdf0559cc0bf1bf3ef2941a2693fd57eb07a99c1 against live protected main 8db4bf358b0a469915d6c5e336054f4a4f9c6b46. The branch now contains current main non-destructively and compare_commits(main, head) shows only the two intended RAG paths. Prior reviews/commands anchored to 91f6c... or earlier are predecessor-head evidence. Security Scan 31324471463 and SAST 31324471464 have succeeded on this head; CI 31324471491 is still running, so do not treat it as acceptance yet. Report only current-head actionable findings.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

expected_head='fdf0559cc0bf1bf3ef2941a2693fd57eb07a99c1'
expected_base='8db4bf358b0a469915d6c5e336054f4a4f9c6b46'

echo '== checked-out and expected commits =='
git rev-parse HEAD
git rev-parse "$expected_head"
git rev-parse "$expected_base"
git merge-base "$expected_base" "$expected_head"
echo
echo '== changed paths from requested base to requested head =='
git diff --name-status "$expected_base" "$expected_head"
echo
echo '== diff check =='
git diff --check "$expected_base" "$expected_head"
echo
echo '== workflow runs =='
gh run view 31324471491 --json databaseId,status,conclusion,headSha,name,url || true
gh run view 31324471463 --json databaseId,status,conclusion,headSha,name,url || true
gh run view 31324471464 --json databaseId,status,conclusion,headSha,name,url || true
echo
echo '== scoring module candidates =='
fd -t f . python/fast_mlsirm/scoring tests | sort
echo
echo '== outlines =='
ast-grep outline python/fast_mlsirm/scoring/rag.py --view expanded
ast-grep outline tests/test_scoring_rag_request.py --view expanded

Length of output: 15296


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== RAG adapter =='
sed -n '1,240p' python/fast_mlsirm/scoring/rag.py
echo
echo '== focused RAG tests =='
sed -n '1,290p' tests/test_scoring_rag_request.py
echo
echo '== shared contract definitions =='
rg -n -C 4 --type py '^(class ScoringRequest\b|def .*scoring.*request\b|def .*request.*scoring\b|def .*metadata\b|_METADATA|metadata:)' python/fast_mlsirm/scoring/contracts.py python/fast_mlsirm/scoring/authorization.py python/fast_mlsirm/scoring/_contract_safety.py
echo
echo '== shared contract outlines =='
ast-grep outline python/fast_mlsirm/scoring/contracts.py --match 'ScoringRequest|create|build|validate' --view expanded
ast-grep outline python/fast_mlsirm/scoring/authorization.py --view expanded
echo
echo '== package public surface =='
cat -n python/fast_mlsirm/scoring/__init__.py
echo
echo '== exact current diff =='
git diff --no-ext-diff --unified=80 8db4bf358b0a469915d6c5e336054f4a4f9c6b46..fdf0559cc0bf1bf3ef2941a2693fd57eb07a99c1 -- python/fast_mlsirm/scoring/rag.py tests/test_scoring_rag_request.py

Length of output: 44091


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== authorization request factory =='
sed -n '1,185p' python/fast_mlsirm/scoring/authorization.py
echo
echo '== execution request model and factory =='
ast-grep outline python/fast_mlsirm/scoring/execution.py --match 'ScoringRequest|build_scoring_request|to_dict|request_fingerprint' --view expanded
rg -n -C 8 --type py '^(class ScoringRequest\b|def build_scoring_request\b|def .*fingerprint\b|def to_dict\b)' python/fast_mlsirm/scoring/execution.py
echo
echo '== shared metadata preflight =='
sed -n '250,450p' python/fast_mlsirm/scoring/_contract_safety.py
echo
echo '== identifier and fingerprint validators =='
rg -n -C 5 --type py '^(def (fingerprint|identifier|.*_id|.*metadata)|class .*Error)' python/fast_mlsirm/scoring/_validation.py
echo
echo '== metadata safety test cases =='
rg -n -C 5 --type py '(metadata.*(string|text|content)|freeze_metadata|invalid_.*metadata|metadata.*value)' \
  tests/test_scoring_contract_metadata.py \
  tests/test_scoring_contract_sensitive_metadata.py \
  tests/test_scoring_contract_preflight_safety.py \
  tests/test_scoring_contract_serialization_security.py
echo
echo '== direct RAG call-field validation tests =='
rg -n -C 3 --type py '(_request\(|system_configuration_id|system_run_id|response_id|query_id|query_testlet_id|occasion_id|evaluation_split)' tests/test_scoring_rag_request.py

Length of output: 41613


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='8db4bf358b0a469915d6c5e336054f4a4f9c6b46'

echo '== ScoringRequest validation and factory =='
sed -n '415,625p' python/fast_mlsirm/scoring/execution.py
sed -n '850,970p' python/fast_mlsirm/scoring/execution.py
echo
echo '== descriptive identifier validation =='
sed -n '90,145p' python/fast_mlsirm/scoring/_validation.py
echo
echo '== RAG request references in current tree =='
rg -n -i -C 3 '(reference-free|RAGAS|ARES|RAGChecker|rag scoring|retrieved-context|world correctness|absolute recall)' \
  README.md docs python tests || true
echo
echo '== changelog conventions and RAG fragments =='
fd -t f . docs/changelog.d | sort | tail -n 60
rg -n -i -C 3 '(changelog\.d|fragment|RAG|reference-free)' \
  README.md docs tests/test_changelog_fragment_contract.py pyproject.toml .github 2>/dev/null || true
echo
echo '== same documentation search on requested base =='
git grep -n -i -E 'reference-free|RAGAS|ARES|RAGChecker|rag scoring|retrieved-context|world correctness|absolute recall' "$base" -- README.md docs python 2>/dev/null || true
echo
echo '== request IDs and metadata values passed through tests =='
rg -n -C 2 --type py 'metadata=\{|evaluation_split|metadata\[' tests/test_scoring_*.py | head -n 260

Length of output: 201532


@seonghobae, I reviewed fdf0559cc0bf1bf3ef2941a2693fd57eb07a99c1 against 8db4bf358b0a469915d6c5e336054f4a4f9c6b46.

The source head and base match the requested commits. Only the two RAG paths differ. git diff --check passes. CI 31324471491 remains in progress.

I found two current-head issues.

  1. High — Raw content can bypass the metadata boundary.
    In python/fast_mlsirm/scoring/rag.py, Line 49 allowlists evaluation_split. Lines 82-91 apply only the general metadata validator. That validator accepts arbitrary bounded strings. A caller can set:

    metadata={"evaluation_split": "<raw query, context, answer, or source text>"}

    The value then enters the serialized ScoringRequest artifact. This violates the stated no-raw-content boundary. Validate evaluation_split as a descriptive identifier or a closed split enum before freeze_metadata. Add a regression that rejects a raw-text value under the allowlisted key with a stable, non-reflective error.

  2. Medium — The required RAG doctoring and changelog evidence are absent.
    The current diff adds no RAG method document and no docs/changelog.d/607-* fragment. The protected base also has no documentation that grounds this boundary in RAGAS, ARES, and RAGChecker. Add concise doctoring that states the evidence and interpretation limits. Add the authoritative changelog fragment. Render and check CHANGELOG.md on the final head.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease only if a final refetch still shows Draft head 5b70d1a9d461bfbcd6cda8c4aacc48b3f12f4661 over protected main 8db4bf358b0a469915d6c5e336054f4a4f9c6b46; abort without writing if either moved or another current-head source writer appears. Earlier handoffs bound to efb9.../91f6... are stale.

A fresh exact-current CodeRabbit review identified two valid issues on predecessor fdf0559...: (1) allowlisted metadata["evaluation_split"] accepts arbitrary raw content; (2) required RAG doctoring/changelog evidence is absent. Current head 5b70... is TEST-ONLY relative to fdf0559... and adds test_rag_evaluation_split_rejects_raw_content_value.

Strict RED→GREEN scope:

  1. Run pytest -q tests/test_scoring_rag_request.py first. Confirm the new test fails because raw query-like text under evaluation_split is currently accepted/serialized; setup/import/fixture failure is not valid RED. Do not write production before that RED is observed.
  2. Implement the smallest fix in python/fast_mlsirm/scoring/rag.py: validate the sole allowlisted evaluation_split value with the existing shared descriptive_identifier(..., "evaluation_split", "$.metadata.evaluation_split") boundary (or an equally narrow established validator), yielding stable non-reflective invalid_evaluation_split. Preserve offline_holdout and all existing request identity/provenance behavior. Do not broaden caller metadata.
  3. Rerun the focused RAG test to GREEN plus relevant shared scoring metadata/authorization tests; maintain complete changed-production statement/branch coverage and public/private docstrings.
  4. Add concise docs/doctoring/ RAG request-boundary evidence grounded in primary RAGAS (EACL 2024), ARES (NAACL 2024), and RAGChecker work, explicitly stating reference-free != truth-free and that the adapter performs no metric arithmetic/provider inference/retrieval/truth adjudication. Add authoritative docs/changelog.d/607-* fragment.
  5. Run python scripts/render_changelog_fragments.py --update CHANGELOG.md, --check CHANGELOG.md, the changelog fragment contract, focused RAG tests, and git diff --check. Commit only this bounded current-review repair and deterministic renderer delta.

Keep Draft. Do not alter canonical architecture PR #604, dependencies, workflows, version/release, provider SDKs, Rust/PyO3 numerical kernels, scoring schemas, review/merge state, or expand into RAG observations/calibration. Stop after one exact-head GREEN/renderer commit and report evidence.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease only if a final refetch still shows Draft head 754f0716b072e551d682adca2639801aaad2e68b over protected main 8db4bf358b0a469915d6c5e336054f4a4f9c6b46; abort without writing if either moved or another current-head source writer appears.

The source fix and required evidence are now present: python/fast_mlsirm/scoring/rag.py validates metadata["evaluation_split"] through shared descriptive_identifier, docs/doctoring/rag_scoring_request_boundary.md records the bounded RAGAS/ARES/RAGChecker interpretation boundary, and docs/changelog.d/607-rag-scoring-request-boundary.md is the new authoritative fragment. Do not alter those semantics unless a focused test proves a current defect.

Finish only the deterministic evidence closure for this exact head:

  1. Run python scripts/render_changelog_fragments.py --update CHANGELOG.md, then python scripts/render_changelog_fragments.py --check CHANGELOG.md; commit only the renderer delta if one is required.
  2. Run pytest -q tests/test_scoring_rag_request.py, the relevant shared scoring metadata/authorization/serialization tests, pytest -q tests/test_changelog_fragment_contract.py, and git diff --check. Confirm test_rag_evaluation_split_rejects_raw_content_value is GREEN with stable non-reflective invalid_evaluation_split while offline_holdout remains accepted.
  3. Do not touch canonical architecture PR docs: establish canonical product and architecture baseline #604, dependencies, workflows, version/release, provider SDKs, Rust/PyO3 numerical kernels, or broaden RAG scope. Keep PR feat(rag): govern reference-free RAG scoring requests #613 Draft after the bounded commit; fresh exact-head CI/security/SAST/review will be evaluated separately.

If the branch or protected base moves before your write, leave a receipt and stop rather than reconciling destructively.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease only if a final refetch still shows Draft head 7c6bd59beb1de10b6f2c8aae670f89ef104e3bb7 over protected main a6b7ecc680b73a277714a795143c7a27125022c3; abort without writing if either moved or another source writer appears.

The branch has already been reconciled non-destructively with current protected main as a two-parent merge commit and now differs from main only by the four RAG contract paths. Preserve the accepted RAG contract and all current-main report UX behavior.

Complete only deterministic release-note cleanup:

  1. Run python scripts/render_changelog_fragments.py --update CHANGELOG.md and python scripts/render_changelog_fragments.py --check CHANGELOG.md, preserving the current-main feat(report): add exact-value essay tooltips and print semantics #616 note plus docs/changelog.d/607-rag-scoring-request-boundary.md through the repository renderer.
  2. Run pytest -q tests/test_scoring_rag_request.py tests/test_changelog_fragment_contract.py and git diff --check (plus formatting if required).
  3. Commit only renderer-produced CHANGELOG.md if those checks require a source change.

Keep Draft. Do not alter RAG request semantics, provider boundaries, dependencies/workflows/version/release, canonical architecture PR #604, mark Ready, approve, merge, or expand into calibration/model selection. Stop after exact-head deterministic evidence.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease on PR #613 only if a final refetch still shows exact head 7c6bd59beb1de10b6f2c8aae670f89ef104e3bb7 and protected main f43a466b1441b27bd2ac4a71be8aa3e4f08c8e8f; abort without writing if either moved or another source writer is active.

Current RCA is deterministic and narrow: exact-head Security/SAST are green and the feature tests pass; CI has one repository-contract failure because docs/changelog.d/607-rag-scoring-request-boundary.md is not rendered into managed CHANGELOG.md. Protected main also advanced through #618 after this branch's last reconciliation.

Execute only this bounded integration repair:

  1. non-destructively reconcile protected main into the branch, preserving all accepted-main behavior and only feat(rag): govern reference-free RAG scoring requests #613's unique RAG implementation/tests/doctoring/fragment;
  2. run python scripts/render_changelog_fragments.py --update, then --check; do not hand-edit or duplicate the managed block;
  3. run pytest -q tests/test_scoring_rag_request.py tests/test_changelog_fragment_contract.py and git diff --check;
  4. push only if those validations are green and the exact branch lease still holds.

Do not change the RAG contract, model arithmetic, dependencies, workflows, credentials, version, release state, or architecture docs. Keep the PR Draft. Report/push the minimal audited diff only.

seonghobae commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Superseded bookkeeping note: an earlier exact-current writer handoff already covers head 7c6bd59beb1de10b6f2c8aae670f89ef104e3bb7 over protected main f43a466b1441b27bd2ac4a71be8aa3e4f08c8e8f. This duplicate request is withdrawn; do not create an additional writer from this comment.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease only if a final refetch still shows Draft head 7c6bd59beb1de10b6f2c8aae670f89ef104e3bb7 and protected main f43a466b1441b27bd2ac4a71be8aa3e4f08c8e8f; abort if either moved or another current-head source writer appears. Prior handoffs tied to older head/base identities are stale.

This PR has only four unique product paths for the governed RAG scoring-request boundary. Preserve the current validation/provenance contract and Rust-only future psychometric arithmetic. Non-destructively reconcile current protected main, including accepted #618 behavior. Then render/check CHANGELOG.md from the authoritative docs/changelog.d/607-rag-scoring-request-boundary.md fragment, run focused RAG request tests plus changelog contract, formatting/lint and git diff --check, and commit only the minimum reconciliation/renderer cleanup required. Keep Draft. Do not expand into RAG numerical metrics, provider inference/retrieval, persistence, architecture PR #604, dependencies/workflows/version/release, Ready state, approval, merge, or another PR. Stop if exact head/base changes during the write; new exact-head full CI/security/review evidence must be produced after the mutation.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Take a bounded writer lease only if a final refetch still shows Draft head f8c855d849ad8ea96bbd0ce603e2ea847190341c and protected main f43a466b1441b27bd2ac4a71be8aa3e4f08c8e8f; abort if either moved or another current-head source writer appears. This exact head is a non-destructive two-parent reconciliation preserving only the four governed RAG request paths over protected main; predecessor handoffs are stale.

Do not change the RAG contract. Run the focused RAG request tests, then synchronize only managed release notes with the authoritative changelog renderer (--update then --check), run the changelog contract, formatting/lint and git diff --check, and commit the minimum renderer result if GREEN. Keep Draft. Do not add RAG metrics/provider inference/retrieval/persistence, alter Rust numerical ownership, dependencies/workflows/version/release, canonical docs #604, Ready/approval/merge state, or create another PR. Stop if exact head/base moves during the write.

Copy link
Copy Markdown
Contributor Author

Exact-head review finding on f8c855d849ad8ea96bbd0ce603e2ea847190341c: the stated content-minimization boundary is still bypassable through the direct system_configuration_id parameter. build_rag_scoring_request() passes that value unchanged into _rag_metadata(), which inserts it as rag_system_configuration_id; the later shared metadata freezer only bounds arbitrary strings and does not require an opaque/descriptive identifier. A caller can therefore put raw query/context/answer/source text (up to the shared metadata text bound) into system_configuration_id, and it will be serialized into the canonical scoring artifact despite the PR's claim that raw content cannot enter this surface. The existing tests validate evaluation_split but do not cover this direct managed-identity channel.

Keep the current source-writer lease intact; do not race the active changelog handoff. Once that writer is demonstrably finished, add a fail-first regression using a raw-content-shaped system_configuration_id, require a stable non-reflective invalid_system_configuration_id, normalize it with the shared descriptive_identifier(...) boundary before constructing managed metadata, and re-run the focused RAG request/security/changelog contracts. This is a current-head source/privacy defect, not a reason to weaken the metadata policy.

Copy link
Copy Markdown
Contributor Author

@jules address

Fallback bounded source-writer handoff for exact Draft head f8c855d849ad8ea96bbd0ce603e2ea847190341c over protected main f43a466b1441b27bd2ac4a71be8aa3e4f08c8e8f. The prior exact-head OpenCode handoff 5234666677 has no receipt/reaction and the source head has not moved; treat it as inactive, but perform a final head/base/comment refetch before writing and abort if another writer appears or either ref moved.

Address the current-head privacy/content-minimization defect before release-note cleanup. First add a fail-first regression using a raw-content-shaped direct system_configuration_id (for example natural-language query/context/answer text rather than an opaque/descriptive identifier) and prove the current builder serializes it into managed RAG provenance. Then make the narrowest fix: validate/normalize system_configuration_id through the existing shared descriptive_identifier(...) boundary before _rag_metadata() constructs rag_system_configuration_id; on invalid content raise stable non-reflective ValueError/package error code invalid_system_configuration_id without echoing the caller text. Preserve distinct configuration/run/response/retrieval/query identities and canonical fingerprint behavior for valid identifiers. Do not broaden arbitrary caller metadata or add raw content storage.

After RED→GREEN, run focused RAG request/security/fingerprint tests, then synchronize managed release notes only with python scripts/render_changelog_fragments.py --update CHANGELOG.md and --check CHANGELOG.md, run the changelog contract, formatting/lint and git diff --check, and commit one bounded source/test/changelog correction if all verification is green. Keep Draft. Do not add RAG metric arithmetic/provider inference/retrieval/persistence, change dependencies/workflows/version/release/Rust ownership/canonical docs #604, mark Ready, approve, merge, close #607, or open another PR. Stop writing if exact head/base changes.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Fresh bounded source/privacy repair for issue #607 after protected-main movement. Immediately before dispatch: Draft #613 exact head f8c855d849ad8ea96bbd0ce603e2ea847190341c; live protected main dccd1f281ec95216b3fcfd682d872c3ace74c68b; compare = diverged, ahead 13 / behind 1, with exactly four unique RAG paths. Prior exact-head writer handoffs were bound to f43a466... or older bases and required abort on base movement, so they are predecessor evidence. Final-refetch head/base/comments before writing; abort if either ref moves or another current-head writer appears.

A current source/privacy defect is independently reproduced from the exact head: build_rag_scoring_request() passes caller-controlled system_configuration_id unchanged into _rag_metadata(), which serializes it as rag_system_configuration_id; only evaluation_split uses descriptive_identifier. Issue #607 comments 5234765114/5234992146 already define the acceptance boundary. Do strict RED→GREEN:

  1. First add/run a production-boundary regression in tests/test_scoring_rag_request.py with raw-content-shaped system_configuration_id; prove exact predecessor accepts/serializes it. Setup/import/fixture failure is not valid RED.
  2. Implement only the narrow identity-boundary fix: normalize/validate system_configuration_id through the shared descriptive/opaque identifier validation before managed metadata construction. Invalid values must fail with stable non-reflective invalid_system_configuration_id; never echo caller content.
  3. Preserve valid identifier fingerprints and the existing identity separation: configuration ID != stochastic system_run_id/respondent != generated response_id; no metric arithmetic/provider calls/new schema hierarchy.
  4. Non-destructively reconcile live protected main, preserving accepted chore(deps): bump github/codeql-action/analyze from 4.37.4 to 4.37.6 #630 CodeQL analyze pin and only feat(rag): govern reference-free RAG scoring requests #613's four unique paths plus the narrow privacy repair.
  5. Run focused RAG/security/content-minimization tests, owned statement/branch coverage and docstrings as applicable, render/check authoritative CHANGELOG, formatting/lint and git diff --check; commit one coherent minimal repair if GREEN.

Keep Draft. Do not touch canonical docs #604, dependencies/workflows/version/release, Ready/approval/merge state, or expand into RAG metrics/inference/retrieval/persistence. Stop source writes after one verified update; fresh exact-head CI/Security/SAST/review returns to the maintainer loop.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Superseding exact-current privacy repair after #631 merged. Final pre-dispatch identities: Draft #613 head f8c855d849ad8ea96bbd0ce603e2ea847190341c; protected main a7be9eb8ca0b807364173f8471fc300e3cf9350f. All earlier handoffs were bound to older protected-main tips and required abort on base movement. Refetch head/main/comments immediately before writing and abort if either moves or another current-head source writer appears.

The exact head still contains the accepted #607 RAG adapter and the independently reproduced managed-identity privacy defect: caller-controlled system_configuration_id is serialized unchanged as rag_system_configuration_id, whereas only evaluation_split is normalized through descriptive_identifier. Use issue #607 comments 5234765114/5234992146 as acceptance. Strict RED→GREEN only: prove a raw-content-shaped system configuration ID currently reaches canonical metadata; then validate/normalize it through the shared descriptive/opaque identifier boundary with stable non-reflective invalid_system_configuration_id; preserve valid identity/fingerprint semantics and configuration != stochastic run/respondent != generated response. Reconcile current protected main non-destructively, preserving both CodeQL init/analyze 4.37.6 pins and only this PR's unique RAG paths. Run focused RAG/privacy/security tests, coverage/docstrings as applicable, authoritative changelog render/check, formatting/lint and git diff --check.

Keep Draft. No RAG metric arithmetic/provider inference/retrieval/persistence, new schema hierarchy, dependency/workflow/version/release changes, canonical docs #604, Ready/approval/merge. Stop source writes after one coherent verified repair; fresh exact-head full CI/Security/SAST/review belongs to the maintainer loop.

Copy link
Copy Markdown
Contributor Author

@jules address

Fallback sole branch writer for exact Draft #613 head f8c855d849ad8ea96bbd0ce603e2ea847190341c over live protected main a7be9eb8ca0b807364173f8471fc300e3cf9350f. Fresh compare remains diverged, ahead 13 / behind 2, merge base f43a466b1441b27bd2ac4a71be8aa3e4f08c8e8f; net feature paths remain only the governed RAG implementation/tests/doctoring/changelog fragment. The latest exact-base OpenCode handoff 5235681169 has no receipt/reaction and has produced no source movement for more than six hours. Treat it as inactive for this bounded fallback. Immediately refetch head/main/comments before writing and abort if either ref moves or any other current writer appears.

Preserve the accepted #607 RAG request contract and exact fail-first history. Reconcile the two accepted CodeQL 4.37.6 protected-main commits non-destructively. Then reproduce the managed-identity privacy RED at the public RAG request boundary: a raw-content-shaped caller system_configuration_id must currently reach rag_system_configuration_id; setup/import/fixture failure is not valid RED. Implement only the minimum GREEN by validating/normalizing that identity through the shared descriptive/opaque identifier boundary and returning stable non-reflective invalid_system_configuration_id for invalid values. Preserve configuration versus stochastic-run/respondent versus generated-response identity, valid fingerprint semantics, evidence regime/candidate visibility, caller metadata allowlist, and raw-text exclusion. Run focused RAG/privacy/security tests, meaningful changed statement/branch coverage and docstrings, formatting/lint and git diff --check; render/check managed CHANGELOG.md only through the repository renderer.

Keep Draft and stop source writes after one coherent verified update. Do not add RAG metric arithmetic, provider inference/retrieval/persistence, another scoring schema, dependencies/workflows/version/release changes, canonical docs #604, Ready/approval/merge state, or create another PR. Fresh exact-head full CI/Security/SAST/current-head review belongs to the maintainer loop.

Copy link
Copy Markdown
Contributor Author

Superseded by clean-lineage Draft #691 from exact protected main a7be9eb8ca0b807364173f8471fc300e3cf9350f. The latest fallback writer on #613 (5238763573) has no reaction/receipt and exact head f8c855d849ad8ea96bbd0ce603e2ea847190341c remained stationary while the branch diverged. #691 initially restores only the RAG implementation/test paths and adds the already independently identified system_configuration_id raw-content-channel regression as a deliberate production-boundary RED. Doctoring/changelog will be restored only after that defect reaches GREEN. No #613 checks/reviews transfer. Closing the stale branch prevents a second writer lineage; #691 is the sole implementation path for this slice.

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