{
 "for": "agents integrating geo.qa perception into their own pipeline",
 "endpoints": {
  "POST /produce/measure": {
   "does": "measure produce in a photograph against a marketing standard",
   "needs": "image_base64 (or image_url); mm_per_px + scale_basis for metric",
   "returns": "length along the convex face, grade at the mid-point, colour stage, blemish fraction, slenderness, and the accuracy of each",
   "refuses": "millimetres without a scale anchor, and a scale without a stated origin",
   "standard": "Commission Delegated Reg. (EU) 2023/2429 Annex I Part B Part 11",
   "measured_on": "with the card in frame the photograph is RECTIFIED onto the card's plane before anything is measured, so one pixel is one distance in every direction. A local scale alone fixes magnitude and not anisotropy: measured, the image-plane length ran +2.6% at 5 degrees of camera tilt and +23% at 25, against 0.2%-1.4% on the plane",
   "scale": "print GET /produce/card.png, lay it flat beside the fruit, and send the photo with no mm_per_px: the scale is then MEASURED from four markers at a printed spacing rather than typed. Recovered within 0.54% across size, rotation, blur, JPEG and noise, and within 2.85% across tilt to 26 degrees. Two bands, not one: perspective foreshortens the card and no single band covers a flat photograph and a 26-degree one -- and taken at the fruit's own position, because the card's is 45.8% out at 32 degrees",
   "identity": "every reply carries `model` -- id, version and a content hash computed over the measuring code and the opencv and numpy versions it ran against, so a re-run a year from now can say which code measured",
   "self_agreement": "every reply measures the fruit six ways -- three rotations by two saturation floors, neither of which changes the true length -- and reports how far the answers sit apart. NOT an error bar: it understates the true error five to tenfold on an easy photograph, because agreement measures variance and the residual error is bias. It is a hardness detector, and a sharp one: 0.18% on a clean shot against 17% on a noisy one. Over 2%, or fewer than 4 of 6 variants measurable, sets send_to_a_person",
   "receipt": "every reply carries an ed25519 receipt binding the image bytes, the numbers returned and that model hash, plus emem's signed log head as a time bound. `verify` in the same reply is the five-step offline recipe; none of steps 1-4 asks this host whether the answer is yes"
  },
  "POST /redact/people": {
   "does": "mosaic every person in a photograph before it is stored",
   "needs": "image_base64; optional floor (default 0.05)",
   "returns": "the redacted image, what was redacted, what sat near the floor, and whether the floor was actually reached",
   "refuses": "to call the result safe. It is a COCO person detector, not an anonymiser: it does not see a face in a mirror, a name on a shirt, or a hand holding an identity document",
   "mosaic_not_blur": "a Gaussian is invertible enough that published attacks recover faces; measured here, a 41-pixel blur still correlates 0.977 with what it replaced and the mosaic 0.05",
   "better": "run geoqa_platform/people_redact.py in your own region. Calling this sends the photograph across a border"
  },
  "POST /stack/count": {
   "does": "count the crate faces in a stack photograph",
   "needs": "image_base64",
   "returns": "the count per axis, the pitch it measured, and when it abstains, which of the three reasons",
   "refuses": "to count a load with no lattice, a stack with a row part out of frame, or a photograph taken at an angle -- the last one comes back as retake: square_on",
   "counts_a_face": "not a load. What is behind the front layer is not in the photograph",
   "measured": "160 SYNTHETIC stacks at four angles and 40 jumbled loads: never a wrong count, never a count on a jumble. Generated here, so it scores the method against our own idea of a lattice; no real stack photograph has been scored. The three negatives ARE real photographs and all abstain"
  },
  "POST /ppe/spraying": {
   "does": "read a spray photograph for respirator, gloves and coverall, keeping no face -- ppe_spraying@1, eudr#172",
   "needs": "image_base64",
   "returns": "each of the three as present / absent / not_visible, with the reason whenever it is not_visible; a signed receipt over the image bytes and the verdicts",
   "every_verdict_is_not_visible_today": "on purpose. There is no calibrated bare-skin band yet and the signal contract says never a guessed value. Run scripts/calibrate_ppe.py over a few dozen ordinary photographs of people at this scale and the band is measured, written in with its n, and the verdicts turn on",
   "what_already_works": "refusing a photograph that cannot answer -- no person, a person under 100 px, no visible eyes -- each with its own reason, so it can never be filed as a pass",
   "no_face_kept": "the forehead is read for its colour inside the call and discarded with the frame. The reply carries distances, verdicts and counts: no crop, colour, coordinate or box, and the image is stored nowhere",
   "measured_against_the_person_themselves": "every distance is from THIS subject's own face in THIS light, so the check does not depend on skin tone. A threshold fitted to one skin reports false violations against another, and a false violation is a person accused"
  },
  "POST /prescreen": {
   "does": "rank candidate farms from their pins, before anyone drives out",
   "needs": "pins[] with lat and lng; optional weights",
   "returns": "the pins worth visiting in order, the ones disqualified by a post-cut-off loss year removed from the ranking rather than scored low, and what could not be read at each",
   "refuses": "a readiness window -- that needs a season of NDVI the shared memory does not hold at an unseeded cell -- and a value range, which is your schedule against your market",
   "a_pin_is_not_a_plot": "it screens which pins are worth a visit; it is not a Due Diligence Statement"
  },
  "POST /water/distance": {
   "does": "find the nearest recurring surface water, for a spray buffer",
   "needs": "lat, lng; optional radii_m and bearings",
   "returns": "a distance BRACKET and the bearing, plus every ring it read",
   "refuses": "a single metre. The rings are sampled, so water lies between two radii and saying 412 m would be precision invented out of a sampling grid",
   "not_a_watercourse_test": "JRC recurrence is how often water RETURNS between years. A ditch that was dry when the satellite passed scores zero and is still a watercourse"
  },
  "POST /crop/agree": {
   "does": "check whether a photograph could be of the field it claims",
   "needs": "image_base64, lat, lng; taken_at strongly recommended",
   "returns": "consistent / disagrees / cannot_say, with the reason, and needs_a_person on a disagreement",
   "refuses": "to compare the colour stage against a vegetation curve. That needs a season of NDVI the shared memory does not hold at an unseeded cell, and a curve fitted to one point would be the failure this check exists to catch",
   "compares": "categories, not stages \u2014 could this photograph be of this cell at all"
  },
  "POST /decide": {
   "does": "rank candidates on typed features, renormalising over what is known",
   "needs": "candidates[].features{value,known}, weights{}",
   "returns": "ranking, per-feature contributions, margin, decisive, and what was unmeasured",
   "refuses": "pricing a feature nobody measured"
  },
  "GET /produce/card.png": {
   "does": "the printable scale card \u2014 print at 100%, lay it flat beside the fruit, and send the photo with no mm_per_px",
   "needs": "nothing. `?dpi=` to match a printer",
   "returns": "a PNG. The marker spacing is printed ON the card so it can be checked against a ruler before a season of measurements is taken with it",
   "why": "a typed mm_per_px is the one load-bearing number in every millimetre and the one no later reader can check. This makes it measured: within 1% across size, rotation, blur, JPEG and noise"
  },
  "GET /produce/selftest": {
   "does": "score the measurement against geometry whose answer is exact, live, and return every case",
   "needs": "nothing",
   "returns": "per-sweep measured vs true, the band those errors span, the published band they are checked against, and the recipe to rebuild the fixture yourself",
   "why": "our accuracy claim, asserted against our running code rather than against a number in a comment"
  }
 },
 "gate_your_deploy_on_ours": {
  "url": "GET /probes",
  "filter": "?only=<substring> for just the checks you depend on",
  "fail_on": "counts.fails > 0, and on `stale`",
  "do_not_fail_on": "counts.undetermined \u2014 that means a check did not run, which is a different fact from a claim being broken"
 },
 "run_it_yourself": {
  "index": "GET /partner/dist",
  "why": "calling these endpoints sends the photograph across a border. The same code runs as a package where the photograph already is, and the wheel and the exported detector are downloadable with their hashes so you can pin both"
 },
 "neither": "decides. Both measure or rank; the thresholds and the policy are yours"
}