<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Specifications</title><link>https://specifications.aureliasrs.ca/</link><description>Recent content on Specifications</description><generator>Hugo</generator><language>en-CA</language><atom:link href="https://specifications.aureliasrs.ca/index.xml" rel="self" type="application/rss+xml"/><item><title>Actions</title><link>https://specifications.aureliasrs.ca/actions/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/actions/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The model is simple: &lt;em&gt;the build system is intelligent, and CI orchestrates it.&lt;/em&gt;
A composite action exists because an orchestration pattern is reusable — check
out, set up credentials, call a command, pass an output along — even when the
work underneath remains entirely repository-owned.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;Promotion path&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-3"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Inline steps&lt;/span&gt;
 &lt;span class="flow-detail"&gt;A few steps in one workflow file&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-workflows" href="https://specifications.aureliasrs.ca/workflows/"&gt;&lt;i&gt;&lt;/i&gt;Workflows&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Composite action&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Repeated or growing steps get a name, inputs, and outputs under &lt;code&gt;.gitea/actions/&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Shared tooling&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Actions that stabilise and prove broadly useful move out of the repository&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;Not every promotion goes through an action. When the repeated thing is &lt;em&gt;logic&lt;/em&gt;
rather than &lt;em&gt;orchestration&lt;/em&gt;, it moves down into a script or make target
instead, where it can be run outside CI.&lt;/p&gt;</description></item><item><title>Authoring specifications</title><link>https://specifications.aureliasrs.ca/about/authoring/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/about/authoring/</guid><description>&lt;h2 id="adding-a-specification"&gt;Adding a specification&lt;a class="heading-anchor" href="#adding-a-specification" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A specification is a page bundle under &lt;code&gt;www/specifications/content/specs/&lt;/code&gt;. The
directory name is its slug and its address: &lt;code&gt;specs/catalog-descriptors/&lt;/code&gt; is
published at &lt;code&gt;/catalog-descriptors/&lt;/code&gt;, which is where owner documentation links to
it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo new --source www/specifications specs/my-specification/index.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The archetype lists every front matter key with a comment. Drop an &lt;code&gt;icon.svg&lt;/code&gt;
beside &lt;code&gt;index.md&lt;/code&gt; to give the specification its own mark — usually the icon of
the repository area it describes. Without one, the library generates a sigil
from the slug, so every specification still has a stable identity.&lt;/p&gt;</description></item><item><title>Automation &amp; CI/CD</title><link>https://specifications.aureliasrs.ca/automation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/automation/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Gitea Actions runs YAML workflows on runners in response to repository events.
This folder holds those recipes, but it deliberately holds very little else.
The repository&amp;rsquo;s behaviour is implemented once, behind its

&lt;a class="spec-chip accent-command-surface" href="https://specifications.aureliasrs.ca/command-surface/"&gt;
&lt;span class="plate plate-xs accent-command-surface" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="19" width="3" height="3" rx="0.8"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Command Surface&lt;/span&gt;
&lt;/a&gt;
, and automation calls it the same way a developer
would.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;Where automation work lives&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-4"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Event&lt;/span&gt;
 &lt;span class="flow-detail"&gt;A push, pull request, tag, schedule, or dispatch triggers a workflow&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-workflows" href="https://specifications.aureliasrs.ca/workflows/"&gt;&lt;i&gt;&lt;/i&gt;Workflows&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Orchestrate&lt;/span&gt;
 &lt;span class="flow-detail"&gt;The workflow orders jobs and calls shared steps&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-actions" href="https://specifications.aureliasrs.ca/actions/"&gt;&lt;i&gt;&lt;/i&gt;Actions&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Execute&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Steps invoke &lt;code&gt;make validate&lt;/code&gt;, &lt;code&gt;make build&lt;/code&gt;, &lt;code&gt;make release&lt;/code&gt;&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-command-surface" href="https://specifications.aureliasrs.ca/command-surface/"&gt;&lt;i&gt;&lt;/i&gt;Command Surface&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Implement&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Make modules and scripts do the actual work&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-scripts" href="https://specifications.aureliasrs.ca/scripts/"&gt;&lt;i&gt;&lt;/i&gt;Scripts&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;Because every layer below the workflow is available outside CI, a failure on a
runner can be reproduced locally with the same command, and a change to how
something builds is made once rather than in each workflow.&lt;/p&gt;</description></item><item><title>Catalog Descriptors</title><link>https://specifications.aureliasrs.ca/catalog-descriptors/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/catalog-descriptors/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A repository may publish a static website, expose an API, and provision a
database. All three could in principle be discovered by reading source files,
infrastructure definitions, and deployment configuration, but only by a consumer
that understands every one of those systems and can infer how they relate.&lt;/p&gt;
&lt;p&gt;A catalog descriptor removes the inference. It states that the resources exist
and says where their definitions are. Consumers follow the reference to the
source of truth rather than relying on a copy.&lt;/p&gt;</description></item><item><title>Code Map</title><link>https://specifications.aureliasrs.ca/code-map/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/code-map/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The code map is the first page to open and the shortest route to the right
second page. It is organised in three layers, each more specific than the last,
and every layer hands off to owner documentation instead of growing its own
detail.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;Reading the code map&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-4"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Structure&lt;/span&gt;
 &lt;span class="flow-detail"&gt;An annotated tree of the shape the conventions expect&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Quick Lookup&lt;/span&gt;
 &lt;span class="flow-detail"&gt;One line per concern: Static Websites → &lt;code&gt;www&lt;/code&gt;, Command Surface → &lt;code&gt;Makefile&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Area sections&lt;/span&gt;
 &lt;span class="flow-detail"&gt;A short paragraph on what the area is for, then &amp;ldquo;Read:&amp;rdquo; links&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Owner documentation&lt;/span&gt;
 &lt;span class="flow-detail"&gt;The area&amp;rsquo;s own &lt;code&gt;README.md&lt;/code&gt; carries the rules and detail&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-owner-documentation" href="https://specifications.aureliasrs.ca/owner-documentation/"&gt;&lt;i&gt;&lt;/i&gt;Owner Documentation&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;Because it is generated from the repository structure, the code map changes
