Repository navigation
feat(coordinator)!: plan and run builds through build_release - #652
Merged
Merged
Conversation
This was referenced Nov 3, 2026
karhu
force-pushed
the
tnet-157/5-build-release
branch
from
November 4, 2026 12:01
781fc7b to
5ead89d
Compare
This was referenced Nov 4, 2026
karhu
force-pushed
the
tnet-157/5-build-release
branch
from
November 4, 2026 12:42
5ead89d to
b5efc4b
Compare
karhu
commented
Nov 4, 2026
This was referenced Nov 4, 2026
karhu
marked this pull request as ready for review
November 4, 2026 13:41
TimoStoff
approved these changes
Nov 4, 2026
TimoStoff
left a comment
Contributor
There was a problem hiding this comment.
LGTM! Thank you. The main issue here again is sloptests and really hard to read Claude comments
karhu
force-pushed
the
tnet-157/5-build-release
branch
from
November 4, 2026 20:02
af8dec3 to
dad0160
Compare
This was referenced Nov 4, 2026
karhu
force-pushed
the
tnet-157/5-build-release
branch
4 times, most recently
from
November 7, 2026 15:20
eea11c2 to
9fe4442
Compare
karhu
force-pushed
the
tnet-157/5-build-release
branch
from
November 10, 2026 14:39
9fe4442 to
c6d0a03
Compare
karhu
force-pushed
the
tnet-157/5-build-release
branch
from
November 10, 2026 15:50
c6d0a03 to
f55c7a0
Compare
karhu
force-pushed
the
tnet-157/5-build-release
branch
from
November 10, 2026 16:24
f55c7a0 to
fd2d755
Compare
There was a problem hiding this comment.
Code review completed
Nothing new to post: everything this review found is already covered by existing comments on this pull request or didn't merit a separate one.
Still open from earlier reviews (1):
- 🔴
packages/timenet/src/timenet/coordinator/build.py:105—When the store already holds the requested release, a copy of a missing payload source also pulls that source's own pay…
If you have decided not to act on one of these findings, resolve its thread (a reply alone leaves it open) and the next review stops counting it. To review this commit again now, use Re-run on its "Claude Code Review" check.
build_release() in timenet.coordinator.build builds one release into a local store, after each release that its build needs. It finds the backend that claims the dataset. If the caller asks for another version than the card declares, it raises TimeNetVersionUnavailableError before anything runs. Then it plans with plan_parents(), adds the build of the requested release, and runs each step in order. A copy step uses copy_release(). If the store holds the release intact, the step copies only each payload source that the store lacks or holds damaged. A build step calls build_prepared() of the backend for that exact release. Each step sends StepStarted and StepFinished. Only the requested release gets force. build_release() returns the Plan that ran. The BuilderBackend protocol gets two methods. dataset_ids() lists the IDs of the datasets that a backend builds. build_prepared(release, store, *, force, pinned_by, options) builds exactly one release into a local store that holds each parent of the release, and each payload source of such a parent. BuildOptions holds keep_cache and the progress callback. find_builder() returns the first backend whose dataset_ids() holds the ID. knows(), declared_version() and build() stay for now. ConnectorBuilder lists its dataset IDs with known_ids() of timenet_connectors.discovery. known_ids() reads the cards on disk and imports no connector. A card that cannot be read raises TimeNetInvalidCardError, which names the file. A dataset ID matches only the ID that a card declares, so the module spelling, such as timenet/hello_world, no longer resolves. The build command checks the ID against known_ids() and shows the usage error with the known IDs. TimeNetVersionUnavailableError is a TimeNetDatasetNotFoundError and a TimeFValidationError. It carries the requested release and the declared version. plan_parents() takes open_access_only. With it, a local store gets the same access checks as a registry that is not local, also for the card and the lineage of a requested release that the store already holds. If the output is not local or open_access_only is set, the planner checks the access of the requested card first, also for a dataset without parents. BREAKING CHANGE: a BuilderBackend must implement dataset_ids() and build_prepared(). find_builder(), timenet-build build and timenet_connectors.build() no longer accept the module spelling of a dataset ID. Part of TNET-157.
BuildOptions gets quiet. It asks the backend to print nothing of its own. An isolated child otherwise prints its build lines and downloads to the inherited stderr. Before, a backend could only guess this from a missing progress callback, so an SDK build with no callback silenced the child too. The protocol docstring of build_prepared() names quiet and the progress callback, and names TimeNetVersionUnavailableError for another version. TimeNetVersionUnavailableError now says what to do: ask for the version that the connector builds, or leave out the version. The hint attribute stays for front ends. Part of TNET-157.
The docstring now says this backend is not ConnectorBuilder and the plan never builds through it. Part of TNET-157.
Say that the coordinator is internal to TimeNet and point users to the build command and the client. Part of TNET-157.
…protocol docstrings The build command now asks ConnectorBuilder().dataset_ids() for the known dataset IDs, as any other caller of the builder protocol does. So known_ids() is now private and is called _known_ids(). The BuilderBackend docstring now states the contract for an implementer, and the card() docstring and the summary of the coordinator build module say less about the planner. Part of TNET-157.
Say only what a caller of the release build needs to know. Part of TNET-157.
…once find_builder(), find_card() and exact_builder() now share one private lookup. A registered backend without dataset_ids() fails with a TimeFValidationError that names its entry point, not an AttributeError. build_release() parses the requested reference once. Before any step runs, it makes sure that a plan with a copy step has a registry to copy from. Its docstring names each error in one line. known_ids() in timenet_connectors.discovery is public again. The build command calls it, and ConnectorBuilder.dataset_ids() wraps it. A card without a dataset_id now fails the list with TimeNetInvalidCardError, as a card that is not a mapping does. The ruff rule against an import of timenet_connectors replaces the subprocess test of the build coordinator. Tests that only checked a dataclass default, a step report that another test covers, or that a lookup ignores knows() go away. The check that the version error is a not-found error and a validation error moves into the parametrized error test. Two client tests now install their builder through the entry points, because find_card() no longer goes through find_builder(). Part of TNET-157.
Shorter docstrings for the code that this change adds or changes. Part of TNET-157.
One connector card that could not be read made known_ids() raise. So every lookup through the installed connectors failed, also for other datasets. Now known_ids() skips that card with a ConnectorCardWarning, and only its own dataset fails. timenet-build build refused org/name@version. It now takes the version and checks it against the card of the connector. builders.installed_builder() walks the entry points once and returns an InstalledBuilder: the backend with its card. builders.declared() also checks a requested version, and it raises the one "no installed connector builds" error. Both replace find_builder() and exact_builder(). The check for a backend without dataset_ids() goes, because the builder protocol requires the method. The coordinator docstring says that the front ends share the planner. BREAKING CHANGE: builders.find_builder() is gone. Use builders.installed_builder(). Part of TNET-157.
karhu
force-pushed
the
tnet-157/5-build-release
branch
from
November 10, 2026 17:41
fd2d755 to
5a98da8
Compare
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.
The Stack
This stack covers refactoring the internal logic of how releases are resolved during read, download & build, in particular also in the context of parent releases / parent datasets. On top of that it refactors the public TimeNet APIs and CLI interfaces around these actions, to streamline the behavior across them.
This PR
Adds the build coordinator,
build_release(), next to the old build path. Later PRs in the stack move the callers onto it.Details
TimeNet starts a build on five paths, and each path plans and runs the build in its own way (TNET-157). The coordinator is the one place that plans a build and runs its steps.
timenet.coordinator.build.build_release(dataset, *, store, fetch_from, build_parents, force, pinned_by, open_access_only, options)builds one release into a local store, after each release that its build needs. It returns thePlanthat ran.TimeNetVersionUnavailableErrorbefore anything runs.plan_parents(), adds the build of the requested release, and runs each step in order. A copy step usescopy_release(). A build step callsbuild_prepared()of the backend for that exact release. Each step sendsStepStartedandStepFinished.BuilderBackendprotocol getsdataset_ids()andbuild_prepared(release, store, *, force, pinned_by, options).BuildOptionsholdskeep_cache, the progress callback andquiet. Unlessquietis set, an isolated child prints its shards and downloads to the inherited stderr.builders.installed_builder()returns anInstalledBuilderwith the first backend whosedataset_ids()holds the ID, and the card of the dataset.builders.declared()also checks the version. It raisesTimeNetDatasetNotFoundErrorfor an unknown ID andTimeNetVersionUnavailableErrorfor another version.BuildOptions.keep_cacheandquietare not read in this PR.ConnectorBuilder.build_prepared()in feat(build)!: build one prepared release in the built-in backend #653 reads them.ConnectorBuilder.dataset_ids()lists the IDs of the cards on disk and imports no connector. It wrapsdiscovery.known_ids(), which thebuildcommand calls to check an ID.timenet-build buildtakes a dataset ID or an exact release,org/name@version. For another version than the card declares, it raisesTimeNetVersionUnavailableErrorbefore anything runs.plan_parents()takesopen_access_only. With it, a local store gets the same access checks as a registry that is not local. The checks cover the card and the lineage of a requested release that the store already holds.Design decisions
timenetand imports nothing fromtimenet_connectors, so any package can provide a backend. A ruff rule that bans the import makes sure of that.builders.declared(), which the coordinator and the build command call.TimeNetVersionUnavailableErroris aTimeNetDatasetNotFoundErrorand aTimeFValidationError, so the error handlers of both current callers keep working.force. The coordinator does not build again a parent that the store holds intact.DatasetIdis case-sensitive and allows_, sotimenet/hello_worldis a different ID fromtimenet/hello-world. For an unknown ID,timenet-build buildstill shows the usage error with the list of known IDs.discovery.known_ids()skips a card that cannot be read, or that has nodataset_id, with aConnectorCardWarningthat names the file. So a broken card fails only its own dataset. The card tests read every card, so CI finds such a card first.timenet.coordinator.Breaking changes
BuilderBackendmust implementdataset_ids()andbuild_prepared().builders.find_builder()andbuilders.exact_builder()are gone. Usebuilders.installed_builder(), orbuilders.declared()to check the version too.timenet-build buildandtimenet_connectors.build()no longer accept the module spelling of an ID, such astimenet/hello_world. Use the ID from the card,timenet/hello-world.Stack
Changes later in the stack:
ConnectorBuildergetsbuild_prepared()in feat(build)!: build one prepared release in the built-in backend #653. Until then, only the tests callbuild_release().timenet_connectors.build()ontobuild_release(), and feat(build)!: run every build through the coordinator #655 moves the client. feat(build)!: run every build through the coordinator #655 removesknows(),declared_version()and the oldbuild()from the protocol, and renamesbuild_prepared()tobuild(). Until feat(build)!: move the build CLI and build() onto the coordinator #654,timenet_connectors.build()accepts the module spelling of an ID and then raises its documentedLookupError.fetch_from=andbuild_parents=arguments ofbuild_release()are thin glue for the current callers. "Client reads on the coordinator" replaces them.Merge message