Skip to content

Make feature ordering non-load-bearing (and fix a real collision)#24

Merged
DanMat merged 1 commit into
mainfrom
refactor/feature-registry
Jul 26, 2026
Merged

Make feature ordering non-load-bearing (and fix a real collision)#24
DanMat merged 1 commit into
mainfrom
refactor/feature-registry

Conversation

@DanMat

@DanMat DanMat commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Features merge their fragments in array order, so a collision between two of them was resolved silently by position — the fragility the architecture review flagged under "make feature ordering explicit."

The approach

Rather than build speculative phase/requires/conflictsWith machinery that nothing yet needs, this enforces the invariant that actually matters: no two features may own the same file or package.json field for a given config. test/feature-registry.test.js asserts unique feature ids and zero collisions across the full matrix (1683 configs), using the collision diagnostics the embedded API already computes. A colliding new feature now fails CI instead of shipping an order-dependent bug.

It found a real one

On node-service, both bundler and service set scripts.dev — and only array order (service listed last) made the correct tsx watch src/index.ts win over the bundler's tsup --watch. Reorder the registry and the service would silently get the wrong dev command.

Fixed by making the service the explicit owner of its dev script; the bundler no longer contributes dev for a service target.

Output is byte-identical — the service won the merge before and owns it outright now. node-service is still 31 files with dev: tsx watch src/index.ts. Also documented the ordering contract in the feature registry.

96 tests pass (2 new), lint clean, web configurator verified.

🤖 Generated with Claude Code

…ision)

Features merge their fragments in array order, so a collision between two
of them was "resolved" silently by position — the exact fragility the
architecture review flagged.

Rather than build speculative phase/requires/conflictsWith machinery, this
enforces the invariant that actually matters: no two features may own the
same file or package.json field for a given config. test/feature-registry
.test.js asserts unique feature ids and zero collisions across the full
matrix (1683 configs), so a colliding new feature fails the test instead
of shipping an order-dependent bug.

That immediately surfaced a real one: on node-service, both `bundler` and
`service` set scripts.dev, and only array order (service last) made the
correct `tsx watch` win over `tsup --watch`. Fixed by making the service
the explicit owner of its dev script — the bundler no longer contributes
`dev` for a service target. Generated output is byte-identical (service
won the merge before, owns it outright now); node-service is still 31
files with `dev: tsx watch src/index.ts`.

96 tests pass (2 new), lint clean, web configurator verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@DanMat
DanMat merged commit e575118 into main Jul 26, 2026
37 checks passed
@DanMat
DanMat deleted the refactor/feature-registry branch July 26, 2026 20:51
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