when the tree changes. That is what keeps it from drifting: a hand-written map
is the first document to fall out of date when areas are added or removed.&lt;/p&gt;</description></item><item><title>Command Surface</title><link>https://specifications.aureliasrs.ca/command-surface/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/command-surface/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The command surface is what a developer or workflow actually types: &lt;code&gt;make doctor&lt;/code&gt;, &lt;code&gt;make build&lt;/code&gt;, &lt;code&gt;make validate&lt;/code&gt;, &lt;code&gt;make lint&lt;/code&gt;, &lt;code&gt;make deploy&lt;/code&gt;. Behind it,
the root &lt;code&gt;Makefile&lt;/code&gt; does only three things — it finds the repository root, reads
&lt;code&gt;repository.mk&lt;/code&gt;, and includes each module in a fixed order.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;How make assembles the surface&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-4"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Root&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;REPO_ROOT&lt;/code&gt; from the &lt;code&gt;Makefile&lt;/code&gt;&amp;rsquo;s own location&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Configure&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Include &lt;code&gt;scripts/build/repository.mk&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Resolve&lt;/span&gt;
 &lt;span class="flow-detail"&gt;For each name in &lt;code&gt;MAKE_MODULE_ORDER&lt;/code&gt;, the first &lt;code&gt;&amp;lt;name&amp;gt;.mk&lt;/code&gt; across the library and repository directories&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Include&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Load the resolved modules in order&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-make-module-registries" href="https://specifications.aureliasrs.ca/make-module-registries/"&gt;&lt;i&gt;&lt;/i&gt;Make Module Registries&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;How the modules then contribute targets without editing each other is the

&lt;a class="spec-chip accent-make-module-registries" href="https://specifications.aureliasrs.ca/make-module-registries/"&gt;
&lt;span class="plate plate-xs accent-make-module-registries" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="3" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Make Module Registries&lt;/span&gt;
&lt;/a&gt;
 pattern.&lt;/p&gt;</description></item><item><title>Decision Records</title><link>https://specifications.aureliasrs.ca/decision-records/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/decision-records/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most decisions in a repository are already written down — in the shape of the
tree, in a make module, in a workflow, in a test. A decision record that
restates one of those becomes a second source of truth that can drift. So the
default is to express a convention where it lives, and to reach for a record
only when that is not enough.&lt;/p&gt;</description></item><item><title>Derived Developer Identity</title><link>https://specifications.aureliasrs.ca/derived-developer-identity/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/derived-developer-identity/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every developer needs their own copy, but nobody wants a directory per
developer. The convention resolves this by deriving identity from context that
already exists. Locally that is your username; in CI it is the branch name; when
you want more than one copy, it is whatever you set &lt;code&gt;DEPLOY_WORKSPACE&lt;/code&gt; to.&lt;/p&gt;
&lt;p&gt;The deployer turns that name into a Terraform workspace, and the root reads it
back as &lt;code&gt;terraform.workspace&lt;/code&gt;. From there, one value flows into the state path,
the hostname, and the resource tags, so two instances can never collide.&lt;/p&gt;</description></item><item><title>Devcontainer Lifecycle</title><link>https://specifications.aureliasrs.ca/devcontainer-lifecycle/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/devcontainer-lifecycle/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The image and its features provide reusable tooling. The lifecycle layer
provides everything specific to &lt;em&gt;this&lt;/em&gt; repository: linking command wrappers,
configuring the shell, restoring dependencies, and running lightweight startup
checks. A freshly rebuilt container, lifecycle included, should be ready for
development without any manual bootstrapping.&lt;/p&gt;
&lt;figure class="diagram phases"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Lifecycle&lt;/span&gt;&lt;span class="diagram-title"&gt;From rebuild to development session&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="phase-track cols-6"&gt;
 &lt;li class="phase accent-initialize-phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;1&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;host · may repeat&lt;/span&gt;
 &lt;span class="phase-label"&gt;&lt;a href="https://specifications.aureliasrs.ca/initialize-phase/"&gt;initializeCommand&lt;/a&gt;&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Prepare host-side files a mount or build expects&lt;/span&gt;
 &lt;/li&gt;
 &lt;li class="phase accent-on-create-phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;2&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;once on create&lt;/span&gt;
 &lt;span class="phase-label"&gt;&lt;a href="https://specifications.aureliasrs.ca/on-create-phase/"&gt;onCreateCommand&lt;/a&gt;&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Container-local state later phases consume&lt;/span&gt;
 &lt;/li&gt;
 &lt;li class="phase accent-update-content-phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;3&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;on content sync&lt;/span&gt;
 &lt;span class="phase-label"&gt;&lt;a href="https://specifications.aureliasrs.ca/update-content-phase/"&gt;updateContentCommand&lt;/a&gt;&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Restore dependencies from lockfiles and manifests&lt;/span&gt;
 &lt;/li&gt;
 &lt;li class="phase accent-post-create-phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;4&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;once after create&lt;/span&gt;
 &lt;span class="phase-label"&gt;&lt;a href="https://specifications.aureliasrs.ca/post-create-phase/"&gt;postCreateCommand&lt;/a&gt;&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Last-mile workspace bootstrap&lt;/span&gt;
 &lt;/li&gt;
 &lt;li class="phase accent-post-start-phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;5&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;every start&lt;/span&gt;
 &lt;span class="phase-label"&gt;&lt;a href="https://specifications.aureliasrs.ca/post-start-phase/"&gt;postStartCommand&lt;/a&gt;&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Fast checks and lightweight services&lt;/span&gt;
 &lt;/li&gt;
 &lt;li class="phase accent-post-attach-phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;6&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;every attach&lt;/span&gt;
 &lt;span class="phase-label"&gt;&lt;a href="https://specifications.aureliasrs.ca/post-attach-phase/"&gt;postAttachCommand&lt;/a&gt;&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Human-facing guidance and auth prompts&lt;/span&gt;
 &lt;/li&gt;
 &lt;/ol&gt;
 
 &lt;svg class="phase-arcs" viewBox="0 0 600 90" preserveAspectRatio="none" aria-hidden="true"&gt;
 
 
 
 
 
 &lt;path class="phase-arc arc-0" d="M550 0 C550 18 450 18 450 2" vector-effect="non-scaling-stroke" /&gt;
 
 
 
 
 
 
 &lt;path class="phase-arc arc-1" d="M550 0 C550 40 550 40 550 2" vector-effect="non-scaling-stroke" /&gt;
 
 
 
 
 
 
 &lt;path class="phase-arc arc-2" d="M550 0 C550 62 50 62 50 2" vector-effect="non-scaling-stroke" /&gt;
 
 
 &lt;/svg&gt;
 &lt;ul class="phase-loops"&gt;
 
 &lt;li class="arc-0"&gt;&lt;span class="loop-glyph" aria-hidden="true"&gt;↺&lt;/span&gt;&lt;span class="loop-trigger"&gt;Restart container&lt;/span&gt;&lt;span class="loop-sep" aria-hidden="true"&gt;→&lt;/span&gt;&lt;span class="loop-target mono"&gt;postStartCommand&lt;/span&gt;&lt;/li&gt;
 
 &lt;li class="arc-1"&gt;&lt;span class="loop-glyph" aria-hidden="true"&gt;↺&lt;/span&gt;&lt;span class="loop-trigger"&gt;Detach and reattach&lt;/span&gt;&lt;span class="loop-sep" aria-hidden="true"&gt;→&lt;/span&gt;&lt;span class="loop-target mono"&gt;postAttachCommand&lt;/span&gt;&lt;/li&gt;
 
 &lt;li class="arc-2"&gt;&lt;span class="loop-glyph" aria-hidden="true"&gt;↺&lt;/span&gt;&lt;span class="loop-trigger"&gt;Rebuild container&lt;/span&gt;&lt;span class="loop-sep" aria-hidden="true"&gt;→&lt;/span&gt;&lt;span class="loop-target mono"&gt;initializeCommand&lt;/span&gt;&lt;/li&gt;
 
 &lt;/ul&gt;
 
