Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Porting Workflow

Audience: contributors porting functionality into Pulse from an external source — a predecessor project, a one-off prototype, an upstream library being absorbed.

Porting is more error-prone than greenfield work. The mistakes cluster around two pitfalls: leaking the source project’s naming through, and writing tests against the source’s behaviour rather than the Pulse-native shape the new code should expose. This workflow exists to keep both at bay.

1. Map the boundary

Identify the source behaviour you are porting and the Pulse package that will own the result. The destination is rarely a 1:1 mirror of the source — Pulse’s package layout (library-first facade, no business logic in cmd/pulse/, all I/O through the injected afero.Fs) often demands a refactor on the way in.

2. Write Pulse-native tests first

Write the destination package’s tests in Pulse-native form before porting any source code. Every identifier — type names, error codes, constants — uses Pulse conventions (AGG_*, PULSE_*, SCREAMING_SNAKE for component types, DOMAIN_CATEGORY for error codes). No predecessor-project string prefixes leak in.

3. Confirm the tests fail informatively

Run go test ./... and confirm the new tests fail with informative messages. If they pass without the implementation, the test is wrong — fix it. A green test before the implementation lands is almost always a sign that the test is asserting on the wrong shape.

4. Port the implementation

Port the source code into the destination package. Refactor for Pulse-native idioms as you go — there is no benefit to landing a direct copy and then refactoring later. Embedders and reviewers will read the final shape, not the migration trace.

5. Re-run tests until green

Iterate on the implementation until the tests pass. If a test refuses to come green, lean on the test rather than the implementation — porting often surfaces edge cases the source project handled implicitly.

6. Update target skill and CLAUDE.md

Update the target skill file(s) per The Update Demand. Run the skill-coverage gates locally (see Running CI Gates Locally). Update CLAUDE.md if the change touches a contract, env var, format version, or registered surface.

7. Predecessor-reference scrub

Run the hygiene gate before opening the PR and confirm zero matches:

go test . -run TestNoOrbit

The gate is non-skippable; CI will catch any leak, but catching it locally saves a round-trip.

8. Open the PR

Follow the Pull Request Process. The porting PR is otherwise identical to any other PR — same Update Demand obligations, same test-first preference, same Conventional Commits subject line.