refactor(core): decouple snapshot type from engine (v0.3.2) - #10
Merged
Conversation
Move the CountdownSnapshot interface out of api/countdown-engine.ts into a leaf module (src/model/countdown-snapshot.ts), removing the format/ -> api/ layer inversion. The public API is unchanged: the type is still re-exported from the package root barrel with an identical six-field shape, so consumers importing it from @timekeeper-countdown/core are unaffected. Two sibling structural fixes ride along: - Collapse the three repeated time-validity guards in runtime/time-providers.ts into one module-private isValidTime(), restoring the <= MAX_SAFE_INTEGER upper bound the fallback path had dropped. This is internal only (createSafeTimeProvider is not exported) and unreachable for a real Date.now(). - Make the published testing-utils buildSnapshot delegate to the engine's canonical buildSnapshot, so the test double can no longer drift from production (single source of truth for parts, isRunning and isCompleted). Its signature and output are unchanged. Add property and contract tests (time-provider coercion boundaries; snapshot-double/engine equivalence) and expand the per-unit mutation suites. Also document the src/model and src/time/clamp modules in CLAUDE.md and clarify in CONTRIBUTING that the Node 22 prerequisite is the build/dev toolchain, while the published packages support Node >= 18 at runtime.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Structural, internal-only refactor of
@timekeeper-countdown/core, plus the lockstep v0.3.2 patch release of both packages. No public API or behavior change — this is aPATCH(verified by a release-readiness audit: the moved type stays barrel-exported with an identical shape, and the only touched behavior is an unreachable, non-exported internal guard).CountdownSnapshotinterface out ofapi/countdown-engine.tsinto a dedicated leaf modulesrc/model/countdown-snapshot.ts, removing theformat/ → api/layer inversion. It is still re-exported from the package root barrel with a byte-identical six-field shape, so consumers importing it from@timekeeper-countdown/coreare unaffected.runtime/time-providers.tsinto one module-privateisValidTime(), restoring theMAX_SAFE_INTEGERupper bound the fallback path had dropped. Internal only (createSafeTimeProvideris not exported) and unreachable for a realDate.now().testing-utilsbuildSnapshotnow delegates to the engine's canonicalbuildSnapshot, so it can no longer drift from production (sameparts/isRunning/isCompletedrules). Signature and output unchanged.src/modelandsrc/time/clampmodules inCLAUDE.md; clarify inCONTRIBUTINGthat the Node 22 prerequisite is the build/dev toolchain, while the published packages support Node ≥ 18 at runtime.Type of Change
v0.3.2version bumpHow to Test
npm installbin/quality-gate.sh— full gate (build + format:check + lint + typecheck + test) is green: core 453 tests, react 18.import type { CountdownSnapshot } from '@timekeeper-countdown/core'(type-only, unchanged shape).Checklist
npm run lintpassesnpm run typecheckpassesnpm run testpassespackages/*/CHANGELOG.md) — recorded as an internal-only note for the0.3.2release (not a user-facing change), and mirrored indocs/changelog.mdCLAUDE.md,CONTRIBUTING.md)