&lt;/figure&gt;

&lt;p&gt;Between the hooks, the Dev Containers tooling builds the image, installs
features, creates the container, and starts it. The hooks never replace those
steps; they only add to them.&lt;/p&gt;</description></item><item><title>Development Container</title><link>https://specifications.aureliasrs.ca/development-container/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/development-container/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The development container is responsible for the environment; the repository&amp;rsquo;s
commands only use it. Developers are not expected to run a separate bootstrap
step to install tools after the container is built — if a tool is needed, the
container provides it.&lt;/p&gt;
&lt;p&gt;The definition is layered. A small base image sets the operating system and
primary runtime. Devcontainer features add reusable capabilities on top. The

&lt;a class="spec-chip accent-devcontainer-lifecycle" href="https://specifications.aureliasrs.ca/devcontainer-lifecycle/"&gt;
&lt;span class="plate plate-xs accent-devcontainer-lifecycle" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="7" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Devcontainer Lifecycle&lt;/span&gt;
&lt;/a&gt;
 adds the last, repository-specific layer.&lt;/p&gt;</description></item><item><title>Environment Doctor</title><link>https://specifications.aureliasrs.ca/environment-doctor/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/environment-doctor/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The 
&lt;a class="spec-chip accent-development-container" href="https://specifications.aureliasrs.ca/development-container/"&gt;
&lt;span class="plate plate-xs accent-development-container" aria-hidden="true"&gt;
 

&lt;svg class="glyph-svg" aria-hidden="true" focusable="false" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"&gt;
 
 &lt;circle cx="16" cy="16" r="14" fill="#193e63" /&gt;
 &lt;polygon points="10.777 22.742 9.343 21.348 12.729 17.865 9.346 14.417 10.774 13.017 15.525 17.859 10.777 22.742" fill="#add1ea" /&gt;
 &lt;polygon points="21.42 19.101 22.854 17.706 19.468 14.224 22.851 10.776 21.423 9.376 16.672 14.218 21.42 19.101" fill="#add1ea" /&gt;
&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Development Container&lt;/span&gt;
&lt;/a&gt;
 is responsible for provisioning the
tools. The doctor is how anyone checks that it did. It walks three registries,
reports each entry, and only then exits — with status 1 if anything was missing.&lt;/p&gt;</description></item><item><title>Environments</title><link>https://specifications.aureliasrs.ca/environments/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/environments/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;env/&lt;/code&gt; answers the question &amp;ldquo;what can be deployed?&amp;rdquo;. Each directory beneath it
is a root that a deployment system can point at and run, and each one stands
for a real target — production, a non-production tier, a variant. Reading the
tree tells you the full set of canonical deployments without opening any file.&lt;/p&gt;
&lt;p&gt;A root is wiring, not implementation. It names a module, supplies a domain, a
backend, and credentials, and exposes the outputs a deployer needs. The
infrastructure pattern itself lives in a module, local or published, so the
same pattern can back every tier. See 
&lt;a class="spec-chip accent-pinned-module-composition" href="https://specifications.aureliasrs.ca/pinned-module-composition/"&gt;
&lt;span class="plate plate-xs accent-pinned-module-composition" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;rect x="3" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="19" width="3" height="3" rx="0.8"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Pinned Module Composition&lt;/span&gt;
&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Explicit Skips</title><link>https://specifications.aureliasrs.ca/explicit-skips/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/explicit-skips/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Repository commands are written to run wherever the repository is checked out.
Some of what they cover is optional: a linter that is only installed in the dev
container, a link checker the repository may not have, Terraform roots that
may not exist yet, a plugin download that needs the network. Rather than fail
on the first absent piece, or silently do nothing, each step announces that it
did not run.&lt;/p&gt;</description></item><item><title>Fingerprinted Cache Tiers</title><link>https://specifications.aureliasrs.ca/fingerprinted-cache-tiers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/fingerprinted-cache-tiers/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A fingerprinted file&amp;rsquo;s URL is derived from its content, so a given URL always
means the same bytes and can be cached forever. An HTML page&amp;rsquo;s URL stays the
same while its content changes, so it must be checked on every request. The
upload encodes that difference in two passes over the same &lt;code&gt;public/&lt;/code&gt; tree.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;Two upload passes&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-3"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Immutable pass&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;--exclude '*' --include '*.min.*.css' --include '*.min.*.js'&lt;/code&gt; with a one-year, immutable header&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Revalidate pass&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Every file, with &lt;code&gt;max-age=0, must-revalidate&lt;/code&gt;, and &lt;code&gt;--delete&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Invalidate&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;/*&lt;/code&gt; clears edge copies of the unhashed files&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Files&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;Cache-Control&lt;/code&gt;&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;*.min.&amp;lt;hash&amp;gt;.css&lt;/code&gt;, &lt;code&gt;*.min.&amp;lt;hash&amp;gt;.js&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;public, max-age=31536000, immutable&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Everything else&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;public, max-age=0, must-revalidate&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Files the first pass has just uploaded are already identical at the
destination, so the second pass skips them and they keep their long header. Its
job is to give every remaining file the short header and to prune keys the new
build no longer produces.&lt;/p&gt;</description></item><item><title>Initialize Phase</title><link>https://specifications.aureliasrs.ca/initialize-phase/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/initialize-phase/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;initializeCommand&lt;/code&gt; is the only phase that runs outside the container. It runs
before the image is built and the container is created, and the Dev Containers
tooling may run it again on later rebuilds. That makes it the narrowest phase:
it exists so that host-side paths are in place when the container definition
refers to them, and for nothing else.&lt;/p&gt;
&lt;p&gt;If a task needs the container shell, the mounted workspace, or a tool the
environment provides, it belongs in 
&lt;a class="spec-chip accent-on-create-phase" href="https://specifications.aureliasrs.ca/on-create-phase/"&gt;
&lt;span class="plate plate-xs accent-on-create-phase" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;On-Create Phase&lt;/span&gt;
&lt;/a&gt;
 or later.&lt;/p&gt;</description></item><item><title>Issue Plan Tree</title><link>https://specifications.aureliasrs.ca/issue-plan-tree/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/issue-plan-tree/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A plan starts as files. &lt;code&gt;gitea-planner&lt;/code&gt; reads the tree and mirrors it into
