Skip to content

feat(cmd): add retriever graph dump tooling#103

Open
zinic wants to merge 1 commit into
mainfrom
kpom/retriever-additions
Open

feat(cmd): add retriever graph dump tooling#103
zinic wants to merge 1 commit into
mainfrom
kpom/retriever-additions

Conversation

@zinic

@zinic zinic commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Description

Adds cmd/retriever, a CLI for exporting and importing live Dawgs graph
databases as manifest-based OpenGraph-derived collections. Retriever supports
PostgreSQL and Neo4j graph targets, deterministic dump ordering, gzip/zstd
fragment compression, checksum validation, metrics/fingerprint verification,
optional deterministic property scrubbing, read-throughput benchmarking, and
single-file encrypted TAR archive workflows using HPKE/ML-KEM.

This also documents retriever usage, adds a Go coding standard, and updates
query.OrderBy so bare criteria default to ascending sort items.

Resolves: N/A

Type of Change

  • Chore (a change that does not modify the application functionality)
  • Bug fix (a change that fixes an issue)
  • New feature / enhancement (a change that adds new functionality)
  • Refactor (no behavior change)
  • Test coverage
  • Build / CI / tooling
  • Documentation

Testing

  • Unit tests added / updated

  • Integration tests added / updated

  • Full test suite run (make test_all with CONNECTION_STRING set)

  • make format

  • go test ./cmd/retriever

Screenshots (if appropriate):

N/A

Driver Impact

  • PostgreSQL driver (drivers/pg)
  • Neo4j driver (drivers/neo4j)

Checklist

  • Code is formatted
  • All existing tests pass
  • go.mod / go.sum are up to date if dependencies changed

Summary by CodeRabbit

  • New Features
    • Added a full retriever CLI for dumping, loading, verifying, benchmarking, key generation, unpacking, and encrypted archive workflows.
    • Introduced deterministic tar creation/extraction, HPKE-encrypted framed archive envelopes, and compressed fragment handling with checksums.
    • Added graph metrics generation, manifest validation, and benchmark reporting.
  • Bug Fixes
    • Strengthened validation to detect tampering, truncation, unsafe archive contents, phase/count mismatches, and non-empty output/load destinations.
  • Documentation
    • Added Go coding standard and expanded README + CLI docs, including encrypted packaging plans and test-metrics guidance.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds the retriever CLI for dumping, loading, verifying, and benchmarking Dawgs graphs, including manifest files, compression, archive packaging, scrubbing, and metrics. Also updates docs, dependency versions, and query ordering behavior.

Changes

Retriever CLI Tool

Layer / File(s) Summary
Manifest and file metadata
cmd/retriever/types.go, cmd/retriever/manifest.go, cmd/retriever/manifest_test.go
Defines manifest/fragment types, validation, read/write helpers, checksum verification, and supporting kind/action utilities.
Compressed JSON fragments
cmd/retriever/compression*.go
Implements gzip/zstd fragment encoding, checksum generation, fragment reading, and in-memory size measurement with tests.
CLI flags and option validation
cmd/retriever/config*.go
Adds custom flag types, worker parsing, option validation, and shared CLI/database helpers with tests.
Database opening and graph targets
cmd/retriever/database*.go
Implements database connection setup, driver inference, graph target resolution, PostgreSQL graph discovery, and graph directory naming with tests.
Archive key envelopes
cmd/retriever/archive_keys*.go
Implements HPKE archive key generation, exclusive file writing, envelope loading, and path validation with tests.
Deterministic TAR packaging
cmd/retriever/archive_tar*.go
Implements collection TAR writing, path sanitization, safe extraction, and archive-force handling with tests.
Encrypted archive envelope
cmd/retriever/archive_envelope*.go
Implements HPKE-encrypted streaming archive framing, header parsing, staged unpacking, and collection validation with extensive tests.
Deterministic property scrubber
cmd/retriever/scrubber*.go, cmd/retriever/defaults.toml
Implements configurable pseudonymization, redaction, timestamp shifting, and value-shape classification, with default rules and tests.
Dump command implementation
cmd/retriever/dump*.go
Implements dump orchestration, fragment writing, scrub pre-scans, path naming, and per-graph consistency checks with tests.
Load command implementation
cmd/retriever/load*.go
Implements load orchestration, archive input preparation, schema assertion, fragment ingestion, and loaded-metric verification with tests.
Metrics and Verify
cmd/retriever/metrics*.go, cmd/retriever/verify.go
Implements deterministic graph metrics, comparison and validation, and the Verify workflow with live database metric collection and tests.
Bench command implementation
cmd/retriever/bench*.go
Implements read-throughput benchmarking, batch aggregation, report formatting, and benchmark tests.
CLI wiring, progress, scan, and integration coverage
cmd/retriever/main*.go, cmd/retriever/progress.go, cmd/retriever/scan*.go, cmd/retriever/README.md, cmd/retriever/packaging_plan.md, cmd/retriever/retriever_integration_test.go
Wires subcommands into the CLI runtime, adds progress and scan helpers, and includes docs plus integration coverage for dump/load/verify flows.

Query OrderBy Fix

Layer / File(s) Summary
OrderBy leaf handling fix
query/model.go, query/neo4j/neo4j_test.go
Updates OrderBy to conditionally wrap non-SortItem inputs and verifies direct node ID ordering renders as expected.

