import { CHAIN_SECTION_ICON, DEPLOY_SECTION_ICON, SCALE_SECTION_ICON } from "#configuration/icons/release.icons"; import { CHAIN_SECTION_ID, DEPLOY_SECTION_ID, SCALE_SECTION_ID } from "#core/ids/release.ids"; import { GAP_SECTION, RETIRED_SECTION } from "#configuration/strings/release.fragment.strings"; import type { Section } from "#types/document.types"; import { TYPESCRIPT_LANGUAGE } from "#configuration/constants/code.constants"; const STAGE_SHAPE = 'export const STAGE_SLUGS = ["", "", ""] as const;\nexport type StageSlug = (typeof STAGE_SLUGS)[number];\n\nexport interface Member {\n readonly id: string;\n readonly dir: string;\n readonly gated: boolean;\n readonly tests: string | null;\n}\n\nexport interface Step {\n readonly label: string;\n readonly command: readonly string[];\n readonly scope: "wide" | "perMember" | "appOnly";\n readonly tags: readonly ("generate" | "validate" | "build")[];\n readonly produces?: string;\n readonly consumes?: string;\n}\n\nexport interface Stage {\n readonly slug: StageSlug;\n readonly bypassedByDefault: boolean;\n readonly parallel: boolean;\n readonly steps: readonly Step[];\n}\n\nexport declare function stagesFor(scope: { readonly members: readonly Member[]; readonly only?: string; readonly bypass?: readonly StageSlug[] }): readonly Stage[];'; const CHAIN_DIAGRAM = 'flowchart TB\n command["one command"]\n rederive["the rule index is re-derived from disk before any stage"]\n prepare["dependency integrity, one typecheck per member"]\n unused["dead code, dead exports, dead dependencies"]\n fixers["strip comments, rebuild the graph, run the rewriters"]\n format["the formatter, fix on"]\n lint["every linter, per member, fix on, reading the graph the fixers wrote"]\n test["every suite, then the passing-test floor"]\n build["the site, the diagrams, the chapters, every generator, every derivation"]\n validate["discovery, leaks, graphs, configs, documents"]\n report["the one aggregate · written on every exit"]\n command --> rederive --> prepare --> unused --> fixers --> format --> lint --> test --> build --> validate --> report\n prepare -. fail fast .-> report\n lint -. fail fast .-> report\n test -. fail fast .-> report'; const NARROWING_DIAGRAM = 'flowchart TB\n whole["No arguments · every stage, whole scope, healing on"]\n member["A member · that member\'s steps, repo-wide steps reported as skipped"]\n step["A step · only that step"]\n bypass["A bypass · one stage skipped, local iteration only"]\n claim["A completion claim"]\n whole --> claim\n member -. never satisfies .-> claim\n step -. never satisfies .-> claim\n bypass -. never satisfies .-> claim'; const SCALE_DIAGRAM = 'flowchart TB\n work["A body of work"]\n partition["Partition it into concerns that must be able to contradict each other"]\n floor["Floor · the number of concerns"]\n fanin["Measure the fan-in on each shared surface"]\n ceiling["Ceiling · the worst fan-in before claims stop surviving"]\n count["The count · a choice inside the range, with the partition written down"]\n work --> partition --> floor\n partition --> fanin --> ceiling\n floor --> count\n ceiling --> count'; const DEPLOY_DIAGRAM = 'flowchart TB\n routes["The served routes"]\n follow["Follow every path a text artefact names"]\n reached["What a page can reach"]\n prune["Delete everything else"]\n backup["Back up what is live"]\n upload["Upload the whole of what is left"]\n check{"Healthy?"}\n done["Live"]\n restore["Restore the backup"]\n routes --> follow --> reached --> prune --> backup --> upload --> check\n check -- yes --> done\n check -- no --> restore'; const CHAIN_SECTION: Section = { icon: CHAIN_SECTION_ICON, id: CHAIN_SECTION_ID, intro: "Every tool sits on one chain, the data a stage array types. One command runs the whole gate in stages, a pipeline architecture whose stages are ordered by causal dependency, as the stages draws, and each stage runs the checks, the fixers, the generators and the validators it owns. A check that only runs when someone remembers its command is a convention, and a convention is not a check; arguments narrow the chain for iteration, and only the whole run satisfies a claim, as narrowing draws. The chain is what turns a collection of tools into a verdict, and the gate holds the line is the rule it exists to serve.", subsections: [ { blocks: [ { application: "Give the project one entry point whose default is the whole pipeline, and let arguments narrow it and never widen it. Order its stages by what each one needs from the one before, and state the dependency when a step produces an artifact another stage consumes. Put every check, fixer, generator and validator in a stage as a direct call, never as an alias the gate shells out to. Write the aggregate on every exit path. Let the gate govern its own tooling with the same rules it applies to the code.", boundary: "Narrowing is for local iteration speed only. A member, a step or a bypass answers a question faster; a completion claim requires one unbypassed whole-scope run, and a narrowed run never overwrites the one aggregate, because a document about a narrower subject under the aggregate's name is a document about a different subject wearing the same name.", cause: "A tool outside the chain depends on a person's memory, and memory is the one component in the system with no check on it.", decision: "Route every tool through the one entry point.", failureMode: "Three linters, two of which nobody has run since spring, and a formatter that runs on some machines because of an editor plugin.", kind: "lesson", principle: "A tool reached only by its own command enforces nothing. One chain, and everything in it.", problem: "Tooling accumulates as separate commands, and the commands stop getting run.", validation: "List every check the project claims to have. Run the one command. Each check must appear in its output, or it is not a check the project has.", }, { kind: "text", text: "Stage order encodes real dependencies, event ordering in the ontology's sense, so it is load-bearing rather than tidy. A cleaning step runs before anything measures a file. A type check runs before any structural check reads a tree that may not compile. The fixer stage writes the closure graph the graph-aware rules read when they load, so it precedes linting, and a graph-aware rule fails closed when the graph is missing rather than passing over nothing. Several stages mutate the working tree, which is why an investigation never runs the gate, as agents as executed contracts says.", }, { kind: "text", text: "A registry the run consumes at load is re-derived before anything loads it, so deleting a member cannot kill the run that would have removed its entry; deleting a rule is then one step, as adding one is one dropped file. The chain checks its own registration contract and the shape of every finding.", }, { kind: "text", text: "Where a host already has a toolchain, the chain hands off rather than duplicating. The host elects which concerns to hand over, its tools stay its own, and there is one chain instead of two. A verification slot the host cannot fill, a build, a runtime probe, a size cap, resolves absent, the step reading it does not run, and the claim it would have settled is carried as observed by a person rather than as verified.", }, { kind: "text", text: "The chain is data before it is a run. A pure planner takes the resolved scope, which members, which step, which bypasses, and returns the stage array, and the runner walks that array in order, with the load-bearing order stated on the step rather than remembered. A member with no tests declares null rather than an empty string, because the two are different claims. Everything a stage-control flag can do is a function over this data, and nothing a flag does can add a step the array does not hold.", }, { code: STAGE_SHAPE, kind: "code", language: TYPESCRIPT_LANGUAGE, title: "a stage array" }, { caption: "the stages", kind: "mermaid", text: CHAIN_DIAGRAM }, { caption: "narrowing", kind: "mermaid", text: NARROWING_DIAGRAM }, ], title: "Everything through one chain", }, ], title: "One chain", }; const SCALE_SECTION: Section = { icon: SCALE_SECTION_ICON, id: SCALE_SECTION_ID, intro: "Nobody chooses how many parties a body of work needs. The count follows from how the work partitions into concerns that must be able to contradict each other. The floor is the number of those concerns. The ceiling is set by the worst fan-in, the point where claims resting on one surface stop surviving, and floor, ceiling, count draws where each comes from. A count with no partition behind it is a preference, and the fan-in finds it out. The architecture page derives the same range for a system, where a concern is a component and the ceiling moves by cost.", subsections: [ { blocks: [ { application: "Partition the work into concerns first. Count the partition to get the floor. Measure the fan-in on each shared surface to find the ceiling, from traffic the surface already records. Choose a count inside that range and write down the partition it came from.", boundary: "Volume is the wrong operand, as a concern is a component shows; the fan-in caps a small task and a large one alike.", cause: "A count chosen independently of the partition either leaves a concern with no owner or gives one surface more claims than it can hold.", decision: "Partition first and count second.", failureMode: "Five agents work a task that has two concerns. Three of them wait, and the surface they all write to becomes the bottleneck.", kind: "lesson", principle: "Scale follows from structure and is never a choice.", problem: "The number of agents or people on a task comes from a preference, and a preferred number is wrong in one of two directions.", validation: "Ask what partition the current count came from. A count with no partition behind it is a preference, and the fan-in will find it out.", }, { kind: "text", text: "Fewer parties than the floor and one concern has no owner, so it is decided by whoever happens to be nearest, which is the substitution every other chapter refuses. More parties than the ceiling and the shared surface becomes the bottleneck: a claim is stale by the time it lands more often than it is read, and the parties spend their rounds re-deriving each other's reads.", }, { kind: "text", text: "Scale follows determinism on the architecture page carries the argument: a deterministic check returns the same verdict whoever runs it, so adding a party adds no enforcement cost, which is why every coordination rule here is either a mechanism or a declared piece of conduct with its evidence written down.", }, { caption: "floor, ceiling, count", kind: "mermaid", text: SCALE_DIAGRAM }, ], title: "Floor and ceiling", }, ], title: "Scale follows from structure", }; const DEPLOY_SECTION: Section = { icon: DEPLOY_SECTION_ICON, id: DEPLOY_SECTION_ID, intro: "The deployable is derived from the routes the site serves, as routes to site draws. The deploy is a file operation with a rollback, and it never touches a process it does not own, which is least privilege for a deploy. Secrets management keeps every secret outside the tree, and every served surface speaks encryption in transit, the local development server included, because environment parity means development exercises the same transport as production or it exercises something else.", subsections: [ { blocks: [ { application: "Start from the served routes and follow every path a text artefact names. Delete every file nothing reaches. Upload the whole of what is left. Keep one backup of what you replace, and restore it on any failure. Hand a command that touches a shared machine to the person who owns it rather than running it, and keep every secret in the one artifact declared to bear it.", boundary: "A machine that hosts other people's processes is never touched beyond your own files. The deploy is a file operation because a file operation has a rollback and a process operation has a blast radius.", cause: "Nothing between the build and the upload asks whether a file is reachable.", decision: "Prune from the routes rather than trust the build folder, and take a file operation over a process one for its rollback.", failureMode: "A page fails to pre-render, nobody notices because the old file is still in the build folder, and the stale page ships.", kind: "lesson", principle: "The deployable is what a page can reach, and the deploy is a file operation with a rollback.", problem: "A deploy that ships a build folder ships whatever happened to be in it.", validation: "List every file in the deployable and the route that reaches it. A file no route reaches is a file the discovery check should have refused.", }, { kind: "text", text: "A discovery check derives, from the same registry the build reads, every route a page can serve and every file a route reaches, and fails the build on a route with no rendered file, a payload a machine cannot parse, or a file nothing reaches, before a deploy rather than after.", }, { caption: "routes to site", kind: "mermaid", text: DEPLOY_DIAGRAM }, ], title: "Derived from the routes", }, ], title: "The deploy is a file operation", }; export const RELEASE_SECTIONS: readonly Section[] = [ CHAIN_SECTION, SCALE_SECTION, DEPLOY_SECTION, RETIRED_SECTION, GAP_SECTION, ];