Gitea: &lt;code&gt;reserve&lt;/code&gt; claims milestone IDs and issue numbers, and &lt;code&gt;sync&lt;/code&gt; pushes
titles, states, labels, assignees, dates, bodies, and dependency edges. Two
things make a plan file good — it is structurally valid, or it will not sync,
and it is readable, because the body is what someone actually works from.&lt;/p&gt;
&lt;figure class="diagram phases"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Lifecycle&lt;/span&gt;&lt;span class="diagram-title"&gt;From draft to synced&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="phase-track cols-4"&gt;
 &lt;li class="phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;1&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;while planning&lt;/span&gt;
 &lt;span class="phase-label"&gt;Draft&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Slug-only names; no &lt;code&gt;id&lt;/code&gt; or &lt;code&gt;number&lt;/code&gt;; &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;state: open&lt;/code&gt;&lt;/span&gt;
 &lt;/li&gt;
 &lt;li class="phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;2&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;on `reserve`&lt;/span&gt;
 &lt;span class="phase-label"&gt;Reserved&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Gitea assigns milestone IDs and issue numbers&lt;/span&gt;
 &lt;/li&gt;
 &lt;li class="phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;3&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;on `sync`&lt;/span&gt;
 &lt;span class="phase-label"&gt;Synced&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Names carry the 4-digit prefix; front matter and edges are mirrored&lt;/span&gt;
 &lt;/li&gt;
 &lt;li class="phase"&gt;
 &lt;span class="phase-node" aria-hidden="true"&gt;&lt;span class="mono"&gt;4&lt;/span&gt;&lt;/span&gt;
 &lt;span class="phase-cadence mono"&gt;on `pull`&lt;/span&gt;
 &lt;span class="phase-label"&gt;Pulled&lt;/span&gt;
 &lt;span class="phase-detail"&gt;Remote state, including numeric &lt;code&gt;depends_on&lt;/code&gt;, is written back to disk&lt;/span&gt;
 &lt;/li&gt;
 &lt;/ol&gt;
 
 &lt;svg class="phase-arcs" viewBox="0 0 400 46" preserveAspectRatio="none" aria-hidden="true"&gt;
 
 
 
 
 
 &lt;path class="phase-arc arc-0" d="M350 0 C350 18 250 18 250 2" vector-effect="non-scaling-stroke" /&gt;
 
 
 &lt;/svg&gt;
 &lt;ul class="phase-loops"&gt;
 
 &lt;li class="arc-0"&gt;&lt;span class="loop-glyph" aria-hidden="true"&gt;↺&lt;/span&gt;&lt;span class="loop-trigger"&gt;Edit and re-sync&lt;/span&gt;&lt;span class="loop-sep" aria-hidden="true"&gt;→&lt;/span&gt;&lt;span class="loop-target mono"&gt;Synced&lt;/span&gt;&lt;/li&gt;
 
 &lt;/ul&gt;
 
&lt;/figure&gt;

&lt;p&gt;A template set uses exactly the same layout as a live tree, in draft mode, so a
reusable plan can be copied in and reserved like any other.&lt;/p&gt;</description></item><item><title>Lint Gate</title><link>https://specifications.aureliasrs.ca/lint-gate/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/lint-gate/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The gate is written so that it works anywhere. A small &lt;code&gt;run&lt;/code&gt; helper checks
whether the linter&amp;rsquo;s command exists; if not, it prints a &lt;code&gt;skip:&lt;/code&gt; line and moves
on. If it does, the linter runs and any failure is recorded, not raised, so the
remaining linters still report.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;One run of the lint gate&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-6"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Locate&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;cd&lt;/code&gt; to the Git top level&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Collect files&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Tracked and untracked-but-not-ignored &lt;code&gt;*.sh&lt;/code&gt;, &lt;code&gt;*.md&lt;/code&gt;, &lt;code&gt;*Dockerfile*&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Run linters&lt;/span&gt;
 &lt;span class="flow-detail"&gt;ShellCheck, MarkdownLint, Hadolint, shfmt, Actionlint, EditorConfig, Codespell&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-explicit-skips" href="https://specifications.aureliasrs.ca/explicit-skips/"&gt;&lt;i&gt;&lt;/i&gt;Explicit Skips&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Prettier&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;npm run format:check&lt;/code&gt; when &lt;code&gt;node_modules/.bin/prettier&lt;/code&gt; exists&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;05&lt;/span&gt;
 &lt;span class="flow-label"&gt;Terraform&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;make check.terraform.fmt check.terraform.lint&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;06&lt;/span&gt;
 &lt;span class="flow-label"&gt;Report&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;Lint PASSED&lt;/code&gt;, or &lt;code&gt;Lint FAILED&lt;/code&gt; and exit 1&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;A linter is skipped only when it is missing. When there are no files of a type
— no Dockerfiles, say — that linter is not invoked at all.&lt;/p&gt;</description></item><item><title>Linter Configuration</title><link>https://specifications.aureliasrs.ca/linter-configuration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/linter-configuration/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Linters conventionally scatter dotfiles across the repository root. Here they
are gathered into one directory, so the root stays focused on the repository&amp;rsquo;s
own structure and the lint setup is visible in one place.&lt;/p&gt;
&lt;p&gt;Configuration is layered. The organisation&amp;rsquo;s defaults travel with the

&lt;a class="spec-chip accent-development-container" href="https://specifications.aureliasrs.ca/development-container/"&gt;
&lt;span class="plate plate-xs accent-development-container" aria-hidden="true"&gt;
 

&lt;svg class="glyph-svg" aria-hidden="true" focusable="false" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"&gt;
 
 &lt;circle cx="16" cy="16" r="14" fill="#193e63" /&gt;
 &lt;polygon points="10.777 22.742 9.343 21.348 12.729 17.865 9.346 14.417 10.774 13.017 15.525 17.859 10.777 22.742" fill="#add1ea" /&gt;
 &lt;polygon points="21.42 19.101 22.854 17.706 19.468 14.224 22.851 10.776 21.423 9.376 16.672 14.218 21.42 19.101" fill="#add1ea" /&gt;
&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Development Container&lt;/span&gt;
&lt;/a&gt;
 and the CI/CD tooling; files in &lt;code&gt;.linter/&lt;/code&gt;
