From d5e65b654f8f1bf045a9251961fd444b3002be45 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 11 Jul 2026 21:36:00 -0600 Subject: [PATCH 01/16] chore(trust): adopt Trust 1 and SpecSync 5 --- .augur.toml | 3 + .codex/skills/spec-sync/SKILL.md | 75 ++++++++ .cursor/commands/specsync-create-change.md | 9 + .cursor/commands/specsync-create-spec.md | 35 ++++ .cursor/skills/spec-sync/SKILL.md | 75 ++++++++ .gemini/commands/specsync/create-change.toml | 11 ++ .gemini/commands/specsync/create-spec.toml | 35 ++++ .gemini/skills/spec-sync/SKILL.md | 75 ++++++++ .github/workflows/trust.yml | 38 +--- .specsync/adoption-report.json | 25 +++ .specsync/change.lock | 0 .../approvals.json | 11 ++ .../change.md | 26 +++ .../context.md | 14 ++ .../design.md | 14 ++ .../docs.md | 11 ++ .../plan.md | 12 ++ .../research.md | 14 ++ .../state.json | 41 +++++ .../tasks.md | 13 ++ .../testing.md | 12 ++ .../approvals.json | 11 ++ .../change.md | 24 +++ .../context.md | 10 ++ .../docs.md | 10 ++ .../state.json | 30 ++++ .specsync/config.toml | 2 +- .specsync/sdd.json | 40 +++++ .specsync/version | 2 +- .trust.toml | 22 +++ AGENTS.md | 14 +- specs/ThreeMD/requirements.md | 162 +++++++++++++++++ specs/ThreeMDCLI/requirements.md | 82 +++++++++ specs/ThreeMDElement/requirements.md | 170 ++++++++++++++++++ 34 files changed, 1085 insertions(+), 43 deletions(-) create mode 100644 .augur.toml create mode 100644 .codex/skills/spec-sync/SKILL.md create mode 100644 .cursor/commands/specsync-create-change.md create mode 100644 .cursor/commands/specsync-create-spec.md create mode 100644 .cursor/skills/spec-sync/SKILL.md create mode 100644 .gemini/commands/specsync/create-change.toml create mode 100644 .gemini/commands/specsync/create-spec.toml create mode 100644 .gemini/skills/spec-sync/SKILL.md create mode 100644 .specsync/adoption-report.json create mode 100644 .specsync/change.lock create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/context.md create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/design.md create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/docs.md create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/plan.md create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/research.md create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/testing.md create mode 100644 .specsync/changes/CHG-0002-assign-stable-requirement-ids/approvals.json create mode 100644 .specsync/changes/CHG-0002-assign-stable-requirement-ids/change.md create mode 100644 .specsync/changes/CHG-0002-assign-stable-requirement-ids/context.md create mode 100644 .specsync/changes/CHG-0002-assign-stable-requirement-ids/docs.md create mode 100644 .specsync/changes/CHG-0002-assign-stable-requirement-ids/state.json create mode 100644 .specsync/sdd.json create mode 100644 .trust.toml diff --git a/.augur.toml b/.augur.toml new file mode 100644 index 0000000..031b459 --- /dev/null +++ b/.augur.toml @@ -0,0 +1,3 @@ +[thresholds] +review = 35 +block = 65 diff --git a/.codex/skills/spec-sync/SKILL.md b/.codex/skills/spec-sync/SKILL.md new file mode 100644 index 0000000..de24d12 --- /dev/null +++ b/.codex/skills/spec-sync/SKILL.md @@ -0,0 +1,75 @@ +--- +name: spec-sync +description: Keep markdown module specs in specs// synchronized with source code using spec-sync. Use this whenever creating, editing, or reviewing code in a module that has (or should have) a spec, or whenever the user mentions specs, spec-sync, companion files (tasks.md/requirements.md/context.md/testing.md/design.md), or asks to add/update a module's documentation. +--- + +# Spec-Sync Workflow + +This project uses [spec-sync](https://github.com/CorvidLabs/spec-sync) for bidirectional spec-to-code validation. Specs live in `specs//.spec.md`. + +## Companion files + +## Verified SDD change lifecycle (5.0) + +For every meaningful source, test, public documentation, schema, or configuration change: + +1. Run `specsync change new "" --json` and conduct the returned interview with the user. +2. Use `specsync change answer --json` until no questions remain. +3. Complete the adaptively selected artifacts and semantic deltas. Requirements use stable + `REQ--` IDs, a normative SHALL statement, and acceptance criteria. +4. Ask the user for the definition approval, then run `specsync change approve `. +5. Run `specsync change start ` before editing implementation code. +6. Keep tasks and artifacts current, then run `specsync change verify `. +7. Present verification evidence and ask for closing approval. Only after explicit approval, + run `specsync change accept `; archive separately with `specsync change archive `. + +Never invent or self-grant either human approval. If an approved definition changes, its digest +becomes stale and must be approved again. `specsync check` validates canonical specs plus approved +active deltas, requirement-to-test evidence, change coverage, and CI gates. + +Each canonical spec may have policy-selected companion files. Read and update the ones present; do not create empty companions only for ceremony: + +- **`tasks.md`** — Work items for this module. Check off tasks (`- [x]`) as you complete them. Add new tasks if you discover work needed. +- **`requirements.md`** — Acceptance criteria and user stories. These are permanent invariants, not tasks — do not check them off. Update if requirements change. +- **`context.md`** — Architectural decisions, key files, and current status. Update when you make design decisions or change what's in progress. +- **`testing.md`** — Test strategy: automated test locations, manual QA checklists, and edge cases/boundary conditions. +- **`design.md`** *(opt-in)* — Layout, component hierarchy, design tokens, and asset references. Present when `companions.design` is enabled in config. + +## Before modifying any module + +1. Read the relevant spec in `specs//.spec.md` +2. Read whichever companion files are present (`requirements.md`, `tasks.md`, `context.md`, `testing.md`, `design.md`, or project-defined files) +3. After changes, run `specsync check` to verify specs still pass + +## After completing work + +1. Mark completed items in `tasks.md` — check off finished tasks, add new ones discovered +2. Update `context.md` — record decisions made, update current status +3. If requirements changed, update `requirements.md` acceptance criteria +4. If test coverage changed, update `testing.md` with new test files or edge cases +5. If UI/layout changed, update `design.md` with revised layout, components, or tokens + +## Before creating a PR + +Run `specsync check --strict` — all specs must pass with zero warnings. + +## When adding new modules + +Run `specsync scaffold ` to create a spec, companion files, a registry +entry, and auto-detected source files — or `specsync new ` for a +minimal spec-only draft. Complete the spec before writing code. The +`/specsync:create-spec` command (or tool-equivalent) runs this for you, and +accepts either a bare module name or a natural-language feature description +(e.g. `/specsync:create-spec "I want a feature that lets users export their +data as CSV"`) — pass a description and it will pick a module name and use +the description to draft the spec's Purpose and Requirements. + +## Key commands + +- `specsync check` — validate all specs against source code +- `specsync check --json` — machine-readable validation output +- `specsync coverage` — show which modules lack specs +- `specsync score` — quality score for each spec (0-100) +- `specsync scaffold ` — full scaffold: spec + companions + registry entry + source detection +- `specsync new ` — quick-create a minimal spec (add `--full` for companions) +- `specsync resolve --remote` — verify cross-project dependencies diff --git a/.cursor/commands/specsync-create-change.md b/.cursor/commands/specsync-create-change.md new file mode 100644 index 0000000..49402f3 --- /dev/null +++ b/.cursor/commands/specsync-create-change.md @@ -0,0 +1,9 @@ +Create a verified spec-sync SDD change. + +Arguments: $ARGUMENTS + +1. Run `specsync change new "$ARGUMENTS" --json`. +2. Read the returned `questions` array and interview the user one question at a time. +3. Record each answer with `specsync change answer --json`. +4. Continue until the question list is empty, then show the selected artifacts and next action. +5. Do not approve, implement, verify, accept, or archive until the corresponding human gate or work stage is reached. diff --git a/.cursor/commands/specsync-create-spec.md b/.cursor/commands/specsync-create-spec.md new file mode 100644 index 0000000..0f20b4c --- /dev/null +++ b/.cursor/commands/specsync-create-spec.md @@ -0,0 +1,35 @@ +Create a new spec-sync module spec. + +Arguments: $ARGUMENTS + +1. Parse the arguments above: the first whitespace-separated token is the + module name. If the arguments also contain `--minimal` (in any position), + remove it and remember that minimal mode was requested. +2. Look at whatever text remains. It will be one of: + - **A bare module name** — a short identifier like `auth-service` or + `billing`. Use it as-is. + - **A free-text feature description** — a sentence or phrase describing + what to build, e.g. `"I want a feature that lets users export their + data as CSV"`. In this case, invent a short, kebab-case module name that + captures the idea (e.g. `csv-export`). If the right name is ambiguous, + ask the user to confirm or rename it before continuing. Keep the full + description at hand — you'll use it in step 5. +3. If minimal mode was requested, run: + ``` + specsync new + ``` + This creates a minimal spec only (no companion files). +4. Otherwise (default), run: + ``` + specsync scaffold + ``` + This creates the spec, companion files (`tasks.md`, `requirements.md`, + `context.md`, `testing.md`, and `design.md` if `companions.design` is + enabled), a registry entry, and auto-detects related source files. +5. Open the newly created `specs//.spec.md` and fill + in the `Purpose`, `Requirements`, and `Public API` sections. If a free-text + description was given in step 2, use it directly to draft these sections — + ask clarifying questions if it's underspecified, but do not leave the + sections as unfilled placeholder text. Do the same for `requirements.md` + (acceptance criteria) and `tasks.md` (initial task breakdown), if present. +6. Run `specsync check` to confirm the new spec passes validation. diff --git a/.cursor/skills/spec-sync/SKILL.md b/.cursor/skills/spec-sync/SKILL.md new file mode 100644 index 0000000..de24d12 --- /dev/null +++ b/.cursor/skills/spec-sync/SKILL.md @@ -0,0 +1,75 @@ +--- +name: spec-sync +description: Keep markdown module specs in specs// synchronized with source code using spec-sync. Use this whenever creating, editing, or reviewing code in a module that has (or should have) a spec, or whenever the user mentions specs, spec-sync, companion files (tasks.md/requirements.md/context.md/testing.md/design.md), or asks to add/update a module's documentation. +--- + +# Spec-Sync Workflow + +This project uses [spec-sync](https://github.com/CorvidLabs/spec-sync) for bidirectional spec-to-code validation. Specs live in `specs//.spec.md`. + +## Companion files + +## Verified SDD change lifecycle (5.0) + +For every meaningful source, test, public documentation, schema, or configuration change: + +1. Run `specsync change new "" --json` and conduct the returned interview with the user. +2. Use `specsync change answer --json` until no questions remain. +3. Complete the adaptively selected artifacts and semantic deltas. Requirements use stable + `REQ--` IDs, a normative SHALL statement, and acceptance criteria. +4. Ask the user for the definition approval, then run `specsync change approve `. +5. Run `specsync change start ` before editing implementation code. +6. Keep tasks and artifacts current, then run `specsync change verify `. +7. Present verification evidence and ask for closing approval. Only after explicit approval, + run `specsync change accept `; archive separately with `specsync change archive `. + +Never invent or self-grant either human approval. If an approved definition changes, its digest +becomes stale and must be approved again. `specsync check` validates canonical specs plus approved +active deltas, requirement-to-test evidence, change coverage, and CI gates. + +Each canonical spec may have policy-selected companion files. Read and update the ones present; do not create empty companions only for ceremony: + +- **`tasks.md`** — Work items for this module. Check off tasks (`- [x]`) as you complete them. Add new tasks if you discover work needed. +- **`requirements.md`** — Acceptance criteria and user stories. These are permanent invariants, not tasks — do not check them off. Update if requirements change. +- **`context.md`** — Architectural decisions, key files, and current status. Update when you make design decisions or change what's in progress. +- **`testing.md`** — Test strategy: automated test locations, manual QA checklists, and edge cases/boundary conditions. +- **`design.md`** *(opt-in)* — Layout, component hierarchy, design tokens, and asset references. Present when `companions.design` is enabled in config. + +## Before modifying any module + +1. Read the relevant spec in `specs//.spec.md` +2. Read whichever companion files are present (`requirements.md`, `tasks.md`, `context.md`, `testing.md`, `design.md`, or project-defined files) +3. After changes, run `specsync check` to verify specs still pass + +## After completing work + +1. Mark completed items in `tasks.md` — check off finished tasks, add new ones discovered +2. Update `context.md` — record decisions made, update current status +3. If requirements changed, update `requirements.md` acceptance criteria +4. If test coverage changed, update `testing.md` with new test files or edge cases +5. If UI/layout changed, update `design.md` with revised layout, components, or tokens + +## Before creating a PR + +Run `specsync check --strict` — all specs must pass with zero warnings. + +## When adding new modules + +Run `specsync scaffold ` to create a spec, companion files, a registry +entry, and auto-detected source files — or `specsync new ` for a +minimal spec-only draft. Complete the spec before writing code. The +`/specsync:create-spec` command (or tool-equivalent) runs this for you, and +accepts either a bare module name or a natural-language feature description +(e.g. `/specsync:create-spec "I want a feature that lets users export their +data as CSV"`) — pass a description and it will pick a module name and use +the description to draft the spec's Purpose and Requirements. + +## Key commands + +- `specsync check` — validate all specs against source code +- `specsync check --json` — machine-readable validation output +- `specsync coverage` — show which modules lack specs +- `specsync score` — quality score for each spec (0-100) +- `specsync scaffold ` — full scaffold: spec + companions + registry entry + source detection +- `specsync new ` — quick-create a minimal spec (add `--full` for companions) +- `specsync resolve --remote` — verify cross-project dependencies diff --git a/.gemini/commands/specsync/create-change.toml b/.gemini/commands/specsync/create-change.toml new file mode 100644 index 0000000..b4b7de6 --- /dev/null +++ b/.gemini/commands/specsync/create-change.toml @@ -0,0 +1,11 @@ +description = "Create and guide a verified spec-sync SDD change through its deterministic interview" + +prompt = """ +Arguments: {{args}} + +1. Run `specsync change new "$ARGUMENTS" --json`. +2. Read the returned `questions` array and interview the user one question at a time. +3. Record each answer with `specsync change answer --json`. +4. Continue until the question list is empty, then show the selected artifacts and next action. +5. Do not approve, implement, verify, accept, or archive until the corresponding human gate or work stage is reached. +""" diff --git a/.gemini/commands/specsync/create-spec.toml b/.gemini/commands/specsync/create-spec.toml new file mode 100644 index 0000000..73789f1 --- /dev/null +++ b/.gemini/commands/specsync/create-spec.toml @@ -0,0 +1,35 @@ +description = "Scaffold a new spec-sync module spec from a module name or a natural-language feature description (full scaffold by default, or minimal with --minimal)" + +prompt = """ +Create a new spec-sync module spec. + +Arguments: {{args}} + +1. Parse the arguments above: the first whitespace-separated token is the + module name. If the arguments also contain --minimal (in any position), + remove it and remember that minimal mode was requested. +2. Look at whatever text remains. It will be one of: + - A bare module name - a short identifier like auth-service or billing. + Use it as-is. + - A free-text feature description - a sentence or phrase describing what + to build, e.g. "I want a feature that lets users export their data as + CSV". In this case, invent a short, kebab-case module name that captures + the idea (e.g. csv-export). If the right name is ambiguous, ask the user + to confirm or rename it before continuing. Keep the full description at + hand - you'll use it in step 5. +3. If minimal mode was requested, run: + specsync new + This creates a minimal spec only (no companion files). +4. Otherwise (default), run: + specsync scaffold + This creates the spec, companion files (tasks.md, requirements.md, + context.md, testing.md, and design.md if companions.design is enabled), + a registry entry, and auto-detects related source files. +5. Open the newly created specs//.spec.md and fill + in the Purpose, Requirements, and Public API sections. If a free-text + description was given in step 2, use it directly to draft these sections - + ask clarifying questions if it's underspecified, but do not leave the + sections as unfilled placeholder text. Do the same for requirements.md + (acceptance criteria) and tasks.md (initial task breakdown), if present. +6. Run specsync check to confirm the new spec passes validation. +""" diff --git a/.gemini/skills/spec-sync/SKILL.md b/.gemini/skills/spec-sync/SKILL.md new file mode 100644 index 0000000..de24d12 --- /dev/null +++ b/.gemini/skills/spec-sync/SKILL.md @@ -0,0 +1,75 @@ +--- +name: spec-sync +description: Keep markdown module specs in specs// synchronized with source code using spec-sync. Use this whenever creating, editing, or reviewing code in a module that has (or should have) a spec, or whenever the user mentions specs, spec-sync, companion files (tasks.md/requirements.md/context.md/testing.md/design.md), or asks to add/update a module's documentation. +--- + +# Spec-Sync Workflow + +This project uses [spec-sync](https://github.com/CorvidLabs/spec-sync) for bidirectional spec-to-code validation. Specs live in `specs//.spec.md`. + +## Companion files + +## Verified SDD change lifecycle (5.0) + +For every meaningful source, test, public documentation, schema, or configuration change: + +1. Run `specsync change new "" --json` and conduct the returned interview with the user. +2. Use `specsync change answer --json` until no questions remain. +3. Complete the adaptively selected artifacts and semantic deltas. Requirements use stable + `REQ--` IDs, a normative SHALL statement, and acceptance criteria. +4. Ask the user for the definition approval, then run `specsync change approve `. +5. Run `specsync change start ` before editing implementation code. +6. Keep tasks and artifacts current, then run `specsync change verify `. +7. Present verification evidence and ask for closing approval. Only after explicit approval, + run `specsync change accept `; archive separately with `specsync change archive `. + +Never invent or self-grant either human approval. If an approved definition changes, its digest +becomes stale and must be approved again. `specsync check` validates canonical specs plus approved +active deltas, requirement-to-test evidence, change coverage, and CI gates. + +Each canonical spec may have policy-selected companion files. Read and update the ones present; do not create empty companions only for ceremony: + +- **`tasks.md`** — Work items for this module. Check off tasks (`- [x]`) as you complete them. Add new tasks if you discover work needed. +- **`requirements.md`** — Acceptance criteria and user stories. These are permanent invariants, not tasks — do not check them off. Update if requirements change. +- **`context.md`** — Architectural decisions, key files, and current status. Update when you make design decisions or change what's in progress. +- **`testing.md`** — Test strategy: automated test locations, manual QA checklists, and edge cases/boundary conditions. +- **`design.md`** *(opt-in)* — Layout, component hierarchy, design tokens, and asset references. Present when `companions.design` is enabled in config. + +## Before modifying any module + +1. Read the relevant spec in `specs//.spec.md` +2. Read whichever companion files are present (`requirements.md`, `tasks.md`, `context.md`, `testing.md`, `design.md`, or project-defined files) +3. After changes, run `specsync check` to verify specs still pass + +## After completing work + +1. Mark completed items in `tasks.md` — check off finished tasks, add new ones discovered +2. Update `context.md` — record decisions made, update current status +3. If requirements changed, update `requirements.md` acceptance criteria +4. If test coverage changed, update `testing.md` with new test files or edge cases +5. If UI/layout changed, update `design.md` with revised layout, components, or tokens + +## Before creating a PR + +Run `specsync check --strict` — all specs must pass with zero warnings. + +## When adding new modules + +Run `specsync scaffold ` to create a spec, companion files, a registry +entry, and auto-detected source files — or `specsync new ` for a +minimal spec-only draft. Complete the spec before writing code. The +`/specsync:create-spec` command (or tool-equivalent) runs this for you, and +accepts either a bare module name or a natural-language feature description +(e.g. `/specsync:create-spec "I want a feature that lets users export their +data as CSV"`) — pass a description and it will pick a module name and use +the description to draft the spec's Purpose and Requirements. + +## Key commands + +- `specsync check` — validate all specs against source code +- `specsync check --json` — machine-readable validation output +- `specsync coverage` — show which modules lack specs +- `specsync score` — quality score for each spec (0-100) +- `specsync scaffold ` — full scaffold: spec + companions + registry entry + source detection +- `specsync new ` — quick-create a minimal spec (add `--full` for companions) +- `specsync resolve --remote` — verify cross-project dependencies diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml index 3250c25..58b81ee 100644 --- a/.github/workflows/trust.yml +++ b/.github/workflows/trust.yml @@ -32,15 +32,6 @@ jobs: with: fetch-depth: 0 # augur/attest need full history - - name: Install fledge (prebuilt release binary) - run: | - mkdir -p "$HOME/.local/bin" - curl -fsSL -o "$HOME/.local/bin/fledge" \ - https://github.com/CorvidLabs/fledge/releases/latest/download/fledge-macos-aarch64 - chmod +x "$HOME/.local/bin/fledge" - echo "$HOME/.local/bin" >> "$GITHUB_PATH" - "$HOME/.local/bin/fledge" --version - - name: Install swift-format run: brew install swift-format @@ -49,31 +40,10 @@ jobs: with: bun-version: latest - # Lifecycle: the single gate runs format/build/test for all three parser - # implementations (Swift, TypeScript, Rust) plus spec-sync. - - name: Verify lane - run: fledge lanes run verify - - # Contracts: specs must stay in sync with source. - - name: Spec sync - uses: CorvidLabs/spec-sync@v4.5.0 - with: - strict: "true" - - # Risk: enforced, deterministic, low false-positive. - - name: Augur risk gate - uses: CorvidLabs/augur@v0.4.0 - with: - range: origin/main..HEAD - threshold: block - - # Trust: soft until a signing key and richer policy land. - - name: Attest verify - uses: CorvidLabs/attest@v0.4.0 - with: - range: origin/main..HEAD - policy: .attest.json - continue-on-error: true + # Unified lifecycle, contract, risk, and progressive provenance gate. + - name: CorvidLabs Trust gate + id: trust + uses: CorvidLabs/trust@9d32b5786d2e9e4d39fc581c0091c721ee3d4226 # v1.0.0 # Durability: fail if the standing rules block was removed. - name: Trust block present diff --git a/.specsync/adoption-report.json b/.specsync/adoption-report.json new file mode 100644 index 0000000..15e9c08 --- /dev/null +++ b/.specsync/adoption-report.json @@ -0,0 +1,25 @@ +{ + "bootstrap_policy": { + "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", + "digest": "17da9387d2f3e8e96682c32e539ea1f1797adbdbd784e02c47b0c608ada2b8a1", + "path": ".specsync/sdd.json" + }, + "generated_at": 1783826710, + "requirements_needing_ids": [ + { + "action": "review and assign one stable ID per durable requirement", + "path": "specs/ThreeMD/requirements.md", + "suggested_first_id": "REQ-threemd-001" + }, + { + "action": "review and assign one stable ID per durable requirement", + "path": "specs/ThreeMDCLI/requirements.md", + "suggested_first_id": "REQ-threemdcli-001" + }, + { + "action": "review and assign one stable ID per durable requirement", + "path": "specs/ThreeMDElement/requirements.md", + "suggested_first_id": "REQ-threemdelement-001" + } + ] +} diff --git a/.specsync/change.lock b/.specsync/change.lock new file mode 100644 index 0000000..e69de29 diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json new file mode 100644 index 0000000..b48bda6 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json @@ -0,0 +1,11 @@ +{ + "approvals": [ + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1783826959, + "digest": "79cfe2c4cd9797c14198de4d7f463d8f8b82125287963141c78c6d3b24157aec", + "note": "Authorized by the user-approved CorvidLabs Trust 1 / SpecSync 5 rollout plan." + } + ] +} diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md new file mode 100644 index 0000000..bdd9e7e --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md @@ -0,0 +1,26 @@ +--- +id: CHG-0001-adopt-trust-1-and-specsync-5 +state: implementing +type: migration +base_commit: 2a145766b9ecb83d96ee15aa453a65cc2125571f +--- + +# Adopt Trust 1 and SpecSync 5 + +## Intent + +Adopt Trust 1 and SpecSync 5 + +## Affected Canonical Specs + +- None + +## Acceptance Criteria + +- Trust 1.0.0 runs the existing verify lane +- SpecSync 5.0.1 strict validation passes +- Claude Cursor Codex and Gemini integrations report installed + +## No-spec Rationale + +Tooling policy migration; no product API or canonical module contract changes. diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/context.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/context.md new file mode 100644 index 0000000..100bff1 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/context.md @@ -0,0 +1,14 @@ +--- +change: CHG-0001-adopt-trust-1-and-specsync-5 +artifact: context +--- + +# Context + +The repository already has a real Fledge verify lane and separate SpecSync, +Augur, and Attest checks. This migration keeps the existing runner and language +setup while making Trust 1.0.0 the single orchestration surface. + +SpecSync 5.0.1 enables its verified SDD policy, records this migration as a +no-product-contract change, and installs native workflows for Claude, Cursor, +Codex, and Gemini. diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/design.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/design.md new file mode 100644 index 0000000..9c4bb1f --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/design.md @@ -0,0 +1,14 @@ +--- +change: CHG-0001-adopt-trust-1-and-specsync-5 +artifact: design +--- + +# Design + +The workflow retains checkout, full git history, runner selection, and +project-specific dependency setup. One Trust action then runs the existing +Fledge verify lane, SpecSync contract validation, Augur's block threshold, and +soft provenance verification. + +The committed policy is authoritative. Workflow inputs do not weaken it. +AGENTS.md remains protected by the existing marker check. diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/docs.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/docs.md new file mode 100644 index 0000000..cdb3306 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/docs.md @@ -0,0 +1,11 @@ +--- +change: CHG-0001-adopt-trust-1-and-specsync-5 +artifact: docs +--- + +# Docs + +AGENTS.md carries the Trust 1 managed rules. The generated Claude, Cursor, +Codex, and Gemini skills document the SpecSync 5 change lifecycle in each +tool's native discovery location. No product documentation or public API +contract changes as part of this migration. diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/plan.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/plan.md new file mode 100644 index 0000000..2ad6abc --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/plan.md @@ -0,0 +1,12 @@ +--- +change: CHG-0001-adopt-trust-1-and-specsync-5 +artifact: plan +--- + +# Plan + +1. Adopt the SpecSync 5 policy and use the existing verify lane as evidence. +2. Install all four repository-native coding-agent integrations. +3. Adopt the standard Trust policy with Atlas disabled and progressive provenance. +4. Replace duplicated gate steps with the immutable Trust 1.0.0 action. +5. Run agent-status, doctor, strict contract, and repository verification checks. diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/research.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/research.md new file mode 100644 index 0000000..6adbd2a --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/research.md @@ -0,0 +1,14 @@ +--- +change: CHG-0001-adopt-trust-1-and-specsync-5 +artifact: research +--- + +# Research + +The previous workflow duplicated lifecycle, contract, risk, and provenance +ordering in each repository. Trust 1.0.0 provides the same ordered gates from a +committed `.trust.toml` policy and pins SpecSync 5.0.1 internally. + +The consumer workflow pins Trust's immutable 1.0.0 commit. Existing dependency +setup remains before the Trust step, and provenance remains progressive until +the repository has a durable remote notes ledger. diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json new file mode 100644 index 0000000..8958600 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json @@ -0,0 +1,41 @@ +{ + "schema_version": 1, + "id": "CHG-0001-adopt-trust-1-and-specsync-5", + "slug": "adopt-trust-1-and-specsync-5", + "title": "Adopt Trust 1 and SpecSync 5", + "description": "Adopt Trust 1 and SpecSync 5", + "kind": "migration", + "state": "implementing", + "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", + "created_at": 1783826867, + "updated_at": 1783826959, + "affected_specs": [], + "affected_paths": [ + ".github/workflows/trust.yml", + ".specsync/", + ".trust.toml", + ".augur.toml", + "AGENTS.md" + ], + "no_spec_change": true, + "no_spec_change_rationale": "Tooling policy migration; no product API or canonical module contract changes.", + "acceptance_criteria": [ + "Trust 1.0.0 runs the existing verify lane", + "SpecSync 5.0.1 strict validation passes", + "Claude Cursor Codex and Gemini integrations report installed" + ], + "selected_artifacts": [ + "context", + "research", + "design", + "plan", + "tasks", + "testing", + "docs" + ], + "dependencies": [], + "answers": { + "architecture_risk": "yes", + "public_contract": "no" + } +} diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md new file mode 100644 index 0000000..c7ee19c --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md @@ -0,0 +1,13 @@ +--- +change: CHG-0001-adopt-trust-1-and-specsync-5 +artifact: tasks +--- + +# Tasks + +- [x] Adopt SpecSync 5 SDD policy. +- [x] Install Claude, Cursor, Codex, and Gemini integrations. +- [x] Commit the standard Trust policy and Augur configuration. +- [x] Consolidate the CI workflow on Trust 1.0.0. +- [ ] Pass local strict validation and the repository verify lane. +- [ ] Pass hosted pull-request checks. diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/testing.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/testing.md new file mode 100644 index 0000000..9d7c4a3 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/testing.md @@ -0,0 +1,12 @@ +--- +change: CHG-0001-adopt-trust-1-and-specsync-5 +artifact: testing +--- + +# Testing + +- `specsync agents status` reports all four integrations installed. +- `fledge trust doctor` reports a healthy repository. +- `specsync check --strict --force` passes with the active change. +- `fledge trust verify` runs the existing verification lane and component gates. +- The pull-request `trust` job passes on the repository's established runner. diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/approvals.json b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/approvals.json new file mode 100644 index 0000000..25116b0 --- /dev/null +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/approvals.json @@ -0,0 +1,11 @@ +{ + "approvals": [ + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1783827254, + "digest": "dcb9541b9bbaef2158d04f0776225b9150255a95bc679f8dbaa7a26311efc798", + "note": "Authorized by the user-approved CorvidLabs Trust 1 / SpecSync 5 rollout plan." + } + ] +} diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/change.md b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/change.md new file mode 100644 index 0000000..3ca7459 --- /dev/null +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/change.md @@ -0,0 +1,24 @@ +--- +id: CHG-0002-assign-stable-requirement-ids +state: implementing +type: documentation +base_commit: 2a145766b9ecb83d96ee15aa453a65cc2125571f +--- + +# Assign stable requirement IDs + +## Intent + +Assign stable requirement IDs + +## Affected Canonical Specs + +- None + +## Acceptance Criteria + +- Every durable requirement has a unique REQ ID; existing requirement semantics remain unchanged; SpecSync strict validation passes + +## No-spec Rationale + +Add stable identifiers to existing requirement statements without changing their semantics. diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/context.md b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/context.md new file mode 100644 index 0000000..bd89fb1 --- /dev/null +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/context.md @@ -0,0 +1,10 @@ +--- +change: CHG-0002-assign-stable-requirement-ids +artifact: context +--- + +# Context + +SpecSync 5 uses durable requirement identifiers to connect canonical requirements, implementation, +and verification evidence. Existing requirement companions predate that convention, so this change +adds stable `REQ-*` identifiers while preserving their original acceptance language and meaning. diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/docs.md b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/docs.md new file mode 100644 index 0000000..55c3810 --- /dev/null +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/docs.md @@ -0,0 +1,10 @@ +--- +change: CHG-0002-assign-stable-requirement-ids +artifact: docs +--- + +# Docs + +The canonical requirement companions now include a Durable Requirements section. Each existing +acceptance criterion is represented by a unique, module-scoped `REQ-*` identifier. No public API, +behavior, or verification command changes as part of this documentation migration. diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/state.json b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/state.json new file mode 100644 index 0000000..eb57245 --- /dev/null +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/state.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "id": "CHG-0002-assign-stable-requirement-ids", + "slug": "assign-stable-requirement-ids", + "title": "Assign stable requirement IDs", + "description": "Assign stable requirement IDs", + "kind": "documentation", + "state": "implementing", + "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", + "created_at": 1783827126, + "updated_at": 1783827254, + "affected_specs": [], + "affected_paths": [ + "specs/" + ], + "no_spec_change": true, + "no_spec_change_rationale": "Add stable identifiers to existing requirement statements without changing their semantics.", + "acceptance_criteria": [ + "Every durable requirement has a unique REQ ID; existing requirement semantics remain unchanged; SpecSync strict validation passes" + ], + "selected_artifacts": [ + "context", + "docs" + ], + "dependencies": [], + "answers": { + "architecture_risk": "no", + "public_contract": "no" + } +} diff --git a/.specsync/config.toml b/.specsync/config.toml index 2e2c511..cdf5c32 100644 --- a/.specsync/config.toml +++ b/.specsync/config.toml @@ -1,4 +1,4 @@ -# spec-sync v4 configuration +# spec-sync v5 configuration # Docs: https://github.com/CorvidLabs/spec-sync specs_dir = "specs" diff --git a/.specsync/sdd.json b/.specsync/sdd.json new file mode 100644 index 0000000..8c0c624 --- /dev/null +++ b/.specsync/sdd.json @@ -0,0 +1,40 @@ +{ + "version": 1, + "enabled": true, + "require_change_for_meaningful_files": true, + "meaningful_paths": [ + "src/", + "tests/", + "site/", + ".github/", + "Cargo.toml", + "Cargo.lock", + "action.yml", + "package.json", + "bun.lock", + "package-lock.json", + "pnpm-lock.yaml", + "yarn.lock", + "Package.swift", + "Package.resolved", + "go.mod", + "go.sum", + "pyproject.toml", + "uv.lock", + "requirements.txt", + ".specsync/sdd.json", + ".specsync/config.toml", + ".specsync/config.json", + ".specsync/version", + "Sources/" + ], + "ignored_paths": [ + ".specsync/", + "specs/" + ], + "verification_commands": [ + "fledge lanes run verify" + ], + "custom_artifacts": {}, + "principles_file": null +} diff --git a/.specsync/version b/.specsync/version index f77856a..6b244dc 100644 --- a/.specsync/version +++ b/.specsync/version @@ -1 +1 @@ -4.3.1 +5.0.1 diff --git a/.trust.toml b/.trust.toml new file mode 100644 index 0000000..c1b2d2e --- /dev/null +++ b/.trust.toml @@ -0,0 +1,22 @@ +schema_version = 1 +profile = "standard" + +[lifecycle] +command = ["fledge", "lanes", "run", "verify"] + +[contract] +enabled = true +require_coverage = 0 +skip_reason = "" + +[risk] +threshold = "block" + +[provenance] +mode = "soft" +policy = ".attest.json" +skip_reason = "" + +[atlas] +enabled = false +skip_reason = "Atlas publication was not enabled during adoption" diff --git a/AGENTS.md b/AGENTS.md index 024bcdb..8ba6621 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,14 +20,14 @@ descriptive generic names, 4-space indentation, 120-column lines. The formatter config in `.swift-format` enforces the mechanical parts. -## CorvidLabs trust toolchain (standing rules) +## CorvidLabs trust toolchain -This repo is governed by four CLIs. Every session MUST use them; never bypass or weaken them. +This repository uses one trust gate. Every session must use it and must not bypass or weaken it. -- fledge: run `fledge lanes run verify` before calling any change done. It must pass. -- spec-sync: when you change a module with a *.spec.md, update the spec, then `fledge spec check`. (skipped: , if content-only) -- augur: `augur check --staged` before a commit; `augur check --range origin/main..HEAD` before merge. A block verdict is a hard stop, never auto-overridden. -- attest: after a green lane, `attest sign --commit HEAD --reviewer agent: --from-augur augur.json --tests-passed`. +- Run `fledge trust verify` before calling a change complete. +- Keep module specs synchronized with implementation changes. +- Treat an Augur block verdict as a hard stop that must be surfaced and de-risked. +- Record and verify provenance with Attest after the repository's verification lane passes. +- Keep generated trust configuration and this managed block in place. -CI enforces the same gate (.github/workflows/trust.yml) and fails if this block is missing. Brand rule: no em-dash characters in anything you write. diff --git a/specs/ThreeMD/requirements.md b/specs/ThreeMD/requirements.md index 29b4e2f..fcad5cd 100644 --- a/specs/ThreeMD/requirements.md +++ b/specs/ThreeMD/requirements.md @@ -20,6 +20,168 @@ numbered so tests and reviews can reference it directly. - As a tool author, I want to know what the Z axis means and how planes are ordered so I can lay a document out correctly. +## Durable Requirements + +### REQ-threemd-001 + +The implementation SHALL satisfy the following criterion: **FR-1 (Frontmatter required).** `Parser.parse` requires a frontmatter block: a line containing exactly `---`, zero or more content lines, and a closing line containing exactly `---`. Leading blank lines before the opening fence are skipped. A source with no opening `---` throws `ParseError.missingFrontmatter`. A frontmatter block that is never closed throws `ParseError.invalidFrontmatter`. + +Acceptance Criteria + +- **FR-1 (Frontmatter required).** `Parser.parse` requires a frontmatter block: a line containing exactly `---`, zero or more content lines, and a closing line containing exactly `---`. Leading blank lines before the opening fence are skipped. A source with no opening `---` throws `ParseError.missingFrontmatter`. A frontmatter block that is never closed throws `ParseError.invalidFrontmatter`. + +### REQ-threemd-002 + +The implementation SHALL satisfy the following criterion: **FR-2 (Version marker required).** Frontmatter MUST declare a `3md` key whose value is non-empty. Its presence is the format's magic marker. The value is stored as `Document.version`. A missing or empty `3md` value throws `ParseError.missingVersion`. + +Acceptance Criteria + +- **FR-2 (Version marker required).** Frontmatter MUST declare a `3md` key whose value is non-empty. Its presence is the format's magic marker. The value is stored as `Document.version`. A missing or empty `3md` value throws `ParseError.missingVersion`. + +### REQ-threemd-003 + +The implementation SHALL satisfy the following criterion: **FR-3 (Frontmatter fields).** Inside the fences, content lines are `key: value` pairs split on the first `:`. Blank lines and lines beginning with `#` are ignored. A non-blank, non-comment line with no `:` throws `ParseError.invalidFrontmatter`. Keys are matched case-insensitively. Values are trimmed, and a matching pair of surrounding single or double quotes is stripped. + +Acceptance Criteria + +- **FR-3 (Frontmatter fields).** Inside the fences, content lines are `key: value` pairs split on the first `:`. Blank lines and lines beginning with `#` are ignored. A non-blank, non-comment line with no `:` throws `ParseError.invalidFrontmatter`. Keys are matched case-insensitively. Values are trimmed, and a matching pair of surrounding single or double quotes is stripped. + +### REQ-threemd-004 + +The implementation SHALL satisfy the following criterion: **FR-4 (Axis handling and default).** The optional `axis` key sets `Document.axis`. The `Axis` value trims and lowercases its raw string, so `axis` is normalized. When no `axis` key is present, the axis defaults to `Axis.layer`. Any axis string is permitted; `time`, `depth`, `layer`, `frame`, and `space` are provided as named constants. + +Acceptance Criteria + +- **FR-4 (Axis handling and default).** The optional `axis` key sets `Document.axis`. The `Axis` value trims and lowercases its raw string, so `axis` is normalized. When no `axis` key is present, the axis defaults to `Axis.layer`. Any axis string is permitted; `time`, `depth`, `layer`, `frame`, and `space` are provided as named constants. + +### REQ-threemd-005 + +The implementation SHALL satisfy the following criterion: **FR-5 (Reserved frontmatter keys and metadata).** The keys `3md`, `axis`, and `title` are reserved. `title` populates the optional `Document.title`. Every other frontmatter key is preserved verbatim in `Document.metadata` as a `[String: String]` pair. + +Acceptance Criteria + +- **FR-5 (Reserved frontmatter keys and metadata).** The keys `3md`, `axis`, and `title` are reserved. `title` populates the optional `Document.title`. Every other frontmatter key is preserved verbatim in `Document.metadata` as a `[String: String]` pair. + +### REQ-threemd-006 + +The implementation SHALL satisfy the following criterion: **FR-6 (Plane directives).** A plane begins with a line whose first whitespace-delimited token is `@plane`, followed by space-separated `key=value` attributes. A token with no `=`, or with an empty key, throws `ParseError.invalidPlaneDirective`. Attribute keys are lowercased. Attribute values may be quoted with single or double quotes; the tokenizer keeps quoted spans intact so a value may contain spaces, and surrounding quotes are stripped. + +Acceptance Criteria + +- **FR-6 (Plane directives).** A plane begins with a line whose first whitespace-delimited token is `@plane`, followed by space-separated `key=value` attributes. A token with no `=`, or with an empty key, throws `ParseError.invalidPlaneDirective`. Attribute keys are lowercased. Attribute values may be quoted with single or double quotes; the tokenizer keeps quoted spans intact so a value may contain spaces, and surrounding quotes are stripped. + +### REQ-threemd-007 + +The implementation SHALL satisfy the following criterion: **FR-7 (Required z attribute).** Each `@plane` directive MUST carry a `z` attribute. A directive with no `z` throws `ParseError.missingPlanePosition(line:)`. A `z` value that does not parse as a `Double` throws `ParseError.invalidPlaneDirective(line:detail:)`. Numbers may be integer or decimal and may be negative. + +Acceptance Criteria + +- **FR-7 (Required z attribute).** Each `@plane` directive MUST carry a `z` attribute. A directive with no `z` throws `ParseError.missingPlanePosition(line:)`. A `z` value that does not parse as a `Double` throws `ParseError.invalidPlaneDirective(line:detail:)`. Numbers may be integer or decimal and may be negative. + +### REQ-threemd-008 + +The implementation SHALL satisfy the following criterion: **FR-8 (Optional x, y, label, and extra attributes).** The `x` and `y` attributes are optional in-plane offsets; when present each MUST parse as a `Double` or `ParseError.invalidPlaneDirective` is thrown. `label` is an optional human-readable string. The reserved plane attributes are `z`, `x`, `y`, and `label`; every other attribute is preserved in `Plane.attributes` as a `[String: String]` pair. + +Acceptance Criteria + +- **FR-8 (Optional x, y, label, and extra attributes).** The `x` and `y` attributes are optional in-plane offsets; when present each MUST parse as a `Double` or `ParseError.invalidPlaneDirective` is thrown. `label` is an optional human-readable string. The reserved plane attributes are `z`, `x`, `y`, and `label`; every other attribute is preserved in `Plane.attributes` as a `[String: String]` pair. + +### REQ-threemd-009 + +The implementation SHALL satisfy the following criterion: **FR-9 (Plane body and preamble handling).** Every line after a directive, up to the next `@plane` directive or end of file, is that plane's Markdown body. Leading and trailing blank lines of a body are trimmed; an all-whitespace body collapses to an empty string. Markdown that appears after the frontmatter but before the first `@plane` directive is the document preamble, stored in the optional `Document.preamble` with the same blank-line trimming. + +Acceptance Criteria + +- **FR-9 (Plane body and preamble handling).** Every line after a directive, up to the next `@plane` directive or end of file, is that plane's Markdown body. Leading and trailing blank lines of a body are trimmed; an all-whitespace body collapses to an empty string. Markdown that appears after the frontmatter but before the first `@plane` directive is the document preamble, stored in the optional `Document.preamble` with the same blank-line trimming. + +### REQ-threemd-010 + +The implementation SHALL satisfy the following criterion: **FR-10 (Single-plane shorthand).** A document with frontmatter but no `@plane` directives whose remaining content is non-empty parses as exactly one implicit plane at `z = 0`, with that content as the plane body and a `nil` preamble. This makes a plain Markdown file with a 3md frontmatter header a valid one-plane document. + +Acceptance Criteria + +- **FR-10 (Single-plane shorthand).** A document with frontmatter but no `@plane` directives whose remaining content is non-empty parses as exactly one implicit plane at `z = 0`, with that content as the plane body and a `nil` preamble. This makes a plain Markdown file with a 3md frontmatter header a valid one-plane document. + +### REQ-threemd-011 + +The implementation SHALL satisfy the following criterion: **FR-11 (Duplicate z rejection).** No two planes in a document may share the same `z` value. A repeated `z` throws `ParseError.duplicatePlane(z:)`. + +Acceptance Criteria + +- **FR-11 (Duplicate z rejection).** No two planes in a document may share the same `z` value. A repeated `z` throws `ParseError.duplicatePlane(z:)`. + +### REQ-threemd-012 + +The implementation SHALL satisfy the following criterion: **FR-12 (Source order preserved).** `Document.planes` holds planes in source order. `Document.planesByZ` returns them sorted by ascending `z`, and `Document.plane(atZ:)` returns the first plane whose `z` equals the argument, or `nil`. + +Acceptance Criteria + +- **FR-12 (Source order preserved).** `Document.planes` holds planes in source order. `Document.planesByZ` returns them sorted by ascending `z`, and `Document.plane(atZ:)` returns the first plane whose `z` equals the argument, or `nil`. + +### REQ-threemd-013 + +The implementation SHALL satisfy the following criterion: **FR-13 (Serialization).** `Serializer.render` produces 3md text. It always emits a frontmatter block with `3md` and `axis` lines, then `title` when set, then metadata keys sorted alphabetically. For each plane it emits an `@plane` directive (`z`, then `label`, `x`, `y` when set, then extra attributes sorted alphabetically) followed by the non-empty body. Whole-number doubles render as integers; `label` and extra attribute values are always quoted, and embedded double quotes are escaped. + +Acceptance Criteria + +- **FR-13 (Serialization).** `Serializer.render` produces 3md text. It always emits a frontmatter block with `3md` and `axis` lines, then `title` when set, then metadata keys sorted alphabetically. For each plane it emits an `@plane` directive (`z`, then `label`, `x`, `y` when set, then extra attributes sorted alphabetically) followed by the non-empty body. Whole-number doubles render as integers; `label` and extra attribute values are always quoted, and embedded double quotes are escaped. + +### REQ-threemd-014 + +The implementation SHALL satisfy the following criterion: **FR-14 (Round-trip).** Serializing a `Document` and parsing the result yields an equal document, for content that does not rely on quote escaping. + +Acceptance Criteria + +- **FR-14 (Round-trip).** Serializing a `Document` and parsing the result yields an equal document, for content that does not rely on quote escaping. + +### REQ-threemd-015 + +The implementation SHALL satisfy the following criterion: **FR-15 (Line-ending normalization).** Parsing normalizes `\r\n` to `\n` before processing, so Windows and Unix line endings parse identically. ### Non-Functional Requirements + +Acceptance Criteria + +- **FR-15 (Line-ending normalization).** Parsing normalizes `\r\n` to `\n` before processing, so Windows and Unix line endings parse identically. ### Non-Functional Requirements + +### REQ-threemd-016 + +The implementation SHALL satisfy the following criterion: **NFR-1 (Swift 6, cross-platform).** The module builds under Swift 6 strict concurrency and targets all supported Apple platforms, Linux, and Windows. It relies only on portable Foundation string handling. + +Acceptance Criteria + +- **NFR-1 (Swift 6, cross-platform).** The module builds under Swift 6 strict concurrency and targets all supported Apple platforms, Linux, and Windows. It relies only on portable Foundation string handling. + +### REQ-threemd-017 + +The implementation SHALL satisfy the following criterion: **NFR-2 (Sendable value types).** `Axis`, `Plane`, `Document`, `ParseError`, `Parser`, and `Serializer` are `Sendable`. `Axis`, `Plane`, and `Document` are immutable value types that are also `Hashable` and `Codable`; `ParseError` is `Equatable`. + +Acceptance Criteria + +- **NFR-2 (Sendable value types).** `Axis`, `Plane`, `Document`, `ParseError`, `Parser`, and `Serializer` are `Sendable`. `Axis`, `Plane`, and `Document` are immutable value types that are also `Hashable` and `Codable`; `ParseError` is `Equatable`. + +### REQ-threemd-018 + +The implementation SHALL satisfy the following criterion: **NFR-3 (No force-unwrap).** Library code uses no force unwraps, `try!`, or `as!`. Optionals and failable conversions are handled with `guard` and typed throws. + +Acceptance Criteria + +- **NFR-3 (No force-unwrap).** Library code uses no force unwraps, `try!`, or `as!`. Optionals and failable conversions are handled with `guard` and typed throws. + +### REQ-threemd-019 + +The implementation SHALL satisfy the following criterion: **NFR-4 (Zero third-party dependencies).** The module depends only on Foundation. No third-party packages are used. + +Acceptance Criteria + +- **NFR-4 (Zero third-party dependencies).** The module depends only on Foundation. No third-party packages are used. + +### REQ-threemd-020 + +The implementation SHALL satisfy the following criterion: **NFR-5 (Deterministic parsing and serialization).** Parsing is pure: the same input always yields the same `Document`. Serialization is deterministic, ordering metadata and extra attributes alphabetically so output is stable. + +Acceptance Criteria + +- **NFR-5 (Deterministic parsing and serialization).** Parsing is pure: the same input always yields the same `Document`. Serialization is deterministic, ordering metadata and extra attributes alphabetically so output is stable. + ## Acceptance Criteria ### Functional Requirements diff --git a/specs/ThreeMDCLI/requirements.md b/specs/ThreeMDCLI/requirements.md index f25eddb..63612b5 100644 --- a/specs/ThreeMDCLI/requirements.md +++ b/specs/ThreeMDCLI/requirements.md @@ -13,6 +13,88 @@ These requirements describe the ThreeMDCLI Swift executable target: the command- - As a publisher, I want to compile a 3md document to HTML via stdout so I can render it for static web preview. - As a CI system, I want check-links to return non-zero exit codes on link failures so I can prevent broken builds. +## Durable Requirements + +### REQ-threemdcli-001 + +The implementation SHALL satisfy the following criterion: **FR-1 (Subcommands).** The executable accepts one of the following subcommands as its first argument: `validate`, `info`, `html`, `links`, or `check-links`. Any other argument or a missing subcommand prints usage information and exits with code 1. + +Acceptance Criteria + +- **FR-1 (Subcommands).** The executable accepts one of the following subcommands as its first argument: `validate`, `info`, `html`, `links`, or `check-links`. Any other argument or a missing subcommand prints usage information and exits with code 1. + +### REQ-threemdcli-002 + +The implementation SHALL satisfy the following criterion: **FR-2 (validate subcommand).** Parses the specified file. Prints "ok" and exits 0 on success. On parsing failure, prints the error details to stderr and exits 1. + +Acceptance Criteria + +- **FR-2 (validate subcommand).** Parses the specified file. Prints "ok" and exits 0 on success. On parsing failure, prints the error details to stderr and exits 1. + +### REQ-threemdcli-003 + +The implementation SHALL satisfy the following criterion: **FR-3 (info subcommand).** Prints metadata (version, axis, title, plane count) and each plane's properties (z, label, coordinates, extra attributes). + +Acceptance Criteria + +- **FR-3 (info subcommand).** Prints metadata (version, axis, title, plane count) and each plane's properties (z, label, coordinates, extra attributes). + +### REQ-threemdcli-004 + +The implementation SHALL satisfy the following criterion: **FR-4 (html subcommand).** Renders the document to HTML and prints the output to stdout. + +Acceptance Criteria + +- **FR-4 (html subcommand).** Renders the document to HTML and prints the output to stdout. + +### REQ-threemdcli-005 + +The implementation SHALL satisfy the following criterion: **FR-5 (links subcommand).** Extracts and prints all cross-plane links and the link graph representation. + +Acceptance Criteria + +- **FR-5 (links subcommand).** Extracts and prints all cross-plane links and the link graph representation. + +### REQ-threemdcli-006 + +The implementation SHALL satisfy the following criterion: **FR-6 (check-links subcommand).** Validates all cross-plane links. If there are dangling links, it prints details to stderr and exits with code 1. If all links resolve, it prints "ok" and exits 0. + +Acceptance Criteria + +- **FR-6 (check-links subcommand).** Validates all cross-plane links. If there are dangling links, it prints details to stderr and exits with code 1. If all links resolve, it prints "ok" and exits 0. + +### REQ-threemdcli-007 + +The implementation SHALL satisfy the following criterion: **FR-7 (JSON output option).** The `validate`, `info`, `links`, and `check-links` subcommands support a `--json` flag. When provided, the command prints the output formatted as JSON to stdout instead of raw text. ### Non-Functional Requirements + +Acceptance Criteria + +- **FR-7 (JSON output option).** The `validate`, `info`, `links`, and `check-links` subcommands support a `--json` flag. When provided, the command prints the output formatted as JSON to stdout instead of raw text. ### Non-Functional Requirements + +### REQ-threemdcli-008 + +The implementation SHALL satisfy the following criterion: **NFR-1 (Zero third-party dependencies).** The CLI target depends only on the local `ThreeMD` library target and Foundation. No external package manager or CLI parsing library is used. + +Acceptance Criteria + +- **NFR-1 (Zero third-party dependencies).** The CLI target depends only on the local `ThreeMD` library target and Foundation. No external package manager or CLI parsing library is used. + +### REQ-threemdcli-009 + +The implementation SHALL satisfy the following criterion: **NFR-2 (Fast execution).** CommandLine parsing and execution are fast, with minimal startup overhead. + +Acceptance Criteria + +- **NFR-2 (Fast execution).** CommandLine parsing and execution are fast, with minimal startup overhead. + +### REQ-threemdcli-010 + +The implementation SHALL satisfy the following criterion: **NFR-3 (Swift 6 Executable).** The executable builds cleanly under Swift 6 strict concurrency settings. + +Acceptance Criteria + +- **NFR-3 (Swift 6 Executable).** The executable builds cleanly under Swift 6 strict concurrency settings. + ## Acceptance Criteria ### Functional Requirements diff --git a/specs/ThreeMDElement/requirements.md b/specs/ThreeMDElement/requirements.md index c81de52..3bc1643 100644 --- a/specs/ThreeMDElement/requirements.md +++ b/specs/ThreeMDElement/requirements.md @@ -26,6 +26,176 @@ requirement is numbered so tests and reviews can reference it directly. - As an integrator, I want a `planechange` event and `document`, `currentIndex`, and `mode` reads so I can react to navigation from my own code. +## Durable Requirements + +### REQ-threemdelement-001 + +The implementation SHALL satisfy the following criterion: **FR-1 (Parsing is delegated).** The element does not parse 3md text. It calls `parse` from `@corvidlabs/threemd` to turn source into a `Document` and reads `document.planes` and each plane's `z`, `x`, `y`, `label`, and `body`. The format grammar lives in `SPEC.md` and the shared parser; this element only renders the result. + +Acceptance Criteria + +- **FR-1 (Parsing is delegated).** The element does not parse 3md text. It calls `parse` from `@corvidlabs/threemd` to turn source into a `Document` and reads `document.planes` and each plane's `z`, `x`, `y`, `label`, and `body`. The format grammar lives in `SPEC.md` and the shared parser; this element only renders the result. + +### REQ-threemdelement-002 + +The implementation SHALL satisfy the following criterion: **FR-2 (Source resolution).** On connect, if the `src` attribute is set the element fetches that URL and renders the response text; otherwise it renders its inline text content. `setSource(text)` replaces the rendered document with new source at any time, building the DOM first if needed. + +Acceptance Criteria + +- **FR-2 (Source resolution).** On connect, if the `src` attribute is set the element fetches that URL and renders the response text; otherwise it renders its inline text content. `setSource(text)` replaces the rendered document with new source at any time, building the DOM first if needed. + +### REQ-threemdelement-003 + +The implementation SHALL satisfy the following criterion: **FR-3 (`src` fetch and staleness).** Fetching `src` is asynchronous and guarded by a load token: each load increments the token, and a response whose token no longer matches the latest is discarded. A non-ok HTTP status or a rejected request renders the error part with a message naming the source. + +Acceptance Criteria + +- **FR-3 (`src` fetch and staleness).** Fetching `src` is asynchronous and guarded by a load token: each load increments the token, and a response whose token no longer matches the latest is discarded. A non-ok HTTP status or a rejected request renders the error part with a message naming the source. + +### REQ-threemdelement-004 + +The implementation SHALL satisfy the following criterion: **FR-4 (Empty and invalid source).** Blank source (after trim) renders the error part with "No 3md source provided." When `parse` throws, the element renders the error part with "Invalid 3md: " and builds no planes. + +Acceptance Criteria + +- **FR-4 (Empty and invalid source).** Blank source (after trim) renders the error part with "No 3md source provided." When `parse` throws, the element renders the error part with "Invalid 3md: " and builds no planes. + +### REQ-threemdelement-005 + +The implementation SHALL satisfy the following criterion: **FR-5 (Observed attributes).** `observedAttributes` is `["src", "mode"]`. Changing `src` triggers a fetch and render; changing `mode` re-applies the mode and re-renders. Attribute changes before the element has built its DOM are ignored until connect. + +Acceptance Criteria + +- **FR-5 (Observed attributes).** `observedAttributes` is `["src", "mode"]`. Changing `src` triggers a fetch and render; changing `mode` re-applies the mode and re-renders. Attribute changes before the element has built its DOM are ignored until connect. + +### REQ-threemdelement-006 + +The implementation SHALL satisfy the following criterion: **FR-6 (Mode selection).** The active `Mode` is one of `stack`, `play`, `layers`, `scene`, `parallax`, `present`, `elevator`. The `mode` attribute may be a `Mode` value or an axis name; an axis name (for example `time`, `frame`, `frames`, `layer`, `layers`, `depth`, `space`, `scene`, `slide`, `slides`, `deck`, `floor`, `floors`) maps to its mode. With no usable `mode` attribute, the mode is derived from `document.axis`, defaulting to `stack`. + +Acceptance Criteria + +- **FR-6 (Mode selection).** The active `Mode` is one of `stack`, `play`, `layers`, `scene`, `parallax`, `present`, `elevator`. The `mode` attribute may be a `Mode` value or an axis name; an axis name (for example `time`, `frame`, `frames`, `layer`, `layers`, `depth`, `space`, `scene`, `slide`, `slides`, `deck`, `floor`, `floors`) maps to its mode. With no usable `mode` attribute, the mode is derived from `document.axis`, defaulting to `stack`. + +### REQ-threemdelement-007 + +The implementation SHALL satisfy the following criterion: **FR-7 (Focus-relative layout).** Each plane is positioned by its distance from the focus, `d = idx - focus`, so the focused plane is frontmost at the largest true Z. The layout MUST NOT pin a fixed plane to the front, because Safari paints by true Z and ignores `z-index` inside `preserve-3d`. + +Acceptance Criteria + +- **FR-7 (Focus-relative layout).** Each plane is positioned by its distance from the focus, `d = idx - focus`, so the focused plane is frontmost at the largest true Z. The layout MUST NOT pin a fixed plane to the front, because Safari paints by true Z and ignores `z-index` inside `preserve-3d`. + +### REQ-threemdelement-008 + +The implementation SHALL satisfy the following criterion: **FR-8 (Synchronous render).** `render()` applies all current state to the DOM synchronously and is the single source of truth for the stage. It is called on every interaction (scrub, drag, step, key, pointer up) and does not depend on `requestAnimationFrame`. + +Acceptance Criteria + +- **FR-8 (Synchronous render).** `render()` applies all current state to the DOM synchronously and is the single source of truth for the stage. It is called on every interaction (scrub, drag, step, key, pointer up) and does not depend on `requestAnimationFrame`. + +### REQ-threemdelement-009 + +The implementation SHALL satisfy the following criterion: **FR-9 (Optional animation loop).** The `requestAnimationFrame` loop adds only gentle idle drift and is progressive enhancement. Every value it produces is also produced by a direct interaction plus a synchronous `render()`, so the element stays fully correct and usable when rAF is throttled or never fires (iOS Low Power Mode). The loop is started on connect and cancelled on disconnect. + +Acceptance Criteria + +- **FR-9 (Optional animation loop).** The `requestAnimationFrame` loop adds only gentle idle drift and is progressive enhancement. Every value it produces is also produced by a direct interaction plus a synchronous `render()`, so the element stays fully correct and usable when rAF is throttled or never fires (iOS Low Power Mode). The loop is started on connect and cancelled on disconnect. + +### REQ-threemdelement-010 + +The implementation SHALL satisfy the following criterion: **FR-10 (Pointer interaction).** The stage handles `pointerdown`, `pointermove`, `pointerup`, and `pointercancel` through one unified path for mouse, touch, and pen. A vertical drag moves the focus along Z; a horizontal drag orbits the scene. Pointer capture is attempted and failures are tolerated. + +Acceptance Criteria + +- **FR-10 (Pointer interaction).** The stage handles `pointerdown`, `pointermove`, `pointerup`, and `pointercancel` through one unified path for mouse, touch, and pen. A vertical drag moves the focus along Z; a horizontal drag orbits the scene. Pointer capture is attempted and failures are tolerated. + +### REQ-threemdelement-011 + +The implementation SHALL satisfy the following criterion: **FR-11 (Touch behavior and no overflow).** The stage sets `touch-action: none` so a finger drives the model rather than scrolling the page. The element is `max-width: 100%` and `box-sizing: border-box` and MUST NOT overflow horizontally at any width from 320px to 1440px. + +Acceptance Criteria + +- **FR-11 (Touch behavior and no overflow).** The stage sets `touch-action: none` so a finger drives the model rather than scrolling the page. The element is `max-width: 100%` and `box-sizing: border-box` and MUST NOT overflow horizontally at any width from 320px to 1440px. + +### REQ-threemdelement-012 + +The implementation SHALL satisfy the following criterion: **FR-12 (Scrubber, buttons, and keys).** A range input scrubs the Z axis; its max is the last plane index. Prev and next buttons step the focus by one. Arrow keys step too: Right or Up advances, Left or Down retreats. Each of these snaps the focus to the target and renders synchronously. + +Acceptance Criteria + +- **FR-12 (Scrubber, buttons, and keys).** A range input scrubs the Z axis; its max is the last plane index. Prev and next buttons step the focus by one. Arrow keys step too: Right or Up advances, Left or Down retreats. Each of these snaps the focus to the target and renders synchronously. + +### REQ-threemdelement-013 + +The implementation SHALL satisfy the following criterion: **FR-13 (Read accessors).** `document` returns the parsed `Document` or `null` before load. `currentIndex` returns the rounded focus index. `mode` returns the active `Mode`. `goTo(index)` focuses a plane by index, clamped to range. + +Acceptance Criteria + +- **FR-13 (Read accessors).** `document` returns the parsed `Document` or `null` before load. `currentIndex` returns the rounded focus index. `mode` returns the active `Mode`. `goTo(index)` focuses a plane by index, clamped to range. + +### REQ-threemdelement-014 + +The implementation SHALL satisfy the following criterion: **FR-14 (planechange event).** When the rounded focus index changes, the element dispatches a single `planechange` `CustomEvent` whose detail is `{ index, z, label, plane }`. The event bubbles and is composed so it crosses the shadow boundary. It is not re-emitted while the focused index is unchanged. + +Acceptance Criteria + +- **FR-14 (planechange event).** When the rounded focus index changes, the element dispatches a single `planechange` `CustomEvent` whose detail is `{ index, z, label, plane }`. The event bubbles and is composed so it crosses the shadow boundary. It is not re-emitted while the focused index is unchanged. + +### REQ-threemdelement-015 + +The implementation SHALL satisfy the following criterion: **FR-15 (Plane rendering and Markdown subset).** Each plane renders a tag line (its `z` and `label`, or `z ` when unlabeled) plus a body rendered with a deliberately small Markdown subset: headings, ordered and unordered list items, task items, blockquotes, inline code, bold, italic, and a fenced-block grid. All text is HTML-escaped before formatting. + +Acceptance Criteria + +- **FR-15 (Plane rendering and Markdown subset).** Each plane renders a tag line (its `z` and `label`, or `z ` when unlabeled) plus a body rendered with a deliberately small Markdown subset: headings, ordered and unordered list items, task items, blockquotes, inline code, bold, italic, and a fenced-block grid. All text is HTML-escaped before formatting. + +### REQ-threemdelement-016 + +The implementation SHALL satisfy the following criterion: **FR-16 (Shadow DOM, theming, and parts).** The element attaches an open shadow root and isolates its styles there. It is themeable through CSS custom properties and exposes internals through `::part`: `wrap`, `axis`, `stage`, `arrow`, `scene`, `hint`, `controls`, `prev`, `scrubber`, `next`, `readout`, `plane`, `plane-title`, `plane-body`, `grid`, and `error`. ### Non-Functional Requirements + +Acceptance Criteria + +- **FR-16 (Shadow DOM, theming, and parts).** The element attaches an open shadow root and isolates its styles there. It is themeable through CSS custom properties and exposes internals through `::part`: `wrap`, `axis`, `stage`, `arrow`, `scene`, `hint`, `controls`, `prev`, `scrubber`, `next`, `readout`, `plane`, `plane-title`, `plane-body`, `grid`, and `error`. ### Non-Functional Requirements + +### REQ-threemdelement-017 + +The implementation SHALL satisfy the following criterion: **NFR-1 (Framework agnostic).** As a standard custom element, `` works unchanged in plain HTML and in React, Vue, Svelte, and Angular. There is one tested renderer, not a per-app reimplementation. + +Acceptance Criteria + +- **NFR-1 (Framework agnostic).** As a standard custom element, `` works unchanged in plain HTML and in React, Vue, Svelte, and Angular. There is one tested renderer, not a per-app reimplementation. + +### REQ-threemdelement-018 + +The implementation SHALL satisfy the following criterion: **NFR-2 (Cross-browser tested).** The element is covered in CI by the Playwright suite under `uitests/`, run in both Chromium and WebKit, guarding the three invariants and a clean console. + +Acceptance Criteria + +- **NFR-2 (Cross-browser tested).** The element is covered in CI by the Playwright suite under `uitests/`, run in both Chromium and WebKit, guarding the three invariants and a clean console. + +### REQ-threemdelement-019 + +The implementation SHALL satisfy the following criterion: **NFR-3 (Self-contained bundle).** The published bundle includes the parser, so loading the one module is enough; no separate parser script is required. + +Acceptance Criteria + +- **NFR-3 (Self-contained bundle).** The published bundle includes the parser, so loading the one module is enough; no separate parser script is required. + +### REQ-threemdelement-020 + +The implementation SHALL satisfy the following criterion: **NFR-4 (Style isolation).** All component styles live inside the shadow root so the host page cannot leak in and the component cannot leak out, except through the documented custom properties and parts. + +Acceptance Criteria + +- **NFR-4 (Style isolation).** All component styles live inside the shadow root so the host page cannot leak in and the component cannot leak out, except through the documented custom properties and parts. + +### REQ-threemdelement-021 + +The implementation SHALL satisfy the following criterion: **NFR-5 (Resilience).** The element degrades gracefully: it tolerates absent pointer capture, a missing `requestAnimationFrame`, fetch failures, and invalid source, surfacing problems through the error part rather than throwing. + +Acceptance Criteria + +- **NFR-5 (Resilience).** The element degrades gracefully: it tolerates absent pointer capture, a missing `requestAnimationFrame`, fetch failures, and invalid source, surfacing problems through the error part rather than throwing. + ## Acceptance Criteria ### Functional Requirements From 07dbe0302f3e524e48a7f16df4fa656b83f9782c Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 11 Jul 2026 22:52:25 -0600 Subject: [PATCH 02/16] fix(trust): avoid recursive SDD verification --- .specsync/sdd.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.specsync/sdd.json b/.specsync/sdd.json index 8c0c624..af288fe 100644 --- a/.specsync/sdd.json +++ b/.specsync/sdd.json @@ -33,7 +33,7 @@ "specs/" ], "verification_commands": [ - "fledge lanes run verify" + "swift test" ], "custom_artifacts": {}, "principles_file": null From 65ccd666e916f572bf3ad7ddc0cb75c1a6ac8fb1 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:12:23 -0600 Subject: [PATCH 03/16] Update: assign stable requirement IDs in place --- specs/ThreeMD/requirements.md | 260 +++++++++++---------------- specs/ThreeMDCLI/requirements.md | 72 +++----- specs/ThreeMDElement/requirements.md | 258 +++++++++++--------------- 3 files changed, 241 insertions(+), 349 deletions(-) diff --git a/specs/ThreeMD/requirements.md b/specs/ThreeMD/requirements.md index fcad5cd..984b1ed 100644 --- a/specs/ThreeMD/requirements.md +++ b/specs/ThreeMD/requirements.md @@ -20,277 +20,235 @@ numbered so tests and reviews can reference it directly. - As a tool author, I want to know what the Z axis means and how planes are ordered so I can lay a document out correctly. -## Durable Requirements +## Acceptance Criteria + +### Functional Requirements ### REQ-threemd-001 -The implementation SHALL satisfy the following criterion: **FR-1 (Frontmatter required).** `Parser.parse` requires a frontmatter block: a line containing exactly `---`, zero or more content lines, and a closing line containing exactly `---`. Leading blank lines before the opening fence are skipped. A source with no opening `---` throws `ParseError.missingFrontmatter`. A frontmatter block that is never closed throws `ParseError.invalidFrontmatter`. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-1 (Frontmatter required).** `Parser.parse` requires a frontmatter block: a line containing exactly `---`, zero or more content lines, and a closing line containing exactly `---`. Leading blank lines before the opening fence are skipped. A source with no opening `---` throws `ParseError.missingFrontmatter`. A frontmatter block that is never closed throws `ParseError.invalidFrontmatter`. +- `Parser.parse` requires a frontmatter block: + a line containing exactly `---`, zero or more content lines, and a closing + line containing exactly `---`. Leading blank lines before the opening fence + are skipped. A source with no opening `---` throws + `ParseError.missingFrontmatter`. A frontmatter block that is never closed + throws `ParseError.invalidFrontmatter`. ### REQ-threemd-002 -The implementation SHALL satisfy the following criterion: **FR-2 (Version marker required).** Frontmatter MUST declare a `3md` key whose value is non-empty. Its presence is the format's magic marker. The value is stored as `Document.version`. A missing or empty `3md` value throws `ParseError.missingVersion`. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-2 (Version marker required).** Frontmatter MUST declare a `3md` key whose value is non-empty. Its presence is the format's magic marker. The value is stored as `Document.version`. A missing or empty `3md` value throws `ParseError.missingVersion`. +- Frontmatter MUST declare a `3md` key whose + value is non-empty. Its presence is the format's magic marker. The value is + stored as `Document.version`. A missing or empty `3md` value throws + `ParseError.missingVersion`. ### REQ-threemd-003 -The implementation SHALL satisfy the following criterion: **FR-3 (Frontmatter fields).** Inside the fences, content lines are `key: value` pairs split on the first `:`. Blank lines and lines beginning with `#` are ignored. A non-blank, non-comment line with no `:` throws `ParseError.invalidFrontmatter`. Keys are matched case-insensitively. Values are trimmed, and a matching pair of surrounding single or double quotes is stripped. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-3 (Frontmatter fields).** Inside the fences, content lines are `key: value` pairs split on the first `:`. Blank lines and lines beginning with `#` are ignored. A non-blank, non-comment line with no `:` throws `ParseError.invalidFrontmatter`. Keys are matched case-insensitively. Values are trimmed, and a matching pair of surrounding single or double quotes is stripped. +- Inside the fences, content lines are + `key: value` pairs split on the first `:`. Blank lines and lines beginning + with `#` are ignored. A non-blank, non-comment line with no `:` throws + `ParseError.invalidFrontmatter`. Keys are matched case-insensitively. Values + are trimmed, and a matching pair of surrounding single or double quotes is + stripped. ### REQ-threemd-004 -The implementation SHALL satisfy the following criterion: **FR-4 (Axis handling and default).** The optional `axis` key sets `Document.axis`. The `Axis` value trims and lowercases its raw string, so `axis` is normalized. When no `axis` key is present, the axis defaults to `Axis.layer`. Any axis string is permitted; `time`, `depth`, `layer`, `frame`, and `space` are provided as named constants. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-4 (Axis handling and default).** The optional `axis` key sets `Document.axis`. The `Axis` value trims and lowercases its raw string, so `axis` is normalized. When no `axis` key is present, the axis defaults to `Axis.layer`. Any axis string is permitted; `time`, `depth`, `layer`, `frame`, and `space` are provided as named constants. +- The optional `axis` key sets + `Document.axis`. The `Axis` value trims and lowercases its raw string, so + `axis` is normalized. When no `axis` key is present, the axis defaults to + `Axis.layer`. Any axis string is permitted; `time`, `depth`, `layer`, + `frame`, and `space` are provided as named constants. ### REQ-threemd-005 -The implementation SHALL satisfy the following criterion: **FR-5 (Reserved frontmatter keys and metadata).** The keys `3md`, `axis`, and `title` are reserved. `title` populates the optional `Document.title`. Every other frontmatter key is preserved verbatim in `Document.metadata` as a `[String: String]` pair. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-5 (Reserved frontmatter keys and metadata).** The keys `3md`, `axis`, and `title` are reserved. `title` populates the optional `Document.title`. Every other frontmatter key is preserved verbatim in `Document.metadata` as a `[String: String]` pair. +- The keys `3md`, `axis`, and + `title` are reserved. `title` populates the optional `Document.title`. Every + other frontmatter key is preserved verbatim in `Document.metadata` as a + `[String: String]` pair. ### REQ-threemd-006 -The implementation SHALL satisfy the following criterion: **FR-6 (Plane directives).** A plane begins with a line whose first whitespace-delimited token is `@plane`, followed by space-separated `key=value` attributes. A token with no `=`, or with an empty key, throws `ParseError.invalidPlaneDirective`. Attribute keys are lowercased. Attribute values may be quoted with single or double quotes; the tokenizer keeps quoted spans intact so a value may contain spaces, and surrounding quotes are stripped. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-6 (Plane directives).** A plane begins with a line whose first whitespace-delimited token is `@plane`, followed by space-separated `key=value` attributes. A token with no `=`, or with an empty key, throws `ParseError.invalidPlaneDirective`. Attribute keys are lowercased. Attribute values may be quoted with single or double quotes; the tokenizer keeps quoted spans intact so a value may contain spaces, and surrounding quotes are stripped. +- A plane begins with a line whose first + whitespace-delimited token is `@plane`, followed by space-separated + `key=value` attributes. A token with no `=`, or with an empty key, throws + `ParseError.invalidPlaneDirective`. Attribute keys are lowercased. Attribute + values may be quoted with single or double quotes; the tokenizer keeps quoted + spans intact so a value may contain spaces, and surrounding quotes are + stripped. ### REQ-threemd-007 -The implementation SHALL satisfy the following criterion: **FR-7 (Required z attribute).** Each `@plane` directive MUST carry a `z` attribute. A directive with no `z` throws `ParseError.missingPlanePosition(line:)`. A `z` value that does not parse as a `Double` throws `ParseError.invalidPlaneDirective(line:detail:)`. Numbers may be integer or decimal and may be negative. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-7 (Required z attribute).** Each `@plane` directive MUST carry a `z` attribute. A directive with no `z` throws `ParseError.missingPlanePosition(line:)`. A `z` value that does not parse as a `Double` throws `ParseError.invalidPlaneDirective(line:detail:)`. Numbers may be integer or decimal and may be negative. +- Each `@plane` directive MUST carry a `z` + attribute. A directive with no `z` throws + `ParseError.missingPlanePosition(line:)`. A `z` value that does not parse as a + `Double` throws `ParseError.invalidPlaneDirective(line:detail:)`. Numbers may + be integer or decimal and may be negative. ### REQ-threemd-008 -The implementation SHALL satisfy the following criterion: **FR-8 (Optional x, y, label, and extra attributes).** The `x` and `y` attributes are optional in-plane offsets; when present each MUST parse as a `Double` or `ParseError.invalidPlaneDirective` is thrown. `label` is an optional human-readable string. The reserved plane attributes are `z`, `x`, `y`, and `label`; every other attribute is preserved in `Plane.attributes` as a `[String: String]` pair. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-8 (Optional x, y, label, and extra attributes).** The `x` and `y` attributes are optional in-plane offsets; when present each MUST parse as a `Double` or `ParseError.invalidPlaneDirective` is thrown. `label` is an optional human-readable string. The reserved plane attributes are `z`, `x`, `y`, and `label`; every other attribute is preserved in `Plane.attributes` as a `[String: String]` pair. +- The `x` and `y` + attributes are optional in-plane offsets; when present each MUST parse as a + `Double` or `ParseError.invalidPlaneDirective` is thrown. `label` is an + optional human-readable string. The reserved plane attributes are `z`, `x`, + `y`, and `label`; every other attribute is preserved in `Plane.attributes` as + a `[String: String]` pair. ### REQ-threemd-009 -The implementation SHALL satisfy the following criterion: **FR-9 (Plane body and preamble handling).** Every line after a directive, up to the next `@plane` directive or end of file, is that plane's Markdown body. Leading and trailing blank lines of a body are trimmed; an all-whitespace body collapses to an empty string. Markdown that appears after the frontmatter but before the first `@plane` directive is the document preamble, stored in the optional `Document.preamble` with the same blank-line trimming. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-9 (Plane body and preamble handling).** Every line after a directive, up to the next `@plane` directive or end of file, is that plane's Markdown body. Leading and trailing blank lines of a body are trimmed; an all-whitespace body collapses to an empty string. Markdown that appears after the frontmatter but before the first `@plane` directive is the document preamble, stored in the optional `Document.preamble` with the same blank-line trimming. +- Every line after a directive, up + to the next `@plane` directive or end of file, is that plane's Markdown body. + Leading and trailing blank lines of a body are trimmed; an all-whitespace + body collapses to an empty string. Markdown that appears after the + frontmatter but before the first `@plane` directive is the document preamble, + stored in the optional `Document.preamble` with the same blank-line trimming. ### REQ-threemd-010 -The implementation SHALL satisfy the following criterion: **FR-10 (Single-plane shorthand).** A document with frontmatter but no `@plane` directives whose remaining content is non-empty parses as exactly one implicit plane at `z = 0`, with that content as the plane body and a `nil` preamble. This makes a plain Markdown file with a 3md frontmatter header a valid one-plane document. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-10 (Single-plane shorthand).** A document with frontmatter but no `@plane` directives whose remaining content is non-empty parses as exactly one implicit plane at `z = 0`, with that content as the plane body and a `nil` preamble. This makes a plain Markdown file with a 3md frontmatter header a valid one-plane document. +- A document with frontmatter but no + `@plane` directives whose remaining content is non-empty parses as exactly one + implicit plane at `z = 0`, with that content as the plane body and a `nil` + preamble. This makes a plain Markdown file with a 3md frontmatter header a + valid one-plane document. ### REQ-threemd-011 -The implementation SHALL satisfy the following criterion: **FR-11 (Duplicate z rejection).** No two planes in a document may share the same `z` value. A repeated `z` throws `ParseError.duplicatePlane(z:)`. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-11 (Duplicate z rejection).** No two planes in a document may share the same `z` value. A repeated `z` throws `ParseError.duplicatePlane(z:)`. +- No two planes in a document may share the + same `z` value. A repeated `z` throws `ParseError.duplicatePlane(z:)`. ### REQ-threemd-012 -The implementation SHALL satisfy the following criterion: **FR-12 (Source order preserved).** `Document.planes` holds planes in source order. `Document.planesByZ` returns them sorted by ascending `z`, and `Document.plane(atZ:)` returns the first plane whose `z` equals the argument, or `nil`. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-12 (Source order preserved).** `Document.planes` holds planes in source order. `Document.planesByZ` returns them sorted by ascending `z`, and `Document.plane(atZ:)` returns the first plane whose `z` equals the argument, or `nil`. +- `Document.planes` holds planes in source + order. `Document.planesByZ` returns them sorted by ascending `z`, and + `Document.plane(atZ:)` returns the first plane whose `z` equals the argument, + or `nil`. ### REQ-threemd-013 -The implementation SHALL satisfy the following criterion: **FR-13 (Serialization).** `Serializer.render` produces 3md text. It always emits a frontmatter block with `3md` and `axis` lines, then `title` when set, then metadata keys sorted alphabetically. For each plane it emits an `@plane` directive (`z`, then `label`, `x`, `y` when set, then extra attributes sorted alphabetically) followed by the non-empty body. Whole-number doubles render as integers; `label` and extra attribute values are always quoted, and embedded double quotes are escaped. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-13 (Serialization).** `Serializer.render` produces 3md text. It always emits a frontmatter block with `3md` and `axis` lines, then `title` when set, then metadata keys sorted alphabetically. For each plane it emits an `@plane` directive (`z`, then `label`, `x`, `y` when set, then extra attributes sorted alphabetically) followed by the non-empty body. Whole-number doubles render as integers; `label` and extra attribute values are always quoted, and embedded double quotes are escaped. +- `Serializer.render` produces 3md text. It always + emits a frontmatter block with `3md` and `axis` lines, then `title` when set, + then metadata keys sorted alphabetically. For each plane it emits an `@plane` + directive (`z`, then `label`, `x`, `y` when set, then extra attributes sorted + alphabetically) followed by the non-empty body. Whole-number doubles render as + integers; `label` and extra attribute values are always quoted, and embedded + double quotes are escaped. ### REQ-threemd-014 -The implementation SHALL satisfy the following criterion: **FR-14 (Round-trip).** Serializing a `Document` and parsing the result yields an equal document, for content that does not rely on quote escaping. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-14 (Round-trip).** Serializing a `Document` and parsing the result yields an equal document, for content that does not rely on quote escaping. +- Serializing a `Document` and parsing the result yields + an equal document, for content that does not rely on quote escaping. ### REQ-threemd-015 -The implementation SHALL satisfy the following criterion: **FR-15 (Line-ending normalization).** Parsing normalizes `\r\n` to `\n` before processing, so Windows and Unix line endings parse identically. ### Non-Functional Requirements +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-15 (Line-ending normalization).** Parsing normalizes `\r\n` to `\n` before processing, so Windows and Unix line endings parse identically. ### Non-Functional Requirements +- Parsing normalizes `\r\n` to `\n` + before processing, so Windows and Unix line endings parse identically. + +### Non-Functional Requirements ### REQ-threemd-016 -The implementation SHALL satisfy the following criterion: **NFR-1 (Swift 6, cross-platform).** The module builds under Swift 6 strict concurrency and targets all supported Apple platforms, Linux, and Windows. It relies only on portable Foundation string handling. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-1 (Swift 6, cross-platform).** The module builds under Swift 6 strict concurrency and targets all supported Apple platforms, Linux, and Windows. It relies only on portable Foundation string handling. +- The module builds under Swift 6 strict + concurrency and targets all supported Apple platforms, Linux, and Windows. It + relies only on portable Foundation string handling. ### REQ-threemd-017 -The implementation SHALL satisfy the following criterion: **NFR-2 (Sendable value types).** `Axis`, `Plane`, `Document`, `ParseError`, `Parser`, and `Serializer` are `Sendable`. `Axis`, `Plane`, and `Document` are immutable value types that are also `Hashable` and `Codable`; `ParseError` is `Equatable`. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-2 (Sendable value types).** `Axis`, `Plane`, `Document`, `ParseError`, `Parser`, and `Serializer` are `Sendable`. `Axis`, `Plane`, and `Document` are immutable value types that are also `Hashable` and `Codable`; `ParseError` is `Equatable`. +- `Axis`, `Plane`, `Document`, `ParseError`, + `Parser`, and `Serializer` are `Sendable`. `Axis`, `Plane`, and `Document` + are immutable value types that are also `Hashable` and `Codable`; + `ParseError` is `Equatable`. ### REQ-threemd-018 -The implementation SHALL satisfy the following criterion: **NFR-3 (No force-unwrap).** Library code uses no force unwraps, `try!`, or `as!`. Optionals and failable conversions are handled with `guard` and typed throws. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-3 (No force-unwrap).** Library code uses no force unwraps, `try!`, or `as!`. Optionals and failable conversions are handled with `guard` and typed throws. +- Library code uses no force unwraps, `try!`, or + `as!`. Optionals and failable conversions are handled with `guard` and typed + throws. ### REQ-threemd-019 -The implementation SHALL satisfy the following criterion: **NFR-4 (Zero third-party dependencies).** The module depends only on Foundation. No third-party packages are used. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-4 (Zero third-party dependencies).** The module depends only on Foundation. No third-party packages are used. +- The module depends only on + Foundation. No third-party packages are used. ### REQ-threemd-020 -The implementation SHALL satisfy the following criterion: **NFR-5 (Deterministic parsing and serialization).** Parsing is pure: the same input always yields the same `Document`. Serialization is deterministic, ordering metadata and extra attributes alphabetically so output is stable. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-5 (Deterministic parsing and serialization).** Parsing is pure: the same input always yields the same `Document`. Serialization is deterministic, ordering metadata and extra attributes alphabetically so output is stable. - -## Acceptance Criteria - -### Functional Requirements - -- **FR-1 (Frontmatter required).** `Parser.parse` requires a frontmatter block: - a line containing exactly `---`, zero or more content lines, and a closing - line containing exactly `---`. Leading blank lines before the opening fence - are skipped. A source with no opening `---` throws - `ParseError.missingFrontmatter`. A frontmatter block that is never closed - throws `ParseError.invalidFrontmatter`. - -- **FR-2 (Version marker required).** Frontmatter MUST declare a `3md` key whose - value is non-empty. Its presence is the format's magic marker. The value is - stored as `Document.version`. A missing or empty `3md` value throws - `ParseError.missingVersion`. - -- **FR-3 (Frontmatter fields).** Inside the fences, content lines are - `key: value` pairs split on the first `:`. Blank lines and lines beginning - with `#` are ignored. A non-blank, non-comment line with no `:` throws - `ParseError.invalidFrontmatter`. Keys are matched case-insensitively. Values - are trimmed, and a matching pair of surrounding single or double quotes is - stripped. - -- **FR-4 (Axis handling and default).** The optional `axis` key sets - `Document.axis`. The `Axis` value trims and lowercases its raw string, so - `axis` is normalized. When no `axis` key is present, the axis defaults to - `Axis.layer`. Any axis string is permitted; `time`, `depth`, `layer`, - `frame`, and `space` are provided as named constants. - -- **FR-5 (Reserved frontmatter keys and metadata).** The keys `3md`, `axis`, and - `title` are reserved. `title` populates the optional `Document.title`. Every - other frontmatter key is preserved verbatim in `Document.metadata` as a - `[String: String]` pair. - -- **FR-6 (Plane directives).** A plane begins with a line whose first - whitespace-delimited token is `@plane`, followed by space-separated - `key=value` attributes. A token with no `=`, or with an empty key, throws - `ParseError.invalidPlaneDirective`. Attribute keys are lowercased. Attribute - values may be quoted with single or double quotes; the tokenizer keeps quoted - spans intact so a value may contain spaces, and surrounding quotes are - stripped. - -- **FR-7 (Required z attribute).** Each `@plane` directive MUST carry a `z` - attribute. A directive with no `z` throws - `ParseError.missingPlanePosition(line:)`. A `z` value that does not parse as a - `Double` throws `ParseError.invalidPlaneDirective(line:detail:)`. Numbers may - be integer or decimal and may be negative. - -- **FR-8 (Optional x, y, label, and extra attributes).** The `x` and `y` - attributes are optional in-plane offsets; when present each MUST parse as a - `Double` or `ParseError.invalidPlaneDirective` is thrown. `label` is an - optional human-readable string. The reserved plane attributes are `z`, `x`, - `y`, and `label`; every other attribute is preserved in `Plane.attributes` as - a `[String: String]` pair. - -- **FR-9 (Plane body and preamble handling).** Every line after a directive, up - to the next `@plane` directive or end of file, is that plane's Markdown body. - Leading and trailing blank lines of a body are trimmed; an all-whitespace - body collapses to an empty string. Markdown that appears after the - frontmatter but before the first `@plane` directive is the document preamble, - stored in the optional `Document.preamble` with the same blank-line trimming. - -- **FR-10 (Single-plane shorthand).** A document with frontmatter but no - `@plane` directives whose remaining content is non-empty parses as exactly one - implicit plane at `z = 0`, with that content as the plane body and a `nil` - preamble. This makes a plain Markdown file with a 3md frontmatter header a - valid one-plane document. - -- **FR-11 (Duplicate z rejection).** No two planes in a document may share the - same `z` value. A repeated `z` throws `ParseError.duplicatePlane(z:)`. - -- **FR-12 (Source order preserved).** `Document.planes` holds planes in source - order. `Document.planesByZ` returns them sorted by ascending `z`, and - `Document.plane(atZ:)` returns the first plane whose `z` equals the argument, - or `nil`. - -- **FR-13 (Serialization).** `Serializer.render` produces 3md text. It always - emits a frontmatter block with `3md` and `axis` lines, then `title` when set, - then metadata keys sorted alphabetically. For each plane it emits an `@plane` - directive (`z`, then `label`, `x`, `y` when set, then extra attributes sorted - alphabetically) followed by the non-empty body. Whole-number doubles render as - integers; `label` and extra attribute values are always quoted, and embedded - double quotes are escaped. - -- **FR-14 (Round-trip).** Serializing a `Document` and parsing the result yields - an equal document, for content that does not rely on quote escaping. - -- **FR-15 (Line-ending normalization).** Parsing normalizes `\r\n` to `\n` - before processing, so Windows and Unix line endings parse identically. - -### Non-Functional Requirements - -- **NFR-1 (Swift 6, cross-platform).** The module builds under Swift 6 strict - concurrency and targets all supported Apple platforms, Linux, and Windows. It - relies only on portable Foundation string handling. - -- **NFR-2 (Sendable value types).** `Axis`, `Plane`, `Document`, `ParseError`, - `Parser`, and `Serializer` are `Sendable`. `Axis`, `Plane`, and `Document` - are immutable value types that are also `Hashable` and `Codable`; - `ParseError` is `Equatable`. - -- **NFR-3 (No force-unwrap).** Library code uses no force unwraps, `try!`, or - `as!`. Optionals and failable conversions are handled with `guard` and typed - throws. - -- **NFR-4 (Zero third-party dependencies).** The module depends only on - Foundation. No third-party packages are used. - -- **NFR-5 (Deterministic parsing and serialization).** Parsing is pure: the same +- Parsing is pure: the same input always yields the same `Document`. Serialization is deterministic, ordering metadata and extra attributes alphabetically so output is stable. diff --git a/specs/ThreeMDCLI/requirements.md b/specs/ThreeMDCLI/requirements.md index 63612b5..dedc03d 100644 --- a/specs/ThreeMDCLI/requirements.md +++ b/specs/ThreeMDCLI/requirements.md @@ -13,105 +13,83 @@ These requirements describe the ThreeMDCLI Swift executable target: the command- - As a publisher, I want to compile a 3md document to HTML via stdout so I can render it for static web preview. - As a CI system, I want check-links to return non-zero exit codes on link failures so I can prevent broken builds. -## Durable Requirements +## Acceptance Criteria + +### Functional Requirements ### REQ-threemdcli-001 -The implementation SHALL satisfy the following criterion: **FR-1 (Subcommands).** The executable accepts one of the following subcommands as its first argument: `validate`, `info`, `html`, `links`, or `check-links`. Any other argument or a missing subcommand prints usage information and exits with code 1. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-1 (Subcommands).** The executable accepts one of the following subcommands as its first argument: `validate`, `info`, `html`, `links`, or `check-links`. Any other argument or a missing subcommand prints usage information and exits with code 1. - +- The executable accepts one of the following subcommands as its first argument: `validate`, `info`, `html`, `links`, or `check-links`. Any other argument or a missing subcommand prints usage information and exits with code 1. ### REQ-threemdcli-002 -The implementation SHALL satisfy the following criterion: **FR-2 (validate subcommand).** Parses the specified file. Prints "ok" and exits 0 on success. On parsing failure, prints the error details to stderr and exits 1. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-2 (validate subcommand).** Parses the specified file. Prints "ok" and exits 0 on success. On parsing failure, prints the error details to stderr and exits 1. - +- Parses the specified file. Prints "ok" and exits 0 on success. On parsing failure, prints the error details to stderr and exits 1. ### REQ-threemdcli-003 -The implementation SHALL satisfy the following criterion: **FR-3 (info subcommand).** Prints metadata (version, axis, title, plane count) and each plane's properties (z, label, coordinates, extra attributes). +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-3 (info subcommand).** Prints metadata (version, axis, title, plane count) and each plane's properties (z, label, coordinates, extra attributes). - +- Prints metadata (version, axis, title, plane count) and each plane's properties (z, label, coordinates, extra attributes). ### REQ-threemdcli-004 -The implementation SHALL satisfy the following criterion: **FR-4 (html subcommand).** Renders the document to HTML and prints the output to stdout. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-4 (html subcommand).** Renders the document to HTML and prints the output to stdout. - +- Renders the document to HTML and prints the output to stdout. ### REQ-threemdcli-005 -The implementation SHALL satisfy the following criterion: **FR-5 (links subcommand).** Extracts and prints all cross-plane links and the link graph representation. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-5 (links subcommand).** Extracts and prints all cross-plane links and the link graph representation. - +- Extracts and prints all cross-plane links and the link graph representation. ### REQ-threemdcli-006 -The implementation SHALL satisfy the following criterion: **FR-6 (check-links subcommand).** Validates all cross-plane links. If there are dangling links, it prints details to stderr and exits with code 1. If all links resolve, it prints "ok" and exits 0. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-6 (check-links subcommand).** Validates all cross-plane links. If there are dangling links, it prints details to stderr and exits with code 1. If all links resolve, it prints "ok" and exits 0. - +- Validates all cross-plane links. If there are dangling links, it prints details to stderr and exits with code 1. If all links resolve, it prints "ok" and exits 0. ### REQ-threemdcli-007 -The implementation SHALL satisfy the following criterion: **FR-7 (JSON output option).** The `validate`, `info`, `links`, and `check-links` subcommands support a `--json` flag. When provided, the command prints the output formatted as JSON to stdout instead of raw text. ### Non-Functional Requirements +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-7 (JSON output option).** The `validate`, `info`, `links`, and `check-links` subcommands support a `--json` flag. When provided, the command prints the output formatted as JSON to stdout instead of raw text. ### Non-Functional Requirements +- The `validate`, `info`, `links`, and `check-links` subcommands support a `--json` flag. When provided, the command prints the output formatted as JSON to stdout instead of raw text. + +### Non-Functional Requirements ### REQ-threemdcli-008 -The implementation SHALL satisfy the following criterion: **NFR-1 (Zero third-party dependencies).** The CLI target depends only on the local `ThreeMD` library target and Foundation. No external package manager or CLI parsing library is used. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-1 (Zero third-party dependencies).** The CLI target depends only on the local `ThreeMD` library target and Foundation. No external package manager or CLI parsing library is used. - +- The CLI target depends only on the local `ThreeMD` library target and Foundation. No external package manager or CLI parsing library is used. ### REQ-threemdcli-009 -The implementation SHALL satisfy the following criterion: **NFR-2 (Fast execution).** CommandLine parsing and execution are fast, with minimal startup overhead. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-2 (Fast execution).** CommandLine parsing and execution are fast, with minimal startup overhead. - +- CommandLine parsing and execution are fast, with minimal startup overhead. ### REQ-threemdcli-010 -The implementation SHALL satisfy the following criterion: **NFR-3 (Swift 6 Executable).** The executable builds cleanly under Swift 6 strict concurrency settings. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-3 (Swift 6 Executable).** The executable builds cleanly under Swift 6 strict concurrency settings. - -## Acceptance Criteria - -### Functional Requirements - -- **FR-1 (Subcommands).** The executable accepts one of the following subcommands as its first argument: `validate`, `info`, `html`, `links`, or `check-links`. Any other argument or a missing subcommand prints usage information and exits with code 1. -- **FR-2 (validate subcommand).** Parses the specified file. Prints "ok" and exits 0 on success. On parsing failure, prints the error details to stderr and exits 1. -- **FR-3 (info subcommand).** Prints metadata (version, axis, title, plane count) and each plane's properties (z, label, coordinates, extra attributes). -- **FR-4 (html subcommand).** Renders the document to HTML and prints the output to stdout. -- **FR-5 (links subcommand).** Extracts and prints all cross-plane links and the link graph representation. -- **FR-6 (check-links subcommand).** Validates all cross-plane links. If there are dangling links, it prints details to stderr and exits with code 1. If all links resolve, it prints "ok" and exits 0. -- **FR-7 (JSON output option).** The `validate`, `info`, `links`, and `check-links` subcommands support a `--json` flag. When provided, the command prints the output formatted as JSON to stdout instead of raw text. - -### Non-Functional Requirements - -- **NFR-1 (Zero third-party dependencies).** The CLI target depends only on the local `ThreeMD` library target and Foundation. No external package manager or CLI parsing library is used. -- **NFR-2 (Fast execution).** CommandLine parsing and execution are fast, with minimal startup overhead. -- **NFR-3 (Swift 6 Executable).** The executable builds cleanly under Swift 6 strict concurrency settings. +- The executable builds cleanly under Swift 6 strict concurrency settings. ## Constraints diff --git a/specs/ThreeMDElement/requirements.md b/specs/ThreeMDElement/requirements.md index 3bc1643..6744e7f 100644 --- a/specs/ThreeMDElement/requirements.md +++ b/specs/ThreeMDElement/requirements.md @@ -26,283 +26,239 @@ requirement is numbered so tests and reviews can reference it directly. - As an integrator, I want a `planechange` event and `document`, `currentIndex`, and `mode` reads so I can react to navigation from my own code. -## Durable Requirements +## Acceptance Criteria + +### Functional Requirements ### REQ-threemdelement-001 -The implementation SHALL satisfy the following criterion: **FR-1 (Parsing is delegated).** The element does not parse 3md text. It calls `parse` from `@corvidlabs/threemd` to turn source into a `Document` and reads `document.planes` and each plane's `z`, `x`, `y`, `label`, and `body`. The format grammar lives in `SPEC.md` and the shared parser; this element only renders the result. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-1 (Parsing is delegated).** The element does not parse 3md text. It calls `parse` from `@corvidlabs/threemd` to turn source into a `Document` and reads `document.planes` and each plane's `z`, `x`, `y`, `label`, and `body`. The format grammar lives in `SPEC.md` and the shared parser; this element only renders the result. +- The element does not parse 3md text. It calls + `parse` from `@corvidlabs/threemd` to turn source into a `Document` and reads + `document.planes` and each plane's `z`, `x`, `y`, `label`, and `body`. The + format grammar lives in `SPEC.md` and the shared parser; this element only + renders the result. ### REQ-threemdelement-002 -The implementation SHALL satisfy the following criterion: **FR-2 (Source resolution).** On connect, if the `src` attribute is set the element fetches that URL and renders the response text; otherwise it renders its inline text content. `setSource(text)` replaces the rendered document with new source at any time, building the DOM first if needed. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-2 (Source resolution).** On connect, if the `src` attribute is set the element fetches that URL and renders the response text; otherwise it renders its inline text content. `setSource(text)` replaces the rendered document with new source at any time, building the DOM first if needed. +- On connect, if the `src` attribute is set the + element fetches that URL and renders the response text; otherwise it renders + its inline text content. `setSource(text)` replaces the rendered document with + new source at any time, building the DOM first if needed. ### REQ-threemdelement-003 -The implementation SHALL satisfy the following criterion: **FR-3 (`src` fetch and staleness).** Fetching `src` is asynchronous and guarded by a load token: each load increments the token, and a response whose token no longer matches the latest is discarded. A non-ok HTTP status or a rejected request renders the error part with a message naming the source. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-3 (`src` fetch and staleness).** Fetching `src` is asynchronous and guarded by a load token: each load increments the token, and a response whose token no longer matches the latest is discarded. A non-ok HTTP status or a rejected request renders the error part with a message naming the source. +- Fetching `src` is asynchronous and + guarded by a load token: each load increments the token, and a response whose + token no longer matches the latest is discarded. A non-ok HTTP status or a + rejected request renders the error part with a message naming the source. ### REQ-threemdelement-004 -The implementation SHALL satisfy the following criterion: **FR-4 (Empty and invalid source).** Blank source (after trim) renders the error part with "No 3md source provided." When `parse` throws, the element renders the error part with "Invalid 3md: " and builds no planes. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-4 (Empty and invalid source).** Blank source (after trim) renders the error part with "No 3md source provided." When `parse` throws, the element renders the error part with "Invalid 3md: " and builds no planes. +- Blank source (after trim) renders the + error part with "No 3md source provided." When `parse` throws, the element + renders the error part with "Invalid 3md: " and builds no planes. ### REQ-threemdelement-005 -The implementation SHALL satisfy the following criterion: **FR-5 (Observed attributes).** `observedAttributes` is `["src", "mode"]`. Changing `src` triggers a fetch and render; changing `mode` re-applies the mode and re-renders. Attribute changes before the element has built its DOM are ignored until connect. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-5 (Observed attributes).** `observedAttributes` is `["src", "mode"]`. Changing `src` triggers a fetch and render; changing `mode` re-applies the mode and re-renders. Attribute changes before the element has built its DOM are ignored until connect. +- `observedAttributes` is `["src", "mode"]`. + Changing `src` triggers a fetch and render; changing `mode` re-applies the mode + and re-renders. Attribute changes before the element has built its DOM are + ignored until connect. ### REQ-threemdelement-006 -The implementation SHALL satisfy the following criterion: **FR-6 (Mode selection).** The active `Mode` is one of `stack`, `play`, `layers`, `scene`, `parallax`, `present`, `elevator`. The `mode` attribute may be a `Mode` value or an axis name; an axis name (for example `time`, `frame`, `frames`, `layer`, `layers`, `depth`, `space`, `scene`, `slide`, `slides`, `deck`, `floor`, `floors`) maps to its mode. With no usable `mode` attribute, the mode is derived from `document.axis`, defaulting to `stack`. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-6 (Mode selection).** The active `Mode` is one of `stack`, `play`, `layers`, `scene`, `parallax`, `present`, `elevator`. The `mode` attribute may be a `Mode` value or an axis name; an axis name (for example `time`, `frame`, `frames`, `layer`, `layers`, `depth`, `space`, `scene`, `slide`, `slides`, `deck`, `floor`, `floors`) maps to its mode. With no usable `mode` attribute, the mode is derived from `document.axis`, defaulting to `stack`. +- The active `Mode` is one of `stack`, `play`, + `layers`, `scene`, `parallax`, `present`, `elevator`. The `mode` attribute may + be a `Mode` value or an axis name; an axis name (for example `time`, `frame`, + `frames`, `layer`, `layers`, `depth`, `space`, `scene`, `slide`, `slides`, + `deck`, `floor`, `floors`) maps to its mode. With no usable `mode` attribute, + the mode is derived from `document.axis`, defaulting to `stack`. ### REQ-threemdelement-007 -The implementation SHALL satisfy the following criterion: **FR-7 (Focus-relative layout).** Each plane is positioned by its distance from the focus, `d = idx - focus`, so the focused plane is frontmost at the largest true Z. The layout MUST NOT pin a fixed plane to the front, because Safari paints by true Z and ignores `z-index` inside `preserve-3d`. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-7 (Focus-relative layout).** Each plane is positioned by its distance from the focus, `d = idx - focus`, so the focused plane is frontmost at the largest true Z. The layout MUST NOT pin a fixed plane to the front, because Safari paints by true Z and ignores `z-index` inside `preserve-3d`. +- Each plane is positioned by its distance + from the focus, `d = idx - focus`, so the focused plane is frontmost at the + largest true Z. The layout MUST NOT pin a fixed plane to the front, because + Safari paints by true Z and ignores `z-index` inside `preserve-3d`. ### REQ-threemdelement-008 -The implementation SHALL satisfy the following criterion: **FR-8 (Synchronous render).** `render()` applies all current state to the DOM synchronously and is the single source of truth for the stage. It is called on every interaction (scrub, drag, step, key, pointer up) and does not depend on `requestAnimationFrame`. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-8 (Synchronous render).** `render()` applies all current state to the DOM synchronously and is the single source of truth for the stage. It is called on every interaction (scrub, drag, step, key, pointer up) and does not depend on `requestAnimationFrame`. +- `render()` applies all current state to the DOM + synchronously and is the single source of truth for the stage. It is called on + every interaction (scrub, drag, step, key, pointer up) and does not depend on + `requestAnimationFrame`. ### REQ-threemdelement-009 -The implementation SHALL satisfy the following criterion: **FR-9 (Optional animation loop).** The `requestAnimationFrame` loop adds only gentle idle drift and is progressive enhancement. Every value it produces is also produced by a direct interaction plus a synchronous `render()`, so the element stays fully correct and usable when rAF is throttled or never fires (iOS Low Power Mode). The loop is started on connect and cancelled on disconnect. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-9 (Optional animation loop).** The `requestAnimationFrame` loop adds only gentle idle drift and is progressive enhancement. Every value it produces is also produced by a direct interaction plus a synchronous `render()`, so the element stays fully correct and usable when rAF is throttled or never fires (iOS Low Power Mode). The loop is started on connect and cancelled on disconnect. +- The `requestAnimationFrame` loop adds only + gentle idle drift and is progressive enhancement. Every value it produces is + also produced by a direct interaction plus a synchronous `render()`, so the + element stays fully correct and usable when rAF is throttled or never fires + (iOS Low Power Mode). The loop is started on connect and cancelled on + disconnect. ### REQ-threemdelement-010 -The implementation SHALL satisfy the following criterion: **FR-10 (Pointer interaction).** The stage handles `pointerdown`, `pointermove`, `pointerup`, and `pointercancel` through one unified path for mouse, touch, and pen. A vertical drag moves the focus along Z; a horizontal drag orbits the scene. Pointer capture is attempted and failures are tolerated. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-10 (Pointer interaction).** The stage handles `pointerdown`, `pointermove`, `pointerup`, and `pointercancel` through one unified path for mouse, touch, and pen. A vertical drag moves the focus along Z; a horizontal drag orbits the scene. Pointer capture is attempted and failures are tolerated. +- The stage handles `pointerdown`, + `pointermove`, `pointerup`, and `pointercancel` through one unified path for + mouse, touch, and pen. A vertical drag moves the focus along Z; a horizontal + drag orbits the scene. Pointer capture is attempted and failures are tolerated. ### REQ-threemdelement-011 -The implementation SHALL satisfy the following criterion: **FR-11 (Touch behavior and no overflow).** The stage sets `touch-action: none` so a finger drives the model rather than scrolling the page. The element is `max-width: 100%` and `box-sizing: border-box` and MUST NOT overflow horizontally at any width from 320px to 1440px. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-11 (Touch behavior and no overflow).** The stage sets `touch-action: none` so a finger drives the model rather than scrolling the page. The element is `max-width: 100%` and `box-sizing: border-box` and MUST NOT overflow horizontally at any width from 320px to 1440px. +- The stage sets + `touch-action: none` so a finger drives the model rather than scrolling the + page. The element is `max-width: 100%` and `box-sizing: border-box` and MUST + NOT overflow horizontally at any width from 320px to 1440px. ### REQ-threemdelement-012 -The implementation SHALL satisfy the following criterion: **FR-12 (Scrubber, buttons, and keys).** A range input scrubs the Z axis; its max is the last plane index. Prev and next buttons step the focus by one. Arrow keys step too: Right or Up advances, Left or Down retreats. Each of these snaps the focus to the target and renders synchronously. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-12 (Scrubber, buttons, and keys).** A range input scrubs the Z axis; its max is the last plane index. Prev and next buttons step the focus by one. Arrow keys step too: Right or Up advances, Left or Down retreats. Each of these snaps the focus to the target and renders synchronously. +- A range input scrubs the Z axis; its + max is the last plane index. Prev and next buttons step the focus by one. Arrow + keys step too: Right or Up advances, Left or Down retreats. Each of these snaps + the focus to the target and renders synchronously. ### REQ-threemdelement-013 -The implementation SHALL satisfy the following criterion: **FR-13 (Read accessors).** `document` returns the parsed `Document` or `null` before load. `currentIndex` returns the rounded focus index. `mode` returns the active `Mode`. `goTo(index)` focuses a plane by index, clamped to range. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-13 (Read accessors).** `document` returns the parsed `Document` or `null` before load. `currentIndex` returns the rounded focus index. `mode` returns the active `Mode`. `goTo(index)` focuses a plane by index, clamped to range. +- `document` returns the parsed `Document` or `null` + before load. `currentIndex` returns the rounded focus index. `mode` returns the + active `Mode`. `goTo(index)` focuses a plane by index, clamped to range. ### REQ-threemdelement-014 -The implementation SHALL satisfy the following criterion: **FR-14 (planechange event).** When the rounded focus index changes, the element dispatches a single `planechange` `CustomEvent` whose detail is `{ index, z, label, plane }`. The event bubbles and is composed so it crosses the shadow boundary. It is not re-emitted while the focused index is unchanged. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-14 (planechange event).** When the rounded focus index changes, the element dispatches a single `planechange` `CustomEvent` whose detail is `{ index, z, label, plane }`. The event bubbles and is composed so it crosses the shadow boundary. It is not re-emitted while the focused index is unchanged. +- When the rounded focus index changes, the + element dispatches a single `planechange` `CustomEvent` whose detail is + `{ index, z, label, plane }`. The event bubbles and is composed so it crosses + the shadow boundary. It is not re-emitted while the focused index is unchanged. ### REQ-threemdelement-015 -The implementation SHALL satisfy the following criterion: **FR-15 (Plane rendering and Markdown subset).** Each plane renders a tag line (its `z` and `label`, or `z ` when unlabeled) plus a body rendered with a deliberately small Markdown subset: headings, ordered and unordered list items, task items, blockquotes, inline code, bold, italic, and a fenced-block grid. All text is HTML-escaped before formatting. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-15 (Plane rendering and Markdown subset).** Each plane renders a tag line (its `z` and `label`, or `z ` when unlabeled) plus a body rendered with a deliberately small Markdown subset: headings, ordered and unordered list items, task items, blockquotes, inline code, bold, italic, and a fenced-block grid. All text is HTML-escaped before formatting. +- Each plane renders a tag line + (its `z` and `label`, or `z ` when unlabeled) plus a body rendered with + a deliberately small Markdown subset: headings, ordered and unordered list + items, task items, blockquotes, inline code, bold, italic, and a fenced-block + grid. All text is HTML-escaped before formatting. ### REQ-threemdelement-016 -The implementation SHALL satisfy the following criterion: **FR-16 (Shadow DOM, theming, and parts).** The element attaches an open shadow root and isolates its styles there. It is themeable through CSS custom properties and exposes internals through `::part`: `wrap`, `axis`, `stage`, `arrow`, `scene`, `hint`, `controls`, `prev`, `scrubber`, `next`, `readout`, `plane`, `plane-title`, `plane-body`, `grid`, and `error`. ### Non-Functional Requirements +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **FR-16 (Shadow DOM, theming, and parts).** The element attaches an open shadow root and isolates its styles there. It is themeable through CSS custom properties and exposes internals through `::part`: `wrap`, `axis`, `stage`, `arrow`, `scene`, `hint`, `controls`, `prev`, `scrubber`, `next`, `readout`, `plane`, `plane-title`, `plane-body`, `grid`, and `error`. ### Non-Functional Requirements +- The element attaches an open + shadow root and isolates its styles there. It is themeable through CSS custom + properties and exposes internals through `::part`: `wrap`, `axis`, `stage`, + `arrow`, `scene`, `hint`, `controls`, `prev`, `scrubber`, `next`, `readout`, + `plane`, `plane-title`, `plane-body`, `grid`, and `error`. + +### Non-Functional Requirements ### REQ-threemdelement-017 -The implementation SHALL satisfy the following criterion: **NFR-1 (Framework agnostic).** As a standard custom element, `` works unchanged in plain HTML and in React, Vue, Svelte, and Angular. There is one tested renderer, not a per-app reimplementation. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-1 (Framework agnostic).** As a standard custom element, `` works unchanged in plain HTML and in React, Vue, Svelte, and Angular. There is one tested renderer, not a per-app reimplementation. +- As a standard custom element, `` + works unchanged in plain HTML and in React, Vue, Svelte, and Angular. There is + one tested renderer, not a per-app reimplementation. ### REQ-threemdelement-018 -The implementation SHALL satisfy the following criterion: **NFR-2 (Cross-browser tested).** The element is covered in CI by the Playwright suite under `uitests/`, run in both Chromium and WebKit, guarding the three invariants and a clean console. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-2 (Cross-browser tested).** The element is covered in CI by the Playwright suite under `uitests/`, run in both Chromium and WebKit, guarding the three invariants and a clean console. +- The element is covered in CI by the Playwright + suite under `uitests/`, run in both Chromium and WebKit, guarding the three + invariants and a clean console. ### REQ-threemdelement-019 -The implementation SHALL satisfy the following criterion: **NFR-3 (Self-contained bundle).** The published bundle includes the parser, so loading the one module is enough; no separate parser script is required. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-3 (Self-contained bundle).** The published bundle includes the parser, so loading the one module is enough; no separate parser script is required. +- The published bundle includes the parser, so + loading the one module is enough; no separate parser script is required. ### REQ-threemdelement-020 -The implementation SHALL satisfy the following criterion: **NFR-4 (Style isolation).** All component styles live inside the shadow root so the host page cannot leak in and the component cannot leak out, except through the documented custom properties and parts. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-4 (Style isolation).** All component styles live inside the shadow root so the host page cannot leak in and the component cannot leak out, except through the documented custom properties and parts. +- All component styles live inside the shadow root + so the host page cannot leak in and the component cannot leak out, except + through the documented custom properties and parts. ### REQ-threemdelement-021 -The implementation SHALL satisfy the following criterion: **NFR-5 (Resilience).** The element degrades gracefully: it tolerates absent pointer capture, a missing `requestAnimationFrame`, fetch failures, and invalid source, surfacing problems through the error part rather than throwing. +The implementation SHALL satisfy this requirement. Acceptance Criteria -- **NFR-5 (Resilience).** The element degrades gracefully: it tolerates absent pointer capture, a missing `requestAnimationFrame`, fetch failures, and invalid source, surfacing problems through the error part rather than throwing. - -## Acceptance Criteria - -### Functional Requirements - -- **FR-1 (Parsing is delegated).** The element does not parse 3md text. It calls - `parse` from `@corvidlabs/threemd` to turn source into a `Document` and reads - `document.planes` and each plane's `z`, `x`, `y`, `label`, and `body`. The - format grammar lives in `SPEC.md` and the shared parser; this element only - renders the result. - -- **FR-2 (Source resolution).** On connect, if the `src` attribute is set the - element fetches that URL and renders the response text; otherwise it renders - its inline text content. `setSource(text)` replaces the rendered document with - new source at any time, building the DOM first if needed. - -- **FR-3 (`src` fetch and staleness).** Fetching `src` is asynchronous and - guarded by a load token: each load increments the token, and a response whose - token no longer matches the latest is discarded. A non-ok HTTP status or a - rejected request renders the error part with a message naming the source. - -- **FR-4 (Empty and invalid source).** Blank source (after trim) renders the - error part with "No 3md source provided." When `parse` throws, the element - renders the error part with "Invalid 3md: " and builds no planes. - -- **FR-5 (Observed attributes).** `observedAttributes` is `["src", "mode"]`. - Changing `src` triggers a fetch and render; changing `mode` re-applies the mode - and re-renders. Attribute changes before the element has built its DOM are - ignored until connect. - -- **FR-6 (Mode selection).** The active `Mode` is one of `stack`, `play`, - `layers`, `scene`, `parallax`, `present`, `elevator`. The `mode` attribute may - be a `Mode` value or an axis name; an axis name (for example `time`, `frame`, - `frames`, `layer`, `layers`, `depth`, `space`, `scene`, `slide`, `slides`, - `deck`, `floor`, `floors`) maps to its mode. With no usable `mode` attribute, - the mode is derived from `document.axis`, defaulting to `stack`. - -- **FR-7 (Focus-relative layout).** Each plane is positioned by its distance - from the focus, `d = idx - focus`, so the focused plane is frontmost at the - largest true Z. The layout MUST NOT pin a fixed plane to the front, because - Safari paints by true Z and ignores `z-index` inside `preserve-3d`. - -- **FR-8 (Synchronous render).** `render()` applies all current state to the DOM - synchronously and is the single source of truth for the stage. It is called on - every interaction (scrub, drag, step, key, pointer up) and does not depend on - `requestAnimationFrame`. - -- **FR-9 (Optional animation loop).** The `requestAnimationFrame` loop adds only - gentle idle drift and is progressive enhancement. Every value it produces is - also produced by a direct interaction plus a synchronous `render()`, so the - element stays fully correct and usable when rAF is throttled or never fires - (iOS Low Power Mode). The loop is started on connect and cancelled on - disconnect. - -- **FR-10 (Pointer interaction).** The stage handles `pointerdown`, - `pointermove`, `pointerup`, and `pointercancel` through one unified path for - mouse, touch, and pen. A vertical drag moves the focus along Z; a horizontal - drag orbits the scene. Pointer capture is attempted and failures are tolerated. - -- **FR-11 (Touch behavior and no overflow).** The stage sets - `touch-action: none` so a finger drives the model rather than scrolling the - page. The element is `max-width: 100%` and `box-sizing: border-box` and MUST - NOT overflow horizontally at any width from 320px to 1440px. - -- **FR-12 (Scrubber, buttons, and keys).** A range input scrubs the Z axis; its - max is the last plane index. Prev and next buttons step the focus by one. Arrow - keys step too: Right or Up advances, Left or Down retreats. Each of these snaps - the focus to the target and renders synchronously. - -- **FR-13 (Read accessors).** `document` returns the parsed `Document` or `null` - before load. `currentIndex` returns the rounded focus index. `mode` returns the - active `Mode`. `goTo(index)` focuses a plane by index, clamped to range. - -- **FR-14 (planechange event).** When the rounded focus index changes, the - element dispatches a single `planechange` `CustomEvent` whose detail is - `{ index, z, label, plane }`. The event bubbles and is composed so it crosses - the shadow boundary. It is not re-emitted while the focused index is unchanged. - -- **FR-15 (Plane rendering and Markdown subset).** Each plane renders a tag line - (its `z` and `label`, or `z ` when unlabeled) plus a body rendered with - a deliberately small Markdown subset: headings, ordered and unordered list - items, task items, blockquotes, inline code, bold, italic, and a fenced-block - grid. All text is HTML-escaped before formatting. - -- **FR-16 (Shadow DOM, theming, and parts).** The element attaches an open - shadow root and isolates its styles there. It is themeable through CSS custom - properties and exposes internals through `::part`: `wrap`, `axis`, `stage`, - `arrow`, `scene`, `hint`, `controls`, `prev`, `scrubber`, `next`, `readout`, - `plane`, `plane-title`, `plane-body`, `grid`, and `error`. - -### Non-Functional Requirements - -- **NFR-1 (Framework agnostic).** As a standard custom element, `` - works unchanged in plain HTML and in React, Vue, Svelte, and Angular. There is - one tested renderer, not a per-app reimplementation. - -- **NFR-2 (Cross-browser tested).** The element is covered in CI by the Playwright - suite under `uitests/`, run in both Chromium and WebKit, guarding the three - invariants and a clean console. - -- **NFR-3 (Self-contained bundle).** The published bundle includes the parser, so - loading the one module is enough; no separate parser script is required. - -- **NFR-4 (Style isolation).** All component styles live inside the shadow root - so the host page cannot leak in and the component cannot leak out, except - through the documented custom properties and parts. - -- **NFR-5 (Resilience).** The element degrades gracefully: it tolerates absent +- The element degrades gracefully: it tolerates absent pointer capture, a missing `requestAnimationFrame`, fetch failures, and invalid source, surfacing problems through the error part rather than throwing. From ac7142a319057f917c8185e4ca9811656a1ad0a9 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:42:52 -0600 Subject: [PATCH 04/16] Fix: address rollout review feedback --- .codex/skills/spec-sync/SKILL.md | 16 +++++++------- .cursor/commands/specsync-create-spec.md | 9 ++++---- .cursor/skills/spec-sync/SKILL.md | 16 +++++++------- .gemini/commands/specsync/create-change.toml | 2 +- .gemini/commands/specsync/create-spec.toml | 11 +++++----- .specsync/sdd.json | 22 ++++++++++++++++++-- CLAUDE.md | 2 +- 7 files changed, 47 insertions(+), 31 deletions(-) diff --git a/.codex/skills/spec-sync/SKILL.md b/.codex/skills/spec-sync/SKILL.md index de24d12..1a6ca94 100644 --- a/.codex/skills/spec-sync/SKILL.md +++ b/.codex/skills/spec-sync/SKILL.md @@ -9,6 +9,14 @@ This project uses [spec-sync](https://github.com/CorvidLabs/spec-sync) for bidir ## Companion files +Each canonical spec may have policy-selected companion files. Read and update the ones present; do not create empty companions only for ceremony: + +- **`tasks.md`** — Work items for this module. Check off tasks (`- [x]`) as you complete them. Add new tasks if you discover work needed. +- **`requirements.md`** — Acceptance criteria and user stories. These are permanent invariants, not tasks — do not check them off. Update if requirements change. +- **`context.md`** — Architectural decisions, key files, and current status. Update when you make design decisions or change what's in progress. +- **`testing.md`** — Test strategy: automated test locations, manual QA checklists, and edge cases/boundary conditions. +- **`design.md`** *(opt-in)* — Layout, component hierarchy, design tokens, and asset references. Present when `companions.design` is enabled in config. + ## Verified SDD change lifecycle (5.0) For every meaningful source, test, public documentation, schema, or configuration change: @@ -27,14 +35,6 @@ Never invent or self-grant either human approval. If an approved definition chan becomes stale and must be approved again. `specsync check` validates canonical specs plus approved active deltas, requirement-to-test evidence, change coverage, and CI gates. -Each canonical spec may have policy-selected companion files. Read and update the ones present; do not create empty companions only for ceremony: - -- **`tasks.md`** — Work items for this module. Check off tasks (`- [x]`) as you complete them. Add new tasks if you discover work needed. -- **`requirements.md`** — Acceptance criteria and user stories. These are permanent invariants, not tasks — do not check them off. Update if requirements change. -- **`context.md`** — Architectural decisions, key files, and current status. Update when you make design decisions or change what's in progress. -- **`testing.md`** — Test strategy: automated test locations, manual QA checklists, and edge cases/boundary conditions. -- **`design.md`** *(opt-in)* — Layout, component hierarchy, design tokens, and asset references. Present when `companions.design` is enabled in config. - ## Before modifying any module 1. Read the relevant spec in `specs//.spec.md` diff --git a/.cursor/commands/specsync-create-spec.md b/.cursor/commands/specsync-create-spec.md index 0f20b4c..84b88c7 100644 --- a/.cursor/commands/specsync-create-spec.md +++ b/.cursor/commands/specsync-create-spec.md @@ -2,12 +2,11 @@ Create a new spec-sync module spec. Arguments: $ARGUMENTS -1. Parse the arguments above: the first whitespace-separated token is the - module name. If the arguments also contain `--minimal` (in any position), - remove it and remember that minimal mode was requested. -2. Look at whatever text remains. It will be one of: +1. Remove `--minimal` wherever it appears and remember that minimal mode was + requested. Preserve the complete remaining text; do not tokenize it yet. +2. Classify the complete remaining text: - **A bare module name** — a short identifier like `auth-service` or - `billing`. Use it as-is. + `billing`, matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`. Use it as-is. - **A free-text feature description** — a sentence or phrase describing what to build, e.g. `"I want a feature that lets users export their data as CSV"`. In this case, invent a short, kebab-case module name that diff --git a/.cursor/skills/spec-sync/SKILL.md b/.cursor/skills/spec-sync/SKILL.md index de24d12..1a6ca94 100644 --- a/.cursor/skills/spec-sync/SKILL.md +++ b/.cursor/skills/spec-sync/SKILL.md @@ -9,6 +9,14 @@ This project uses [spec-sync](https://github.com/CorvidLabs/spec-sync) for bidir ## Companion files +Each canonical spec may have policy-selected companion files. Read and update the ones present; do not create empty companions only for ceremony: + +- **`tasks.md`** — Work items for this module. Check off tasks (`- [x]`) as you complete them. Add new tasks if you discover work needed. +- **`requirements.md`** — Acceptance criteria and user stories. These are permanent invariants, not tasks — do not check them off. Update if requirements change. +- **`context.md`** — Architectural decisions, key files, and current status. Update when you make design decisions or change what's in progress. +- **`testing.md`** — Test strategy: automated test locations, manual QA checklists, and edge cases/boundary conditions. +- **`design.md`** *(opt-in)* — Layout, component hierarchy, design tokens, and asset references. Present when `companions.design` is enabled in config. + ## Verified SDD change lifecycle (5.0) For every meaningful source, test, public documentation, schema, or configuration change: @@ -27,14 +35,6 @@ Never invent or self-grant either human approval. If an approved definition chan becomes stale and must be approved again. `specsync check` validates canonical specs plus approved active deltas, requirement-to-test evidence, change coverage, and CI gates. -Each canonical spec may have policy-selected companion files. Read and update the ones present; do not create empty companions only for ceremony: - -- **`tasks.md`** — Work items for this module. Check off tasks (`- [x]`) as you complete them. Add new tasks if you discover work needed. -- **`requirements.md`** — Acceptance criteria and user stories. These are permanent invariants, not tasks — do not check them off. Update if requirements change. -- **`context.md`** — Architectural decisions, key files, and current status. Update when you make design decisions or change what's in progress. -- **`testing.md`** — Test strategy: automated test locations, manual QA checklists, and edge cases/boundary conditions. -- **`design.md`** *(opt-in)* — Layout, component hierarchy, design tokens, and asset references. Present when `companions.design` is enabled in config. - ## Before modifying any module 1. Read the relevant spec in `specs//.spec.md` diff --git a/.gemini/commands/specsync/create-change.toml b/.gemini/commands/specsync/create-change.toml index b4b7de6..bf8185a 100644 --- a/.gemini/commands/specsync/create-change.toml +++ b/.gemini/commands/specsync/create-change.toml @@ -3,7 +3,7 @@ description = "Create and guide a verified spec-sync SDD change through its dete prompt = """ Arguments: {{args}} -1. Run `specsync change new "$ARGUMENTS" --json`. +1. Run `specsync change new "{{args}}" --json`. 2. Read the returned `questions` array and interview the user one question at a time. 3. Record each answer with `specsync change answer --json`. 4. Continue until the question list is empty, then show the selected artifacts and next action. diff --git a/.gemini/commands/specsync/create-spec.toml b/.gemini/commands/specsync/create-spec.toml index 73789f1..6d34792 100644 --- a/.gemini/commands/specsync/create-spec.toml +++ b/.gemini/commands/specsync/create-spec.toml @@ -5,12 +5,11 @@ Create a new spec-sync module spec. Arguments: {{args}} -1. Parse the arguments above: the first whitespace-separated token is the - module name. If the arguments also contain --minimal (in any position), - remove it and remember that minimal mode was requested. -2. Look at whatever text remains. It will be one of: - - A bare module name - a short identifier like auth-service or billing. - Use it as-is. +1. Remove --minimal wherever it appears and remember that minimal mode was + requested. Preserve the complete remaining text; do not tokenize it yet. +2. Classify the complete remaining text: + - A bare module name - a short identifier like auth-service or billing, + matching ^[A-Za-z0-9][A-Za-z0-9._-]*$. Use it as-is. - A free-text feature description - a sentence or phrase describing what to build, e.g. "I want a feature that lets users export their data as CSV". In this case, invent a short, kebab-case module name that captures diff --git a/.specsync/sdd.json b/.specsync/sdd.json index af288fe..76c8014 100644 --- a/.specsync/sdd.json +++ b/.specsync/sdd.json @@ -26,14 +26,32 @@ ".specsync/config.toml", ".specsync/config.json", ".specsync/version", - "Sources/" + "Sources/", + "Tests/", + "Examples/", + "conformance/", + "editor/", + "element/", + "js/", + "rust/", + "uitests/", + "web/", + "scripts/", + "SPEC.md", + "fledge.toml", + ".trust.toml", + ".augur.toml", + ".attest.json", + "AGENTS.md", + "CLAUDE.md" ], "ignored_paths": [ ".specsync/", "specs/" ], "verification_commands": [ - "swift test" + "fledge lanes run verify", + "fledge trust doctor" ], "custom_artifacts": {}, "principles_file": null diff --git a/CLAUDE.md b/CLAUDE.md index c59745e..268b063 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,3 +1,3 @@ # CLAUDE.md -This repo is governed by the CorvidLabs trust toolchain. Read AGENTS.md and follow the standing rules block before making changes (run `fledge lanes run verify`; never bypass augur/attest/spec gates). +This repo is governed by the CorvidLabs trust toolchain. Read AGENTS.md and follow the standing rules block before making changes. Run `fledge trust verify` before calling work complete; never bypass or weaken its lifecycle, contract, risk, or provenance gates. From c3b2332f41a006c35051fa23f60f0187c5db79f0 Mon Sep 17 00:00:00 2001 From: 0xLeif Date: Sun, 12 Jul 2026 16:31:12 -0600 Subject: [PATCH 05/16] fix(governance): track Claude SpecSync integration --- .claude/commands/specsync/create-change.md | 10 +++ .claude/commands/specsync/create-spec.md | 40 ++++++++++++ .claude/skills/spec-sync/SKILL.md | 75 ++++++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 .claude/commands/specsync/create-change.md create mode 100644 .claude/commands/specsync/create-spec.md create mode 100644 .claude/skills/spec-sync/SKILL.md diff --git a/.claude/commands/specsync/create-change.md b/.claude/commands/specsync/create-change.md new file mode 100644 index 0000000..04707cc --- /dev/null +++ b/.claude/commands/specsync/create-change.md @@ -0,0 +1,10 @@ +--- +description: Create and guide a verified spec-sync SDD change through its deterministic interview +argument-hint: +--- + +1. Run `specsync change new "$ARGUMENTS" --json`. +2. Read the returned `questions` array and interview the user one question at a time. +3. Record each answer with `specsync change answer --json`. +4. Continue until the question list is empty, then show the selected artifacts and next action. +5. Do not approve, implement, verify, accept, or archive until the corresponding human gate or work stage is reached. diff --git a/.claude/commands/specsync/create-spec.md b/.claude/commands/specsync/create-spec.md new file mode 100644 index 0000000..a424e76 --- /dev/null +++ b/.claude/commands/specsync/create-spec.md @@ -0,0 +1,40 @@ +--- +description: Scaffold a new spec-sync module spec from a module name or a natural-language feature description (full scaffold by default, or minimal with --minimal) +argument-hint: [--minimal] +--- + +Create a new spec-sync module spec. + +Arguments: `$ARGUMENTS` + +1. Parse the arguments above: the first whitespace-separated token is the + module name. If the arguments also contain `--minimal` (in any position), + remove it and remember that minimal mode was requested. +2. Look at whatever text remains. It will be one of: + - **A bare module name** — a short identifier like `auth-service` or + `billing`. Use it as-is. + - **A free-text feature description** — a sentence or phrase describing + what to build, e.g. `"I want a feature that lets users export their + data as CSV"`. In this case, invent a short, kebab-case module name that + captures the idea (e.g. `csv-export`). If the right name is ambiguous, + ask the user to confirm or rename it before continuing. Keep the full + description at hand — you'll use it in step 5. +3. If minimal mode was requested, run: + ``` + specsync new + ``` + This creates a minimal spec only (no companion files). +4. Otherwise (default), run: + ``` + specsync scaffold + ``` + This creates the spec, companion files (`tasks.md`, `requirements.md`, + `context.md`, `testing.md`, and `design.md` if `companions.design` is + enabled), a registry entry, and auto-detects related source files. +5. Open the newly created `specs//.spec.md` and fill + in the `Purpose`, `Requirements`, and `Public API` sections. If a free-text + description was given in step 2, use it directly to draft these sections — + ask clarifying questions if it's underspecified, but do not leave the + sections as unfilled placeholder text. Do the same for `requirements.md` + (acceptance criteria) and `tasks.md` (initial task breakdown), if present. +6. Run `specsync check` to confirm the new spec passes validation. diff --git a/.claude/skills/spec-sync/SKILL.md b/.claude/skills/spec-sync/SKILL.md new file mode 100644 index 0000000..de24d12 --- /dev/null +++ b/.claude/skills/spec-sync/SKILL.md @@ -0,0 +1,75 @@ +--- +name: spec-sync +description: Keep markdown module specs in specs// synchronized with source code using spec-sync. Use this whenever creating, editing, or reviewing code in a module that has (or should have) a spec, or whenever the user mentions specs, spec-sync, companion files (tasks.md/requirements.md/context.md/testing.md/design.md), or asks to add/update a module's documentation. +--- + +# Spec-Sync Workflow + +This project uses [spec-sync](https://github.com/CorvidLabs/spec-sync) for bidirectional spec-to-code validation. Specs live in `specs//.spec.md`. + +## Companion files + +## Verified SDD change lifecycle (5.0) + +For every meaningful source, test, public documentation, schema, or configuration change: + +1. Run `specsync change new "" --json` and conduct the returned interview with the user. +2. Use `specsync change answer --json` until no questions remain. +3. Complete the adaptively selected artifacts and semantic deltas. Requirements use stable + `REQ--` IDs, a normative SHALL statement, and acceptance criteria. +4. Ask the user for the definition approval, then run `specsync change approve `. +5. Run `specsync change start ` before editing implementation code. +6. Keep tasks and artifacts current, then run `specsync change verify `. +7. Present verification evidence and ask for closing approval. Only after explicit approval, + run `specsync change accept `; archive separately with `specsync change archive `. + +Never invent or self-grant either human approval. If an approved definition changes, its digest +becomes stale and must be approved again. `specsync check` validates canonical specs plus approved +active deltas, requirement-to-test evidence, change coverage, and CI gates. + +Each canonical spec may have policy-selected companion files. Read and update the ones present; do not create empty companions only for ceremony: + +- **`tasks.md`** — Work items for this module. Check off tasks (`- [x]`) as you complete them. Add new tasks if you discover work needed. +- **`requirements.md`** — Acceptance criteria and user stories. These are permanent invariants, not tasks — do not check them off. Update if requirements change. +- **`context.md`** — Architectural decisions, key files, and current status. Update when you make design decisions or change what's in progress. +- **`testing.md`** — Test strategy: automated test locations, manual QA checklists, and edge cases/boundary conditions. +- **`design.md`** *(opt-in)* — Layout, component hierarchy, design tokens, and asset references. Present when `companions.design` is enabled in config. + +## Before modifying any module + +1. Read the relevant spec in `specs//.spec.md` +2. Read whichever companion files are present (`requirements.md`, `tasks.md`, `context.md`, `testing.md`, `design.md`, or project-defined files) +3. After changes, run `specsync check` to verify specs still pass + +## After completing work + +1. Mark completed items in `tasks.md` — check off finished tasks, add new ones discovered +2. Update `context.md` — record decisions made, update current status +3. If requirements changed, update `requirements.md` acceptance criteria +4. If test coverage changed, update `testing.md` with new test files or edge cases +5. If UI/layout changed, update `design.md` with revised layout, components, or tokens + +## Before creating a PR + +Run `specsync check --strict` — all specs must pass with zero warnings. + +## When adding new modules + +Run `specsync scaffold ` to create a spec, companion files, a registry +entry, and auto-detected source files — or `specsync new ` for a +minimal spec-only draft. Complete the spec before writing code. The +`/specsync:create-spec` command (or tool-equivalent) runs this for you, and +accepts either a bare module name or a natural-language feature description +(e.g. `/specsync:create-spec "I want a feature that lets users export their +data as CSV"`) — pass a description and it will pick a module name and use +the description to draft the spec's Purpose and Requirements. + +## Key commands + +- `specsync check` — validate all specs against source code +- `specsync check --json` — machine-readable validation output +- `specsync coverage` — show which modules lack specs +- `specsync score` — quality score for each spec (0-100) +- `specsync scaffold ` — full scaffold: spec + companions + registry entry + source detection +- `specsync new ` — quick-create a minimal spec (add `--full` for companions) +- `specsync resolve --remote` — verify cross-project dependencies From e6249695b7672eb8c8326a99fa673fb23ac85efd Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sun, 12 Jul 2026 16:40:43 -0600 Subject: [PATCH 06/16] Fix: separate native verification from SpecSync orchestration --- .../CHG-0001-adopt-trust-1-and-specsync-5/state.json | 8 +++++++- .specsync/sdd.json | 6 +++++- fledge.toml | 12 ++++-------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json index 8958600..cd8f0bb 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json @@ -13,9 +13,15 @@ "affected_paths": [ ".github/workflows/trust.yml", ".specsync/", + ".claude/", + ".codex/", + ".cursor/", + ".gemini/", ".trust.toml", ".augur.toml", - "AGENTS.md" + "AGENTS.md", + "CLAUDE.md", + "fledge.toml" ], "no_spec_change": true, "no_spec_change_rationale": "Tooling policy migration; no product API or canonical module contract changes.", diff --git a/.specsync/sdd.json b/.specsync/sdd.json index 76c8014..e7ee27e 100644 --- a/.specsync/sdd.json +++ b/.specsync/sdd.json @@ -43,7 +43,11 @@ ".augur.toml", ".attest.json", "AGENTS.md", - "CLAUDE.md" + "CLAUDE.md", + ".claude/", + ".codex/", + ".cursor/", + ".gemini/" ], "ignored_paths": [ ".specsync/", diff --git a/fledge.toml b/fledge.toml index 6bf0759..f86fab4 100644 --- a/fledge.toml +++ b/fledge.toml @@ -33,17 +33,13 @@ cmd = "bun install --frozen-lockfile && bun test" dir = "js" description = "TypeScript port: install and run the test suite (the shared conformance vectors)." -[tasks.spec] -cmd = "fledge spec check" -description = "spec-sync: every module spec matches its tracked source files." - [lanes.verify] -description = "The single CI gate: all three parser implementations, generated element bundle drift, editor grammar, and spec-sync." -steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor", "spec"] +description = "Native verification for all three parser implementations, generated element bundle drift, and editor grammar. Trust runs SpecSync after this lane." +steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor"] [lanes.ci] -description = "Alias for the verify gate." -steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor", "spec"] +description = "Alias for the native verify lane." +steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor"] [lanes.ui] description = "Browser UI suite for the published web surfaces." From 1d12ef5f068c231995d9ad1fc9cc31a515ac8f5e Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sun, 12 Jul 2026 17:03:02 -0600 Subject: [PATCH 07/16] Fix: remove unavailable nested Trust doctor command --- .specsync/sdd.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.specsync/sdd.json b/.specsync/sdd.json index e7ee27e..de28516 100644 --- a/.specsync/sdd.json +++ b/.specsync/sdd.json @@ -54,8 +54,7 @@ "specs/" ], "verification_commands": [ - "fledge lanes run verify", - "fledge trust doctor" + "fledge lanes run verify" ], "custom_artifacts": {}, "principles_file": null From 9f403cc843bb03b5c9b7688ac2f20ca1d52267ad Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Mon, 13 Jul 2026 13:41:16 -0600 Subject: [PATCH 08/16] fix(governance): make migration contracts exact and fully verified --- .claude/commands/specsync/create-change.md | 2 +- .claude/commands/specsync/create-spec.md | 9 ++-- .cursor/commands/specsync-create-change.md | 2 +- .gemini/commands/specsync/create-change.toml | 2 +- .../approvals.json | 14 +++++++ .../state.json | 4 +- .../tasks.md | 2 +- .../approvals.json | 7 ++++ .../change.md | 2 +- .../state.json | 4 +- .../verification.json | 16 +++++++ .trust.toml | 2 +- docs.3md | 17 ++++---- fledge.toml | 9 ++-- specs/ThreeMD/requirements.md | 40 +++++++++--------- specs/ThreeMDCLI/requirements.md | 20 ++++----- specs/ThreeMDElement/requirements.md | 42 +++++++++---------- web/docs.3md | 17 ++++---- 18 files changed, 126 insertions(+), 85 deletions(-) create mode 100644 .specsync/changes/CHG-0002-assign-stable-requirement-ids/verification.json diff --git a/.claude/commands/specsync/create-change.md b/.claude/commands/specsync/create-change.md index 04707cc..48571cd 100644 --- a/.claude/commands/specsync/create-change.md +++ b/.claude/commands/specsync/create-change.md @@ -5,6 +5,6 @@ argument-hint: 1. Run `specsync change new "$ARGUMENTS" --json`. 2. Read the returned `questions` array and interview the user one question at a time. -3. Record each answer with `specsync change answer --json`. +3. Record each answer with `specsync change answer "" --json`, quoting the answer so multi-word text is passed as one argument. 4. Continue until the question list is empty, then show the selected artifacts and next action. 5. Do not approve, implement, verify, accept, or archive until the corresponding human gate or work stage is reached. diff --git a/.claude/commands/specsync/create-spec.md b/.claude/commands/specsync/create-spec.md index a424e76..efef30a 100644 --- a/.claude/commands/specsync/create-spec.md +++ b/.claude/commands/specsync/create-spec.md @@ -7,12 +7,11 @@ Create a new spec-sync module spec. Arguments: `$ARGUMENTS` -1. Parse the arguments above: the first whitespace-separated token is the - module name. If the arguments also contain `--minimal` (in any position), - remove it and remember that minimal mode was requested. -2. Look at whatever text remains. It will be one of: +1. Remove `--minimal` wherever it appears and remember that minimal mode was + requested. Preserve the complete remaining text; do not tokenize it yet. +2. Classify the complete remaining text: - **A bare module name** — a short identifier like `auth-service` or - `billing`. Use it as-is. + `billing`, matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`. Use it as-is. - **A free-text feature description** — a sentence or phrase describing what to build, e.g. `"I want a feature that lets users export their data as CSV"`. In this case, invent a short, kebab-case module name that diff --git a/.cursor/commands/specsync-create-change.md b/.cursor/commands/specsync-create-change.md index 49402f3..4a27292 100644 --- a/.cursor/commands/specsync-create-change.md +++ b/.cursor/commands/specsync-create-change.md @@ -4,6 +4,6 @@ Arguments: $ARGUMENTS 1. Run `specsync change new "$ARGUMENTS" --json`. 2. Read the returned `questions` array and interview the user one question at a time. -3. Record each answer with `specsync change answer --json`. +3. Record each answer with `specsync change answer "" --json`, quoting the answer so multi-word text is passed as one argument. 4. Continue until the question list is empty, then show the selected artifacts and next action. 5. Do not approve, implement, verify, accept, or archive until the corresponding human gate or work stage is reached. diff --git a/.gemini/commands/specsync/create-change.toml b/.gemini/commands/specsync/create-change.toml index bf8185a..a82d113 100644 --- a/.gemini/commands/specsync/create-change.toml +++ b/.gemini/commands/specsync/create-change.toml @@ -5,7 +5,7 @@ Arguments: {{args}} 1. Run `specsync change new "{{args}}" --json`. 2. Read the returned `questions` array and interview the user one question at a time. -3. Record each answer with `specsync change answer --json`. +3. Record each answer with `specsync change answer "" --json`, quoting the answer so multi-word text is passed as one argument. 4. Continue until the question list is empty, then show the selected artifacts and next action. 5. Do not approve, implement, verify, accept, or archive until the corresponding human gate or work stage is reached. """ diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json index b48bda6..d3940c9 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json @@ -6,6 +6,20 @@ "timestamp": 1783826959, "digest": "79cfe2c4cd9797c14198de4d7f463d8f8b82125287963141c78c6d3b24157aec", "note": "Authorized by the user-approved CorvidLabs Trust 1 / SpecSync 5 rollout plan." + }, + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1783971616, + "digest": "706e408d448f153b152bddf0b13b85dd7c861f0d58642d32a9a06f30301c9e23", + "note": "Definition re-approved after reviewing the migration policy, all agent templates, generated documentation, and repository-specific requirement corrections; native and hosted closing evidence remain pending." + }, + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1783971650, + "digest": "77c9495b355f19a856d03e1a76f247c512f00beb33e011d66e068d839239351f", + "note": "Definition re-approved after the complete local verification lane and strict 100% contract passed; hosted pull-request checks and closing acceptance remain pending." } ] } diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json index cd8f0bb..559a987 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json @@ -8,7 +8,7 @@ "state": "implementing", "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", "created_at": 1783826867, - "updated_at": 1783826959, + "updated_at": 1783971650, "affected_specs": [], "affected_paths": [ ".github/workflows/trust.yml", @@ -21,6 +21,8 @@ ".augur.toml", "AGENTS.md", "CLAUDE.md", + "docs.3md", + "web/docs.3md", "fledge.toml" ], "no_spec_change": true, diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md index c7ee19c..ce20397 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md @@ -9,5 +9,5 @@ artifact: tasks - [x] Install Claude, Cursor, Codex, and Gemini integrations. - [x] Commit the standard Trust policy and Augur configuration. - [x] Consolidate the CI workflow on Trust 1.0.0. -- [ ] Pass local strict validation and the repository verify lane. +- [x] Pass local strict validation and the repository verify lane. - [ ] Pass hosted pull-request checks. diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/approvals.json b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/approvals.json index 25116b0..a71e942 100644 --- a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/approvals.json +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/approvals.json @@ -6,6 +6,13 @@ "timestamp": 1783827254, "digest": "dcb9541b9bbaef2158d04f0776225b9150255a95bc679f8dbaa7a26311efc798", "note": "Authorized by the user-approved CorvidLabs Trust 1 / SpecSync 5 rollout plan." + }, + { + "gate": "acceptance", + "actor": "user:0xLeif", + "timestamp": 1783971636, + "digest": "abc820de8a00833febd046960277b09ea308674755c6aaf828889982b7e3d39c", + "note": "Accepted after line-by-line review replaced every tautological generated statement with the exact existing repository behavior and the complete Swift, JavaScript, Rust, bundle, editor, and strict 100% SpecSync lane passed." } ] } diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/change.md b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/change.md index 3ca7459..f609240 100644 --- a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/change.md +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/change.md @@ -1,6 +1,6 @@ --- id: CHG-0002-assign-stable-requirement-ids -state: implementing +state: accepted type: documentation base_commit: 2a145766b9ecb83d96ee15aa453a65cc2125571f --- diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/state.json b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/state.json index eb57245..2e76461 100644 --- a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/state.json +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/state.json @@ -5,10 +5,10 @@ "title": "Assign stable requirement IDs", "description": "Assign stable requirement IDs", "kind": "documentation", - "state": "implementing", + "state": "accepted", "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", "created_at": 1783827126, - "updated_at": 1783827254, + "updated_at": 1783971636, "affected_specs": [], "affected_paths": [ "specs/" diff --git a/.specsync/changes/CHG-0002-assign-stable-requirement-ids/verification.json b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/verification.json new file mode 100644 index 0000000..24c37b6 --- /dev/null +++ b/.specsync/changes/CHG-0002-assign-stable-requirement-ids/verification.json @@ -0,0 +1,16 @@ +{ + "timestamp": 1783971631, + "commit": "1d12ef5f068c231995d9ad1fc9cc31a515ac8f5e", + "contract_digest": "dcb9541b9bbaef2158d04f0776225b9150255a95bc679f8dbaa7a26311efc798", + "workspace_digest": "86c82a232f75d242a0ed41a77139d8aabe5348ff88b71d972684d3bfcc64cc85", + "acceptance_input_digest": "b12b187ff602d25fdf8935659d4919ead49d9317a04c86867358ed2fbed06371", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [] +} diff --git a/.trust.toml b/.trust.toml index c1b2d2e..82c7ed8 100644 --- a/.trust.toml +++ b/.trust.toml @@ -6,7 +6,7 @@ command = ["fledge", "lanes", "run", "verify"] [contract] enabled = true -require_coverage = 0 +require_coverage = 100 skip_reason = "" [risk] diff --git a/docs.3md b/docs.3md index d97d72b..496964e 100644 --- a/docs.3md +++ b/docs.3md @@ -21,6 +21,7 @@ regenerate with `node scripts/build-docs-3md.mjs`. # 3md [![CI](https://github.com/CorvidLabs/3md/actions/workflows/trust.yml/badge.svg)](https://github.com/CorvidLabs/3md/actions/workflows/trust.yml) +[![spec coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Fcorvidlabs.github.io%2F3md%2Fbadges%2Fcoverage.json)](https://corvidlabs.github.io/3md/) [![Release](https://img.shields.io/github/v/release/CorvidLabs/3md?sort=semver)](https://github.com/CorvidLabs/3md/releases) [![License: MIT](https://img.shields.io/github/license/CorvidLabs/3md)](LICENSE) [![Live demo](https://img.shields.io/badge/demo-live-0E6F66)](https://corvidlabs.github.io/3md/) @@ -228,7 +229,7 @@ cross-implementation contract that keeps the parsers behaving identically. ## Status The format and spec are at version 1.0 (stable, frozen grammar). The latest -release is v1.0.0. Older `3md: 0.1` documents remain valid: the parser is +release is v1.8.1 (see the release badge above). Older `3md: 0.1` documents remain valid: the parser is version-lenient and never rejects a document by its version string. ## License @@ -802,16 +803,16 @@ descriptive generic names, 4-space indentation, 120-column lines. The formatter config in `.swift-format` enforces the mechanical parts. -## CorvidLabs trust toolchain (standing rules) +## CorvidLabs trust toolchain -This repo is governed by four CLIs. Every session MUST use them; never bypass or weaken them. +This repository uses one trust gate. Every session must use it and must not bypass or weaken it. -- fledge: run `fledge lanes run verify` before calling any change done. It must pass. -- spec-sync: when you change a module with a *.spec.md, update the spec, then `fledge spec check`. (skipped: , if content-only) -- augur: `augur check --staged` before a commit; `augur check --range origin/main..HEAD` before merge. A block verdict is a hard stop, never auto-overridden. -- attest: after a green lane, `attest sign --commit HEAD --reviewer agent: --from-augur augur.json --tests-passed`. +- Run `fledge trust verify` before calling a change complete. +- Keep module specs synchronized with implementation changes. +- Treat an Augur block verdict as a hard stop that must be surfaced and de-risked. +- Record and verify provenance with Attest after the repository's verification lane passes. +- Keep generated trust configuration and this managed block in place. -CI enforces the same gate (.github/workflows/trust.yml) and fails if this block is missing. Brand rule: no em-dash characters in anything you write. @plane z=7 label="PROOF" file="docs/PROOF.md" diff --git a/fledge.toml b/fledge.toml index f86fab4..2e42f66 100644 --- a/fledge.toml +++ b/fledge.toml @@ -12,6 +12,7 @@ lint = "swift-format lint --strict --recursive Sources Tests Package.swift" build = "swift build" test = "swift test" element-bundle = "bun scripts/check-element-bundle.mjs" +spec = "specsync check --strict --force --require-coverage 100" [tasks.editor] cmd = "bun install --frozen-lockfile && bun run test" @@ -34,12 +35,12 @@ dir = "js" description = "TypeScript port: install and run the test suite (the shared conformance vectors)." [lanes.verify] -description = "Native verification for all three parser implementations, generated element bundle drift, and editor grammar. Trust runs SpecSync after this lane." -steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor"] +description = "Native verification for all three parser implementations, generated element bundle drift, editor grammar, and the strict 100% SpecSync contract." +steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor", "spec"] [lanes.ci] -description = "Alias for the native verify lane." -steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor"] +description = "Alias for the complete verify lane." +steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor", "spec"] [lanes.ui] description = "Browser UI suite for the published web surfaces." diff --git a/specs/ThreeMD/requirements.md b/specs/ThreeMD/requirements.md index 984b1ed..b1274a7 100644 --- a/specs/ThreeMD/requirements.md +++ b/specs/ThreeMD/requirements.md @@ -26,7 +26,7 @@ numbered so tests and reviews can reference it directly. ### REQ-threemd-001 -The implementation SHALL satisfy this requirement. +`Parser.parse` SHALL require a complete frontmatter block and report missing or unclosed fences with typed parse errors. Acceptance Criteria @@ -39,7 +39,7 @@ Acceptance Criteria ### REQ-threemd-002 -The implementation SHALL satisfy this requirement. +Frontmatter SHALL declare a non-empty `3md` value that is stored as `Document.version`. Acceptance Criteria @@ -50,7 +50,7 @@ Acceptance Criteria ### REQ-threemd-003 -The implementation SHALL satisfy this requirement. +The parser SHALL read frontmatter as case-insensitive `key: value` pairs while rejecting malformed content lines. Acceptance Criteria @@ -63,7 +63,7 @@ Acceptance Criteria ### REQ-threemd-004 -The implementation SHALL satisfy this requirement. +The parser SHALL normalize the optional `axis` value and default it to `Axis.layer` when absent. Acceptance Criteria @@ -75,7 +75,7 @@ Acceptance Criteria ### REQ-threemd-005 -The implementation SHALL satisfy this requirement. +The parser SHALL map reserved frontmatter keys to document fields and preserve every other key in `Document.metadata`. Acceptance Criteria @@ -86,7 +86,7 @@ Acceptance Criteria ### REQ-threemd-006 -The implementation SHALL satisfy this requirement. +The parser SHALL recognize `@plane` directives and parse their quoted or unquoted `key=value` attributes. Acceptance Criteria @@ -100,7 +100,7 @@ Acceptance Criteria ### REQ-threemd-007 -The implementation SHALL satisfy this requirement. +Every explicit plane SHALL provide a numeric `z` attribute, including support for negative and decimal positions. Acceptance Criteria @@ -112,7 +112,7 @@ Acceptance Criteria ### REQ-threemd-008 -The implementation SHALL satisfy this requirement. +Plane directives SHALL parse optional numeric `x` and `y`, optional `label`, and preserve non-reserved attributes. Acceptance Criteria @@ -125,7 +125,7 @@ Acceptance Criteria ### REQ-threemd-009 -The implementation SHALL satisfy this requirement. +The parser SHALL assign trimmed Markdown bodies to their planes and preserve pre-plane Markdown as the document preamble. Acceptance Criteria @@ -138,7 +138,7 @@ Acceptance Criteria ### REQ-threemd-010 -The implementation SHALL satisfy this requirement. +A frontmatter document with non-empty content and no directive SHALL parse as one implicit plane at `z = 0`. Acceptance Criteria @@ -150,7 +150,7 @@ Acceptance Criteria ### REQ-threemd-011 -The implementation SHALL satisfy this requirement. +The parser SHALL reject duplicate plane `z` values with `ParseError.duplicatePlane(z:)`. Acceptance Criteria @@ -159,7 +159,7 @@ Acceptance Criteria ### REQ-threemd-012 -The implementation SHALL satisfy this requirement. +`Document` SHALL preserve source plane order while providing ascending-Z lookup and sorting helpers. Acceptance Criteria @@ -170,7 +170,7 @@ Acceptance Criteria ### REQ-threemd-013 -The implementation SHALL satisfy this requirement. +`Serializer.render` SHALL emit deterministic frontmatter, plane directives, attributes, and non-empty bodies. Acceptance Criteria @@ -184,7 +184,7 @@ Acceptance Criteria ### REQ-threemd-014 -The implementation SHALL satisfy this requirement. +Serialization output SHALL parse back to an equal document when content does not depend on quote escaping. Acceptance Criteria @@ -193,7 +193,7 @@ Acceptance Criteria ### REQ-threemd-015 -The implementation SHALL satisfy this requirement. +Parsing SHALL normalize Windows CRLF line endings to LF before processing. Acceptance Criteria @@ -204,7 +204,7 @@ Acceptance Criteria ### REQ-threemd-016 -The implementation SHALL satisfy this requirement. +The module SHALL build under Swift 6 strict concurrency for supported Apple platforms, Linux, and Windows. Acceptance Criteria @@ -214,7 +214,7 @@ Acceptance Criteria ### REQ-threemd-017 -The implementation SHALL satisfy this requirement. +Public model and service types SHALL provide the documented `Sendable`, value, coding, hashing, and error conformances. Acceptance Criteria @@ -225,7 +225,7 @@ Acceptance Criteria ### REQ-threemd-018 -The implementation SHALL satisfy this requirement. +Library code SHALL handle optionals and conversions without force unwraps, `try!`, or `as!`. Acceptance Criteria @@ -235,7 +235,7 @@ Acceptance Criteria ### REQ-threemd-019 -The implementation SHALL satisfy this requirement. +The ThreeMD module SHALL depend only on Foundation and no third-party packages. Acceptance Criteria @@ -244,7 +244,7 @@ Acceptance Criteria ### REQ-threemd-020 -The implementation SHALL satisfy this requirement. +Parsing SHALL be pure and serialization SHALL order metadata and extra attributes deterministically. Acceptance Criteria diff --git a/specs/ThreeMDCLI/requirements.md b/specs/ThreeMDCLI/requirements.md index dedc03d..c0f09bb 100644 --- a/specs/ThreeMDCLI/requirements.md +++ b/specs/ThreeMDCLI/requirements.md @@ -19,49 +19,49 @@ These requirements describe the ThreeMDCLI Swift executable target: the command- ### REQ-threemdcli-001 -The implementation SHALL satisfy this requirement. +The executable SHALL accept the documented subcommands and return usage with exit code 1 for missing or unknown commands. Acceptance Criteria - The executable accepts one of the following subcommands as its first argument: `validate`, `info`, `html`, `links`, or `check-links`. Any other argument or a missing subcommand prints usage information and exits with code 1. ### REQ-threemdcli-002 -The implementation SHALL satisfy this requirement. +`validate` SHALL parse the requested file, print `ok` on success, and report parse failures to stderr with exit code 1. Acceptance Criteria - Parses the specified file. Prints "ok" and exits 0 on success. On parsing failure, prints the error details to stderr and exits 1. ### REQ-threemdcli-003 -The implementation SHALL satisfy this requirement. +`info` SHALL print document metadata and every plane's position, label, coordinates, and extra attributes. Acceptance Criteria - Prints metadata (version, axis, title, plane count) and each plane's properties (z, label, coordinates, extra attributes). ### REQ-threemdcli-004 -The implementation SHALL satisfy this requirement. +`html` SHALL render the document to HTML on stdout. Acceptance Criteria - Renders the document to HTML and prints the output to stdout. ### REQ-threemdcli-005 -The implementation SHALL satisfy this requirement. +`links` SHALL print every cross-plane link and the link graph representation. Acceptance Criteria - Extracts and prints all cross-plane links and the link graph representation. ### REQ-threemdcli-006 -The implementation SHALL satisfy this requirement. +`check-links` SHALL fail with dangling-link details or print `ok` and exit successfully when all links resolve. Acceptance Criteria - Validates all cross-plane links. If there are dangling links, it prints details to stderr and exits with code 1. If all links resolve, it prints "ok" and exits 0. ### REQ-threemdcli-007 -The implementation SHALL satisfy this requirement. +Supported inspection subcommands SHALL emit JSON on stdout when `--json` is supplied. Acceptance Criteria @@ -71,21 +71,21 @@ Acceptance Criteria ### REQ-threemdcli-008 -The implementation SHALL satisfy this requirement. +The CLI target SHALL depend only on the local `ThreeMD` target and Foundation. Acceptance Criteria - The CLI target depends only on the local `ThreeMD` library target and Foundation. No external package manager or CLI parsing library is used. ### REQ-threemdcli-009 -The implementation SHALL satisfy this requirement. +The executable SHALL parse commands and start with minimal overhead. Acceptance Criteria - CommandLine parsing and execution are fast, with minimal startup overhead. ### REQ-threemdcli-010 -The implementation SHALL satisfy this requirement. +The executable SHALL build cleanly under Swift 6 strict concurrency. Acceptance Criteria diff --git a/specs/ThreeMDElement/requirements.md b/specs/ThreeMDElement/requirements.md index 6744e7f..441873a 100644 --- a/specs/ThreeMDElement/requirements.md +++ b/specs/ThreeMDElement/requirements.md @@ -32,7 +32,7 @@ requirement is numbered so tests and reviews can reference it directly. ### REQ-threemdelement-001 -The implementation SHALL satisfy this requirement. +The element SHALL delegate 3md parsing to `@corvidlabs/threemd` and render the returned document model. Acceptance Criteria @@ -44,7 +44,7 @@ Acceptance Criteria ### REQ-threemdelement-002 -The implementation SHALL satisfy this requirement. +The element SHALL render either fetched `src` content or inline content and allow `setSource(text)` replacement. Acceptance Criteria @@ -55,7 +55,7 @@ Acceptance Criteria ### REQ-threemdelement-003 -The implementation SHALL satisfy this requirement. +Asynchronous source loading SHALL discard stale responses and render descriptive failures through the error part. Acceptance Criteria @@ -66,7 +66,7 @@ Acceptance Criteria ### REQ-threemdelement-004 -The implementation SHALL satisfy this requirement. +Blank or invalid source SHALL render the documented error message without building planes. Acceptance Criteria @@ -76,7 +76,7 @@ Acceptance Criteria ### REQ-threemdelement-005 -The implementation SHALL satisfy this requirement. +The element SHALL observe `src` and `mode` and reapply them after its DOM is available. Acceptance Criteria @@ -87,7 +87,7 @@ Acceptance Criteria ### REQ-threemdelement-006 -The implementation SHALL satisfy this requirement. +The element SHALL select a supported rendering mode from `mode`, axis aliases, or the document axis, defaulting to `stack`. Acceptance Criteria @@ -100,7 +100,7 @@ Acceptance Criteria ### REQ-threemdelement-007 -The implementation SHALL satisfy this requirement. +Plane layout SHALL derive true Z position from distance to focus so the focused plane remains frontmost. Acceptance Criteria @@ -111,7 +111,7 @@ Acceptance Criteria ### REQ-threemdelement-008 -The implementation SHALL satisfy this requirement. +`render()` SHALL synchronously apply all interaction state as the stage's single source of truth. Acceptance Criteria @@ -122,7 +122,7 @@ Acceptance Criteria ### REQ-threemdelement-009 -The implementation SHALL satisfy this requirement. +Animation frames SHALL provide only optional idle drift and SHALL NOT be required for correct interaction rendering. Acceptance Criteria @@ -135,7 +135,7 @@ Acceptance Criteria ### REQ-threemdelement-010 -The implementation SHALL satisfy this requirement. +The stage SHALL use one pointer-event path for mouse, touch, and pen drag interactions. Acceptance Criteria @@ -146,7 +146,7 @@ Acceptance Criteria ### REQ-threemdelement-011 -The implementation SHALL satisfy this requirement. +The element SHALL reserve touch gestures for the model and avoid horizontal overflow from 320px through 1440px. Acceptance Criteria @@ -157,7 +157,7 @@ Acceptance Criteria ### REQ-threemdelement-012 -The implementation SHALL satisfy this requirement. +The scrubber, step buttons, and arrow keys SHALL synchronously navigate the focused plane within range. Acceptance Criteria @@ -168,7 +168,7 @@ Acceptance Criteria ### REQ-threemdelement-013 -The implementation SHALL satisfy this requirement. +The public element API SHALL expose its document, current index, active mode, and clamped `goTo(index)` navigation. Acceptance Criteria @@ -178,7 +178,7 @@ Acceptance Criteria ### REQ-threemdelement-014 -The implementation SHALL satisfy this requirement. +A focus-index change SHALL emit one bubbling, composed `planechange` event containing the selected plane details. Acceptance Criteria @@ -189,7 +189,7 @@ Acceptance Criteria ### REQ-threemdelement-015 -The implementation SHALL satisfy this requirement. +Each plane SHALL render its tag and an HTML-escaped body using the documented limited Markdown subset. Acceptance Criteria @@ -201,7 +201,7 @@ Acceptance Criteria ### REQ-threemdelement-016 -The implementation SHALL satisfy this requirement. +The element SHALL use an open shadow root and expose theming through the documented custom properties and parts. Acceptance Criteria @@ -215,7 +215,7 @@ Acceptance Criteria ### REQ-threemdelement-017 -The implementation SHALL satisfy this requirement. +`` SHALL work unchanged in plain HTML, React, Vue, Svelte, and Angular. Acceptance Criteria @@ -225,7 +225,7 @@ Acceptance Criteria ### REQ-threemdelement-018 -The implementation SHALL satisfy this requirement. +CI SHALL exercise the component's invariants and console cleanliness in Chromium and WebKit with Playwright. Acceptance Criteria @@ -235,7 +235,7 @@ Acceptance Criteria ### REQ-threemdelement-019 -The implementation SHALL satisfy this requirement. +The published element bundle SHALL include the parser so no separate parser script is required. Acceptance Criteria @@ -244,7 +244,7 @@ Acceptance Criteria ### REQ-threemdelement-020 -The implementation SHALL satisfy this requirement. +Component styles SHALL remain isolated inside the shadow root except for documented theming surfaces. Acceptance Criteria @@ -254,7 +254,7 @@ Acceptance Criteria ### REQ-threemdelement-021 -The implementation SHALL satisfy this requirement. +The element SHALL degrade gracefully when optional browser capabilities or external source loading are unavailable. Acceptance Criteria diff --git a/web/docs.3md b/web/docs.3md index d97d72b..496964e 100644 --- a/web/docs.3md +++ b/web/docs.3md @@ -21,6 +21,7 @@ regenerate with `node scripts/build-docs-3md.mjs`. # 3md [![CI](https://github.com/CorvidLabs/3md/actions/workflows/trust.yml/badge.svg)](https://github.com/CorvidLabs/3md/actions/workflows/trust.yml) +[![spec coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Fcorvidlabs.github.io%2F3md%2Fbadges%2Fcoverage.json)](https://corvidlabs.github.io/3md/) [![Release](https://img.shields.io/github/v/release/CorvidLabs/3md?sort=semver)](https://github.com/CorvidLabs/3md/releases) [![License: MIT](https://img.shields.io/github/license/CorvidLabs/3md)](LICENSE) [![Live demo](https://img.shields.io/badge/demo-live-0E6F66)](https://corvidlabs.github.io/3md/) @@ -228,7 +229,7 @@ cross-implementation contract that keeps the parsers behaving identically. ## Status The format and spec are at version 1.0 (stable, frozen grammar). The latest -release is v1.0.0. Older `3md: 0.1` documents remain valid: the parser is +release is v1.8.1 (see the release badge above). Older `3md: 0.1` documents remain valid: the parser is version-lenient and never rejects a document by its version string. ## License @@ -802,16 +803,16 @@ descriptive generic names, 4-space indentation, 120-column lines. The formatter config in `.swift-format` enforces the mechanical parts. -## CorvidLabs trust toolchain (standing rules) +## CorvidLabs trust toolchain -This repo is governed by four CLIs. Every session MUST use them; never bypass or weaken them. +This repository uses one trust gate. Every session must use it and must not bypass or weaken it. -- fledge: run `fledge lanes run verify` before calling any change done. It must pass. -- spec-sync: when you change a module with a *.spec.md, update the spec, then `fledge spec check`. (skipped: , if content-only) -- augur: `augur check --staged` before a commit; `augur check --range origin/main..HEAD` before merge. A block verdict is a hard stop, never auto-overridden. -- attest: after a green lane, `attest sign --commit HEAD --reviewer agent: --from-augur augur.json --tests-passed`. +- Run `fledge trust verify` before calling a change complete. +- Keep module specs synchronized with implementation changes. +- Treat an Augur block verdict as a hard stop that must be surfaced and de-risked. +- Record and verify provenance with Attest after the repository's verification lane passes. +- Keep generated trust configuration and this managed block in place. -CI enforces the same gate (.github/workflows/trust.yml) and fails if this block is missing. Brand rule: no em-dash characters in anything you write. @plane z=7 label="PROOF" file="docs/PROOF.md" From 8d917f3f3044985138e084021ee6c0d9a702127c Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Mon, 13 Jul 2026 13:46:51 -0600 Subject: [PATCH 09/16] fix(ci): preinstall pinned SpecSync for strict lifecycle --- .github/workflows/trust.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml index 58b81ee..ad53ea0 100644 --- a/.github/workflows/trust.yml +++ b/.github/workflows/trust.yml @@ -40,6 +40,26 @@ jobs: with: bun-version: latest + # The lifecycle preserves this repository's pre-migration strict + # SpecSync check; Trust's composed contract step still owns the gate. + - name: Install SpecSync 5.0.1 for lifecycle verification + shell: bash + run: | + set -euo pipefail + archive="$RUNNER_TEMP/specsync-macos-aarch64.tar.gz" + checksum="$archive.sha256" + base="https://github.com/CorvidLabs/spec-sync/releases/download/v5.0.1" + curl -fsSL "$base/specsync-macos-aarch64.tar.gz" -o "$archive" + curl -fsSL "$base/specsync-macos-aarch64.tar.gz.sha256" -o "$checksum" + expected="$(awk '{print $1}' "$checksum")" + actual="$(shasum -a 256 "$archive" | awk '{print $1}')" + test "$actual" = "$expected" + mkdir -p "$RUNNER_TEMP/specsync-bin" + tar -xzf "$archive" -C "$RUNNER_TEMP/specsync-bin" + mv "$RUNNER_TEMP/specsync-bin/specsync-macos-aarch64" "$RUNNER_TEMP/specsync-bin/specsync" + chmod +x "$RUNNER_TEMP/specsync-bin/specsync" + echo "$RUNNER_TEMP/specsync-bin" >> "$GITHUB_PATH" + # Unified lifecycle, contract, risk, and progressive provenance gate. - name: CorvidLabs Trust gate id: trust From 0c02573f0da6ce948dcf665c2e5ffff23b0aecf8 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:02:58 -0600 Subject: [PATCH 10/16] fix(ci): avoid recursive strict SpecSync verification --- .github/workflows/trust.yml | 5 +++++ fledge.toml | 9 ++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml index ad53ea0..53cca6e 100644 --- a/.github/workflows/trust.yml +++ b/.github/workflows/trust.yml @@ -60,6 +60,11 @@ jobs: chmod +x "$RUNNER_TEMP/specsync-bin/specsync" echo "$RUNNER_TEMP/specsync-bin" >> "$GITHUB_PATH" + # Preserve the former warning-as-error contract without placing SpecSync + # inside its own configured verification command. + - name: Strict SpecSync contract + run: specsync check --strict --force --require-coverage 100 + # Unified lifecycle, contract, risk, and progressive provenance gate. - name: CorvidLabs Trust gate id: trust diff --git a/fledge.toml b/fledge.toml index 2e42f66..f86fab4 100644 --- a/fledge.toml +++ b/fledge.toml @@ -12,7 +12,6 @@ lint = "swift-format lint --strict --recursive Sources Tests Package.swift" build = "swift build" test = "swift test" element-bundle = "bun scripts/check-element-bundle.mjs" -spec = "specsync check --strict --force --require-coverage 100" [tasks.editor] cmd = "bun install --frozen-lockfile && bun run test" @@ -35,12 +34,12 @@ dir = "js" description = "TypeScript port: install and run the test suite (the shared conformance vectors)." [lanes.verify] -description = "Native verification for all three parser implementations, generated element bundle drift, editor grammar, and the strict 100% SpecSync contract." -steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor", "spec"] +description = "Native verification for all three parser implementations, generated element bundle drift, and editor grammar. Trust runs SpecSync after this lane." +steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor"] [lanes.ci] -description = "Alias for the complete verify lane." -steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor", "spec"] +description = "Alias for the native verify lane." +steps = ["lint", "build", "test", "js", "rust", "element-bundle", "editor"] [lanes.ui] description = "Browser UI suite for the published web surfaces." From 8bb1f76a1e9c49a0eb28997899ba3c30ca6608c4 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:05:06 -0600 Subject: [PATCH 11/16] fix(ci): install pinned Fledge for strict contract precheck --- .github/workflows/trust.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml index 53cca6e..4c46130 100644 --- a/.github/workflows/trust.yml +++ b/.github/workflows/trust.yml @@ -42,7 +42,7 @@ jobs: # The lifecycle preserves this repository's pre-migration strict # SpecSync check; Trust's composed contract step still owns the gate. - - name: Install SpecSync 5.0.1 for lifecycle verification + - name: Install pinned lifecycle tools shell: bash run: | set -euo pipefail @@ -58,6 +58,14 @@ jobs: tar -xzf "$archive" -C "$RUNNER_TEMP/specsync-bin" mv "$RUNNER_TEMP/specsync-bin/specsync-macos-aarch64" "$RUNNER_TEMP/specsync-bin/specsync" chmod +x "$RUNNER_TEMP/specsync-bin/specsync" + fledge="$RUNNER_TEMP/specsync-bin/fledge" + curl -fsSL \ + "https://github.com/CorvidLabs/fledge/releases/download/v1.7.0/fledge-macos-aarch64" \ + -o "$fledge" + expected_fledge="21d0916d52ef14e6d33e3967417773369e047a0311e66bbb1eecc8f69332a040" + actual_fledge="$(shasum -a 256 "$fledge" | awk '{print $1}')" + test "$actual_fledge" = "$expected_fledge" + chmod +x "$fledge" echo "$RUNNER_TEMP/specsync-bin" >> "$GITHUB_PATH" # Preserve the former warning-as-error contract without placing SpecSync From 6148c1f853c5f50269a84d005a4d474ce384b9f2 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:20:30 -0600 Subject: [PATCH 12/16] update(governance): align public docs with Trust gate --- .../approvals.json | 7 ++++++ .../state.json | 5 +++- .specsync/sdd.json | 3 +++ CONTRIBUTING.md | 10 ++++---- README.md | 14 ++++++----- docs.3md | 24 +++++++++++-------- fledge.toml | 4 ++-- web/docs.3md | 24 +++++++++++-------- 8 files changed, 58 insertions(+), 33 deletions(-) diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json index d3940c9..ff870eb 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json @@ -20,6 +20,13 @@ "timestamp": 1783971650, "digest": "77c9495b355f19a856d03e1a76f247c512f00beb33e011d66e068d839239351f", "note": "Definition re-approved after the complete local verification lane and strict 100% contract passed; hosted pull-request checks and closing acceptance remain pending." + }, + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1783973991, + "digest": "174ccd0189f9b600f8f14088871b133f15bcab0570c991e16373ce5fca69f72b", + "note": "Definition refreshed after final review: public documentation names Trust as the complete gate and README, CONTRIBUTING, and docs are governed meaningful paths." } ] } diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json index 559a987..6efd1b3 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json @@ -8,7 +8,7 @@ "state": "implementing", "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", "created_at": 1783826867, - "updated_at": 1783971650, + "updated_at": 1783973991, "affected_specs": [], "affected_paths": [ ".github/workflows/trust.yml", @@ -21,6 +21,9 @@ ".augur.toml", "AGENTS.md", "CLAUDE.md", + "README.md", + "CONTRIBUTING.md", + "docs/", "docs.3md", "web/docs.3md", "fledge.toml" diff --git a/.specsync/sdd.json b/.specsync/sdd.json index de28516..803a2d5 100644 --- a/.specsync/sdd.json +++ b/.specsync/sdd.json @@ -37,6 +37,9 @@ "uitests/", "web/", "scripts/", + "README.md", + "CONTRIBUTING.md", + "docs/", "SPEC.md", "fledge.toml", ".trust.toml", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5100d21..e996cbf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,14 +19,16 @@ conformance vector.** ## The gate -One command runs everything (Swift format check, build, tests, and the Rust -crate): +Run the complete repository gate before calling any change done: ```bash -fledge lanes run verify +fledge trust verify ``` -Run it before calling any change done. Per language: +Trust validates the SpecSync contract, risk policy, and provenance posture, and +composes the native `fledge lanes run verify` lane. The native lane runs the +Swift format check, build, tests, TypeScript parity, Rust crate, generated +bundle drift, and editor checks. Per language: ```bash swift test # Swift diff --git a/README.md b/README.md index 40c61d1..d5b5684 100644 --- a/README.md +++ b/README.md @@ -189,17 +189,19 @@ agreed) and for people (plain, readable, diffable text). ## Development -This repo uses the CorvidLabs trust toolchain. The single gate is: +This repo uses the CorvidLabs trust toolchain. Run the complete repository gate +before calling a change done: ```bash -fledge lanes run verify +fledge trust verify ``` -which runs the Swift format check, build, and tests plus the Rust crate. See +Trust validates the SpecSync contract, risk policy, and provenance posture, and +composes the native `fledge lanes run verify` lane. That native lane runs the +Swift format check, build, and tests plus the Rust crate, TypeScript parser +parity, generated web-component bundle drift, and VS Code grammar tests. See [AGENTS.md](AGENTS.md) for the standing rules every contributor and agent follows. -The same gate also checks TypeScript parser parity, generated web-component -bundle drift, VS Code grammar tests, and spec-sync. Browser UI tests are exposed -separately with `fledge lanes run ui`. +Browser UI tests are exposed separately with `fledge lanes run ui`. Each implementation has its own tests (the Swift suite has 122 tests, the TypeScript suite 76), and all three implementations run the shared 43-vector diff --git a/docs.3md b/docs.3md index 496964e..4c11a35 100644 --- a/docs.3md +++ b/docs.3md @@ -209,17 +209,19 @@ agreed) and for people (plain, readable, diffable text). ## Development -This repo uses the CorvidLabs trust toolchain. The single gate is: +This repo uses the CorvidLabs trust toolchain. Run the complete repository gate +before calling a change done: ```bash -fledge lanes run verify +fledge trust verify ``` -which runs the Swift format check, build, and tests plus the Rust crate. See +Trust validates the SpecSync contract, risk policy, and provenance posture, and +composes the native `fledge lanes run verify` lane. That native lane runs the +Swift format check, build, and tests plus the Rust crate, TypeScript parser +parity, generated web-component bundle drift, and VS Code grammar tests. See [AGENTS.md](AGENTS.md) for the standing rules every contributor and agent follows. -The same gate also checks TypeScript parser parity, generated web-component -bundle drift, VS Code grammar tests, and spec-sync. Browser UI tests are exposed -separately with `fledge lanes run ui`. +Browser UI tests are exposed separately with `fledge lanes run ui`. Each implementation has its own tests (the Swift suite has 122 tests, the TypeScript suite 76), and all three implementations run the shared 43-vector @@ -694,14 +696,16 @@ conformance vector.** ## The gate -One command runs everything (Swift format check, build, tests, and the Rust -crate): +Run the complete repository gate before calling any change done: ```bash -fledge lanes run verify +fledge trust verify ``` -Run it before calling any change done. Per language: +Trust validates the SpecSync contract, risk policy, and provenance posture, and +composes the native `fledge lanes run verify` lane. The native lane runs the +Swift format check, build, tests, TypeScript parity, Rust crate, generated +bundle drift, and editor checks. Per language: ```bash swift test # Swift diff --git a/fledge.toml b/fledge.toml index f86fab4..2af0f11 100644 --- a/fledge.toml +++ b/fledge.toml @@ -1,8 +1,8 @@ # fledge.toml - project task definitions and lanes # Detected project type: swift # -# The single CI gate is the `verify` lane (see AGENTS.md). Run it with: -# fledge lanes run verify +# Trust is the complete repository gate (see AGENTS.md). The `verify` lane is +# its native implementation-verification component. [tasks] # swift format unifies formatting and linting. `fmt` fixes in place; `lint` diff --git a/web/docs.3md b/web/docs.3md index 496964e..4c11a35 100644 --- a/web/docs.3md +++ b/web/docs.3md @@ -209,17 +209,19 @@ agreed) and for people (plain, readable, diffable text). ## Development -This repo uses the CorvidLabs trust toolchain. The single gate is: +This repo uses the CorvidLabs trust toolchain. Run the complete repository gate +before calling a change done: ```bash -fledge lanes run verify +fledge trust verify ``` -which runs the Swift format check, build, and tests plus the Rust crate. See +Trust validates the SpecSync contract, risk policy, and provenance posture, and +composes the native `fledge lanes run verify` lane. That native lane runs the +Swift format check, build, and tests plus the Rust crate, TypeScript parser +parity, generated web-component bundle drift, and VS Code grammar tests. See [AGENTS.md](AGENTS.md) for the standing rules every contributor and agent follows. -The same gate also checks TypeScript parser parity, generated web-component -bundle drift, VS Code grammar tests, and spec-sync. Browser UI tests are exposed -separately with `fledge lanes run ui`. +Browser UI tests are exposed separately with `fledge lanes run ui`. Each implementation has its own tests (the Swift suite has 122 tests, the TypeScript suite 76), and all three implementations run the shared 43-vector @@ -694,14 +696,16 @@ conformance vector.** ## The gate -One command runs everything (Swift format check, build, tests, and the Rust -crate): +Run the complete repository gate before calling any change done: ```bash -fledge lanes run verify +fledge trust verify ``` -Run it before calling any change done. Per language: +Trust validates the SpecSync contract, risk policy, and provenance posture, and +composes the native `fledge lanes run verify` lane. The native lane runs the +Swift format check, build, tests, TypeScript parity, Rust crate, generated +bundle drift, and editor checks. Per language: ```bash swift test # Swift From 2458e7d2e607a8cd98448652821d515ed1f51bf9 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:34:33 -0600 Subject: [PATCH 13/16] update(governance): record accepted rollout evidence --- .../approvals.json | 14 ++++++++++++++ .../change.md | 2 +- .../state.json | 4 ++-- .../tasks.md | 2 +- .../verification.json | 16 ++++++++++++++++ 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification.json diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json index ff870eb..ca6090f 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json @@ -27,6 +27,20 @@ "timestamp": 1783973991, "digest": "174ccd0189f9b600f8f14088871b133f15bcab0570c991e16373ce5fca69f72b", "note": "Definition refreshed after final review: public documentation names Trust as the complete gate and README, CONTRIBUTING, and docs are governed meaningful paths." + }, + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1783974811, + "digest": "3e3993f3a310d989da0f46bf1d7643e8d7c3cfe201df57371fcb31e1c4b52116", + "note": "Definition refreshed after the complete corrected PR head passed Trust, browser UI, and all CodeQL checks." + }, + { + "gate": "acceptance", + "actor": "user:0xLeif", + "timestamp": 1783974846, + "digest": "2514197b66c28890a33152e1f34edae858598990a6c2fcd0171df22d1715711c", + "note": "Accepted after native Swift, TypeScript, Rust, generated-bundle, and editor verification plus successful hosted Trust, browser UI, and CodeQL checks on the corrected PR head." } ] } diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md index bdd9e7e..f4cfb2d 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md @@ -1,6 +1,6 @@ --- id: CHG-0001-adopt-trust-1-and-specsync-5 -state: implementing +state: accepted type: migration base_commit: 2a145766b9ecb83d96ee15aa453a65cc2125571f --- diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json index 6efd1b3..a334084 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json @@ -5,10 +5,10 @@ "title": "Adopt Trust 1 and SpecSync 5", "description": "Adopt Trust 1 and SpecSync 5", "kind": "migration", - "state": "implementing", + "state": "accepted", "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", "created_at": 1783826867, - "updated_at": 1783973991, + "updated_at": 1783974846, "affected_specs": [], "affected_paths": [ ".github/workflows/trust.yml", diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md index ce20397..9ae70aa 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/tasks.md @@ -10,4 +10,4 @@ artifact: tasks - [x] Commit the standard Trust policy and Augur configuration. - [x] Consolidate the CI workflow on Trust 1.0.0. - [x] Pass local strict validation and the repository verify lane. -- [ ] Pass hosted pull-request checks. +- [x] Pass hosted pull-request checks. diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification.json new file mode 100644 index 0000000..1dfbecb --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification.json @@ -0,0 +1,16 @@ +{ + "timestamp": 1783974833, + "commit": "6148c1f853c5f50269a84d005a4d474ce384b9f2", + "contract_digest": "3e3993f3a310d989da0f46bf1d7643e8d7c3cfe201df57371fcb31e1c4b52116", + "workspace_digest": "0b62c7bf6e4900e50e9406a10f9d176018528ed72e5fc53aaba17d7f9594fdb6", + "acceptance_input_digest": "cfc943b5b376e22b72c0c900d66b9f2b57c945e8e70a215a880fbf4cf0dbca34", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [] +} From 765abbf6be3919262f3fb885ed36439afafc5c5b Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Tue, 14 Jul 2026 01:08:31 -0600 Subject: [PATCH 14/16] feat: fix final SDD governance review findings --- .claude/skills/spec-sync/SKILL.md | 2 +- .codex/skills/spec-sync/SKILL.md | 2 +- .cursor/skills/spec-sync/SKILL.md | 2 +- .gemini/skills/spec-sync/SKILL.md | 2 +- .github/workflows/trust.yml | 11 +----- .../approvals.json | 19 +++++++++ .../change.md | 24 ++++++++++++ .../context.md | 10 +++++ .../docs.md | 10 +++++ .../plan.md | 11 ++++++ .../requirements.md | 11 ++++++ .../state.json | 39 +++++++++++++++++++ .../tasks.md | 12 ++++++ .../testing.md | 12 ++++++ .specsync/sdd.json | 10 +++-- 15 files changed, 159 insertions(+), 18 deletions(-) create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/approvals.json create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/change.md create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/context.md create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/docs.md create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/plan.md create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/requirements.md create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/state.json create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/tasks.md create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/testing.md diff --git a/.claude/skills/spec-sync/SKILL.md b/.claude/skills/spec-sync/SKILL.md index de24d12..4832c7b 100644 --- a/.claude/skills/spec-sync/SKILL.md +++ b/.claude/skills/spec-sync/SKILL.md @@ -14,7 +14,7 @@ This project uses [spec-sync](https://github.com/CorvidLabs/spec-sync) for bidir For every meaningful source, test, public documentation, schema, or configuration change: 1. Run `specsync change new "" --json` and conduct the returned interview with the user. -2. Use `specsync change answer --json` until no questions remain. +2. Use `specsync change answer "" --json` until no questions remain. 3. Complete the adaptively selected artifacts and semantic deltas. Requirements use stable `REQ--` IDs, a normative SHALL statement, and acceptance criteria. 4. Ask the user for the definition approval, then run `specsync change approve `. diff --git a/.codex/skills/spec-sync/SKILL.md b/.codex/skills/spec-sync/SKILL.md index 1a6ca94..e597cd0 100644 --- a/.codex/skills/spec-sync/SKILL.md +++ b/.codex/skills/spec-sync/SKILL.md @@ -22,7 +22,7 @@ Each canonical spec may have policy-selected companion files. Read and update th For every meaningful source, test, public documentation, schema, or configuration change: 1. Run `specsync change new "" --json` and conduct the returned interview with the user. -2. Use `specsync change answer --json` until no questions remain. +2. Use `specsync change answer "" --json` until no questions remain. 3. Complete the adaptively selected artifacts and semantic deltas. Requirements use stable `REQ--` IDs, a normative SHALL statement, and acceptance criteria. 4. Ask the user for the definition approval, then run `specsync change approve `. diff --git a/.cursor/skills/spec-sync/SKILL.md b/.cursor/skills/spec-sync/SKILL.md index 1a6ca94..e597cd0 100644 --- a/.cursor/skills/spec-sync/SKILL.md +++ b/.cursor/skills/spec-sync/SKILL.md @@ -22,7 +22,7 @@ Each canonical spec may have policy-selected companion files. Read and update th For every meaningful source, test, public documentation, schema, or configuration change: 1. Run `specsync change new "" --json` and conduct the returned interview with the user. -2. Use `specsync change answer --json` until no questions remain. +2. Use `specsync change answer "" --json` until no questions remain. 3. Complete the adaptively selected artifacts and semantic deltas. Requirements use stable `REQ--` IDs, a normative SHALL statement, and acceptance criteria. 4. Ask the user for the definition approval, then run `specsync change approve `. diff --git a/.gemini/skills/spec-sync/SKILL.md b/.gemini/skills/spec-sync/SKILL.md index de24d12..4832c7b 100644 --- a/.gemini/skills/spec-sync/SKILL.md +++ b/.gemini/skills/spec-sync/SKILL.md @@ -14,7 +14,7 @@ This project uses [spec-sync](https://github.com/CorvidLabs/spec-sync) for bidir For every meaningful source, test, public documentation, schema, or configuration change: 1. Run `specsync change new "" --json` and conduct the returned interview with the user. -2. Use `specsync change answer --json` until no questions remain. +2. Use `specsync change answer "" --json` until no questions remain. 3. Complete the adaptively selected artifacts and semantic deltas. Requirements use stable `REQ--` IDs, a normative SHALL statement, and acceptance criteria. 4. Ask the user for the definition approval, then run `specsync change approve `. diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml index 4c46130..d096218 100644 --- a/.github/workflows/trust.yml +++ b/.github/workflows/trust.yml @@ -1,24 +1,15 @@ name: trust on: - # Skip the gate for documentation-only changes (it has nothing code to verify). - # Anything that touches code, web/, specs/, SPEC.md, or conformance still runs. + # Public documentation is governed by SpecSync, so those changes run Trust. pull_request: paths-ignore: - - "README.md" - - "ROADMAP.md" - - "CONTRIBUTING.md" - - "docs/**" - "LICENSE" - "**/*.png" - ".github/ISSUE_TEMPLATE/**" push: branches: [main] paths-ignore: - - "README.md" - - "ROADMAP.md" - - "CONTRIBUTING.md" - - "docs/**" - "LICENSE" - "**/*.png" - ".github/ISSUE_TEMPLATE/**" diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/approvals.json b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/approvals.json new file mode 100644 index 0000000..d751961 --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/approvals.json @@ -0,0 +1,19 @@ +{ + "approvals": [ + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1783976028, + "digest": "2ce2d380b030b04d904a99189d4c5d2be5a18789bdddd7155f374f83daa0961d", + "note": "Definition reviewed after final-head comments; scope is limited to Trust path filters, SDD governance paths, and installed agent guidance." + }, + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1784012911, + "digest": "5bd9d4eddcff67d4e2ed60328ba2cf59b66e0a8a29627e72b6b08fd006d3f754", + "note": "Reapproved after replacing circular verification tasks with truthful completed configuration and preserving hosted checks as post-push evidence." + } + ], + "reopenings": [] +} diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/change.md b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/change.md new file mode 100644 index 0000000..e6a2271 --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/change.md @@ -0,0 +1,24 @@ +--- +id: CHG-0003-address-final-trust-and-sdd-governance-review-corrections +state: implementing +type: migration +base_commit: 2458e7d2e607a8cd98448652821d515ed1f51bf9 +--- + +# Address final Trust and SDD governance review corrections + +## Intent + +Address final Trust and SDD governance review corrections + +## Affected Canonical Specs + +- None + +## Acceptance Criteria + +- Trust runs for every governed public-documentation change; SDD policy and canonical spec edits require a covering change; all installed agent skills preserve multi-word interview answers; strict SpecSync and the complete Trust gate pass at 100%. + +## No-spec Rationale + +Governance policy and generated-agent guidance corrections only; no product or canonical module behavior changes. diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/context.md b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/context.md new file mode 100644 index 0000000..5380abe --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/context.md @@ -0,0 +1,10 @@ +--- +change: CHG-0003-address-final-trust-and-sdd-governance-review-corrections +artifact: context +--- + +# Context + +Final-head review found that public documentation could skip Trust, broad ignore +rules could exempt canonical contracts and SDD policy from change coverage, and +installed agent skills could split multi-word interview answers. diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/docs.md b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/docs.md new file mode 100644 index 0000000..29dfab6 --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/docs.md @@ -0,0 +1,10 @@ +--- +change: CHG-0003-address-final-trust-and-sdd-governance-review-corrections +artifact: docs +--- + +# Docs + +No public product documentation changes. The workflow comment now explains why +governed documentation must run Trust; installed agent guidance consistently +shows a quoted interview answer. diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/plan.md b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/plan.md new file mode 100644 index 0000000..19eee60 --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/plan.md @@ -0,0 +1,11 @@ +--- +change: CHG-0003-address-final-trust-and-sdd-governance-review-corrections +artifact: plan +--- + +# Plan + +1. Align Trust path filters with the meaningful documentation policy. +2. Govern every source used by the public documentation bundle and remove conflicting ignores. +3. Quote interview answers in all installed agent skills. +4. Run strict SpecSync, native verification, Trust, and hosted checks. diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/requirements.md b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/requirements.md new file mode 100644 index 0000000..345266c --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/requirements.md @@ -0,0 +1,11 @@ +--- +change: CHG-0003-address-final-trust-and-sdd-governance-review-corrections +artifact: requirements +--- + +# Requirements + +- Trust SHALL run when governed public documentation changes. +- Canonical specs and SDD policy files SHALL require a covering change. +- Every installed agent skill SHALL preserve an interview answer as one CLI argument. +- Existing product behavior and canonical module requirements SHALL remain unchanged. diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/state.json b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/state.json new file mode 100644 index 0000000..6404f78 --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/state.json @@ -0,0 +1,39 @@ +{ + "schema_version": 1, + "id": "CHG-0003-address-final-trust-and-sdd-governance-review-corrections", + "slug": "address-final-trust-and-sdd-governance-review-corrections", + "title": "Address final Trust and SDD governance review corrections", + "description": "Address final Trust and SDD governance review corrections", + "kind": "migration", + "state": "implementing", + "base_commit": "2458e7d2e607a8cd98448652821d515ed1f51bf9", + "created_at": 1783975947, + "updated_at": 1784012911, + "affected_specs": [], + "affected_paths": [ + ".github/workflows/trust.yml", + ".specsync/sdd.json", + ".claude/skills/spec-sync/SKILL.md", + ".codex/skills/spec-sync/SKILL.md", + ".cursor/skills/spec-sync/SKILL.md", + ".gemini/skills/spec-sync/SKILL.md" + ], + "no_spec_change": true, + "no_spec_change_rationale": "Governance policy and generated-agent guidance corrections only; no product or canonical module behavior changes.", + "acceptance_criteria": [ + "Trust runs for every governed public-documentation change; SDD policy and canonical spec edits require a covering change; all installed agent skills preserve multi-word interview answers; strict SpecSync and the complete Trust gate pass at 100%." + ], + "selected_artifacts": [ + "context", + "requirements", + "plan", + "tasks", + "testing", + "docs" + ], + "dependencies": [], + "answers": { + "architecture_risk": "no", + "public_contract": "no" + } +} diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/tasks.md b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/tasks.md new file mode 100644 index 0000000..4f87774 --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/tasks.md @@ -0,0 +1,12 @@ +--- +change: CHG-0003-address-final-trust-and-sdd-governance-review-corrections +artifact: tasks +--- + +# Tasks + +- [x] Align Trust documentation path filters. +- [x] Correct meaningful and ignored SDD paths. +- [x] Quote interview answers in all four installed agent skills. +- [x] Configure strict SpecSync and the complete local Trust gate as closing evidence. +- [x] Preserve hosted Trust, UI, and CodeQL as required post-push checks without claiming their result early. diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/testing.md b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/testing.md new file mode 100644 index 0000000..a71bc3f --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/testing.md @@ -0,0 +1,12 @@ +--- +change: CHG-0003-address-final-trust-and-sdd-governance-review-corrections +artifact: testing +--- + +# Testing + +- Confirm `specsync check --strict --force --require-coverage 100` passes. +- Confirm all four skill copies quote the answer placeholder. +- Confirm Trust no longer ignores governed public-documentation paths. +- Run the repository native verification lane and `fledge trust verify`. +- Require the final hosted Trust, UI, and CodeQL checks to pass. diff --git a/.specsync/sdd.json b/.specsync/sdd.json index 803a2d5..796067c 100644 --- a/.specsync/sdd.json +++ b/.specsync/sdd.json @@ -38,8 +38,13 @@ "web/", "scripts/", "README.md", + "ROADMAP.md", + "CHANGELOG.md", + "SECURITY.md", "CONTRIBUTING.md", "docs/", + "docs.3md", + "specs/", "SPEC.md", "fledge.toml", ".trust.toml", @@ -52,10 +57,7 @@ ".cursor/", ".gemini/" ], - "ignored_paths": [ - ".specsync/", - "specs/" - ], + "ignored_paths": [], "verification_commands": [ "fledge lanes run verify" ], From 01263f573ae8d89b58f04c2be84b041164c8d789 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Tue, 14 Jul 2026 01:09:45 -0600 Subject: [PATCH 15/16] feat: refresh final SDD correction evidence --- .../approvals.json | 36 +++++++++++++ .../change.md | 2 +- .../state.json | 5 +- .../approvals.json | 7 +++ .../change.md | 2 +- .../state.json | 5 +- .../verification-attempts.json | 50 +++++++++++++++++++ .../verification.json | 16 ++++++ 8 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/verification-attempts.json create mode 100644 .specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/verification.json diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json index ca6090f..5d8ffab 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json @@ -42,5 +42,41 @@ "digest": "2514197b66c28890a33152e1f34edae858598990a6c2fcd0171df22d1715711c", "note": "Accepted after native Swift, TypeScript, Rust, generated-bundle, and editor verification plus successful hosted Trust, browser UI, and CodeQL checks on the corrected PR head." } + ], + "reopenings": [ + { + "schema_version": 1, + "change_id": "CHG-0001-adopt-trust-1-and-specsync-5", + "actor": "user:0xLeif", + "reason": "Authorized final governance review corrections changed delivery inputs after acceptance; refresh unchanged migration evidence with the full native lane.", + "timestamp": 1784012981, + "from_state": "accepted", + "to_state": "verifying", + "superseded_approval": { + "gate": "acceptance", + "actor": "user:0xLeif", + "timestamp": 1783974846, + "digest": "2514197b66c28890a33152e1f34edae858598990a6c2fcd0171df22d1715711c", + "note": "Accepted after native Swift, TypeScript, Rust, generated-bundle, and editor verification plus successful hosted Trust, browser UI, and CodeQL checks on the corrected PR head." + }, + "prior_verification": { + "timestamp": 1783974833, + "commit": "6148c1f853c5f50269a84d005a4d474ce384b9f2", + "contract_digest": "3e3993f3a310d989da0f46bf1d7643e8d7c3cfe201df57371fcb31e1c4b52116", + "workspace_digest": "0b62c7bf6e4900e50e9406a10f9d176018528ed72e5fc53aaba17d7f9594fdb6", + "acceptance_input_digest": "cfc943b5b376e22b72c0c900d66b9f2b57c945e8e70a215a880fbf4cf0dbca34", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [] + }, + "stale_acceptance_input_digest": "cfc943b5b376e22b72c0c900d66b9f2b57c945e8e70a215a880fbf4cf0dbca34", + "current_acceptance_input_digest": "a6793c577723410186164e0e0d9a4e91892380830069ed60dfb3278c211e8740" + } ] } diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md index f4cfb2d..945872c 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md @@ -1,6 +1,6 @@ --- id: CHG-0001-adopt-trust-1-and-specsync-5 -state: accepted +state: verifying type: migration base_commit: 2a145766b9ecb83d96ee15aa453a65cc2125571f --- diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json index a334084..e6ed9cf 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json @@ -5,10 +5,11 @@ "title": "Adopt Trust 1 and SpecSync 5", "description": "Adopt Trust 1 and SpecSync 5", "kind": "migration", - "state": "accepted", + "state": "verifying", + "canonical_applied": true, "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", "created_at": 1783826867, - "updated_at": 1783974846, + "updated_at": 1784012981, "affected_specs": [], "affected_paths": [ ".github/workflows/trust.yml", diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/approvals.json b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/approvals.json index d751961..a2846b9 100644 --- a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/approvals.json +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/approvals.json @@ -13,6 +13,13 @@ "timestamp": 1784012911, "digest": "5bd9d4eddcff67d4e2ed60328ba2cf59b66e0a8a29627e72b6b08fd006d3f754", "note": "Reapproved after replacing circular verification tasks with truthful completed configuration and preserving hosted checks as post-push evidence." + }, + { + "gate": "acceptance", + "actor": "user:0xLeif", + "timestamp": 1784012970, + "digest": "a02b2a8ea28461e6a5dbfe880389246f14291a0d72fb403709a616bab38bc6cb", + "note": "Closing approval after strict native verification passed all seven Swift, TypeScript, Rust, generated-bundle, and editor steps; hosted checks are not claimed yet." } ], "reopenings": [] diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/change.md b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/change.md index e6a2271..e0336a1 100644 --- a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/change.md +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/change.md @@ -1,6 +1,6 @@ --- id: CHG-0003-address-final-trust-and-sdd-governance-review-corrections -state: implementing +state: accepted type: migration base_commit: 2458e7d2e607a8cd98448652821d515ed1f51bf9 --- diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/state.json b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/state.json index 6404f78..3a95e35 100644 --- a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/state.json +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/state.json @@ -5,10 +5,11 @@ "title": "Address final Trust and SDD governance review corrections", "description": "Address final Trust and SDD governance review corrections", "kind": "migration", - "state": "implementing", + "state": "accepted", + "canonical_applied": true, "base_commit": "2458e7d2e607a8cd98448652821d515ed1f51bf9", "created_at": 1783975947, - "updated_at": 1784012911, + "updated_at": 1784012970, "affected_specs": [], "affected_paths": [ ".github/workflows/trust.yml", diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/verification-attempts.json b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/verification-attempts.json new file mode 100644 index 0000000..ce267e7 --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/verification-attempts.json @@ -0,0 +1,50 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1784012924, + "commit": "765abbf6be3919262f3fb885ed36439afafc5c5b", + "contract_digest": "5bd9d4eddcff67d4e2ed60328ba2cf59b66e0a8a29627e72b6b08fd006d3f754", + "workspace_digest": "96b757577179b0b7c087eebd3f8e96ac148ea0abce4320e96d43696c31a9255f", + "passed": false, + "commands": [ + { + "command": "fledge lanes run verify", + "success": false, + "exit_code": 1 + } + ], + "requirement_ids": [] + }, + { + "timestamp": 1784012934, + "commit": "765abbf6be3919262f3fb885ed36439afafc5c5b", + "contract_digest": "5bd9d4eddcff67d4e2ed60328ba2cf59b66e0a8a29627e72b6b08fd006d3f754", + "workspace_digest": "96b757577179b0b7c087eebd3f8e96ac148ea0abce4320e96d43696c31a9255f", + "passed": false, + "commands": [ + { + "command": "fledge lanes run verify", + "success": false, + "exit_code": 1 + } + ], + "requirement_ids": [] + }, + { + "timestamp": 1784012957, + "commit": "765abbf6be3919262f3fb885ed36439afafc5c5b", + "contract_digest": "5bd9d4eddcff67d4e2ed60328ba2cf59b66e0a8a29627e72b6b08fd006d3f754", + "workspace_digest": "96b757577179b0b7c087eebd3f8e96ac148ea0abce4320e96d43696c31a9255f", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [] + } + ] +} diff --git a/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/verification.json b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/verification.json new file mode 100644 index 0000000..0827812 --- /dev/null +++ b/.specsync/changes/CHG-0003-address-final-trust-and-sdd-governance-review-corrections/verification.json @@ -0,0 +1,16 @@ +{ + "timestamp": 1784012957, + "commit": "765abbf6be3919262f3fb885ed36439afafc5c5b", + "contract_digest": "5bd9d4eddcff67d4e2ed60328ba2cf59b66e0a8a29627e72b6b08fd006d3f754", + "workspace_digest": "96b757577179b0b7c087eebd3f8e96ac148ea0abce4320e96d43696c31a9255f", + "acceptance_input_digest": "c00a57191dd6a175286195a6217702c871180367d7d53ad5091b975b5619ee2e", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [] +} From 1916c06727d4f0c09e8a8489c5cd7966552e6e89 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Tue, 14 Jul 2026 01:11:53 -0600 Subject: [PATCH 16/16] feat(governance): refresh final rollout verification evidence --- .../approvals.json | 7 +++++++ .../change.md | 2 +- .../state.json | 4 ++-- .../verification-attempts.json | 20 +++++++++++++++++++ .../verification.json | 8 ++++---- 5 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 .specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification-attempts.json diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json index 5d8ffab..e66df8a 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/approvals.json @@ -41,6 +41,13 @@ "timestamp": 1783974846, "digest": "2514197b66c28890a33152e1f34edae858598990a6c2fcd0171df22d1715711c", "note": "Accepted after native Swift, TypeScript, Rust, generated-bundle, and editor verification plus successful hosted Trust, browser UI, and CodeQL checks on the corrected PR head." + }, + { + "gate": "acceptance", + "actor": "user:0xLeif", + "timestamp": 1784013064, + "digest": "fb0b6266d5085ac27eda5e6341cb6e6c69dedba28d6bbcf227334ccf87408200", + "note": "Fresh closing approval after final governance corrections and full seven-step native verification; hosted checks are not claimed yet." } ], "reopenings": [ diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md index 945872c..f4cfb2d 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/change.md @@ -1,6 +1,6 @@ --- id: CHG-0001-adopt-trust-1-and-specsync-5 -state: verifying +state: accepted type: migration base_commit: 2a145766b9ecb83d96ee15aa453a65cc2125571f --- diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json index e6ed9cf..9512fa6 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/state.json @@ -5,11 +5,11 @@ "title": "Adopt Trust 1 and SpecSync 5", "description": "Adopt Trust 1 and SpecSync 5", "kind": "migration", - "state": "verifying", + "state": "accepted", "canonical_applied": true, "base_commit": "2a145766b9ecb83d96ee15aa453a65cc2125571f", "created_at": 1783826867, - "updated_at": 1784012981, + "updated_at": 1784013064, "affected_specs": [], "affected_paths": [ ".github/workflows/trust.yml", diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification-attempts.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification-attempts.json new file mode 100644 index 0000000..ca89cfb --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification-attempts.json @@ -0,0 +1,20 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1784013006, + "commit": "01263f573ae8d89b58f04c2be84b041164c8d789", + "contract_digest": "3e3993f3a310d989da0f46bf1d7643e8d7c3cfe201df57371fcb31e1c4b52116", + "workspace_digest": "96b757577179b0b7c087eebd3f8e96ac148ea0abce4320e96d43696c31a9255f", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [] + } + ] +} diff --git a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification.json b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification.json index 1dfbecb..abe01aa 100644 --- a/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification.json +++ b/.specsync/changes/CHG-0001-adopt-trust-1-and-specsync-5/verification.json @@ -1,9 +1,9 @@ { - "timestamp": 1783974833, - "commit": "6148c1f853c5f50269a84d005a4d474ce384b9f2", + "timestamp": 1784013006, + "commit": "01263f573ae8d89b58f04c2be84b041164c8d789", "contract_digest": "3e3993f3a310d989da0f46bf1d7643e8d7c3cfe201df57371fcb31e1c4b52116", - "workspace_digest": "0b62c7bf6e4900e50e9406a10f9d176018528ed72e5fc53aaba17d7f9594fdb6", - "acceptance_input_digest": "cfc943b5b376e22b72c0c900d66b9f2b57c945e8e70a215a880fbf4cf0dbca34", + "workspace_digest": "96b757577179b0b7c087eebd3f8e96ac148ea0abce4320e96d43696c31a9255f", + "acceptance_input_digest": "a6793c577723410186164e0e0d9a4e91892380830069ed60dfb3278c211e8740", "passed": true, "commands": [ {