Skip to content

fix(package): render a multi-valued facet as separate values - #5

Merged
Sunrisepeak merged 1 commit into
mainfrom
fix/multivalue-facet-display
Aug 13, 2026
Merged

fix(package): render a multi-valued facet as separate values#5
Sunrisepeak merged 1 commit into
mainfrom
fix/multivalue-facet-display

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

The bug

A facet is multi-valued by contractbuild.py filters with
str(pkg.facets.get(facet.key) or "").split(). But package.html printed the
raw value, so a two-value facet rendered as one blob:

category   tui web-ui
keyword    claude-code coding-agent ink react terminal tui

tui web-ui reads as a single odd token, not two values. The filter row on the
home page splits correctly; only the detail page did not.

Fix

Split at display the same way it is split at filter time, and render each value
as a chip — the markup platforms already use.

Added as a split_facet filter rather than an inline .split(), so the
contract sits in one place next to platform_label.

Test

tests/test_facet_display.py builds a throwaway index whose plugin sets one
two-value facet and one single-value facet, then asserts on the rendered
values
, not on a string:

  • kind emits exactly ["tui", "web-ui"]
  • single emits exactly ["solo"] (single-valued behaviour unchanged)
  • the joined form tui web-ui appears nowhere on the page

Reverting the template fails all three.

Full suite: 45 passed.

Where it showed up

Sunrisepeak/dsh-index, whose plugin sets category and keyword from each
plugin's own topics — those are naturally multi-valued.

A facet is multi-valued by contract -- build.py filters with
`str(value).split()` -- but the package page printed the raw value, so a
two-value facet came out as one blob:

    category   tui web-ui

which reads as a single odd token rather than two values. Filtering and display
now split the same way, and each value renders as its own chip, matching how
platforms already render.

Adds a `split_facet` filter rather than splitting inline, so the contract lives
in one place next to `platform_label`.

The test asserts the rendered values, not the string: it builds a throwaway
index whose plugin sets a two-value and a one-value facet, then checks the
package page emits exactly ["tui", "web-ui"] and ["solo"], plus that the joined
form never appears anywhere on the page. Reverting the template fails all three.
@Sunrisepeak
Sunrisepeak merged commit 08c866d into main Aug 13, 2026
5 checks passed
Sunrisepeak added a commit to Sunrisepeak/dsh-index that referenced this pull request Aug 13, 2026
…ackages

Follow-up to #1, driven by installing from the live index rather than reading
the code.

Plugins now land in a profile the user can find. The subos branch was dead
code: it read XLINGS_SUBOS, which xlings does not set, so "the profile follows
the subos" was documented but never true and every install silently landed in
`web`. It now comes from system.subos_sysrootdir(), a libxpkg API rather than
an ambient variable. Surface plugins (tui, desktop) get a profile named after
themselves, matching what upstream's own docs tell users to run, and config()
prints the profile and the launch command -- the obvious guess was the command
upstream documents, and it failed.

The index drops from 168 descriptors to 68. 51 that nobody can install and 70
with fewer than two stars, overlapping. Broken is measured, not inferred: the
mirror pipeline refuses what it cannot build, and the causes break the direct
path too -- dependencies that do not resolve or do not exist, and TypeScript
packages whose `main` is absent from their own tarball. The 30 that were broken
AND had two or more stars were re-verified one at a time before deleting; all
30 reproduced. Removal is data in tools/excluded.json with the reason attached,
read by gen_descriptors.py, because deleting a file alone would be undone by
the next regenerate.

Packages whose license cannot be identified are kept. They install fine; they
just cannot be mirrored, since mirroring is redistribution. They are labelled
`unknown`, following GitHub's own convention rather than the API's NONE
sentinel.

41 survivors carry a mirror block backfilled from releases published to both
GitHub and GitCode, each verified three ways at publish time.

Facet values rendered as Python reprs, so `['web-ui',` and `'session']` became
separate buttons: pkg.facets is Dict[str, str] and the core splits multi-valued
facets on whitespace. The other half of that bug is fixed upstream in
openxlings/xpkgindex#5.

README follows mcpp's shape now, and .agents/docs carries a work log for the
whole integration.

Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
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