Skip to content

ps-plate-03-verify: implement authoritative verification stage#80

Merged
bryantharpe merged 2 commits into
mainfrom
ps-plate-03-verify
Jul 21, 2026
Merged

ps-plate-03-verify: implement authoritative verification stage#80
bryantharpe merged 2 commits into
mainfrom
ps-plate-03-verify

Conversation

@bryantharpe

Copy link
Copy Markdown
Owner

Implements the verification stage of the plate solver per openspec/specs/plate-solver/spec.md §Verification.

  • Attitude: centroid-distance correspondence, coarse FOV from largest-edge ratio, SVD attitude solve, reflection rejection.
  • Projection/match: diagonal-FOV catalog gather, derotate/project, in-frame trim, brightest 2·n_centroids cap, unique 1:1 matching within match_radius·width.
  • False-alarm acceptance: binomial CDF test with Bonferroni correction; first accepted candidate wins.

Reuses math-core attitude/binomial/fov/pattern helpers and pattern-database nearby_stars query.

🤖 Generated with Claude Code

Implement the verification pipeline in crates/plate-solver/src/verify.rs:
- Attitude: pair 4 image and 4 catalog pattern stars by centroid-distance order,
  estimate coarse FOV from largest-edge ratio, solve SVD attitude, reject
  reflections (det(R) < 0).
- Projection and match: gather catalog stars within diagonal-FOV radius of the
  boresight (R row 0), derotate and project to pixels, keep in-frame, trim to
  brightest 2*n_centroids, and match 1:1 within match_radius*width.
- False-alarm acceptance: run the binomial test; accept the first candidate whose
  probability is below the Bonferroni-corrected threshold.

Wire the new verify module through lib.rs, candidates::verify_candidate, and
solve::iterate_patterns (passing centroids and image dimensions).

Co-Authored-By: Claude <noreply@anthropic.com>
@bryantharpe bryantharpe added the integrity:graded authoring-integrity: transcript scanned, no recovery reconnaissance label Jul 21, 2026
@bryantharpe

Copy link
Copy Markdown
Owner Author

review/judge — APPROVE on 65ebe2edf119

VERDICT: APPROVE
BLOCKING: NONE
NITS: verify.rs:103 — .expect("valid star index") on db.star_vector is a panic vector in a hot loop; consider propagating an error or filtering invalid indices upstream.
NITS: verify.rs:131 — comment says "brightness order is index order" but this depends on nearby_stars returning results sorted by brightness; if that contract is not guaranteed, the "brightest 2·n_centroids" cap may not select the actual brightest stars.
NITS: verify.rs — no unit tests for match_projected_to_centroids or largest_pixel_edge; both are pure functions that would be straightforward to test in isolation.
NITS: verify.rs:58 — reflection rejection is documented as part of this stage but the code delegates entirely to solve_attitude returning None; a brief comment noting that solve_attitude handles det(R) < 0 internally would make the delegation explicit.


Independent U3 review by the judge role (glm-5.2, Zhipu — different lineage
than every author seat). Verdict is on blocking findings, not a score. To
supersede with human sign-off (U4): judge-pr.sh override 80 "<reason>".

@bryantharpe
bryantharpe enabled auto-merge (squash) July 21, 2026 00:20
@bryantharpe bryantharpe added the hold:human operator hold: automation must not review, merge, undraft or escalate this PR label Jul 21, 2026
@bryantharpe
bryantharpe disabled auto-merge July 21, 2026 02:17
Mechanical rustfmt-only fix for PR #80 (ps-plate-03-verify). CI's required
rustfmt check (cargo fmt --all --check) failed on head 65ebe2e; this reflows
call arguments in candidates.rs and verify.rs. No logic change --
cargo check --all --locked passes.

Provenance note: applied by an operator-directed agent, not by the authoring
polecat. slit's session was dead and its worktree git linkage was severed, so
it could not push its own fix. The authored content of this PR is unchanged and
remains slit's (review/judge=SUCCESS on 65ebe2e).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014YmME89aAzhaDdS65KVMBK
@bryantharpe bryantharpe added integrity:cleared OPERATOR ONLY: a human ruled this authoring-integrity finding acceptable and removed hold:human operator hold: automation must not review, merge, undraft or escalate this PR labels Jul 21, 2026
@bryantharpe

Copy link
Copy Markdown
Owner Author

review/judge — APPROVE on b025923d2477

