Architect
Rationale
ExplanationInformative

The configurability boundary

Almost nothing is purely configurable or purely fixed — every value sits inside an invariant, and the job is to write both down.

The slogan is configuration changes the path, never the walls. It is a good slogan and a bad model, because almost nothing in a real system is purely one or the other. Read the slogan as a reminder of what misconfiguration is allowed to cost, and the rest of this page as the model.

Getting the line wrong fails in two directions. Too far one way and you have a rigid product the client abandons because it no longer matches how they work. Too far the other and you have a product whose confidentiality guarantee is whatever the last administrator typed.

Most things are not one or the other

The binary — this field is configurable, that one is fixed — breaks on the first real field. Almost everything is a configurable value inside a fixed invariant:

FieldThe value, configuredThe invariant, fixed
Retention period3 years, 7 years, whatever the client setsNever below the statutory minimum, never above the legal maximum; the deletion job runs regardless
Approval threshold50 million, 10 millionAbove the threshold, a second approver is required, and it may not be the same person
Workflow guardWhich conditions gate this stepThe step's required capability comes from a trusted registry, never from the configuration
File size limit10 MB, 25 MBContent is validated on its real type; the scan runs; the quota exists
Territory listWhatever territories existEvery record has exactly one; it is never empty

The question is never "configurable or fixed". It is: what is the value, and what is the invariant that value may never break?

Write both. The invariant goes in the module reference; the value goes wherever it is changed from — a versioned configuration artefact you publish, or an administration screen the client operates. Either way a publication check enforces the invariant against the value before the change takes effect.

The two tests

First — is there a value here at all?

Would this statement be false if the client reorganised next year?

Yes → there is a configurable value. No → it is pure specification.

Second — what invariant bounds it?

Run the value against each of these. Any yes is an invariant you must write down and enforce; it does not make the value unconfigurable.

If an administrator sets this wrong, can it…Then the invariant concerns
let someone see what they should not?confidentiality
let someone change or delete what they should not?integrity
let one person complete an act alone that requires two?separation of duties
move money, or move more of it than someone may authorise?financial authority
breach a statutory minimum or maximum?legality
destroy records before they may be destroyed?retention
make the system unusable, or a record unreachable?availability
cause physical or personal harm?safety

A value with no yes is free configuration. A value with several is still configurable — it just carries several fixed bounds.

Where the value almost always exists

These carry a configurable value in nearly every system. That does not mean they carry no invariant — run them through the table above.

ElementExamples
Organisational unitsServices, teams, directorates, branches, and their names
Territories and their coverageWhich unit covers which area, dated so history survives
Category setsRequest types, actor categories, document types, priority levels
Process stepsThe states, the transitions, their order, their guards
Required inputsWhich documents, which fields, per category
Thresholds and boundsAmounts, sizes, formats, deadlines, retention
Labels and templatesWhat things are called, what notifications say

What has no configurable value at all

A small set of things really is pure specification — there is no value to set, only a rule. Changing one is a specification change, reviewed as such.

ElementWhy it cannot be configuration
CapabilitiesAdding one means deciding who holds it; that is a design act
Role × capability matrixIf this is runtime data, no statement about confidentiality is verifiable
Object ownership"Only the author sees their own record" cannot be switched off by an admin
Separation of dutiesThe rule exists precisely to constrain people with administrative reach
Audit integrityA log an administrator can rewrite proves nothing
Identity uniquenessOne person, one account — otherwise every separation rule is bypassable
Allowed effect typesConfiguration may select an effect; it may never define a new one

The asymmetry worth stating out loud

A badly configured system must be able to stall a case. It must never be able to expose one, pay out on one, or destroy one.

This is the sentence to put in the specification. It does not decide every field on its own — that is what the invariant table is for — but it settles the argument about what misconfiguration is allowed to cost, which is the argument that actually recurs.

Three-family enumerations

Closed does not mean fixed. Sort every enumeration into one of three families and say which route changes it:

FamilyChanged byExample
Fixed by specificationEditing the specificationRoles, verdict values, visibility scopes
Administered reference dataAn administration capabilityTerritories, units, categories, request types
Carried by a versioned artefactPublishing a new version of that artefactWorkflow states and transitions

All three are closed — no free text, no "other" category. They differ only in who may change them and how.

Configuration is not free

Four costs, all real. They are the price of the administration surface — not of the schema. If you cannot fund all four, defer the surface: hold the value in a versioned configuration artefact you change on the client's behalf. Do not defer the schema.

  1. Validation. Configuration without validation is worse than a constant: it lets someone configure an incoherent state and discover it in production. Every configurable surface needs a publication check — references resolve, no unreachable state, no dead end, every value mapped.
  2. Withdrawal safety. Retiring a configured element while live records depend on it makes those records unreachable with no visible error. Nothing is deleted; things are retired; and retirement is refused while dependencies exist.
  3. History. Old records must keep the meaning they had. Retired elements stay readable with the labels they carried at the time. A rename that rewrites history is a bug, not a feature.
  4. Governance. Who may change the value, whether the change needs a second pair of eyes, how it is rolled back, and what trail it leaves. Removing the deployment step does not remove the review step.

And one fact that is not a cost: somebody has to operate it. A client with no administrator gets a screen frozen at its defaults, and you have built governance and rollback to achieve nothing. Ask who will operate it before deciding to build a screen. That question never touches the schema.

Separate the administration of things from the administration of access

If belonging to a configured unit grants access to records, then whoever can create units and place people in them can grant access — regardless of what the access-control design says.

Split it:

  • one capability administers the lists — create, rename, retire units, territories, categories;
  • a different capability administers people — who belongs to which unit, who holds which role.

Neither alone opens access to anything. Cheap to specify, and impossible to retrofit once an administration screen exists.

Worked example — a ministry's grant platform

The first specification said "the ministry has 32 regional directorates" and "the 8 central directorates are: …", and produced a 28-item question list for the client, of which the first two were "give us the list of the 32" and "tell us which of the 8 participate".

Both were blocking. Neither should have been asked.

What the corrected model separated:

NotionWhat it isFamily
TerritoryA locality the applicant declares. Geography, not organisation.Administered
Organisational unitA service that acts in the process, carrying a closed operational functionAdministered — except the function
Territorial competenceDated mapping between the twoAdministered

The operational function — does this unit instruct, or is it consulted — stayed fixed in the specification, because the product behaves differently for each and confusing them would erase a step. Everything else became data.

Two further corrections fell out of it:

  • The applicant declares where they are, never which internal service handles it. Making them pick a service exposes the org chart to someone who has no reason to know it, and their declaration becomes false at the next reorganisation.
  • Access stayed an intersection — bounded by unit and by territory. Collapsing them into "any unit you belong to" turns AND into OR and grants an agent their whole unit nationwide plus their whole territory across every unit.

The question list went from 28 to 13 — 15 of 28 were configuration, just over half.

Note what did not become configurable, and why. The role × capability matrix stayed fixed: making it runtime data would have meant no statement about confidentiality was verifiable. The operational function stayed fixed: the product behaves differently for a unit that instructs and one that is consulted. Both are invariants, not values.

On this page