Skip to content
C.W.K.
Lesson 06 of 06 · published

The Question From the Kit's Side

~12 min · drift, enforcement, deploy, process

Level 0Loose Parts
0 XP0/52 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

Green Here, Stale Everywhere Else

Every check in this track so far points the same way. A consumer's suite compares that consumer's copies with the kit, so a hand-edited copy goes red in the repository where somebody edited it. That covers one way a copy can go stale. In November the family met the other way.

Two kit changes landed within hours of each other — stricter typing for some shared Python helpers, and a fix that moved some React effects out of render. Each session committed its change, ran the kit's suite, saw every test green, and closed. Neither session deployed. For two days forty-two consumer repositories carried the previous bytes: a hundred and forty-six drift lines in all. Nothing in the kit noticed, because nothing in the kit was wrong. What finally noticed was a lab — a separate machine where consumers' suites are queued and run — which reported the stale copies as a kit mismatch.

The consumers' checks did work. They went red the first time anyone ran them. The problem was who ran them and when: two days later, on another machine, in front of somebody who had not made the change. That is the failure the earlier lesson on whose suite runs the check was written to prevent — the correction arriving later, to somebody else — reached from the opposite side.

The Side That Goes Home Has to Ask

A kit session reports done on the kit's suite. So the kit's suite now asks the family question itself, with two tests:

  • Every present consumer carries the kit. The test runs the family-wide check and fails while any consumer checked out beside the kit differs from its source.
  • Every deployed copy is committed. A copy that was deployed but not committed in its consumer exists on this disk only. Origin, the lab and every other machine still run the old one, so the test fails on it as well.

Put those beside a rule the deployer already enforced — it refuses to deploy a kit source that differs from the committed tree — and the suite can only go green in one order: commit in the kit, deploy, commit and push in each consumer, check. The house order used to be a sentence in the kit's own instructions. Now it is the only path that ends in green.

One honest exception. A kit checkout with no consumers beside it — a scratch worktree, a cloud session — cannot see the family, so it cannot judge it. There the tests skip, and the skip says to run the suite from the main checkout. A skip that names what it could not see is a report; a silent pass would be the old blind spot with a green light on it.

A change is done where it lands, so the side that makes the change must ask whether it landed. For every direction a copy can go stale, find the side that would go home believing it was finished, and put the check in the suite that side reports done on. A check that only the receivers run will eventually fire — later, elsewhere, at someone else.

What "Carries It" Includes

The same week showed where the kit's question stops. One consumer does not only hold vendored web sources; it commits a bundle built from them, which its native app loads. The deploy brought the new sources, the kit's check was satisfied, and that consumer's own suite failed on the lab — it has a test that the committed bundle matches its sources — until someone ran the bundle build. The kit's instructions now say so: a consumer that commits a build of vendored sources owes that rebuild as part of taking a kit change.

That is the right split of work, not a gap to close from the kit. The kit can see its copies; it cannot know every artifact each consumer derives from them. The consumer that derives one is the only place a test can compare the artifact with what it was built from, and that test already existed. The kit's side asks "did my bytes arrive"; the consumer's side asks "is everything I make from them current". Two questions, two suites, and neither pretends to answer the other.

Code

The kit's own suite stays red until every present consumer carries and commits the change·python
"""Runs in the KIT's own suite. A kit change is not done until every
consumer on this machine carries it AND has committed it."""
import json
import subprocess
import sys
from pathlib import Path

import pytest

KIT = Path(__file__).resolve().parents[1]
SYNC = KIT / "sync" / "kit_sync.py"
FIX = ("commit the kit source, deploy, commit and push in each "
       "consumer, then re-run the check")


def manifest() -> dict:
    return json.loads((KIT / "sync" / "manifest.json").read_text())


def present_consumers() -> dict[str, Path]:
    """Consumers checked out beside this kit. One that is absent here is
    named by the sync itself; it is not silently counted as clean."""
    found = {name: (KIT / rel).resolve()
             for name, rel in manifest()["consumers"].items()}
    # The kit may list itself as a consumer; it is never its own family.
    return {name: path for name, path in found.items()
            if path != KIT.resolve() and path.is_dir()}


def require_family() -> dict[str, Path]:
    present = present_consumers()
    if not present:
        pytest.skip("no consumer beside this checkout (a scratch worktree?): "
                    "the family cannot be judged from here")
    return present


def test_every_present_consumer_carries_the_kit() -> None:
    require_family()
    run = subprocess.run([sys.executable, str(SYNC), "--check"],
                         cwd=KIT, capture_output=True, text=True, timeout=600)
    assert run.returncode == 0, (
        f"the kit is ahead of its consumers; {FIX}\n{run.stdout}")


def test_every_deployed_copy_is_committed() -> None:
    """Deployed but uncommitted has reached THIS disk only - not origin,
    not the lab, not any other machine."""
    targets: dict[str, list[str]] = {}
    for entry in manifest()["files"]:
        for repo, rel in entry["targets"].items():
            targets.setdefault(repo, []).append(rel)
    dirty = []
    for repo, root in sorted(require_family().items()):
        paths = [t for t in targets.get(repo, []) if (root / t).exists()]
        if not paths:
            continue
        status = subprocess.run(
            ["git", "-C", str(root), "status", "--porcelain", "--", *paths],
            capture_output=True, text=True)
        if status.returncode != 0:
            dirty.append(f"{repo}: git status failed")   # unknown is not clean
            continue
        dirty += [f"{repo}: {line}" for line in status.stdout.splitlines()]
    assert not dirty, f"deployed but not committed; {FIX}\n" + "\n".join(dirty)

External links

Exercise

Pick one shared artifact in your work that other projects copy or pin — a library version, a schema, a config template. Write down the suite the artifact's author runs before calling a change done. Then answer: can that suite fail if the change never reached a single consumer? If not, sketch the one test that would make it fail, and the skip message it should print where it cannot see the consumers.
Hint
Start from the last time a consumer discovered a change late. Ask who made the change, what they ran before they stopped, and why that run was green. The missing check is almost always on the author's side, in the direction nobody wrote down.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.