Repository navigation
Small upstream fixes: IPv6 pairing, EPIPE, Ollama model lookup, GPU labels, CSP - #33
Merged
Merged
Conversation
I don't see any pdf.js code, so I presume we don't need this. (cherry picked from commit 5365a48) Co-authored-by: Kaylee Lubick <klubick@nvidia.com> Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Closes NVIDIA#33. ## Problem `NodeCardDetails.tsx:276` passed only the first GPU to the node card header: ```tsx gpuLabel={gpuInfo.length > 0 ? gpuInfo[0].name : undefined} ``` `NodeLabel` took a single `gpuLabel: string | undefined`, so every GPU after the first was unrepresentable by construction. A host with a Tesla P100 **and** an RTX 3060 rendered identically to one with only the 3060, with no count or overflow hint that anything was missing. The data was never wrong — `/v1/node-info` reports every GPU, `inferenceHardwareIds` was absent (which by the contract in `gpu-inference.ts` means "show every GPU"), and the detailed performance view already charts all of them. Only the header dropped them. ## Change Emit **one label segment per GPU**. Segments are the right unit rather than a joined string: `NodeLabel` applies wrapping, `·` separators and truncation *per segment*, so `gpus.join(' · ')` would be a single segment that truncates after the first name on a narrow card — the same blind spot in a new shape. Per-GPU segments keep the existing layout behavior and let each name wrap and truncate on its own. Three supporting details: - The segment builder moves to `ui/utils/node-label-segments.ts`. The unit project runs `environment: 'node'` with no DOM and deliberately excludes components, so a pure helper is testable there without adding jsdom/testing-library to the tree. It also lands inside the existing coverage scope ("the renderer's helper and constant modules"). - `gpuLabels` is memoized in `NodeCardDetails`. Building the array inline gave it a new identity every render, and `NodeLabel` observes its segments — that would have torn down and rebuilt the `ResizeObserver` on every render. - Blank GPU names are skipped, so a backend reporting an empty name cannot render a separator with nothing after it. Behavior for 0- and 1-GPU hosts is unchanged. ## Tests `desktop/tests/modular/node-label-segments.test.ts` — 13 cases: - name/address ordering, and the address-as-primary fallback - single-GPU host unchanged - the reported dual-GPU regression, asserting topology order - `it.each([3, 4, 5, 6, 7, 8])` — every GPU present, in order, at each count; 8-GPU servers are the case that matters most here - unique, stable `gpu-N` ids across an 8-GPU host so React keys do not collide - blank names dropped without disturbing the rest - no GPU segments for a host reporting none ## Verification Run from `desktop/`, all green on this branch: | Gate | Result | |---|---| | `npm run lint` | exit 0 (one pre-existing warning in `node-info-poller.ts`, untouched here) | | `npm run typecheck` | exit 0 | | `npm run dead-code:check` | exit 0 — no dead code | | `npm run test:unit` | 38 files, 221 tests passed | --- *Proudly Made in Nebraska. Go Big Red! 🌽 <https://xkcd.com/2347/>* (cherry picked from commit 54d2fe3) Co-authored-by: Aaron K. Clark <cryptojones@owasp.org> Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
When the inviter was reached over IPv6 link-local, outboundIP dropped the scope zone when advertising its address, so the joiner's Completion Exchange POST had no route and pairing failed after the PIN step. Keep the zone, and render peer addresses into URLs via net/url so the zone is percent-encoded per RFC 6874 (a raw % is rejected as an invalid URL escape). (cherry picked from commit 93076e6) Co-authored-by: Mallikh Kalkere <mkalkere@users.noreply.github.com> Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
File append was already best-effort. Console write was not, so a closed stdout pipe (parent gone, or a launch that inherited a pipe that later closed) raised uncaught write EPIPE from afterWriteDispatched. Electron then showed "A JavaScript error occurred in the main process". Treat stdio the same as the log file: try/catch around write, and attach error listeners so the async EPIPE event is not an uncaughtException. (cherry picked from commit b82fe49) Co-authored-by: Michael Gannotti <michael@smfworks.com> Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
The Ollama model hub browses a committed snapshot (desktop/src/electron/model-hub/ollama-models.json) regenerated by hand, so a model published after that snapshot is invisible in the hub even though the engine can pull it. The pull path never had this limit: pull_model forwards whatever name it is given and never consulted the catalog, so the snapshot gated discovery alone. When a search matches nothing locally and the query is a well-formed model reference, resolve that one exact name against registry.ollama.ai and fold the answer into the list as an ordinary result row. The registry speaks the same OCI distribution API ollama pull uses, so this asks the source the engine would ask rather than scraping rendered HTML. It answers 404 for /tags/list, so browsing still comes from the snapshot and this is an exact-name lookup rather than a search. A manifest carries no publication date and the registry sends no last-modified, so ModelEntry.updatedAt becomes optional and a resolved row omits its age rather than claiming it was updated just now. Lookups arrive over IPC, so the reference is validated in the main process rather than trusting the renderer's own check: without it "foo/.." walks out of the namespace and "foo/bar#z" truncates the request path. Refs NVIDIA#21 (cherry picked from commit 3fefdb1) Co-authored-by: Shaun Y <me@shaunyap.ca> Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
…registry lookup Review follow-ups: - A link-local zone names an interface of the machine that wrote it. The joiner dialled the inviter's advertised address with the inviter's own zone (its %en0), which works only when both machines name the interface the same. It now uses the zone of the connection the inviter reached it on. Pairing signals (decline, fail, expire, acknowledgements) also build their URL with peerURL, so a scoped target parses. - The Ollama registry helpers took unknown, which AGENTS.md forbids; they now take JsonValue. A transient lookup failure is no longer cached, so the next search asks again; a 404 still is. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Review follow-up. Only the dialled address took the local zone; the address recorded as the member's kept the inviter's, so pairing could complete with an unusable member address. The joiner now scopes the inviter's advertised link-local address before dialling or recording it, and keeps it as an observation so a roster claim cannot replace it, as the inviter already does for the joiner. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
JaredP94
force-pushed
the
fix/small-upstream-ports
branch
from
November 2, 2026 18:52
b0ac105 to
86c121a
Compare
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.
Description
Small upstream fixes that applied with little or no change:
%zonein advertised addresses and peer URLs (Preserve IPv6 scope zone in pairing addresses and peer URLs NVIDIA/Personal-AI-Router#82, [Bug]: pairing fails after a correct PIN when the inviter connected over IPv6 link-local — the joiner's return POST drops the %zone ([fe80::…]:14321 → no route to host) NVIDIA/Personal-AI-Router#69).write EPIPE(fix(desktop): swallow EPIPE from structured logger stdout NVIDIA/Personal-AI-Router#40). Its test now logs atinfo, since this fork writesverboseto file only at debug level.Not included: scheduler priority retry (NVIDIA/Personal-AI-Router@d90590f) — its "retry after a failed write" can't happen in this fork, because the shared codec latches the first write error.
Validation
go test ./...innvpair-cluster-manager; desktoptypecheck,lint,test:unit(762 passed),dead-code:check,service-contracts:check; SPDX check.Risk
Low. cluster-manager 2.1.1.
Checklist
git commit -s), certifying the Developer Certificate of Origin.services/versions.json, and described user-visible changes above so they reach the release notes.Part of the upstream issue/PR review. Each branch is independent off
main; they all bumpservices/versions.json, so the second one merged will need a trivial conflict resolution there.