Coding Standard and README Updates

Layer / File(s) Summary
Go coding standard and README notes
GOLANG_CODING_STANDARD.md, README.md
Introduces GOLANG_CODING_STANDARD.md and expands the README with retriever command notes.

Dependency Maintenance

Layer / File(s) Summary
Dependency version bumps
go.mod
Updates the Go version and direct and indirect module requirements.

Estimated code review effort: 5 (Critical) | ~150 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant main.go
  participant Dump
  participant Load
  participant Verify
  participant Bench

  User->>main.go: retriever dump/load/verify/bench
  main.go->>Dump: Dump(ctx, db, targets, options)
  main.go->>Load: Load(ctx, db, options)
  main.go->>Verify: Verify(ctx, db, options)
  main.go->>Bench: Bench(ctx, db, targets, options)
  Dump-->>main.go: dumpResult / manifest
  Load-->>main.go: loadResult
  Verify-->>main.go: verifyResult / metricsMismatchError
  Bench-->>main.go: benchReport
Loading
sequenceDiagram
  participant Dump
  participant writeCollectionTar
  participant encryptedArchiveWriter
  participant unpackEncryptedCollectionArchive
  participant unpackTar

  Dump->>writeCollectionTar: stream manifest+fragments as tar
  writeCollectionTar->>encryptedArchiveWriter: write tar bytes into HPKE envelope
  encryptedArchiveWriter-->>Dump: encrypted archive file

  unpackEncryptedCollectionArchive->>encryptedArchiveWriter: read frames, decrypt via HPKE
  encryptedArchiveWriter->>unpackTar: decrypted tar stream
  unpackTar-->>unpackEncryptedCollectionArchive: extracted collection files
Loading

Suggested labels: enhancement, go
Suggested reviewers: brandonshearin, urangel

Poem

A rabbit hopped through fragments and frames,
Sealed archives bright with encrypted names.
It scrubbed every carrot and counted each hare,
Then dumped, loaded, verified—thump!—all with care.
🐇🔐

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main retriever CLI addition, though it understates the broader import, verify, and archive features.
Description check ✅ Passed The description follows the template structure and covers purpose, type, testing, driver impact, and checklist, with only the ticket field left as N/A.
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.
✨ 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 kpom/retriever-additions

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.

@zinic zinic force-pushed the kpom/retriever-additions branch from 0a49819 to 809e585 Compare July 7, 2026 17:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (8)
cmd/retriever/defaults.toml (1)

1-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Single-source the scrubber defaults defaults.toml is only a documented -config template; newScrubber reads an explicitly supplied path and nothing embeds or auto-loads this file. Since it mirrors defaultScrubberConfig(), derive one from the other to avoid drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/retriever/defaults.toml` around lines 1 - 64, The scrubber defaults are
duplicated between the TOML template and the runtime config source, so they can
drift over time. Update the configuration path used by newScrubber and
defaultScrubberConfig so both come from a single source of truth, and make
defaults.toml reflect that same structure instead of independently maintaining
values like scrub, classifier, and value_shapes.
cmd/retriever/main_test.go (1)

85-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Temp dir leaks if assertions fail before manual cleanup() call.

cleanup is only invoked at line 96, after the t.Fatalf checks at lines 87, 90, and 93. If any of those fail, the test halts before cleanup runs, leaking the temp input directory created by prepareLoadInput.

♻️ Suggested fix: guarantee cleanup runs
 	cfg, cleanup, err := prepareLoadInput(cfg)
 	if err != nil {
 		t.Fatalf("prepare load input from archive: %v", err)
 	}
+	t.Cleanup(cleanup)
 	if cfg.InputDir == "" {
 		t.Fatalf("expected temp input dir")
 	}
 	if _, err := readManifest(cfg.InputDir); err != nil {
 		t.Fatalf("read prepared load manifest: %v", err)
 	}
 	inputDir := cfg.InputDir
-	cleanup()
 	if _, err := os.Stat(inputDir); !os.IsNotExist(err) {
 		t.Fatalf("expected load temp dir cleanup, got %v", err)
 	}

Note: with t.Cleanup, the os.Stat assertion would need to run inside a registered cleanup ordered after the primary one, or be restructured to call cleanup explicitly in the success path while still registering it via t.Cleanup for the failure paths as a safety net.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/retriever/main_test.go` around lines 85 - 99, The test in main_test.go
leaks the temp input directory when an earlier assertion fails because cleanup
is only called in the success path. Update the prepareLoadInput test flow to
guarantee cleanup runs by registering the returned cleanup function with
t.Cleanup (or otherwise ensuring it executes on failure), and keep the
post-cleanup os.Stat check in a separate ordered cleanup/assertion path so the
temp dir deletion is still verified.
cmd/retriever/metrics.go (1)

297-302: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Silent diff truncation with no indicator.

appendMetricDiff caps at maxMetricDiffs (20) and silently drops further differences. When Verify surfaces this list directly as the error message, a user debugging a large mismatch has no way to know the reported list is incomplete.

