From 7ff96056f9b0cfd7fd7802f0dd2bac385f148f29 Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Thu, 26 Mar 2026 22:32:12 +0100 Subject: [PATCH 1/4] docs: URL contract, legacy /guides/ redirects, and docs-06 follow-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add authoritative reference/documentation-url-contract, design notes, §7 tasks, modules-docs-publishing spec updates, and redirect_from for guides whose canonical permalink is outside /guides/ so legacy modules /guides/ URLs keep working. Made-with: Cursor --- CHANGELOG.md | 6 ++ docs/_layouts/default.html | 1 + docs/guides/ai-ide-workflow.md | 2 + docs/guides/brownfield-engineer.md | 2 + docs/guides/brownfield-faq.md | 8 +++ docs/guides/brownfield-journey.md | 2 + docs/guides/brownfield-roi.md | 8 +++ docs/guides/common-tasks.md | 2 + docs/guides/competitive-analysis.md | 2 + docs/guides/contract-testing-workflow.md | 8 +++ docs/guides/copilot-mode.md | 2 + docs/guides/dual-stack-enrichment.md | 8 +++ docs/guides/integrations-overview.md | 8 +++ docs/guides/migration-0.16-to-0.19.md | 8 +++ docs/guides/migration-cli-reorganization.md | 8 +++ docs/guides/migration-guide.md | 2 + docs/guides/specmatic-integration.md | 8 +++ docs/guides/team-collaboration-workflow.md | 2 + docs/guides/testing-terminal-output.md | 2 + docs/guides/troubleshooting.md | 2 + docs/guides/use-cases.md | 2 + docs/guides/ux-features.md | 2 + docs/guides/workflows.md | 8 +++ docs/reference/README.md | 1 + docs/reference/documentation-url-contract.md | 56 +++++++++++++++++++ openspec/CHANGE_ORDER.md | 2 +- .../design.md | 18 ++++++ .../tasks.md | 8 +++ .../specs/modules-docs-publishing/spec.md | 15 +++++ 29 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 docs/reference/documentation-url-contract.md create mode 100644 openspec/changes/docs-06-modules-site-ia-restructure/design.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 177052a..2ba436a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this repository will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows SemVer for bundle versions. +## [Unreleased] + +### Added + +- Documentation: authoritative `docs/reference/documentation-url-contract.md` for core vs modules URL ownership; `redirect_from` aliases for legacy `/guides//` on pages whose canonical path is outside `/guides/`; sidebar link to the contract page. + ## [0.44.0] - 2026-03-17 ### Added diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 0b2d36c..172dbc0 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -222,6 +222,7 @@