contain only what this repository changes. Each tool is told where to find its
file — &lt;code&gt;--config .linter/.markdownlint.json&lt;/code&gt;, &lt;code&gt;-config-file .linter/actionlint.yaml&lt;/code&gt; — instead of discovering it at the root.&lt;/p&gt;</description></item><item><title>Make Module Registries</title><link>https://specifications.aureliasrs.ca/make-module-registries/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/make-module-registries/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The root &lt;code&gt;Makefile&lt;/code&gt; is identical in every repository. It includes the
repository&amp;rsquo;s configuration and then a fixed sequence of numbered modules. Each
module is self-contained: it defines its own targets and &lt;em&gt;registers&lt;/em&gt; them by
appending to shared lists. No module edits another.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;Assembling the command surface&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-4"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Configure&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;repository.mk&lt;/code&gt; declares components; &lt;code&gt;00-config.mk&lt;/code&gt; initialises empty registries&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Register&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Each module appends: &lt;code&gt;BUILD_TARGETS += check.hugo&lt;/code&gt;, &lt;code&gt;DOCTOR_TOOLS += terraform&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Aggregate&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;90-aggregates.mk&lt;/code&gt; is read last, so &lt;code&gt;build: $(BUILD_TARGETS)&lt;/code&gt; sees every registration&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Run&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;make build&lt;/code&gt;, &lt;code&gt;make validate&lt;/code&gt;, and &lt;code&gt;make clean&lt;/code&gt; cover whatever modules are present&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;aside class="callout callout-caution"&gt;
 &lt;p class="callout-label mono"&gt;Caution&lt;/p&gt;</description></item><item><title>Managed Standard Files</title><link>https://specifications.aureliasrs.ca/managed-standard-files/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/managed-standard-files/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some files express a convention that should read the same everywhere. Copying
them by hand guarantees drift, so an external tool owns them: it writes them
into each repository and overwrites them when the standard changes. The header
tells a reader, before they start editing, that this is not the place to make
the change.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;Changing a managed file&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-4"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Notice the header&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;DO NOT EDIT&lt;/code&gt; on the first line marks the file as managed&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Find the source&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Change the standard file in the tool that manages it&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Propagate&lt;/span&gt;
 &lt;span class="flow-detail"&gt;The next update rewrites the file in every repository&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Keep local values local&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Anything repository-specific goes in the file the standard delegates to&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;aside class="callout callout-caution"&gt;
 &lt;p class="callout-label mono"&gt;Caution&lt;/p&gt;</description></item><item><title>Modules</title><link>https://specifications.aureliasrs.ca/modules/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/modules/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A module is the part of the infrastructure that does not care where it is
deployed. It knows how to build a thing — a bucket and its distribution, a
secrets store, a network — and it asks the caller for everything that differs
between targets: the domain, the tags, which providers to use.&lt;/p&gt;
&lt;p&gt;Roots supply those answers. Because a module makes no assumptions about tier or
account, the same module can sit behind production and behind every developer&amp;rsquo;s
own copy, and a fix made once reaches all of them.&lt;/p&gt;</description></item><item><title>Offline Validation</title><link>https://specifications.aureliasrs.ca/offline-validation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/offline-validation/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Validation is most useful when it is reproducible: the same inputs give the
same result, and nothing changes underneath it mid-run. A target that re-runs
&lt;code&gt;terraform init&lt;/code&gt; or &lt;code&gt;tflint --init&lt;/code&gt; as a side effect quietly depends on the
network and on whatever the registry serves that minute.&lt;/p&gt;
&lt;p&gt;The repository separates the two concerns. Getting dependencies onto the
machine is setup — the dev container&amp;rsquo;s lifecycle hooks locally, a prepare phase
in CI. Validation then runs against the hydrated workspace, and &lt;code&gt;OFFLINE=1&lt;/code&gt;
tells every module that the network is off-limits.&lt;/p&gt;</description></item><item><title>On-Create Phase</title><link>https://specifications.aureliasrs.ca/on-create-phase/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/on-create-phase/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On-create is the first phase inside the container. Its job is to lay down
&lt;em&gt;container-local&lt;/em&gt; state — things that live under &lt;code&gt;$HOME&lt;/code&gt; or in tool
configuration — so that the repository-driven phases that follow find them in
place.&lt;/p&gt;
&lt;p&gt;The distinction from 
&lt;a class="spec-chip accent-update-content-phase" href="https://specifications.aureliasrs.ca/update-content-phase/"&gt;
&lt;span class="plate plate-xs accent-update-content-phase" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;rect x="3" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Update-Content Phase&lt;/span&gt;
&lt;/a&gt;
 is the input. On-create
work depends on the container; update-content work depends on the repository&amp;rsquo;s
files. A Terraform plugin cache directory is on-create; &lt;code&gt;terraform init&lt;/code&gt; against
the checked-in roots is not.&lt;/p&gt;</description></item><item><title>Owner Documentation</title><link>https://specifications.aureliasrs.ca/owner-documentation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/owner-documentation/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A reader who opens a directory is already looking at the thing they want to
understand. Owner documentation meets them there. The README beside the files
says what the area is for, what belongs in it and what does not, and the handful
of rules that keep it coherent. Moving or deleting the area takes its
documentation with it.&lt;/p&gt;
&lt;p&gt;The same principle applies below the directory level. A make module explains
itself in its header comment, a script in its usage line, a workflow in its
file header. The decision-record guidance lists these owners explicitly and
asks for a separate record only when none of them can carry the explanation.&lt;/p&gt;</description></item><item><title>Parameterless Deployment</title><link>https://specifications.aureliasrs.ca/parameterless-deployment/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/parameterless-deployment/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If a deployment needs someone to remember a flag, it is only as reliable as
that memory. Canonical roots avoid the question entirely: every value they need
is written down in the repository or looked up from a well-defined source, so
the only thing a deployer has to know is which directory to run.&lt;/p&gt;
&lt;p&gt;That is what lets one generic deployer drive every root. It does not carry
per-environment knowledge; it runs &lt;code&gt;terraform init&lt;/code&gt;, &lt;code&gt;apply&lt;/code&gt;, and reads outputs
using the same commands everywhere, with &lt;code&gt;-input=false&lt;/code&gt; so a missing value
fails loudly instead of prompting.&lt;/p&gt;</description></item><item><title>Pinned Module Composition</title><link>https://specifications.aureliasrs.ca/pinned-module-composition/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/pinned-module-composition/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The repository deploys one static website to several places. Rather than
describe that website&amp;rsquo;s infrastructure several times, it describes it once — the
S3 bucket, CloudFront distribution, ACM certificate, and DNS records — as a
published module, and gives each environment a root that does nothing but call
it.&lt;/p&gt;
&lt;p&gt;Because every root runs the same module at the same version, the pattern lives
in exactly one place and every environment is the same deployment. A change
tested in a developer&amp;rsquo;s copy is the change production will get, because there is
no second implementation for it to diverge from.&lt;/p&gt;</description></item><item><title>Post-Attach Phase</title><link>https://specifications.aureliasrs.ca/post-attach-phase/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/post-attach-phase/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Post-attach is the last phase and the only one aimed at a person. It runs on
every attach, including reattaching to a container that has been running for
days, so it says what is useful &lt;em&gt;now&lt;/em&gt; and gets out of the way.&lt;/p&gt;
&lt;p&gt;The repository stays usable without it. A container that is started and never
attached — by automation, for example — has everything it needs from the
earlier phases; post-attach only adds guidance on top. Anything that has to
happen for the session itself belongs in 
&lt;a class="spec-chip accent-post-start-phase" href="https://specifications.aureliasrs.ca/post-start-phase/"&gt;
&lt;span class="plate plate-xs accent-post-start-phase" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="7" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Post-Start Phase&lt;/span&gt;
&lt;/a&gt;
.&lt;/p&gt;</description></item><item><title>Post-Create Phase</title><link>https://specifications.aureliasrs.ca/post-create-phase/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/post-create-phase/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Post-create is the final creation-time phase. By the time it runs, the
container exists, the content is synchronised, and dependencies are restored.
What remains is wiring the workspace together so it is ready for development.&lt;/p&gt;
&lt;p&gt;The line with 
&lt;a class="spec-chip accent-update-content-phase" href="https://specifications.aureliasrs.ca/update-content-phase/"&gt;
&lt;span class="plate plate-xs accent-update-content-phase" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;rect x="3" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Update-Content Phase&lt;/span&gt;
&lt;/a&gt;
 is about purpose rather than
