policy-playground: the Space gets its name, and a box for what the search misses - #285
Open
pierre-rouanet wants to merge 4 commits into
Open
pierre-rouanet wants to merge 4 commits into
pierre-rouanet wants to merge 4 commits into
Conversation
The gallery is `?search=microduck`, which is a convention rather than a rule. A policy on a branch, in a repo named something else, or published into a search index that has not caught up is invisible in the list and perfectly fetchable — so there is a box above the rows, and its button is the same four calls the row buttons make. What it takes is `robotctl policy add`'s own spelling — `org/name`, optionally `@revision`, optionally `:file.onnx` — because a second syntax for the same three fields is a second syntax to get wrong, and a Hub URL besides, because what is in somebody's clipboard is the page they were just reading. `blob/`, `resolve/`, `tree/` and the api JSON all resolve to the same three fields. `parse_spec` repeats `updater/src/policy.rs`'s rule about what an `org/name` is for one reason: the daemon's refusal is correct and arrives after a round trip to a robot, and a typo deserves an answer while the cursor is still in the box. A Space URL is named as one rather than left to 404, since it is the same shape as a model's and it is the mistake to expect. Nothing is read here first, which is the difference from a row: a row has had its manifest read and can be refused before anything downloads, a typed repo has not, and fetching one to pre-judge it would be this page second-guessing `policy.fetch` — which reads the same file on the robot and refuses on shape before downloading. The encoding refusal still lands, one step later, off the fetch answer. The four calls move into `put_on_the_duck`, taking a repo, a revision and a file rather than a catalogue row, and the line a run finishes on is now the spec — `org/name@v2:walk.onnx`, what was actually fetched — which pastes back into the box or into `robotctl policy add`. `uv run catalogue.py <repo-or-URL>` is the check: what each argument parses to and what the Hub has there, needing no robot, no token and no Space. Assisted-by: Claude:claude-opus-5
Coverage72.10% lines on this branch, against a floor of 70%. Per-file |
The Space it publishes to is `pollen-robotics/microduck-policy-playground`, and nothing here is sold: the page is where you put a stranger's policy on your duck to find out whether it is any good, which is what `policy-channel-design.md` §1 asked the channel for in the first place. `publish-space.sh` derives the Space id from the directory name, so a directory called `policy-shop` would need `--space` passed by hand at every publish, and the README's own "this is what puts it here" line would be wrong. The name is in five other places besides the directory — the Space card's title, the page title, the consumer label the rendezvous sees, `vision-demo`'s note about sharing the log handler, and `remote-access-design.md` §5.2 — and all of them move together. The three symlinks into `spaces/shared/` are relative and at the same depth, so they survive the rename untouched. Assisted-by: Claude:claude-opus-5
The Space would not build. The error was a page of `reachy-mini X does not provide the extra 'central-consumer'` for every version from 1.8.4 down, which is pip backtracking after the newest one — the one that does provide it — failed to install, and names the wrong thing entirely. On Linux `reachy_mini` pulls `PyGObject`, which compiles against `gobject-introspection` headers a Gradio Space's builder does not carry. On a laptop the same line resolves to a `gstreamer-bundle` wheel and installs in seconds, which is why this was only ever going to be found in their builder. Installing the build deps would have worked and would still have been wrong. The whole contribution of `reachy_mini[central-consumer]` here was `aiortc`, `av` and one DTLS cipher patch; taking it meant a motor controller, `rustypot`, `libusb`, ONNX Runtime and zeroconf inside a web page that drives a robot over HTTP. So the libraries the page actually uses are named — including `aiohttp`, `numpy` and `huggingface_hub`, which were arriving transitively, which is not the same as being dependencies — and `lan.py` carries the cipher patch itself. That patch is theirs, copied, with the upstream aiortc PR named and the flag it sets kept at their attribute name: whichever copy runs first, the other sees it and does nothing. Without it aiortc and `webrtcsink` share no cipher, DTLS never completes, and the peer connection hangs in `connecting` — indistinguishable from the NAT failure the other tab exists to work around, which is the worst shape a bug here can take. `uv run --isolated lan.py` drives the whole session on loopback with no `reachy_mini` installed: DTLS, SCTP, the control channel, a call matched to its reply, a refusal, and frames decoded to RGB. Assisted-by: Claude:claude-opus-5
The build passed and the app did not. Ten log lines: gradio bound 7860 "with SSR (Node proxy -> Python :7861)", then `Stopping Node.js server...` ten seconds later, then nothing — no traceback, no port, `RUNTIME_ERROR`. SSR is a second process in front of the first, and what it buys is SEO for a page that sits behind a Hugging Face sign-in. Ruling it out at `launch` costs nothing and removes the whole of that surface. `vision-demo` rules it out too, with `GRADIO_SSR_MODE=false` in its Dockerfile, for the different reason that a `-slim` image has no Node for gradio to find. Assisted-by: Claude:claude-opus-5
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 commits, and the second one is why the first can be published.
spaces/policy-shop→spaces/policy-playgroundThe Space that serves this is
pollen-robotics/microduck-policy-playground, and nothing here is sold: the page is where you put a stranger's policy on your duck to find out whether it is any good, which is whatpolicy-channel-design.md§1 asked the channel for.publish-space.shderives the Space id from the directory name, so a directory still calledpolicy-shopwould need--spacepassed by hand at every publish, and the README's own this is what puts it here line would be wrong. The name is in five other places — the Space card's title, the page title, the consumer label the rendezvous sees,vision-demo's note about sharing the log handler, andremote-access-design.md§5.2 — and they move together. The three symlinks intospaces/shared/are relative and at the same depth, so they survive untouched.A box for the policy the search does not reach
The gallery is
?search=microduck, which is a convention rather than a rule: a policy on a branch, in a repo named something else, or published into a search index that has not caught up is invisible in the list and perfectly fetchable. So there is a box above the rows, and its button makes the same four calls the row buttons make.What it takes is
robotctl policy add's own spelling, because a second syntax for the same three fields is a second syntax to get wrong — and a Hub URL besides, because what is in somebody's clipboard is the page they were just reading:RemiFabre/microduck-flamingo-cyclemain, the only.onnxpollen-robotics/microduck-policies:roulade.onnxsomeone/thing@devhttps://huggingface.co/org/name/blob/v3/policy.onnxhttps://huggingface.co/spaces/org/namecatalogue.parse_specrepeatsupdater/src/policy.rs's rule about what anorg/nameis, rather than relying on it: the daemon's refusal is correct and arrives after a round trip to a robot, and a typo deserves an answer while the cursor is still in the box. That includes the dot —org/Phi-3.5-miniis unfetchable by a duck because both halves become a directory on it, so a page that accepted one would be a page that sends a call guaranteed to come back refused.Nothing is read here first, and that is the difference from a row. A row has had its manifest read by the gallery, so a ground pick can be refused before anything downloads. A typed repo has not, and fetching one to pre-judge it would be this page second-guessing
policy.fetch— which reads the same file on the robot, refuses on shape before downloading, and is the reading the skill gets written from either way. The encoding refusal still lands, one step later, off the fetch answer.The four calls are now
put_on_the_duck(repo, revision, file, hold)rather than a function taking a catalogue index, and it passesrevisionthrough topolicy.fetch, which has always accepted one. The line a run finishes on is the spec —org/name@v2:walk.onnx, what was actually fetched — which pastes back into the box or intorobotctl policy addon the robot.Checked
answers for the box without a robot, a token or a Space: what each argument parses to, and what the Hub has there. A set repo named without a
:fileis told it is a set and given the names, which is the refusalpolicy.fetchwould otherwise make after a round trip.The page builds from the renamed directory and every shape in the table above was run against the real Hub. The robot half is the same four calls the rows already make.
🤖 Generated with Claude Code