@spec-engine/spec-engine 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent/AGENTS.md +678 -0
- package/dist/agent/mcp.json +11 -0
- package/dist/agent/pre-commit +3 -0
- package/dist/agent/skills/req-author/SKILL.md +102 -0
- package/dist/docs/agent-reference/index.html +1280 -33
- package/dist/docs/architecture/index.html +6 -6
- package/dist/docs/checks/index.html +19 -266
- package/dist/docs/commands/index.html +32 -164
- package/dist/docs/format/index.html +2 -9
- package/dist/docs/getting-started/index.html +3 -3
- package/dist/docs/guides/platform-setup/index.html +2 -2
- package/dist/docs/pagefind/fragment/en_10e3da6.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_37cae5e.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_7fc2fcd.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_96d3bc1.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_a26aa07.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_b7e68ef.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_d8a5bcd.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_de67937.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_fc3c55b.pf_fragment +0 -0
- package/dist/docs/pagefind/index/en_1664b45.pf_index +0 -0
- package/dist/docs/pagefind/index/en_a8b8bb6.pf_index +0 -0
- package/dist/docs/pagefind/pagefind-entry.json +1 -1
- package/dist/docs/pagefind/pagefind.en_bc3d4a7766.pf_meta +0 -0
- package/dist/docs/platform-mapping/index.html +2 -1
- package/dist/docs/tags/index.html +9 -92
- package/dist/impl.js +2011 -703
- package/package.json +1 -1
- package/dist/docs/pagefind/fragment/en_1f98c2d.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_24f76b6.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_4bd9de6.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_9cc1878.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_9cfc306.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_b2867b9.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_b81dc52.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_c3abf3d.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_c3e92c6.pf_fragment +0 -0
- package/dist/docs/pagefind/index/en_6e50ed4.pf_index +0 -0
- package/dist/docs/pagefind/index/en_afc98e5.pf_index +0 -0
- package/dist/docs/pagefind/pagefind.en_d0b5c328bc.pf_meta +0 -0
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
<p>Nothing here needs a checkout. In any repo of your own:</p>
|
|
80
80
|
<p><strong>1. Scaffold a domain and author the first requirement</strong> — no hand-written JSON:</p>
|
|
81
81
|
<div class="expressive-code"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="shell"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">$</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">domain</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">new</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">ORDERS</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">created</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec-engine/ORDERS/SPEC.json</span></div></div><div class="ec-line"><div class="code">
|
|
82
|
-
</div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">$</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">req</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">orders</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">--text</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">An order total equals the sum of its line items.</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">--why</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Mispriced orders ship money out the door silently.</span><span style="--0:#D9F5DD;--1:#111111">"</span
|
|
82
|
+
</div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">$</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">req</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">orders</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">--text</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">An order total equals the sum of its line items.</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">--why</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Mispriced orders ship money out the door silently.</span><span style="--0:#D9F5DD;--1:#111111">"</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">appended</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">ORDERS-001</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">to</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec-engine/ORDERS/SPEC.json</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="$ spec domain new ORDERScreated spec-engine/ORDERS/SPEC.json$ spec req orders --text "An order total equals the sum of its line items." \ --why "Mispriced orders ship money out the door silently."appended ORDERS-001 to spec-engine/ORDERS/SPEC.json"><div></div></button></div></figure></div>
|
|
83
83
|
<p><strong>2. Bind code to it</strong> with a <code dir="auto">@spec</code> tag — implementation and test:</p>
|
|
84
84
|
<div class="expressive-code"><figure class="frame has-title not-content"><figcaption class="header"><span class="title">src/orders.ts</span></figcaption><pre data-language="ts"><code><div class="ec-line"><div class="code"><span style="--0:#C792EA;--1:#8844AE">export</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">function</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">total</span><span style="--0:#D9F5DD;--1:#111111">()</span><span style="--0:#D6DEEB;--1:#403F53"> { </span><span style="--0:#919F9F;--1:#5F636F">/* … */</span><span style="--0:#D6DEEB;--1:#403F53"> } </span><span style="--0:#919F9F;--1:#5D6376">// @spec ORDERS-001</span></div></div><div class="ec-line"><div class="code">
|
|
85
85
|
</div></div><div class="ec-line"><div class="code"><span style="--0:#919F9F;--1:#5D6376">// test/orders.test.ts</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">it</span><span style="--0:#D6DEEB;--1:#403F53">(</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">sums line items</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#D9F5DD;--1:#111111">()</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> {}) </span><span style="--0:#919F9F;--1:#5D6376">// @spec ORDERS-001 unit</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="export function total() { /* … */ } // @spec ORDERS-001// test/orders.test.tsit("sums line items", () => {}) // @spec ORDERS-001 unit"><div></div></button></div></figure></div>
|
|
@@ -94,11 +94,11 @@
|
|
|
94
94
|
<p>The <a href="https://github.com/spec-engine/spec-engine">repo</a> ships <code dir="auto">fixtures/platform-fixture</code> — a canonical <code dir="auto">spec-engine/</code> plus three member repos, with drift deliberately planted so <code dir="auto">spec check</code> has something to catch. The fixtures are test data and are <strong>not</strong> part of the npm package, so this one needs a clone:</p>
|
|
95
95
|
<div class="expressive-code"><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="shell"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">$</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">git</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">clone</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">https://github.com/spec-engine/spec-engine</span><span style="--0:#D6DEEB;--1:#403F53"> && </span><span style="--0:#C5E478;--1:#3B61B0">cd</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec-engine</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">$</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">map</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">fixtures/platform-fixture</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">DOMAIN</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">REQUIREMENT</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">STATUS</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">admin</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">api</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">mobile</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec-engine</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">AUTH</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">AUTH-001</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">Active</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">BILLING</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">BILLING-001</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">Superseded</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">src</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">BILLING</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">BILLING-002</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">Active</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">src</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">BILLING</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">BILLING-007</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">Active</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">src+test</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">src+test</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">src</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">BILLING</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">BILLING-009</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">Active</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">src+test</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">—</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="$ git clone https://github.com/spec-engine/spec-engine && cd spec-engine$ spec map fixtures/platform-fixtureDOMAIN REQUIREMENT STATUS admin api mobile spec-engineAUTH AUTH-001 Active — — — —BILLING BILLING-001 Superseded — — src —BILLING BILLING-002 Active — src — —BILLING BILLING-007 Active src+test src+test src —BILLING BILLING-009 Active — src+test — —"><div></div></button></div></figure></div>
|
|
96
96
|
<div class="sl-heading-wrapper level-h2"><h2 id="single-repo-rung-1">Single repo (rung 1)</h2><a class="sl-anchor-link" href="#single-repo-rung-1"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “Single repo (rung 1)”</span></a></div>
|
|
97
|
-
<p>One repo with an in-repo <code dir="auto">spec-engine/<DOMAIN>/SPEC.json</code> and <code dir="auto">@spec</code> tags in its own code is a complete platform. No members
|
|
97
|
+
<p>One repo with an in-repo <code dir="auto">spec-engine/<DOMAIN>/SPEC.json</code> and <code dir="auto">@spec</code> tags in its own code is a complete platform. No members and no pin; <code dir="auto">spec init .</code> there installs only the agent surface (the agent reference in <code dir="auto">AGENTS.md</code>, the <code dir="auto">req-author</code> skill, the <code dir="auto">spec</code> MCP server, and a <code dir="auto">spec guard</code> pre-commit hook). See the <a href="/guides/single-repo/">Single Repo guide</a>.</p>
|
|
98
98
|
<div class="sl-heading-wrapper level-h2"><h2 id="grow-to-a-platform">Grow to a platform</h2><a class="sl-anchor-link" href="#grow-to-a-platform"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “Grow to a platform”</span></a></div>
|
|
99
99
|
<ol>
|
|
100
100
|
<li>Add a member repo beside <code dir="auto">spec-engine/</code> with <code dir="auto">@spec ORDERS-001</code> tags in source and test files</li>
|
|
101
|
-
<li>Pin the member: <code dir="auto">spec init checkout</code> (the default pin is the derived platform version)</li>
|
|
101
|
+
<li>Pin the member: <code dir="auto">spec init checkout</code> (the default pin is the derived platform version; it also installs the agent surface into <code dir="auto">checkout</code>)</li>
|
|
102
102
|
<li>Index and check: <code dir="auto">spec index && spec check</code></li>
|
|
103
103
|
</ol>
|
|
104
104
|
<p>See the <a href="/guides/platform-setup/">Platform Setup guide</a> for the full walkthrough.</p>
|
|
@@ -74,9 +74,9 @@
|
|
|
74
74
|
<p>Need the CLI first? <code dir="auto">bun add -g @spec-engine/spec-engine</code> puts <code dir="auto">spec</code> on your PATH — no clone required. See <a href="/getting-started/">Getting Started</a>.</p>
|
|
75
75
|
<div class="sl-heading-wrapper level-h2"><h2 id="step-1-create-the-domain-and-its-first-requirement">Step 1: Create the domain and its first requirement</h2><a class="sl-anchor-link" href="#step-1-create-the-domain-and-its-first-requirement"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “Step 1: Create the domain and its first requirement”</span></a></div>
|
|
76
76
|
<div class="expressive-code"><link rel="stylesheet" href="/_astro/ec.v4551.css"><script type="module" src="/_astro/ec.0vx5m.js"></script><figure class="frame is-terminal not-content"><figcaption class="header"><span class="title"></span><span class="sr-only">Terminal window</span></figcaption><pre data-language="shell"><code><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">$</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">domain</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">new</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">ORDERS</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">created</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec-engine/ORDERS/SPEC.json</span></div></div><div class="ec-line"><div class="code">
|
|
77
|
-
</div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">$</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">req</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">orders</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">--text</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">An order total equals the sum of its line items.</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">--why</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Mispriced orders ship money out the door silently.</span><span style="--0:#D9F5DD;--1:#111111">"</span
|
|
77
|
+
</div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">$</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">req</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">orders</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">--text</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">An order total equals the sum of its line items.</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#F78C6C;--1:#AA0982">\</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#82AAFF;--1:#3B61B0">--why</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">Mispriced orders ship money out the door silently.</span><span style="--0:#D9F5DD;--1:#111111">"</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">appended</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">ORDERS-001</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">to</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#ECC48D;--1:#3B61B0">spec-engine/ORDERS/SPEC.json</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="$ spec domain new ORDERScreated spec-engine/ORDERS/SPEC.json$ spec req orders --text "An order total equals the sum of its line items." \ --why "Mispriced orders ship money out the door silently."appended ORDERS-001 to spec-engine/ORDERS/SPEC.json"><div></div></button></div></figure></div>
|
|
78
78
|
<p><code dir="auto">spec req</code> appends a born-active entry through the same validated write seam every surface uses. The result on disk:</p>
|
|
79
|
-
<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="json"><code><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"key"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">ORDERS</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"owner"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"updated"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">2026-07-16</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"requirements"</span><span style="--0:#D6DEEB;--1:#403F53">: [</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"id"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">ORDERS-001</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"status"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">active</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"statement"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">An order total equals the sum of its line items.</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"why"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">Mispriced orders ship money out the door silently.</span><span style="--0:#D9F5DD;--1:#111111">"</span
|
|
79
|
+
<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="json"><code><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"key"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">ORDERS</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"owner"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#FF6A83;--1:#A24848">null</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"updated"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">2026-07-16</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"requirements"</span><span style="--0:#D6DEEB;--1:#403F53">: [</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"id"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">ORDERS-001</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"status"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">active</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"statement"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">An order total equals the sum of its line items.</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#7FDBCA;--1:#096E72">"why"</span><span style="--0:#D6DEEB;--1:#403F53">: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#C789D6;--1:#7C5686">Mispriced orders ship money out the door silently.</span><span style="--0:#D9F5DD;--1:#111111">"</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">]</span></div></div><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="{ "key": "ORDERS", "owner": null, "updated": "2026-07-16", "requirements": [ { "id": "ORDERS-001", "status": "active", "statement": "An order total equals the sum of its line items.", "why": "Mispriced orders ship money out the door silently." } ]}"><div></div></button></div></figure></div>
|
|
80
80
|
<p>Note there is no version counter in the file — the domain’s version is derived from its supersede history.</p>
|
|
81
81
|
<div class="sl-heading-wrapper level-h2"><h2 id="step-2-add-a-member">Step 2: Add a member</h2><a class="sl-anchor-link" href="#step-2-add-a-member"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “Step 2: Add a member”</span></a></div>
|
|
82
82
|
<p>Beside <code dir="auto">spec-engine/</code>, make a <code dir="auto">checkout/</code> repo (a <code dir="auto">.git</code> entry or a <code dir="auto">package.json</code> is what makes it a repository platform-map can declare) with tagged files:</p>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.5.2","languages":{"en":{"hash":"
|
|
1
|
+
{"version":"1.5.2","languages":{"en":{"hash":"en_bc3d4a7766","wasm":"en","page_count":12}},"include_characters":["_","‿","⁀","⁔","︳","︴","﹍","﹎","﹏","_"]}
|
|
Binary file
|
|
@@ -245,7 +245,8 @@
|
|
|
245
245
|
</tr>
|
|
246
246
|
</tbody>
|
|
247
247
|
</table>
|
|
248
|
-
<p>It resolves symlinks, locates the platform root, and refuses
|
|
248
|
+
<p>It resolves symlinks, locates the platform root, and refuses a directory inside a <code dir="auto">spec-engine/</code> tree with exit 2, because a pin there registers the requirement source as a member of itself. <!-- @spec INIT-042 --></p>
|
|
249
|
+
<p>The platform root itself is not a member: <code dir="auto">spec init</code> writes only the agent surface there and no pin. <!-- @spec INIT-043 --></p>
|
|
249
250
|
<p>The refusal reads every path segment for the name <code dir="auto">spec-engine</code>. On the engine’s own checkout, whose root package is named <code dir="auto">@spec-engine/spec-engine</code>, only the path below the platform root is judged, so a checkout named <code dir="auto">spec-engine</code> can still scaffold its own packages. <!-- @spec INIT-030 --></p>
|
|
250
251
|
<p>The default pin is the derived platform version. With no located platform, <code dir="auto">spec init</code> writes <code dir="auto">spec-engine@1</code> and says so.</p>
|
|
251
252
|
<div class="sl-heading-wrapper level-h2"><h2 id="the-webapps-scan-mode-tile">The webapp’s scan-mode tile</h2><a class="sl-anchor-link" href="#the-webapps-scan-mode-tile"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “The webapp’s scan-mode tile”</span></a></div>
|
|
@@ -70,58 +70,10 @@
|
|
|
70
70
|
})();
|
|
71
71
|
</script></sl-sidebar-state-persist><div class="md:sl-hidden"><div class="mobile-preferences sl-flex astro-hclhd3l6"><div class="social-icons astro-hclhd3l6"><a href="https://github.com/spec-engine/spec-engine" rel="me" class="sl-flex astro-n6yxnlqb"><span class="sr-only astro-n6yxnlqb">GitHub</span><svg aria-hidden="true" class="astro-n6yxnlqb astro-ica5m7eu" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M12 .3a12 12 0 0 0-3.8 23.38c.6.12.83-.26.83-.57L9 21.07c-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.08-.74.09-.73.09-.73 1.2.09 1.83 1.24 1.83 1.24 1.08 1.83 2.81 1.3 3.5 1 .1-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.14-.3-.54-1.52.1-3.18 0 0 1-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.28-1.55 3.29-1.23 3.29-1.23.64 1.66.24 2.88.12 3.18a4.65 4.65 0 0 1 1.23 3.22c0 4.61-2.8 5.63-5.48 5.92.42.36.81 1.1.81 2.22l-.01 3.29c0 .31.2.69.82.57A12 12 0 0 0 12 .3Z"/></svg></a></div><starlight-theme-select><label style="--sl-select-width: 6.25em" class="astro-bqlrlpix"><span class="sr-only astro-bqlrlpix">Select theme</span><svg aria-hidden="true" class="icon label-icon astro-bqlrlpix astro-ica5m7eu" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg><select autocomplete="off" class="astro-bqlrlpix"><option value="dark" class="astro-bqlrlpix">Dark</option><option value="light" class="astro-bqlrlpix">Light</option><option value="auto" selected class="astro-bqlrlpix">Auto</option></select><svg aria-hidden="true" class="icon caret astro-bqlrlpix astro-ica5m7eu" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg></label></starlight-theme-select><script>
|
|
72
72
|
StarlightThemeProvider.updatePickers();
|
|
73
|
-
</script></div></div></div></div></nav><div class="main-frame astro-qobrlvtk"><script type="module">var e=document.getElementById(`starlight__sidebar`),t=e?.querySelector(`sl-sidebar-state-persist`),n=`sl-sidebar-state`,r=()=>{let r=[],i=t?.dataset.hash||``;try{let e=sessionStorage.getItem(n),t=JSON.parse(e||`{}`);Array.isArray(t.open)&&t.hash===i&&(r=t.open)}catch{}return{hash:i,open:r,scroll:e?.scrollTop||0}},i=e=>{try{sessionStorage.setItem(n,JSON.stringify(e))}catch{}},a=()=>i(r()),o=(e,t)=>{let n=r();n.open[t]=e,i(n)};t?.addEventListener(`click`,e=>{if(!(e.target instanceof Element))return;let t=e.target.closest(`summary`)?.closest(`details`);if(!t)return;let n=t.querySelector(`sl-sidebar-restore`),r=parseInt(n?.dataset.index||``);isNaN(r)||o(!t.open,r)}),addEventListener(`visibilitychange`,()=>{document.visibilityState===`hidden`&&a()}),addEventListener(`pageHide`,a);</script><div class="lg:sl-flex astro-iv7ihhtf"><aside class="right-sidebar-container print:hidden astro-iv7ihhtf"><div class="right-sidebar astro-iv7ihhtf"><div class="lg:sl-hidden astro-dfaa6j3s"><mobile-starlight-toc data-min-h="2" data-max-h="3" class="astro-hhhdejk6"><nav aria-labelledby="starlight__on-this-page--mobile" class="astro-hhhdejk6"><details id="starlight__mobile-toc" class="astro-hhhdejk6"><summary id="starlight__on-this-page--mobile" class="sl-flex astro-hhhdejk6"><span class="toggle sl-flex astro-hhhdejk6">On this page<svg aria-hidden="true" class="caret astro-hhhdejk6 astro-ica5m7eu" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></span><span class="display-current astro-hhhdejk6"></span></summary><div class="dropdown astro-hhhdejk6"><ul class="isMobile astro-l6rvz6dz" style="--depth: 0;"><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#_top" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Overview</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#
|
|
73
|
+
</script></div></div></div></div></nav><div class="main-frame astro-qobrlvtk"><script type="module">var e=document.getElementById(`starlight__sidebar`),t=e?.querySelector(`sl-sidebar-state-persist`),n=`sl-sidebar-state`,r=()=>{let r=[],i=t?.dataset.hash||``;try{let e=sessionStorage.getItem(n),t=JSON.parse(e||`{}`);Array.isArray(t.open)&&t.hash===i&&(r=t.open)}catch{}return{hash:i,open:r,scroll:e?.scrollTop||0}},i=e=>{try{sessionStorage.setItem(n,JSON.stringify(e))}catch{}},a=()=>i(r()),o=(e,t)=>{let n=r();n.open[t]=e,i(n)};t?.addEventListener(`click`,e=>{if(!(e.target instanceof Element))return;let t=e.target.closest(`summary`)?.closest(`details`);if(!t)return;let n=t.querySelector(`sl-sidebar-restore`),r=parseInt(n?.dataset.index||``);isNaN(r)||o(!t.open,r)}),addEventListener(`visibilitychange`,()=>{document.visibilityState===`hidden`&&a()}),addEventListener(`pageHide`,a);</script><div class="lg:sl-flex astro-iv7ihhtf"><aside class="right-sidebar-container print:hidden astro-iv7ihhtf"><div class="right-sidebar astro-iv7ihhtf"><div class="lg:sl-hidden astro-dfaa6j3s"><mobile-starlight-toc data-min-h="2" data-max-h="3" class="astro-hhhdejk6"><nav aria-labelledby="starlight__on-this-page--mobile" class="astro-hhhdejk6"><details id="starlight__mobile-toc" class="astro-hhhdejk6"><summary id="starlight__on-this-page--mobile" class="sl-flex astro-hhhdejk6"><span class="toggle sl-flex astro-hhhdejk6">On this page<svg aria-hidden="true" class="caret astro-hhhdejk6 astro-ica5m7eu" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></span><span class="display-current astro-hhhdejk6"></span></summary><div class="dropdown astro-hhhdejk6"><ul class="isMobile astro-l6rvz6dz" style="--depth: 0;"><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#_top" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Overview</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#which-files-and-paths" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Which files and paths</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#what-to-tag" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">What to tag</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#verification-levels" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Verification levels</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#coverage" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Coverage</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#tag-scanner-notes" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Tag scanner notes</span></a></li></ul></div></details></nav></mobile-starlight-toc><script type="module" src="/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js"></script></div><div class="right-sidebar-panel sl-hidden lg:sl-block astro-dfaa6j3s"><div class="sl-container astro-dfaa6j3s"><starlight-toc data-min-h="2" data-max-h="3"><nav aria-labelledby="starlight__on-this-page"><h2 id="starlight__on-this-page">On this page</h2><ul class="astro-l6rvz6dz" style="--depth: 0;"><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#_top" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Overview</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#which-files-and-paths" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Which files and paths</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#what-to-tag" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">What to tag</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#verification-levels" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Verification levels</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#coverage" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Coverage</span></a></li><li style="--depth: 0;" class="astro-l6rvz6dz"><a href="#tag-scanner-notes" style="--depth: 0;" class="astro-l6rvz6dz"><span style="--depth: 0;" class="astro-l6rvz6dz">Tag scanner notes</span></a></li></ul></nav></starlight-toc><script type="module" src="/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js"></script></div></div></div></aside><div class="main-pane astro-iv7ihhtf"><main data-pagefind-body class="astro-kmpt7d6z" lang="en" dir="ltr"><div class="content-panel astro-d3w5v5qg"><div class="sl-container astro-d3w5v5qg"><h1 id="_top" class="astro-elp5pbgd">Tags</h1></div></div><div class="content-panel astro-d3w5v5qg"><div class="sl-container astro-d3w5v5qg"><div class="sl-markdown-content"><p>A tag in implementation code <strong>implements</strong> a requirement; a tag in a test file <strong>verifies</strong> it, optionally at a level.</p>
|
|
74
74
|
<div class="expressive-code"><link rel="stylesheet" href="/_astro/ec.v4551.css"><script type="module" src="/_astro/ec.0vx5m.js"></script><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="ts"><code><div class="ec-line"><div class="code"><span style="--0:#C792EA;--1:#8844AE">export</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">function</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">renew</span><span style="--0:#D9F5DD;--1:#111111">()</span><span style="--0:#D6DEEB;--1:#403F53"> { </span><span style="--0:#919F9F;--1:#5F636F">/* ... */</span><span style="--0:#D6DEEB;--1:#403F53"> } </span><span style="--0:#919F9F;--1:#5D6376">// @spec BILLING-009</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">it</span><span style="--0:#D6DEEB;--1:#403F53">(</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">charges at current price</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#D9F5DD;--1:#111111">()</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> {}) </span><span style="--0:#919F9F;--1:#5D6376">// @spec BILLING-009 unit</span></div></div><div class="ec-line"><div class="code"><span style="--0:#82AAFF;--1:#3B61B0">it</span><span style="--0:#D6DEEB;--1:#403F53">(</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">renews end to end</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#D9F5DD;--1:#111111">()</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> {}) </span><span style="--0:#919F9F;--1:#5D6376">// @spec BILLING-009 e2e</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="export function renew() { /* ... */ } // @spec BILLING-009it("charges at current price", () => {}) // @spec BILLING-009 unitit("renews end to end", () => {}) // @spec BILLING-009 e2e"><div></div></button></div></figure></div>
|
|
75
|
-
<div class="sl-heading-wrapper level-h2"><h2 id="
|
|
76
|
-
<p>
|
|
77
|
-
<ul>
|
|
78
|
-
<li><code dir="auto">.ts</code>, <code dir="auto">.tsx</code>, <code dir="auto">.js</code>, <code dir="auto">.jsx</code>, <code dir="auto">.mjs</code></li>
|
|
79
|
-
<li><code dir="auto">.sh</code></li>
|
|
80
|
-
<li><code dir="auto">.lua</code>, <code dir="auto">.luau</code></li>
|
|
81
|
-
<li><code dir="auto">.go</code></li>
|
|
82
|
-
<li><code dir="auto">.rs</code></li>
|
|
83
|
-
<li><code dir="auto">.tf</code></li>
|
|
84
|
-
<li><code dir="auto">.toml</code></li>
|
|
85
|
-
<li><code dir="auto">.sql</code></li>
|
|
86
|
-
<li><code dir="auto">.css</code></li>
|
|
87
|
-
<li><code dir="auto">.yml</code>, <code dir="auto">.yaml</code></li>
|
|
88
|
-
<li><code dir="auto">.astro</code></li>
|
|
89
|
-
</ul>
|
|
90
|
-
<p>Documentation is read from <code dir="auto">.md</code> files.</p>
|
|
91
|
-
<p>The tag regex ignores the comment leader, so each of these binds:</p>
|
|
92
|
-
<table>
|
|
93
|
-
<thead>
|
|
94
|
-
<tr>
|
|
95
|
-
<th>Leader</th>
|
|
96
|
-
<th>Where</th>
|
|
97
|
-
</tr>
|
|
98
|
-
</thead>
|
|
99
|
-
<tbody>
|
|
100
|
-
<tr>
|
|
101
|
-
<td><code dir="auto">// @spec BILLING-009</code></td>
|
|
102
|
-
<td>TypeScript, JavaScript, Go, Rust, Astro front-matter</td>
|
|
103
|
-
</tr>
|
|
104
|
-
<tr>
|
|
105
|
-
<td><code dir="auto"># @spec BILLING-009</code></td>
|
|
106
|
-
<td>shell, Terraform, TOML, YAML, Dockerfile</td>
|
|
107
|
-
</tr>
|
|
108
|
-
<tr>
|
|
109
|
-
<td><code dir="auto">-- @spec BILLING-009</code></td>
|
|
110
|
-
<td>Lua, Luau, SQL</td>
|
|
111
|
-
</tr>
|
|
112
|
-
<tr>
|
|
113
|
-
<td><code dir="auto">/* @spec BILLING-009 */</code></td>
|
|
114
|
-
<td>CSS</td>
|
|
115
|
-
</tr>
|
|
116
|
-
<tr>
|
|
117
|
-
<td>an HTML comment</td>
|
|
118
|
-
<td>Astro template, Markdown</td>
|
|
119
|
-
</tr>
|
|
120
|
-
</tbody>
|
|
121
|
-
</table>
|
|
122
|
-
<p>Dot-prefixed directories are skipped, except <code dir="auto">.github/</code>.</p>
|
|
123
|
-
<div class="sl-heading-wrapper level-h2"><h2 id="tag-kind">Tag kind</h2><a class="sl-anchor-link" href="#tag-kind"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “Tag kind”</span></a></div>
|
|
124
|
-
<p>Kind is <strong>path-derived</strong>, never authored:</p>
|
|
75
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="which-files-and-paths">Which files and paths</h2><a class="sl-anchor-link" href="#which-files-and-paths"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “Which files and paths”</span></a></div>
|
|
76
|
+
<p>The scanner reads common source extensions, Dockerfiles, and Markdown documents, and ignores the comment leader, so <code dir="auto">//</code>, <code dir="auto">#</code>, <code dir="auto">--</code>, <code dir="auto">/* */</code>, and an HTML comment all bind. A path is a test path when it follows a test-runner convention such as <code dir="auto">.test.</code>, <code dir="auto">__tests__/</code>, or <code dir="auto">_test.go</code>. The exact extension list and test-path patterns are in the <a href="/agent-reference/#tags">Agent Reference</a>.</p>
|
|
125
77
|
<table>
|
|
126
78
|
<thead>
|
|
127
79
|
<tr>
|
|
@@ -131,57 +83,22 @@
|
|
|
131
83
|
</thead>
|
|
132
84
|
<tbody>
|
|
133
85
|
<tr>
|
|
134
|
-
<td
|
|
86
|
+
<td>implementation code</td>
|
|
135
87
|
<td><strong>implements</strong></td>
|
|
136
88
|
</tr>
|
|
137
89
|
<tr>
|
|
138
|
-
<td
|
|
90
|
+
<td>a test path</td>
|
|
139
91
|
<td><strong>verifies</strong></td>
|
|
140
92
|
</tr>
|
|
141
93
|
<tr>
|
|
142
|
-
<td>a
|
|
94
|
+
<td>a Markdown document</td>
|
|
143
95
|
<td><strong>documents</strong></td>
|
|
144
96
|
</tr>
|
|
145
97
|
</tbody>
|
|
146
98
|
</table>
|
|
147
|
-
<p>
|
|
148
|
-
<
|
|
149
|
-
<
|
|
150
|
-
<tr>
|
|
151
|
-
<th>Convention</th>
|
|
152
|
-
<th>Substring</th>
|
|
153
|
-
<th>Example</th>
|
|
154
|
-
</tr>
|
|
155
|
-
</thead>
|
|
156
|
-
<tbody>
|
|
157
|
-
<tr>
|
|
158
|
-
<td>TypeScript and JavaScript runners</td>
|
|
159
|
-
<td><code dir="auto">.test.</code>, <code dir="auto">.spec.</code>, <code dir="auto">__tests__/</code>, <code dir="auto">/tests/</code>, <code dir="auto">/e2e/</code>, <code dir="auto">.e2e.</code></td>
|
|
160
|
-
<td><code dir="auto">test/renew.test.ts</code>, <code dir="auto">src/renew.spec.ts</code></td>
|
|
161
|
-
</tr>
|
|
162
|
-
<tr>
|
|
163
|
-
<td>Go</td>
|
|
164
|
-
<td><code dir="auto">_test.go</code></td>
|
|
165
|
-
<td><code dir="auto">renew_test.go</code></td>
|
|
166
|
-
</tr>
|
|
167
|
-
<tr>
|
|
168
|
-
<td>Rust</td>
|
|
169
|
-
<td><code dir="auto">/tests/</code>, <code dir="auto">_test.rs</code></td>
|
|
170
|
-
<td><code dir="auto">tests/renew.rs</code>, <code dir="auto">src/renew_test.rs</code></td>
|
|
171
|
-
</tr>
|
|
172
|
-
<tr>
|
|
173
|
-
<td>Lua with busted</td>
|
|
174
|
-
<td><code dir="auto">_spec.lua</code>, <code dir="auto">_test.lua</code>, <code dir="auto">/spec/</code></td>
|
|
175
|
-
<td><code dir="auto">spec/renew_spec.lua</code></td>
|
|
176
|
-
</tr>
|
|
177
|
-
<tr>
|
|
178
|
-
<td>Luau with TestEZ or Jest-Lua</td>
|
|
179
|
-
<td><code dir="auto">.spec.</code>, <code dir="auto">.test.</code></td>
|
|
180
|
-
<td><code dir="auto">renew.spec.luau</code>, <code dir="auto">renew.test.luau</code></td>
|
|
181
|
-
</tr>
|
|
182
|
-
</tbody>
|
|
183
|
-
</table>
|
|
184
|
-
<p>Rust unit tests written inline under <code dir="auto">#[cfg(test)]</code> live in the implementation file, so a tag there counts as <strong>implements</strong>; a verifying tag belongs in a <code dir="auto">tests/</code> integration test or a <code dir="auto">*_test.rs</code> file. A path rule cannot see inside a file, and Spec Engine does not read attributes.</p>
|
|
99
|
+
<p>Rust unit tests written inline under <code dir="auto">#[cfg(test)]</code> live in the implementation file, so a tag there counts as <strong>implements</strong>; a verifying tag belongs in a <code dir="auto">tests/</code> integration test or a <code dir="auto">*_test.rs</code> file.</p>
|
|
100
|
+
<div class="sl-heading-wrapper level-h2"><h2 id="what-to-tag">What to tag</h2><a class="sl-anchor-link" href="#what-to-tag"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “What to tag”</span></a></div>
|
|
101
|
+
<p>A tag binds the one function that produces the behavior and the one test that proves it. Helpers, glue code, and configuration carry no tag. If you cannot name the behavior a line produces, do not tag it.</p>
|
|
185
102
|
<div class="sl-heading-wrapper level-h2"><h2 id="verification-levels">Verification levels</h2><a class="sl-anchor-link" href="#verification-levels"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore>Section titled “Verification levels”</span></a></div>
|
|
186
103
|
<p>On test tags, an optional level token can be appended:</p>
|
|
187
104
|
<ul>
|