Lane proposals must be on the road, and the drivable surface becomes editable - #26
Merged
Conversation
Reported as "the drivable area is not showing properly". It was showing correctly. Isolating the layers proved it: the polygon traces the road surface, hugging the motorcycle wheels, wrapping the autorickshaw, following the kerb on one side and a parked car on the other. What was wrong sat on top of it. The same frame carried six proposed lanes, every one an edge of a blue and white striped hoarding, spanning up to 79% of the frame width and drawn as thick diagonals across the sky. They buried the drivable overlay and made a correct segmentation look broken. A lane detector finds bright linear structure, and an Indian dashcam frame is full of bright linear structure that is not a lane: hoardings, flyover girders, kerbs, awnings. The disqualifying fact was already computed, because the drivable mask says where the road is, and a lane sits on the road while a line across the sky does not. Three decisions carry it. The margin, without which this would be worse than the problem. A lane boundary runs along the edge of the drivable region and its points legitimately fall outside it, so strict containment would delete exactly the road-edge lanes the ontology cares most about. Points may sit within 3% of the frame width of the surface. Missing evidence is not evidence of absence. A frame nobody has segmented keeps its lanes; a proposer that produced nothing until somebody had run the segmenter first would be a worse failure than this one. And the threshold came from the corpus rather than from me. Scored over 4,525 stored lanes, 97.8% sit on the road and 2.2% do not, which is a filter cutting a tail rather than a rule purging a population. A geometric test was tried first and thrown out. Rejecting a lane wider than it is tall reads as obviously right, since a lane runs toward the vanishing point, and on this corpus it would have removed 73.6% of all lanes: near the horizon a lane really is nearly horizontal. Measuring it is the only reason it is not in here, and the note stays in the module so nobody adds it back. Wired into both paths that create lanes, the interactive proposer and the pod ingest, and both report what they rejected rather than quietly halving their own output. The stored corpus was swept the same way: 101 implausible proposals removed, human-drawn lanes never touched, and the six on the frame that started this are gone. Nine tests, and the ones that matter are the refusals to refuse: the road-edge lane just outside the polygon, the frame with no mask at all, the road split by a traffic island, the degenerate two-point polygon that is a line rather than a region.
DrivableMask has carried a `human` source since M2.2 and it could never be set. The refine
endpoint existed, was correct, and had no caller: no function in the web client spoke to it, the
canvas drew the polygons with `listening={false}`, and the free-space tools were declared in the
editor registry and consumed by nothing. `source` read `proposed` on 2,478 of 2,479 masks, and
the one exception was a curl I ran while auditing.
So the layer was machine output a person could look at and not fix, which is a visualisation
rather than a label.
Regions are now drawn on the same canvas that draws the lanes, in the three classes the ternary
mask actually carries. Fallback is offered alongside drivable rather than folded into
non-drivable, because the unpaved shoulder is what India drives on and a surface model that
cannot say so is describing a different country.
A region and a lane get separate in-progress buffers. A lane is an open polyline and a region is
a closed area, so sharing one would render whichever was not being drawn incorrectly. The
in-progress outline is tinted in its own class colour, so which surface the next click adds to is
visible rather than remembered. Three points is the minimum that encloses anything; fewer is a
stray click, and closing it would write a degenerate sliver into the coverage statistics.
Verified by driving it: drew a fallback region, closed it, watched the PUT fire, saw the count go
from three regions to four and the coverage readout follow, confirmed `source` had flipped to
`human` in the database, then put the frame back to the model's output byte for byte.
…reasoner thought Three additions, each closing a gap where the data existed and nothing could reach it. ## The review queue can see the reasoner's conflict The ranking used uncertainty, diversity, rarity and an error term currently firing on 40% of the corpus at a near-constant score. Meanwhile the reasoning layer computes, on every object, a measure of how much the evidence disagrees with itself, stores it in provenance, and the queue had no idea it was there. Conflict rather than score, deliberately. A low score means the evidence agrees the label is wrong, and the gate already routes those. Conflict means the evidence cannot settle: the detector is confident and physics says impossible, or every path proposed a different class. Those are the objects where a human adds the most and where nothing else in this ranking can look. An adjudicate verdict counts as conflict whatever the number says, because that is the layer stating out loud that it could not decide. On the live queue it surfaces objects scoring 0.57 conflict with an error term of zero, which no other term could have found. ## Behaviour search across the corpus Every event route shipped session-scoped. That is right for reviewing a drive and cannot answer the question the layer exists for, because "every illegal lane change while a signal was red" is a fact about the fleet. The conjunction is the part that matters and the part that is not a filtered list: it is a temporal join within each session, done in SQL so the limit still means something. `within_ms` widens both sides so "while" can mean "around", since a crossing a second after the light changed is still a crossing at that light. Severity is expanded to its kinds before the query rather than filtered after the fetch, for the same reason as everywhere else in this codebase. Results carry the city, the vehicle, the actor's class and the offset into the drive, so an answer is a list of places to go rather than a count. The page states the question back in words, because a row of dropdowns says what is set and a sentence says what was asked, and that is what somebody reads before trusting a zero. ## Approach on red, named for what the evidence carries The question worth answering is whether the ego entered on red. The honest answer is that this corpus cannot support it: ego speed exists on 846 frames of 40,222 and on none of the 173 sessions holding signal phases. Built on `ego_speed` it would have returned nothing on every session anybody opened. What the corpus does have is 3,061 signal tracks, and a signal's apparent geometry is an ego-motion instrument: approaching a fixed object makes it grow and drift down the frame. So the claim is the weaker, supportable one, and the kind is `signal_approach_on_red` rather than `ran_red_light` because a growing box says the gap is shrinking and does not say a stop line was crossed. Severity is notable, not violation, for the same reason. It fires on almost nothing here and the reason is upstream and already reported: 91% of signal phases in this corpus are a single frame, and exactly one red or amber phase spans the four frames a trend needs. That is the label noise the flicker detector flags, not a fault in the rule, and every refusal says which threshold it failed and why. Both measures take a median at each end rather than a mean. A detector that loses the signal for one frame emits a box at the origin, and a mean over three samples was enough to invert the direction of travel and turn a real approach into a refusal. 16 tests. Suite 1,320 passing against the same 5 pre-existing failures.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two changes, both from a report that "the drivable area is not showing properly in the canvas".
It was showing correctly. Isolating the layers proved it: the polygon traces the road surface,
hugging the motorcycle wheels, wrapping the autorickshaw, following the kerb on one side and a
parked car on the other. Two other things were wrong, and this PR fixes both.
A proposed lane has to be on the road
The same frame carried six proposed lanes, every one an edge of a blue and white striped
hoarding, spanning up to 79% of the frame width and drawn as thick diagonals across the sky.
They buried the drivable overlay and made a correct segmentation look broken.
A lane detector finds bright linear structure, and an Indian dashcam frame is full of bright
linear structure that is not a lane: hoardings, flyover girders, kerbs, awnings. The
disqualifying fact was already computed, because the drivable mask says where the road is.
Three decisions carry it:
outside it, so strict containment would delete exactly the road-edge lanes the ontology cares
most about. Points may sit within 3% of frame width of the surface.
2.2% do not: a filter cutting a tail rather than a rule purging a population.
A geometric test was tried first and thrown out. Rejecting a lane wider than it is tall reads as
obviously right, and on this corpus would have removed 73.6% of all lanes, because near the
horizon a lane really is nearly horizontal. Measuring it is the only reason it is not in here.
Wired into both creation paths, the interactive proposer and the pod ingest, and both report
what they rejected rather than quietly halving their own output. The stored corpus was swept the
same way: 101 implausible proposals removed, human-drawn lanes never touched.
The drivable surface becomes editable
DrivableMaskhas carried ahumansource since M2.2 and it could never be set. The refineendpoint existed, was correct, and had no caller: nothing in the web client spoke to it, the
canvas drew the polygons with
listening={false}, and the free-space tools were declared in theeditor registry and consumed by nothing.
sourcereadproposedon 2,478 of 2,479 masks.Regions are now drawn, dragged and deleted on the same canvas that draws the lanes, in the three
classes the ternary mask carries. Fallback is offered alongside drivable rather than folded into
non-drivable, because the unpaved shoulder is what India drives on.
Verification
the road-edge lane just outside the polygon, the frame with no mask, the road split by a
traffic island, the degenerate two-point polygon.
tests/KNOWN_FAILURES.md(2 need a local Ollama, 3 are test-ordering pollution).the PUT fire, saw three regions become four with the coverage readout following, confirmed
sourceflipped tohumanin the database, then restored the frame to the model's output.