♻️ Suggested fix: append a truncation marker
 func appendMetricDiff(target []string, value string) []string {
-	if len(target) >= maxMetricDiffs {
+	if len(target) >= maxMetricDiffs {
+		if len(target) == maxMetricDiffs {
+			return append(target, "... additional differences omitted")
+		}
 		return target
 	}
 	return append(target, value)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/retriever/metrics.go` around lines 297 - 302, The appendMetricDiff helper
currently stops adding entries at maxMetricDiffs and silently truncates the diff
list, so update it to append a clear truncation marker when the limit is
reached. Adjust appendMetricDiff (and any Verify path that uses its output) so
the returned slice explicitly indicates there are more differences than shown,
making the Metric verification error message obviously incomplete rather than
silently cut off.
cmd/retriever/bench.go (2)

294-359: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate byte-accounting logic between benchNodeBatch and benchRelationshipBatch.

Both functions build a slice of fragment items, then call compressedJSONSize on a wrapped {Phase, Items} struct with identical guard/timing logic. This is a good candidate to consolidate alongside the benchNodes/benchEdges refactor above.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/retriever/bench.go` around lines 294 - 359, `benchNodeBatch` and
`benchRelationshipBatch` duplicate the same batch byte-accounting flow: build
fragment items, time `compressedJSONSize`, and populate `benchPhaseResult`.
Refactor this shared logic into a common helper that accepts the
phase/type-specific item builder for `fragmentNode` and `fragmentEdge`, then
have both functions delegate to it while preserving the existing `Count`,
timing, and byte-size fields.

200-292: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate keyset-scan loop between benchNodes and benchEdges.

The two functions are structurally identical (planned-count loop, keyset advancement check, batch dispatch, progress logging) aside from calling readDatabaseNodes/readDatabaseRelationships and benchNodeBatch/benchRelationshipBatch. This duplication risks the two loops silently diverging on bug fixes (e.g., the keyset-advancement guard) in the future.

Consider extracting a shared generic helper that accepts the batch-read and batch-process functions as parameters, keyed by graph.ID.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/retriever/bench.go` around lines 200 - 292, `benchNodes` and `benchEdges`
duplicate the same keyset-scan loop, so factor the shared flow into a helper
that takes the read and batch handlers as parameters. Keep the common
planned-count loop, `lastID` advancement check, progress logging, and
elapsed-time tracking in one place, and let `benchNodes`/`benchEdges` only
supply `readDatabaseNodes` vs `readDatabaseRelationships` and `benchNodeBatch`
vs `benchRelationshipBatch`. Ensure the helper still works with `graph.ID` and
preserves the existing `retrieverInitialProgressAt`, `retrieverBatchLimit`, and
`logBenchPhaseProgress` behavior.
cmd/retriever/README.md (1)

177-203: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Bench's -all-graphs flag is undocumented.

main.go's runBench wires -all-graphs (flags.BoolVar(&cfg.AllGraphs, "all-graphs", false, "Benchmark every graph discoverable by the selected driver.")), mirroring the dump command, but the Bench section here doesn't mention it (only the Dump section at Line 23-26 documents -all-graphs).

As per coding guidelines, "Keep README.md in lock-step with test, build, setup, and user-facing workflow changes."

 retriever bench \
   -connection "$CONNECTION_STRING" \
   -graph default \
   -workers 1 \
   -batch-size 10000 \
   -sample-size 1000000

+Use -all-graphs to benchmark every graph discoverable by the selected driver,
+mirroring the dump command's discovery behavior.
+
Benchmark mode performs read-only scans and reports node and relationship


<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @cmd/retriever/README.md around lines 177 - 203, The Bench README is missing
documentation for the user-facing -all-graphs flag wired in runBench. Update the
Bench section in cmd/retriever/README.md to mention that -all-graphs benchmarks
every graph discoverable by the selected driver, matching the behavior already
documented for dump, and place it alongside the existing bench flags description
so the CLI docs stay in sync with main.go.


</details>

<!-- cr-comment:v1:8ac1582bcf141dbd0d10face -->

_Source: Coding guidelines_

</blockquote></details>
<details>
<summary>cmd/retriever/bench_test.go (1)</summary><blockquote>

`1-71`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _⚡ Quick win_

**Missing coverage for `benchNodeBatch`/`benchRelationshipBatch`/`logBenchPhaseProgress`.**

These are pure, DB-free functions (compression accounting and progress-threshold logging) that fall squarely within the project's stated testing policy of covering "compression/checksum behavior... and other pure helpers" (per `cmd/retriever/README.md`), yet they have no direct test here. In particular, `benchNodeBatch`/`benchRelationshipBatch` exercise the `compressionNone` short-circuit and the `compressedJSONSize` call path, which would benefit from at least one assertion each.

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @cmd/retriever/bench_test.go around lines 1 - 71, The bench helper test
coverage is missing direct assertions for the pure DB-free helpers
benchNodeBatch, benchRelationshipBatch, and logBenchPhaseProgress. Extend
TestBenchSamplingHelpers or add focused tests to exercise the compressionNone
short-circuit and compressedJSONSize path in benchNodeBatch and
benchRelationshipBatch, and verify logBenchPhaseProgress emits the expected
threshold-based progress behavior using the existing helper symbols.


</details>

<!-- cr-comment:v1:daeaeb76d18556bd196ba2e3 -->

</blockquote></details>
<details>
<summary>cmd/retriever/compression.go (1)</summary><blockquote>

`24-38`: _🎯 Functional Correctness_ | _🔵 Trivial_ | _💤 Low value_

**Rename `compressionNone` if it’s only a sentinel.**

`validateCompression`, `newCompressionWriter`, and `newDecompressionReader` intentionally reject it, while `bench` treats it as the uncompressed path. The name makes it look like a general “store uncompressed” codec even though dump/load don’t support that.

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @cmd/retriever/compression.go around lines 24 - 38, Rename the
compressionNone sentinel to something that clearly indicates “no compression
supported” and update its uses in validateCompression, newCompressionWriter,
newDecompressionReader, and the bench path. Keep the behavior the same, but
make the enum/value name reflect that dump/load reject it while benchmarking
treats it as the uncompressed case.


</details>

<!-- cr-comment:v1:538174c05fc0aaff8cde5c9b -->

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

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 @cmd/retriever/archive_keys.go:

  • Around line 3-11: The archive key handling in archive_keys.go imports
    crypto/hpke, which is not available with the current Go toolchain version in
    go.mod. Update the project’s Go version/toolchain to 1.26+ if HPKE from the
    standard library is required, or replace the crypto/hpke usage in the archive
    key code with a compatible external HPKE implementation so the package builds
    again.

In @cmd/retriever/load.go:

  • Around line 94-152: The load loop in load.go currently appends graph data
    without verifying the target is empty, so reruns can duplicate earlier fragments
    after a partial failure. Add a preflight check in the main load path before
    iterating nextManifest.Graphs (or clear existing graph data there) so load
    either fails fast on non-empty state or becomes explicitly idempotent/resumable.
    Use the loadResult and graph-loading flow around loadGraphNodes/loadGraphEdges
    to place the check where it guards all fragment commits.

In @cmd/retriever/main.go:

  • Around line 1-12: The new crypto/hpke import in main makes the module require
    Go 1.26+, but the repo still targets an older toolchain, so update the declared
    Go version and any CI setup that reads go.mod (including the workflows using
    go-version-file) to 1.26 or newer, or remove the hpke usage from
    cmd/retriever/main.go if you want to keep the older version. Locate the change
    in main and align the module/tooling versions accordingly.

In @cmd/retriever/scrubber.go:

  • Around line 587-589: The object_sid handling in scrubber.go can panic when the
    value is routed into the shape == "object_sid" branch but does not actually
    match objectSIDPattern, because FindStringSubmatch may return nil and matches[1]
    is accessed unconditionally. Update the object_sid case in the scrubber logic to
    verify the submatch result before using it, and fall back safely when no match
    is found; keep the fix localized around the objectSIDPattern match and
    pseudonymizeString call.

In @cmd/retriever/types.go:

  • Around line 135-201: The manifest validation in validate() is missing a
    whitelist check for s.Scrub.Mode, so invalid or corrupted scrub modes can slip
    through. Add a scrub mode validation alongside the existing Format, IDStrategy,
    and Compression checks, and reject any value other than the supported scrubNone
    and scrubFull symbols used by manifest validation. Keep the change in validate()
    so readManifest, load, and verify all benefit from the same enforcement.

In @GOLANG_CODING_STANDARD.md:

  • Around line 3-4: The intro text in the Go coding standard still references the
    old repository name and should be updated to match the current project. Edit the
    opening sentence in GOLANG_CODING_STANDARD.md so it uses dawgs instead of gtfo,
    keeping the rest of the guidance unchanged.

Nitpick comments:
In @cmd/retriever/bench_test.go:

  • Around line 1-71: The bench helper test coverage is missing direct assertions
    for the pure DB-free helpers benchNodeBatch, benchRelationshipBatch, and
    logBenchPhaseProgress. Extend TestBenchSamplingHelpers or add focused tests to
    exercise the compressionNone short-circuit and compressedJSONSize path in
    benchNodeBatch and benchRelationshipBatch, and verify logBenchPhaseProgress
    emits the expected threshold-based progress behavior using the existing helper
    symbols.

In @cmd/retriever/bench.go:

  • Around line 294-359: benchNodeBatch and benchRelationshipBatch duplicate
    the same batch byte-accounting flow: build fragment items, time
    compressedJSONSize, and populate benchPhaseResult. Refactor this shared
    logic into a common helper that accepts the phase/type-specific item builder for
    fragmentNode and fragmentEdge, then have both functions delegate to it while
    preserving the existing Count, timing, and byte-size fields.
  • Around line 200-292: benchNodes and benchEdges duplicate the same
    keyset-scan loop, so factor the shared flow into a helper that takes the read
    and batch handlers as parameters. Keep the common planned-count loop, lastID
    advancement check, progress logging, and elapsed-time tracking in one place, and
    let benchNodes/benchEdges only supply readDatabaseNodes vs
    readDatabaseRelationships and benchNodeBatch vs benchRelationshipBatch.
    Ensure the helper still works with graph.ID and preserves the existing
    retrieverInitialProgressAt, retrieverBatchLimit, and logBenchPhaseProgress
    behavior.

In @cmd/retriever/compression.go:

  • Around line 24-38: Rename the compressionNone sentinel to something that
    clearly indicates “no compression supported” and update its uses in
    validateCompression, newCompressionWriter, newDecompressionReader, and the
    bench path. Keep the behavior the same, but make the enum/value name reflect
    that dump/load reject it while benchmarking treats it as the uncompressed case.

In @cmd/retriever/defaults.toml:

  • Around line 1-64: The scrubber defaults are duplicated between the TOML
    template and the runtime config source, so they can drift over time. Update the
    configuration path used by newScrubber and defaultScrubberConfig so both come
    from a single source of truth, and make defaults.toml reflect that same
    structure instead of independently maintaining values like scrub, classifier,
    and value_shapes.

In @cmd/retriever/main_test.go:

  • Around line 85-99: The test in main_test.go leaks the temp input directory
    when an earlier assertion fails because cleanup is only called in the success
    path. Update the prepareLoadInput test flow to guarantee cleanup runs by
    registering the returned cleanup function with t.Cleanup (or otherwise ensuring
    it executes on failure), and keep the post-cleanup os.Stat check in a separate
    ordered cleanup/assertion path so the temp dir deletion is still verified.

In @cmd/retriever/metrics.go:

  • Around line 297-302: The appendMetricDiff helper currently stops adding
    entries at maxMetricDiffs and silently truncates the diff list, so update it to
    append a clear truncation marker when the limit is reached. Adjust
    appendMetricDiff (and any Verify path that uses its output) so the returned
    slice explicitly indicates there are more differences than shown, making the
    Metric verification error message obviously incomplete rather than silently cut
    off.

In @cmd/retriever/README.md:

  • Around line 177-203: The Bench README is missing documentation for the
    user-facing -all-graphs flag wired in runBench. Update the Bench section in
    cmd/retriever/README.md to mention that -all-graphs benchmarks every graph
    discoverable by the selected driver, matching the behavior already documented
    for dump, and place it alongside the existing bench flags description so the CLI
    docs stay in sync with main.go.

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Organization UI

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `f666e22b-9c23-4cdd-8b0a-6a7c17b14d07`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 44b68ea4dee770c469835ec27565e56d8fb9a6ca and 0a498192ab8b478f57468edbc2204d2c6a8a3abf.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `go.sum` is excluded by `!**/*.sum`

</details>

<details>
<summary>📒 Files selected for processing (39)</summary>

* `GOLANG_CODING_STANDARD.md`
* `README.md`
* `cmd/benchdiff/compare_test.go`
* `cmd/retriever/README.md`
* `cmd/retriever/archive_envelope.go`
* `cmd/retriever/archive_envelope_test.go`
* `cmd/retriever/archive_keys.go`
* `cmd/retriever/archive_keys_test.go`
* `cmd/retriever/archive_tar.go`
* `cmd/retriever/archive_tar_test.go`
* `cmd/retriever/bench.go`
* `cmd/retriever/bench_test.go`
* `cmd/retriever/compression.go`
* `cmd/retriever/compression_test.go`
* `cmd/retriever/config.go`
* `cmd/retriever/config_test.go`
* `cmd/retriever/database.go`
* `cmd/retriever/database_test.go`
* `cmd/retriever/defaults.toml`
* `cmd/retriever/dump.go`
* `cmd/retriever/dump_test.go`
* `cmd/retriever/load.go`
* `cmd/retriever/load_test.go`
* `cmd/retriever/main.go`
* `cmd/retriever/main_test.go`
* `cmd/retriever/manifest.go`
* `cmd/retriever/manifest_test.go`
* `cmd/retriever/metrics.go`
* `cmd/retriever/metrics_test.go`
* `cmd/retriever/packaging_plan.md`
* `cmd/retriever/progress.go`
* `cmd/retriever/retriever_integration_test.go`
* `cmd/retriever/scrubber.go`
* `cmd/retriever/scrubber_test.go`
* `cmd/retriever/types.go`
* `cmd/retriever/verify.go`
* `go.mod`
* `query/model.go`
* `query/neo4j/neo4j_test.go`

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread cmd/retriever/archive_keys.go
Comment thread cmd/retriever/load.go
Comment thread cmd/retriever/main.go
Comment thread cmd/retriever/scrubber.go Outdated
Comment thread cmd/retriever/types.go
Comment thread GOLANG_CODING_STANDARD.md Outdated
@zinic zinic force-pushed the kpom/retriever-additions branch 2 times, most recently from 068719f to bde58b1 Compare July 7, 2026 20:21

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
cmd/retriever/load_test.go (1)

167-182: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Wrong-phase sub-test doesn't isolate the phase-check from checksum validation.

Unlike the count-mismatch case just above (which reuses valid CompressedBytes/SHA256 to isolate solely the count check), this sub-test passes a fileManifest with zero-value CompressedBytes/SHA256. If checksum validation runs before phase validation, this test would pass due to a checksum failure rather than the intended phase mismatch, masking regressions in phase-validation logic.

♻️ Proposed fix
-	if _, err := readNodeFragmentFile(dir, compressionGzip, fileManifest{
-		Path:  "wrong-phase.gz",
-		Count: 1,
-	}); err == nil {
-		t.Fatalf("expected node phase mismatch")
-	}
+	wrongPhaseFile := fileManifest{
+		Path:  "wrong-phase.gz",
+		Count: 1,
+	}
+	if _, err := readNodeFragmentFile(dir, compressionGzip, wrongPhaseFile); err == nil {
+		t.Fatalf("expected node phase mismatch")
+	} else if !strings.Contains(err.Error(), "phase") {
+		t.Fatalf("expected phase mismatch error, got: %v", err)
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/retriever/load_test.go` around lines 167 - 182, The wrong-phase sub-test
in readNodeFragmentFile is not isolating the phase check because the
fileManifest uses zero-value CompressedBytes and SHA256, so a checksum failure
could satisfy the test before phase validation runs. Update the sub-test to
reuse the same valid manifest metadata pattern as the count-mismatch case by
providing the correct compressed bytes and checksum for "wrong-phase.gz" while
keeping the phase set to phaseEdges, so the assertion specifically verifies the
node-phase mismatch path.
🤖 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 `@cmd/retriever/archive_envelope.go`:
- Around line 278-289: promoteUnpackStagingDirectory currently deletes outputDir
before moving stagingDir into place, which can lose the original contents if
os.Rename fails. Update this function to use a safe swap flow: rename outputDir
to a temporary backup first, then rename stagingDir to outputDir, and only
remove the backup after the second rename succeeds; if the staging rename fails,
restore the backup so the force path in promoteUnpackStagingDirectory and its
callers never leaves the target missing.
- Around line 389-403: The size check in writeEncryptedArchiveFrame uses
int(^uint32(0)), which can fail to compile on 32-bit builds. Update the length
guard to compare len(ciphertext) using an unsigned type such as uint64 against a
32-bit maximum, then keep the uint32 cast for frameHeader[1:] only after that
check. Use writeEncryptedArchiveFrame as the reference point when making the
fix.

---

Nitpick comments:
In `@cmd/retriever/load_test.go`:
- Around line 167-182: The wrong-phase sub-test in readNodeFragmentFile is not
isolating the phase check because the fileManifest uses zero-value
CompressedBytes and SHA256, so a checksum failure could satisfy the test before
phase validation runs. Update the sub-test to reuse the same valid manifest
metadata pattern as the count-mismatch case by providing the correct compressed
bytes and checksum for "wrong-phase.gz" while keeping the phase set to
phaseEdges, so the assertion specifically verifies the node-phase mismatch path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 35d7e160-4518-412b-bdf7-a3d229758be4

📥 Commits

Reviewing files that changed from the base of the PR and between 0a49819 and bde58b1.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (42)
  • GOLANG_CODING_STANDARD.md
  • README.md
  • cmd/benchdiff/compare.go
  • cmd/benchdiff/compare_test.go
  • cmd/retriever/README.md
  • cmd/retriever/archive_envelope.go
  • cmd/retriever/archive_envelope_test.go
  • cmd/retriever/archive_keys.go
  • cmd/retriever/archive_keys_test.go
  • cmd/retriever/archive_tar.go
  • cmd/retriever/archive_tar_test.go
  • cmd/retriever/bench.go
  • cmd/retriever/bench_test.go
  • cmd/retriever/compression.go
  • cmd/retriever/compression_test.go
  • cmd/retriever/config.go
  • cmd/retriever/config_test.go
  • cmd/retriever/database.go
  • cmd/retriever/database_test.go
  • cmd/retriever/defaults.toml
  • cmd/retriever/dump.go
  • cmd/retriever/dump_test.go
  • cmd/retriever/load.go
  • cmd/retriever/load_test.go
  • cmd/retriever/main.go
  • cmd/retriever/main_test.go
  • cmd/retriever/manifest.go
  • cmd/retriever/manifest_test.go
  • cmd/retriever/metrics.go
  • cmd/retriever/metrics_test.go
  • cmd/retriever/packaging_plan.md
  • cmd/retriever/progress.go
  • cmd/retriever/retriever_integration_test.go
  • cmd/retriever/scan.go
  • cmd/retriever/scan_test.go
  • cmd/retriever/scrubber.go
  • cmd/retriever/scrubber_test.go
  • cmd/retriever/types.go
  • cmd/retriever/verify.go
  • go.mod
  • query/model.go
  • query/neo4j/neo4j_test.go
✅ Files skipped from review due to trivial changes (2)
  • README.md
  • GOLANG_CODING_STANDARD.md
🚧 Files skipped from review as they are similar to previous changes (33)
  • cmd/benchdiff/compare_test.go
  • query/model.go
  • query/neo4j/neo4j_test.go
  • cmd/retriever/progress.go
  • cmd/retriever/archive_keys_test.go
  • cmd/retriever/dump_test.go
  • cmd/retriever/database.go
  • cmd/retriever/config_test.go
  • cmd/retriever/archive_tar_test.go
  • cmd/retriever/manifest.go
  • cmd/retriever/database_test.go
  • cmd/retriever/metrics_test.go
  • cmd/retriever/README.md
  • cmd/retriever/archive_tar.go
  • cmd/retriever/main_test.go
  • go.mod
  • cmd/retriever/verify.go
  • cmd/retriever/bench.go
  • cmd/retriever/compression_test.go
  • cmd/retriever/compression.go
  • cmd/retriever/manifest_test.go
  • cmd/retriever/types.go
  • cmd/retriever/main.go
  • cmd/retriever/archive_keys.go
  • cmd/retriever/metrics.go
  • cmd/retriever/defaults.toml
  • cmd/retriever/retriever_integration_test.go
  • cmd/retriever/config.go
  • cmd/retriever/dump.go
  • cmd/retriever/scrubber_test.go
  • cmd/retriever/load.go
  • cmd/retriever/scrubber.go
  • cmd/retriever/archive_envelope_test.go

Comment thread cmd/retriever/archive_envelope.go
Comment thread cmd/retriever/archive_envelope.go
@zinic zinic force-pushed the kpom/retriever-additions branch 2 times, most recently from 0574efb to 8ad1d4d Compare July 7, 2026 21:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
cmd/retriever/metrics_test.go (1)

286-289: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unused test helper.

buildFingerprintFixture is not referenced anywhere else in this file; only buildNamedFingerprintFixture is used by the actual tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/retriever/metrics_test.go` around lines 286 - 289, The test helper
buildFingerprintFixture is unused and should be removed from the test file. Keep
buildNamedFingerprintFixture as the shared fixture builder used by the tests,
and delete buildFingerprintFixture unless you find an actual test reference that
should be updated to call it instead.
🤖 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 `@cmd/retriever/bench.go`:
- Around line 200-284: The `workers` parameter in `benchNodes` and `benchEdges`
is only used by `logBenchPhaseProgress`, while `scanEntityBatches` still runs
the same sequential path. Update the batching/handling flow so `workers`
actually controls concurrent scanning or batch processing in the
`benchNodes`/`benchEdges` pipeline, or remove the option entirely if concurrency
is not intended. Use the existing `scanEntityBatches`, `benchNodeBatch`, and
`benchRelationshipBatch` symbols to wire the change in the right place.

---

Nitpick comments:
In `@cmd/retriever/metrics_test.go`:
- Around line 286-289: The test helper buildFingerprintFixture is unused and
should be removed from the test file. Keep buildNamedFingerprintFixture as the
shared fixture builder used by the tests, and delete buildFingerprintFixture
unless you find an actual test reference that should be updated to call it
instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1aa49e60-7ada-41e0-ad4b-8b44eac1ad92

📥 Commits

Reviewing files that changed from the base of the PR and between bde58b1 and 8ad1d4d.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (40)
  • GOLANG_CODING_STANDARD.md
  • README.md
  • cmd/retriever/README.md
  • cmd/retriever/archive_envelope.go
  • cmd/retriever/archive_envelope_test.go
  • cmd/retriever/archive_keys.go
  • cmd/retriever/archive_keys_test.go
  • cmd/retriever/archive_tar.go
  • cmd/retriever/archive_tar_test.go
  • cmd/retriever/bench.go
  • cmd/retriever/bench_test.go
  • cmd/retriever/compression.go
  • cmd/retriever/compression_test.go
  • cmd/retriever/config.go
  • cmd/retriever/config_test.go
  • cmd/retriever/database.go
  • cmd/retriever/database_test.go
  • cmd/retriever/defaults.toml
  • cmd/retriever/dump.go
  • cmd/retriever/dump_test.go
  • cmd/retriever/load.go
  • cmd/retriever/load_test.go
  • cmd/retriever/main.go
  • cmd/retriever/main_test.go
  • cmd/retriever/manifest.go
  • cmd/retriever/manifest_test.go
  • cmd/retriever/metrics.go
  • cmd/retriever/metrics_test.go
  • cmd/retriever/packaging_plan.md
  • cmd/retriever/progress.go
  • cmd/retriever/retriever_integration_test.go
  • cmd/retriever/scan.go
  • cmd/retriever/scan_test.go
  • cmd/retriever/scrubber.go
  • cmd/retriever/scrubber_test.go
  • cmd/retriever/types.go
  • cmd/retriever/verify.go
  • go.mod
  • query/model.go
  • query/neo4j/neo4j_test.go
✅ Files skipped from review due to trivial changes (3)
  • cmd/retriever/README.md
  • cmd/retriever/dump_test.go
  • GOLANG_CODING_STANDARD.md
🚧 Files skipped from review as they are similar to previous changes (28)
  • cmd/retriever/defaults.toml
  • query/model.go
  • cmd/retriever/scan.go
  • query/neo4j/neo4j_test.go
  • cmd/retriever/database.go
  • cmd/retriever/compression_test.go
  • cmd/retriever/scan_test.go
  • cmd/retriever/archive_keys_test.go
  • cmd/retriever/compression.go
  • cmd/retriever/manifest_test.go
  • cmd/retriever/main_test.go
  • cmd/retriever/main.go
  • cmd/retriever/verify.go
  • cmd/retriever/archive_tar.go
  • cmd/retriever/retriever_integration_test.go
  • cmd/retriever/types.go
  • cmd/retriever/archive_tar_test.go
  • cmd/retriever/manifest.go
  • cmd/retriever/archive_keys.go
  • cmd/retriever/dump.go
  • cmd/retriever/metrics.go
  • cmd/retriever/load.go
  • cmd/retriever/config_test.go
  • cmd/retriever/database_test.go
  • cmd/retriever/config.go
  • cmd/retriever/scrubber_test.go
  • go.mod
  • cmd/retriever/scrubber.go

Comment thread cmd/retriever/bench.go
@zinic zinic force-pushed the kpom/retriever-additions branch from 8ad1d4d to 473c2cc Compare July 7, 2026 22:16
@zinic zinic force-pushed the kpom/retriever-additions branch from 473c2cc to 080b7b7 Compare July 8, 2026 03:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@cmd/retriever/archive_envelope.go`:
- Around line 311-315: The cleanup in the archive promotion path should not turn
a successful unpack into a failure if removing the backup directory fails.
Update the backup removal logic in the promotion flow around
os.RemoveAll(backupDir) to log a warning instead of returning an error after the
rename has already succeeded, so unpackEncryptedCollectionArchive still reports
success while preserving visibility into cleanup issues.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b50bea76-ee87-48dc-a484-0fc36c150af9

📥 Commits

Reviewing files that changed from the base of the PR and between 8ad1d4d and 080b7b7.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (40)
  • GOLANG_CODING_STANDARD.md
  • README.md
  • cmd/retriever/README.md
  • cmd/retriever/archive_envelope.go
  • cmd/retriever/archive_envelope_test.go
  • cmd/retriever/archive_keys.go
  • cmd/retriever/archive_keys_test.go
  • cmd/retriever/archive_tar.go
  • cmd/retriever/archive_tar_test.go
  • cmd/retriever/bench.go
  • cmd/retriever/bench_test.go
  • cmd/retriever/compression.go
  • cmd/retriever/compression_test.go
  • cmd/retriever/config.go
  • cmd/retriever/config_test.go
  • cmd/retriever/database.go
  • cmd/retriever/database_test.go
  • cmd/retriever/defaults.toml
  • cmd/retriever/dump.go
  • cmd/retriever/dump_test.go
  • cmd/retriever/load.go
  • cmd/retriever/load_test.go
  • cmd/retriever/main.go
  • cmd/retriever/main_test.go
  • cmd/retriever/manifest.go
  • cmd/retriever/manifest_test.go
  • cmd/retriever/metrics.go
  • cmd/retriever/metrics_test.go
  • cmd/retriever/packaging_plan.md
  • cmd/retriever/progress.go
  • cmd/retriever/retriever_integration_test.go
  • cmd/retriever/scan.go
  • cmd/retriever/scan_test.go
  • cmd/retriever/scrubber.go
  • cmd/retriever/scrubber_test.go
  • cmd/retriever/types.go
  • cmd/retriever/verify.go
  • go.mod
  • query/model.go
  • query/neo4j/neo4j_test.go
✅ Files skipped from review due to trivial changes (3)
  • GOLANG_CODING_STANDARD.md
  • README.md
  • cmd/retriever/README.md
🚧 Files skipped from review as they are similar to previous changes (32)
  • query/model.go
  • cmd/retriever/dump_test.go
  • cmd/retriever/compression_test.go
  • cmd/retriever/archive_keys_test.go
  • cmd/retriever/scan_test.go
  • cmd/retriever/manifest.go
  • query/neo4j/neo4j_test.go
  • cmd/retriever/progress.go
  • cmd/retriever/verify.go
  • cmd/retriever/database_test.go
  • cmd/retriever/main_test.go
  • cmd/retriever/config_test.go
  • cmd/retriever/database.go
  • cmd/retriever/archive_tar_test.go
  • cmd/retriever/defaults.toml
  • cmd/retriever/manifest_test.go
  • cmd/retriever/scrubber_test.go
  • cmd/retriever/types.go
  • cmd/retriever/scan.go
  • cmd/retriever/load_test.go
  • cmd/retriever/bench.go
  • cmd/retriever/retriever_integration_test.go
  • cmd/retriever/metrics.go
  • cmd/retriever/metrics_test.go
  • cmd/retriever/main.go
  • cmd/retriever/archive_keys.go
  • cmd/retriever/compression.go
  • cmd/retriever/archive_tar.go
  • cmd/retriever/scrubber.go
  • cmd/retriever/load.go
  • cmd/retriever/archive_envelope_test.go
  • go.mod

Comment on lines +311 to +315
if backupDir != "" {
if err := os.RemoveAll(backupDir); err != nil {
return fmt.Errorf("remove output directory backup: %w", err)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Don't return an error after the promotion has already succeeded.

If os.RemoveAll(backupDir) fails at this point, the staging directory has already been renamed to outputDir — the unpack operation succeeded. Returning an error here misleads the caller into thinking the operation failed, and the deferred os.RemoveAll(stagingDir) in unpackEncryptedCollectionArchive becomes a no-op (the path no longer exists). The backup directory is leaked but the data is correct.

Log a warning instead of propagating a fatal error.

🔧 Proposed fix: warn instead of error on backup cleanup failure
 	if backupDir != "" {
-		if err := os.RemoveAll(backupDir); err != nil {
-			return fmt.Errorf("remove output directory backup: %w", err)
-		}
+		if err := os.RemoveAll(backupDir); err != nil {
+			slog.Warn("retriever archive backup cleanup failed",
+				slog.String("backup_dir", backupDir),
+				slog.String("error", err.Error()),
+			)
+		}
 	}
 	return nil
📝 Committable suggestion

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

Suggested change
if backupDir != "" {
if err := os.RemoveAll(backupDir); err != nil {
return fmt.Errorf("remove output directory backup: %w", err)
}
}
if backupDir != "" {
if err := os.RemoveAll(backupDir); err != nil {
slog.Warn("retriever archive backup cleanup failed",
slog.String("backup_dir", backupDir),
slog.String("error", err.Error()),
)
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/retriever/archive_envelope.go` around lines 311 - 315, The cleanup in the
archive promotion path should not turn a successful unpack into a failure if
removing the backup directory fails. Update the backup removal logic in the
promotion flow around os.RemoveAll(backupDir) to log a warning instead of
returning an error after the rename has already succeeded, so
unpackEncryptedCollectionArchive still reports success while preserving
visibility into cleanup issues.

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