Skip to content

Paths audit follow-ups: no path detail page, slug never uniqueness-checked, stale gate-4a doc, draft-with-courses renders #974

Description

@thomgabriel

Smaller findings from the 2026-08-04 paths-feature audit (the CRITICAL _draft/ divergence is #973). All verified with file:line evidence; none merge-gating on its own.

  1. No learner-facing path page (MEDIUM, scope decision). Paths exist only as a tab in /courses; the only /paths route is the admin table. No /paths/[slug] → paths are not deep-linkable/shareable, and per-path progress has no home. Related latent bug: slug is required by the schema (path.ts:27) and projected, but consumed by nothing and not uniqueness-checked (gate-2 covers ids only) — a silent collision the moment slug routing is added. Decide: ship a path detail page, or record "tab-only for launch" explicitly.
  2. Stale doc contradicts a working gate (LOW, quick fix). achievements/README.md:49 (academy-courses) says award refs are unverified, "double-check them by hand" — but gate-4a verifies exactly this at ERROR tier including the empty-path case. Tells authors a working gate doesn't exist.
  3. Draft-with-courses renders (LOW). paths-view.tsx filters on courses.length > 0 only (deliberate, tested, commented — content-lint: verify achievement award refs; rule on the dead path draft flag #627): a draft: true path that HAS courses would render to learners. Schema only forces draft on empty paths. One-line runtime filter or a lint gate ("draft paths must be empty") closes it; moot today with one live non-draft path.
  4. gate-13a: detect contradictory course orderings across multiple paths #910 clarification (already filed). The cross-path ordering gate does not exist; gate-13a is capabilities and accumulates into one shared map with no conflict detection (gate13a-capabilities.ts:72-89) — contradictory orderings pass silently. Unfireable with one path; re-arms the moment a second populated path lands (e.g. an alpha path for the new courses).
  5. Stale content.lock note (expected, not a defect). The monorepo pins 23e4d1bf, predating content PRs Feat/lms bounty 26 02 2026 #31/Superteam fromancient #32generated/paths.json still carries all 8 old paths (7 empty drafts), which today's gate-4b would reject. Self-resolves on the next lock bump; noting so nobody mistakes the pinned bundle for current content-repo state.
  6. Golden-fixture doc-comment nit (LOW). content-schema/src/path.ts:15-17 claims the bundle's LearningPath carries neither lifecycle flag; the projector's spread (projector.ts:174) does carry draft/retired into paths.json. Conclusion (no consumer reads them) is right; the stated reason is wrong.

For contrast, verified GOOD and worth keeping as-is: schema refine + gate-4b lifecycle rules; gate-4a's never-exhaustive award-kind switch; paths-view empty state + one-clear-start with tests; getAllLearningPaths gating members to synced deployments; the path-completed predicate's vacuous-truth guard (achievements.ts:180-191, the PR #892 lesson).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions