Repository navigation
fix(backend): review-page links, packet still paths, C2 join agreement, and hydrated reads/scale - #255
Conversation
- compose: hydrate reads/scale from work_dir when the short input keys are absent, and sign review-page photo and artifact links against the promoted capture/run prefixes so the review page renders from storage - reads: resolve packet still paths against the promoted captures/ prefix before reading; uploads expire after promotion - criteria: the C2 join with zero matched positions now reports positions_compared and agreement_with_c1=null instead of claiming perfect agreement Co-Authored-By: Obvious Fusion <noreply@obvious.ai>
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
Review: fixes verified; one real limitation, two nitsAll four fixes are mechanically correct and the regression tests are real. Full suite is green apart from the 5 failures the body names, which I reproduced identically on baseline What I ran
The 5: Count nit: the body's "196 passed, 1 skipped" doesn't reproduce. My rerun of the three touched suites gives 240 passed, 1 skipped (57 result + 67 reads + 116 criteria + 1 skip) — likely the body counted a C3-off criteria run. Green either way. Claim checks
Findings
Both non-blocking. Nice catch on |
|
Independent review (Obvious, Autobuild + Max) Verdict: ready (draft → ready for review). I found no blocking defect. Three non-blocking findings below, plus one inaccuracy in the body's test counts. I did not write this PR; I verified every claim below by running the code myself at head Findings (ranked)
Claim checks (evidence)
What I ran (all on head
|
| Check | Command | Result |
|---|---|---|
| Touched suites | uv run --frozen --extra api pytest server/result/tests server/reads/tests server/criteria/tests -q |
240 passed, 1 skipped (91.9s) |
| 4 new regression tests @ head | pytest node IDs | 4 passed (0.83s) |
| Same tests, fix reverted | git checkout 57f57ff8 -- server/criteria/c2/veto.py server/criteria/run.py server/reads/aggregate.py server/result/compose.py, then same node IDs |
5 failed (1.03s) — the 4 new tests plus the modified test_packet_uses_img_and_file_digest all fail on pre-fix source; tree restored clean after |
| Lint | ruff check . · ruff format --check . · lint-imports |
All green; 459 files formatted; 5 contracts kept, 0 broken |
| Full suite @ head | uv run --frozen --extra api pytest -q |
5 failed, 1207 passed, 17 skipped (270.7s) |
Full suite @ base 57f57ff8 |
same | 5 failed, 1203 passed, 17 skipped (284.5s) — identical failure set: tests/test_ssr_overlap_check.py::test_repo_has_no_ssr_shingle_overlap + 4 server/eval/tests/test_gates.py nodes. Pre-existing, exactly as the body claims; head is base plus 4 passing regression tests |
One body inaccuracy: "Touched suites green: 196 passed, 1 skipped" does not reproduce — the three touched suites give 240 passed, 1 skipped. Green either way; the 196 likely counts a C3-off criteria run.
What I could not verify
- Live GCS/R2 signed-URL behavior — verified through the code path and a signing storage double only; no cloud credentials here.
- Anything the local full-suite runs don't cover (real device packets, Modal workers).
- CI: this PR has no backend test workflow signal (label bot + skipped CodeRabbit only) — the known repo-wide gap that
server/CI doesn't coverbackend/.
Scoped backend/server/result/compose.py and test_compose.py changes from #255 (producer head 6cb76b1, applied three-way onto merge-base 2d0911f of obv/burst7-bs-capture-placement-runner). The composer falls back to the hydrated work_dir/reads and work_dir/scale copies when short input keys are absent, and receives storage/settings to sign reviewer verdict links. Co-Authored-By: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
|
Note Review skipped Codemetrics is installed on this repository, but it hasn't been added to your team yet. To enable AI code reviews for this repo, go to your dashboard and add BaseScanning to your team's repositories. |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
[Medium impact] Fixes data structure and file path handling in criteria and results. Fix the two remaining review-page failures before merging.
|
| ttl = getattr(settings, "HSS_INGEST_RESULT_URL_TTL_S", 900) | ||
| try: | ||
| return str(sign(key, int(ttl) if ttl else 900)) |
There was a problem hiding this comment.
The signed URLs expire after the result stage creates review.html, not after a reviewer opens it. The default lifetime is 900 seconds, and get_review returns the saved HTML unchanged. Reviewers opening the page later get expired photo and raw-file links, even after reloading. Sign the URLs when serving the page, or use stable authenticated download routes.
Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/server/result/compose.py
Line: 819-821
Comment:
**Saved review links expire**
The signed URLs expire after the result stage creates `review.html`, not after a reviewer opens it. The default lifetime is 900 seconds, and `get_review` returns the saved HTML unchanged. Reviewers opening the page later get expired photo and raw-file links, even after reloading. Sign the URLs when serving the page, or use stable authenticated download routes.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| image = kf.get("image") | ||
| url = None | ||
| if image: | ||
| photo_key = f"captures/{capture.capture_id}/{image}" | ||
| if storage is not None and getattr(storage, "exists", lambda _k: False)(photo_key): | ||
| url = _signed_url(storage, settings, photo_key) |
There was a problem hiding this comment.
The photo fix skips production keyframes. _retarget_keyframes creates them without an image field, and the scene stage saves them without adding one. Signing is therefore skipped, and the page still uses the bare kf["id"] as its photo URL. Carry the packet image path into the scene, or resolve it from the packet before signing. Add a test using the production keyframe shape.
Prompt To Fix With AI
This is a comment left during a code review.
Path: backend/server/result/compose.py
Line: 860-865
Comment:
**Production photos stay broken**
The photo fix skips production keyframes. `_retarget_keyframes` creates them without an `image` field, and the scene stage saves them without adding one. Signing is therefore skipped, and the page still uses the bare `kf["id"]` as its photo URL. Carry the packet image path into the scene, or resolve it from the packet before signing. Add a test using the production keyframe shape.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Summary
Addresses four Greptile review findings on PR #247, each with a regression test that fails without the fix:
server/result/compose.py) —review.htmlis served under/v1/captures/{id}/review, so its relativehrefs to verdicts andresult.json404, and photo paths point at expireduploads/keys. Now photos resolve to the promotedcaptures/{capture_id}/...key and get signed URLs when storage is available; raw artifact links are signed under the capture/run prefix, falling back to bare names offline.server/reads/aggregate.py) —build_readspassed packet-relative paths (s1.jpg) straight to storage, but promotion stores files undercaptures/{capture_id}/...and uploads expire. Paths are now resolved against the promoted prefix beforeread_still.server/criteria/c2/veto.py) — with zero matched positions the join reportedagreement_with_c1=1.0(perfect agreement with no evidence). It now reportspositions_comparedandagreement_with_c1=nullwhen nothing matched, threaded through the criteria report.server/result/compose.py) —compose.run()only read the short input keys (reads/scale), but the orchestrator hydratesreads/reads.jsonandscale/scale.jsonunderwork_dir. A fallback now resolves the hydrated paths, so meter auto-fill and scale attribution stop being dropped.Testing
test_review_page_signs_photos_and_raw_links,test_run_resolves_reads_and_scale_from_work_dir,test_build_reads_resolves_packet_paths_against_promoted_files,test_join_without_matches_reports_no_comparison— all four fail on the pre-fix source and pass with it.result,reads,criteria).make lintgreen (ruff check, ruff format, lint-imports).Handoff
feat/port-house-scanning-server; branchobv/burst4-20261015-bs-backend-results, commit6cb76b17, author Sam Gu.