Skip to content

Picker refresh: one survival authority, settled attribute semantics, 9 new distros - #1

Merged
GionaGranchelli merged 11 commits into
masterfrom
refresh/picker-0.7
Sep 28, 2026
Merged

GionaGranchelli merged 11 commits into
masterfrom
refresh/picker-0.7

Conversation

@GionaGranchelli

@GionaGranchelli GionaGranchelli commented Sep 28, 2026 •

Copy link
Copy Markdown
Owner

Picker refresh: one survival authority, settled attribute semantics, 9 new distros

Five commits on refresh/picker-0.7. Every claim below is checkable in the diff, in
docs/distro-data-evidence.md, or in docs/evidence/ (the raw verification records).

Why: the two defects the review found

  1. Two pickers, one brand. The results page filtered with scoring.ts
    (applyHardConstraints, three rules: architecture, avoid-proprietary, secure boot) while
    /compare used eliminateDistros (eight rules). Measured across eight answer profiles,
    87 entries were presented as matches on the results page that the other engine excludes.
    An old-hardware, no-terminal, XFCE user got 54 matches and 0 exclusions; a no-terminal
    beginner was offered Alpine as a 2/5 "match"; an ARM user's /compare kept 31 of 33 entries
    that cannot run on ARM.
  2. Gates were red and unread. npm run typecheck failed with 126 errors and
    npm run test with one snapshot, and every CI run since 2026-07-17 was failure. The
    snapshot failure was the duplicate Artix entry crowding arch out of a persona's top five.

What changed

Engine (e951f76). Survival now has exactly one authority: eliminate.ts, called through
buildCompatibility. scoring.ts is deleted, with its hardcoded weights (gaming LIMITED 0.5,
NVIDIA GOOD/OK 2/1, a beginner docs bonus) and the low-coverage escape hatch that silently
turned a stated constraint into a soft one when fewer than three distros matched it. Architecture
became a real elimination rule. Ordering is counts only — stated constraints matched, then stated
preferences matched (weight 1 each), then name — which is the contract the persona suite already
asserted but could not actually exercise, because inclusion reason lists were always empty.

Explainability is now real: every card carries its inclusion reasons, every excluded entry the rule
that fired, and the conflict report covers all eight rules instead of three. The UI no longer
prints a match score.

Data (39563f3, b90ab46, ccb1731). Three dead question-level fields
(isHardConstraint, preferenceWeight, constraintMode) were deleted — no code read them, and
their only effect was the 126 typecheck errors. proprietarySupport got an operational
definition (default-path scale, firmware deliberately excluded) and 13 entries were corrected
from primary sources. The Ubuntu family is consistent again. Artix is one entry, verified against
the project's download page.

Coverage (ccb1731, 5048ffd, 40da0fe). Nine entries added: Omarchy, SteamOS, RHEL,
Raspberry Pi OS, antiX, Devuan, Vanilla OS 3, Guix System, Archcraft. Two entries removed as
unmaintained — feren_os (no release since 2025.03 after a ~4.5-year gap) and bodhi_linux
(DistroWatch "Dormant", last release 2023) — and centos_stream now says it is RHEL's upstream
development branch rather than reading like a stable server choice. Dataset: 53 → 60. Reasons for everything
deliberately not added are in docs/evidence/coverage-*.md (HoloISO EOL, ArcoLinux superseded,
BlackArch dormant, XeroLinux paid ISO, RebornOS installer failures, Batocera not a desktop,
Amazon Linux / Ubuntu Core cloud-only, Numa mobile, Slax / Porteus dormant, Oracle Linux a fourth
RHEL rebuild).

Gates (b90ab46, ccb1731, 5048ffd). validate-distro-invariants is now real: identity
(duplicate name, not just id), freshness ratchet, core-data completeness, Secure Boot requires
a UEFI architecture, Ubuntu-family consistency, architecture vocabulary, "no stated answer may be
unsatisfiable", and a compare-view reconciliation that fails if a rendered row is not in the
distro schema. Each check has a negative fixture. tests/resultContract.spec.ts sweeps 120
answer combinations
plus all personas against an independent oracle: no result may violate an
answer the user gave, kept set == oracle set, every entry explained, conflict flag exact,
output stable under dataset reordering.

Gates, verbatim

