diff --git a/.attest.json b/.attest.json new file mode 100644 index 0000000..ba4a063 --- /dev/null +++ b/.attest.json @@ -0,0 +1,4 @@ +{ + "requireAttestation": true, + "requireTestsPassed": true +} 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/.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..9d0b080 --- /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. Remove `--minimal` if present and remember that minimal mode was requested. + Preserve the complete remaining argument string; do not truncate it to its + first whitespace-separated token. +2. Classify the complete remaining string as one of: + - **A bare module name** — a single kebab-case 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 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..00a0ede --- /dev/null +++ b/.cursor/commands/specsync-create-spec.md @@ -0,0 +1,35 @@ +Create a new spec-sync module spec. + +Arguments: $ARGUMENTS + +1. Remove `--minimal` if present and remember that minimal mode was requested. + Preserve the complete remaining argument string; do not truncate it to its + first whitespace-separated token. +2. Classify the complete remaining string as one of: + - **A bare module name** — a single kebab-case 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..bf8185a --- /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 "{{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. +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..26b856b --- /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. Remove --minimal if present and remember that minimal mode was requested. + Preserve the complete remaining argument string; do not truncate it to its + first whitespace-separated token. +2. Classify the complete remaining string as one of: + - A bare module name - a single kebab-case 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/ci.yml b/.github/workflows/ci.yml index f39788b..5b75045 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,17 @@ on: - Cargo.toml - Cargo.lock - .github/workflows/ci.yml + - .github/workflows/trust.yml + - .specsync/** + - specs/** + - .trust.toml + - .augur.toml + - .attest.json + - fledge.toml + - plugin.toml + - README.md + - CHANGELOG.md + - docs/** pull_request: branches: [main] paths: @@ -15,6 +26,17 @@ on: - Cargo.toml - Cargo.lock - .github/workflows/ci.yml + - .github/workflows/trust.yml + - .specsync/** + - specs/** + - .trust.toml + - .augur.toml + - .attest.json + - fledge.toml + - plugin.toml + - README.md + - CHANGELOG.md + - docs/** env: CARGO_TERM_COLOR: always diff --git a/.github/workflows/trust.yml b/.github/workflows/trust.yml new file mode 100644 index 0000000..1e5e560 --- /dev/null +++ b/.github/workflows/trust.yml @@ -0,0 +1,25 @@ +name: trust + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + trust: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v5 + with: + fetch-depth: 0 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt + - uses: Swatinem/rust-cache@v2 + - name: CorvidLabs Trust gate + id: trust + uses: CorvidLabs/trust@9d32b5786d2e9e4d39fc581c0091c721ee3d4226 # v1.0.0 diff --git a/.specsync/.gitignore b/.specsync/.gitignore new file mode 100644 index 0000000..a655086 --- /dev/null +++ b/.specsync/.gitignore @@ -0,0 +1,3 @@ +backup-3x/ +config.local.toml +hashes.json diff --git a/.specsync/adoption-report.json b/.specsync/adoption-report.json new file mode 100644 index 0000000..3f87fe1 --- /dev/null +++ b/.specsync/adoption-report.json @@ -0,0 +1,9 @@ +{ + "bootstrap_policy": { + "base_commit": "fc904d508cefaecf6e69bda7416bb62d4912d352", + "digest": "60f4daa45898deb8dd8e2e13c1b50cea62ece0d84fb8e188c29b74668c0f2bc6", + "path": ".specsync/sdd.json" + }, + "generated_at": 1783882746, + "requirements_needing_ids": [] +} 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-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/approvals.json b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/approvals.json new file mode 100644 index 0000000..eb00c02 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/approvals.json @@ -0,0 +1,19 @@ +{ + "approvals": [ + { + "gate": "definition", + "actor": "user:0xLeif", + "timestamp": 1783987290, + "digest": "cea8a322db10e3519fbbd2ab72a9d2976e0be22f1c6b746422dea6ba63ef5bbf", + "note": "Approved the audited migration definition with five truthful requirement mappings, portable native verification, complete governance path coverage, and no product-code changes." + }, + { + "gate": "acceptance", + "actor": "user:0xLeif", + "timestamp": 1783987354, + "digest": "4b9dc512b51461703a48b2eb6ee34185bbd61959b82bc7fe9ff9f9fe683e84be", + "note": "Closing approval after exact-head native verification passed with all five Speedtest requirement IDs, portable smoke coverage, and real 100% source coverage." + } + ], + "reopenings": [] +} diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/change.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/change.md new file mode 100644 index 0000000..22584b3 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/change.md @@ -0,0 +1,29 @@ +--- +id: CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin +state: accepted +type: migration +base_commit: fc904d508cefaecf6e69bda7416bb62d4912d352 +--- + +# Adopt SpecSync 5.0.1 and Trust 1.0.0 governance for the Speedtest Fledge plugin + +## Intent + +Adopt SpecSync 5.0.1 and Trust 1.0.0 governance for the Speedtest Fledge plugin + +## Affected Canonical Specs + +- `speedtest` + +## Acceptance Criteria + +- SpecSync strict file and LOC coverage is a non-vacuous 100%. +- All five canonical requirements have concrete evidence and stable IDs. +- Claude, Cursor, Codex, and Gemini integrations are installed. +- Trust doctor and native verification pass. +- Formatting, Clippy, 22 tests, release build, and portable help smoke pass. +- Governance-only pull requests trigger the preserved Linux, macOS, and Windows CI matrix. + +## No-spec Rationale + +Not applicable diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/context.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/context.md new file mode 100644 index 0000000..272fe04 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/context.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin +artifact: context +--- + +# Context + +Speedtest measures bounded latency, download, and upload samples against Cloudflare. The rollout adds verified governance without replacing cross-platform CI, release packaging, or Pages. diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/deltas/speedtest.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/deltas/speedtest.md new file mode 100644 index 0000000..6b0d746 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/deltas/speedtest.md @@ -0,0 +1,33 @@ +## MODIFIED + +### REQUIREMENT REQ-speedtest-001 +The default command SHALL measure latency, download, and upload, while direction subcommands limit the selected work. + +Acceptance Criteria +- Source inspection confirms the default, download-only, and upload-only dispatch branches select the documented measurements. + +### REQUIREMENT REQ-speedtest-002 +Each direction SHALL run for the bounded duration, rotate committed payload sizes, and record completed samples. + +Acceptance Criteria +- Duration unit tests require a one-second minimum and preserve non-zero values. +- Source inspection confirms both direction loops rotate the committed size list and record only completed samples before the deadline. + +### REQUIREMENT REQ-speedtest-003 +Truncated download responses and failed samples SHALL not inflate the throughput percentile. + +Acceptance Criteria +- Source inspection confirms downloads are sampled only when received bytes equal requested bytes and failed attempts add no sample. + +### REQUIREMENT REQ-speedtest-004 +Reports SHALL use decimal Mbps and a deterministic interpolated 90th percentile, returning zero for no samples. + +Acceptance Criteria +- Unit tests cover decimal Mbps conversion, empty/single/unsorted inputs, clamping, p0/p50/p90/p100, and two-value interpolation. + +### REQUIREMENT REQ-speedtest-005 +Human and JSON outputs SHALL represent the same report while interactive progress remains on standard error. + +Acceptance Criteria +- Report serialization tests cover full, partial, and empty JSON shapes. +- Source inspection confirms both renderers consume the same report and progress writes only to interactive standard error. diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/design.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/design.md new file mode 100644 index 0000000..b6ab75b --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/design.md @@ -0,0 +1,10 @@ +--- +change: CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin +artifact: design +--- + +# Design + +Add an active `speedtest` specification with stable sampling and report requirements. Stamp SpecSync 5.0.1 at 100% coverage and install all integrations. + +Trust runs formatting, Clippy, 22 tests, release build, and help smoke through Fledge. Risk blocks, provenance is progressive, and Atlas stays disabled because Pages is independent. The workflow pins Trust 1.0.0 immutably. diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/docs.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/docs.md new file mode 100644 index 0000000..161a7c9 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/docs.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin +artifact: docs +--- + +# Docs + +The managed `AGENTS.md` block documents the unified verification path. The canonical spec records existing behavior; no command or endpoint semantics change. diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/plan.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/plan.md new file mode 100644 index 0000000..56c1311 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/plan.md @@ -0,0 +1,12 @@ +--- +change: CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin +artifact: plan +--- + +# Plan + +1. Document measurement windows, samples, percentiles, and output contracts. +2. Adopt SpecSync 5.0.1 and install all integrations. +3. Add the complete Rust verification lane and Trust policy. +4. Add the immutable Trust workflow. +5. Validate deterministic behavior and preserve platform, release, and Pages checks. diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/research.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/research.md new file mode 100644 index 0000000..c2fa965 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/research.md @@ -0,0 +1,8 @@ +--- +change: CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin +artifact: research +--- + +# Research + +The single Rust implementation has 22 deterministic tests for duration bounds, Mbps conversion, percentile interpolation/clamping, progress fractions, and JSON reports. Live network throughput is intentionally excluded from deterministic CI. Existing CI builds and tests Linux, macOS, and Windows and blocks Clippy and formatting. diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/state.json b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/state.json new file mode 100644 index 0000000..3f7e930 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/state.json @@ -0,0 +1,61 @@ +{ + "schema_version": 1, + "id": "CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin", + "slug": "adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin", + "title": "Adopt SpecSync 5.0.1 and Trust 1.0.0 governance for the Speedtest Fledge plugin", + "description": "Adopt SpecSync 5.0.1 and Trust 1.0.0 governance for the Speedtest Fledge plugin", + "kind": "migration", + "state": "accepted", + "canonical_applied": true, + "base_commit": "fc904d508cefaecf6e69bda7416bb62d4912d352", + "created_at": 1783882816, + "updated_at": 1783987354, + "affected_specs": [ + "speedtest" + ], + "affected_paths": [ + "src/", + "Cargo.toml", + "Cargo.lock", + "plugin.toml", + "fledge.toml", + ".github/", + ".specsync/", + "specs/", + ".trust.toml", + ".attest.json", + ".augur.toml", + ".claude/", + ".codex/", + ".cursor/", + ".gemini/", + "AGENTS.md", + "README.md", + "CHANGELOG.md", + "docs/" + ], + "no_spec_change": false, + "no_spec_change_rationale": null, + "acceptance_criteria": [ + "SpecSync strict file and LOC coverage is a non-vacuous 100%.", + "All five canonical requirements have concrete evidence and stable IDs.", + "Claude, Cursor, Codex, and Gemini integrations are installed.", + "Trust doctor and native verification pass.", + "Formatting, Clippy, 22 tests, release build, and portable help smoke pass.", + "Governance-only pull requests trigger the preserved Linux, macOS, and Windows CI matrix." + ], + "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-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/tasks.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/tasks.md new file mode 100644 index 0000000..0d3afa8 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/tasks.md @@ -0,0 +1,15 @@ +--- +change: CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin +artifact: tasks +--- + +# Tasks + +- [x] Create the canonical Speedtest specification and stable requirements. +- [x] Adopt and stamp SpecSync 5.0.1 at 100% coverage. +- [x] Install all four integrations. +- [x] Add the five-step Rust lane and Trust policy. +- [x] Add the immutable Trust 1.0.0 workflow. +- [x] Validate formatting, Clippy, 22 tests, release build, smoke, and governance. +- [x] Prepare the portable definition approval and supported lifecycle commands. +- [x] Configure governance-only changes to trigger the preserved hosted platform matrix. diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/testing.md b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/testing.md new file mode 100644 index 0000000..09d8e85 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/testing.md @@ -0,0 +1,16 @@ +--- +change: CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin +artifact: testing +--- + +# Testing + +Local acceptance requires the five-step Fledge lane, all 22 deterministic tests, strict 100% coverage, four integrations, healthy Trust doctor, and a clean diff. + +- `REQ-speedtest-001`: dispatch-branch source inspection. +- `REQ-speedtest-002`: duration unit tests and bounded-loop source inspection. +- `REQ-speedtest-003`: completed-response and failed-sample source inspection. +- `REQ-speedtest-004`: Mbps and percentile unit tests. +- `REQ-speedtest-005`: report serialization tests and shared-report/progress source inspection. + +Hosted acceptance requires the new `trust` job plus existing Linux/macOS/Windows build-test matrix and Linux lint job. Live throughput remains an operator-run network check. diff --git a/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/verification.json b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/verification.json new file mode 100644 index 0000000..32af066 --- /dev/null +++ b/.specsync/changes/CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin/verification.json @@ -0,0 +1,22 @@ +{ + "timestamp": 1783987340, + "commit": "a4d6ce228dfe71a5d67eb68a2cef90704b24bb83", + "contract_digest": "cea8a322db10e3519fbbd2ab72a9d2976e0be22f1c6b746422dea6ba63ef5bbf", + "workspace_digest": "7c3eafa30aee6b43fa2a14ecb8b81f17a976404a0dd326f80128b5b198755954", + "acceptance_input_digest": "6311f2ccc218e42ef36359ad8a099cdbeabcf3e04c0312ff658d044cf3cb1dad", + "passed": true, + "commands": [ + { + "command": "fledge lanes run verify", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-speedtest-001", + "REQ-speedtest-002", + "REQ-speedtest-003", + "REQ-speedtest-004", + "REQ-speedtest-005" + ] +} diff --git a/.specsync/config.toml b/.specsync/config.toml new file mode 100644 index 0000000..a470655 --- /dev/null +++ b/.specsync/config.toml @@ -0,0 +1,12 @@ +# SpecSync 5 configuration +# Docs: https://github.com/CorvidLabs/spec-sync + +specs_dir = "specs" +source_dirs = ["src"] +exclude_dirs = [] +exclude_patterns = [] +required_sections = ["Purpose", "Public API", "Invariants", "Behavioral Examples", "Error Cases", "Dependencies", "Change Log"] +enforcement = "strict" + +[lifecycle] +track_history = false diff --git a/.specsync/registry.toml b/.specsync/registry.toml new file mode 100644 index 0000000..a4706d9 --- /dev/null +++ b/.specsync/registry.toml @@ -0,0 +1,5 @@ +[registry] +name = "fledge-plugin-speedtest-trust-wave6" + +[specs] +speedtest = "specs/speedtest/speedtest.spec.md" diff --git a/.specsync/sdd.json b/.specsync/sdd.json new file mode 100644 index 0000000..362704f --- /dev/null +++ b/.specsync/sdd.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "enabled": true, + "require_change_for_meaningful_files": true, + "meaningful_paths": [ + "src/", + ".github/", + ".claude/", + ".codex/", + ".cursor/", + ".gemini/", + "docs/", + "README.md", + "CHANGELOG.md", + "AGENTS.md", + ".augur.toml", + ".attest.json", + "Cargo.toml", + "Cargo.lock", + "plugin.toml", + "fledge.toml", + ".trust.toml", + ".specsync/sdd.json", + ".specsync/config.toml", + ".specsync/version" + ], + "ignored_paths": [ + ".specsync/", + "specs/" + ], + "verification_commands": [ + "fledge lanes run verify" + ], + "custom_artifacts": {}, + "principles_file": null +} diff --git a/.specsync/version b/.specsync/version new file mode 100644 index 0000000..6b244dc --- /dev/null +++ b/.specsync/version @@ -0,0 +1 @@ +5.0.1 diff --git a/.trust.toml b/.trust.toml new file mode 100644 index 0000000..12e0013 --- /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 = 100 +skip_reason = "" + +[risk] +threshold = "block" + +[provenance] +mode = "soft" +policy = ".attest.json" +skip_reason = "" + +[atlas] +enabled = false +skip_reason = "Standalone Pages publication remains independently managed" diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3da08a2 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,12 @@ + +## CorvidLabs trust toolchain + +This repository uses one trust gate. Every session must use it and must not bypass or weaken it. + +- 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. + + diff --git a/fledge.toml b/fledge.toml index d3da7a6..5106704 100644 --- a/fledge.toml +++ b/fledge.toml @@ -4,3 +4,8 @@ build = "cargo build --release" test = "cargo test" lint = "cargo clippy -- -D warnings" fmt = "cargo fmt --check" +smoke = "cargo run --release -- --help" + +[lanes.verify] +description = "Format, lint, test, build, and smoke-test the speedtest plugin" +steps = ["fmt", "lint", "test", "build", "smoke"] diff --git a/specs/speedtest/context.md b/specs/speedtest/context.md new file mode 100644 index 0000000..6cd3259 --- /dev/null +++ b/specs/speedtest/context.md @@ -0,0 +1,17 @@ +--- +spec: speedtest.spec.md +--- + +## Context + +This Rust plugin offers a dependency-light Fledge command using public Cloudflare endpoints and deterministic local metric calculations. + +## Related Modules + +- Cloudflare download and upload speed endpoints. +- Fledge plugin command registration. + +## Design Decisions + +- Use a percentile rather than a single sample to reduce transient noise. +- Keep progress on standard error so JSON remains machine-readable. diff --git a/specs/speedtest/requirements.md b/specs/speedtest/requirements.md new file mode 100644 index 0000000..5f6993c --- /dev/null +++ b/specs/speedtest/requirements.md @@ -0,0 +1,54 @@ +--- +spec: speedtest.spec.md +--- + +## User Stories + +- As a developer, I want a quick terminal measurement of current network latency and throughput. + +## Acceptance Criteria + +### REQ-speedtest-001 + +The default command SHALL measure latency, download, and upload, while direction subcommands limit the selected work. + +Acceptance Criteria +- Source inspection confirms the default, download-only, and upload-only dispatch branches select the documented measurements. + +### REQ-speedtest-002 + +Each direction SHALL run for the bounded duration, rotate committed payload sizes, and record completed samples. + +Acceptance Criteria +- Duration unit tests require a one-second minimum and preserve non-zero values. +- Source inspection confirms both direction loops rotate the committed size list and record only completed samples before the deadline. + +### REQ-speedtest-003 + +Truncated download responses and failed samples SHALL not inflate the throughput percentile. + +Acceptance Criteria +- Source inspection confirms downloads are sampled only when received bytes equal requested bytes and failed attempts add no sample. + +### REQ-speedtest-004 + +Reports SHALL use decimal Mbps and a deterministic interpolated 90th percentile, returning zero for no samples. + +Acceptance Criteria +- Unit tests cover decimal Mbps conversion, empty/single/unsorted inputs, clamping, p0/p50/p90/p100, and two-value interpolation. + +### REQ-speedtest-005 + +Human and JSON outputs SHALL represent the same report while interactive progress remains on standard error. + +Acceptance Criteria +- Report serialization tests cover full, partial, and empty JSON shapes. +- Source inspection confirms both renderers consume the same report and progress writes only to interactive standard error. + +## Constraints + +- Results depend on network path, endpoint availability, and runtime load and are not a service-level guarantee. + +## Out of Scope + +- Server selection, historical storage, ISP diagnostics, and continuous monitoring. diff --git a/specs/speedtest/speedtest.spec.md b/specs/speedtest/speedtest.spec.md new file mode 100644 index 0000000..6ccd66d --- /dev/null +++ b/specs/speedtest/speedtest.spec.md @@ -0,0 +1,68 @@ +--- +module: speedtest +version: 2 +status: active +files: + - src/main.rs + +db_tables: [] +depends_on: [] +--- + +# Speedtest + +## Purpose + +Measure network latency, download throughput, and upload throughput against Cloudflare's speed-test endpoints with bounded duration and human or JSON output. + +## Public API + +| Surface | Behavior | +|---------|----------| +| default | Measure latency, download, and upload. | +| download | Measure latency and download only. | +| upload | Measure upload only. | +| duration | Bound each selected direction's measurement window to at least one second. | +| JSON | Emit a structured report without progress output contamination. | + +## Invariants + +1. Progress is emitted only to interactive standard error; report output remains clean. +2. Latency uses the best of three zero-byte probes. +3. Download and upload rotate through committed payload sizes until the duration window ends. +4. Truncated download responses are excluded from throughput samples. +5. Throughput uses decimal megabits per second. +6. The reported direction throughput is the linearly interpolated 90th percentile. +7. Empty sample sets report zero rather than failing or producing NaN. +8. HTTP requests use the configured timeout and rustls TLS. + +## Behavioral Examples + +``` +Given network access to the configured Cloudflare endpoints +When the developer runs a selected direction for a bounded duration +Then the plugin reports sample counts and the computed latency or throughput in human or JSON form +``` + +## Error Cases + +| Error | When | Behavior | +|-------|------|----------| +| Client creation failure | TLS or client configuration cannot initialize | Surface the client error. | +| Latency failure | A probe cannot be sent or drained | Report latency context and exit non-zero. | +| Download failure | Requests fail within the measurement loop | Skip failed samples and report from completed full responses. | +| Upload failure | Requests fail within the measurement loop | Skip failed samples and report from completed samples. | +| Serialization failure | JSON report cannot be encoded | Surface the serialization error. | + +## Dependencies + +- Rust 1.89 or later +- Network access to Cloudflare speed-test endpoints +- `reqwest`, `clap`, `serde`, and `serde_json` + +## Change Log + +| Version | Date | Changes | +|---------|------|---------| +| 1 | 2026-07-12 | Document existing bounded latency and throughput measurement behavior for SpecSync 5 adoption. | +| 2 | 2026-07-14 | CHG-0001-adopt-specsync-5-0-1-and-trust-1-0-0-governance-for-the-speedtest-fledge-plugin: Adopt SpecSync 5.0.1 and Trust 1.0.0 governance for the Speedtest Fledge plugin | diff --git a/specs/speedtest/tasks.md b/specs/speedtest/tasks.md new file mode 100644 index 0000000..131f270 --- /dev/null +++ b/specs/speedtest/tasks.md @@ -0,0 +1,8 @@ +--- +spec: speedtest.spec.md +--- + +## Tasks + +- [x] Document measurement windows, samples, percentiles, and output behavior. +- [x] Preserve cross-platform build, tests, lint, formatting, and packaging. diff --git a/specs/speedtest/testing.md b/specs/speedtest/testing.md new file mode 100644 index 0000000..a0f99fe --- /dev/null +++ b/specs/speedtest/testing.md @@ -0,0 +1,18 @@ +--- +spec: speedtest.spec.md +--- + +## Test Plan + +### Unit Tests + +- Mbps conversion for zero, subsecond, and standard durations. +- Percentile empty, single, interpolation, sorting, and clamping behavior. + +### Integration Tests + +- `cargo fmt --check` +- `cargo clippy -- -D warnings` +- `cargo test` +- `cargo build --release` +- Verify help without performing a live network test.