timing. Update-content &lt;em&gt;reacts&lt;/em&gt; to repository content and may rerun when it
changes; post-create &lt;em&gt;configures&lt;/em&gt; the workspace once, using whatever is now in
place.&lt;/p&gt;</description></item><item><title>Post-Start Phase</title><link>https://specifications.aureliasrs.ca/post-start-phase/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/post-start-phase/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Post-start is the first phase that repeats in normal use: restarting the
container returns here without passing through creation again. Everything in it
pays that cost on every start, so it holds only work that is cheap and that has
to be true for the session to work.&lt;/p&gt;
&lt;p&gt;It differs from 
&lt;a class="spec-chip accent-post-attach-phase" href="https://specifications.aureliasrs.ca/post-attach-phase/"&gt;
&lt;span class="plate plate-xs accent-post-attach-phase" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="7" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="19" width="3" height="3" rx="0.8"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Post-Attach Phase&lt;/span&gt;
&lt;/a&gt;
 in audience. Post-start runs
for the container whether or not an editor ever connects; post-attach runs for a
person who has just arrived. Services and runtime repairs belong here; prompts
and guidance belong there.&lt;/p&gt;</description></item><item><title>Product Development Life Cycle</title><link>https://specifications.aureliasrs.ca/product-development-life-cycle/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/product-development-life-cycle/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most of a repository explains &lt;em&gt;what&lt;/em&gt; and &lt;em&gt;how&lt;/em&gt;. The PDLC directory explains
&lt;em&gt;why&lt;/em&gt;, and is written to stay true for a long time. A reader opening it should
learn what the repository is for, what went wrong when it lost its way, and
which constraints any change should respect — without wading through the
history of how each decision was reached.&lt;/p&gt;
&lt;p&gt;The README calls these files the cornerstone of the repository: they are the
reference point other documentation, structure, and code are measured against.&lt;/p&gt;</description></item><item><title>Reference Over Duplication</title><link>https://specifications.aureliasrs.ca/reference-over-duplication/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/reference-over-duplication/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every copy of a fact is a promise to keep two places in step. Promises like
that are broken quietly: one file is updated, the other is not, and a reader
can no longer tell which is current. The repository avoids making the promise.
A fact lives with the thing that owns it, and everything else links.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;Resolving a fact&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-3"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Index&lt;/span&gt;
 &lt;span class="flow-detail"&gt;The code map, a descriptor, or a summary names the thing&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-code-map" href="https://specifications.aureliasrs.ca/code-map/"&gt;&lt;i&gt;&lt;/i&gt;Code Map&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Reference&lt;/span&gt;
 &lt;span class="flow-detail"&gt;A link or path points at its owner&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Source of truth&lt;/span&gt;
 &lt;span class="flow-detail"&gt;The owner — a README, a make module, a Terraform root, an API definition — holds the detail&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-owner-documentation" href="https://specifications.aureliasrs.ca/owner-documentation/"&gt;&lt;i&gt;&lt;/i&gt;Owner Documentation&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;h2 id="what-drift-looks-like"&gt;What drift looks like&lt;a class="heading-anchor" href="#what-drift-looks-like" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The problem statement for this repository lists the symptoms of losing this
discipline. Human-facing docs, the generated code map, and the actual layout
drifted apart. It became hard to tell which files were externally managed,
which were repository-specific, and which were meant to be reused. The
conclusion: a repository cannot be a trustworthy reference &amp;ldquo;if readers must
reverse-engineer which source of truth is current.&amp;rdquo;&lt;/p&gt;</description></item><item><title>Release Pipeline</title><link>https://specifications.aureliasrs.ca/release-pipeline/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/release-pipeline/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The same three stages run at every point a change passes through. What
changes from stage to stage is only where the output is published: nowhere
locally, to an edge or staging location on a pull request, and to production on
merge.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;One pipeline, every stage&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-3"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Build&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Produce the artifact or site from source&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Test&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Exercise it with the same logic CI runs&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Publish&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Push the output to the location this stage targets&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;Running that pipeline three times is the point. A pull request that already
built, tested, and published to an edge location has rehearsed most of the
release, so merge is a promotion rather than a first attempt.&lt;/p&gt;</description></item><item><title>Run-Parts Hook Directories</title><link>https://specifications.aureliasrs.ca/run-parts-hooks/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/run-parts-hooks/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The name comes from the classic Unix &lt;code&gt;run-parts&lt;/code&gt; utility, which runs every
script in a directory. Here the directory is chosen by event: &lt;code&gt;post-start&lt;/code&gt;
resolves to &lt;code&gt;post-start.d/&lt;/code&gt;, &lt;code&gt;on-create&lt;/code&gt; to &lt;code&gt;on-create.d/&lt;/code&gt;, and so on. Adding
a hook is adding a file; the &lt;code&gt;devcontainer.json&lt;/code&gt; command never changes.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;One invocation of run-parts.sh&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-5"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Check arguments&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Exactly one non-empty event name, or usage text and exit 1&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Resolve directory&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;&amp;lt;event&amp;gt;.d/&lt;/code&gt; beside the runner; missing directory exits 1&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Announce&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;Running lifecycle event: &amp;lt;event&amp;gt;&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Run hooks&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Each &lt;code&gt;*.sh&lt;/code&gt; in lexical order, as &lt;code&gt;bash &amp;lt;script&amp;gt;&lt;/code&gt;, after &lt;code&gt;==&amp;gt; Running &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;05&lt;/span&gt;
 &lt;span class="flow-label"&gt;Finish&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Report &lt;code&gt;No lifecycle scripts found&lt;/code&gt; when the glob matched nothing&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;The canonical event names are &lt;code&gt;initialize&lt;/code&gt;, &lt;code&gt;on-create&lt;/code&gt;, &lt;code&gt;update-content&lt;/code&gt;,
