Skip to content

Module 07: Build Architecture, Layered Includes, and Build APIs

Architecture defects are often successful builds. A private helper creates the main artifact but omits verification. A release include changes ordinary compilation. Two sources collapse into one output, and Make faithfully builds the one target it was given.

Module 07 teaches you to review those failures as ownership contracts:

  • external callers depend on declared targets
  • policy values propagate only through their owned target branches
  • output paths preserve source ownership as the repository grows
  • macros remain inside boundaries that can be inspected and tested

The standard is not “the Makefiles are organized.” It is:

A maintainer can name each owner, follow each consumer, and inspect evidence that the boundary holds.

The architecture questions this module now tests

The executable audits establish four existing contracts. The reading and practice extend them with five questions that become important as a repository grows:

  1. Does the public API define supported variables, outputs, evidence, and failure meaning, or only target names?
  2. Can two requested branches give a shared prerequisite conflicting target-specific policy?
  3. Is the source-to-output mapping total, injective, owner-preserving, and stable for every supported discovery root?
  4. Can a reviewer follow macro text through both eval expansion stages and identify every generated target and parse-time side effect?
  5. Do include layers follow an allowed dependency direction, or do policy, graph, publication, and interface layers reach back into one another?

Those are not requests for more files. They are tests of whether the architecture still has one explainable owner for each decision.

flowchart TD
  api["public target and parameter API"] --> graph["owned graph"]
  policy["policy layer"] --> graph
  roots["declared discovery roots"] --> mapping["total, injective mapping"]
  mapping --> graph
  macro["bounded rule generator"] --> graph
  graph --> publication["process-local candidate publication"]
  publication --> evidence["promised artifacts and proof"]
  review["dependency-direction review"] -.checks.-> api
  review -.checks.-> policy
  review -.checks.-> mapping
  review -.checks.-> macro

Begin with the executable audits

From the repository root:

cd programs/reproducible-research/deep-dive-make/capstone
gmake architecture-contract-audit
gmake abstraction-contract-audit

The bundles are written under the repository’s artifacts/ directory:

artifacts/audit/reproducible-research/deep-dive-make/architecture-contracts/
artifacts/audit/reproducible-research/deep-dive-make/abstraction-contracts/

Read each bundle in this order:

  1. route.txt
  2. its named audit guide
  3. summary.tsv
  4. one case in report.json
  5. that case’s trace
  6. its specimen and generated workspace

The architecture audit contains six cases:

Boundary Defect model Control model
build API private caller bypasses verification declared caller receives full evidence
include ownership release include mutates global flags release target scopes its policy
output ownership two sources collapse to one path source namespaces survive in outputs

An aggregate PASS includes three deliberately reproduced defects. Always quote the finding and observation, not only the result column.

The abstraction audit then asks a narrower question: what changed when repeated explicit rules became a macro?

Model Required observation
explicit rules target, prerequisite, policy, and publication contracts are visible
bounded macro the same contract survives and the call domain remains explicit
opaque macro hidden targets and parse-time policy mutation are reproduced

This bundle has three PASS rows, including the opaque counterexample. A passing counterexample means the audit observed the promised defect; it does not approve that design.

flowchart LR
  claim["ownership claim"]
  defect["successful defect"]
  control["enforced control"]
  trace["trace"]
  artifact["artifact evidence"]
  judgment["review judgment"]

  claim --> defect
  claim --> control
  defect --> trace
  control --> trace
  trace --> artifact --> judgment

One serious-session route

Allow about six hours if you are studying independently.

Time Work Evidence to keep
45 minutes run both audits and interpret all nine rows annotated summaries
50 minutes trace private and declared callers help, caller, and artifact comparison
60 minutes compare global and target-scoped policy four flag artifact values
55 minutes derive both source-to-output mappings source/output counts and owner files
55 minutes compare explicit, bounded, and opaque generation database map and side-effect table
65 minutes execute the tangled-layout refactor before/after contract table
70 minutes complete the ten exercises reproducible review packet
30 minutes run both self-tests and write the review rejection results and remaining risk

If you have only one hour, run the audit, read summary.tsv, and follow one family from specimen to trace to artifact. Do not skim every page and omit the evidence.

Entry diagnostic

Before reading the lessons, answer these against one Make repository:

Prompt Your initial answer
Which variables may callers set, and which values are rejected?
What artifacts and evidence does each public target promise?
Can an ordinary and specialized goal share a prerequisite built under different policy?
Can two distinct selected sources ever map to one output key?
What text remains after the first and second expansion of one eval macro?
Which include directions are forbidden?

Keep the answers. The module is incomplete if the final answers are only more polished phrasing. Each answer should point to a rule, database entry, artifact, or rejection test.

Follow four contracts through the build

flowchart TD
  caller["external caller"] --> public["declared target"]
  public --> graph["owned graph"]
  base["base policy"] --> graph
  release["release specialization"] --> release_branch["release branch"]
  sources["rooted sources"] --> map["namespace-preserving map"]
  map --> graph
  explicit["explicit rule contract"] --> bounded["bounded macro"]
  bounded --> graph
  graph --> evidence["verification and owned artifacts"]

For every arrow, name:

  1. the file or target that owns the decision
  2. the consumer that relies on it
  3. the evidence that would change if the boundary leaked