Reference

    +
  • Core vs modules URL contract
  • Reference Documentation
  • Command Reference
  • Thorough Codebase Validation
  • diff --git a/docs/guides/ai-ide-workflow.md b/docs/guides/ai-ide-workflow.md index bae3bb0..07c3384 100644 --- a/docs/guides/ai-ide-workflow.md +++ b/docs/guides/ai-ide-workflow.md @@ -2,6 +2,8 @@ layout: default title: AI IDE Workflow Guide permalink: /ai-ide-workflow/ +redirect_from: + - /guides/ai-ide-workflow/ --- # Legacy Workflow Note diff --git a/docs/guides/brownfield-engineer.md b/docs/guides/brownfield-engineer.md index 85301b8..0eb6e88 100644 --- a/docs/guides/brownfield-engineer.md +++ b/docs/guides/brownfield-engineer.md @@ -2,6 +2,8 @@ layout: default title: Modernizing Legacy Code (Brownfield Engineer Guide) permalink: /brownfield-engineer/ +redirect_from: + - /guides/brownfield-engineer/ --- # Legacy Workflow Note diff --git a/docs/guides/brownfield-faq.md b/docs/guides/brownfield-faq.md index e0f57d5..09cb8d3 100644 --- a/docs/guides/brownfield-faq.md +++ b/docs/guides/brownfield-faq.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Brownfield Modernization FAQ +permalink: /brownfield-faq/ +redirect_from: + - /guides/brownfield-faq/ +--- + # Brownfield Modernization FAQ > **Frequently asked questions about using SpecFact CLI for legacy code modernization** diff --git a/docs/guides/brownfield-journey.md b/docs/guides/brownfield-journey.md index 37b13df..63d62b7 100644 --- a/docs/guides/brownfield-journey.md +++ b/docs/guides/brownfield-journey.md @@ -2,6 +2,8 @@ layout: default title: Brownfield Modernization Journey permalink: /brownfield-journey/ +redirect_from: + - /guides/brownfield-journey/ --- # Legacy Workflow Note diff --git a/docs/guides/brownfield-roi.md b/docs/guides/brownfield-roi.md index 70e2845..3e31f8e 100644 --- a/docs/guides/brownfield-roi.md +++ b/docs/guides/brownfield-roi.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Brownfield Modernization ROI with SpecFact +permalink: /brownfield-roi/ +redirect_from: + - /guides/brownfield-roi/ +--- + # Brownfield Modernization ROI with SpecFact > **Calculate your time and cost savings when modernizing legacy Python code** diff --git a/docs/guides/common-tasks.md b/docs/guides/common-tasks.md index 94b2f53..f3b17fd 100644 --- a/docs/guides/common-tasks.md +++ b/docs/guides/common-tasks.md @@ -2,6 +2,8 @@ layout: default title: Common Tasks Quick Reference permalink: /common-tasks/ +redirect_from: + - /guides/common-tasks/ --- # Legacy Workflow Note diff --git a/docs/guides/competitive-analysis.md b/docs/guides/competitive-analysis.md index a835f4f..eaf37b1 100644 --- a/docs/guides/competitive-analysis.md +++ b/docs/guides/competitive-analysis.md @@ -2,6 +2,8 @@ layout: default title: Competitive Analysis permalink: /competitive-analysis/ +redirect_from: + - /guides/competitive-analysis/ --- # Legacy Workflow Note diff --git a/docs/guides/contract-testing-workflow.md b/docs/guides/contract-testing-workflow.md index 951c313..2872fa4 100644 --- a/docs/guides/contract-testing-workflow.md +++ b/docs/guides/contract-testing-workflow.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Contract Testing Workflow +permalink: /contract-testing-workflow/ +redirect_from: + - /guides/contract-testing-workflow/ +--- + # Legacy Workflow Note This page described older `specfact plan`, `specfact generate`, `specfact contract`, or `specfact sdd constitution` workflows that are not part of the current public mounted CLI in this repository. The detailed command examples previously documented here were removed because they no longer match the command surface exposed by `specfact --help`. diff --git a/docs/guides/copilot-mode.md b/docs/guides/copilot-mode.md index 14d17de..02c6b99 100644 --- a/docs/guides/copilot-mode.md +++ b/docs/guides/copilot-mode.md @@ -2,6 +2,8 @@ layout: default title: Using CoPilot Mode permalink: /copilot-mode/ +redirect_from: + - /guides/copilot-mode/ --- # Legacy Workflow Note diff --git a/docs/guides/dual-stack-enrichment.md b/docs/guides/dual-stack-enrichment.md index 951c313..61c60d4 100644 --- a/docs/guides/dual-stack-enrichment.md +++ b/docs/guides/dual-stack-enrichment.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Dual-Stack Enrichment +permalink: /dual-stack-enrichment/ +redirect_from: + - /guides/dual-stack-enrichment/ +--- + # Legacy Workflow Note This page described older `specfact plan`, `specfact generate`, `specfact contract`, or `specfact sdd constitution` workflows that are not part of the current public mounted CLI in this repository. The detailed command examples previously documented here were removed because they no longer match the command surface exposed by `specfact --help`. diff --git a/docs/guides/integrations-overview.md b/docs/guides/integrations-overview.md index 4dad320..c219397 100644 --- a/docs/guides/integrations-overview.md +++ b/docs/guides/integrations-overview.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Integrations Overview +permalink: /integrations-overview/ +redirect_from: + - /guides/integrations-overview/ +--- + # Integrations Overview > **Comprehensive guide to all SpecFact CLI integrations** diff --git a/docs/guides/migration-0.16-to-0.19.md b/docs/guides/migration-0.16-to-0.19.md index ee01927..c131a91 100644 --- a/docs/guides/migration-0.16-to-0.19.md +++ b/docs/guides/migration-0.16-to-0.19.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Migration 0.16 to 0.19 +permalink: /migration-0.16-to-0.19/ +redirect_from: + - /guides/migration-0.16-to-0.19/ +--- + # Legacy Workflow Note This page referenced command groups or workflow steps that are no longer part of the current public mounted CLI in this repository. The old examples were removed to avoid directing readers to unavailable commands. diff --git a/docs/guides/migration-cli-reorganization.md b/docs/guides/migration-cli-reorganization.md index 951c313..4190d4c 100644 --- a/docs/guides/migration-cli-reorganization.md +++ b/docs/guides/migration-cli-reorganization.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Migration CLI Reorganization +permalink: /migration-cli-reorganization/ +redirect_from: + - /guides/migration-cli-reorganization/ +--- + # Legacy Workflow Note This page described older `specfact plan`, `specfact generate`, `specfact contract`, or `specfact sdd constitution` workflows that are not part of the current public mounted CLI in this repository. The detailed command examples previously documented here were removed because they no longer match the command surface exposed by `specfact --help`. diff --git a/docs/guides/migration-guide.md b/docs/guides/migration-guide.md index a7775af..05d579a 100644 --- a/docs/guides/migration-guide.md +++ b/docs/guides/migration-guide.md @@ -2,6 +2,8 @@ layout: default title: Migration Guide permalink: /migration-guide/ +redirect_from: + - /guides/migration-guide/ --- # Legacy Workflow Note diff --git a/docs/guides/specmatic-integration.md b/docs/guides/specmatic-integration.md index ee01927..7b75f96 100644 --- a/docs/guides/specmatic-integration.md +++ b/docs/guides/specmatic-integration.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Specmatic Integration +permalink: /specmatic-integration/ +redirect_from: + - /guides/specmatic-integration/ +--- + # Legacy Workflow Note This page referenced command groups or workflow steps that are no longer part of the current public mounted CLI in this repository. The old examples were removed to avoid directing readers to unavailable commands. diff --git a/docs/guides/team-collaboration-workflow.md b/docs/guides/team-collaboration-workflow.md index 91a7847..a9eaa90 100644 --- a/docs/guides/team-collaboration-workflow.md +++ b/docs/guides/team-collaboration-workflow.md @@ -2,6 +2,8 @@ layout: default title: Team Collaboration Workflow permalink: /team-collaboration-workflow/ +redirect_from: + - /guides/team-collaboration-workflow/ --- # Team Collaboration Workflow diff --git a/docs/guides/testing-terminal-output.md b/docs/guides/testing-terminal-output.md index 21b7bfd..ba22b8c 100644 --- a/docs/guides/testing-terminal-output.md +++ b/docs/guides/testing-terminal-output.md @@ -2,6 +2,8 @@ layout: default title: Testing Terminal Output Modes permalink: /testing-terminal-output/ +redirect_from: + - /guides/testing-terminal-output/ --- # Testing Terminal Output Modes diff --git a/docs/guides/troubleshooting.md b/docs/guides/troubleshooting.md index ca3d61c..dc7ecb2 100644 --- a/docs/guides/troubleshooting.md +++ b/docs/guides/troubleshooting.md @@ -2,6 +2,8 @@ layout: default title: Troubleshooting permalink: /troubleshooting/ +redirect_from: + - /guides/troubleshooting/ --- # Legacy Workflow Note diff --git a/docs/guides/use-cases.md b/docs/guides/use-cases.md index 2876175..2d5daf2 100644 --- a/docs/guides/use-cases.md +++ b/docs/guides/use-cases.md @@ -2,6 +2,8 @@ layout: default title: Use Cases permalink: /use-cases/ +redirect_from: + - /guides/use-cases/ --- # Legacy Workflow Note diff --git a/docs/guides/ux-features.md b/docs/guides/ux-features.md index e4d1270..66a3cc3 100644 --- a/docs/guides/ux-features.md +++ b/docs/guides/ux-features.md @@ -2,6 +2,8 @@ layout: default title: UX Features Guide permalink: /ux-features/ +redirect_from: + - /guides/ux-features/ --- # Legacy Workflow Note diff --git a/docs/guides/workflows.md b/docs/guides/workflows.md index 951c313..4864780 100644 --- a/docs/guides/workflows.md +++ b/docs/guides/workflows.md @@ -1,3 +1,11 @@ +--- +layout: default +title: Workflows (legacy note) +permalink: /workflows/ +redirect_from: + - /guides/workflows/ +--- + # Legacy Workflow Note This page described older `specfact plan`, `specfact generate`, `specfact contract`, or `specfact sdd constitution` workflows that are not part of the current public mounted CLI in this repository. The detailed command examples previously documented here were removed because they no longer match the command surface exposed by `specfact --help`. diff --git a/docs/reference/README.md b/docs/reference/README.md index 66907c3..6ae8e72 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -10,6 +10,7 @@ Complete technical reference for the official modules site and bundle-owned work ## Available References +- **[Core and modules docs URL contract](documentation-url-contract.md)** - Ownership and permalink rules vs `docs.specfact.io` - **[Commands](commands.md)** - Complete command reference with all options - **[Thorough Codebase Validation](thorough-codebase-validation.md)** - Quick check, contract-decorated, sidecar, and dogfooding - **[Command Syntax Policy](command-syntax-policy.md)** - Source-of-truth argument syntax conventions for docs diff --git a/docs/reference/documentation-url-contract.md b/docs/reference/documentation-url-contract.md new file mode 100644 index 0000000..ceb10e3 --- /dev/null +++ b/docs/reference/documentation-url-contract.md @@ -0,0 +1,56 @@ +--- +layout: default +title: Core and modules docs URL contract +permalink: /reference/documentation-url-contract/ +description: Ownership boundaries and published URL rules between docs.specfact.io and modules.specfact.io. +--- + +# Core and modules documentation URL contract + +This page is the **authoritative** reference for how published URLs work across the two public documentation sites. **Contributors must read this before adding cross-site links or changing `permalink` / `redirect_from` metadata.** + +## Sites and repositories + +| Site | Repository | Published URL | +| --- | --- | --- | +| Core CLI docs | `nold-ai/specfact-cli` (`docs/`) | `https://docs.specfact.io/` | +| Modules docs | `nold-ai/specfact-cli-modules` (`docs/`) | `https://modules.specfact.io/` | + +## Ownership (what lives where) + +- **Core (`specfact-cli`)** owns: lean-core CLI topology, installation/upgrade, registry and marketplace *as a platform*, architecture of the runtime, debug/modes, authentication *as used by core*, migration topics that are release-line wide, and **handoff pages** that summarize bundle workflows while pointing to modules for depth. +- **Modules (`specfact-cli-modules`)** owns: official bundle deep guides, adapter runbooks, module authoring, bundle-specific command examples, and the **canonical** URL for any migrated guide that previously lived only under core `docs/guides/`. + +Do not assume the **same path** on both sites points to the same page. Path shape differs after IA restructures (for example bundle paths under `/bundles/.../` on modules). + +## Modules permalink rules (this site) + +1. **Default** (`docs/_config.yml`): pages default to `permalink: /:basename/` (filename stem at site root), unless overridden. +2. **Explicit `permalink`** in front matter always wins. Many guides use `permalink: /guides//` so the published URL stays under `/guides/`. +3. **Bundle and integration moves** (OpenSpec change `docs-06-modules-site-ia-restructure`): canonical URLs live under `/bundles/.../`, `/integrations/.../`, `/authoring/.../`, etc. Each moved page **must** include `redirect_from` for the **previous** modules URL (typically `/guides//`). +4. **Legacy `/guides//` aliases**: If a page’s canonical URL is **not** under `/guides/` (for example `/brownfield-engineer/` or `/contract-testing-workflow/`), the page **must** include: + + ```yaml + redirect_from: + - /guides// + ``` + + so bookmarks and older links keep working. + +5. **Core handoff links**: When `specfact-cli` links to this site, authors **must** use the **actual** `permalink` (or the default-derived path) for the target page—**not** mirror core’s `/guides/...` path unless this site’s target also uses `/guides/...`. + +## Core site obligations (`specfact-cli`) + +- Internal links on `docs.specfact.io` must match **core** published routes (see `tests/unit/docs/test_release_docs_parity.py` and docs review gate). +- Any `https://modules.specfact.io/...` link in core docs must target a **real** modules path. When in doubt, open the target file in `specfact-cli-modules` and copy its `permalink` (or infer `//` from defaults). +- Prefer linking to **`/reference/documentation-url-contract/`** on this site from core’s [Documentation URL contract](https://docs.specfact.io/reference/documentation-url-contract/) page for the full table mindset; keep core’s page as a short summary so the contract does not drift. + +## Related OpenSpec changes + +- **Modules**: `docs-06-modules-site-ia-restructure` — IA, moves, redirects for moved pages. +- **Core**: `docs-07-core-handoff-conversion` — thin handoff pages on core with canonical links to modules. + +## Change process + +- **URL or redirect changes** on this site: update front matter, run `bundle exec jekyll build` locally, and ensure `redirect_from` covers prior public URLs. +- **Cross-repo**: if a canonical target moves again, update both repos in the same release window when possible, and extend `redirect_from` on modules before updating core links. diff --git a/openspec/CHANGE_ORDER.md b/openspec/CHANGE_ORDER.md index 2eb988e..796d9f5 100644 --- a/openspec/CHANGE_ORDER.md +++ b/openspec/CHANGE_ORDER.md @@ -54,7 +54,7 @@ Cross-repo dependency: `docs-06-modules-site-ia-restructure` is a prerequisite f | Module | Order | Change folder | GitHub # | Blocked by | |--------|-------|---------------|----------|------------| -| docs | 06 | docs-06-modules-site-ia-restructure | [#95](https://github.com/nold-ai/specfact-cli-modules/issues/95) | docs-01 ✅; docs-cli-command-alignment ✅ | **in-progress** | +| docs | 06 | docs-06-modules-site-ia-restructure | [#95](https://github.com/nold-ai/specfact-cli-modules/issues/95) | docs-01 ✅; docs-cli-command-alignment ✅ | ✅ implemented (pending archive; §7 URL contract) | | docs | 08 | docs-08-bundle-overview-pages | [#96](https://github.com/nold-ai/specfact-cli-modules/issues/96) | docs-06-modules-site-ia-restructure | | docs | 09 | docs-09-missing-command-docs | [#97](https://github.com/nold-ai/specfact-cli-modules/issues/97) | docs-06-modules-site-ia-restructure | | docs | 10 | docs-10-workflow-consolidation | [#98](https://github.com/nold-ai/specfact-cli-modules/issues/98) | docs-06-modules-site-ia-restructure | diff --git a/openspec/changes/docs-06-modules-site-ia-restructure/design.md b/openspec/changes/docs-06-modules-site-ia-restructure/design.md new file mode 100644 index 0000000..5d664fb --- /dev/null +++ b/openspec/changes/docs-06-modules-site-ia-restructure/design.md @@ -0,0 +1,18 @@ +# Design: Modules docs IA restructure — URL policy + +## Context + +Jekyll defaults in `docs/_config.yml` set `permalink: /:basename/` for pages unless front matter overrides. Guides may therefore publish at `/guides//` **or** at root `//` depending on explicit `permalink`. After moving bundle content to `bundles/` and `integrations/`, **canonical** URLs changed; `redirect_from` preserves old `/guides/...` modules URLs. + +Core docs (`docs.specfact.io`) often use `/guides//` for handoff pages. **Modules paths are not guaranteed to mirror core**; authors must use each page’s real `permalink` on the modules site. + +## Decisions + +1. **Authoritative contract page**: `docs/reference/documentation-url-contract.md` on the modules site is the single source of truth for cross-site URL rules. Core docs link to it from a short summary page. +2. **Legacy `/guides/` on modules**: For any guide whose canonical URL is not under `/guides/`, add `redirect_from: /guides//` so older links keep working. +3. **Status tracking**: `openspec/CHANGE_ORDER.md` reflects lifecycle; completed IA work is paired with redirect hygiene tasks in the same change folder until archive. + +## Non-goals + +- Unifying all modules URLs under `/guides/` (would break bundle-first IA). +- Building combined Jekyll sites in CI for every PR (see docs-12 on core for cross-site HTTP checks). diff --git a/openspec/changes/docs-06-modules-site-ia-restructure/tasks.md b/openspec/changes/docs-06-modules-site-ia-restructure/tasks.md index 41e0403..9d5d350 100644 --- a/openspec/changes/docs-06-modules-site-ia-restructure/tasks.md +++ b/openspec/changes/docs-06-modules-site-ia-restructure/tasks.md @@ -42,3 +42,11 @@ - [x] 6.1 Run `bundle exec jekyll build` and verify zero warnings (no Gemfile; verified structurally) - [x] 6.2 Verify all sidebar links resolve correctly - [x] 6.3 Verify redirect entries preserve old URLs + +## 7. Cross-site URL contract and legacy `/guides/` aliases (follow-up) + +- [x] 7.1 Add `docs/reference/documentation-url-contract.md` (authoritative rules vs `docs.specfact.io`) +- [x] 7.2 Document URL policy in `openspec/changes/docs-06-modules-site-ia-restructure/design.md` +- [x] 7.3 Extend `openspec/specs/modules-docs-publishing/spec.md` with permalink and redirect requirements +- [x] 7.4 Add `redirect_from: /guides//` for guides whose canonical permalink is outside `/guides/` (brownfield, team collaboration, stubs, and similar) +- [x] 7.5 Link the contract from `docs/_layouts/default.html` and `docs/reference/README.md` diff --git a/openspec/specs/modules-docs-publishing/spec.md b/openspec/specs/modules-docs-publishing/spec.md index 0dcf662..808c1d3 100644 --- a/openspec/specs/modules-docs-publishing/spec.md +++ b/openspec/specs/modules-docs-publishing/spec.md @@ -34,3 +34,18 @@ The modules documentation site SHALL support independent publishing and deployme - **THEN** the modules docs build and publication workflow can ship the change without rebuilding the core docs site - **AND** the site metadata and navigation remain valid for the public docs topology. +### Requirement: Published URL contract is documented and redirects preserve legacy paths + +The modules documentation site SHALL maintain a published reference page that explains ownership boundaries and permalink rules relative to `docs.specfact.io`, and SHALL use `redirect_from` so that prior public URLs under `/guides//` continue to resolve when the canonical permalink moves to a non-`/guides/` path or to bundle/integration paths. + +#### Scenario: Contributor looks up cross-site linking rules + +- **WHEN** a contributor needs to link from core docs to modules docs or change a `permalink` +- **THEN** the reference page at `/reference/documentation-url-contract/` on `modules.specfact.io` describes repository ownership, default permalink behavior, and redirect expectations +- **AND** pages that publish outside `/guides//` include `redirect_from` for `/guides//` when that path could have been used historically + +#### Scenario: IA-moved guide keeps old URL working + +- **WHEN** a guide is moved under `bundles/`, `integrations/`, or `authoring/` with a new canonical `permalink` +- **THEN** the page includes `jekyll-redirect-from` entries for the previous modules URL (as required by the IA restructure change) + From 55733583d57c6ca0d6588ead3a74a9efecb986ab Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Thu, 26 Mar 2026 22:42:30 +0100 Subject: [PATCH 2/4] docs: handoff URL table, fix architecture link on modules index - Document canonical modules.specfact.io paths for docs-07-core-handoff-conversion - Clarify mixed permalink styles (guides vs site root vs bundles) - Fix docs index Architecture link to /architecture/ - Point README and reference index at the contract for maintainers Made-with: Cursor --- README.md | 1 + docs/index.md | 2 +- docs/reference/README.md | 2 +- docs/reference/documentation-url-contract.md | 22 +++++++++++++++++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9e0ae5f..fbf5ae8 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ This repository hosts official nold-ai bundles only. - Official bundles are maintained under `packages/`. - Third-party bundles are published from third-party repositories and are not hosted here. - Bundle and module documentation changes are made in this repository under `docs/`. +- Cross-site linking rules and canonical paths for core→modules handoffs: `docs/reference/documentation-url-contract.md` (published: `https://modules.specfact.io/reference/documentation-url-contract/`). - GitHub Pages documentation target: `https://nold-ai.github.io/specfact-cli-modules/`. ## Local development (IDE / Cursor) diff --git a/docs/index.md b/docs/index.md index 4fae584..b04f9a9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -47,4 +47,4 @@ The modules site owns all bundle-specific deep guidance. Core CLI platform docs - [Command Reference](reference/commands/) - [Module Contracts](reference/module-contracts/) - [Module Security](reference/module-security/) -- [Architecture](reference/architecture/) +- [Architecture](architecture/) diff --git a/docs/reference/README.md b/docs/reference/README.md index 6ae8e72..f0d3ac0 100644 --- a/docs/reference/README.md +++ b/docs/reference/README.md @@ -10,7 +10,7 @@ Complete technical reference for the official modules site and bundle-owned work ## Available References -- **[Core and modules docs URL contract](documentation-url-contract.md)** - Ownership and permalink rules vs `docs.specfact.io` +- **[Core and modules docs URL contract](documentation-url-contract.md)** - Ownership, permalink rules vs `docs.specfact.io`, and the **canonical handoff URL table** for core thin pages linking here (see *Canonical handoff targets* on that page) - **[Commands](commands.md)** - Complete command reference with all options - **[Thorough Codebase Validation](thorough-codebase-validation.md)** - Quick check, contract-decorated, sidecar, and dogfooding - **[Command Syntax Policy](command-syntax-policy.md)** - Source-of-truth argument syntax conventions for docs diff --git a/docs/reference/documentation-url-contract.md b/docs/reference/documentation-url-contract.md index ceb10e3..eba38f6 100644 --- a/docs/reference/documentation-url-contract.md +++ b/docs/reference/documentation-url-contract.md @@ -26,7 +26,7 @@ Do not assume the **same path** on both sites points to the same page. Path shap ## Modules permalink rules (this site) 1. **Default** (`docs/_config.yml`): pages default to `permalink: /:basename/` (filename stem at site root), unless overridden. -2. **Explicit `permalink`** in front matter always wins. Many guides use `permalink: /guides//` so the published URL stays under `/guides/`. +2. **Explicit `permalink`** in front matter always wins. Guides are **mixed**: some use `permalink: /guides//`, many use **site-root** paths such as `//` (from the default or an explicit override), and bundle or integration content uses `/bundles/.../`, `/integrations/.../`, `/authoring/.../`, and so on. **Never infer** the live URL from the on-disk path alone—read `permalink` (or the default rule) for each file. 3. **Bundle and integration moves** (OpenSpec change `docs-06-modules-site-ia-restructure`): canonical URLs live under `/bundles/.../`, `/integrations/.../`, `/authoring/.../`, etc. Each moved page **must** include `redirect_from` for the **previous** modules URL (typically `/guides//`). 4. **Legacy `/guides//` aliases**: If a page’s canonical URL is **not** under `/guides/` (for example `/brownfield-engineer/` or `/contract-testing-workflow/`), the page **must** include: @@ -39,6 +39,26 @@ Do not assume the **same path** on both sites points to the same page. Path shap 5. **Core handoff links**: When `specfact-cli` links to this site, authors **must** use the **actual** `permalink` (or the default-derived path) for the target page—**not** mirror core’s `/guides/...` path unless this site’s target also uses `/guides/...`. +### Canonical handoff targets (core → modules) + +Use these **published** paths when authoring thin handoff pages on core (`docs-07-core-handoff-conversion`). Replace `https://modules.specfact.io` with `relative_url` or repo-relative links as appropriate. + +| Topic | Canonical URL | `redirect_from` (bookmarks; optional) | +| --- | --- | --- | +| This URL contract | `https://modules.specfact.io/reference/documentation-url-contract/` | — | +| Backlog bundle overview | `https://modules.specfact.io/bundles/backlog/overview/` | — | +| Project bundle overview | `https://modules.specfact.io/bundles/project/overview/` | — | +| Codebase bundle overview | `https://modules.specfact.io/bundles/codebase/overview/` | — | +| Spec bundle overview | `https://modules.specfact.io/bundles/spec/overview/` | — | +| Govern bundle overview | `https://modules.specfact.io/bundles/govern/overview/` | — | +| Code Review bundle overview | `https://modules.specfact.io/bundles/code-review/overview/` | — | +| DevOps adapter (integrations) | `https://modules.specfact.io/integrations/devops-adapter-overview/` | `/guides/devops-adapter-integration/` | +| Brownfield engineer | `https://modules.specfact.io/brownfield-engineer/` | `/guides/brownfield-engineer/` | +| Contract testing workflow | `https://modules.specfact.io/contract-testing-workflow/` | `/guides/contract-testing-workflow/` | +| Brownfield journey | `https://modules.specfact.io/brownfield-journey/` | `/guides/brownfield-journey/` | + +**Reference pages** are not all under `/reference/`: for example [Architecture](https://modules.specfact.io/architecture/) and [Operational modes](https://modules.specfact.io/modes/) live at the site root. Always copy the target file’s `permalink` when building `https://modules.specfact.io/...` links. + ## Core site obligations (`specfact-cli`) - Internal links on `docs.specfact.io` must match **core** published routes (see `tests/unit/docs/test_release_docs_parity.py` and docs review gate). From d33c606f33abb07b3f6c0925fab45db00a1b423f Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Thu, 26 Mar 2026 22:51:27 +0100 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20CHANGE=5FORDER=20table=20column;=20t?= =?UTF-8?q?est=20guides=20legacy=20redirect=5Ffrom=20(docs-06=20=C2=A77.4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Merge docs-06 status into Blocked by column (five columns) - Add _list_redirect_from_routes and _guides_legacy_redirect_violation helpers - Enforce /guides// redirect for guides/*.md when canonical not under /guides/ - Add passing/failing unit examples plus repo-wide assertion Made-with: Cursor --- openspec/CHANGE_ORDER.md | 2 +- tests/unit/docs/test_docs_review.py | 101 ++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/openspec/CHANGE_ORDER.md b/openspec/CHANGE_ORDER.md index 796d9f5..66a8ae2 100644 --- a/openspec/CHANGE_ORDER.md +++ b/openspec/CHANGE_ORDER.md @@ -54,7 +54,7 @@ Cross-repo dependency: `docs-06-modules-site-ia-restructure` is a prerequisite f | Module | Order | Change folder | GitHub # | Blocked by | |--------|-------|---------------|----------|------------| -| docs | 06 | docs-06-modules-site-ia-restructure | [#95](https://github.com/nold-ai/specfact-cli-modules/issues/95) | docs-01 ✅; docs-cli-command-alignment ✅ | ✅ implemented (pending archive; §7 URL contract) | +| docs | 06 | docs-06-modules-site-ia-restructure | [#95](https://github.com/nold-ai/specfact-cli-modules/issues/95) | docs-01 ✅; docs-cli-command-alignment ✅ — implemented, pending archive (§7 URL contract) | | docs | 08 | docs-08-bundle-overview-pages | [#96](https://github.com/nold-ai/specfact-cli-modules/issues/96) | docs-06-modules-site-ia-restructure | | docs | 09 | docs-09-missing-command-docs | [#97](https://github.com/nold-ai/specfact-cli-modules/issues/97) | docs-06-modules-site-ia-restructure | | docs | 10 | docs-10-workflow-consolidation | [#98](https://github.com/nold-ai/specfact-cli-modules/issues/98) | docs-06-modules-site-ia-restructure | diff --git a/tests/unit/docs/test_docs_review.py b/tests/unit/docs/test_docs_review.py index d0977bd..6175752 100644 --- a/tests/unit/docs/test_docs_review.py +++ b/tests/unit/docs/test_docs_review.py @@ -371,6 +371,75 @@ def test_config_links_to_core_docs_site() -> None: # --------------------------------------------------------------------------- +def _list_redirect_from_routes(text: str) -> list[str]: + """Return normalized routes declared under ``redirect_from:`` in front matter.""" + routes: list[str] = [] + lines = text.splitlines() + i = 0 + while i < len(lines): + if lines[i].strip() == "redirect_from:": + i += 1 + while i < len(lines): + stripped = lines[i].strip() + if stripped.startswith("- "): + val = stripped[2:].strip().strip('"').strip("'") + routes.append(_normalize_route(val)) + i += 1 + elif not stripped or stripped.startswith("#"): + i += 1 + elif stripped == "---": + break + else: + break + break + i += 1 + return routes + + +def _guides_legacy_redirect_violation(path: Path, text: str) -> str | None: + """If ``docs/guides/.md`` publishes outside ``/guides/``, require ``redirect_from`` for ``/guides//``. + + Returns a human-readable violation message, or ``None`` when the rule is satisfied. + """ + try: + rel = path.relative_to(_docs_root()) + except ValueError: + return None + if len(rel.parts) < 2 or rel.parts[0] != "guides" or rel.suffix != ".md": + return None + if rel.name == "README.md": + return None + + metadata, _ = _split_front_matter(text) + canonical = _published_route_for_path(path, metadata) + if canonical.startswith("/guides/"): + return None + + expected = _normalize_route(f"/guides/{path.stem}/") + redirects = _list_redirect_from_routes(text) + if expected in redirects: + return None + return ( + f"{path}: canonical {canonical} is outside /guides/ but redirect_from " + f"does not include legacy alias {expected} (got {redirects})" + ) + + +def _iter_guides_legacy_redirect_violations() -> list[str]: + guides = _docs_root() / "guides" + if not guides.is_dir(): + return [] + violations: list[str] = [] + for path in sorted(guides.glob("*.md")): + if path.name == "README.md": + continue + text = _read_text(path) + msg = _guides_legacy_redirect_violation(path.resolve(), text) + if msg: + violations.append(msg) + return violations + + def _extract_redirect_from_entries() -> dict[str, Path]: """Build map of redirect_from routes to the file that declares them.""" redirects: dict[str, Path] = {} @@ -419,6 +488,38 @@ def test_moved_files_have_redirect_from_entries() -> None: assert not missing, "Moved files missing redirect_from entries:\n" + "\n".join(missing) +def test_guides_canonical_outside_guides_prefix_includes_legacy_redirect_alias() -> None: + """docs-06 §7.4: ``docs/guides/*.md`` whose canonical permalink is not under ``/guides/`` must list ``/guides//`` in ``redirect_from``.""" + violations = _iter_guides_legacy_redirect_violations() + assert not violations, "Guides legacy redirect alias missing:\n" + "\n".join(violations) + + +def test_guides_legacy_redirect_rule_passing_example() -> None: + path = _docs_root() / "guides" / "example-pass.md" + text = """--- +layout: default +title: Example +permalink: /example-pass/ +redirect_from: + - /guides/example-pass/ +--- +""" + assert _guides_legacy_redirect_violation(path.resolve(), text) is None + + +def test_guides_legacy_redirect_rule_failing_example() -> None: + path = _docs_root() / "guides" / "example-fail.md" + text = """--- +layout: default +title: Example +permalink: /example-fail/ +--- +""" + msg = _guides_legacy_redirect_violation(path.resolve(), text) + assert msg is not None + assert "/guides/example-fail/" in msg + + # --------------------------------------------------------------------------- # Config plugin alignment # --------------------------------------------------------------------------- From 50811ad7569c5c1b879ac951c346d3da01958a69 Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Thu, 26 Mar 2026 23:07:34 +0100 Subject: [PATCH 4/4] Fix pre-validation gates --- tests/unit/docs/test_docs_review.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/docs/test_docs_review.py b/tests/unit/docs/test_docs_review.py index 6175752..d8c9675 100644 --- a/tests/unit/docs/test_docs_review.py +++ b/tests/unit/docs/test_docs_review.py @@ -489,7 +489,10 @@ def test_moved_files_have_redirect_from_entries() -> None: def test_guides_canonical_outside_guides_prefix_includes_legacy_redirect_alias() -> None: - """docs-06 §7.4: ``docs/guides/*.md`` whose canonical permalink is not under ``/guides/`` must list ``/guides//`` in ``redirect_from``.""" + """docs-06 §7.4: require ``/guides//`` in ``redirect_from`` for guides with non-/guides/ canonical URLs. + + Applies to ``docs/guides/*.md`` whose canonical permalink is not under ``/guides/``. + """ violations = _iter_guides_legacy_redirect_violations() assert not violations, "Guides legacy redirect alias missing:\n" + "\n".join(violations)