VERDICT: APPROVE
BLOCKING: NONE
NITS: verify.rs:62 — db.star_vector(...).expect("valid star index") and verify.rs:80 — .expect("valid star index") use panicking expects on database lookups in the hot solve path; consider returning MatchResult::Rejected on None for robustness against malformed candidates.
NITS: verify.rs — no unit tests for the new module; coverage gate will assess, but dedicated tests for match_projected_to_centroids and largest_pixel_edge would strengthen confidence.
NITS: verify.rs:55 — reflection rejection relies entirely on solve_attitude returning None; an explicit det(R) < 0 guard would make the spec-mandated rejection self-evident in this module rather than implicit in math-core.


Independent U3 review by the judge role (glm-5.2, Zhipu — different lineage
than every author seat). Verdict is on blocking findings, not a score. To
supersede with human sign-off (U4): judge-pr.sh override 80 "<reason>".

@bryantharpe
bryantharpe merged commit 370f094 into main Jul 21, 2026
24 of 37 checks passed
@bryantharpe

Copy link
Copy Markdown
Owner Author

review/judge — APPROVE on b025923d2477

VERDICT: APPROVE
BLOCKING: NONE
NITS: verify.rs has no unit tests for the new verification pipeline (match_projected_to_centroids, largest_pixel_edge, ordered_pattern_pair are all testable in isolation)
NITS: verify.rs:33 doc claims "Reflections (det(R) < 0) are rejected" as a step in this module, but the rejection is implicit in solve_attitude returning None or producing only proper rotations — an explicit det(R) check or a doc clarification would prevent reader confusion
NITS: verify.rs:96 comment "brightness order is index order" assumes nearby_stars returns stars sorted by brightness; this invariant is load-bearing for the "brightest 2·n_centroids" trim but is not asserted or documented at the nearby_stars API boundary
NITS: verify.rs:53 candidate.edges[5] is assumed to be the largest sorted edge — the assumption is stated in a comment but not validated; a wrong edge ordering would silently produce an incorrect FOV estimate


Independent U3 review by the judge role (glm-5.2, Zhipu — different lineage
than every author seat). Verdict is on blocking findings, not a score. To
supersede with human sign-off (U4): judge-pr.sh override 80 "<reason>".

bryantharpe added a commit that referenced this pull request Jul 21, 2026
CI repair on an already-submitted PR. The authoring polecat (furiosa) had
already run `gt done` and exited, so no seat remained to own the red checks
(ps-ops-17-fmt-pre-done-gate, second occurrence after PR #80).

Changes are deliberately minimal — the authoring design is left intact for
the judge to review:

- `cargo fmt --all` over refine.rs, solve.rs, verify.rs (whitespace only).
- verify.rs: replace a `match ... { Some(r) => r, None => return None }`
  with `?` (clippy::question_mark). Semantically identical.
- verify.rs: `#[allow(clippy::too_many_arguments)]` and
  `#[allow(clippy::type_complexity)]` on `match_projected_to_centroids`,
  matching existing precedent in solve.rs and preparation.rs rather than
  redesigning the function signature pre-review.

Verified locally: `cargo fmt --all --check` clean, `cargo clippy --workspace
--all-targets --all-features --locked -- -D warnings` clean, 137 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qz1AHuSpjFqRYJWVVVq9mp
bryantharpe added a commit that referenced this pull request Jul 21, 2026
…nement, residuals, and solution outputs (#82)

* ps-plate-04-refine: scaffold refine module with signatures and helpers

* ps-plate-04-refine: wire real refine module into lib.rs

* ps-plate-04-refine: implement attitude re-fit, RA/Dec/Roll, FOV/distortion refinement, residuals, and solution outputs

* ps-plate-04-refine: fix rustfmt drift and three clippy lints

CI repair on an already-submitted PR. The authoring polecat (furiosa) had
already run `gt done` and exited, so no seat remained to own the red checks
(ps-ops-17-fmt-pre-done-gate, second occurrence after PR #80).

Changes are deliberately minimal — the authoring design is left intact for
the judge to review:

- `cargo fmt --all` over refine.rs, solve.rs, verify.rs (whitespace only).
- verify.rs: replace a `match ... { Some(r) => r, None => return None }`
  with `?` (clippy::question_mark). Semantically identical.
- verify.rs: `#[allow(clippy::too_many_arguments)]` and
  `#[allow(clippy::type_complexity)]` on `match_projected_to_centroids`,
  matching existing precedent in solve.rs and preparation.rs rather than
  redesigning the function signature pre-review.

Verified locally: `cargo fmt --all --check` clean, `cargo clippy --workspace
--all-targets --all-features --locked -- -D warnings` clean, 137 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qz1AHuSpjFqRYJWVVVq9mp

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integrity:cleared OPERATOR ONLY: a human ruled this authoring-integrity finding acceptable integrity:graded authoring-integrity: transcript scanned, no recovery reconnaissance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant