Appendix A - 28. Enforce at the right semantic level
The Structure of Enforce at the right semantic level — its shape at a glance:
Rank the candidate placements as a ladder of widening scope; find the rung where the property is legible; place the mechanism there. Below that rung the check is blind or false-fires; at or above it, the property is decidable.
flowchart TB
Prop[Property to enforce] --> Q{At what scope is<br/>the property legible?}
Q --> L1[Rung 1 · one changed file<br/>syntactic check]
Q --> L2[Rung 2 · reasoning over the diff]
Q --> L3[Rung 3 · whole worktree / final commit]
Q --> L4[Rung 4 · whole task on agent return]
L1 -. below legible scope .-> Miss([Misses, or false-fires])
L4 ==>|legible here| Fire([Mechanism decides correctly])
Accessible description: a property to enforce is matched against a ladder of placements ordered by widening scope — one changed file, reasoning over the diff, the whole worktree, the whole task on agent return. A mechanism placed below the scope at which the property is legible either misses it or false-fires on a partial state; a mechanism placed at the rung where the property is legible decides correctly.
Projected from the catalogue entry governance-doc-controls / Enforce at the right semantic level.
On this page: Intent · Motivation · Applicability · Structure · Sample Code · Consequences · Example use within DocAble · Related Patterns
Intent
Intent — Place a mechanism at the granularity where the property it checks first becomes legible, not at the cheapest or earliest point; a check fired below that scope either can't see the property or rejects a legitimate partial state (our instance: model↔code drift is checked when an agent returns from a multi-commit task, never at a per-commit hook where the model is legitimately mid-flight).
Motivation
A property has a scope at which it becomes legible — the smallest window in which enough of the world is visible to decide it true or false. Place a mechanism below that scope and it fails one of two ways:
- It misses the property. The property is not yet expressible at that granularity, so the check looks at a slice that cannot contain the evidence. A monitor judging one system call at a time never sees a data leak, because a leak is a sequence — the call that reads the secret and the call that ships it are legible together, never apart.
- It false-fires on a legitimate partial state. The property is a claim about a finished unit, and a check fired mid-unit sees an intermediate that is correctly inconsistent. A per-commit gate on model↔code parity rejects every intermediate commit of a multi-commit feature, because the model is allowed to lag the code until the work is done.
The reflex is to place a mechanism where it is cheapest and earliest — the pre-commit hook, the single syscall, the one changed file — because that is where enforcement is convenient. Convenience and legibility are different axes, and when they diverge the convenient placement is wrong. The failure recurs at every new mechanism's design, and it is silent: a mis-placed mechanism looks wired, runs green (or red) on every fire, and never enforces the thing it was built for.
Applicability
- A ladder of enforcement points at distinct scopes. Without a runtime that exposes a commit event, a task-return event, and a unit-close gate, there is nowhere to place a mechanism but the one hook you have. The ladder is what makes placement a choice.
- The property stated as a predicate, sharp enough that "where is this legible?" has an answer. A vague property ("the code is good") has no legibility scope and cannot be placed.
- A reviewer who asks the placement question at design time. This is a soft judgment; it holds only if someone reaching for a new mechanism asks at what scope is this legible? before defaulting to the cheapest hook. A failure-interpretation handoff that routes a recurrence to design a mechanism is the natural place to force the question.
Structure
The Structure diagram appears at the top of this page.
Sample Code
Placement is a design-time judgment, so the "code" is the decision procedure, not a runtime call: for a given property, pick the coarsest window it needs, and refuse to wire the mechanism any lower. Here the property model_and_code_agree is a claim about a finished unit, so it is legible only at agent-return scope; wiring it at the commit rung is the mis-placement the procedure rejects.
from enum import IntEnum
class Scope(IntEnum): # the ladder, ordered by widening semantic scope
CHANGED_FILE = 1 # a syntactic check over one file
DIFF_REASONING = 2 # a pass that reasons over the whole diff
WORKTREE = 3 # the whole worktree / final commit
TASK_RETURN = 4 # the whole unit of work, when the agent returns
def legible_scope(prop: str) -> Scope:
# the smallest window in which the property's evidence is fully visible
if prop == "banned_api_absent": return Scope.CHANGED_FILE # evidence is in one file
if prop == "no_data_exfiltration": return Scope.DIFF_REASONING # a SEQUENCE, not one call
if prop == "model_and_code_agree": return Scope.TASK_RETURN # a FINISHED-unit claim
raise ValueError(f"unranked property: {prop}")
def place_mechanism(prop: str, chosen: Scope) -> None:
need = legible_scope(prop)
if chosen < need: # below legible scope = blind / false-fires
raise SystemExit(
f"'{prop}' is legible at {need.name}, not {chosen.name}: "
"the mechanism would miss it or reject a legitimate partial state"
)
wire_mechanism(prop, chosen) # at or above: the property is decidable
Consequences
- The higher rung costs latency. A property legible only at agent-return is caught later than a per-commit author would like; the intermediate work proceeds un-checked on that dimension until the unit closes. That is the price of soundness, not a defect — a lower placement would be wrong, not merely faster.
- It is a judgment, not a gate. Nothing forces a designer to place a mechanism correctly; a mis-placed mechanism still ships and still looks wired. The defense is the design-time question, and a soft question can be skipped. The tell of a skipped one is a mechanism that fires forever and never catches its class.
- Over-placing is its own waste. Lifting a property that is legible in one file up to an Epic-close review buys nothing and delays the catch. The rule is the lowest sound rung, not the highest.
Example use within DocAble
- Model-drift → agent-return, not the commit hook. A model↔code parity claim about a finished unit is legible only when the agent returns from the whole task; a per-commit gate would false-fire on every legitimate mid-task commit. The trust-nothing re-run at the unit's close (the Epic Definition-of-Done) is this placement at the intent-level rung.
- Data-exfiltration → a call sequence, not one syscall. A leak is legible only across a stitched sequence of calls; a monitor judging calls one at a time sits below the policy's semantics and passes the leak. This is the classic OS "semantic gap" — VM introspection and firewalls fail for the same reason when they sit below the semantics they must apply.
- Operator-loop omissions → a runtime lifecycle event, not a source lint. "Did the operator write a hand-off before compaction?" has no source artifact to analyze; it is legible only in the running loop, at the pre-compaction event. Placed as a lint, it has nothing to read.
- A banned API → one changed file. The counter-example that keeps the principle honest: a property fully legible in a single tree belongs on the cheapest rung, the pre-commit hook. Not everything climbs the ladder; most mechanisms belong at the bottom.
Related Patterns
- Specialized by — epic-definition-of-done: the intent-level rung of the ladder, where a finished feature and its plan are both legible. It is the top-of-ladder instance this principle cites; its trust-nothing re-run is placement-at-agent-return made concrete.
- See also (a placement each) — pre-commit-hook sits at the syntactic-diff rung; lifecycle-hooks at the runtime-event rung. Each is a mechanism placed by this judgment; this entry is the judgment that places them. The named axis is placement-principle vs placed-mechanism.
- Consumer — the operate→harden handoff (operator-runbook-skill) routes a recurring failure to design a mechanism, and part of that design is asking this placement question before defaulting to the nearest hook.
- See also (complement) — control-substrate-dependency: that computes which substrate a control depends on; this chooses at what scope a control fires. Both are questions about a control's fit — one to the substrate it reads, one to the property it checks.