&lt;code&gt;post-create&lt;/code&gt;, &lt;code&gt;post-start&lt;/code&gt;, and &lt;code&gt;post-attach&lt;/code&gt;, one per phase of the

&lt;a class="spec-chip accent-devcontainer-lifecycle" href="https://specifications.aureliasrs.ca/devcontainer-lifecycle/"&gt;
&lt;span class="plate plate-xs accent-devcontainer-lifecycle" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="7" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Devcontainer Lifecycle&lt;/span&gt;
&lt;/a&gt;
. The runner enforces them through the
directory check: an event with no matching directory is refused.&lt;/p&gt;</description></item><item><title>Scripts</title><link>https://specifications.aureliasrs.ca/scripts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/scripts/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A script exists because something does not fit comfortably in a make recipe. It
gives that behaviour a name and an entry point, but it does not take over
decisions that belong to its caller. The make module decides that Terraform
roots are &lt;code&gt;$(TERRAFORM_DIRS)&lt;/code&gt;; the script works on whatever it is handed.&lt;/p&gt;
&lt;p&gt;That narrowness keeps scripts predictable. Run twice with the same arguments
and environment, a script does the same thing, because it does not reach for
ambient repository state or set up its own prerequisites along the way.&lt;/p&gt;</description></item><item><title>Self-Documenting Help</title><link>https://specifications.aureliasrs.ca/self-documenting-help/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/self-documenting-help/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is no hand-maintained list of commands. The help target runs &lt;code&gt;awk&lt;/code&gt; over
every makefile that make has loaded and picks out two kinds of line: section
headings that start with &lt;code&gt;##@&lt;/code&gt;, and rule lines that end in &lt;code&gt;## description&lt;/code&gt;.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;From comments to help&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-4"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Annotate&lt;/span&gt;
 &lt;span class="flow-detail"&gt;A module writes &lt;code&gt;doctor: ## Verify required tools ...&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Load&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Make records every included file in &lt;code&gt;MAKEFILE_LIST&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Scan&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;awk&lt;/code&gt; prints &lt;code&gt;##@&lt;/code&gt; lines as headings and &lt;code&gt;target: ## text&lt;/code&gt; as entries&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Print&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;HELP_START&lt;/code&gt; banner, then each section in load order&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;Because the source of the listing is the makefiles themselves, adding a module
adds its section, and deleting one removes it. The help composes the same way
the 
&lt;a class="spec-chip accent-make-module-registries" href="https://specifications.aureliasrs.ca/make-module-registries/"&gt;
&lt;span class="plate plate-xs accent-make-module-registries" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="3" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Make Module Registries&lt;/span&gt;
&lt;/a&gt;
 do, without a registry of its own.&lt;/p&gt;</description></item><item><title>Staged Content Mounts</title><link>https://specifications.aureliasrs.ca/staged-content-mounts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/staged-content-mounts/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Documentation under &lt;code&gt;docs/&lt;/code&gt; is written as ordinary Markdown for people reading
the repository. A Hugo site wants front matter and a content tree. Rather than
make the documents serve both masters, a small script stages a Hugo-ready copy
and the site mounts it.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;From docs/ to a published page&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-4"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Author&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Edit Markdown in &lt;code&gt;docs/&lt;/code&gt;, where it is owned&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-owner-documentation" href="https://specifications.aureliasrs.ca/owner-documentation/"&gt;&lt;i&gt;&lt;/i&gt;Owner Documentation&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Stage&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;prepare-site-content.mjs&lt;/code&gt; writes &lt;code&gt;.cache/docs-site/content/&amp;lt;path&amp;gt;&lt;/code&gt; with front matter&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Mount&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;[module]&lt;/code&gt; mounts place the staged tree at &lt;code&gt;content/repository&lt;/code&gt;&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Build&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;check.hugo&lt;/code&gt; renders it alongside the site&amp;rsquo;s own content&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-static-websites" href="https://specifications.aureliasrs.ca/static-websites/"&gt;&lt;i&gt;&lt;/i&gt;Static Websites&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;The mount, not the script, decides where the pages appear. The script only knows
about &lt;code&gt;docs/&lt;/code&gt; and &lt;code&gt;.cache/&lt;/code&gt;; the site decides that repository documentation is
published beneath &lt;code&gt;/repository/&lt;/code&gt; so it cannot collide with library pages.&lt;/p&gt;</description></item><item><title>Static Site Delivery</title><link>https://specifications.aureliasrs.ca/static-site-delivery/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/static-site-delivery/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Deployment is five steps, and &lt;code&gt;make deploy&lt;/code&gt; is all five. They live in one
script that is short enough to read before running it, and the make targets are
one-line wrappers that pass &lt;code&gt;ENV&lt;/code&gt; through.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;make deploy&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-5"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Build&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;make check.hugo&lt;/code&gt; renders every site into &lt;code&gt;public/&lt;/code&gt;&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-static-websites" href="https://specifications.aureliasrs.ca/static-websites/"&gt;&lt;i&gt;&lt;/i&gt;Static Websites&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Init&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;terraform init -input=false&lt;/code&gt; in the selected root&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Apply&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Provisions the S3 bucket, CloudFront distribution, ACM certificate, and DNS records&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-pinned-module-composition" href="https://specifications.aureliasrs.ca/pinned-module-composition/"&gt;&lt;i&gt;&lt;/i&gt;Pinned Module Composition&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Upload&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Two &lt;code&gt;aws s3 sync&lt;/code&gt; passes with different &lt;code&gt;Cache-Control&lt;/code&gt; headers&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-fingerprinted-cache-tiers" href="https://specifications.aureliasrs.ca/fingerprinted-cache-tiers/"&gt;&lt;i&gt;&lt;/i&gt;Fingerprinted Cache Tiers&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;05&lt;/span&gt;
 &lt;span class="flow-label"&gt;Invalidate&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;create-invalidation --paths '/*'&lt;/code&gt; on the distribution&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;plan&lt;/code&gt; and &lt;code&gt;destroy&lt;/code&gt; stop after &lt;code&gt;init&lt;/code&gt; (and workspace selection): &lt;code&gt;plan&lt;/code&gt; prints
