import { ALGO_FACE, KIND_FACE, LAYER_FACE } from "@govlab/constants";
import { CANON_SECTION_ICON, GROUPING_SECTION_ICON, KIND_SECTION_ICON } from "#configuration/icons/architecture.icons";
import { CANON_SECTION_ID, GROUPING_SECTION_ID, RECORD_KIND_SECTION_ID } from "#core/ids/architecture.ids";
import {
KIND_SECTION_ID,
LEXICON_TAB,
MEMBERSHIP_SECTION_ID,
RANGE_SECTION_ID,
SCHEMA_TAB,
TOPOLOGY_SECTION_ID,
} from "#core/ids/ontology.ids";
import { pagePath, tabLink } from "#assets/link.assets";
import { ONTOLOGY_PAGE } from "#core/ids/page.ids";
import type { Section } from "#types/document.types";
import { TYPESCRIPT_LANGUAGE } from "#configuration/constants/code.constants";
import { faceLink } from "#domain/converters/ontology.converter";
const PRINCIPLE_SHAPE =
'export type Kind =\n | "anti-pattern" | "metric" | "quality-attribute" | "principle" | "constraint"\n | "capability" | "activity" | "pattern" | "mechanism" | "technique"\n | "approach" | "model" | "artifact" | "style";\n\nexport interface Principle {\n readonly id: string;\n readonly name: string;\n readonly type: Kind;\n readonly category: string;\n readonly scope: readonly string[];\n readonly requires: readonly string[];\n readonly reinforces: readonly string[];\n readonly enables: readonly string[];\n readonly conflictsWith: readonly string[];\n readonly tensionsWith: readonly string[];\n readonly violatedBy: string;\n readonly detectedBy: string;\n readonly measuredBy: string;\n readonly refactoredBy: string;\n readonly enforcedBy: string;\n readonly severity: string;\n readonly exemplar?: { readonly before: string; readonly after: string; readonly lang: string };\n}\n\nexport interface Issues {\n readonly danglingEdges: readonly { from: string; relation: string; target: string }[];\n readonly duplicateIds: readonly string[];\n}\n\nexport const validate = (canon: readonly Principle[], resolveId: (name: string) => string | null): Issues => {\n const ids = new Set(canon.map((principle) => principle.id));\n const edges = ["requires", "reinforces", "enables", "conflictsWith", "tensionsWith"] as const;\n return {\n danglingEdges: canon.flatMap((principle) =>\n edges.flatMap((relation) =>\n principle[relation]\n .filter((target) => resolveId(target) === null && !ids.has(target))\n .map((target) => ({ from: principle.id, relation, target })),\n ),\n ),\n duplicateIds: canon.map((principle) => principle.id).filter((id, index, all) => all.indexOf(id) !== index),\n };\n};';
const KIND_SHAPE =
"export interface KindRecord {\n readonly kind: Kind;\n readonly discriminator: string;\n readonly distinguishesFrom: string;\n readonly definitionSignatures: readonly string[];\n}\n\nexport const kindAgrees = (term: { readonly kind: Kind; readonly definition: string }, taxonomy: readonly KindRecord[]): boolean => {\n const record = taxonomy.find((entry) => entry.kind === term.kind);\n return record !== undefined && record.definitionSignatures.some((signature) => term.definition.includes(signature));\n};";
const CANON_DIAGRAM =
'flowchart TB\n principle["A principle · one canonical id, one kind, one category, a severity"]\n requires["requires · cannot hold without"]\n reinforces["reinforces · holds more easily beside"]\n enables["enables · makes possible"]\n tensions["in tension with · a record it pulls against, resolved by mechanism"]\n conflicts["conflicts with · the anti-patterns that negate it"]\n violated["violated by · what a violation looks like"]\n detected["detected by · the signals that see it"]\n measured["measured by · the numbers that size it"]\n refactored["refactored by · the repairs that reverse it"]\n enforced["enforced by · the gates that hold it"]\n principle --> requires\n principle --> reinforces\n principle --> enables\n principle --> tensions\n principle --> conflicts\n principle --> violated\n principle --> detected\n principle --> measured\n principle --> refactored\n principle --> enforced\n gate["A resolution gate · every edge resolves to a record or a defined term, every kind is in range, or the gate refuses"]\n requires -.-> gate\n tensions -.-> gate\n conflicts -.-> gate';
const RECORD_DIAGRAM =
"classDiagram\n class Principle {\n id\n name\n kind\n category\n severity\n violatedBy\n detectedBy\n measuredBy\n refactoredBy\n enforcedBy\n }\n class Term {\n id\n name\n kind\n definition\n }\n class AntiPattern {\n id\n absentControl\n }\n class Layer {\n id\n observes\n feeds\n }\n Principle --> Principle : requires\n Principle --> Principle : reinforces\n Principle --> Principle : enables\n Principle --> Term : tensions with\n Principle --> AntiPattern : conflicts with\n Principle --> Layer : member of";
const KIND_MINDMAP =
'flowchart TB\n kind(("kind"))\n rule["a rule"]\n measure["a measure"]\n doing["a doing"]\n shape["a shape"]\n avoid["a condition to avoid"]\n kind --> rule & measure & doing & shape & avoid\n rule --> principle["principle · prescribes"] & constraint["constraint · must hold"]\n measure --> metric["metric · a number"] & quality["quality attribute · a degree"]\n doing --> capability["capability · what can be done"] & mechanism["mechanism · the facility"] & technique["technique · the method"] & approach["approach · the strategy"]\n shape --> pattern["pattern · an arrangement"] & model["model · a representation"] & convention["style · a convention"] & artifact["artifact · a produced thing"]\n avoid --> anti["anti-pattern"]';
const KIND_DIAGRAM =
'flowchart TB\n record["A record"]\n question{"What does the definition say it is?"}\n property["a property held to a degree · quality attribute"]\n number["a measurement · metric"]\n rule["a rule that prescribes · principle"]\n bound["a rule that must hold · constraint"]\n facility["a facility that does it · mechanism"]\n method["a method a person applies · technique"]\n arrangement["a design-level arrangement · pattern"]\n avoided["a condition to avoid · anti-pattern"]\n record --> question\n question --> property\n question --> number\n question --> rule\n question --> bound\n question --> facility\n question --> method\n question --> arrangement\n question --> avoided\n polarity["The polarity law · only conflicts-with may point at an anti-pattern"]\n avoided -.-> polarity';
const LAYER_DIAGRAM =
'flowchart TB\n subgraph core["The four core layers"]\n computation["computation · stateless"]\n resource["resource · stateful"]\n execution["execution · control flow and events"]\n structural["structural · applies to all, observes itself"]\n end\n human["human factors · what a person can hold"]\n evolution["evolution · how the whole changes"]\n subgraph crosscut["Cross-cutting layers · each cuts across the structural core"]\n correctness["correctness"]\n security["security"]\n performance["performance"]\n contracts["contracts"]\n causality["causality"]\n declarative["declarative"]\n extensibility["extensibility"]\n observability["observability"]\n enforcement["enforcement"]\n atomic["atomic boundary"]\n domain["domain modeling"]\n patterns["design patterns"]\n end\n resource -- observe --> computation\n computation --> execution\n resource --> execution\n execution --> structural\n structural -- feedback --> execution\n structural --> human\n structural --> evolution\n evolution --> human\n crosscut -. cross-cuts .-> structural';
const CANON_SECTION: Section = {
icon: CANON_SECTION_ICON,
id: CANON_SECTION_ID,
intro: `A principle is a typed record, never a slogan, the record a principle record types with the slots ten slots draws and the edges the five edges traces. The whole canon resolves by identity join, which is what turns a list of good ideas into something a check can consult, and every record this page names can be opened and walked on the ontology page.`,
subsections: [
{
blocks: [
{
application:
"Give every principle one identity that nothing else carries, a kind from a closed taxonomy and a category from the data that holds it. Record its relations to the other records as names that resolve to identities, never as free prose, and record what violates it, what detects and measures a violation, the repairs that reverse it and the gates that enforce it. Attach an exemplar with a before and an after, and let the gate prove the whole before anything consults it.",
boundary:
"A canon is a vocabulary for reasoning, and it is the wrong home for a threshold or a path. A principle says that complexity is bounded; the number lives in the gate's config and the check reads it there. A canon that carries numbers is a second config, and a canon that carries paths is bound to one tree.",
cause: "Prose principles cannot be joined, so nothing can compute which principle a finding violates, which repair follows, or which two principles a design has set against each other.",
decision: "Hold the canon as data a gate resolves rather than as a document a reviewer cites.",
failureMode:
"A review cites a principle by name, a second review cites its opposite by another name, both are in the document, and nobody can show that the two were ever meant to conflict or how the conflict resolves.",
kind: "lesson",
principle:
"Principles are typed and related, and a canon that does not resolve by identity is refused by its gate.",
problem:
"Architecture principles are usually a reading list, and a reading list cannot tell you which of its entries a given change just broke.",
validation:
"Take a finding from any check and resolve its canonical id. It must reach the principle, the principle's severity, its repairs and its relation graph in one lookup. A finding that reaches only a message has no canon behind it.",
},
{ caption: "ten slots", kind: "mermaid", text: CANON_DIAGRAM },
],
title: "Ten slots, one gate",
},
{
blocks: [
{
kind: "text",
text: `Requires says a principle cannot hold without another, so a design that adopts modularity has adopted its ${faceLink(ALGO_FACE, "dependency-closure", "whole closure")} whether it meant to or not. Reinforces says two principles hold more easily together, which is how an improvement ${faceLink(ALGO_FACE, "reinforcement-propagation", "propagates")} past the record it was made to. Enables says one makes another possible.`,
},
{
kind: "text",
text: `In tension with says two records pull against each other on one construct, and every such pair carries a resolution whose mechanism follows from what the two records are. Conflicts with is the one negative edge: it points from a principle to the ${faceLink(KIND_FACE, "anti-pattern", "anti-patterns")} that negate it, and the polarity law says it may point nowhere else.`,
},
{ caption: "the five edges", kind: "mermaid", text: RECORD_DIAGRAM },
],
title: "The five edges",
},
{
blocks: [
{
kind: "text",
text: `The descriptors are prose a person reads. Violated-by describes the violation, detected-by the ${faceLink(ALGO_FACE, "violation-detection", "signals that see it")}, measured-by the numbers that size it, refactored-by the ${faceLink(ALGO_FACE, "refactor-selection", "repairs that reverse it")}, and enforced-by the ${faceLink(ALGO_FACE, "enforcement-gate", "gates that hold the line")}.`,
},
{
kind: "text",
text: `${faceLink(ALGO_FACE, "severity-policy", "Severity")} says how strictly the principle binds and, where the record states one, the condition under which it binds that strictly. It is a routing field: it decides which handler a failure reaches, a refusal, a review note or an information line, and it never ranks one principle above another. A check still answers pass or fail; severity says what happens to the answer.`,
},
{ code: PRINCIPLE_SHAPE, kind: "code", language: TYPESCRIPT_LANGUAGE, title: "a principle record" },
],
title: "The five descriptors",
},
{
blocks: [
{
kind: "text",
text: "Modularity is a mandatory principle in the structural core. It requires high cohesion, low coupling and explicit boundaries, because a module whose insides do not belong together, or whose edges nobody drew, is not one you can replace. It reinforces separation of concerns and composability, and it enables replaceability and plugin architecture.",
},
{
kind: "text",
text: "It is in tension with cross-cutting concerns, and that pair carries a recorded resolution. It conflicts with the big ball of mud, the one anti-pattern that is its outright negation. A reading list can tell you modularity is good. The record can tell you what you have already committed to by choosing it, what you will get for free, and what it refuses.",
},
{
kind: "text",
text: "Its descriptors meet the tree. It is violated by cyclic dependencies, shared mutable state and boundary leakage. It is detected by dependency cycles and an unstable module graph, measured by a modularity score, graph density and instability, and refactored by splitting the module, introducing a boundary or inverting the dependency. It is enforced by module rules, package ownership and fitness functions, and that last slot is the difference between a canon and a book: a principle with an empty enforced-by is a wish.",
},
],
title: "One record, walked",
},
],
title: "Principles are typed",
};
const KIND_SECTION: Section = {
icon: KIND_SECTION_ICON,
id: RECORD_KIND_SECTION_ID,
intro: `Every record carries a kind from a closed taxonomy. The kind is read the way kind from definition draws, and the kinds are the set the fourteen kinds groups and a kind record types. The kind decides what may point at a record, how a tension with it resolves and whether a check can measure it, so a wrong kind is a wrong answer to every one of those questions at once.`,
subsections: [
{
blocks: [
{
application:
"Read the definition and ask what it describes: a degree a system exhibits, a number, a rule that prescribes, a rule that must hold, a facility, a method, an arrangement, a representation, a produced thing, a convention of expression, or a condition to avoid. Assign the kind from that reading and never from the name.",
boundary:
"A kind classifies what a record is, never how important it is. Two records of the same kind can differ in severity, and a quality that a whole system depends on is still a quality rather than a rule, because the taxonomy answers one question and severity answers another.",
cause: "Names are chosen for recognition and definitions are written for precision, so the name of a record tends to overclaim its kind, and the overclaim is only visible once someone reads the definition against the taxonomy.",
decision:
"Hold each kind's discriminator as data the gate reads, rather than as a reviewer's judgement, so a record whose definition disagrees with its kind is refused rather than shipped.",
failureMode:
"A quality that a system exhibits to a degree is filed as a principle, a check is written to enforce it as a rule, and the check has nothing to return because a degree has no violation to report.",
kind: "lesson",
principle: "A record's kind follows from its definition, and the taxonomy of kinds is closed.",
problem:
"Everything on a reading list is called a principle, so a quality, a mechanism and a technique are argued as though they were rules.",
validation:
"Take any record and cover its name. Read the definition and name the kind from the definition alone. If it differs from the kind the record carries, the record is mis-filed, and every edge that points at it has been reasoning about the wrong thing.",
},
{ caption: "kind from definition", kind: "mermaid", text: KIND_DIAGRAM },
],
title: "Read the definition, not the name",
},
{
blocks: [
{
kind: "text",
text: `Each kind answers one question: a rule, a measure, a doing, a shape or a condition to avoid. The pairs that are most often confused sit closest: a metric is the measurement and a quality attribute is the property measured, a principle prescribes and a constraint binds, a mechanism is the facility and a technique is the method a person applies. The gate checks that every kind is in range, and for a defined term it checks that the kind agrees with the definition, so a term cannot call itself a principle while defining a metric.`,
},
{ caption: "the fourteen kinds", kind: "mermaid", text: KIND_MINDMAP },
{ code: KIND_SHAPE, kind: "code", language: TYPESCRIPT_LANGUAGE, title: "a kind record" },
],
title: "The fourteen kinds",
},
{
blocks: [
{
kind: "text",
text: "Reading a kind off a name is the mistake the taxonomy exists to catch. Homoiconicity is a quality attribute, a degree a system exhibits, whatever a reading list calls it. Orchestration and choreography are mechanisms, facilities that do a thing. Pure functions are a technique a person applies. Event sourcing and CQRS are patterns, arrangements a design takes. Fail fast is a principle and idempotency is a principle, because each prescribes.",
},
{
kind: "text",
text: "A check can enforce a principle and measure a metric, but it cannot enforce a quality attribute. A tension between two principles can separate by scope, while a tension between a principle and a quality attribute can only be traded, which separate, trade, or mitigate derives.",
},
],
title: "What a name overclaims",
},
],
title: "Every record has a kind",
};
const GROUPING_SECTION: Section = {
icon: GROUPING_SECTION_ICON,
id: GROUPING_SECTION_ID,
intro: `The canon is grouped twice, and the two groupings answer different questions. The records are held in topical categories, so a reader looking for least privilege finds it beside the other security records and backpressure beside the other resilience records. Each category is then a member of one layer, in the topology the layers draws, and the layers are where tensions resolve, because a layer is a scope a principle can hold whole in.`,
subsections: [
{
blocks: [
{
application:
"Group records by topic for the reader who is looking for one, and map every topical group to exactly one layer for the check that has to decide a scope. Keep the two groupings as data with one derivation between them, so a record's layer is read from its category and never stated twice. Record which layer observes, feeds or cuts across which, because that topology is what a scope-separation between two principles is decided against.",
boundary:
"A grouping is a lookup structure and never a claim about a record. A principle in the security category is not more important than one in the structural category, and a layer is not a rank; the layer says only which scope a principle holds whole in.",
cause: "One grouping cannot serve both a reader and a check, because a reader looks by topic and a check decides by scope, and a canon that picks one leaves the other question answered by guesswork.",
decision: "Keep both groupings rather than pick one, at the cost of one derivation between them.",
failureMode:
"Two principles pull against each other, the reviewer looks for the domain each belongs to, and finds two topical categories that say nothing about scope, so the tension is settled by whoever argues longer.",
kind: "lesson",
principle:
"A canon is grouped by topic for people and by layer for checks, and the layer is derived from the topic rather than stated beside it.",
problem:
"A canon organised one way answers one question, and the other question is answered from memory.",
validation:
"Take any principle and name its layer without opening the record, from its category alone. If the category does not decide it, the grouping is a reading order and not a scope, and no tension that names this principle can be resolved by data.",
},
{ caption: "the layers", kind: "mermaid", text: LAYER_DIAGRAM },
],
title: "By topic for people, by layer for checks",
},
{
blocks: [
{
kind: "text",
text: `Four layers form the core. ${faceLink(LAYER_FACE, "computation-core", "Computation")} is stateless and its outputs are frozen. ${faceLink(LAYER_FACE, "resource-core", "Resource")} is stateful, and every handle has one owner and a bounded lifetime. ${faceLink(LAYER_FACE, "execution-core", "Execution")} is control flow and events. ${faceLink(LAYER_FACE, "structural-core", "Structural")} applies to everything and observes itself.`,
},
{
kind: "text",
text: `Beneath the core sit ${faceLink(LAYER_FACE, "human-factors", "human factors")}, which bound the whole by what a person can hold, and ${faceLink(LAYER_FACE, "evolution-principles", "evolution")}, which says how the whole changes over time. Around the core sit the layers that cut across it: ${faceLink(LAYER_FACE, "correctness-core", "correctness")}, ${faceLink(LAYER_FACE, "security-core", "security")}, ${faceLink(LAYER_FACE, "performance-core", "performance")}, ${faceLink(LAYER_FACE, "contracts-core", "contracts")}, ${faceLink(LAYER_FACE, "causality-core", "causality")}, ${faceLink(LAYER_FACE, "declarative-core", "declarative design")}, ${faceLink(LAYER_FACE, "extensibility-core", "extensibility")}, ${faceLink(LAYER_FACE, "observability", "observability")}, ${faceLink(LAYER_FACE, "enforcement-core", "enforcement")}, the ${faceLink(LAYER_FACE, "atomic-boundary", "atomic boundary")}, ${faceLink(LAYER_FACE, "domain-modeling", "domain modeling")} and ${faceLink(LAYER_FACE, "design-patterns-core", "design patterns")}.`,
},
{
kind: "text",
text: `The topology records which layer observes, feeds or cuts across which. A principle stated in one layer reaches the others by relation, never by being restated there.`,
},
],
title: "The layers",
},
{
blocks: [
{
kind: "text",
text: `The derivation is single source of truth applied to the grouping, and the same reasoning shapes how a record names its relations. Identity is the one thing written literally, and everything that points at a record does so by a name that resolves to that identity, so a leaf record depends on nothing beside it and a display name can be corrected without breaking an edge. Held that way the canon is a graph rather than a list, the ${faceLink(ALGO_FACE, "architecture-knowledge-graph", "whole of it is traversable")}, and each ${faceLink(ALGO_FACE, "architectural-relationship-record", "principle record")} reconciles to one vocabulary rather than the vocabulary bending to the records.`,
},
],
title: "One derivation, never two facts",
},
],
title: "The canon is grouped twice",
};
export const CANON_SECTIONS: readonly Section[] = [CANON_SECTION, KIND_SECTION, GROUPING_SECTION];