Local and in CI: run 36393018936 was the first CI run in this repository to execute a gate —
its ten steps (install, typecheck, test, validate, lint, build) all report success, and the
same is true for the run on the current HEAD (40da0fe).

  • npm run typecheck → exit 0 (was 126 errors)
  • npm run test → exit 0, 93/93 across 14 files (was 73/74; the feren_os spec file left with its entry)
  • npm run validate → PASSED, validate:invariants PASSED over 60 entries
  • npm run lint → exit 0
  • npm run build → exit 0, 33 routes prerendered

Where my own review was wrong

  • Debian was not misclassified. Official media ship main + non-free-firmware only;
    contrib/non-free stay off and nvidia-driver is [non-free], so OPTIONAL is correct.
    The defect was the undefined field, not the value. Recorded as refuted.
  • Whonix is not NONE. Its maintainer states non-free and contrib ship enabled → FULL
    under the definition (medium confidence: upstream wiki unreachable, forum statement used).
    Qubes, which I expected to stay OPTIONAL, became NONE.
  • Ubuntu's Secure Boot drift was on proprietarySupport, not secureBootOutOfBox: Ubuntu and
    its flavours shared the signed shim already; they disagreed about proprietary support.

Residuals — honest, not fixed here

  1. 37 of 54 pre-existing entries are still verificationMethod: INFERRED with one
    bulk-stamped date. The freshness invariant now fails on staleness, so this cleans up as entries
    are touched rather than in one bulk pass (backfill-distro-metadata is what stamped them
    MANUAL-across-the-board; it should not be re-run).
  2. rocky_linux / almalinux / centos_stream list supportedDesktops: ["OTHER"] while the
    new RHEL entry uses ["GNOME"]
    (upstream default). Same family, different answer — the same
    class of drift as the Ubuntu family. Not changed here because it needs a decision, not a
    source: either RHEL drops to OTHER for consistency or the three clones move to GNOME.
  3. Tie-heavy profiles expose the ceiling of a weight-free order. With rolling + systemd + pacman, eight Arch-family entries tie at 3/3 and the order among them is the name; the server
    persona now has Raspberry Pi OS at rank 4 and Ubuntu at 5 for the same reason. The fix is a
    question that discriminates (desktop image vs server image), not a hidden weight.
  4. minRam remains collected and consumed by nothing, and the i18n demo key
    distros.new_distro is still present. Neither is user-visible any more, both are dead weight.

Merge

Branch only, deliberately: merging to master triggers the production deploy, so that is your
call.

…pse the duplicate Artix entry

npm run typecheck was failing with 126 errors on master. They were the visible
symptom of three schema fields that no code ever read:

- QuestionOption.isHardConstraint / .preferenceWeight (types.ts): set nowhere
  and read nowhere. Their only effect was to make Zod's inferred output type
  require them on every option literal.
- Question.constraintMode (types.ts, set once at questions.ts:358): required by
  the schema, read by nothing.

Hardness lives in src/engine/eliminate.ts and nowhere else; these fields were a
half-migrated second authority for it, so they are deleted rather than
populated.

Also fixed, all reported by the same typecheck run:
- ConstraintKeys was missing constraint_init_other and constraint_pkg_other,
  which state.ts:1057/1077 already emit and state.ts:1147/1165 already switch
  on. Added to the enum (the i18n keys already existed in en).
- ResultsVM requires hardConstraintConflict/hardConstraintConflictFields; the
  pre-completion branch of resultsVM omitted them (TS2769 at state.ts:469).