the change set, and &lt;code&gt;destroy&lt;/code&gt; removes everything, bucket contents included,
because the stack bucket sets &lt;code&gt;force_destroy&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Static Websites</title><link>https://specifications.aureliasrs.ca/static-websites/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/static-websites/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;www/&lt;/code&gt; is a logical grouping, not a site. Every child directory is a complete
site root: point a static site generator at it and it builds, with nothing
borrowed from a sibling. That keeps each site understandable on its own and lets
a site be moved, renamed, or deleted without breaking another.&lt;/p&gt;
&lt;p&gt;The make module for Hugo turns the declared sites into one output tree. The
first site in &lt;code&gt;HUGO_DIRS&lt;/code&gt; owns the root of &lt;code&gt;public/&lt;/code&gt;; every later site is nested
beneath it under its own directory name.&lt;/p&gt;</description></item><item><title>Tools</title><link>https://specifications.aureliasrs.ca/tools/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/tools/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A tool owns a workflow. Where a script runs a few existing commands in a
particular order, a tool defines what it accepts, what it produces, and how it
gets from one to the other — and that definition is what callers depend on.&lt;/p&gt;
&lt;p&gt;Because callers depend on it, the entry point is treated as stable. The
implementation behind it can change language, structure, or dependencies; the
command and its contract stay put.&lt;/p&gt;</description></item><item><title>Update-Content Phase</title><link>https://specifications.aureliasrs.ca/update-content-phase/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/update-content-phase/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Update-content is where the repository&amp;rsquo;s own files start to matter. It runs
once the workspace content is available, and may run again when that content is
refreshed during creation or prebuilding. Because the work is a function of the
checked-in files, rerunning it after a content change brings the workspace back
in line.&lt;/p&gt;
&lt;p&gt;It sits between two easily confused neighbours. 
&lt;a class="spec-chip accent-on-create-phase" href="https://specifications.aureliasrs.ca/on-create-phase/"&gt;
&lt;span class="plate plate-xs accent-on-create-phase" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="11" y="7" width="3" height="3" rx="0.8"/&gt;&lt;rect x="3" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="8.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="11" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="15" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="15" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;On-Create Phase&lt;/span&gt;
&lt;/a&gt;

prepares the container before content matters; 
&lt;a class="spec-chip accent-post-create-phase" href="https://specifications.aureliasrs.ca/post-create-phase/"&gt;
&lt;span class="plate plate-xs accent-post-create-phase" aria-hidden="true"&gt;
 &lt;svg class="glyph-svg sigil" viewBox="0 0 25 25" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;circle cx="4.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="7" y="3" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="3" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="4.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="8.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="3" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="11" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="11" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="12.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="4.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="20.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="8.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="16.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;circle cx="12.5" cy="16.5" r="0.55" class="sigil-dot"/&gt;&lt;rect x="3" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="19" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="7" y="19" width="3" height="3" rx="0.8"/&gt;&lt;rect x="15" y="19" width="3" height="3" rx="0.8"/&gt;&lt;circle cx="12.5" cy="20.5" r="0.55" class="sigil-dot"/&gt;&lt;/svg&gt;
&lt;/span&gt;
&lt;span&gt;Post-Create Phase&lt;/span&gt;
&lt;/a&gt;

finishes the workspace once everything is in place. Update-content is the step
that responds to the content itself.&lt;/p&gt;</description></item><item><title>Workflows</title><link>https://specifications.aureliasrs.ca/workflows/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/workflows/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A workflow answers three questions: &lt;em&gt;when&lt;/em&gt; does automation run, &lt;em&gt;how&lt;/em&gt; are its
jobs ordered, and &lt;em&gt;which&lt;/em&gt; commands or actions does each step invoke. Anything
beyond that — how the site builds, how a scanner is configured, how a bucket is
uploaded — belongs to the repository, where it can be run and tested without a
runner.&lt;/p&gt;
&lt;figure class="diagram flow"&gt;
 &lt;figcaption class="diagram-caption"&gt;&lt;span class="eyebrow"&gt;Flow&lt;/span&gt;&lt;span class="diagram-title"&gt;Phases of a primary CI workflow&lt;/span&gt;&lt;/figcaption&gt;
 &lt;ol class="flow-steps cols-4"&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;01&lt;/span&gt;
 &lt;span class="flow-label"&gt;Validate&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;make validate&lt;/code&gt;, &lt;code&gt;make lint&lt;/code&gt;, &lt;code&gt;make test&lt;/code&gt; on every pull request&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;02&lt;/span&gt;
 &lt;span class="flow-label"&gt;Package&lt;/span&gt;
 &lt;span class="flow-detail"&gt;&lt;code&gt;make build&lt;/code&gt; / &lt;code&gt;make package&lt;/code&gt; produce the artifact&lt;/span&gt;
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;03&lt;/span&gt;
 &lt;span class="flow-label"&gt;Publish&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Artifacts go to a CI, edge, or staging location&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-release-pipeline" href="https://specifications.aureliasrs.ca/release-pipeline/"&gt;&lt;i&gt;&lt;/i&gt;Release Pipeline&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;li class="flow-step"&gt;
 &lt;span class="flow-index mono"&gt;04&lt;/span&gt;
 &lt;span class="flow-label"&gt;Deploy&lt;/span&gt;
 &lt;span class="flow-detail"&gt;Only where the repository has something to deploy&lt;/span&gt;
 
 
 &lt;a class="flow-spec accent-static-site-delivery" href="https://specifications.aureliasrs.ca/static-site-delivery/"&gt;&lt;i&gt;&lt;/i&gt;Static Site Delivery&lt;/a&gt;
 
 
 &lt;/li&gt;
 &lt;/ol&gt;
&lt;/figure&gt;

&lt;p&gt;The pull request path and the main-branch path should look alike. If a check
only runs after merge, a pull request can be green while main breaks; keeping
event differences narrow is what makes the pull request result trustworthy.&lt;/p&gt;</description></item><item><title>Workspaces</title><link>https://specifications.aureliasrs.ca/workspaces/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://specifications.aureliasrs.ca/workspaces/</guid><description>&lt;h2 id="behaviour"&gt;Behaviour&lt;a class="heading-anchor" href="#behaviour" aria-label="Link to this section"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;env/&lt;/code&gt; holds the deployments that matter to everyone. &lt;code&gt;workspaces/&lt;/code&gt; holds the
ones that matter to a single person or branch for a while. Both compose the
same reusable modules, so a developer&amp;rsquo;s copy is built the same way production
is; the difference is how the instance is named and who owns it.&lt;/p&gt;
&lt;p&gt;A workspace root is still committed, reviewed configuration. What it adds is
permission to depend on context: the Terraform workspace, the current user, a
branch name, an environment variable. That context decides the instance&amp;rsquo;s
identity — its hostname, its state, its resources — and nothing else.&lt;/p&gt;</description></item></channel></rss>