Skip to content

Independent R&D project · Cologne

Executable Fences

A forbidden state prevents the relevant merge, release, deployment or publication.

Non-normative

Companion version
1.0
Maps to COADF Core
2.2
Status
Current
Last reviewed
COADF principles
P-6

Architectural property

COADF P-6: a guardrail that lives in a document is advice; a guardrail that runs in the pipeline and blocks a release is a fence. Fences fall into four categories (data, architecture, copy and process), each with an identifier, a rule and an enforcement method, and a fence earns its place only by a proof of teeth. COADF does not publish the vocabulary its own publication fence matches on, because a list of what is watched is a map of what is protected.

The property is not "there is a check". It is that the forbidden state cannot travel past a given point, and that somebody has watched it being stopped there.

Why it matters

Every other property in this Companion can be implemented correctly once and lost in the next change. A fence is what keeps a property true across changes nobody reviewed with that property in mind. The hard part is rarely writing the check. It is placing the check on the path the forbidden state must travel, and proving that it fires there, on the real path, rather than in a unit test of the checking function.

Valid implementation strategies

Enforcement surfaces

Each surface sees something different, and each has a characteristic bypass. A fence belongs on the surface that sees the forbidden state, and is only as strong as that surface's bypass.

Where a fence can sit, what it sees there, and how it is typically bypassed
SurfaceSeesTypical bypass
Compiler and type checkerCode structure and declared typesCasts, dynamic typing, reflection, generated code
Application validationValues at a boundary, at run timeA second entry point: a batch job, a script, a migration
Architecture testThe dependency graphLoading by name at run time; a new package the rule does not name
Contract and schema testInterface compatibilityA consumer nobody registered
Continuous integrationThe repository at one commitA required check that is skipped and reported as success
Merge gateWhich checks must pass before a mergeAdministrators, direct pushes, protection the hosting plan does not enforce
Release pipelineThe artifact being promotedA manual upload
Deployment admissionAPI objects submitted to the clusterA failure policy that ignores errors; objects that existed before the policy
Publication buildThe rendered public outputContent served from outside the build

Three chains, each ending in a stopped transition, are implemented in the profiles:

  • An architecture violation fails an architecture test, and the merge does not happen (Python and FastAPI).
  • A contract incompatibility fails a contract check, and the release does not happen.
  • A synthetic forbidden sentinel in the built site fails the publication fence, and the publication does not happen (Python and FastAPI, Cloud-Native).

Continuous integration is one surface among nine, not the definition of a fence. GitHub Actions, GitLab CI and Jenkins can all host one; so can a type checker, an admission policy or the build that renders a site.

Proof of teeth

  • Introduce a controlled, synthetic defect.
  • Exercise the real enforcement path, not a unit test of the checking function.
  • Verify that it fails, and fails for the planted reason.
  • Restore the exact fixture, and prove it by comparing a digest before and after.
  • Verify that it passes again.

Commit before planting. Restoring by discarding changes restores the last commit, which on a working branch may not be where you started, and the proof then destroys the work it was meant to protect.

Failure modes

  1. The fence is on the wrong path

    It checks the repository, while the forbidden content is injected at build time, at deploy time or at run time.

  2. A skipped required check reads as success

    GitHub reports a skipped job as successful, and a skipped job does not prevent a merge even when it is a required check. A required job that depends on a failed fence is skipped, and the merge goes through. Require the fence itself, or a summary job that always runs and fails unless every fence passed (GitHub's own advice for checks that depend on other jobs).

  3. Advisory by configuration

    continue-on-error, allow_failure: true in GitLab CI, an admission webhook whose failure policy ignores errors, a Gatekeeper constraint in dryrun or warn: each turns a fence into advice without anybody writing the word.

  4. Nothing checked, reported as clean

    An empty pattern list, a test selection that matches nothing, a scan of an empty directory. The number of checks actually executed belongs in the result, and zero is a failure.

  5. The fence fires on legitimate work and is switched off

    Precision keeps a fence alive. A rule that matches ordinary copy will be disabled rather than obeyed, and a disabled fence is worse than none, because everybody still believes it is there.

  6. The fence's own list is published

    A public list of watched terms tells a reader exactly what is being protected.

  7. Existing state is never checked

    Admission and pre-merge checks act on requests as they are made, not on what is already there. Kubernetes documents it for one admission plugin in so many words: when a LimitRange is added, the pods that already exist continue unchanged. Gatekeeper has an audit of existing resources for exactly this gap.

  8. Green is read as sufficient

    A passing check proves that the check passed. Whether it is the right check is an architectural question no pipeline can answer; see the technology note.

Verification

  • Architecture test

    Passes when: The dependency rule passes on the current tree.

    Proof of teeth: Plant the forbidden import: it fails, and the merge gate refuses.

  • Contract test

    Passes when: Producer and consumer schemas are compatible.

    Proof of teeth: Remove a required field from the producer: the check fails and the release job does not run.

  • End-to-end test

    Passes when: The publication fence scans the built output and passes.

    Proof of teeth: Plant a synthetic sentinel in the output: the build fails. Remove it, compare the digest, and the build passes.

  • Deployment or admission test

    Passes when: An object that follows the rule is admitted.

    Proof of teeth: Submit one that breaks it: refused, with the rule's message.

  • Manual evidence

    Passes when: At merge, a named person confirms that each fence ran in this run: the run identifier and the number of executed checks are recorded, not remembered.

Alternative realizations

  • Pre-commit hooks. Fast feedback, and bypassable on the developer's own machine: advice, not a fence.
  • Runtime guards. Stop a forbidden state in production rather than before it. Necessary where the state only exists at run time.
  • Manual gates. A named person performs a written procedure. COADF reports such a control honestly as manual, never as enforced.
  • Policy engines for infrastructure rules. Kubernetes ValidatingAdmissionPolicy in-process, or Open Policy Agent with Gatekeeper, where the forbidden state is an API object.

Limitations

  • A text fence cannot see a mechanism expressed through control flow, renamed identifiers, data flow or a diagram's geometry. Automated guards are necessary and not sufficient; human review remains.
  • A fence detects what it was written to detect, and nothing else.
  • Passing fences establish that the fences passed. They establish no regulatory status.

Sources

COADF Engineering Companion 1.0 · non-normative · maps to COADF Core 2.2

Publication rights reserved. No public licence is granted for the COADF Engineering Companion 1.0 or its reference examples at this time.

IP and publication status