Artix: distros.json carried two entries for one distro (artix, artix_linux)
with contradictory attributes. Collapsed into artix, verified against
https://artixlinux.org/download.php (read 2026-09-28):
- installerExperience MANUAL -> GUI: graphical ISOs ship Calamares and the page
  tells non-experts to use them ("Unless you really know your way around Linux,
  use a graphical or community edition").
- supportedDesktops [OTHER, TILING] -> the six documented graphical editions
  (KDE, XFCE, MATE, CINNAMON, LXQT) plus OTHER (LXDE).
- description, distroSeaUrl, lastVerified (2026-09-28) from the removed entry.

tests/recommendation.regression.spec.ts passes WITHOUT re-blessing its snapshot:
the failing diff was `+ "artix_linux"`, `- "arch"`, i.e. the duplicate was
crowding arch out of the OPENRC persona's top five. The snapshot was correct and
the data was wrong.

Gates: typecheck exit 0 (0 errors, was 126) | test exit 0 (74/74, was 73/74) |
validate exit 0 | lint exit 0.
…uthority

The results page ran its own, weaker filter: applyHardConstraints in scoring.ts
enforced only architecture, avoid-proprietary and secure boot, while /compare ran
eliminateDistros with eight rules. The same answers therefore produced different
verdicts on the two pages: measured across eight profiles, 87 entries were
presented as matches on the results page that the other engine excludes — an
old-hardware, no-terminal, XFCE user saw 54 matches and zero exclusions.

Survival
- buildResultsPresentation now runs buildCompatibility (eliminate.ts) only.
- scoring.ts is deleted, along with the hardcoded weights (gaming LIMITED 0.5,
  NVIDIA GOOD/OK 2/1, the beginner docs bonus) and its hard-constraint filter.
- The low-coverage escape hatch is gone: eliminateDistros no longer softens a
  stated constraint when fewer than three distros match it. Removing the
  threshold machinery also removes EnginePolicyOptions, which compatibility.ts
  and recommend.ts no longer take.
- Architecture became a real elimination rule (exclude_architecture_unsupported):
  it was enforced only by the deleted filter, so /compare previously kept
  x86-only distros for an ARM user (31 of 33 in one profile).
- The dead scoring types (ScoredDistro, MatchDetail) are deleted, as is the
  never-discriminating sort tier that consumed them.

Ordering
- Counts only, as agreed: stated constraints matched, then stated preferences
  matched (weight 1 each, no half matches), then name. The persona harness
  already asserted this order; it now actually receives populated reason lists,
  so its second tier discriminates for the first time.

Explainability
- Every compatible card carries its inclusion reasons and every excluded entry
  the rule that fired, instead of one generic "does not match" string.
- hardConstraintConflictFields is derived from the exclusion axes, covering all
  eight rules rather than three.
- The UI no longer prints a match score: DistroCard and ResultsView show the
  matched-constraint count and the reason chips.

Tests
- tests/scoring.* are replaced by tests/hardConstraints.spec.ts (the elimination
  contract, including "never relaxes a stated constraint when few distros match
  it"), tests/ranking.spec.ts (ordering, reason completeness, stability under
  dataset reordering, hard-conflict reporting) and tests/pickerIntegration.spec.ts.
- compatibility.spec.ts's low-coverage test asserted the old behaviour; it now
  asserts that a stated requirement is enforced.
- Two persona snapshots were re-blessed after review; the whole diff is
  "- alpine" and "- almalinux"/"+ bazzite". Alpine leaves the privacy persona
  because GUI + no-terminal now exclude its manual installer and hands-on
  maintenance; almalinux leaves the server persona for hands-on maintenance and
  bazzite inherits the alphabetical slot among two-reason distros.

i18n
- 7 locales are now key-identical to en (380 keys each): added
  reasons.exclude_architecture_unsupported, constraints.constraint_init_other,
  constraints.constraint_pkg_other, reasons.exclude_hard_constraint_mismatch,
  wizard.narrowChoice and results.distroCard.links.tryOnline, translated
  constraint_pkg_portage (was English in all six) and removed the four stale
  q_experience_depth keys left behind by a deleted question.

Gates: typecheck exit 0 | test exit 0 (81/81, was 73/74 before slice 0) |
validate exit 0 | lint exit 0 | build exit 0 (33 routes prerendered).
…mily

Definitions recorded in docs/distro-data-evidence.md:

- proprietarySupport = how far a DEFAULT install of the main desktop edition gets
  you to proprietary drivers/codecs through first-party means, with no repo added
  or edited. FULL = on/offered by default or installable from default-enabled
  repos; OPTIONAL = documented first-party opt-in only; NONE = no first-party
  path. Firmware blobs are excluded from the field, which is what made
  Debian-class entries unclassifiable.
- secureBootOutOfBox = a default install boots with UEFI Secure Boot enabled
  (signed shim + kernel, no hand-enrolled MOK).

Corrections, each cited in docs/distro-data-evidence.md:

- ubuntu: secureBootOutOfBox false -> true. help.ubuntu.com/community/UEFI:
  "All current Ubuntu 64bit (not 32bit) versions now support this feature
  [Secure Boot]". The value contradicted the five *buntu flavours that already
  said true while sharing Ubuntu's archive and signed shim.
- kubuntu, xubuntu, lubuntu, ubuntu_budgie, ubuntu_studio, ubuntu_mate:
  proprietarySupport OPTIONAL -> FULL. They are built from the same archive with
  the same default components (main restricted universe multiverse; restricted is
  the proprietary-driver component) and the same ubuntu-drivers tooling, so
  Ubuntu=FULL with flavour=OPTIONAL was indefensible.
- The six flavour entries and ubuntu move to lastVerified 2026-09-28 /
  verificationMethod MANUAL, which is the date these values were actually
  checked. The remaining INFERRED entries are untouched and still flagged as
  inferred.

The Debian claim from the review is recorded as refuted: official Debian media
ship main + non-free-firmware only, contrib/non-free stay disabled and
nvidia-driver is [non-free], so OPTIONAL is the correct value there — the defect
was the undefined field, not the value.

Gates: typecheck 0 | test 98/98 | validate PASSED (53 entries) | lint 0.
PART 1 — corrections (53 entries before, evidence in docs/evidence/ and
docs/distro-data-evidence.md)

Verification was done against primary sources for each changed field; the
corrections are the ones the sources forced, not preferences:

- linux_mint: proprietarySupport OPTIONAL->FULL, secureBootOutOfBox false->true
- lmde: same two changes (medium confidence: LMDE configures main contrib
  non-free non-free-firmware; its shim was later hit by an SBAT revocation)
- zorin_os, debian: secureBootOutOfBox false->true (Zorin docs; Debian ships
  shim since Buster)
- arch, endeavouros, manjaro, mx_linux, parrot: proprietarySupport
  OPTIONAL->FULL (nvidia in extra; ISO NVIDIA boot entry + nvidia-inst; free vs
  proprietary driver choice at install; MX Tools driver GUI; parrot.list ships
  contrib non-free non-free-firmware)
- qubes_os: proprietarySupport OPTIONAL->NONE (no first-party non-free path;
  NVIDIA "may require significant troubleshooting"; only third-party repos)
- whonix: proprietarySupport OPTIONAL->FULL (maintainer states non-free and
  contrib ship enabled; upstream wiki unreachable, recorded as medium)

Unchanged after checking, against my own review's expectation: pop_os and
mx_linux keep Secure Boot false; Arch/EndeavourOS/Manjaro keep it false; debian
keeps proprietarySupport OPTIONAL. All 13 changed entries now carry
lastVerified 2026-09-28 and verificationMethod MANUAL.

PART 2 — seven new entries (53 -> 59)

omarchy, steamos, rhel, raspios (Raspberry Pi OS), antix, devuan. Each is
schema-valid, has verified-resolving links (field-level quotes in
docs/evidence/new-distros-tier1.md) and carries the values the sources support.
Four calls were mine rather than an upstream statement, and are recorded as such:

- omarchy.installerExperience = MANUAL: the ISO ships the Omarchy Configurator,
  a guided text-mode wizard over archinstall. The enum has no "guided CLI"
  value; GUI would hand Omarchy to a no-terminal beginner.
- steamos.supportedArchitectures = ["x86_64"]: Valve ships SteamOS on x86_64
  handhelds/machines; no ARM build exists.
- raspios.nvidiaExperience = HARD: no NVIDIA path on Raspberry Pi hardware, and
  the dataset invariant bans UNKNOWN.
- devuan.initSystem = OTHER: sysvinit has no enum value.

Deliberately not added, with reasons in docs/evidence/coverage-*.md: HoloISO
(end of life), ArcoLinux (superseded), BlackArch (dormant), XeroLinux (paid
ISO), RebornOS (installer failures), Batocera (not a desktop), Amazon Linux and
Ubuntu Core (cloud/IoT), postmarketOS/Nura (mobile), Slax and Porteus (dormant),
Oracle Linux (fourth RHEL rebuild when RHEL itself is now listed).

Test consequences, all reviewed before re-blessing:

- compatibility.spec.ts used linux_mint as its "no Secure Boot" example in three
  places; that value is now (correctly) true, so the negative example moved to
  pop_os, whose upstream docs require Secure Boot to be off.
- The duplicate "keeps hard filtering when coverage is at least 3" test encoded
  the removed coverage heuristic and is deleted.
- hardConstraints.spec.ts asserted "fewer than 5 NONE distros", a dataset
  snapshot that the Qubes change broke; it now asserts a relative bound.
- Two persona snapshots changed: "- arch / + antix" (equal counts, name
  tie-break) and "+ raspios / - bazzite" for the server persona. Both were
  explained from a decision trace before being re-blessed.

Gates: typecheck 0 | test 97/97 (15 files) | validate PASSED | validate:invariants
PASSED over 59 entries | lint 0.
Three entries added (59 -> 62): vanilla_os (Vanilla OS 3), guix (Guix System),
archcraft. Sources in docs/evidence/new-distros-tier2.md.

Two draft values were replaced before merging because they were unverified and
would have overpromised:

- vanilla_os.secureBootOutOfBox true -> false (no upstream statement that its
  kernel chain is signed)
- vanilla_os.nvidiaExperience OK -> HARD (NVIDIA on an immutable ABRoot base is
  not a documented easy path)

Architecture spellings: the draft used aarch64/armv7/i686, while the engine only
consults x86_64, arm64 and x86 (src/engine/eliminate.ts). "aarch64" would have
made an ARM answer silently miss Guix and Archcraft, so the entries were
normalised to the engine vocabulary and a new invariant now fails the build on
any other spelling, with a negative fixture in tests/distroInvariants.spec.ts.
32-bit ARM and i686 remain inexpressible, the same limitation Raspberry Pi OS's
armhf runs into.

Tiny Core Linux was dropped rather than merged: it has no logo on Wikimedia
Commons and its own site was unreachable from the verification environment, so it
could not satisfy the missing_core_data invariant. Carving an exception into the
invariant for one optional entry was the worse trade; the entry is easy to re-add
once a hotlinkable logo exists.

One persona snapshot changed and was explained from a decision trace before being
re-blessed: advanced_rolling_system_preferences now reads
[arch, archcraft, cachyos, endeavouros, garuda]. Archcraft legitimately answers
that persona's stated rolling + systemd + pacman answers, and all eight
Arch-family entries tie at 3/3, so the order among them is the name tie-break.

Gates: typecheck 0 | test 98/98 (15 files) | validate PASSED |
validate:invariants PASSED over 62 entries | lint 0 | build 0 (33 routes).
Copilot AI lite review requested due to automatic review settings September 28, 2026 07:25
Every CI run in this repository so far failed at actions/setup-node, not at a gate:
the workflow configured cache:"npm" and ran `npm ci` while the project is pnpm
(pnpm-lock.yaml, lockfileVersion 9.0, no package-lock.json). GitHub Actions
reported "Dependencies lock file is not found in .../pickyourlinux" and stopped
before typecheck, test, validate or lint executed once. The six most recent runs
on master are all failures for that reason, which is why the 126 typecheck errors
and the failing persona snapshot could sit there unseen.

- pnpm/action-setup@v4 (version 11, matching the local toolchain)
- setup-node cache: "pnpm", then `pnpm install --frozen-lockfile`
- gates run as pnpm scripts: typecheck, test, validate, lint
- `pnpm build` added: typecheck does not cover prerendering, and the site is a
  statically prerendered Nuxt app (33 routes), so a broken prerender should fail
  the pipeline rather than the deploy

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Some of the newly added/updated tests contain logic bugs (incorrect filtering/counting and a broken Ubuntu presence assertion), and there is an API inconsistency where buildResultsPresentation ignores its distros argument for compatibility computation.

Review effort: Lite
Findings: 4 Medium severity

Open (4)
What changed in this PR

Unifies the picker around a single elimination-based compatibility engine, removes the legacy scoring system, expands/normalizes distro data, and adds stronger invariants + contract tests to prevent future drift between results and compare views.

Changes:

  • Replaces score-based ranking with deterministic ordering based on matched stated constraints, then matched stated preferences, then name; improves explainability via inclusion/exclusion reasons.
  • Removes the old scoring.ts pipeline and associated tests; adds broader contract tests (result set, explanations, determinism, invariants).
  • Updates distro dataset semantics (notably proprietarySupport, secureBootOutOfBox), adds new distros, and introduces invariant validation scripts/docs.
File Description
tests/​ui/​smoke.spec.ts Updates UI smoke expectations to reflect removal of match score and addition of “reasons” text.
tests/​scoring.softPreferences.spec.ts Removes tests for deleted soft scoring pipeline.
tests/​scoring.integration.spec.ts Removes integration tests for deleted scoring/hard-constraint pipeline.
tests/​scoring.hardConstraints.spec.ts Removes tests for deleted applyHardConstraints.
tests/​resultContract.spec.ts Adds oracle-based contract test for “never violate answers”, exact kept set, explainability, determinism.
tests/​ranking.spec.ts Adds ordering/score-removal contract tests for results ranking.
tests/​pickerIntegration.spec.ts Adds end-to-end profile tests for the new engine behavior and explainability.
tests/​hardConstraints.spec.ts Adds direct tests for eliminateDistros as single survival authority.
tests/​engine/​state.spec.ts Updates state tests to reflect new ordering model (no score).
tests/​engine/​compatibility.spec.ts Updates compatibility tests to reflect strict enforcement (no low-coverage escape hatch).
tests/​distros.ferenos.spec.ts Updates distro-specific test to use compatibility reasons rather than scoring fields.
tests/​distros.artix.spec.ts Updates Artix test for deduped ID and reason-based inclusion/exclusion.
tests/​distroInvariants.spec.ts Adds tests for new dataset invariants and compare-view reconciliation.
tests/​__snapshots__/​recommendation.regression.spec.ts.snap Updates regression snapshot outputs after ranking + dataset changes.
src/​pages/​compare.vue Removes minRam from compare view (aligns with schema/invariants).
src/​engine/​state.ts Reworks results presentation to use compatibility reasons + count-based ordering; removes score fields.
src/​engine/​scoring.ts Deletes legacy scoring engine (hard constraints + weighted soft scoring).
src/​engine/​recommend.ts Updates recommendations to call compatibility without policy options.
src/​engine/​eliminate.ts Removes low-coverage softening; adds architecture rule + excludedAxes for conflict reporting.
src/​engine/​compatibility.ts Removes policy options; builds inclusion reasons from elimination survivors.
src/​data/​types.ts Removes unused question-level constraint/scoring metadata and scoring-related types.
src/​data/​reason-templates.ts Adds new exclusion key and new constraint keys for OTHER init/pkg variants.
src/​data/​questions.ts Removes unused constraintMode / isHardConstraint fields from questions/options.
src/​data/​distros.json Updates many distro attributes, dedupes Artix, and adds new distro entries.
src/​components/​ResultsView.vue Removes score UI and switches to “why it matches” reason chips.
src/​components/​DistroCard.vue Removes score UI and updates card/detail views to show reasons + confidence label.
scripts/​validate-distro-invariants.ts Replaces ad-hoc checks with findInvariantViolations and compare-view key validation.
scripts/​distro-invariants.ts Introduces semantic dataset invariants (identity, freshness, satisfiable answers, compare-view keys, etc.).
i18n/​locales/​pt.json Adds/adjusts keys for new UI text, reasons, and constraints.
i18n/​locales/​nl.json Adds/adjusts keys for new UI text, reasons, and constraints.
i18n/​locales/​it.json Adds/adjusts keys for new UI text, reasons, and constraints.
i18n/​locales/​fr.json Adds/adjusts keys for new UI text, reasons, and constraints.
i18n/​locales/​es.json Adds/adjusts keys for new UI text, reasons, and constraints.
i18n/​locales/​en.json Adds translation for new architecture exclusion reason.
i18n/​locales/​de.json Adds/adjusts keys for new UI text, reasons, and constraints.
docs/​evidence/​new-distros-tier2.md Adds evidence table for tier-2 distro additions (method + sources).
docs/​evidence/​distro-attributes-ubuntu-family.md Adds verification notes/sources for Ubuntu-family-related attribute semantics.
docs/​evidence/​distro-attributes-arch-strict.md Adds verification notes/sources for Arch-family-related attribute semantics.
docs/​evidence/​coverage-non-arch.md Adds coverage analysis + rationale for included/excluded non-Arch distros.
docs/​evidence/​coverage-arch-gaming-desktop.md Adds coverage analysis + rationale for Arch/gaming/desktop distro inclusion decisions.
docs/​distro-data-evidence.md Documents operational definitions + verified values and deltas in the dataset.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/engine/state.ts
Comment on lines +1185 to 1188
// Single survival authority: eliminate.ts. The results page applies exactly the
// same rules as /compare and the persona suite — no second, weaker filter.
const compatibility = buildCompatibility(intent);
const distrosById = new Map(distros.map((distro) => [distro.id, distro] as const));
Comment on lines +123 to +129
// Within a group of equal fit, the order is alphabetical by name — never by a
// hidden score. Groups are keyed by (strict matches, stated-preference matches).
const keys = presentation.compatible.map((item) => ({
strict: item.matchedConstraints.length,
preferences: item.includedBecause.length,
name: item.name,
}));
Comment thread tests/ranking.spec.ts
Comment on lines +51 to +55
const keys = presentation.compatible.map((item) => ({
strict: item.matchedConstraints.length,
preferences: item.includedBecause.filter((reason) => reason !== "include_meets_requirements").length,
name: item.name,
}));
Comment thread tests/ranking.spec.ts
Comment on lines +71 to +72
const ubuntu = keys.find((key) => new Set(presentation.compatible.map((item) => item.name)).has("Ubuntu"));
expect(ubuntu).toBeDefined();
…ault

pnpm 11 fails the install with ERR_PNPM_IGNORED_BUILDS for @parcel/watcher and
esbuild unless they are explicitly approved, which is what stopped the first
CI run that actually reached an install step. Approving exactly these two
package names (esbuild covers both pinned versions) keeps the stricter default
for everything else rather than disabling it wholesale.
…1 allowBuilds)

