Zones are no longer taught only by driving: fix unbound remedies, editor anchor provenance, and the drive-to-teach prose - #112
Merged
Conversation
…anchor provenance The zone layer was written when a zone got geometry one way: a robot was driven there and `save-zone` captured the pose. `segment-map` and the dashboard's zone editor have since added two more, and M4 made a binding travel inside a map revision, so a robot can hold geometry for a floor it has never entered. Five behaviours and about sixty prose sites still said otherwise. **`unbound` is a fact about the revision, not about where the robot has been.** The goto/fetch refusal, `task_server`'s boot warning, `site info` and `bundle.validate`'s warning each said the remedy was to drive there. They now name the mechanism — no geometry for this name in the binding this robot holds — and all three remedies: place it in the dashboard's zone editor and promote, pull the revision that binds it, or drive there and `save-zone`, which is the one that also measures an approach heading. `site info` puts the remedy on its own line under the count, since a tally and three sentences do not belong in one parenthesis. **Geometry an operator places is no longer recorded as one a robot drove to.** `zone.anchor()` defaulted to `taught` and the editor sent no anchor at all, so every click, drag and reshape was stored as a measurement — in the one field that exists to tell a later reader whether to trust a coordinate after the map changes. The editor now stamps zone/v0's `external` (`EDITOR_ANCHOR`, through `reanchored`) on every zone whose geometry it moves, and leaves an untouched one carrying what it arrived with, so a `segment-map` room stays `derived` until somebody reshapes it. `external` is zone/v0's closest fit rather than an exact one — the spec glosses it as an off-platform localisation system — but the enum is closed, and the alternatives were recording a click as a measurement or as an algorithm's output. A successor revision should carry a method for it (#616). The browser says only the method and `by: zone-editor`; `_stamp_anchor` fills in `at` from the server's clock and rewrites `by` to name the operator holding the token, which is the half a browser cannot be trusted for. Carrying it through took two fixes: `bundle.parse_zones` dropped `anchor` outright, and `zone.split` stamped `taught` over whatever arrived — between them the editor's own output was relabelled on the way back in. `read_anchor` validates one at the parse, so a method outside the four is a 422 rather than a stored claim nothing afterwards can distinguish from a real one. The snap rule loses its `taught` justification with it: nothing re-snaps a coordinate the operator did not touch, whoever put it there, and a dragged pose does snap because a drag is a fresh coordinate with the map's precision and no more. The prose sweep replaces "taught" used as a synonym for "bound" throughout, and keeps it where it means the anchor method or a floor written before a migration. Verified: `pixi run lint` clean; 749 passed / 10 skipped across `mote_fleet/test`, `mote_bringup/test` and `mote_tasks/test` (the skips are the JSON Schema conformance set — `jsonschema` is not in the env); 97 node UI tests. Driven in a real browser against `fleet-ui-check`: editing `pickup`'s pose and saving stored `method: external, by: fleet-ui-check (zone-editor)` with a server timestamp, while untouched `dropoff` and `home` kept `taught`; the review pane showed the reworded validator warning and the new inherited- zones tooltip. The goto refusal and `site info` output were read back directly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UUbZKWZ1coJyJAiaqdVvaS
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.
The zone layer was written when a zone got geometry one way: a robot was driven
there and
save-zonecaptured the pose.segment-mapand the fleet dashboard'szone editor have since added two more, and M4 made a binding travel inside a map
revision — so a robot can hold geometry for a floor it has never entered. Five
behaviours and about sixty prose sites still said otherwise.
unboundis a fact about the revision, not about where the robot has beenThe goto/fetch refusal,
task_server's boot warning,site infoandbundle.validate's warning each gave "drive there and run save-zone" as theremedy. They now name the mechanism — no geometry for this name in the binding
this robot holds — and all three remedies: place it in the dashboard's zone
editor and promote, pull the revision that binds it, or drive there and
save-zone, which is the one that also measures an approach heading.site infoputs the remedy on its own line under the count, since a one-word tallyand three sentences do not belong in one parenthesis.
Geometry an operator places is no longer recorded as one a robot drove to
zone.anchor()defaulted totaughtand the editor sent no anchor at all, soevery click, drag and reshape was stored as a measurement — in the one field
that exists to tell a later reader whether to trust a coordinate after the map
changes. The editor now stamps zone/v0's
external(EDITOR_ANCHOR, appliedthrough
reanchored) on every zone whose geometry it moves, and leaves anuntouched one carrying what it arrived with, so a
segment-maproom staysderiveduntil somebody reshapes it. Renames and notes do not re-anchor:vocabulary is not geometry.
externalis zone/v0's closest fit rather than an exact one — the spec glossesit as an off-platform localisation system — but the schema's enum is closed, and
the alternatives were recording a click as a measurement (
taught) or as analgorithm's output (
derived), which are the two larger lies. A successorrevision should carry a method for it; noted in the code and in CLAUDE.md
against #616.
The browser says only the method and
by: zone-editor;bundle_store. _stamp_anchorfills inatfrom the server's clock and rewritesbyto namethe operator holding the token — the half a browser cannot be trusted for.
Carrying the anchor through took two fixes:
bundle.parse_zonesdropped thefield outright, and
zone.splitstampedtaughtover whatever arrived, sobetween them the editor's own output was relabelled on the way back in.
zone.read_anchorvalidates one at the parse, so a method outside the four isa 422 rather than a stored claim nothing afterwards could tell from a real one.
The snap rule loses its
taughtjustification with it: nothing re-snaps acoordinate the operator did not touch, whoever put it there, and a dragged pose
does snap, because a drag is a fresh coordinate with the map's precision and
no more.
Prose
CLAUDE.md's "zones are taught by driving there... not by editing YAML" and"nobody has driven me there",
docs/robot/sites.md's teach-by-driving heading,mote_tasks/README.md's "reachable by construction" and its pre-split YAMLexample,
save_zone.py's docstring,bundle.binding()'s "never leaves thisrobot" (false since M4), and
mapping-pipeline.md's click-to-teach listed asunbuilt (it shipped) are rewritten. About fifty further uses of "taught" as a
synonym for "bound" are now "bound"; it is kept where it means the anchor
method or a floor written before a migration.
Verification
pixi run lintclean.mote_fleet/test,mote_bringup/testandmote_tasks/test. The skips are the JSON Schema conformance set —jsonschemais not installed in this env, so they skip here as in CI; thebinding schema's enum was read directly and does contain
external.freshZoneall carry the editor anchor while an untouched zone keeps its own.pixi run fleet-ui-check: editingpickup'spose and saving stored
method: external, by: fleet-ui-check (zone-editor)with a server timestamp, while untouched
dropoffandhomekepttaught.The review pane showed the reworded validator warning ("no geometry for any of
this floor's places, so every name resolves unbound…") and the new
inherited-zones tooltip.
site infooutput were read back directly:zone 'store room' is a place on this floor, but the map revision this robot is running has no geometry for it — place it in the dashboard's zone editor and promote, pull the revision that binds it, or drive there and run save-zone, withthe galleystill distinct asunknown_name.save-zoneas one of three remedies, or are unrelated (arm poses, the fetchtree, a mapsync config comment).
Branch
zones-unbound-remedies, one commit, not pushed.