This article is based on a real failure in the author's AI-assisted publishing workflow. The author defined the problem and operating boundary; AI implemented and tested the mechanism, drafted the source, and recomposed this English version under a standing delegation for English-market publication. #ABotWroteThis
The trigger was a tag edit. The body and images were unchanged, but every automated review ran again. A reviewer's small wording fix then created another revision and restarted the set.
CI often behaves the same way: a README typo starts integration and E2E tests; a CSS change waits for backend jobs with identical inputs. The safe fix is not to call a diff "small." It is to fingerprint what each check actually uses and reuse a prior PASS only when its inputs, rules, and evidence still match.
TL;DR
- Freeze related edits as one revision before evaluation. Saving a file should not automatically mean "start every check now."
- Give every check an explicit dependency projection and fingerprint that projection, not the whole repository.
- Reuse a prior PASS only when its input fingerprint, rule digest, and evidence still match. Unknown means execute.
- Start with one slow job: write down exactly what must change before that job needs to run again.
Quick answer: how do you avoid rerunning every CI job?
Hash each job's verdict-changing inputs, rules, and tool version. Rebind a matching attested PASS with a new receipt; execute on mismatch or uncertainty. Decide once per frozen edit batch, not after every save.
The smell appears before the pipeline feels slow
The problem exists as soon as any of these are true:
- Nobody can explain why a given job runs after a documentation-only change.
- A single review comment causes unrelated jobs to restart.
- The only invalidation rule is the repository commit SHA.
Parallelism does not remove irrelevant runs. File patterns also miss broad inputs such as policies, generated schemas, base images, fixtures, or prompts.
The question is not "Was the diff small?" It is:
Did any input that this specific check used to reach PASS change?
Separate editing from evaluation
People and agents make related edits in sequence. If each save starts evaluation, the pipeline judges incomplete intermediate states. Treat the edits as one revision batch:
- Make all known edits.
- Freeze the revision that will be judged.
- Compute the checks required for that frozen revision.
- Finish those checks before asking for the next human decision.
Saving records work in progress. Freezing identifies the exact candidate whose evidence matters.
Fingerprint each check's real dependency set
A repository-wide hash makes every character invalidate everything. Instead, define a projection: the smallest complete set of inputs that can affect one check's verdict.
Examples:
- A Markdown style check may depend on documentation files and its lint configuration.
- A frontend visual test may depend on UI code, styles, assets, browser version, fixtures, and baseline images.
- A backend integration test may depend on code, schema, service configuration, fixtures, and runner version.
- A security check may depend on source, lockfiles, policy, and scanner version.
For each check, choose current_pass when it already passed this revision, reuse_prior_pass when an attested PASS matches its projected inputs and rule digest, or execute otherwise. project() must include everything the check reads. If the set is uncertain, execute.
A minimal executable model
This executable model shows a documentation edit changing only the documentation projection:
from hashlib import sha256
import json
checks = {
"docs": ["README.md", "docs/config.yml"],
"backend": ["src/app.py", "requirements.lock"],
}
before = {
"README.md": "old heading",
"docs/config.yml": "strict=true",
"src/app.py": "return 200",
"requirements.lock": "framework==1.0",
}
after = before | {"README.md": "new heading"}
def fingerprint(files, state, rule="v1"):
projected = {name: state[name] for name in sorted(files)}
payload = {"inputs": projected, "rule": rule}
return sha256(json.dumps(payload, sort_keys=True).encode()).hexdigest()
for name, files in checks.items():
decision = (
"reuse_prior_pass"
if fingerprint(files, before) == fingerprint(files, after)
else "execute"
)
print(f"{name}: {decision}")
Run it:
$ python3 change_aware_demo.py
docs: execute
backend: reuse_prior_pass
In production, use content-addressed files, generated inputs, environment data, and tool versions. Store the prior PASS as immutable evidence; this comparison alone is not authorization.
A result depends on rules, not just files
Matching files is insufficient. If a personal-data rule, scanner, browser, prompt, threshold, or target changes, yesterday's PASS does not prove today's verdict. Fingerprint both:
- The projected content and environment inputs.
- The rule digest that produced the verdict.
Incident-driven acceptance conditions belong in the rule digest too. Selective execution narrows invalidation; it must not hide it.
Reusing PASS is not the same as skipping
"We ran this before" is not evidence.
A reusable PASS binds:
- check identity;
- projected input fingerprint;
- rule digest and tool version;
- verdict and immutable evidence;
- the original revision; and
- a new receipt binding that evidence to the current revision.
"Job skipped" is vague. "PASS reused because inputs A, B, C and rule R are unchanged" is falsifiable.
What should happen for common changes?
| Change | Expected behavior |
|---|---|
| README only | Run docs checks; reuse unrelated PASS only when projections and rules match. |
| CSS or UI asset | Run build, accessibility, and relevant visual checks; backend may be reusable. |
| Dependency or lockfile | Invalidate every consumer of the resolved graph. |
| Article tag/metadata | Keep body and image PASS when unchanged; read the remote metadata back. |
| Article body or image | Run checks whose projections include that body or image. |
| Unknown/legacy diff | Run everything. |
What we tested in the real workflow
We tested the implementation with a real article and real image inputs, without granting publication authority. Before an answer, the PASS receipt count was zero; after the answer it was exactly one; replay was rejected; and the next review received the real article and image instead of placeholders.
This verifies the review-return and evidence path, not a universal speedup or a successful publication. No improvement percentage is claimed because it was not measured.
A practical migration path
Choose one expensive or frequently unnecessary check and answer:
- What exact files, generated data, environment values, fixtures, policies, and tool versions can change its verdict?
- Can you build a deterministic projection of those inputs?
- What immutable evidence proves the previous PASS?
- What rule changes must invalidate that evidence?
- What unknown states should fall back to execution?
Log the decision before enabling reuse, and compare it with full-pipeline results. False reuse is a design failure; extra execution is only a missed optimization. Enable one check at a time.
Before you close this tab
Find one job that runs after unrelated changes. Write: "This check must run when..." List its actual inputs, rules, and tool version. If you cannot prove an input is unchanged, execute.
One honest dependency boundary is enough to start replacing "something changed, run everything" with explainable execution and explainable PASS reuse.

Top comments (0)