Skip to content

fix(osm): only a routable, surface-level way may corroborate a gate - #280

Open
cs-util wants to merge 1 commit into
r489from
r490
Open

fix(osm): only a routable, surface-level way may corroborate a gate#280
cs-util wants to merge 1 commit into
r489from
r490

Conversation

@cs-util

@cs-util cs-util commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Acts on the review of #277 and #278. Restricts which ways may corroborate a gate, which removed the last corpus opening -- both the rule originally produced were false positives. Plus the T-junction decision, the stale docstrings, and two JSDoc defects in the r488 recorder.

  • fix(osm): only a routable, surface-level way may corroborate a gate

Acts on the review of #277 and #278.

The DEC-A2 rule indexed EVERY way as a possible corroborator, so a
building outline, a `landuse` edge, a waterway or another wall could
vouch for a gate. That is the likeliest false-positive shape in real
data, because `entrance=*` nodes are overwhelmingly building-outline
vertices -- "building entrance node + outline + a fence within a metre"
would have opened the fence. It was not hypothetical: the one corpus
opening the rule had added at Sylt came from `barrier=wall` 739515786
corroborating `barrier=wall` 740958910.

The below-surface veto was also asymmetric -- applied to the gate node
but not to the corroborating way -- so a `tunnel=yes` road crossing in
plan would have opened the wall above it, DEC-R12-1's rejected failure
mode arriving from the other side. Deliberately NOT "same layer as the
barrier": the Tower's own corroborating way is `bridge=yes layer=1`.

So DEC-A2 now changes NOTHING at any of the eight corpus sites. Both
openings it originally produced were false positives, and a rule that is
a no-op everywhere looks exactly like a rule that works -- which is why
the demonstration is `agent-route.tower-gate.test.ts` on real Tower
geometry, and why both the test and the sidecar say so.

Also from the review: the "NOT a vertex of any barrier" docstrings were
false (nothing tested membership, and could not); `Enu` duplicated
`EnuPoint`; touching-counts-as-crossing was undocumented and is now a
stated decision with a T-junction test; and the tolerance boundary and
non-perpendicular crossings were untested.

And two JSDoc defects in the r488 recorder: the header prescribed
observing `documentElement`, which is the exact bug the implementation
was fixed to avoid, and the new function had been inserted between
`recordStatus`'s doc block and `recordStatus` itself -- so the block
documented the wrong function, on the one pair where confusing them
costs the most.
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a8c432aa-ce93-4b7b-b299-01375e212636

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@claude

claude Bot commented Aug 8, 2026

Copy link
Copy Markdown

Claude finished @cs-util's task in 4m 9s —— View job


Review

Two inline comments, both on the new restriction and its test. Nothing blocking.

  • Read review guidelines
  • Read the diff vs origin/r489
  • Review barrier-gates.ts corroboration change
  • Check tests + sidecar doc consistency
  • Post review

Inline findings

  1. barrier-gates.ts:216canCorroborate is a presence test on highway, in the file that already documents why presence tests were the wrong shape for entrance. highway=pedestrian + area=yes is a polygon outline, i.e. the building-outline false positive this change exists to close, arriving from the other side; roads.ts:143-146 already refuses it. construction/proposed are the denial-shaped values. Zero corpus impact today, so this is about the rule's stated argument holding, not a live wrong opening.
  2. barrier-gates.test.ts:337 — the new tolerance test doesn't pin the boundary it says it pins: gateNear offsets longitude by a latitude metre, so 1 m is really 0.62 m and 3 m is 1.87 m. A > vs >= slip in nearestOnLine still passes. A LNG_M = M / cos(lat) constant makes 0.95/1.05 assertions viable.

Checked and consistent

  • The Tower fixture's corroborating way (agent-route.tower-gate.test.ts:89) is highway=footway bridge=yes layer=1, so it survives both halves of canCorroborate — the motivating case is genuinely unaffected.
  • Sylt 13 → 12 is applied in all three places that state it (file header, sidecar .md, site-barriers.test.ts).
  • fixtures.js — the JSDoc really was attached to the wrong function, and the document vs documentElement wording now matches fixtures.js:394-397.

One note on the prose. Several of the new docstrings narrate their own edit history rather than the rule — "An earlier version of this comment claimed … which was simply false", "that restriction was a review finding rather than the original design", "(raised in review on #277)" in four test docstrings. Git and this PR hold that; a reader in six months wants the invariant. The DEC-A2 measurement history is different and worth keeping, because it is the evidence for the rule's narrowness.

Not verified: I could not run the suite — pnpm install needs approval in this environment, so the corpus counts and the five new tests are unexecuted here. CI covers them.
· branch r490

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
gps-plus-slam 3c19511 Commit Preview URL

Branch Preview URL
Aug 08 2026, 11:05 PM

* `bridge=yes layer=1`, so above-surface ways have to stay acceptable.
*/
function canCorroborate(feature: OsmFeature & { type: "way" }): boolean {
return feature.tags["highway"] !== undefined && !isBelowSurface(feature);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A presence test on highway, in the one file that already documents why a presence test is the wrong shape. DENIED_ENTRANCES exists precisely because entrance had "degraded to a presence test" and entrance=no opened the one node OSM took the trouble to deny. highway has the same denial-shaped values, and one structural one:

  • highway=construction / highway=proposed — a route that does not exist yet vouching for a gate.
  • highway=pedestrian + area=yes — this is the building-outline argument arriving from the other side. A plaza polygon is an outline, not a line through, and plazas abut walls constantly; roads.ts:139-147 already refuses exactly this shape ("A highway AREA is a surface, not a ribbon"). The docstring above says "highway is the routable set" — with area=yes in it, it is not.

Moderate confidence on how often this bites real data; measured corpus impact is zero today, so this is about the rule's argument holding rather than a live wrong opening. But isRoad is right next door and encodes "a highway that is genuinely a linear route", including the tunnel/covered veto that canCorroborate reimplements one half of via isBelowSurface. Either reuse it or add the two exclusions:

const highway = feature.tags["highway"];
if (highway === undefined || NON_ROUTE_HIGHWAYS.has(highway)) return false;
if (feature.tags["area"] === "yes") return false;   // an outline, not a way through
return !isBelowSurface(feature);

Fix this →

Comment on lines +337 to +338
expect(opens(GATE_ON_BARRIER_M)).toBe(true);
expect(opens(GATE_ON_BARRIER_M * 3)).toBe(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test does not pin the boundary its own docstring says it pins. gateNear offsets in longitude by M, a latitude metre, so at 51.5° N the real offsets are 1 m → 0.62 m and 3 m → 1.87 m. The docstring acknowledges the scaling but then claims "an off-by-a-comparison in nearestOnLine would be invisible without this" — it still would be: nothing here lands within 0.38 m of GATE_ON_BARRIER_M, and > vs >= at the boundary is untestable at 0.62 m. The bracket only narrows from (0.12 m, 2.49 m) — the existing 0.2 and *4 cases — to (0.62 m, 1.87 m).

Convert the offset properly and the test becomes what it claims to be:

/** A metre EAST in degrees of longitude at ORIGIN's latitude. */
const LNG_M = M / Math.cos((ORIGIN.lat * Math.PI) / 180);

then have gateNear use LNG_M for the offset and assert opens(GATE_ON_BARRIER_M * 0.95) === true / opens(GATE_ON_BARRIER_M * 1.05) === false. The other cases in this block (0.2, *3, *4) stay correct under the change — they only move further from the boundary, and crossingAt's ±5 m arms are unaffected by a 1.6× east scaling.

Fix this →

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant