Version: l4-kernel.v1
Status: contract · Conceptual layer: ④ Decision · Repo layer: L4 knowledge-reasoning · Source: architecture section 3.6.4, section 5.3, section 8 · ADRs: 020 · 025 · 026

Frozen surface — changes only through an ADR, a kernel version bump, and a full replay. Sibling docs link here; they must not restate these rules in softer language.

“Frozen” means replay has a fixed yardstick and the plant has a stable promise. It does not mean the kernel never changes. It is kept small and parameterised by registries, so most expansions never touch it.


1. Terminals#

Every DecisionCaseOne run unit: intake + snapshot + obligations + candidates + terminal ends in exactly one terminal, always with a DecisionTraceAlways-on record: observed, context, action, policy, approval, outcome (and seam decisions):

TerminalMeaning
emitSend one Prescription to L5 (as built: card proposal / prescription.json 1.0.0)
supersedeReplace a prior L4 proposal for the same condition key before owner acceptance
withholdDo not send; reason recorded (constraint, disagreement, proof floor, etc.)
abstainInsufficient case to decide; reason recorded

Portfolio hold is not a terminal. It is L4-internal: the proposal stays in the L4 store, visible to staff, and is not sent to L5.


2. One-card rule#

  • One card per condition keyStable id for “this plant condition”; one open card per key.
  • One recommended action; at most two alternatives; one alternative is always no action.
  • One owner role from the configured role set.
  • Primary domain is a domain registry id, taken from the family registry (Findings) or the pattern registry (discoveries).
  • The kernel refers to registries by id. It never lists domains by name.

3. Write ban#

No L4 tool writes equipment, schedules, dispatch, quality holds, maintenance authorization, master data, or customer commitments. Reads only. Side effects belong to L5 policy (default off) after a human accepts.


4. Money#

Rupees only from L3 calculator references. An unreferenced rupee (or any money field without a calculator citation) → drop the claim; if the candidate still depends on that unreferenced rupee → withhold. Models never invent or assign a rupee. Non-money quantities without citations are dropped as uncited claims (section 13); they do not by themselves force withhold unless a family proof obligation requires them. Section wallets are never summed into one hero number.


5. Constraint evaluator#

Code evaluates typed constraints. Result:

ResultKernel action
violatedwithhold
unknown on a hard constraintwithhold (reason=constraint_unknown)
LLM “possible conflict” without a code resultwithhold (gate_id=llm_possible_conflict, hard)

None of these can be overridden by modeled benefit. Code always evaluates every hard constraint row whose footprint intersects the candidate. Models may only add advisory rows to evaluate; they may never omit a matching hard row.


6. Verification plan#

A verification plan may only narrow its source plan (FindingAs-built L3 detector output admitted to L4 (finding.json 1.2.0) plan or L3-built discovery plan): same boundary, equal or tighter bounds. It may not invent new signals or widen scope.


7. Supersede#

Supersede only before owner acceptance. After acceptance → a separate card or a conflict note — never silent replace. Wire fields: 18-contract-deltas.md.


8. Simulator output#

L3 simulator output is evidence tierContract tier on claims: measured / confirmed / modeled / unknown; quantity labels per D13 Modeled, cites method and version, and must sit inside that method’s validated envelope to support emit. Out-of-envelope → withhold (gate_id=simulator_out_of_envelope, hard).


9. Hard stops#

Hard stops from the master document section 7 always apply: no silent safety or critical-equipment control; no quality hold release, conformance sign-off, or process acceptance; no maintenance authorization or lockout bypass; no silent change to customer priority, promise dates, routing, master data, or the full dispatch sequence. A quality correction and a near-term sequence are allowed when a named person accepts them before any write-back. No constraint override for a model benefit alone.


10. No self-promotion#

Nothing in procedural memory, prompts, registries, thresholds, or model pins promotes itself. Changes go through release lockfile, replay, and a named owner where required. A global pin applies at a plant only after that plant’s named owner accepts it (or has opted in to automatic acceptance of global pins).


11. Gates: hard vs soft#

Every gate is typed hard or soft. Every block records the gate idStable id of the hard or soft gate that blocked a candidate (canonical table below). Detail and exploration eligibility: 22-missed-opportunities.md.

Hard gates (never tunable, never in backlog, never explored)#

