Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/guide/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ Spec Engine — it invents no semantics of its own. Exit codes mirror specdrift:
| `goldpath db status [--path <dir>]` | What is applied, what is pending — also inlined into `check`. |
| `goldpath db bundle [--path <dir>]` | A self-contained migration bundle for environments where the SDK is not installed. |

## Export

- `goldpath export compose [--path <dir>]` — reads the AppHost (the ONLY definition of the
topology) and writes a `docker-compose.yaml` + Dockerfile beside it. Re-runnable; the
compose file is an EXPORT, never a second source of truth. Exit 1 with the reason when
the AppHost declares no resources or a project has no matching directory.

## Inspect

| Verb | What it does |
Expand All @@ -55,3 +62,8 @@ goldpath/templates/goldpath-worker kind=worker name=GoldpathWorker
- It never edits what the engine would reject: every transform is validated, and a refusal
rolls the change back whole.
- It calls no LLM. The AI skills call the CLI and the engine, never the reverse (ADR-0004).

## Help

- `goldpath help` (also `--help`, `-h`) — the verb list with one line each; `--version`/`-v`
prints the informational version. Unknown verbs exit 2 with usage — never a silent 0.
3 changes: 2 additions & 1 deletion docs/rfc/goldpath-notification.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ replay to the jobs console. The notification rows ARE the audit.
- Insurance's nightly renewal run: 10k notifications rendered + evidence-stamped against
a no-op channel — measure rows/s (expectation: template render is string work; the
channel dominates in production).
- Render micro-bench: token replacement at p95 (budget: sub-millisecond).
- Render micro-bench: token replacement at p95 (budget: sub-millisecond). Reference
profile: `scripts/bench-notification.sh` → `packages/Goldpath.Notification/ops/notification-benchmarks.md`.
- Queue-age under a stopped channel: the backlog drains after recovery without loss or
duplicates (the claim proof, notification-flavored).

Expand Down
2 changes: 1 addition & 1 deletion docs/rfc/goldpath-versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ warnings first; a later minor may raise severity, and says so in the guide).

No release tag without all three, in the same release PR:

1. **PublicAPI roll:** every package's `Unshipped.txt` rolls into `Shipped.txt` (the
1. **PublicAPI roll (`scripts/roll-shipped.sh`):** every package's `Unshipped.txt` rolls into `Shipped.txt` (the
ledger IS the released surface; the roll script lands with the NuGet release work).
2. **CHANGELOG entry** for the train (one file, newest on top).
3. **Upgrade guide:** `docs/upgrades/<version>.md` — step-by-step for every break;
Expand Down
14 changes: 14 additions & 0 deletions docs/strategy/coverage-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ for planning · — deliberately absent (the card does not trigger it).
| specdrift CLI path | ✅ | — |
| specdrift MCP path (from skills) | 🟡 not exercised in a sample flow | Insurance build runs it |

## Ring C modules (matrix entry pending their sample cards)

| Capability | CorPay (finance) | Insurance | Telco |
|---|---|---|---|
| Approvals | 🟡 no sample story yet (the api-portal product proves the pattern end to end) | 🔷 endorsement four-eyes candidate | 🔷 tariff-change four-eyes candidate |
| FileExchange | 🟡 no sample story yet | 🔷 bordereaux import candidate | 🔷 CDR drop candidate |

## Foundational packages (no matrix row — they underpin EVERY cell)

Abstractions · Sdk · ServiceDefaults · ApiDefaults · Data · Messaging — composed by every
sample and every generated shape; their proof is the nightly golden-manifest matrix, not a
sector story. Named here so the docs-freshness inventory can hold this file to the full
package list.

## Console panels (post-UI; eyes-on + Playwright per sample)

