Repository navigation
refactor: separate task execution from collection tracking - #59
Merged
Merged
Conversation
This was referenced Sep 6, 2026
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.
Problem
The public API file mixes service provisioning, task overload adaptation, collection execution, outcome counters, and an unusual result-mode completion rule. To follow
Progress.all, a maintainer must unpack a nested exit handler while keeping automatic scope management in mind. The single helper inutils.tsalso has no obvious owner.Solution
Organize execution around three concrete responsibilities:
api/provide-progress.tsreuses an existing Progress service or provides a scoped instance around the operation.api/task.tsadapts the public single-task entry point to the service's task runner.api/collections.tskeepsall,forEach, their execution types, and shared outcome accounting together.trackEffectOutcomenames the per-item counting responsibility.completeAccountedResultTasknames the exceptional result-mode completion rule.Move
inferTotalfromutils.tstoapi/infer-total.ts. Explicit API and package-root exports preserve the existing functions and option/return types. Update the service comment to point to the task entry point's new location.Examples
Following nested execution
Progress.task(effect, options)entersapi/task.ts, which usesprovideProgressand delegates toprogress.task. To investigate reuse versus an isolated service, openprovide-progress.ts; the collection execution code no longer contains that implementation.Understanding result-mode defects
For
Progress.all([Effect.die(defect)], { description: "work", mode: "result" }), the one unit is accounted for as failed. The collection still exits with the defect, while its task is marked done because all work was accounted for. With another unprocessed unit, the task remains eligible for failure finalization instead.completeAccountedResultTaskmakes that distinction explicit without changing the effect exit.Counting interrupted work
Both collection helpers use
trackEffectOutcome: successful work increments succeeded, failed work increments failed, and interruption-only exits do not increment either counter. That policy remains shared rather than duplicated acrossallandforEach.Validation
bun test: 130 passed, 0 failed, 396 assertions.bun run check: typecheck, lint, formatting, and Knip passed.bun run formatapplied; staged diff whitespace check passed.Existing tests exercise defects in default/result modes, interruption, explicit finalization, service reuse, tuple/record inference, pipe forms, and total inference. Non-failing TSGO suggestions remain in existing schema definitions/tests. No build or dev server was run.
Review notes
This layer follows type ownership. Start with
completeAccountedResultTaskand its call site, then the small task/provisioning modules. The collection algorithms, options, public overloads, and scope boundaries are retained; no new generic execution framework is introduced.Stack
GitHub stack #63:
main→ #58 (types) → #59 (execution) → #60 (ETA) → #61 (tests) → #62 (examples). Each PR is based on the layer below it, so its diff contains only that concern. Manage the chain withgh stack; no PR has been merged by this change.