pnpm 11 ignores the package.json "pnpm" field entirely and fails the install with
ERR_PNPM_IGNORED_BUILDS unless each dependency needing a lifecycle script is named
in pnpm-workspace.yaml. The key is allowBuilds (a name -> true map), which is what
pnpm approve-builds writes itself; onlyBuiltDependencies in the same file did not
take effect. @parcel/watcher and esbuild are the only two, and everything else
keeps the stricter default. The ignored package.json#pnpm field left by the
previous attempt is removed.

Verified: pnpm install --frozen-lockfile exits 0 and leaves pnpm-lock.yaml
unchanged.
'nuxt typecheck' needs both, and neither was declared: typescript was only
present transitively, so a clean CI install made Nuxt fetch it through npx and
that fetched TypeScript 7, whose exports map no longer provides './lib/tsc'
(ERR_PACKAGE_PATH_NOT_EXPORTED). Pinning typescript 5.9.3 — the version the
gates were verified against locally — and vue-tsc 3.3.11 keeps the gate
deterministic. Verified: pnpm typecheck exits 0 with the declared toolchain.
Removals, both from the coverage evidence in docs/evidence/:

- feren_os: no release since 2025.03 (2025-04-10) after a ~4.5-year gap, and the
  project's own post concedes it; DistroWatch's 6-month rank slid to 253.
- bodhi_linux: DistroWatch status "Dormant", last release 7.0.0 (2023-08-21).

A picker's worst failure mode is confidently recommending something unmaintained,
so an entry that cannot be verified as alive does not stay in the dataset. Both
were proprietarySupport OPTIONAL and neither appeared in a persona's top five, so
no snapshot moved.

centos_stream stays but now says what it is: "RHEL's upstream development
branch: a rolling preview of the next RHEL release, without the long lifecycle of
a stable server distribution." It is maintained, so removing it would lose
information; the confusion came from the description.

Tests: tests/distros.ferenos.spec.ts is deleted with the entry. Two tests used the
removed entries as their examples and now use live ones —
pickerIntegration.spec.ts takes Debian for the APT-match-but-not-runit case, and
compatibility.spec.ts's docs-ecosystem test uses antiX (compatible under the same
answers, docs only OK) instead of Bodhi.

Dataset: 62 -> 60 entries. Gates: typecheck 0 | test 93/93 (14 files) | validate
PASSED | validate:invariants PASSED over 60 entries | lint 0.
@GionaGranchelli
GionaGranchelli merged commit dbb21d4 into master Sep 28, 2026
2 checks passed
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.

2 participants