gate_idTrigger
hard_stopADR-018 sacred constraints
constraint_violatedCode evaluator violated
constraint_unknown_hardunknown on hard / conditional-hard neighbourhood
llm_possible_conflictModel flags conflict without code result
unreferenced_rupeeMoney without calculator citation after claim drop
write_toolWrite / OT side-effect tool attempted
proof_floorMissing asset bind, verification path, or L3 condition test (discoveries)
simulator_out_of_envelopeModeled support outside validated use
action_seam_disagreementDual-family disagreement on action / owner / constraint-affecting / verification / terminal seams
uncertified_detectorUncertified detector version (shadow / withhold — never emit)
supersede_after_acceptAttempt to supersede after owner acceptance
staleness_hard_limitFreshness past the hard staleness limit

Action-seam disagreement is hard, not soft. Two families either picked the same closed option or they did not — there is no tunable “agreement floor” for action-affecting seams.

Soft gates (thresholds in registry; tuned by evidence; exploration-eligible only when listed in 22)#

gate_idTrigger
routing_agreementDisagreement on routing-class seams only (workflow, optional analysis, …) — uses registry default; soft for calibration of whether default was right
one_family_confidenceOne-family mode numeric floors
evidence_tier_minSoft minimum tier for emit path
freshness_marginSoft freshness (hard limit is staleness_hard_limit)
attention_budgetOver per-role shift budget → hold
reproposal_cooldownNegative memory cooldown
hypothesis_volume_capGrounded-hypothesis lane volume
pattern_precisionPattern demotion to shadow

12. Stage-graph checkpoints#

Every stage graph (see 21-registries-and-stage-graph.md) must still pass:

  1. Constraint evaluator before portfolio
  2. Portfolio before terminal
  3. Card minimizer (one primary domain, wallets not summed, verification narrowed) before kernel re-check
  4. Kernel re-check on the chosen set before terminal

Default order: candidates → constraint evaluator → portfolio → card minimizer → kernel re-check → terminal.

Kernel re-check (normative list)#

On the chosen set, code re-verifies: money references; write ban; constraint results for intersecting hard rows; proof floorMinimum evidence/structure required before emit (asset bound, verification path, L3 condition test for discoveries); one-card / one-owner shape; verification narrow-only; action-seam disagreement not present; simulator envelope if Modeled supports emit. Failure → withhold / abstain with reason — never quiet emit.


13. Evidence#

  • Every claim cites a ledger row id. Uncited claims are dropped by code (gate_id recorded when drop invalidates the candidate).
  • EvidenceLayer contract for detector output (direction; as built: Finding finding.json 1.2.0) tiers are assigned by code from source type (as built ledger: Measured / Confirmed / Modeled / Unknown; direction: evidence labels and contract tiers per D13). Models never assign a tier.
  • Partitions (measured, advisory, model) are never merged.

14. Primary domain#

Primary domain is a domain registry id:

  • Findings → from the family registry
  • Certified patterns → from the pattern registry
  • Grounded hypotheses → from the hypothesis type’s registry entry (required field before the lane may emit)

The kernel never lists domain names.


Change control#

ChangePath
Soft-gate thresholdRegistry + replay + owner acceptance
New domain / stage / patternRegistry + replay (17-change-guide.md)
Any rule in this fileADR + l4-kernel version bump + full replay

v1 slice vs later#

v1Later
This kernel version (l4-kernel.v1) as the yardstickNew version only via ADR + full replay
Hard vs soft gate split as listedSoft list may grow via registry; hard list only via ADR
Dual-family disagreement → withhold on action-affecting seamsSame unless an ADR changes disagreement policy
Page history: last 5 changes
  1. 2026-10-07 docs: keep agents out of archive; changelog; final check suite fd7f122
  2. 2026-10-07 docs(technical): rewrite l4 00-10 to the architecture c52a111
  3. 2026-10-03 docs(decisions): add ADR-033..038 (twin runtime, fast read path, plant-side writer, message classes, alerts and quality-to-lot link, part-keyed parameters), fast-loop technical set, rebuilt index with renumbering map; fix bare-number link text and ranges 22e2872
  4. 2026-10-03 docs(decisions): renumber live ADRs 001-032 in order, mark withdrawn refs ADR-W###, repoint withdrawn links to archive, note partial supersessions 36c944e
  5. 2026-09-25 docs(l4): agentic decision architecture, ADRs, and production hardness 8275e7c

Diagram

100%

Search the architecture