Skip to content

ps-grpc-01-surface: gRPC PlateSolver service surface#84

Merged
bryantharpe merged 3 commits into
mainfrom
polecat/furiosa/ps-grpc-01-surface@mrvcbyaz
Jul 22, 2026
Merged

ps-grpc-01-surface: gRPC PlateSolver service surface#84
bryantharpe merged 3 commits into
mainfrom
polecat/furiosa/ps-grpc-01-surface@mrvcbyaz

Conversation

@bryantharpe

Copy link
Copy Markdown
Owner

Implements the public gRPC surface for the plate solver with four RPCs, coordinate swap, shared-memory stub, and acceptance tests.\n\n🤖 Generated with Claude Code

…te swap, and acceptance tests

Implements the public gRPC surface for the plate solver:
- PlateSolver service with ExtractCentroids, SolveFromCentroids, SolveFromImage, and GetInfo.
- Protobuf messages matching cedar-detect Image/ImageCoord shapes and the project Solution contract.
- Coordinate swap between wire (x,y) and solver (y,x) at the service boundary.
- Shared-memory fast path stub returning INTERNAL to trigger inline fallback.
- Detection parameters forwarded to star-detection; solve params forwarded to plate-solver.
- Acceptance tests using an in-memory duplex channel client.

Fixes during bring-up:
- Synthetic test images now use isolated bright pixels on a non-zero background so the detector's strict 1-D peak gate fires.
-  now reports  in degrees on timeout/failure paths (it is already degrees from ) while still converting radians to degrees on the success path.

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

Copy link
Copy Markdown
Owner Author

review/judge — DISSENT on 4600814fc723

VERDICT: DISSENT
BLOCKING: crates/grpc-service/src/server.rs:~265-275 — to_proto_solution FOV unit heuristic (if f > PI { f } else { f.to_degrees() }) is incorrect for small FOVs (< ~3.14°) on failure/timeout paths where fov_used is already in degrees; a 2° FOV would be misreported as ~114.6°, breaking the gRPC surface contract for a core telescope use case.
NITS: crates/grpc-service/src/server.rs:~289 — binned_image branch is redundant (if params.return_binned { None } else { None }); simplify to None with a comment.
NITS: crates/grpc-service/src/server.rs:~155,~195 — hardcoded 0.002 magic number passed to solver without explanation.
NITS: crates/grpc-service/src/server.rs:~310 — mag: 0.0 hardcoded for all matched stars; document why magnitude is unavailable.
NITS: crates/grpc-service/src/server.rs:~155,~195 — (*self.db).clone() clones the entire pattern database on every request; expensive but functionally correct.
NITS: crates/grpc-service/proto/cedar_detect.proto — vendored reference proto included but not compiled by build.rs; consider moving to a reference/ directory to avoid confusion.


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 84 "<reason>".

@bryantharpe bryantharpe added the hold:human operator hold: automation must not review, merge, undraft or escalate this PR label Jul 22, 2026
bryantharpe and others added 2 commits July 22, 2026 02:44
…mings, model unset attitude

Follow-up on the service surface, correcting defects found while verifying the
implementation against the spec's acceptance scenarios.

Solution FOV was reported in the wrong unit for narrow-field databases.
`Solution.fov_used` carries two different units depending on which path produced
it: the success path in `refine` copies `PinholeCamera.fov` (radians), while
every failure path copies `ctx.fov_initial`, which derives from the database FOV
bounds (degrees). The previous conversion guessed the unit by magnitude —
"greater than pi must already be degrees". A radian FOV never exceeds pi, so
that test only ever misfires on the failure path, where it silently
double-converts any database narrower than 3.14 degrees: a 2.5 degree FOV was
reported as 143.2. Discriminate on `camera` instead, which is set by exactly the
one site that writes radians. Covered by a regression test that fails against
the old heuristic with the 143.2 value.

`t_extract_ms` and `t_solve_ms` were hardcoded to 0.0 despite the spec requiring
the Solution carry them. SolveFromCentroids now reports a measured solve time.
SolveFromImage reports its measured total under `t_solve_ms`: the core
`solve_from_image` fuses detection and solving into one call, so the two cannot
be timed apart without duplicating detection, and ps-grpc-02 owns that RPC's
detection path. Reporting the honest total beats inventing a split.

