Repository navigation
20260916 - Ask the owner how we can reach them - #90
Merged
Merged
Conversation
Spec v1.2.0 added PUT /v1/nodes/contact and v1.2.2 gave it a phone country. Nothing on a node holds any of it, so retina-telemetry has nothing to send until this end collects it, the same ordering the consent records went through. Two surfaces, one route. A wizard step straight after the agreements step, so it is asked while the owner is still answering questions about themselves rather than about the radar, and a block under Remote support on the configuration page for adding or amending it later. Both post to /set-up/contact, because handing them separate handlers is how two surfaces start storing different shapes of the same thing. Under Remote support rather than a section of its own: those settings are how support reaches the node, and this is how they reach the owner. Same subject, so the same heading. Optional throughout, and that is the steady state rather than an unfinished one. The spec says a node with nothing to report never calls the endpoint at all, so Skip is a real button rather than an escape hatch, and an absent file is how the node says it has nothing. Clearing works, and it works by doing less rather than more. A blank box is simply not written, and a document with nothing left in it removes the file, so skipping the step and emptying every box converge on the same state. The Save button says "Details removed" rather than "Saved" in that case: claiming to have stored details we have just deleted would be the one confusing outcome here. The endpoint replaces its document wholesale, so this end replaces rather than merges and the two cannot disagree about what is held. Stored at /data/retina-gui/telemetry-contact.json, a cross-repo contract like the consent file, and deliberately not inside it. Those are versioned acceptances neither end may invent and retina-telemetry refuses to register without all three; a mutable optional document sharing that file would let a malformed contact stop a node registering. The shape mirrors the wire's NodeContact one-for-one so nothing is translated between what the owner typed and what the server is told. The caps are the spec's, commented as such beside TX_NAME_MAX_LENGTH's for the same reason: a value past one of them means retina-telemetry cannot build the payload, so the whole document is refused and the owner is never reachable. Better to refuse it at the box. `country` is checked in the route rather than the model. It is ISO 3166-1 alpha-2 and belongs to the phone number rather than to the owner, which is what the server asked for; asking "where do you live" would put a wrong answer against a real person. The check is in the route because `regex=` is pydantic v1 and `pattern=` is v2, nodes run v1 and CI runs v2, so a constraint spelled either way breaks one of them. It joins the rules the routes already own, which is also where a complaint can attach to the box it concerns. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Collects the owner's contact details for
PUT /v1/nodes/contact, which arrived in node ingest spec v1.2.0 and gained a phonecountryin v1.2.2. Nothing on a node holds any of it today, so retina-telemetry has nothing to send until this lands. Same ordering the consent records went through.The retina-telemetry half is offworldlabs/retina-telemetry#18. They are independent: that side treats an absent contact document as a complete answer, so neither breaks the other whichever way round they merge. This one first is the sensible order, because the feature only does anything once this is deployed.
Two surfaces, one route
A wizard step straight after the agreements step, so it is asked while the owner is still answering questions about themselves rather than about the radar. Plus a block under Remote support on the Configuration page for adding or amending it later. Both post to
/set-up/contact, because handing them separate handlers is how two surfaces start storing different shapes of the same thing.Under Remote support rather than a section of its own: those settings are how support reaches the node, and this is how they reach the owner.
Optional throughout, and that is the steady state
The spec is explicit that a node with nothing to report never calls the endpoint at all. So Skip is a real button rather than an escape hatch, and an absent file is how the node says it has nothing.
Clearing works, by doing less rather than more
A blank box is simply not written, and a document with nothing left in it removes the file. Skipping the step and emptying every box converge on the same state. The Save button says Details removed rather than Saved in that case: claiming to hold details we have just deleted would be the one confusing outcome here.
The endpoint replaces its document wholesale, so this end replaces rather than merges and the two cannot disagree about what is held.
Storage
/data/retina-gui/telemetry-contact.json, a cross-repo contract like the consent file, and deliberately not inside it. Those are versioned acceptances neither end may invent, and retina-telemetry refuses to register without all three; a mutable optional document sharing that file would let a malformed contact stop a node registering.The shape mirrors the wire's
NodeContactone-for-one, so nothing is translated between what the owner typed and what the server is told.Notes for review
TX_NAME_MAX_LENGTH's for the same reason: a value past one of them means retina-telemetry cannot build the payload, so the whole document is refused and the owner is never reachable.countryis checked in the route, not the model. It is ISO 3166-1 alpha-2 and belongs to the phone number rather than to the owner, which is what the server asked for. The check sits in the route becauseregex=is pydantic v1 andpattern=is v2; nodes run v1 and CI runs v2, so a constraint spelled either way breaks one of them.Verification
920 tests pass (24 new), ruff and vulture clean.
Verified end to end on owl-ded9 by deploying this branch to the node, posting through the real endpoint with a real CSRF token, and confirming the file landed at the real path with
gbnormalised toGB. retina-telemetry then read that file and sent all five fields. The node was restored tov0.8.0afterwards.🤖 Generated with Claude Code