feat(perception): freeze blind detector gates

This commit is contained in:
DCCONSTRUCTIONS
2026-07-29 14:20:31 +03:00
parent 8b1f109b09
commit 82a44478fb
14 changed files with 3087 additions and 0 deletions
@@ -0,0 +1,134 @@
# LAB E45 · RAVNOVES00 binding sensitivity
Date: 2026-07-29
Status: accepted diagnostic measurement only
Immutable result:
`e45-binding-sensitivity-b10fa117f110d5ac7942f73c62f1300c7d9ce833a187542b992e58fb24d1be72`
## Task
E31 accepted zero recorded-host-arrival offset for all 87 evidenced
camera↔LiDAR correspondences, but its residual is a support-centroid location
inside a reviewed detector box. It is not a calibration-target measurement.
E45 asks whether that already accepted diagnostic residual visibly degrades
with fisheye radius, rig motion, LiDAR↔camera age, or pose↔point age.
E45 does not:
- re-run projection or inference;
- change E31 thresholds or the selected offset;
- infer hardware firing time;
- infer vehicle body or physical mount dimensions;
- rename a detector-box residual as calibration truth.
## Immutable inputs
- RAVNOVES00 session `20260720T065719Z_viewer_live`;
- E10 LiDAR pack
`e10-lidar-pack-576c994a6c814e2592dd6240ace3902a5db94843312c759a73ba0c9166157d2b`;
- accepted E31
`e31-source-qualification-b2460a5eb143688c7eea6821b2277e13aea79868abe81d83f7e78548c119159a`;
- E30 materialization
`e30-materialization-841af926d8d28ab93538c46d8f31278a2234c4d1c12c7dc4dc296b249d59735a`;
- factory calibration identity
`05f3ad9b38b3a4fc95388a8ec83da83c745e217709e51787b3d5aad0969f6fa9`;
- right camera, `camera_1`, KB4, 800×600.
## Method
For every accepted E31 correspondence, E45 joins the zero-offset score with:
- normalized detector-box-centre radius from the 800×600 image centre;
- centred translational speed from adjacent valid recorded poses;
- centred quaternion angular speed from adjacent valid recorded poses;
- absolute LiDAR↔camera host-arrival age;
- absolute pose↔point host-arrival age;
- translation and rotation exposure proxies over the combined source age.
The 561 unavailable E10 LiDAR/pose rows remain unavailable. They are neither
interpolated nor replaced. Motion is evaluated only between adjacent valid
pose rows. Every derived row preserves the exact E31 item and source frame
identity.
The frozen E45 profile uses descriptive low/middle/high strata. Correlations
are Spearman rank coefficients against the existing
`centroid_residual_bbox_diagonal`. They are diagnostic associations, not
causal calibration-error estimates.
## Result
Evidence accounting closes at 87/87 rows. All 87 retain at least two occupied
points in their reviewed box.
| Measurement | Value |
| --- | ---: |
| Support fraction | 1.000 |
| Residual p50 | 0.22045 bbox diagonal |
| Residual p95 | 0.39466 bbox diagonal |
| Occupied support p50 | 6 points |
| Occupied support p95 | 57 points |
| Image radius max | 0.72639 normalized |
| Translation speed p50 / p95 | 1.325 / 2.709 m/s |
| Angular speed p50 / p95 | 13.941 / 34.579 deg/s |
| LiDAR↔camera age p50 / p95 | 22.633 / 81.594 ms |
| Pose↔point age p50 / p95 | 6.060 / 16.829 ms |
| Translation exposure p50 / p95 | 0.0383 / 0.1159 m |
| Rotation exposure p50 / p95 | 0.4157 / 1.3000 deg |
Residual correlations are small:
| Variable | Spearman ρ |
| --- | ---: |
| Image radius | +0.0421 |
| Translation speed | +0.0076 |
| Angular speed | 0.0669 |
| LiDAR↔camera age | +0.1016 |
| Pose↔point age | 0.0181 |
| Translation exposure | +0.0051 |
| Rotation exposure | 0.0312 |
The high LiDAR↔camera-age stratum contains 12 correspondences and still closes
12/12 support. The high translation-speed stratum contains 57 and closes
57/57. The high angular-speed stratum contains 48 and closes 48/48.
The image-radius high stratum is empty. The accepted E31 correspondence set
does not test the outer KB4 fisheye belt beyond normalized radius `0.85`.
## Failed attempt retained as implementation evidence
The first bounded E45 execution failed closed because the source pack contains
561 deliberately unavailable LiDAR/pose rows with non-finite pose arrays. The
initial implementation incorrectly required finite pose values for all 4,489
camera rows. The implementation was corrected to derive motion only between
adjacent valid pose rows. No missing pose was interpolated and no E31 input was
changed.
The successful local run completed in 0.74 seconds. Maximum RSS was
249,446,400 bytes and peak memory footprint was 213,025,728 bytes. No Docker
container, Worker 006 job, model, video decode, network change, or second
Mission Core service was started.
## Decision
The accepted E31 zero-offset source binding is retained unchanged. E45 finds
no material monotonic relationship between the existing detector-box
support-centroid residual and the measured motion/age/radius variables inside
the represented source envelope.
This result does not close calibrated-perception P0:
- measured static-landmark or calibration-target reprojection error remains
unavailable;
- the outer fisheye belt is not represented;
- physical mount/body dimensions remain unavailable;
- hardware firing time remains unavailable;
- cross-route or changed-mount transfer remains unproved.
The next detector-quality gate is an independent Truth Island with no model
prelabels exposed to reviewers and with prediction frozen before labels are
revealed. A later physical calibration-target capture can close the remaining
P0 measurement, but E45 does not fabricate it from RAVNOVES00.
Navigation, safety and command authority remain false.
@@ -0,0 +1,95 @@
# LAB E46 · RAVNOVES00 detector Truth Island preparation
Date: 2026-07-29
Status: prepared; awaiting two independent human reviews
Immutable result:
`e46-detector-truth-island-d8ab2745679636dce374b720b562fce05d6d0a26be3eac88650224d7aa92267d`
## Task
E46 prepares a small, bounded and reviewable detector Truth Island on the
known RAVNOVES00 right-camera source. It breaks the circular evaluation pattern
identified by E41: reviewers receive source-image references and an empty
annotation template, while model prelabels, predictions, scores and candidate
identities stay outside the review package.
E46 does not yet create truth, calculate accuracy or select a detector.
## Immutable input
- E2 evaluation pack
`evaluation-pack-7a983bba75d46c7c260252cb2d461e1384dcb92cda9e164397e841e6ebb37789`;
- source job `recorded-camera-602ac89026ed12978619801d`;
- source input SHA-256
`602ac89026ed12978619801d4edea0cae24b5cc3afabd9f7af2858de6505a20e`;
- session `20260720T065719Z_viewer_live`;
- right camera, `camera_1`, KB4, 800×600;
- fixed valid-FOV-fill preprocessing identity retained only as source
provenance, not shown as a model hint.
## Frozen selection
The deterministic profile selects 32 frames:
- 16 anchors: two from each of eight route-time bins;
- 16 temporal frames: all four frames from each of four existing temporal
groups;
- source frame range: 704436;
- referenced source image bytes: 14,919,621;
- copied source images: zero.
The four temporal groups are:
- `clip-close-car`;
- `clip-near-structure`;
- `clip-stroller-person`;
- `clip-vehicle-occlusion`.
The package is content-addressed through
`image-references.jsonl`. Every reference retains source path, byte length,
file SHA-256 and pixel SHA-256.
## Review contract
Two different human reviewers must independently annotate all identifiable
instances inside the valid camera field of view. The target classes are
`person`, `bicycle`, `motorcycle`, `car`, `heavy_vehicle`,
`static_obstacle` and `animal`. Hard-negative status plus occlusion and
truncation flags are required. Disagreements require adjudication.
Neither reviewer may see:
- model prelabels;
- model predictions or scores;
- candidate identity;
- candidate comparison results.
Prediction must be frozen before labels are revealed. E47 performs that freeze
in a separate immutable result.
## Result and resource boundary
The package contains 32/32 valid references, an empty review template, the
blind contract and a preparation report. Its state is
`prepared-awaiting-independent-human-review`; truth remains unavailable and
candidate comparison remains unauthorized.
The local preparation completed in 0.54 seconds. Maximum RSS was 102,596,608
bytes and peak memory footprint was 64,406,344 bytes. No Docker container,
Worker 006 job, model inference, image copy, network mutation or second Mission
Core service was started.
## Decision
Truth Island preparation is complete, but the island is not sealed. The next
manual gate is two independent reviews followed by adjudication. Only the
sealed adjudicated labels may be joined with the already-frozen E47
predictions.
This is still same-source truth on RAVNOVES00, not cross-route validation.
E38E40 source-trained candidates remain ineligible for this gate because the
source already contains dense engineering labels.
Navigation, safety and command authority remain false.
@@ -0,0 +1,72 @@
# LAB E47 · detector candidate freeze before truth reveal
Date: 2026-07-29
Status: predictions frozen; awaiting E46 truth seal
Immutable result:
`e47-detector-candidate-freeze-514bcca7a8a26313cab5ffcacca053d7a0ec6fe7cbef25f15faf3a11e48ee92f`
## Task
E47 freezes two detector prediction candidates for the exact 32 E46 frames
before either independent review is revealed. This makes the later
raw-versus-calibrated-preprocessing comparison reproducible and prevents
post-label tuning.
E47 deliberately computes no accuracy metric and selects no winner.
## Candidates
Both candidates use the same exact generic Mask R-CNN checkpoint:
`73cbd0190fcbe3ba339921fbce2c3a0b6bb9126c9a133c85e43a2a8e060a109e`.
The only intended comparison variable is camera preprocessing:
| Candidate | Input profile | Admitted boxes | Frames |
| --- | --- | ---: | ---: |
| `maskrcnn-kb4-raw` | raw KB4 800×600 | 417 | 32 |
| `maskrcnn-kb4-valid-fov-fill` | fixed valid-FOV fill 800×600 | 394 | 32 |
The raw candidate contained 432 source instances. Fifteen categories outside
the frozen task ontology were ignored, leaving 417 admitted predictions. The
valid-FOV-fill candidate contained and admitted 394 predictions. Both
candidates produced at least one admitted prediction for every selected frame.
These counts are descriptive only. Fewer or more boxes do not imply better
accuracy.
## Frozen output
E47 writes 64 content-addressed prediction rows: one row for each candidate and
E46 image. The combined prediction row digest is
`0aec660d33c002b3e0578841b09e9bbb25e15c425b2428ebbf5a1957d23371fa`.
Every row retains the E46 sequence and source-image digest while excluding
truth and review fields.
The E46 reviewer package is not modified. The result records:
- truth labels unavailable;
- no truth join performed;
- accuracy metrics unavailable;
- no candidate winner;
- model retraining unauthorized.
## Resource boundary
The local freeze completed in 0.51 seconds. Maximum RSS was 105,103,360 bytes
and peak memory footprint was 67,634,016 bytes. It reused existing immutable
prediction artifacts; no model inference, video decode, Docker container,
Worker 006 job, network mutation or second Mission Core service was started.
## Decision
The two preprocessing candidates are now frozen before label reveal. The next
gate is to complete and adjudicate both E46 reviews, seal the resulting truth,
then compute COCO AP/AR, per-class recall, person/vehicle miss rate,
false-large-box rate, valid-FOV boundary leakage and temporal flicker.
Until that gate, neither candidate is preferred and no detector-quality claim
is made. The result remains source-scoped to the known RAVNOVES00 right camera
and cannot establish cross-route generalization.
Navigation, safety and command authority remain false.
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""Build the source-scoped E45 binding sensitivity audit."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from k1link.compute.e45_binding_sensitivity import (
build_e45_binding_sensitivity,
)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--e31-result-root", type=Path, required=True)
parser.add_argument("--source-pack-root", type=Path, required=True)
parser.add_argument("--materialization-root", type=Path, required=True)
parser.add_argument("--output-root", type=Path, required=True)
args = parser.parse_args()
result = build_e45_binding_sensitivity(
e31_result_root=args.e31_result_root,
source_pack_root=args.source_pack_root,
materialization_root=args.materialization_root,
output_root=args.output_root,
)
print(
json.dumps(
{
"result_id": result.result_id,
"result_root": str(result.result_root),
"analysis": result.report["analysis"],
"decision": result.report["decision"],
},
ensure_ascii=False,
sort_keys=True,
)
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
"""Prepare the references-only E46 detector Truth Island."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from k1link.compute.e46_detector_truth_island import (
build_e46_detector_truth_island,
)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--evaluation-pack-root", type=Path, required=True)
parser.add_argument("--output-root", type=Path, required=True)
args = parser.parse_args()
result = build_e46_detector_truth_island(
evaluation_pack_root=args.evaluation_pack_root,
output_root=args.output_root,
)
print(
json.dumps(
{
"result_id": result.result_id,
"result_root": str(result.result_root),
"status": result.report["status"],
"selection": result.report["selection"],
"blindness": result.report["blindness"],
},
ensure_ascii=False,
sort_keys=True,
)
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""Freeze E47 detector candidates before E46 truth reveal."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from k1link.compute.e47_detector_candidate_freeze import (
build_e47_detector_candidate_freeze,
)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--truth-island-root", type=Path, required=True)
parser.add_argument("--raw-result-root", type=Path, required=True)
parser.add_argument("--valid-fov-result-root", type=Path, required=True)
parser.add_argument("--output-root", type=Path, required=True)
args = parser.parse_args()
result = build_e47_detector_candidate_freeze(
truth_island_root=args.truth_island_root,
raw_result_root=args.raw_result_root,
valid_fov_result_root=args.valid_fov_result_root,
output_root=args.output_root,
)
report = result["report"]
print(
json.dumps(
{
"result_id": result["result_id"],
"result_root": str(result["result_root"]),
"status": report["status"],
"candidates": report["candidates"],
"blindness": report["blindness"],
},
ensure_ascii=False,
sort_keys=True,
)
)
return 0
if __name__ == "__main__":
raise SystemExit(main())