The spec calls for unset attitude fields on failure, which a plain proto3 double
cannot express — 0.0 is a legitimate ra/dec/roll, so a failed solve was
indistinguishable from a real solve on the celestial origin. The attitude and
quality fields are now `optional`, matching the core solution's own `Option`
modelling.

`MATCH_FOUND = 0` meant a default-constructed or absent Solution decoded as a
successful match. Added `SOLVE_STATUS_UNSPECIFIED = 0` and renumbered, keeping
the five statuses the spec names.

Also drops an if/else whose branches both yielded None.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…og data, address review nits

cargo-machete flagged `prost` and `tonic-prost` as unused. Verified empirically
by removing each and rebuilding: both are load-bearing. The code generated by
`tonic-prost-build` into OUT_DIR emits `prost::` paths, `#[prost(..)]`
attributes and `tonic_prost::` codecs, which machete cannot see because it scans
hand-written source only. Kept both and declared them in
[package.metadata.cargo-machete] with the reason.

Matched-star data was wrong in two ways, not just the flagged `mag: 0.0`.
`Solution::matched_catalog_ids` holds database star-table INDICES — verification
feeds them straight to `db.star_vector(StarId(..))` — so emitting them as
`cat_id` leaked an internal index onto the wire as though it were a catalog
identifier. Both magnitude and the real identifier are recoverable from the
database, so `to_proto_solution` now takes it and resolves them. Magnitude comes
from the star table and is optional, since a database need not carry an entry.
BSC and Hipparcos IDs are single numbers; Tycho is a (TYC1, TYC2, TYC3) triple
that cannot be flattened into one integer without inventing an encoding, so a
`cat_id_str` field carries the canonical rendering for every catalog and
`cat_id` is left unset for Tycho.

Remaining review nits:
- The `0.002` passed to the solver is now MATCH_MAX_ERROR, documented as the
  spec default and as deliberately not client-facing: it describes how the
  database was built, not a per-request knob.
- `(*self.db).clone()` clones the whole pattern database per request. Left in
  place with a comment: the solver takes the database by value, so removing the
  clone means changing `plate_solver::solve_*` to accept a reference, which is
  ps-plate-04's API rather than this boundary's.
- Removed crates/grpc-service/proto/cedar_detect.proto. It was never compiled by
  build.rs and never imported, and was byte-identical to proto/cedar_detect.proto
  which ps-plate-04 already put at the repo root. A third uncompiled copy inside
  the crate's proto directory invites edits that silently do not affect the wire
  format.
- The redundant `if return_binned { None } else { None }` was already collapsed
  in 51bccf7.

Tests: matched-star resolution (magnitude, real Hipparcos number rather than the
index, and the coordinate swap on matched centroids), Tycho string-only form,
and suppression when return_matches is false.

Verified by hand: cargo fmt --all --check, cargo clippy --locked --all-targets
-- -D warnings, cargo test --locked, cargo machete all clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@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 22, 2026
@bryantharpe

Copy link
Copy Markdown
Owner Author

review/judge — APPROVE on 08215fec0ec1

VERDICT: APPROVE
BLOCKING: NONE
NITS: crates/grpc-service/proto/plate_solver.proto:55-61 — enum values MATCH_FOUND, NO_MATCH, etc. lack the SOLVE_STATUS_ prefix recommended by proto3 style guides; only the zero value is prefixed. Not blocking for Rust/prost but may cause collisions in other language bindings.
NITS: Cargo.toml:12-14 — removing [workspace.dependencies] for math-core and star-detection is safe today (grpc-service uses direct path refs and Cargo.lock regenerated), but future crates that expect .workspace = true shorthand will fail silently; consider keeping them or documenting the removal.
NITS: crates/grpc-service/src/server.rs:86 — peak_star_pixel: 0 is an undocumented stub unlike the adjacent hot_pixel_count which is explicitly marked as ps-grpc-02's responsibility; a one-line comment would keep the two stubs consistent.


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 84 "<reason>".

@bryantharpe
bryantharpe merged commit ec095e5 into main Jul 22, 2026
24 of 37 checks passed
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