diff --git a/.add/milestones/build-strategy-facets/MILESTONE.md b/.add/milestones/build-strategy-facets/MILESTONE.md
index 67ba0c11..e807a2a8 100644
--- a/.add/milestones/build-strategy-facets/MILESTONE.md
+++ b/.add/milestones/build-strategy-facets/MILESTONE.md
@@ -3,7 +3,7 @@
goal: the build phase carries a structured, domain-anchored implementation strategy — algorithm approach, data strategy, dev pattern, and optimization stance are declared facets (not one overloaded line), each anchored upstream (§0/§1/§3), harvested per-facet into the §7 Decisions (ADR) block, and cross-cited by §7 Watch
rationale: intake bucket=one-task-gap → micro-milestone (2026-07-07): senior review of TASK.md.tmpl found §5's single `Strategy (ordered batches)` line conflates build order · architecture pattern · issue advice · persona stance, so builds skip the domain implementation decision (algorithm/data/pattern/optimization); no active milestone's goal covers method-template structure
stage: mvp · status: active · created: 2026-07-07T03:57:31+00:00
-release: pending
+release: 1.18.0
> SDD living doc for this milestone. Keep it THIN: breadth, shared decisions, and
> exit criteria only — per-task detail lives in each `.add/tasks//TASK.md`,
diff --git a/.add/milestones/delta-drain/MILESTONE.md b/.add/milestones/delta-drain/MILESTONE.md
index 0f1af4e9..e6d9d7ce 100644
--- a/.add/milestones/delta-drain/MILESTONE.md
+++ b/.add/milestones/delta-drain/MILESTONE.md
@@ -3,7 +3,7 @@
goal: the 4 open SPEC deltas are each resolved into a shipped behavior — compact-foundation gains a read-only --propose preview, personas gain a dedicated `verify` flow value, the streams.md worker-contract `` block names the flow preference, and status/check render an engine-built persona roster line — leaving zero open SPEC deltas
rationale: intake bucket=sub-milestone (2026-07-07, Tin: "implement all directly"): 4 independent deltas from 3 prior tasks, each small but crossing engine+skill+guard surfaces; loose fast tasks would lose the shared roster/flow decisions, so a thin milestone binds them
stage: mvp · status: active · created: 2026-07-07T08:15:15+00:00
-release: pending
+release: 1.18.0
> SDD living doc for this milestone. Keep it THIN: breadth, shared decisions, and
> exit criteria only — per-task detail lives in each `.add/tasks//TASK.md`,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa723614..b9a21713 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,11 @@
# Changelog
-## 1.17.0 — 2026-07-07
+## 1.18.0 — 2026-07-07
+
+- Drain the 4 open SPEC deltas — 0 carried · 0 key decision(s)
+- Faceted §5 build strategy — 0 carried · 0 key decision(s)
+
+## 1.17.0 — 2026-07-06
- Persona domain-fit nudge — 2 carried · 0 key decision(s)
- Method ergonomics — 0 carried · 0 key decision(s)
diff --git a/RELEASES.md b/RELEASES.md
index 400571c7..003336bc 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,5 +1,12 @@
# Releases
+## 1.18.0 — 2026-07-07
+milestones: delta-drain, build-strategy-facets
+loose tasks: none
+waivers: reclaim-ticket-race, js-reclaim-lock-heartbeat
+actor: Tin Dang (git)
+evidence: test_release_1_18_0.py 11/11 green · add.py check green · milestones build-strategy-facets(#139) + delta-drain(#140) merged to main
+
## 1.17.0 — 2026-07-07
milestones: persona-domain-fit, method-ergonomics, dynamic-personas, self-improving-loop
loose tasks: grep-binary-agnostic-milestone-test, prune-data-update-lock, sweep-orphan-reclaim-tickets, adr-harvester-multiline-fields, strip-scaffold-backtick-comment-fix, worktree-isolated-spawn-default, fold-glossary-deltas, reclaim-ticket-race, js-reclaim-lock-heartbeat, scope-components-check, fastlane-intake-nudge, persona-required-domain-hint
diff --git a/add-method/.claude-plugin/plugin.json b/add-method/.claude-plugin/plugin.json
index c4d31bbe..872f198d 100644
--- a/add-method/.claude-plugin/plugin.json
+++ b/add-method/.claude-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "add",
"displayName": "ADD — AI-Driven Development",
- "version": "1.17.0",
+ "version": "1.18.0",
"description": "ADD (AI-Driven Development). One skill. Eight steps. Five disciplines. Every feature ships through the loop — a minimal, state-tracked Claude Code skill that ships the AIDD book as its trust layer.",
"author": {
"name": "Tin Dang",
diff --git a/add-method/CHANGELOG.md b/add-method/CHANGELOG.md
index 25db9f2b..985245f5 100644
--- a/add-method/CHANGELOG.md
+++ b/add-method/CHANGELOG.md
@@ -4,6 +4,37 @@ All notable changes to the ADD method (`@pilotspace/add` on npm,
`pilotspace-add` on PyPI) are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/); versions follow semver.
+## [1.18.0] — 2026-07-07
+
+Minor: two milestones — **build-strategy-facets** (§5 build strategy becomes
+four domain-generic facet lines with fast-lane collapse, plus per-facet ADR
+harvest) and **delta-drain** (all 4 open SPEC deltas resolved into shipped
+behavior, leaving zero open SPEC deltas). All additive; no gate weakened,
+nothing removed or renamed.
+
+### Added
+- **Faceted §5 build strategy** — four domain-generic facet lines drafted at
+ the tests→build cross: `Approach` (domain strategy) · `Data strategy` ·
+ `Pattern` · `Optimization stance`; the fast lane collapses them to one line
+ (build-strategy-facets).
+- **per-facet ADR harvest** — each §5 facet lands in §7 Decisions (ADR) as its
+ own actor-tagged line at done (build-strategy-facets).
+- **compact-foundation `--propose`** — a read-only preview of the compaction a
+ run would take; inspect before any byte moves (delta-drain).
+- **`verify` flow value for personas** — personas route to the verify surface
+ directly; the streams.md worker-contract `` block names the flow
+ preference (delta-drain).
+- **persona roster line** — `status`/`check` render an engine-built roster with
+ flows, never hand-maintained (delta-drain).
+
+### Changed
+- §5 build strategy guidance, phase guides, and the TASK.md/TASK.fast.md
+ templates teach and carry the facet block (build-strategy-facets).
+
+### Disclosed waivers (non-security, signed)
+- `reclaim-ticket-race` — lock-reclaim TOCTOU flake; owner Tin Dang, expires 2026-08-04.
+- `js-reclaim-lock-heartbeat` — JS lock-heartbeat race; owner Tin Dang, expires 2026-08-04.
+
## [1.17.0] — 2026-07-06
Minor: four milestones — **method-ergonomics** (every recurring gate rule becomes
diff --git a/add-method/README.md b/add-method/README.md
index 011c7fc0..aa526b59 100644
--- a/add-method/README.md
+++ b/add-method/README.md
@@ -2,12 +2,13 @@
+
# ADD — AI-Driven Development
-**One skill. Eight steps. Five disciplines. Every feature ships through the loop.**
+**Describe the feature. The agent drives the build. You approve once — exactly where a mistake would actually cost you.**
> A minimal, state-tracked skill for building software when the AI writes the code
> and **you** own the two things it cannot do alone: decide *what* to build, and
@@ -46,8 +47,28 @@ scenarios → contract → tests as one bundle (you approve once, at the frozen
contract), then builds and verifies to green. Full detail below — **Install**,
**Use it**, and the [10-minute Quickstart](./GETTING-STARTED.md).
+## Highlights
+
+- ✅ **Approve once, then let it run** — one human sign-off at the frozen contract; the agent builds the rest.
+- 🔬 **Proof, not promises** — verified against observed behavior and pre-declared expectations, never just a plausible-looking diff.
+- 🔒 **Security never gets waved through** — any security finding is a hard stop, human in the loop.
+- 🌱 **Prototype to production** — task → milestone → graduate (analytics-gated) → recorded release, one method throughout.
+- 🧠 **Smarter as you go** — lessons consolidate into a living, compacting foundation carried across milestones.
+- 🎨 **See it before you build it** — a wireframe and a zero-dependency HTML mock, approved before any code.
+- 👥 **Built for teams** — git-native multi-user, N parallel milestones, DAG-scheduled waves.
+- 🧩 **One slice, many components** — monorepo or multi-repo, in one team.
+- 🤝 **Works with your AI** — Claude, Copilot, Cursor, Codex, Gemini; install via npm, pip, or the Claude Code plugin.
+
+> _Direction before speed. Trust comes from passing tests — not from reading code and finding it plausible._
+
## Why ADD (and why it is minimal)
+Every AI coding tool can write code fast now. The part that never got solved is
+trust — how do you know it built the *right* thing, and how do you know it's
+*correct*, without reading every line yourself? ADD answers both: freeze the
+direction *before* any code is written, then trust the result through passing
+evidence, never a diff that merely looks right.
+
Heavy doc-first methods burn your time writing documents and lose the thread
across sessions (context rot). ADD fixes both:
@@ -225,6 +246,12 @@ be upset to lose is "the code," you're still working the old way.
Start at [`docs/README.md`](./docs/README.md) — Foundations → the six steps →
operating it across a team → templates, prompts, and a full worked example.
+More entry points:
+
+- 📖 [Read the book online](https://pilotspace.github.io/ADD/) — the full AIDD method, chapter by chapter
+- 🔍 [Full hands-on walkthrough](./GETTING-STARTED.md) — one real feature, end to end
+- 🗞️ [ADD Across the Org: AI-Driven Development Beyond Code](https://inkpaper-blog.pages.dev/series/add-across-the-org/)
+
## What's next
**Dynamic Agent Skills** — the next scope: skills that adapt at runtime to the
diff --git a/add-method/package-lock.json b/add-method/package-lock.json
index b1b7502c..5588bdec 100644
--- a/add-method/package-lock.json
+++ b/add-method/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@pilotspace/add",
- "version": "1.17.0",
+ "version": "1.18.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@pilotspace/add",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"dependencies": {
"@clack/prompts": "^1.5.1"
diff --git a/add-method/package.json b/add-method/package.json
index 5bb68729..0bad7fd1 100644
--- a/add-method/package.json
+++ b/add-method/package.json
@@ -1,6 +1,6 @@
{
"name": "@pilotspace/add",
- "version": "1.17.0",
+ "version": "1.18.0",
"description": "ADD (AI-Driven Development). One skill. Eight steps. Five disciplines. Every feature ships through the loop — a minimal, state-tracked Claude Code skill that ships the AIDD book as its trust layer.",
"bin": {
"add": "bin/cli.js"
diff --git a/add-method/pyproject.toml b/add-method/pyproject.toml
index 12f31e94..33c14e69 100644
--- a/add-method/pyproject.toml
+++ b/add-method/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "pilotspace-add"
-version = "1.17.0"
+version = "1.18.0"
description = "ADD (AI-Driven Development). One skill. Eight steps. Five disciplines. Every feature ships through the loop — install the ADD skill, tooling, and AIDD book into any project."
readme = "README.md"
license = "MIT"
diff --git a/add-method/src/add_method/__init__.py b/add-method/src/add_method/__init__.py
index 32c95711..e73d9155 100644
--- a/add-method/src/add_method/__init__.py
+++ b/add-method/src/add_method/__init__.py
@@ -14,4 +14,4 @@
from add_method._installer import install
__all__ = ["install"]
-__version__ = "1.17.0"
+__version__ = "1.18.0"
diff --git a/add-method/tooling/test_release_1_17_0.py b/add-method/tooling/test_release_1_17_0.py
index 5a661ac3..123ac3bd 100644
--- a/add-method/tooling/test_release_1_17_0.py
+++ b/add-method/tooling/test_release_1_17_0.py
@@ -95,26 +95,11 @@ def test_audit_line_survives_bumps(self):
class ReleaseShapeTest(unittest.TestCase):
- def test_versions_agree_at_1_17_0(self):
- pkg = json.loads((PKG / "package.json").read_text(encoding="utf-8"))["version"]
- py = re.search(r'(?m)^version\s*=\s*"([^"]+)"',
- (PKG / "pyproject.toml").read_text(encoding="utf-8")).group(1)
- self.assertEqual((pkg, py), (VERSION, VERSION),
- "publish.yml's guard would fail this release closed")
-
- def test_plugin_version_agrees(self):
- plugin = json.loads(
- (PKG / ".claude-plugin" / "plugin.json").read_text(encoding="utf-8")
- )["version"]
- self.assertEqual(plugin, VERSION,
- "the Claude Code plugin manifest must match the shipped version")
-
- def test_runtime_version_agrees(self):
- init = (PKG / "src" / "add_method" / "__init__.py").read_text(encoding="utf-8")
- runtime = re.search(r'(?m)^__version__\s*=\s*"([^"]+)"', init).group(1)
- self.assertEqual(runtime, VERSION,
- "add_method.__version__ must match the shipped version")
-
+ # NOTE: 1.17.0 is superseded by 1.18.0 — the live-version-agreement assertions
+ # (versions/plugin/runtime == VERSION) moved to test_release_1_18_0.py (the
+ # forward-migration the release-gate pattern demands; the 1.16.0 -> 1.16.1
+ # precedent). This file keeps only lineage + shipped-doc + parity checks,
+ # which stay true across bumps.
def test_getting_started_mentions_guide_line(self):
text = (PKG / "GETTING-STARTED.md").read_text(encoding="utf-8")
self.assertIn("guide :", text,
diff --git a/add-method/tooling/test_release_1_18_0.py b/add-method/tooling/test_release_1_18_0.py
new file mode 100644
index 00000000..4c29fc0d
--- /dev/null
+++ b/add-method/tooling/test_release_1_18_0.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python3
+"""Red/green tests for the 1.18.0 release readiness (build-strategy-facets + delta-drain).
+
+Minor cut: two milestones — **build-strategy-facets** (§5 build strategy becomes
+four domain-generic facet lines — Approach · Data strategy · Pattern ·
+Optimization stance — with fast-lane collapse, plus per-facet ADR harvest into
+§7) and **delta-drain** (the 4 open SPEC deltas each resolved into shipped
+behavior: `compact-foundation --propose` read-only preview · a dedicated
+`verify` persona flow value · the streams.md worker-contract `` block
+names the flow preference · an engine-built persona roster line in
+status/check). All additive; no gate weakened, nothing removed or renamed.
+
+In-repo readiness only — the live-registry halves (npm/PyPI serving 1.18.0) are
+verify-gate EVIDENCE gathered after the human-gated tag push, never unit tests.
+Run:
+ python3 -m unittest test_release_1_18_0 -v
+"""
+import hashlib
+import json
+import re
+import unittest
+from pathlib import Path
+
+HERE = Path(__file__).resolve().parent
+PKG = HERE.parent # add-method/
+REPO = PKG.parent
+BUNDLE = PKG / "src" / "add_method" / "_bundled"
+
+CHANGELOG = PKG / "CHANGELOG.md"
+CI_YML = REPO / ".github" / "workflows" / "ci.yml"
+PUBLISH_YML = REPO / ".github" / "workflows" / "publish.yml"
+
+VERSION = "1.18.0"
+PRIOR_VERSIONS = ("1.17.0", "1.16.1", "1.16.0", "1.15.0", "1.14.0", "1.13.0", "1.12.0",
+ "1.11.0", "1.10.0", "1.9.0", "1.8.0", "1.7.3", "1.7.2", "1.7.1",
+ "1.7.0", "1.6.0", "1.5.0", "1.4.0", "1.3.0", "1.2.0", "1.1.0", "1.0.0")
+from engine_pin import ENGINE_MD5
+CANONICAL_AUDIT = "run: python3 .add/tooling/add.py audit"
+# the headline changes the 1.18.0 notes must name
+FEATURE_ANCHORS = ("Approach", "Data strategy", "Optimization stance",
+ "per-facet ADR harvest", "compact-foundation `--propose`",
+ "`verify` flow", "persona roster line")
+
+
+class ChangelogTest(unittest.TestCase):
+ def test_changelog_has_1_18_0_entry(self):
+ self.assertTrue(CHANGELOG.is_file(), "CHANGELOG.md missing")
+ text = CHANGELOG.read_text(encoding="utf-8")
+ self.assertIn(f"## [{VERSION}]", text)
+ for prior in PRIOR_VERSIONS:
+ self.assertIn(f"## [{prior}]", text,
+ f"the {prior} lineage entry must survive the bump")
+ entry = text.split(f"## [{VERSION}]", 1)[1].split("## [", 1)[0]
+ for anchor in FEATURE_ANCHORS:
+ self.assertIn(anchor, entry, f"1.18.0 entry must name: {anchor}")
+
+ def test_changelog_ships_in_both_channels(self):
+ files = json.loads((PKG / "package.json").read_text(encoding="utf-8"))["files"]
+ self.assertIn("CHANGELOG.md", files, "npm tarball must ship the changelog")
+ self.assertIn("include CHANGELOG.md",
+ (PKG / "MANIFEST.in").read_text(encoding="utf-8"),
+ "sdist/wheel must ship the changelog")
+
+
+class SecurityPolicyShipsTest(unittest.TestCase):
+ """SECURITY.md must keep travelling with both published distributions."""
+
+ def test_security_md_present(self):
+ self.assertTrue((PKG / "SECURITY.md").is_file(),
+ "add-method/SECURITY.md must exist")
+
+ def test_security_md_ships_in_both_channels(self):
+ files = json.loads((PKG / "package.json").read_text(encoding="utf-8"))["files"]
+ self.assertIn("SECURITY.md", files, "npm tarball must ship SECURITY.md")
+ self.assertIn("include SECURITY.md",
+ (PKG / "MANIFEST.in").read_text(encoding="utf-8"),
+ "sdist/wheel must ship SECURITY.md")
+
+
+class WorkflowHygieneTest(unittest.TestCase):
+ def test_no_deprecated_actions(self):
+ for wf in (CI_YML, PUBLISH_YML):
+ text = wf.read_text(encoding="utf-8")
+ self.assertNotIn("actions/checkout@v4", text, wf.name)
+ self.assertNotIn("actions/setup-python@v5", text, wf.name)
+ self.assertNotIn("actions/setup-node@v4", text, wf.name)
+
+ def test_audit_line_survives_bumps(self):
+ self.assertIn(CANONICAL_AUDIT, CI_YML.read_text(encoding="utf-8"),
+ "the seam-audit command must stay byte-identical")
+
+
+class ReleaseShapeTest(unittest.TestCase):
+ def test_versions_agree_at_1_18_0(self):
+ pkg = json.loads((PKG / "package.json").read_text(encoding="utf-8"))["version"]
+ py = re.search(r'(?m)^version\s*=\s*"([^"]+)"',
+ (PKG / "pyproject.toml").read_text(encoding="utf-8")).group(1)
+ self.assertEqual((pkg, py), (VERSION, VERSION),
+ "publish.yml's guard would fail this release closed")
+
+ def test_plugin_version_agrees(self):
+ plugin = json.loads(
+ (PKG / ".claude-plugin" / "plugin.json").read_text(encoding="utf-8")
+ )["version"]
+ self.assertEqual(plugin, VERSION,
+ "the Claude Code plugin manifest must match the shipped version")
+
+ def test_runtime_version_agrees(self):
+ init = (PKG / "src" / "add_method" / "__init__.py").read_text(encoding="utf-8")
+ runtime = re.search(r'(?m)^__version__\s*=\s*"([^"]+)"', init).group(1)
+ self.assertEqual(runtime, VERSION,
+ "add_method.__version__ must match the shipped version")
+
+ def test_getting_started_mentions_guide_line(self):
+ text = (PKG / "GETTING-STARTED.md").read_text(encoding="utf-8")
+ self.assertIn("guide :", text,
+ "orient docs must name the phase-playbook line")
+
+ def test_engine_trees_parity(self):
+ for p in (HERE / "add.py", REPO / ".add" / "tooling" / "add.py",
+ BUNDLE / "tooling" / "add.py"):
+ self.assertEqual(hashlib.md5(p.read_bytes()).hexdigest(), ENGINE_MD5,
+ f"engine trees must stay byte-identical + pinned: {p}")
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)