Skip to content

Migrate off the shadcn contract pin (v2.3.0 → production v3.0.0) #28

Description

@ryandmonk

input/shadcn-ui.dspack.json is pinned to 805732c (shadcn/ui v2.3.0, 8 components) rather than tracking dspack@main, which now carries the v3.0.0 production contract (32 components, 14 worked examples) merged in aestheticfunction/dspack#35.

Full record, including provenance and enforcement: docs/CONTRACT-PIN.md.

The pinned contract is not current shadcn/ui coverage. It describes 8 of the 32 components the contract now governs.

Why the pin exists

This package's shadcnProfile, the shadcn renderers, and the profile-parity invariants were all designed against v2.3.0. Following main immediately produces a broken catalog, not a bigger one.

Measured on a bare local sync (2026-08-05):

Gap Measurement
Worked examples that refuse to emit 12 of 14
Components with no classification 24 of 32 (profile maps 6, declares 2 casualties)
Sub-components needing subCoverage 106 (39 today)
Renderers silently misrendering 7 of 22 emitted instances, six renderers
Declared checks resolving to {} 5 components — no functions path in the profile format

The parity suite fails 14 tests. The two completeness invariants fail for a reason profile authoring cannot fix cleanly: the suite asserts every worked example emits, which the production contract cannot satisfy until refusal-for-an-acknowledged-reason is a first-class outcome.

Declaring 24 new casualties to make the sync green was considered and rejected — those components are "not mapped yet", not "cannot represent", and overloading the casualty vocabulary weakens the fail-closed gate it exists to power.

Removal condition

Replace the pin only after the representation-foundation milestone is implemented and measured:

  • profile v2 schema + explicit profileVersion dispatch
  • v1 directive desugaring into the internal Identity/Route/Collect model
  • load-time validation of selectors and destinations
  • EmitSurfaceResult.fidelity + --strict-surface
  • sub-component coverage derived and enforced from the internal model
  • six shadcn renderer drifts repaired, with props-level parity tests
  • functions support on the profile/catalog path
  • parity invariant 1 restated as every worked example either emits, or refuses for a declared-casualty reason the contract itself acknowledges

Then: remove the pin block, node scripts/check-sync.mjs --write, regenerate derived catalogs and json-render goldens, commit together.

Enforcement

scripts/check-sync.mjs verifies the pinned artifact's sha256 on every CI run (a pinned ref must be immutable), fails on local drift, and always reports how far behind main the pin sits — so it can never quietly read as current.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions