Add pack-ready GroundRecall query bundle export

This commit is contained in:
welsberr 2026-04-27 13:01:52 -04:00
parent d48ad29aa2
commit fcbd4d7c8c
3 changed files with 44 additions and 1 deletions

View File

@ -12,6 +12,7 @@ from .query import (
query_provenance, query_provenance,
search_claims, search_claims,
) )
from .export import export_groundrecall_query_bundle
from .store import GroundRecallStore from .store import GroundRecallStore
__all__ = [ __all__ = [
@ -27,6 +28,7 @@ __all__ = [
"query_provenance", "query_provenance",
"search_claims", "search_claims",
"build_query_bundle_for_concept", "build_query_bundle_for_concept",
"export_groundrecall_query_bundle",
"build_query_parser", "build_query_parser",
"query_main", "query_main",
"summarize_store", "summarize_store",

View File

@ -92,11 +92,28 @@ def export_query_bundle(
return payload return payload
def export_groundrecall_query_bundle(
store_dir: str | Path,
concept_ref: str,
out_dir: str | Path,
) -> dict[str, Any]:
target = Path(out_dir)
target.mkdir(parents=True, exist_ok=True)
out_path = target / "groundrecall_query_bundle.json"
payload = export_query_bundle(store_dir, concept_ref, out_path)
return {
"concept_ref": concept_ref,
"bundle_path": str(out_path),
"bundle": payload,
}
def export_canonical_bundle( def export_canonical_bundle(
store_dir: str | Path, store_dir: str | Path,
out_dir: str | Path, out_dir: str | Path,
concept_refs: list[str] | None = None, concept_refs: list[str] | None = None,
snapshot_id: str | None = None, snapshot_id: str | None = None,
pack_ready_concept: str | None = None,
) -> dict[str, Any]: ) -> dict[str, Any]:
target = Path(out_dir) target = Path(out_dir)
target.mkdir(parents=True, exist_ok=True) target.mkdir(parents=True, exist_ok=True)
@ -107,12 +124,18 @@ def export_canonical_bundle(
bundle_path = target / f"query_bundle__{safe_name}.json" bundle_path = target / f"query_bundle__{safe_name}.json"
export_query_bundle(store_dir, concept_ref, bundle_path) export_query_bundle(store_dir, concept_ref, bundle_path)
query_bundle_paths.append(str(bundle_path)) query_bundle_paths.append(str(bundle_path))
pack_ready_bundle = None
if pack_ready_concept:
pack_ready_bundle = export_groundrecall_query_bundle(store_dir, pack_ready_concept, target)
manifest = json.loads((target / "export_manifest.json").read_text(encoding="utf-8")) manifest = json.loads((target / "export_manifest.json").read_text(encoding="utf-8"))
manifest["query_bundles"] = query_bundle_paths manifest["query_bundles"] = query_bundle_paths
if pack_ready_bundle is not None:
manifest["groundrecall_query_bundle"] = pack_ready_bundle["bundle_path"]
_write_json(target / "export_manifest.json", manifest) _write_json(target / "export_manifest.json", manifest)
return { return {
"canonical_outputs": outputs, "canonical_outputs": outputs,
"query_bundles": query_bundle_paths, "query_bundles": query_bundle_paths,
"groundrecall_query_bundle": pack_ready_bundle,
} }
@ -122,6 +145,7 @@ def build_parser() -> argparse.ArgumentParser:
parser.add_argument("out_dir") parser.add_argument("out_dir")
parser.add_argument("--snapshot-id", default=None) parser.add_argument("--snapshot-id", default=None)
parser.add_argument("--concept", action="append", default=[]) parser.add_argument("--concept", action="append", default=[])
parser.add_argument("--pack-ready-concept", default=None)
return parser return parser
@ -132,5 +156,6 @@ def main() -> None:
out_dir=args.out_dir, out_dir=args.out_dir,
concept_refs=list(args.concept or []), concept_refs=list(args.concept or []),
snapshot_id=args.snapshot_id, snapshot_id=args.snapshot_id,
pack_ready_concept=args.pack_ready_concept,
) )
print(json.dumps(payload, indent=2)) print(json.dumps(payload, indent=2))

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import json import json
from pathlib import Path from pathlib import Path
from groundrecall.export import export_canonical_bundle, export_query_bundle from groundrecall.export import export_canonical_bundle, export_groundrecall_query_bundle, export_query_bundle
from groundrecall.models import ( from groundrecall.models import (
ArtifactRecord, ArtifactRecord,
ClaimRecord, ClaimRecord,
@ -104,6 +104,7 @@ def test_export_canonical_bundle_writes_expected_files(tmp_path: Path) -> None:
out_dir=out_dir, out_dir=out_dir,
concept_refs=["channel-capacity"], concept_refs=["channel-capacity"],
snapshot_id="snap_export_001", snapshot_id="snap_export_001",
pack_ready_concept="channel-capacity",
) )
assert (out_dir / "groundrecall_snapshot.json").exists() assert (out_dir / "groundrecall_snapshot.json").exists()
@ -113,6 +114,7 @@ def test_export_canonical_bundle_writes_expected_files(tmp_path: Path) -> None:
assert (out_dir / "provenance_manifest.json").exists() assert (out_dir / "provenance_manifest.json").exists()
assert (out_dir / "export_manifest.json").exists() assert (out_dir / "export_manifest.json").exists()
assert (out_dir / "query_bundle__channel-capacity.json").exists() assert (out_dir / "query_bundle__channel-capacity.json").exists()
assert (out_dir / "groundrecall_query_bundle.json").exists()
snapshot = json.loads((out_dir / "groundrecall_snapshot.json").read_text(encoding="utf-8")) snapshot = json.loads((out_dir / "groundrecall_snapshot.json").read_text(encoding="utf-8"))
manifest = json.loads((out_dir / "export_manifest.json").read_text(encoding="utf-8")) manifest = json.loads((out_dir / "export_manifest.json").read_text(encoding="utf-8"))
@ -120,8 +122,10 @@ def test_export_canonical_bundle_writes_expected_files(tmp_path: Path) -> None:
assert snapshot["snapshot_id"] == "snap_export_001" assert snapshot["snapshot_id"] == "snap_export_001"
assert manifest["export_kind"] == "canonical" assert manifest["export_kind"] == "canonical"
assert len(manifest["query_bundles"]) == 1 assert len(manifest["query_bundles"]) == 1
assert manifest["groundrecall_query_bundle"].endswith("groundrecall_query_bundle.json")
assert claims[0]["claim_id"] == "clm_001" assert claims[0]["claim_id"] == "clm_001"
assert payload["query_bundles"] assert payload["query_bundles"]
assert payload["groundrecall_query_bundle"] is not None
def test_export_query_bundle_is_assistant_neutral(tmp_path: Path) -> None: def test_export_query_bundle_is_assistant_neutral(tmp_path: Path) -> None:
@ -134,3 +138,15 @@ def test_export_query_bundle_is_assistant_neutral(tmp_path: Path) -> None:
assert payload["bundle_kind"] == "groundrecall_query_bundle" assert payload["bundle_kind"] == "groundrecall_query_bundle"
forbidden = {"assistant", "codex", "claude", "prompt_text"} forbidden = {"assistant", "codex", "claude", "prompt_text"}
assert set(payload).isdisjoint(forbidden) assert set(payload).isdisjoint(forbidden)
def test_export_groundrecall_query_bundle_uses_pack_ready_filename(tmp_path: Path) -> None:
store = GroundRecallStore(tmp_path / "groundrecall")
_seed_store(store)
out_dir = tmp_path / "pack-ready"
payload = export_groundrecall_query_bundle(store.base_dir, "channel-capacity", out_dir)
assert (out_dir / "groundrecall_query_bundle.json").exists()
assert payload["bundle_path"].endswith("groundrecall_query_bundle.json")
assert payload["bundle"]["bundle_kind"] == "groundrecall_query_bundle"