| Panel | CorPay | Insurance | Telco |
Expand Down
22 changes: 22 additions & 0 deletions docs/strategy/golden-manifests-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,25 @@
2. A combination that blows up in the field → a GM update or a regression manifest (never deleted).
3. A GM change demands a review as serious as a schema/template change (these are the product's contract).
4. Every GM is also an example project usable in sales/demos — narrated by its persona name.

## 6. The nightly matrix today (docs-freshness gate keeps this table honest)

Every shape below runs nightly via `scripts/validate-gm.sh` — pack → generate → build →
spec-lint → smoke with real containers. A shape name here and in `nightly.yml` may not
drift apart; the gate fails on either direction.

| Shape | Arguments | What it proves |
|---|---|---|
| GmOneAuthDefault | (defaults) | the default shape, auth floor up |
| GmOneOpenFlow | `--auth none` | open shape drives the full order flow |
| GmFourSimple | `--db sqlserver --broker none --auth none` | the SqlServer/no-broker quadrant |
| GmFourClean | `--layout clean-architecture …` | four-project split, migrations in Infrastructure |
| GmSixGateway | `--auth none` + `new service` + `new gateway` | multi-head by the adopter's own verbs; routed probe |
| GmBulkOnly | `--features bulk --broker none --auth none` | operational module with ONLY the app database |
| Gm.Dotted | `--broker none --auth none` | dotted solution names (issue #24 regression) |
| GmConsole | `--features bulk --auth none` | the console SERVES with its own bundle |
| GmConsoleAuthed | `--features bulk` | the console's 401 floor branch |
| GmEverything | all eleven features | maximal composition compiles, boots, smokes |
| GmWorkerQueue | worker template | queue-triggered worker shape |
| GmWorkerSchedule | worker `--trigger schedule` | schedule-triggered worker shape |
| GmWorkerJobs | worker `--trigger jobs` | jobs-profile worker shape |
4 changes: 2 additions & 2 deletions packages/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# packages/

The NuGet train — 19 packages (Abstractions → ServiceDefaults → ApiDefaults → Data →
Messaging → Ring B/C modules), published as `0.1.0-preview.*` with OIDC trusted publishing.
The NuGet train — 23 packages (Abstractions → ServiceDefaults → ApiDefaults → Data →
Messaging → Ring B/C modules + providers), published as `0.1.0-preview.*` with OIDC trusted publishing.
Per-module RFCs and status: `docs/rfc/README.md`. Live capability ledger:
`docs/strategy/coverage-matrix.md`.
80 changes: 80 additions & 0 deletions scripts/docs-freshness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,83 @@ if offences:
sys.exit(1)
print("── retired names: none of the retired tools are mentioned")
PY

# ── INVENTORY SYNC (#174): every public surface is NAMED where readers look for it, and
# every numeric claim about a surface matches reality. Same contract as the tests:
# "the docs are stale" is a RED state, never a silent one.
python3 - "$ROOT" <<'PY'
import os, re, sys
root = sys.argv[1]
fail = []
def read(*parts):
path = os.path.join(root, *parts)
return open(path, encoding="utf-8", errors="replace").read() if os.path.exists(path) else ""

# 1. Every package is on the live capability ledger.
ledger = read("docs", "strategy", "coverage-matrix.md")
packages = sorted(d for d in os.listdir(os.path.join(root, "packages"))
if d.startswith("Goldpath.") and os.path.isdir(os.path.join(root, "packages", d)))
# The matrix speaks capability SHORT names ("Idempotency"); providers ride their base
# capability's row ("Locking" covers Locking.SqlServer). Either spelling satisfies.
for package in packages:
short = package.removeprefix("Goldpath.")
base = short.split(".")[0]
if package not in ledger and short not in ledger and base not in ledger:
fail.append(f"package {package} missing from docs/strategy/coverage-matrix.md")

# 2. A doc that COUNTS packages must count them correctly (packages/README said 19 while
# 23 existed — found by this gate's first run).
readme = read("packages", "README.md")
for claim in re.findall(r"(\d+)\s+packages", readme):
if int(claim) != len(packages):
fail.append(f"packages/README.md claims {claim} packages; there are {len(packages)}")

# 3. Every CLI verb the dispatcher knows is in the CLI reference.
dispatch = read("tools", "Goldpath.Cli", "CliRunner.cs")
verbs = set()
for m in re.finditer(r'\["([a-z]+)"(?:, "([a-z]+)")?', dispatch):
verbs.add(m.group(1) if not m.group(2) else f"{m.group(1)} {m.group(2)}")
verbs -= {"new"} if "new " in " ".join(verbs) else set()
reference = read("docs", "guide", "cli-reference.md")
for verb in sorted(verbs):
if f"goldpath {verb}" not in reference:
fail.append(f"CLI verb 'goldpath {verb}' missing from docs/guide/cli-reference.md")

# 4. Every golden-manifest shape in the nightly matrix is in the golden-manifests doc.
nightly = read(".github", "workflows", "nightly.yml")
gm_doc = read("docs", "strategy", "golden-manifests-v1.md")
for shape in re.findall(r"- name: (Gm[A-Za-z.]+)", nightly):
if shape not in gm_doc:
fail.append(f"nightly shape {shape} missing from docs/strategy/golden-manifests-v1.md")

# 5. Every script is referenced SOMEWHERE a reader can find it.
corpus = ""
for scope in ["README.md", "CLAUDE.md"]:
corpus += read(scope)
for base, dirs, names in os.walk(os.path.join(root, "docs")):
for n in names:
if n.endswith(".md"):
corpus += read(os.path.relpath(os.path.join(base, n), root))
for n in os.listdir(os.path.join(root, ".github", "workflows")):
corpus += read(".github", "workflows", n)
corpus += "".join(read("scripts", n) for n in os.listdir(os.path.join(root, "scripts")))
for script in sorted(os.listdir(os.path.join(root, "scripts"))):
if script.endswith((".sh", ".py")) and script not in corpus.replace("docs-freshness.sh", script, 0):
others = corpus
if script not in others:
fail.append(f"scripts/{script} is referenced nowhere (README, CLAUDE.md, docs, workflows, other scripts)")

# 6. Every template is in templates/README.md.
templates_doc = read("templates", "README.md")
for template in sorted(d for d in os.listdir(os.path.join(root, "templates"))
if d.startswith("goldpath-") and os.path.isdir(os.path.join(root, "templates", d))):
if template not in templates_doc:
fail.append(f"template {template} missing from templates/README.md")

if fail:
print("── inventory sync: the docs stopped telling the truth:")
for f in fail:
print(f" {f}")
sys.exit(1)
print(f"── inventory sync: {len(packages)} packages, {len(verbs)} CLI verbs, nightly shapes, scripts and templates all documented")
PY
6 changes: 4 additions & 2 deletions templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
Golden-path templates. Current: `goldpath-solution` (GM-1 shape defaults: modular-monolith,
vertical-slice, PostgreSQL, RabbitMQ) — with `--layout clean-architecture` generating the
four-project split (Domain / Application / Infrastructure / Api; the packages anchor rides
Infrastructure, which also owns migrations). Further shapes arrive per the template RFC
phasing (`docs/rfc/goldpath-template.md`, decision D1).
Infrastructure, which also owns migrations). Also current: `goldpath-worker` — the
headless worker shape (queue / schedule / jobs triggers; probes instead of business
contracts, no OpenAPI artifact). Further shapes arrive per the template RFC phasing
(`docs/rfc/goldpath-template.md`, decision D1).

```
dotnet new install Goldpath.Templates
Expand Down
Loading