ADR 0267 (proposed): an artifact is rebuilt only when its build source changes
A merge to a shared repository moved every module that read it, in a gated tier each (issue 338). The operator's rule maps a change onto the artifacts whose build source it touches and adds only modules with a build dependency on a changed artifact; sharing a repository is no dependency. Supersedes in part ADR 0162 decision 1 (the packages kind) and ADR 0238 decision 3 (whole repository and context reads); adds build source to the glossary.
This commit is contained in:
@@ -300,6 +300,15 @@ planner, the walk). **Downstream of** Module, Core, Health and repair and Data.
|
||||
([ADR 0156](../02-DECISIONS/0156-an-artifact-is-what-a-build-produces-and-the-store-is-named-for-its-scope.md)).
|
||||
An image is one kind of artifact, and a module is not an image. A package and an artifact are two
|
||||
protocols, not one store being weak ([ADR 0075](../02-DECISIONS/0075-two-stores-and-which-provides-what.md)).
|
||||
- **build source** — the files one artifact is built from, in one or more repositories: for a Go program
|
||||
its import closure (the directories of its packages, its Go module files) and its recipe; for any other
|
||||
artifact the paths its manifest names, by default its module's own directory. Each artifact of a build
|
||||
has its own, and a change rebuilds the artifacts whose build source it touches
|
||||
([ADR 0267](../02-DECISIONS/0267-an-artifact-is-rebuilt-only-when-its-build-source-changes-and-a-module-moves-only-along-build-dependencies-on-artifacts.md),
|
||||
proposed). Older records (ADR 0015, ADR 0111) and designs say *build source* for the repository a module
|
||||
is built from; this entry narrows it to the files within, and that use reads as *the repository holding
|
||||
the build source*. Sharing a repository is not a dependency, and no build source is a whole repository
|
||||
holding another module's files.
|
||||
- **catalogue** — what the mesh holds of every module, at which commit; and the repository the
|
||||
modules live in. `mesh-catalog` and `catalog_modules` are identifiers and keep their spelling.
|
||||
*Not:* ~~catalog~~ (hq)
|
||||
|
||||
@@ -11,6 +11,13 @@ extends: 02-DECISIONS/0157-a-build-says-what-it-does-on-the-bus-as-it-happens.md
|
||||
|
||||
> **Progressive insight — 2026-10-02.** The context below says a dependent is *built by whichever build machine is running — the only one there could be*. That was a fact of the day, not of the decision: since [ADR 0190](0190-a-seats-work-is-shared-by-its-holders-and-building-is-the-first-such-role.md) a tier's asks are taken by every machine holding the build seat. The plan and its tiers are unchanged.
|
||||
|
||||
> **Superseded in part — 2026-10-08, by [ADR 0267](0267-an-artifact-is-rebuilt-only-when-its-build-source-changes-and-a-module-moves-only-along-build-dependencies-on-artifacts.md) (proposed; it takes effect when it is accepted).**
|
||||
> In decision 1, the `packages` kind ("the module's build reads the other's repository") and the *code*
|
||||
> dependency ("B packages A's source … rebuilt whenever A changes, in the same tier") no longer hold: a file
|
||||
> two modules build from moves both through their build sources, and no edge is drawn for sharing a
|
||||
> repository. `stands-on` and `declared` name an artifact at each end. The build and runtime dependencies,
|
||||
> `built-by`, and decisions 2 to 4 stand as decided here.
|
||||
|
||||
## Context
|
||||
|
||||
A merge on the forge reaches the controller as an event, and the controller asks the build
|
||||
|
||||
+5
@@ -16,6 +16,11 @@ extends: 02-DECISIONS/0227-the-core-holds-nine-rules-each-checked-and-is-built-t
|
||||
> no core module starts on that module's word, and *held* is a delivery's state, released by a person through
|
||||
> `mesh-delivery`'s `release`. These are the gate rules ADR 0239 applies when a member of a delivery group fails.
|
||||
|
||||
> **The mechanism changed — 2026-10-08, by [ADR 0267](0267-an-artifact-is-rebuilt-only-when-its-build-source-changes-and-a-module-moves-only-along-build-dependencies-on-artifacts.md) (proposed; it takes effect when it is accepted).**
|
||||
> What stands: a rebuild that changes nothing is no move. What moved: the source fingerprint of the issue 280
|
||||
> insight below is taken per artifact over its build source, not per build over the module's directory and
|
||||
> each context's whole repository, and an artifact with an equal fingerprint is not built again.
|
||||
|
||||
## Context
|
||||
|
||||
**The operator said "start phase 4"** of [to-be 45](../03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md)
|
||||
|
||||
+6
@@ -18,6 +18,12 @@ extends: 02-DECISIONS/0237-a-change-is-judged-against-the-mesh-that-runs-before-
|
||||
> leads to the delivery's view on the pull request. The *change plan* is called the **delivery plan**. Decisions
|
||||
> 1 to 5 stand as decided here.
|
||||
|
||||
> **Superseded in part — 2026-10-08, by [ADR 0267](0267-an-artifact-is-rebuilt-only-when-its-build-source-changes-and-a-module-moves-only-along-build-dependencies-on-artifacts.md) (proposed; it takes effect when it is accepted).** In
|
||||
> decision 3, "the whole repository for a module built from its root, and a repository a recipe names (the
|
||||
> build record's `read`)" no longer holds: a changed file touches the artifacts whose build source contains
|
||||
> it, and through them their modules. The one mapping function, a file read by no build touching nothing,
|
||||
> and a new `module.json` being a new module, stand.
|
||||
|
||||
## Context
|
||||
|
||||
[ADR 0237](0237-a-change-is-judged-against-the-mesh-that-runs-before-it-merges-on-the-build-seat.md) put a
|
||||
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
---
|
||||
topic: building it
|
||||
status: proposed
|
||||
date: 2026-10-08
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
supersedes-in-part:
|
||||
- 0162-a-merge-produces-a-tiered-plan-the-mesh-keeps.md
|
||||
- 0238-a-commit-is-the-build-at-hand-one-commit-one-change-plan-checked-off-the-trunk-and-published-only-on-it.md
|
||||
extends: 02-DECISIONS/0238-a-commit-is-the-build-at-hand-one-commit-one-change-plan-checked-off-the-trunk-and-published-only-on-it.md
|
||||
---
|
||||
|
||||
# 267. An artifact is rebuilt only when its build source changes, and a module moves only along build dependencies on artifacts
|
||||
|
||||
## Context
|
||||
|
||||
The operator stated the rule on 2026-10-08, in their words:
|
||||
|
||||
> If only files for module A changed, only module A is taken into the deploy plan. Then the deploy plan
|
||||
> checks our module graph to check which modules have a dependency on the changed module. However, 1
|
||||
> commit might change files from more than 1 module in a repository.
|
||||
|
||||
> a change to A … moves A and all modules with a build dependency on A
|
||||
|
||||
> you should only check the build dependencies in the module graph in our module catalog
|
||||
|
||||
And: sharing a repository is not a dependency — "there is no repository dependency". What the operator
|
||||
calls the *deploy plan* is, in the glossary's words, the delivery plan's **build plan**: the modules a
|
||||
delivery moves and their dependents, in tiers. The glossary's *deploy plan* is only its per-node part.
|
||||
|
||||
### How a merge reaches the nodes today
|
||||
|
||||
This description was read from the records and from mesh-controller at `8170fc5`, and confirmed by the
|
||||
operator before this record was written.
|
||||
|
||||
- **A pull request is a delivery** ([ADR 0239](0239-a-delivery-is-owned-by-the-mesh-delivery-module-and-runs-from-commit-to-delivered.md)):
|
||||
checked by the merge gate and the repository check ([ADR 0238](0238-a-commit-is-the-build-at-hand-one-commit-one-change-plan-checked-off-the-trunk-and-published-only-on-it.md) §4,
|
||||
[ADR 0237](0237-a-change-is-judged-against-the-mesh-that-runs-before-it-merges-on-the-build-seat.md)),
|
||||
published once merged on the trunk, and walked: one node first, judged at the first-node gate, put back
|
||||
if it fails ([ADR 0218](0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md),
|
||||
[ADR 0236](0236-a-build-is-judged-on-its-first-machine-and-put-back-by-something-other-than-itself-and-so-it-rolls-out-unattended.md)).
|
||||
- **What moves** is computed by one function, ADR 0238 §3: "A changed file touches exactly the modules
|
||||
whose build reads it: a module's own directory, the whole repository for a module built from its root,
|
||||
and a repository a recipe names." Dependents are added along the catalogue's one relation
|
||||
([ADR 0162](0162-a-merge-produces-a-tiered-plan-the-mesh-keeps.md) §1), with four kinds: `stands-on`,
|
||||
`declared`, `packages` ("the module's build reads the other's repository") and `built-by`, which
|
||||
"orders and gates but never widens".
|
||||
- **A build is one module at one commit, and makes every artifact its manifest declares**, every time, in
|
||||
name order (the builder's `build`). The recipe and the compiler see the module's own directory ([issue
|
||||
280](../04-ISSUES/280-a-rebuild-of-an-unchanged-source-was-read-as-a-new-bus/00-report.md)); a module
|
||||
built from its repository's root sees the whole repository; an artifact's `context` clones another
|
||||
repository whole ([ADR 0155](0155-a-definition-names-no-installation-and-how-that-is-checked.md): "A build
|
||||
context may live on the git seat").
|
||||
- **A build produces artifacts, and most are bundles.** [ADR 0156](0156-an-artifact-is-what-a-build-produces-and-the-store-is-named-for-its-scope.md):
|
||||
"An artifact is anything a build produces … *Image* is one kind. A module is not an image; a module may
|
||||
build several artifacts and install none." The kinds in the code are `bundle`, `archive`, `image` and
|
||||
`upstream`, served by the artifact store by digest, and `package`, published to the package registry by
|
||||
version ([ADR 0075](0075-two-stores-and-which-provides-what.md), [ADR 0076](0076-the-sdk-is-a-published-package.md)).
|
||||
On the catalogue's trunk on 2026-10-08, 99 of 119 modules build something; they declare 97 bundles, 6
|
||||
archives, 5 images and 3 upstream copies, no package; 9 modules build more than one artifact.
|
||||
- **The facts already name artifacts.** A resource names the artifact it runs by its local name, resolved
|
||||
to a digest when the build is registered. `build.on` names a base as a module *and* an artifact, and a
|
||||
build records what it stood on as `artifact-store://<module>/<artifact>@<digest>`. A send recreates per
|
||||
resource: the walk of 2026-10-08 said "recreates 1 of route-proxy's 3 container(s) (with a new image:
|
||||
server)". **Three things reduce that to modules**: the inventory's edges (mesh-controller
|
||||
`internal/inventory/dependencies.go` keeps `on.Module` and cuts a recorded base at its first `/`), the
|
||||
build request (one per module), and the source fingerprint (one per build).
|
||||
- **A new build is a change unless its fingerprint repeats** (ADR 0236, its note on issue 280):
|
||||
"Such a rebuild is registered with the artifacts of the build it repeats, so no machine is sent a new
|
||||
digest." The fingerprint hashes the module directory's tree, **each context's whole repository tree**,
|
||||
every base by digest and the toolchain. A build that resolves packages from the registry has none, and
|
||||
is compared by its artifacts' digests.
|
||||
|
||||
### What went wrong
|
||||
|
||||
Issue 338
|
||||
(hq pull request #231, not yet merged when this was written). Two catalogue modules, `route-proxy` and `build-agent`,
|
||||
build an image from a recipe whose context is the controller's repository. Every merge to that
|
||||
repository on 2026-10-08 planned the same three modules in three gated tiers, whatever the files:
|
||||
|
||||
- `mergeCandidates` and `readsFrom` (mesh-controller `cmd/mesh-controller/upgrades.go`) add a module
|
||||
whose build read the merged repository with no test on the changed paths; `touchedBy`, the function
|
||||
ADR 0238 §3 names, is never applied to it.
|
||||
- `dependencies.go` draws a `packages` edge from it to every module built from that repository. So the
|
||||
`packages` edge is a **context read**, nothing to do with the `package` artifact kind, and it treats
|
||||
sharing a repository as a dependency.
|
||||
- **The live tiers come from the code, not from ADR 0162.** That record puts a code dependency "in the
|
||||
same tier"; the planner put each in a tier of its own (mesh-controller → build-agent → route-proxy,
|
||||
the last ordered by `built-by`). Each tier waited for its own first-node gate, about three and a half
|
||||
minutes. Seven completed controller walks took 10 to 11 minutes in gates alone, about 15 minutes in
|
||||
all, against 4 to 5 for the controller's own tier.
|
||||
- **The fingerprint is wider than what the build compiles.** It hashes the context's whole tree, so no
|
||||
two builds repeat. The route proxy's program, built at each of nine merges with `-trimpath
|
||||
-buildvcs=false`, changed at two of them; it was recreated on its node at five of seven walks.
|
||||
- **A file in a module's directory is not the right test either.** The merge that did change the route
|
||||
proxy's program changed nothing under its directory: it changed `internal/broker`, which the proxy
|
||||
imports. A program's source is its import closure, not its directory.
|
||||
- The controller is built from its repository's root, so a change to the route proxy alone, or to
|
||||
`README.md`, moves the controller too.
|
||||
|
||||
The controller's planner rules are held by tests since mesh-controller #167
|
||||
(`cmd/mesh-controller/planner_rules_test.go`, `planner_records_test.go`); the rows tagged *issue 338*
|
||||
assert today's repository-grain behaviour and say they change with this decision.
|
||||
|
||||
[ADR 0009](0009-modules-and-the-graph.md) already said what the build edge should be: "derived rather
|
||||
than declared … a declared list of dependencies drifts from the imports it describes", and "Reading build
|
||||
edges needs a language-aware tool per language, which is the real cost". The code derives the edge from
|
||||
the bases a build was handed, and draws none from imports.
|
||||
|
||||
## Considered Options
|
||||
|
||||
**What a change is mapped onto.**
|
||||
|
||||
1. *Keep repository grain* (today). Rejected: it is issue 338. A module reading a repository moves on every
|
||||
merge to it, and each such module costs a gated tier.
|
||||
2. *Module grain, narrowed*: one build source per module, edges module to module, one fingerprint per
|
||||
build. The smaller change, and honest about its cost: 9 of the 99 modules that build something build
|
||||
more than one artifact, and with the fingerprint's repeat rule an unchanged artifact rebuilt with its
|
||||
module is still sent nowhere. Rejected because the operator's rule is about what a build *produces*,
|
||||
and the mesh already records the artifact on every edge and every resource; module grain is the
|
||||
planner discarding what the records hold. A module built against one artifact of another would move
|
||||
whenever any other artifact of it changed — the same widening as issue 338, one level down.
|
||||
3. **Artifact grain** — chosen. Each artifact has its own build source and fingerprint; a dependency points
|
||||
at an artifact.
|
||||
|
||||
**How an artifact's build source is known.**
|
||||
|
||||
1. *Hand-listed paths, checked against the import closure.* Rejected for Go: a list drifts, and a path
|
||||
missing from it is a real change missed, which is worse than a needless rebuild. The check that would
|
||||
catch the drift has to compute the closure anyway, so the list adds nothing but a way to be wrong.
|
||||
2. **Derived from the import closure for Go** (`go list -deps`) — chosen; ADR 0009's "derived rather
|
||||
than declared", for the language the mesh's own code and 97 bundles are written in.
|
||||
3. **Declared paths for anything without a reader** — chosen, and made loud: the builder hands such a
|
||||
build only its declared paths, so a missing path is a failed build, not a missed change.
|
||||
|
||||
**Other remedies.**
|
||||
|
||||
1. *Split the route proxy and the build seat's program into repositories of their own.* Rejected: they
|
||||
import the controller's packages, which would move to the SDK, and a change there then moves all three
|
||||
through a real build edge; the root-built controller would still claim every file. The rule has to
|
||||
hold whatever a repository's layout is.
|
||||
2. *Reproducible builds alone.* Rejected as the remedy: the planner would still plan and gate three tiers,
|
||||
and the gates are the cost (7 of about 11 minutes). Kept as one rule of this decision, for the builds
|
||||
whose fingerprint cannot be narrow.
|
||||
|
||||
## Decision
|
||||
|
||||
1. **Every artifact has a build source**: the files it is built from, in one or more repositories. One
|
||||
build may produce many artifacts, of any kind, and each has its own.
|
||||
- **An artifact that compiles a Go program** (a Go bundle, or an image or package whose recipe compiles
|
||||
one) has its build source **derived**: the directories of every package in the program's import
|
||||
closure inside the repositories it reads (`go list -deps`, the standard library left out), its Go
|
||||
module files (`go.mod`, `go.sum`, `vendor/modules.txt`), and its recipe. The manifest names the
|
||||
program's package where it does not already: a Go bundle's `from` does; an image whose recipe
|
||||
compiles Go gains a field naming the package it compiles.
|
||||
- **Any other artifact** has the paths its manifest names, within its module's repository or its
|
||||
context. Absent, it is the module's own directory — today's rule — or, for an `archive`, its `from`.
|
||||
- **A build source is never a whole repository that holds another module's files.** A module built
|
||||
from its repository's root (the controller) and an artifact built from a context (the route proxy,
|
||||
the build seat's program) are narrowed by rule 1's derivation or by named paths. A manifest whose
|
||||
build source would be such a repository is refused by the catalogue's check.
|
||||
- The builder records each artifact's build source with the build. A Go closure can only change by an
|
||||
edit to a file already in it (an import line in one of its packages, or a module file), so the build
|
||||
source recorded for the trunk's last build is enough to map the next change. An artifact with no
|
||||
recorded build source (its first build) is built.
|
||||
2. **A change moves exactly the artifacts whose build source it touches.** The planner's one mapping
|
||||
function (ADR 0238 §3) maps each changed file onto artifacts, then onto the modules that build them.
|
||||
One commit may touch artifacts of several modules, in one repository or across the repositories a
|
||||
build source spans. A change to a module's manifest moves that module; it rebuilds only the artifacts
|
||||
whose own declaration or build source changed.
|
||||
3. **A dependency points at an artifact.** A build dependency is an edge from a module's artifact to the
|
||||
artifact it is built against: a base named in `build.on`, a base the build recorded standing on, a
|
||||
bundle's toolchain, a package resolved by version. The plan adds, transitively, every module with a
|
||||
build dependency on a changed artifact, as the catalogue's module graph states it, in the next tier
|
||||
after that artifact is built. A dependent is planned when its base's fingerprint changed and **left
|
||||
out when the base is built to the same digest**.
|
||||
4. **Nothing else moves a module.** Not sharing a repository, not a whole-repository context, not a file
|
||||
outside every build source. The `packages` edge kind is removed. `built-by` stays as ADR 0162 left it:
|
||||
it orders the modules a plan already holds after the build seat's holder and never adds one.
|
||||
5. **An artifact whose build source did not change is not rebuilt as a new digest and not sent.** Its
|
||||
fingerprint is computed per artifact, over its build source (the git object of each of its paths), the
|
||||
bases it stands on by digest, its recipe and its toolchain. An equal fingerprint keeps the digest the
|
||||
mesh holds, and the artifact is not built again. A module is sent only when an artifact it runs has a
|
||||
new digest or its definition changed; one whose artifacts are all unchanged is not recreated.
|
||||
6. **A build is reproducible where its fingerprint cannot be narrow.** An unchanged build source gives an
|
||||
identical artifact, for every kind: nothing in an artifact varies with the commit, the clock or the
|
||||
path it was built at. For Go: `-trimpath` (the toolchain has it) and `-buildvcs=false`, and no `.git`
|
||||
in what a recipe sees. This matters for a build with no fingerprint (one resolving packages from the
|
||||
registry) and for any build source wider than what is compiled. It is not the remedy for issue 338;
|
||||
rules 1 to 5 are.
|
||||
|
||||
### What this supersedes, and what stands
|
||||
|
||||
- **ADR 0162 §1, in part.** The `packages` kind ("the module's build reads the other's repository") and
|
||||
the paragraph's *code dependency* ("B packages A's source — means B is rebuilt whenever A changes, in the
|
||||
same tier") no longer hold: a shared file is in both artifacts' build sources and moves both by rule 2,
|
||||
and no edge is drawn for it. `stands-on` and `declared` hold, but name an artifact at each end, not a
|
||||
module. The *build* and *runtime* dependency tier rules, `built-by`, §2 (the plan is a record), §3 and §4
|
||||
stand.
|
||||
- **ADR 0238 §3, in part.** "the whole repository for a module built from its root, and a repository a
|
||||
recipe names (the build record's `read`)" no longer holds: a changed file touches the artifacts whose
|
||||
build source contains it, and through them their modules. That one function maps every path, that a
|
||||
file read by no build touches nothing, and that a new `module.json` is a new module, stand.
|
||||
- **ADR 0236's insight of issue 280, as a mechanism.** "two builds of a module with one fingerprint as one
|
||||
build" becomes one artifact with one fingerprint. The decision it supports — a rebuild that changes
|
||||
nothing is no move — stands. This is a mechanism change, not a supersession.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **The manifest schema grows two fields on an artifact**: the paths of its build source within its
|
||||
repository or context, and, for an image or package whose recipe compiles Go, the package it compiles.
|
||||
Their names are settled at the build handoff. `route-proxy` and `build-agent` take the second; the
|
||||
controller's own manifest builds `cmd/mesh-controller` as a Go bundle and is narrowed by derivation,
|
||||
so `README.md`, `examples/route-proxy` and `cmd/mesh-builder` stop moving it.
|
||||
- **The builder builds and fingerprints per artifact.** It derives a Go artifact's build source, records
|
||||
it and the fingerprint with each artifact, hands a declared-path build only those paths, and skips an
|
||||
artifact whose fingerprint the mesh holds. One build request may still name a module; what it builds
|
||||
inside it is per artifact.
|
||||
- **The planner** drops the packaging kind in `mergeCandidates` and `readsFrom`, and the `packages`
|
||||
addition in `reachOfMerge` and `SourceMoved`; it maps files onto artifacts through the recorded build
|
||||
sources, and confirms a dependent after its base is built.
|
||||
- **The inventory's relation** (`internal/inventory/dependencies.go`) draws edges between artifacts, keeps
|
||||
`on.Artifact` and the recorded base's artifact segment, and loses `EdgePackages`. `moveFacts.identical`,
|
||||
which today compares catalogue commits, compares digests.
|
||||
- **A controller merge that changes only the controller's program** plans one module in one tier. A change
|
||||
to a package all three programs import plans all three: the build seat's holder first (`built-by`),
|
||||
then the controller and the route proxy together, two tiers where there were three.
|
||||
- **What got harder**: a Go program's build source needs the Go toolchain to read, on the builder; a
|
||||
second language gets a reader of its own or declared paths. A declared-path build that reads a file it
|
||||
did not declare now fails where it used to succeed.
|
||||
- **Design** [to-be 47](../03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md) and
|
||||
[to-be 10](../03-DESIGN/01-to-be/10-delivery.md) name this record when it is accepted, and the build
|
||||
handoff opens on mesh-controller and the catalogue.
|
||||
|
||||
## How this is checked
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| A change moves exactly the artifacts whose build source it touches; a file in none moves nothing | mesh-controller `planner_rules_test.go`, `TestAPlanIsWhatTheChangeTouchedAndWhatIsBuiltOnIt`: rows for a file in one artifact's build source, a file shared by two modules' build sources, a `README.md` at a root-built module's root |
|
||||
| Sharing a repository moves nothing (issue 338) | `TestASharedRepositoryMovesWhatPackagesItAsItDoesToday` in `planner_rules_test.go` and `TestASharedRepositoryIsPlannedFromTheRecordsAsItIsToday` in `planner_records_test.go`: the rows tagged *issue 338* flip — a `README.md` change plans no module, a change to the proxy's package plans the proxy alone, a shared package plans three modules in two tiers |
|
||||
| A plan is the touched artifacts' modules and what is reachable along build dependencies, and nothing else | the property test `TestAPlanIsTheTouchedModulesAndWhatIsReachableAlongTheWideningEdges`, with `packages` removed from the widening kinds and edges at artifact grain |
|
||||
| A dependency points at an artifact; a dependent of an unchanged artifact of a changed module does not move | a new inventory test over a fixture: a module with two artifacts, a dependent built against one; a change to the other plans no dependent |
|
||||
| A dependent whose base is rebuilt to the same digest leaves the plan | a new planner test: a base rebuilt with an equal digest; the dependent's tier asks nothing |
|
||||
| A Go artifact's build source is its import closure | a builder test over a fixture repository: the derived build source equals `go list -deps` for the program, and grows when an import is added |
|
||||
| No build source is a whole repository holding another module's files | a catalogue check in `merge-check.sh`: every manifest's artifacts derived or declared, and a root or context build source refused |
|
||||
| A declared-path build sees only its paths | a builder test: a recipe reading an undeclared file fails, naming it |
|
||||
| An unchanged build source is not rebuilt and not sent | a builder test: two builds at commits differing outside an artifact's build source give one fingerprint and one build; a walk test: no send for it |
|
||||
| A build is reproducible | a builder test per kind: building one source twice gives one digest |
|
||||
| Live | the `plans` what-if for the controller's repository with only `README.md` answers no module; with the proxy's package alone, `route-proxy` alone |
|
||||
|
||||
## References
|
||||
|
||||
- Issue 338 and its diagnosis (hq pull request #231); issue [280](../04-ISSUES/280-a-rebuild-of-an-unchanged-source-was-read-as-a-new-bus/00-report.md)
|
||||
- [ADR 0009](0009-modules-and-the-graph.md), [ADR 0072](0072-two-graphs-and-the-build-chain.md), [ADR 0155](0155-a-definition-names-no-installation-and-how-that-is-checked.md), [ADR 0156](0156-an-artifact-is-what-a-build-produces-and-the-store-is-named-for-its-scope.md), [ADR 0162](0162-a-merge-produces-a-tiered-plan-the-mesh-keeps.md), [ADR 0236](0236-a-build-is-judged-on-its-first-machine-and-put-back-by-something-other-than-itself-and-so-it-rolls-out-unattended.md), [ADR 0238](0238-a-commit-is-the-build-at-hand-one-commit-one-change-plan-checked-off-the-trunk-and-published-only-on-it.md), [ADR 0239](0239-a-delivery-is-owned-by-the-mesh-delivery-module-and-runs-from-commit-to-delivered.md)
|
||||
- mesh-controller #167 (the planner's rules held by a table and a property test)
|
||||
Reference in New Issue
Block a user