Do this before moving files. A new include layout is not evidence that ownership improved.

Build one architecture packet

Keep a single packet:

build-architecture-review/
  public-api.md
  policy-propagation.md
  source-output-map.tsv
  generated-rule-map.txt
  layer-dependencies.tsv
  acceptance.md
  evidence/

The packet must answer:

Claim Minimum evidence
caller uses supported API help or contract manifest, caller command, promised outputs
parameter is owned origin/flavor/value, validation behavior, affected artifacts
specialization is unambiguous isolated ordinary/specialized runs and combined-goal challenge
mapping preserves owners selected-source and unique-output counts plus reverse-owner lookup
macro preserves contract explicit baseline, expansion trace, database map, artifacts
layer direction holds include/variable/rule dependency map and a deliberate forbidden-edge rejection

An absent row is not “obvious architecture.” It is an unreviewed boundary.

Independent-study checkpoints

Pause after each pair of lessons:

  • after public API and layering, explain target and variable ownership to a reviewer using only public-api.md and policy-propagation.md
  • after discovery and macros, reconstruct one output path and one generated rule from their explicit inputs
  • after architecture review, inject one forbidden dependency direction and require the gate to reject it
  • after the worked example, ask another learner to locate the evidence for each accepted boundary without opening the narrative first

These checkpoints replace instructor interpretation with durable artifacts.

Study route

Read the pages in this order on the first pass:

  1. Public Targets and Build API Design
  2. Layered Includes and Responsibility Boundaries
  3. Discovery, Namespacing, and Repository Growth
  4. Macros, call, and Reuse Without Opaqueness
  5. Architecture Review and Maintenance Discipline
  6. Worked Example: Refactoring a Tangled Build Layout
  7. Exercises
  8. Exercise Answers
  9. Glossary

The first three pages share the architecture audit bundle. The macro lesson uses the abstraction audit to compare explicit, bounded, and opaque rule generation. The review lesson and worked example combine both evidence families into one acceptance decision.

The ten files in this module

  1. Overview (index.md)
  2. Public Targets and Build API Design
  3. Layered Includes and Responsibility Boundaries
  4. Macros, call, and Reuse Without Opaqueness
  5. Discovery, Namespacing, and Repository Growth
  6. Architecture Review and Maintenance Discipline
  7. Worked Example: Refactoring a Tangled Build Layout
  8. Exercises
  9. Exercise Answers
  10. Glossary

How to use the file set

If you need to... Start here
define which targets humans and automation may rely on Public Targets and Build API Design
split a large build into mk/*.mk layers without hidden mutation Layered Includes and Responsibility Boundaries
reduce duplication without turning the build into a macro puzzle Macros, call, and Reuse Without Opaqueness
keep source discovery and target names stable as the repository grows Discovery, Namespacing, and Repository Growth
review a build layout before it becomes institutional folklore Architecture Review and Maintenance Discipline
see the whole module in one realistic refactor story Worked Example: Refactoring a Tangled Build Layout
test your own understanding Exercises
compare your reasoning against a reference Exercise Answers
stabilize the module vocabulary Glossary

Commands to keep close

Run these from capstone/ unless a lesson says otherwise:

gmake architecture-contract-audit
gmake architecture-contract-selftest
gmake abstraction-contract-audit
gmake abstraction-contract-selftest
gmake --trace verify
gmake -pRrq -f Makefile
gmake -n all

The self-tests matter because they mutate disposable controls and require both audits to reject dishonest evidence.

Learning outcomes

By the end of this module, you should be able to:

  • distinguish a reachable target from a declared public promise
  • define supported target parameters, outputs, evidence, and failure meaning
  • prove that external callers receive every artifact promised by their target
  • explain how include parsing and target-specific variables produce different policy scope
  • detect shared-prerequisite ambiguity across specialized goal branches
  • detect output collisions by mapping cardinality and artifact owner identity
  • prove mapping totality, injectivity, reversibility, and extension stability
  • compare an explicit rule contract with bounded and opaque generation
  • trace both eval expansion stages and use process-local publication candidates
  • keep macros only when expanded rules, policy, and public surfaces preserve that contract
  • reject forbidden dependency directions between architecture layers
  • write a reproducible architecture review that cites findings, mutations, limits, and risk

Exit standard

Do not move on until all of these are true:

  • you can explain why PRIVATE_TARGET_DEPENDENCE_REPRODUCED is a defect despite exit zero
  • you can identify the artifact proving CROSS_LAYER_POLICY_LEAK_REPRODUCED
  • you can derive where the flat mapping loses one source owner
  • you can show equal source and unique-output counts in the namespaced control
  • you can prove that a bounded macro preserves the explicit prerequisite and policy contract
  • you can explain why target-specific policy is unsafe for one shared artifact requested under conflicting branches
  • you can identify the hidden target and policy side effect in the opaque counterexample
  • you can show that generated publication candidates cannot collide across concurrent recipe processes
  • you can reject one forbidden include-layer dependency with a named diagnostic
  • you have completed all ten exercises without relying on an instructor
  • gmake architecture-contract-selftest passes
  • gmake abstraction-contract-selftest passes
  • your review packet names a claim, observation, conclusion, limit, controlled mutation, and at least one unresolved risk