diff --git a/.github/ISSUE_TEMPLATE/adoption_help.yml b/.github/ISSUE_TEMPLATE/adoption_help.yml new file mode 100644 index 0000000..ffb45e5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/adoption_help.yml @@ -0,0 +1,74 @@ +name: Adoption help +description: Ask a focused public question about trying CCP in a repository. +title: "[Adoption help]: " +labels: + - question +body: + - type: markdown + attributes: + value: | + Use this form for setup, fit, or first-run questions. This is not an evidence report: do not attach private receipts, raw logs, secrets, or customer data. + - type: input + id: ccp_version + attributes: + label: CCP version + description: Which commit-ci-preflight version are you using? + placeholder: commit-ci-preflight 0.1.0 + validations: + required: true + - type: input + id: project_runtime + attributes: + label: Project runtime + description: Which language runtime, toolchain, or interpreter does the repository use? + placeholder: Rust 1.96 with Cargo + validations: + required: true + - type: input + id: platform + attributes: + label: Platform + description: Include OS, architecture, and relevant container runtime; policy/resource profiles are separate from the project runtime. + placeholder: macOS 15, Apple Silicon, Docker Desktop + validations: + required: true + - type: input + id: repository_language + attributes: + label: Repository language + description: What primary language and build tooling does the repository use? + placeholder: Rust with Cargo + validations: + required: true + - type: textarea + id: attempted_step + attributes: + label: Attempted step + description: What were you trying to do, and which documented command or guide did you follow? + validations: + required: true + - type: textarea + id: error_summary + attributes: + label: Bounded error summary + description: Summarize the visible result without pasting private or unredacted logs. + validations: + required: true + - type: textarea + id: expected_outcome + attributes: + label: Expected outcome + description: What result would let you decide whether CCP fits your repository? + validations: + required: true + - type: checkboxes + id: privacy_confirmation + attributes: + label: Public-safe content + options: + - label: I have removed secrets, private logs, private receipt fields, customer data, machine identity, and local paths. + required: true + - type: markdown + attributes: + value: | + For a completed trial with public, redacted results, use the adoption-report form instead. For a security vulnerability, follow SECURITY.md. diff --git a/CHANGELOG.md b/CHANGELOG.md index 11797f4..e874387 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,14 @@ Semantic Versioning after its first public release. ### Added +- Added the adoption-help issue-form source and a 1280 × 640 social-preview PNG + upload candidate. GitHub form rendering/live chooser remains unverified until + the remote gate; preview upload is owner-only and pending. + +- Added a benefit-led visitor journey, bounded PR #71 case study, and public + support routing for adoption, defects, security reports, and proposals, + including concise operator-safety routing for agent-mode questions. + - Shared terminal owned-resource finalization now routes historical and matrix runs, benchmarks, and guarded execution through completion-before-release, exactly-once admission release, and fail-closed release-error precedence. diff --git a/README.md b/README.md index 26cecb1..6b0e25a 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,18 @@ # Commit CI Preflight -Proof-carrying CI for developer-owned execution. Commit CI Preflight runs a -reviewed, pinned execution contract on your hardware, writes a commit-bound -receipt, and lets GitHub verify that evidence instead of rerunning heavy work. +> **Run heavy CI locally. Prove the exact commit on GitHub.** -Commit CI Preflight is an independent, vendor-neutral Apache-2.0 project with a -Rust core. It is designed for teams whose remote CI cost or queue time is -growing, but who do not want cost control to weaken review, security, or -platform coverage. +Commit CI Preflight (CCP) is an independent, vendor-neutral Apache-2.0 Rust +project that turns expensive, deterministic checks into commit-bound evidence: +run a reviewed plan on your machine, then let a small GitHub gate verify the +exact pull-request head. It is for teams whose remote CI cost or queue time is +growing without weakening review, security, or platform coverage. + +Start here: + +- [PR #71 case study](docs/CASE_STUDY_PR71.md) — a bounded, public example. +- [Clean-room tutorial](docs/TUTORIAL.md) — produce and verify a first receipt. +- [Adoption guide](docs/ADOPTION_GUIDE.md) — decide whether CCP fits your repository. > Status: **v0.1.0-rc.1 prerelease**. The source implementation and native > benchmark evidence are complete. The @@ -65,6 +70,14 @@ absolute home paths, and personal or machine identity fields. A receipt is integrity and policy evidence. It is not an identity attestation, a signature, or proof that arbitrary local and hosted workflows are identical. +## Is CCP for this repository? + +| If your repository has… | CCP fit | +|---|---| +| deterministic, container-friendly checks and pinned runtime images | **Yes — start with a clean-room trial** | +| trusted secrets, deployments, or platform-specific behavior | **Partial — retain the relevant remote/native jobs** | +| a requirement for signed identity-bound attestations | **No — CCP is not that attestation system** | + ## Quick start Adopting CCP in another repository? Start with the @@ -87,92 +100,25 @@ cargo build --locked The first build can take longer when Rust dependencies are not cached. `plan` normalizes the contract, `doctor` performs a bounded runtime probe, and `dry-run` renders the exact container command and mounts. None of these three -commands executes project code or emits an attestable receipt. +commands executes project code or emits an attestable receipt. For admission, +resource, cache, and guarded-workflow details, read the +[coordination runbook](docs/COORDINATION_RUNBOOK.md), +[local run contract](docs/LOCAL_RUN.md), and +[resource observation history](docs/RESOURCE_OBSERVATION_HISTORY.md). + +The planned agent admission mode is an owner-approved safety exception for +orphan prevention, not a second scheduler. `agent mode opt-in` must remain +explicit: operators must never bypass unknown ownership, never revive a terminated chat, +and never auto-execute a command. An official launcher is a shell-free wrapper around one explicit program argv. +Official launchers must pass through `guard exec` to be covered. See the +coordination runbook, local run contract, and adoption guide above for the +complete safety contract. For a real PASS and receipt, use the [clean-room tutorial](docs/TUTORIAL.md). It first creates a separate Git repository for the fixture; running the example configuration against this source checkout would validate the wrong repository. -### 2. Inspect a configuration without running checks - -```console -./target/debug/commit-ci-preflight plan --config examples/projects/rust/.commit-ci-preflight.toml -./target/debug/commit-ci-preflight doctor --config examples/projects/rust/.commit-ci-preflight.toml -./target/debug/commit-ci-preflight dry-run --config examples/projects/rust/.commit-ci-preflight.toml -``` - -`doctor` performs a bounded read-only runtime probe. `dry-run` prints the -exact container argv and mounts but does not execute project code. - -`run` and `benchmark` are serialized through a default-on host-wide single-slot -queue so independent local agents cannot start both heavy workloads at once. -The planned agent admission mode is an owner-approved safety exception for -orphan prevention, not a second scheduler. -This agent mode opt-in must never bypass unknown ownership. -This agent mode opt-in must never revive a terminated chat. -This agent mode opt-in must never auto-execute a command. -A live activity must make an explicit claim before it invokes its own guarded -command. -Use `--admission-timeout-seconds` to select the bounded wait. The -`admission status --json` result distinguishes the transient `queue_lock` from -the heavy-work `slot_lock`, and reports the slot's opaque owner/run identifier, -acquisition time, heartbeat time, and lease state when available. A missing -owner record, a malformed lease, or a contradiction between the OS lock and -the lease is reported as `unknown` and is never treated as inactivity. The -status also states explicitly that absence of a process in one local shell -does not prove global inactivity across Codex activities or users. On macOS, the queue is followed by a strict `macos-v4` -host-memory admission sample, and `run` has a two-second watchdog that cancels -only on sustained compound or critical pressure. Admission requires at least 20% available memory and -3 GiB reclaimable uncompressed memory, and caps swap at the smaller of 8 GiB -and 30% of physical RAM. Compression alone is advisory both before and during -the run; at pre-start it denies only when at least 70% compression accompanies -another pressure signal. The in-run watchdog treats compression the same way: -soft cancellation needs -at least two converging signals for about 30 seconds, while critical available, -reclaimable, swap, or compound-compression conditions remain immediate stops. -`resource status --json` reports bounded metrics and -capability; Linux and Windows report `unsupported_not_enforced`. Resource and -admission evidence are not part of receipts yet. - -Wrap any other long local workflow with the same protection by passing one -explicit argv after `--`: - -```console -commit-ci-preflight guard exec \ - --admission-timeout-seconds 21600 \ - --timeout-seconds 21600 \ - --resource-profile ready \ - --resource-workload-family brain-linux-ci-v1 \ - --resource-executor orbstack \ - --resource-execution-mode emulated \ - --resource-target-platform linux-amd64 \ - -- make all -``` - -The wrapper never invokes a shell, runs the child from the caller's current -working directory, never creates a receipt, and keeps the admission slot until -the supervised process tree has stopped. Both waits -default to six hours for `guard exec` and are capped at 24 hours. On macOS it -retains at most 500 local, privacy-bounded v2 summaries with workload, -executor, cache, execution-mode, target and optional requested-limit context. -The history changes no policy decision and can be disabled -with `--no-resource-history`; see the -[resource observation history contract](docs/RESOURCE_OBSERVATION_HISTORY.md). -Official launchers must pass through `guard exec` to be covered. CCP does not -claim visibility into direct Docker or OrbStack processes that bypass it; see -the [coverage and adoption inventory](docs/ORBSTACK_TELEMETRY_COVERAGE.md). -When multiple agent activities or repositories share the Mac, follow the -[cross-activity coordination runbook](docs/COORDINATION_RUNBOOK.md). It defines -the owner/lease interpretation, reservation handoff, worktree isolation, and -safe recovery rules; a process list from one terminal is not a host-wide -ownership proof. -Inspect the bounded local records without starting work: - -```console -commit-ci-preflight resource history --json -``` - -### 3. Run the clean-room demo +### 2. Run the clean-room demo Follow the [end-to-end tutorial](docs/TUTORIAL.md). It copies a tiny public Rust fixture into its own Git repository, runs its test through a pinned container, @@ -182,6 +128,12 @@ repository policy. For installation, checksum verification, and local candidate archives, see [the installation guide](docs/INSTALLATION.md). +## Dogfooding proof + +This repository uses CCP for its own bounded qualification workflow. See the +[PR #71 case study](docs/CASE_STUDY_PR71.md) for the exact public anchors and +the limits of what that evidence proves. + ## What makes it different | Tool or approach | Primary model | Relationship to Commit CI Preflight | diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 0000000..7adac05 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,13 @@ +# Support + +Please choose the smallest public route that matches your question: + +- Reproducible defects: use the [bug report form](https://github.com/MarcoPorcellato/commit-ci-preflight/issues/new?template=bug_report.yml). +- Adoption questions: use the public [issue chooser](https://github.com/MarcoPorcellato/commit-ci-preflight/issues/new/choose) and select **Adoption help** when GitHub displays it. The form is for fit and setup questions, not evidence reports. +- Completed trials: use the [adoption report form](https://github.com/MarcoPorcellato/commit-ci-preflight/issues/new?template=adoption_report.yml). +- Security vulnerabilities: follow [SECURITY.md](SECURITY.md) and its private reporting instructions. +- Design proposals: use the [feature request form](https://github.com/MarcoPorcellato/commit-ci-preflight/issues/new?template=feature_request.yml). + +Before opening a public issue, remove secrets, proprietary logs, receipts with +private fields, customer data, machine identity, and local paths. A minimal +reproduction and the relevant public commit are usually enough. diff --git a/docs/CASE_STUDY_PR71.md b/docs/CASE_STUDY_PR71.md new file mode 100644 index 0000000..32b781f --- /dev/null +++ b/docs/CASE_STUDY_PR71.md @@ -0,0 +1,39 @@ +# Case study: Commit CI Preflight PR #71 + +## What problem this demonstrates + +CCP's `dry-run` output is a planning surface, not a replay bundle. A copied +Docker command can reference lifecycle-managed cache sources that no longer +exist; the diagnostic must therefore use its own writable, independently +validated mounts. + +## Exact public anchors + +This case study concerns [PR #71](https://github.com/MarcoPorcellato/commit-ci-preflight/pull/71) +at head `f3fb14a0329cf031d08f474115a8b56fe1cffcf6`, merged by commit +`820a7fa6ce83a7ac8593c2800f8be4f44ab82ebc`. + +The append-only evidence ref resolves to commit +`382ba81a6869777a92f987068e2814f542e7ec8b`. Its public receipt has SHA-256 +`624477439b1bdb7b397876a7e5f8434057f8805835162c5fccb21beac015000b` and +receipt ID `sha256:3536dce784a646f6450f6a228230e09ffff8d4d5bd45f89dfd285223a9a235d1`. +The associated [workflow run](https://github.com/MarcoPorcellato/commit-ci-preflight/actions/runs/33220815044) +completed successfully. + +## What happened + +The workflow followed a bounded lifecycle: local qualification produced the +receipt; evidence was published append-only; GitHub checked the receipt against +the exact pull-request head; and the pull request was merged. The public +[evidence ref](https://github.com/MarcoPorcellato/commit-ci-preflight/tree/ccp-evidence/f3fb14a0329cf031d08f474115a8b56fe1cffcf6) +and [receipt specification](RECEIPT_SPEC.md) describe the inspectable artifacts. + +## What this proves — and does not prove + +The receipt integrity and policy checks, together with the exact-head gate, +prove the recorded local evidence for this exact commit. They do not prove +producer identity, a signature, cost savings, arbitrary hosted-CI parity, or +qualification of other platforms. They also do not turn a receipt into an +identity attestation. + +The [verification policy](VERIFICATION_POLICY.md) defines these boundaries. diff --git a/docs/REPOSITORY_PRESENTATION.md b/docs/REPOSITORY_PRESENTATION.md index 41f3ee9..3af50be 100644 --- a/docs/REPOSITORY_PRESENTATION.md +++ b/docs/REPOSITORY_PRESENTATION.md @@ -6,10 +6,11 @@ GitHub setting. ## Recommended repository metadata -- Description: `Proof-carrying CI: run heavy checks locally, verify exact-commit receipts on GitHub.` +- Description: `Run heavy CI locally. Verify exact-commit receipts on GitHub.` - Website: leave empty until a maintained project site exists. -- Topics: `ci`, `continuous-integration`, `devtools`, `github-actions`, - `local-first`, `rust`, `supply-chain`, `developer-tools`. +- Topics: `ci`, `continuous-integration`, `developer-tools`, `devtools`, + `github-actions`, `local-ci`, `local-first`, `reproducible-builds`, `rust`, + `supply-chain`. - Discussions: enable only when a maintainer is ready to moderate adoption and design questions. @@ -39,6 +40,9 @@ Before uploading a preview through **Settings → General → Social preview**: The repository does not treat the source SVG as proof that GitHub is currently using that image. +The rendered `docs/assets/social-preview.png` is an upload candidate only. It +has not been uploaded or verified as the live GitHub preview. + ## Public claim boundary Use `proof-carrying CI` and `CI receipts for exact Git commits`. Do not claim diff --git a/docs/assets/social-preview.png b/docs/assets/social-preview.png new file mode 100644 index 0000000..4fe22bb Binary files /dev/null and b/docs/assets/social-preview.png differ diff --git a/docs/superpowers/goals/2026-08-29-open-source-growth-program.txt b/docs/superpowers/goals/2026-08-29-open-source-growth-program.txt new file mode 100644 index 0000000..76f616f --- /dev/null +++ b/docs/superpowers/goals/2026-08-29-open-source-growth-program.txt @@ -0,0 +1,34 @@ +Complete the Commit CI Preflight open-source growth and truthful stable-release +programme according to the canonical specification at +`docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md` and the +master plan at +`docs/superpowers/plans/2026-08-29-open-source-growth-program.md`. + +Start from the isolated branch `codex/open-source-growth-program-v1`, whose +last verified base was `820a7fa6ce83a7ac8593c2800f8be4f44ab82ebc`, but reverify +the live worktree, `origin/main`, GitHub state, active CCP operator contract, +and completed milestone evidence before acting. Preserve the divergent primary +checkout and do not redo work already proved in the specification ledger. + +Proceed autonomously through dependency-ordered milestones M0-M10. Create an +exact live-source TDD plan before each milestone, deliver independently +reviewable commits and pull requests, run deterministic validation before +native, network, Docker, or CCP work, and keep the canonical specification and +restart handoff current. + +Use deterministic tools first. Delegate bounded inventories, documentation, +mechanical isolated edits, deterministic test runs, and independent reviews to +GPT-5.6 Luna. Keep architecture, trust, security, cryptography, integration, +qualification, release, publication, and merge decisions with the primary +agent. Serialize overlapping writes and verify every delegated result. + +Keep all evidence and claim boundaries unchanged. Treat commit, push, PR, +ready transition, CCP run, evidence publication, merge, repository settings, +package upload, tag, release, signing, case-study consent, and public launch as +separate gates requiring exact live authorization when not already explicit. +Never silently replace the installed global producer or manipulate CCP +admission, journal, receipt, lease, cache, lock, or resource state. + +Continue safe independent work until every applicable completion item is +supported by authoritative current evidence. Ask only at a named authority +boundary, an unavailable native/consent dependency, or a material scope change. diff --git a/docs/superpowers/plans/2026-08-29-m1-conversion-surface.md b/docs/superpowers/plans/2026-08-29-m1-conversion-surface.md new file mode 100644 index 0000000..991aba7 --- /dev/null +++ b/docs/superpowers/plans/2026-08-29-m1-conversion-surface.md @@ -0,0 +1,368 @@ +# M1 Conversion Surface and Dogfooding Proof Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make Commit CI Preflight understandable, credible, and actionable for a new maintainer while preserving every evidence, release, and trust boundary. + +**Architecture:** Human copy is reviewed as copy, not frozen by source-string tests. Executable repository contracts instead protect navigability, issue-form validity, and the rendered social-preview asset; a bounded dogfooding case study connects the product claim to public exact-head evidence. GitHub metadata changes remain a separate remote gate after the source PR is merged. + +**Tech Stack:** Markdown, Rust integration tests, GitHub issue forms, SVG/PNG assets, GitHub CLI read-only evidence checks. + +**Spec:** `docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md` + +## Global Constraints + +- All shell commands begin with `rtk`. +- Work only in `/Users/marco1/Documents/CODICE con VS CODE/ccp-worktrees/open-source-growth-program-v1` on `codex/open-source-growth-program-v1`. +- Preserve the divergent primary checkout. +- Do not assert exact marketing sentences in tests; human prose earns editorial review, not a change-detector test. +- TDD applies to the executable link, PNG, and issue-form contracts. +- Every public claim names or links authoritative evidence and states what it does not prove. +- Do not claim zero CI, guaranteed savings, publisher identity, execution attestation, hosted parity, or unqualified platforms. +- Every user-visible source change updates `CHANGELOG.md`. +- Do not push, open a PR, publish evidence, merge, alter GitHub settings, or upload the preview during local M1 implementation. +- Do not invoke CCP, Docker, or a heavy full-suite run without a fresh exact authorization envelope. + +## File Structure + +- `tests/public_documentation_contract.rs` — executable repository-relative Markdown link and PNG structure validation. +- `README.md` — visitor journey: pain, mechanism, proof, fit, first action, boundaries. +- `docs/CASE_STUDY_PR71.md` — exact public dogfooding proof with explicit non-claims. +- `SUPPORT.md` — routes adoption help, defects, security reports, and evidence discussions. +- `.github/ISSUE_TEMPLATE/adoption_help.yml` — structured adoption question form distinct from evidence reports. +- `tests/repository_hygiene_contract.rs` — issue-form and source social-preview safety contract. +- `docs/assets/social-preview.svg` — editable source of truth. +- `docs/assets/social-preview.png` — GitHub-uploadable 1280x640 render under 1 MiB. +- `docs/REPOSITORY_PRESENTATION.md` — exact proposed description/topics and owner-only upload procedure. +- `CHANGELOG.md` — Unreleased user-visible M1 record. + +--- + +### Task 1: Executable public-documentation contracts + +**Files:** +- Create: `tests/public_documentation_contract.rs` + +**Interfaces:** +- Produces: `local_link_destinations(markdown: &str) -> Vec` +- Produces: `validate_local_links(root: &Path, document: &Path) -> Vec` +- Produces: `markdown_heading_anchors(markdown: &str) -> HashSet` +- Produces: `png_dimensions(bytes: &[u8]) -> Result<(u32, u32), String>` +- Consumed by: Task 2 public README/case-study/support link validation and Task 3 preview validation. + +- [ ] **Step 1: Write failing parser and PNG tests** + + Create the test file with literal fixtures that require: + + ```rust + #[test] + fn local_link_validation_reports_missing_files_and_fragments() { + let root = unique_fixture_root("broken-links"); + std::fs::create_dir_all(root.join("docs")).expect("create docs"); + std::fs::write( + root.join("README.md"), + "# Root\n\n[missing](docs/missing.md)\n[bad anchor](docs/present.md#absent)\n", + ) + .expect("write README"); + std::fs::write(root.join("docs/present.md"), "# Present heading\n") + .expect("write target"); + + let findings = validate_local_links(&root, Path::new("README.md")); + + assert_eq!( + findings, + vec![ + "README.md: missing local target docs/missing.md", + "README.md: missing fragment #absent in docs/present.md", + ] + ); + } + + #[test] + fn png_dimensions_rejects_invalid_or_truncated_bytes() { + assert_eq!(png_dimensions(b"not a png"), Err("invalid PNG signature".into())); + } + ``` + + Test fixtures must use a unique directory under `std::env::temp_dir()` and remove only that exact owned directory after assertions. + +- [ ] **Step 2: Run RED and confirm the intended compile failure** + + ```console + rtk cargo test --locked --test public_documentation_contract -- --nocapture + ``` + + Expected: compilation fails because the four declared helper interfaces are not implemented. + +- [ ] **Step 3: Implement the minimal link and PNG helpers** + + Implement only inline Markdown links of the form `](destination)`. Ignore `http:`, `https:`, `mailto:`, absolute `/` URLs, and fragment-only links after validating them against the current document. Strip optional angle brackets and split one optional `#fragment`. Reject path traversal escaping `root`; percent-decoding is out of scope and must be reported as unsupported rather than guessed. + + Parse PNG dimensions only from the standard 8-byte signature followed by the `IHDR` chunk. Read width and height as big-endian `u32`; reject missing `IHDR`, zero dimensions, and truncated bytes. + +- [ ] **Step 4: Add the repository public-document set** + + Validate these current files: + + ```rust + const PUBLIC_DOCUMENTS: &[&str] = &[ + "README.md", + "SUPPORT.md", + "docs/CASE_STUDY_PR71.md", + "docs/INSTALLATION.md", + "docs/TUTORIAL.md", + "docs/ADOPTION_GUIDE.md", + "docs/BETA_SUPPORT.md", + "docs/REPOSITORY_PRESENTATION.md", + "docs/THREAT_MODEL.md", + ]; + ``` + + Until Task 2 creates `SUPPORT.md` and the case study, keep them out of the active slice but leave one comment naming Task 2 as the point where they become required. The completed Task 2 must remove the comment and add both paths. + +- [ ] **Step 5: Run GREEN** + + ```console + rtk cargo test --locked --test public_documentation_contract -- --nocapture + ``` + + Expected: all parser, PNG, traversal, and current-document link tests pass. + +- [ ] **Step 6: Commit Task 1** + + ```console + rtk git add tests/public_documentation_contract.rs + rtk git commit -m "test: validate public documentation artifacts" + ``` + +### Task 2: Benefit-led README, support path, and PR #71 case study + +**Files:** +- Modify: `README.md` +- Create: `docs/CASE_STUDY_PR71.md` +- Create: `SUPPORT.md` +- Modify: `tests/public_documentation_contract.rs` +- Modify: `CHANGELOG.md` + +**Interfaces:** +- Consumes: Task 1 link checker. +- Consumes exact public evidence: PR head `f3fb14a0329cf031d08f474115a8b56fe1cffcf6`, evidence commit `382ba81a6869777a92f987068e2814f542e7ec8b`, receipt SHA-256 `624477439b1bdb7b397876a7e5f8434057f8805835162c5fccb21beac015000b`, receipt ID `sha256:3536dce784a646f6450f6a228230e09ffff8d4d5bd45f89dfd285223a9a235d1`, workflow run `33220815044`, merge commit `820a7fa6ce83a7ac8593c2800f8be4f44ab82ebc`. +- Produces: public visitor path and dogfooding proof consumed by Task 4 editorial review. + +- [ ] **Step 1: Reverify the public case-study anchors read-only** + + ```console + rtk gh pr view 71 --repo MarcoPorcellato/commit-ci-preflight --json state,headRefOid,mergeCommit,statusCheckRollup,url + rtk gh api repos/MarcoPorcellato/commit-ci-preflight/git/ref/heads/ccp-evidence/f3fb14a0329cf031d08f474115a8b56fe1cffcf6 --jq .object.sha + ``` + + Stop Task 2 if any exact anchor differs; do not repair or reinterpret remote evidence. + +- [ ] **Step 2: Restructure the first visitor journey** + + Use this hierarchy without changing the established trust claim: + + 1. hero: `Run heavy CI locally. Prove the exact commit on GitHub.`; + 2. one short mechanism paragraph; + 3. three links: real receipt/case study, clean-room demo, repository-fit decision; + 4. current prerelease warning; + 5. problem and four-stage local-to-GitHub flow; + 6. compact `Is CCP for this repository?` yes/no table; + 7. short first inspection; + 8. dogfooding proof; + 9. differentiation, assumptions, boundaries, security, deeper docs. + + Preserve the existing official comparison links and the `not an identity attestation` statement. Keep `The problem`, `How it works`, `Quick start`, `What makes it different`, `When to use it`, `When not to use it`, and `Evidence and limitations` headings required by the current release contract. + +- [ ] **Step 3: Remove the quick-start interruption** + + Delete the duplicated plan/doctor/dry-run block. Move the long admission, resource, swap, history, and `guard exec` explanation out of the quick-start flow by replacing it with a concise operator-safety paragraph linking to `docs/COORDINATION_RUNBOOK.md`, `docs/LOCAL_RUN.md`, and `docs/RESOURCE_OBSERVATION_HISTORY.md`. Do not delete those source contracts. + +- [ ] **Step 4: Write the bounded PR #71 case study** + + Include: + + - problem: copied dry-run Docker argv is not a replay bundle; + - exact source/evidence/workflow/merge anchors; + - lifecycle: local qualification, append-only evidence, exact-head GitHub verification, merge; + - proof: receipt integrity/policy and exact-head gate; + - non-proofs: savings, producer identity, arbitrary hosted parity, other platforms; + - links to the PR, workflow, evidence ref, receipt spec, and verification policy. + + Exclude local paths, commands, raw logs, usernames beyond public GitHub ownership, environment values, or machine identity. + +- [ ] **Step 5: Write `SUPPORT.md`** + + Route: + + - reproducible defects to the bug form; + - adoption questions to the adoption-help form created in Task 3; + - completed trials to the adoption-report form; + - security vulnerabilities to `SECURITY.md` and private reporting instructions; + - design proposals to the feature form. + + State that public issues must not contain secrets, proprietary logs, receipts with private fields, or customer data. + +- [ ] **Step 6: Make the new documents part of the executable link gate** + + Add `SUPPORT.md` and `docs/CASE_STUDY_PR71.md` to `PUBLIC_DOCUMENTS`. Run: + + ```console + rtk cargo test --locked --test public_documentation_contract -- --nocapture + rtk cargo test --locked --test release_hardening_contract public_readme_is_human_first_and_truthfully_differentiated -- --exact + ``` + +- [ ] **Step 7: Update the Unreleased changelog** + + Add one concise `Added` entry covering the visitor journey, bounded PR #71 case study, and support routing. Do not claim GitHub metadata or social-preview upload is already live. + +- [ ] **Step 8: Commit Task 2** + + ```console + rtk git add README.md SUPPORT.md docs/CASE_STUDY_PR71.md tests/public_documentation_contract.rs CHANGELOG.md + rtk git commit -m "docs: sharpen the public CCP adoption path" + ``` + +### Task 3: Community intake and uploadable social preview + +**Files:** +- Create: `.github/ISSUE_TEMPLATE/adoption_help.yml` +- Modify: `SUPPORT.md` +- Modify: `tests/repository_hygiene_contract.rs` +- Create: `docs/assets/social-preview.png` +- Modify: `tests/public_documentation_contract.rs` +- Modify: `docs/REPOSITORY_PRESENTATION.md` +- Modify: `CHANGELOG.md` + +**Interfaces:** +- Consumes: Task 2 `SUPPORT.md` link to the adoption-help form. +- Produces: safe structured help intake, uploadable 1280x640 preview, and exact owner metadata proposal. + +- [ ] **Step 1: Write failing issue-form and PNG requirements** + + In `tests/repository_hygiene_contract.rs`, add: + + ```rust + const ADOPTION_HELP_FORM: &str = + include_str!("../.github/ISSUE_TEMPLATE/adoption_help.yml"); + ``` + + Require one YAML mapping with `name`, `description`, `title`, `labels`, and `body`, plus the same unsafe-claim rejection applied to other templates. Add the path to `roadmap_and_templates_reference_existing_local_docs`. + + In `tests/public_documentation_contract.rs`, add `include_bytes!` for `docs/assets/social-preview.png` and require `png_dimensions(...) == Ok((1280, 640))` and `bytes.len() < 1_048_576`. + +- [ ] **Step 2: Run RED** + + ```console + rtk cargo test --locked --test repository_hygiene_contract issue_template_yaml_is_present_and_safe -- --exact + rtk cargo test --locked --test public_documentation_contract social_preview_png_is_uploadable -- --exact + ``` + + Expected: compile failure because the new form and PNG do not exist. + +- [ ] **Step 3: Create the adoption-help form** + + Use label `question`, which already exists remotely. Require runtime/platform, repository language, attempted step, bounded error summary, expected outcome, and confirmation that no secrets/private logs are included. Explain that adoption help is not an evidence report. + + Update `SUPPORT.md` so the adoption route says the dedicated form is + available from the public issue chooser. Remove the temporary “being added” + language, but do not claim that GitHub has already rendered or activated the + form before the later live-page verification gate. + +- [ ] **Step 4: Render and inspect the preview** + + Render into an owned temporary directory: + + ```console + rtk qlmanage -t -s 1280 -o /private/tmp/ccp-social-preview-render docs/assets/social-preview.svg + rtk sips -z 640 1280 /private/tmp/ccp-social-preview-render/social-preview.svg.png --out docs/assets/social-preview.png + rtk sips -g pixelWidth -g pixelHeight docs/assets/social-preview.png + rtk ls -lh docs/assets/social-preview.png + ``` + + Inspect the committed PNG visually at original resolution. If Quick Look changes the layout or crops text, stop Task 3 and use a reviewed renderer rather than accepting a distorted asset. + +- [ ] **Step 5: Update repository presentation guidance** + + Record the proposed live values exactly: + + - Description: `Run heavy CI locally. Verify exact-commit receipts on GitHub.` + - Topics: `ci`, `continuous-integration`, `developer-tools`, `devtools`, `github-actions`, `local-ci`, `local-first`, `reproducible-builds`, `rust`, `supply-chain`. + + State that the PNG is an upload candidate only. Preserve the owner-only manual verification steps and the fact that committing metadata guidance changes no GitHub setting. + +- [ ] **Step 6: Run GREEN** + + ```console + rtk cargo test --locked --test repository_hygiene_contract + rtk cargo test --locked --test public_documentation_contract + ``` + +- [ ] **Step 7: Update the Unreleased changelog and commit Task 3** + + Add an `Added` entry for adoption-help intake and the uploadable preview candidate, explicitly not its remote activation. + + ```console + rtk git add .github/ISSUE_TEMPLATE/adoption_help.yml SUPPORT.md docs/assets/social-preview.png docs/REPOSITORY_PRESENTATION.md tests/repository_hygiene_contract.rs tests/public_documentation_contract.rs CHANGELOG.md + rtk git commit -m "docs: complete public intake and preview assets" + ``` + +### Task 4: M1 integration review and local qualification + +**Files:** +- Modify: `docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md` +- Modify: SDD ledger only in git-ignored workspace + +**Interfaces:** +- Consumes: Tasks 1-3 commits and review verdicts. +- Produces: M1 status/evidence update and the exact remote-action envelope for push/PR and later metadata upload. + +- [ ] **Step 1: Perform structured editorial acceptance** + + A reviewer must answer from the rendered README without relying on implementation docs: + + 1. What expensive duplication does CCP address? + 2. What runs locally and what remains on GitHub? + 3. What does a receipt prove and not prove? + 4. Is the repository a fit? + 5. What is the shortest safe next action? + 6. Which public exact-head example demonstrates the flow? + + Any answer requiring inference or deep-doc navigation is an Important finding. + +- [ ] **Step 2: Run focused M1 validation** + + ```console + rtk cargo test --locked --test public_documentation_contract + rtk cargo test --locked --test repository_hygiene_contract + rtk cargo test --locked --test release_hardening_contract + rtk cargo run --locked --quiet --example generate_release_metadata -- --check + rtk git diff --check 820a7fa6ce83a7ac8593c2800f8be4f44ab82ebc...HEAD + ``` + +- [ ] **Step 3: Run the broad branch review** + + Review the complete M1 diff for claim accuracy, broken links, accidental release-state changes, private evidence, duplicated onboarding, accessibility, issue-form safety, and asset legibility. One fix wave and one scoped re-review are allowed by SDD. + +- [ ] **Step 4: Update the canonical milestone status** + + Change only the M1 current-status/evolution-ledger fields that terminal local evidence proves. Do not mark GitHub metadata, social-preview activation, push, PR, CCP receipt, or merge complete. + +- [ ] **Step 5: Commit the local M1 closure** + + ```console + rtk git add docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md + rtk git commit -m "docs: record local M1 qualification" + ``` + +- [ ] **Step 6: Stop at the external gate** + + Prepare but do not execute: + + - non-forced branch push; + - PR creation; + - exact-head CCP qualification envelope; + - evidence publication and merge; + - GitHub description/topics update; + - social-preview upload and live-page verification; + - creation of missing remote labels such as `adoption`, `security`, `cost-model`, and `platform`. diff --git a/docs/superpowers/plans/2026-08-29-open-source-growth-program.md b/docs/superpowers/plans/2026-08-29-open-source-growth-program.md new file mode 100644 index 0000000..8bd4dce --- /dev/null +++ b/docs/superpowers/plans/2026-08-29-open-source-growth-program.md @@ -0,0 +1,403 @@ +# Commit CI Preflight Open-Source Growth Programme Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Deliver the dependency-ordered product, distribution, adoption, qualification, and public-proof milestones required for a truthful Commit CI Preflight stable release. + +**Architecture:** `docs/PRODUCT_ROADMAP.md` remains the public product authority; the programme specification defines evidence and governance, while this master plan sequences independently reviewable vertical tranches. Each future tranche starts by refreshing its own exact TDD implementation plan against the then-current `main`, preventing stale source signatures from becoming false instructions. + +**Tech Stack:** Rust 1.96.0 (MSRV 1.87), Cargo workspace, shell-free CLI execution, Git/GitHub, Docker-compatible runtimes, GitHub Actions, TOML/JSON/YAML contracts, Markdown documentation, SPDX SBOM, exact-head CCP receipts. + +**Spec:** `docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md` + +## Global Constraints + +- All shell commands begin with `rtk`. +- Preserve the divergent primary checkout; work only in isolated worktrees from a verified `origin/main`. +- TDD is mandatory for behavior and contract changes. +- Every user-visible change updates `CHANGELOG.md`. +- No zero-CI, guaranteed-savings, hosted-parity, A0-identity, or unexecuted-platform claim. +- Never silently replace the installed global CCP producer. +- Keep availability, smoke verification, E2E qualification, A0, and A1 distinct. +- Commit, push, PR, CCP, evidence, ready, merge, release, signing, settings, and case-study publication remain separate gates. +- Deterministic tests precede Docker, native runners, network, and CCP qualification. +- Public evidence excludes raw logs, identities, local paths, secrets, environment values, and customer data. + +## Programme File Structure + +- `docs/PRODUCT_ROADMAP.md` — public product direction and tranche outcomes. +- `docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md` — canonical execution and evidence contract. +- `docs/superpowers/plans/2026-08-29-open-source-growth-program.md` — dependency order and master checklist. +- `docs/superpowers/plans/YYYY-MM-DD-.md` — exact live-source TDD plan created immediately before each milestone. +- `docs/superpowers/goals/2026-08-29-open-source-growth-program.txt` — concise persistent execution pointer. +- `docs/handoffs/OPEN_SOURCE_GROWTH_.md` — restart checkpoint when needed. + +--- + +### Task 0: Commit durable programme control + +**Files:** +- Create: `docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md` +- Create: `docs/superpowers/plans/2026-08-29-open-source-growth-program.md` +- Create: `docs/superpowers/goals/2026-08-29-open-source-growth-program.txt` + +**Interfaces:** +- Consumes: `docs/PRODUCT_ROADMAP.md`, global CCP operator contract, live `origin/main`. +- Produces: one canonical spec path and one persistent goal used by every later task. + +- [ ] **Step 1: Verify programme anchors** + + Run: + + ```console + rtk git status --short --branch + rtk git rev-parse HEAD + rtk git merge-base HEAD origin/main + rtk gh api repos/MarcoPorcellato/commit-ci-preflight/git/ref/heads/main --jq .object.sha + ``` + + Expected: clean isolated branch, exact base recorded in the specification, no primary-checkout mutation. + +- [ ] **Step 2: Self-review the specification and plan** + + Run: + + ```console + rtk rg -n '^### M[0-9]+|^### Task [0-9]+' docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md docs/superpowers/plans/2026-08-29-open-source-growth-program.md + ``` + + Expected: milestone/task inventory is complete and ordered. Read both files + end-to-end and reject unresolved markers, vague implementation instructions, + contradictory interfaces, or a specification requirement without a task. + +- [ ] **Step 3: Commit the control artifacts** + + ```console + rtk git add docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md docs/superpowers/plans/2026-08-29-open-source-growth-program.md docs/superpowers/goals/2026-08-29-open-source-growth-program.txt + rtk git commit -m "docs: define open-source growth programme" + ``` + +### Task 1: M1 conversion surface and dogfooding proof + +**Files:** +- Modify: `README.md` +- Modify: `docs/REPOSITORY_PRESENTATION.md` +- Modify: `docs/PRODUCT_ROADMAP.md` +- Modify: `docs/TUTORIAL.md` +- Modify: `CHANGELOG.md` +- Create: `docs/CASE_STUDY_PR71.md` +- Create: `SUPPORT.md` +- Render from: `docs/assets/social-preview.svg` +- Create: `docs/assets/social-preview.png` +- Modify: `.github/ISSUE_TEMPLATE/*.yml` only where live audit finds a concrete funnel gap +- Test: `tests/repository_hygiene_contract.rs` +- Test: `tests/release_hardening_contract.rs` + +**Interfaces:** +- Consumes: public PR #71 receipt/gate evidence; current support and release matrices. +- Produces: exact README hero `Run heavy CI locally. Prove the exact commit on GitHub.`, three CTA paths, fit/no-fit decision table, FAQ, dogfooding proof, and metadata change envelope. + +- [ ] **Step 1: Create the exact M1 TDD plan** + + Read the live files and write `docs/superpowers/plans/YYYY-MM-DD-m1-conversion-surface.md` with exact line anchors, copy, local-link tests, render command, and commit boundaries. Do not change the README in this step. + +- [ ] **Step 2: Add failing executable documentation contracts** + + Add a local Markdown-link checker that resolves repository-relative targets + from each public document and rejects missing files or invalid fragments + without requiring network. Add an asset check that parses the rendered social + preview and requires 1280x640 dimensions and a file smaller than 1 MiB. + Exercise both helpers against controlled broken fixtures before applying them + to the repository files. Human-facing wording is reviewed against the M1 copy + checklist; it is not frozen with exact-string change-detector tests. + +- [ ] **Step 3: Verify the new tests fail for the intended missing anchors** + + ```console + rtk cargo test --locked --test repository_hygiene_contract -- --nocapture + ``` + + Expected: FAIL because the controlled missing link and invalid preview fixture + are detected, not because an exact prose sentence changed. + +- [ ] **Step 4: Implement the benefit-led README path** + + Keep trust boundaries, comparison, cost assumptions, ideal/non-ideal users, security, and documentation links. Remove the duplicated inspection block. Move the admission/resource/`guard exec` deep dive out of the quick-start flow and replace it with one link to `docs/COORDINATION_RUNBOOK.md` and one short safety sentence. + +- [ ] **Step 5: Publish a bounded dogfooding case study** + + `docs/CASE_STUDY_PR71.md` must record exact PR head, evidence commit, receipt hash/ID, workflow run, merge commit, what was proven, what was not proven, and no raw/local details. It must not claim savings because no before/after billing evidence exists. + +- [ ] **Step 6: Complete community and preview surfaces** + + Add `SUPPORT.md`; review existing bug/feature/adoption forms rather than duplicating them; export the 1280x640 preview to a deterministic PNG under 1 MiB; visually inspect it; record proposed description/topics in `REPOSITORY_PRESENTATION.md`. + +- [ ] **Step 7: Run focused validation** + + ```console + rtk cargo test --locked --test repository_hygiene_contract + rtk cargo test --locked --test release_hardening_contract + rtk cargo run --locked --quiet --example generate_release_metadata -- --check + ``` + +- [ ] **Step 8: Commit independently reviewable M1 units** + + Use separate commits for contract tests, README/case study, community surface, and preview/metadata. Stop before remote settings, push, PR, or merge unless authorized. + +### Task 2: M2 independent verifier boundary + +**Files:** +- Create: `docs/superpowers/specs/YYYY-MM-DD-independent-verifier-design.md` +- Create: `docs/superpowers/plans/YYYY-MM-DD-independent-verifier.md` +- Modify: `Cargo.toml` +- Create: `crates/ccp-core/` +- Create: `crates/ccp-verifier/` +- Modify: existing root crate compatibility re-exports +- Test: receipt, verification, schema, CLI, release-hardening and dependency-boundary contracts + +**Interfaces:** +- Consumes: canonical receipt/policy/schema behavior and byte fixtures. +- Produces: `ccp_core` types/canonicalization plus a verifier binary exposing bounded verify/schema surfaces without runner dependencies. + +- [ ] **Step 1: Freeze the compatibility envelope** + + Record exact fixture hashes and add a dependency-boundary test that fails while verifier code remains coupled to Docker/process/cache/admission/resource modules. + +- [ ] **Step 2: Approve the milestone design and exact live-source plan** + + The design must specify crate graph, compatibility re-exports, error stability, binary naming, feature policy, and migration order. The plan must use red/green moves small enough for one reviewer gate. + +- [ ] **Step 3: Execute behavior-preserving extraction** + + Move canonical JSON, schemas, receipt, policy, and verification into the inner crates without mixing feature changes. Keep root public behavior stable through explicit re-exports. + +- [ ] **Step 4: Prove physical independence** + + ```console + rtk cargo tree -p ccp-verifier + rtk cargo test --locked --workspace --all-targets --all-features + rtk cargo clippy --locked --workspace --all-targets --all-features -- -D warnings + rtk cargo doc --locked --workspace --no-deps + ``` + + Expected: no verifier dependency on runtime, process, workspace, cache, admission, resource, benchmark, or Docker orchestration. + +- [ ] **Step 5: Qualify exact head and stop at publication gates** + + Obtain a fresh CCP authorization only after deterministic review. Preserve fixture hashes and rollback path. + +### Task 3: M3 multi-platform immutable distribution + +**Files:** +- Create: `docs/adr/YYYY-MM-DD-distribution-and-provenance.md` +- Create: `docs/superpowers/plans/YYYY-MM-DD-multi-platform-distribution.md` +- Modify: `Cargo.toml`, release metadata, `docs/INSTALLATION.md`, `docs/BETA_SUPPORT.md`, `CHANGELOG.md` +- Modify/Create: release workflow under `.github/workflows/` +- Create: shell and PowerShell installer tests and scripts +- Create: package metadata for cargo-binstall, Homebrew/tap handoff, and crates.io dry validation +- Test: `tests/release_hardening_contract.rs` and new packaging/install contracts + +**Interfaces:** +- Consumes: M2 isolated verifier, exact tag, locked dependency graph. +- Produces: artifact manifest keyed by target with checksum, SBOM, provenance, availability, smoke, and qualification fields. + +- [ ] **Step 1: Research and approve one maintained distribution tool** + + Compare current official cargo-dist/release alternatives, pin exact versions and actions by immutable digest/SHA, define rollback, and document why no moving `latest` is trusted. + +- [ ] **Step 2: Write failing packaging contracts** + + Require exact target names, archive contents, license/notice/SBOM, checksum manifest, installer checksum enforcement, non-overwrite, isolated prefix, uninstall, and offline failure behavior. + +- [ ] **Step 3: Implement artifact matrix and installers without publishing** + + Generate local/hosted candidate artifacts, never tags or registry uploads. Separate runner and verifier packages when trust or size requires it. + +- [ ] **Step 4: Native smoke each claimed target** + + Record exact artifact SHA-256, host OS/architecture, installation prefix, `--version`, bounded verifier fixture, uninstall, and rollback. Label unexecuted targets `AVAILABLE` only. + +- [ ] **Step 5: Run release qualification and request publication separately** + + No GitHub Release, crate, tap, Winget/Scoop, signature, or attestation publication occurs until its exact artifact set is authorized. + +### Task 4: M4 slim trusted GitHub gate + +**Files:** +- Create: `docs/superpowers/plans/YYYY-MM-DD-slim-trusted-gate.md` +- Modify: `.github/workflows/receipt-gate.yml` +- Modify: `examples/github/receipt-gate.yml.example` +- Modify: `scripts/github-receipt-gate.sh` +- Modify: `docs/GITHUB_GATE.md`, `docs/THREAT_MODEL.md`, `CHANGELOG.md` +- Test: `tests/github_gate_contract.rs`, `tests/release_hardening_contract.rs` + +**Interfaces:** +- Consumes: immutable M3 verifier artifact plus checksum/provenance and rollback artifact. +- Produces: gate inputs `{repository, expected_head, evidence_ref, verifier_digest, policy}` and a bounded exact-head status. + +- [ ] **Step 1: Add failing no-build/no-registry gate tests** + + Reject `cargo build`, `cargo run`, Docker, package-registry access, mutable artifact URLs, missing digest verification, and execution of PR code. + +- [ ] **Step 2: Implement immutable verifier acquisition** + + Download or restore only the reviewed exact version, verify digest/provenance before execution, and preserve one rollback version. + +- [ ] **Step 3: Exercise the complete negative fixture matrix** + + Missing, oversized, stale, malformed, digest-invalid, untrusted, wrong repository, + wrong head, wrong policy, and wrong configuration must fail closed. + +- [ ] **Step 4: Validate hosted behavior on an authorized exact-head PR** + + Record runner allocation separately from verifier wall time and do not infer cost savings from one run. + +### Task 5: M5 first-value and adoption commands + +**Files:** +- Create: `docs/superpowers/specs/YYYY-MM-DD-first-value-adoption-design.md` +- Create: `docs/superpowers/plans/YYYY-MM-DD-first-value-adoption.md` +- Create: `src/check.rs`, `src/init.rs`, `src/adopt.rs`, `src/setup_github.rs` +- Modify: `src/main.rs`, `src/lib.rs`, config and run orchestration only through reviewed interfaces +- Create: focused CLI/contract tests and Rust/Python/Node fixtures +- Modify: README, tutorial, adoption guide, configuration, compatibility docs, changelog + +**Interfaces:** +- `check`: consumes a reviewed plan plus dirty working source; produces local result only, never receipt/evidence/A0. +- `init`: consumes repository inventory; produces deterministic proposed config/policy diff, never silent image-tag resolution. +- `adopt`: consumes `GithubActionsCompatibilityReportV1`; preserves `ready`, `manual_review`, and `blocked` dispositions. +- `setup-github`: consumes reviewed config/policy and immutable verifier coordinates; produces deterministic workflow/policy guidance without overwrite. + +- [ ] **Step 1: Specify non-attestante and mutation boundaries** + + Freeze how `check` differs from `run`, how proposals are represented, confirmation semantics, JSON versions, and idempotence. + +- [ ] **Step 2: Implement `check` TDD** + + Prove dirty-tree acceptance, result propagation, no receipt, no evidence ref, no publication, and no A0 language. + +- [ ] **Step 3: Implement project `init` TDD** + + Detect `Cargo.lock`, Python lockfiles, and Node lockfiles deterministically; emit a diff-first proposal; refuse overwrite; require explicit image digest input or a separately confirmed resolution step. + +- [ ] **Step 4: Compose Actions adoption without guessing** + + Reuse the existing parser/report. Unsupported expressions/actions/services remain manual or blocked. Generated proposals are inert until reviewed. + +- [ ] **Step 5: Implement deterministic GitHub setup generation** + + Require immutable verifier coordinates, exact policy inputs, no secret values, idempotent output, and explicit overwrite confirmation. + +- [ ] **Step 6: Prove the three-language activation path** + + Rust, Python, and Node public clean-room fixtures must reach the documented first result from one page. Docker/network-dependent E2E remains a separately authorized validation. + +### Task 6: M6 transactional evidence publication + +**Files:** +- Create: milestone design and exact TDD plan +- Create: `src/publish.rs`, `src/hooks.rs` +- Modify: `src/main.rs`, `src/lib.rs`, receipt/verify composition only through stable interfaces +- Create: local bare-remote and hook fixtures/tests +- Modify: GitHub gate, adoption, rollback, troubleshooting, changelog + +**Interfaces:** +- `publish(receipt, policy, repository, expected_head, remote) -> PublicationOutcome` +- Exact evidence ref: `refs/heads/ccp-evidence/<64-hex-source-sha>` +- Existing identical ref is idempotent; conflicting content is fail-closed; force push is never used. + +- [ ] **Step 1: Approve transaction and recovery design** + + Define remote identity checks, isolated ref construction, interruption journal, retry, cleanup ownership, and unique-work preservation. + +- [ ] **Step 2: Implement local bare-repository TDD matrix** + + Cover new ref, identical retry, conflicting ref, stale receipt, dirty/wrong head, non-fast-forward, network error, cancellation, and interrupted cleanup. + +- [ ] **Step 3: Add reversible pre-push integration** + + Never overwrite an existing hook; use a documented chain or stop. Uninstall restores only CCP-owned bytes. Source push cannot be reported protected if publication failed. + +- [ ] **Step 4: Perform one authorized live pilot** + + Bind exact repo/head/binary/config/generation/output and stop before merge unless separately authorized. + +### Task 7: M7 explicit cost intelligence + +**Files:** +- Create: milestone design and exact plan +- Create: `src/cost.rs` plus versioned input/output schema +- Modify: `src/main.rs`, `src/lib.rs`, docs and changelog +- Create: golden CSV/JSON fixtures and CLI tests + +**Interfaces:** +- Inputs distinguish GitHub usage rows, dated SKU rates, included quota, retained jobs, gate cost, local electricity/hardware rate, and measured duration. +- Outputs label every field `measured`, `supplied`, or `inferred` and never access billing automatically. + +- [ ] **Step 1: Freeze schema and privacy limits** +- [ ] **Step 2: TDD zero-savings, under-quota, mixed-platform, rounding, malformed, and large-file cases** +- [ ] **Step 3: Implement bounded local-only analyze/estimate/compare commands** +- [ ] **Step 4: Validate current pricing references against official GitHub documentation** +- [ ] **Step 5: Publish examples only with assumptions visibly attached** + +### Task 8: M8 native Linux x86_64 qualification + +**Files:** +- Create: native qualification plan, immutable manifest, receipts and public bounded report +- Modify: `docs/BETA_SUPPORT.md`, benchmark/parity, installation and changelog only after evidence +- Extend: native workflow/fixtures only where they reflect genuine host execution + +**Interfaces:** +- Consumes exact M3-M6 artifacts and policies. +- Produces native Linux evidence classes for PASS, FAIL, timeout, cancellation, cleanup, cache, verify, publish, and gate. + +- [ ] **Step 1: Freeze exact native host/runtime/image/source envelope** +- [ ] **Step 2: Run deterministic synthetic and failure-path checks first** +- [ ] **Step 3: Obtain one-attempt exact authorization for each heavy qualification family** +- [ ] **Step 4: Preserve terminal receipts and independent verification** +- [ ] **Step 5: Promote support wording only after every required class passes** + +### Task 9: M9 optional A1 signer identity + +**Files:** +- Create: signing/key-custody ADR, threat-model update, milestone design/plan +- Modify: core/verifier policy schemas through a backwards-compatible envelope +- Create: cryptographic fixture tests and documentation + +**Interfaces:** +- Detached signed envelope references canonical receipt digest and signer-policy fields. +- Unsigned A0 remains valid where policy permits; A1 never implies A2/A3. + +- [ ] **Step 1: Evaluate DSSE/in-toto/Sigstore interoperability from official specifications** +- [ ] **Step 2: Approve credential and revocation model before creating any key** +- [ ] **Step 3: TDD valid, tampered, unknown, expired, revoked, offline, and unsigned-policy paths** +- [ ] **Step 4: Qualify compatibility and negative claims** +- [ ] **Step 5: Publish identity material only with separate exact authorization** + +### Task 10: M10 external case studies and stable release + +**Files:** +- Create: case-study protocol/template, three consented reports, launch article, stable checklist +- Modify: README, support matrix, installation, upgrade/rollback, roadmap, changelog +- Create/Modify: exact release workflow and artifact manifest from qualified M3 machinery + +**Interfaces:** +- Each case study binds repository/source interval, consent, retained remote jobs, + local runtime, gate runtime, list/billed assumptions, and exact receipts. +- Stable release consumes only previously qualified exact artifacts or performs a fresh exact rebuild with equivalent evidence. + +- [ ] **Step 1: Obtain explicit consent and freeze the case-study methodology** +- [ ] **Step 2: Run small, medium/monorepo, and agent-driven studies without fabricated controls** +- [ ] **Step 3: Independently review claims, anonymization, and reproducibility** +- [ ] **Step 4: Execute the stable-release checklist on exact head** +- [ ] **Step 5: Request separate tag, release, package, signature, and announcement authorization** +- [ ] **Step 6: Verify public assets, install/rollback paths, checksums, attestations, support matrix, and links after publication** + +## Final programme audit + +- [ ] Re-read every specification completion item and map it to terminal current evidence. +- [ ] Verify no skipped, running, partial, wrong-head, wrong-platform, or stale artifact is represented as PASS. +- [ ] Reconcile live GitHub description, topics, social preview, issues, discussions, releases, packages, PRs, evidence refs, and `main`. +- [ ] Verify the installed global producer separately from merged source. +- [ ] Write a final durable handoff with exact anchors and residual boundaries. +- [ ] Mark the persistent goal complete only when every applicable checklist item is proved. diff --git a/docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md b/docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md new file mode 100644 index 0000000..c5475dd --- /dev/null +++ b/docs/superpowers/specs/2026-08-29-open-source-growth-program-design.md @@ -0,0 +1,511 @@ +--- +type: execution-specification +title: "Commit CI Preflight open-source growth and stable-release programme" +description: "Turn CCP's evidence-first technical core into an understandable, installable, independently verifiable, and responsibly promotable open-source product." +status: approved-for-staged-delivery +last_verified: 2026-08-29 +--- + +# Commit CI Preflight open-source growth and stable-release programme + +This file is the canonical execution contract for the programme. The public +product direction remains authoritative in [`PRODUCT_ROADMAP.md`](../../PRODUCT_ROADMAP.md); +this specification defines how that direction is delivered, evidenced, and +resumed across multiple pull requests. Conversation history, issues, and local +notes are supporting context, not competing plans. + +## Outcome + +Commit CI Preflight becomes a public open-source product for maintainers who +repeat deterministic heavy CI work on paid hosted runners. A new maintainer can: + +1. understand the problem and the local/remote trust split in 30 seconds; +2. decide whether CCP fits their repository without reading implementation docs; +3. install a checksum- and provenance-verifiable artifact for a supported host; +4. reach a first non-attestante development check with a short, deterministic path; +5. produce and independently verify an exact-commit A0 receipt in a clean-room path; +6. connect the slim GitHub exact-head gate without compiling the runner in the gate; +7. publish evidence through a transactional, append-only workflow; +8. evaluate cost and latency using explicit measured or supplied inputs; +9. distinguish availability, smoke verification, end-to-end qualification, and identity assurance; +10. inspect reproducible external case studies before a truthful stable release. + +The programme is complete only when the final checklist is proven against live +GitHub state, native receipts, released artifacts, and user-visible instructions. + +## Authoritative anchors + +| Item | Verified state | Evidence | +|---|---|---| +| Repository | `MarcoPorcellato/commit-ci-preflight` | live GitHub repository | +| Programme base | `820a7fa6ce83a7ac8593c2800f8be4f44ab82ebc` | `origin/main`, post-PR #71 | +| Delivery branch | `codex/open-source-growth-program-v1` | isolated worktree | +| Isolated worktree | `/Users/marco1/Documents/CODICE con VS CODE/ccp-worktrees/open-source-growth-program-v1` | clean at programme creation | +| Product authority | `docs/PRODUCT_ROADMAP.md` | staged PR 1-10 roadmap | +| Current public release | `v0.1.0-rc.1` | unsigned macOS arm64 archive plus checksum | +| Current release drift | public tag is 39 commits behind `main` at programme creation | GitHub compare API | +| Active global producer | source `faf587890e4f899803f027660bc66452623f405e`, binary SHA-256 `7cde4c2888721d72fbb8c86b4fdcc75f992050979c5175a5bf10b0cecfa7c6f8` | live global CCP operator contract, reverified 2026-08-29 | +| Current programme milestone | M1 product slice locally qualified through `94b424da6f3c36bc99da1ede98b87ea903eecf92`; external publication pending | full locked workspace tests, all-target/all-feature Clippy with warnings denied, docs, release metadata, structured editorial acceptance, and broad branch review on 2026-08-29 | + +Every drift-prone anchor must be reverified before a commit, push, CCP +qualification, evidence publication, repository-setting mutation, release, or +merge. A merged source change does not update the active global producer. + +## Status vocabulary + +- **Verified:** terminal authoritative evidence exists for the exact artifact or commit. +- **In delivery:** recoverable saved work exists but qualification is incomplete. +- **Blocked:** a named human, platform, secret, consent, or external dependency prevents this path. +- **Planned:** dependency-ordered work with an explicit exit gate. +- **Deferred:** intentionally excluded until a predecessor justifies it. +- **Available:** an artifact exists for a target; no smoke or end-to-end claim is implied. +- **Smoke verified:** installation and bounded CLI probes passed on the named target. +- **End-to-end qualified:** genuine native runner-to-receipt-to-verifier evidence passed on the named target. +- **A0:** receipt integrity and repository-policy assurance only. +- **A1:** policy-accepted signer identity; no execution-truth claim. + +## Scope + +### Public conversion surface + +- Benefit-led README hero, clear calls to action, fit/no-fit decision path, FAQ, + dogfooding proof, and a short path to first visible value. +- Accurate GitHub description, topics, social preview, support and contributor pathways. +- Public claims bound to exact receipts, artifacts, platforms, dates, and assumptions. + +### Product activation + +- Physically independent verifier and slim trusted GitHub gate. +- Multi-platform artifact generation with checksums, SBOM, provenance, installers, + package-manager metadata, smoke verification, and explicit publication gates. +- Non-attestante dirty-tree `check`, deterministic project `init`, bounded Actions + adoption proposal, GitHub setup generation, and clean-room demonstrations. +- Transactional evidence publication and reversible pre-push integration. +- Explicit cost analysis and comparison from user-supplied or measured inputs. + +### Qualification and responsible promotion + +- Native Linux x86_64 complete `run` qualification independent of fixed benchmark evidence. +- Optional A1 signed identity envelope that remains distinct from execution attestation. +- Three consented, reproducible case studies and a stable-release launch package. + +## Non-goals + +- Claiming zero remote CI, guaranteed savings, GitHub-hosted parity, producer + identity at A0, or truthful execution against a malicious insider. +- Executing arbitrary marketplace Actions or silently translating unsupported workflow features. +- Treating availability, compilation, benchmark evidence, or containerized Linux + execution on macOS as native Linux end-to-end qualification. +- Publishing a crate, package, signature, key, release, case study, billing data, + or customer information without its separate authority and evidence gate. +- Replacing the installed global CCP producer merely because newer source is merged. +- Manipulating admission, journal, receipt, lease, cache, lock, or resource state to make progress. + +## Invariants and approval boundaries + +1. All shell commands begin with `rtk`. +2. Dirty or divergent user checkouts remain untouched; delivery uses isolated worktrees. +3. TDD applies to behavior and contract changes: failing test, minimal implementation, + focused PASS, then proportional broad validation. +4. Every user-visible change updates `CHANGELOG.md`. +5. Deterministic checks run before Docker, network, native qualification, or CCP. +6. `check` can never create an A0 receipt or publish evidence. +7. Unsupported Actions remain `manual_review` or `blocked`, never guessed into executable configuration. +8. Generated files are deterministic, diff-first, idempotent, and never overwrite without explicit confirmation. +9. Evidence refs are exact-SHA-derived and append-only; no force push belongs to the standard path. +10. A checksum or SBOM proves no publisher identity. A signature identifies a declarant but proves no execution truth. +11. Commit, push, PR creation, ready transition, CCP run, evidence publication, + merge, repository-setting mutation, package upload, release, signing, and + case-study publication are distinct gates. +12. Heavy CCP authorizations remain exact-worktree, exact-head, binary-hash, + configuration-digest, generation, maximum-count, and stop-boundary bound. +13. Public metrics must be measured, supplied, or explicitly inferred; fabricated + adoption, savings, timing, billing, or platform evidence is prohibited. +14. Raw logs, usernames, local paths, environment values, container IDs, secrets, + proprietary data, and personal identity fields do not enter public evidence. + +## Evidence and claim envelope + +| Evidence | Proves | Does not prove | +|---|---|---| +| Deterministic unit/contract tests | exact tested behavior on the named source/toolchain | native runtime, publication, or another commit | +| Hosted GitHub check | exact hosted job result and artifact for its SHA | unexecuted platforms or local producer identity | +| CCP receipt + independent verify | exact receipt integrity and configured policy match | who ran it or malicious-host truthfulness | +| Native installation smoke | named artifact installs and bounded probes pass on the named host | full project `run` qualification | +| Native end-to-end receipt | named platform completed runner/receipt/verifier path | every platform or every repository | +| Signed A1 envelope | accepted signer declared the receipt | attested execution or honest insider behavior | +| Case study | stated repository and measured interval under published assumptions | universal savings or performance | + +Negative and null results remain first-class evidence. A failed or inconclusive +attempt is retained with its scope; a later PASS does not reinterpret it. + +## Programme architecture + +The programme follows the public roadmap but orders delivery by trust dependency: + +1. conversion and truthful proof surface; +2. independent verifier boundary; +3. immutable multi-platform verifier distribution; +4. slim trusted GitHub gate; +5. first-value and adoption commands; +6. transactional evidence publication; +7. cost intelligence; +8. native Linux end-to-end qualification; +9. optional A1 signed identity; +10. consented case studies and stable release. + +Each milestone receives its own bounded implementation plan and branch. The +master plan defines dependencies and exit gates; a tranche plan fixes exact +files, interfaces, tests, and commits against the live base immediately before +implementation. This avoids inventing stale code signatures months in advance. + +## Evolution ledger + +| Milestone | Delivered result | Evidence | Residual boundary | +|---|---|---|---| +| Reliability foundation | managed-cache pins and terminal resource release merged | PR #68 and PR #69 | installed global producer remains older | +| Dry-run boundary | planning/replay distinction documented and contract-tested | PR #71, head `f3fb14a...`, receipt gate SUCCESS, merge `820a7fa...` | documentation does not add runtime behavior | +| Marketing audit | live GitHub, README, release, community, traffic, and competitor surfaces reviewed | 2026-08-29 read-only audit | no repository or setting mutation | +| M1 conversion surface | benefit-led README, bounded PR #71 case study, support intake, metadata proposal, uploadable preview candidate, and concise agent-safety copy are locally qualified through `94b424da6f3c36bc99da1ede98b87ea903eecf92` | full locked workspace tests PASS, all-target/all-feature Clippy with warnings denied PASS, docs PASS, release metadata current, preview SHA-256 `3b4aa8fe0cd8f0122065990133d64f03cf86089dab383b4bd90ec11d4e49ff4a`, editorial PASS, broad review ready | not pushed, PR-opened, CCP-qualified, evidence-published, merged, or activated as live GitHub metadata/preview; issue-form rendering remains unverified | + +## Ordered milestones + +### M0 — Durable programme control + +**Outcome** + +- Canonical specification, master plan, persistent goal, isolated branch, and restart procedure exist. + +**Dependencies** + +- `origin/main` exact anchor verified and divergent primary checkout preserved. + +**Exit evidence** + +- Markdown self-review passes; files committed on the isolated branch; clean status recorded. + +**Impact** + +- Long work can resume after compaction or restart without redefining scope. + +**Residual risk** + +- No product or public GitHub behavior changes. + +### M1 — Conversion surface and dogfooding proof + +**Outcome** + +- A maintainer understands pain, mechanism, proof, fit, limits, and next action from the README. +- PR #71 becomes a compact public dogfooding case study. +- Advanced admission/resource detail no longer interrupts the new-user path. +- Social-preview render, metadata proposal, support surface, and community labels/forms are accurate. + +**Dependencies** + +- M0 complete; current issue forms and repository metadata re-audited live. + +**Exit evidence** + +- Focused repository-hygiene, release-contract, metadata, and link tests pass. +- Rendered preview is 1280x640, under GitHub's size limit, visually inspected. +- No claim exceeds the public receipt/release evidence. + +**Impact** + +- Improves comprehension and conversion without runtime changes. + +**Residual risk** + +- GitHub settings and organic adoption remain unproven until separately changed and observed. + +### M2 — Physically independent verifier + +**Outcome** + +- Receipt/policy/schema/canonicalization logic lives in a bounded core plus verifier binary that has no runner, Docker, cache, admission, process, or resource dependency. + +**Dependencies** + +- M1 merged; exact receipt fixtures and compatibility contract frozen. + +**Exit evidence** + +- Golden receipt/policy bytes remain compatible; dependency graph proves verifier isolation; + full deterministic suite and exact-head qualification pass. + +**Impact** + +- Creates a smaller trust root suitable for immutable distribution and GitHub verification. + +**Residual risk** + +- Artifact availability and identity are not yet established. + +### M3 — Multi-platform immutable distribution + +**Outcome** + +- Exact-tag artifacts, installers, checksums, SBOM, provenance/attestation workflow, + package-manager metadata, and an availability/smoke/qualification matrix exist for prioritized targets. + +**Dependencies** + +- M2 verifier boundary; approved distribution ADR; native builders for each claimed target. + +**Exit evidence** + +- Reproducible packaging tests, native install/uninstall smoke receipts, checksum/SBOM parity, + rollback rehearsal, and exact artifact digest ledger. + +**Impact** + +- Removes source compilation as the default evaluation barrier. + +**Residual risk** + +- Package or release publication remains a separate owner action; smoke is not E2E. + +### M4 — Slim trusted GitHub gate + +**Outcome** + +- The receipt gate downloads or restores one immutable, trusted verifier artifact and does not compile Rust, run Docker, access a package registry, or execute PR code. + +**Dependencies** + +- M3 immutable verifier artifact with rollback anchor. + +**Exit evidence** + +- PASS, stale, mismatched, oversized, malformed, missing, and untrusted fixtures fail or pass exactly as policy specifies; hosted wall time and network surfaces are recorded. + +**Impact** + +- Makes the remote control plane small, explainable, and cheap. + +**Residual risk** + +- Gate success remains A0 unless a later policy requires A1. + +### M5 — First-value and adoption commands + +**Outcome** + +- `check`, project `init`, Actions `adopt`, `setup-github`, and Rust/Python/Node clean-room demonstrations provide short, deterministic activation paths. + +**Dependencies** + +- M3 installable artifacts; M4 stable gate contract; current config/migration behavior preserved. + +**Exit evidence** + +- Dirty-tree check produces no receipt; init/adopt/setup are idempotent and diff-first; + unsupported workflow features remain blocked; three public fixtures reach their documented terminal state. + +**Impact** + +- Reduces time to first visible value without weakening evidence boundaries. + +**Residual risk** + +- Manual evidence publication remains until M6. + +### M6 — Transactional evidence publication and pre-push + +**Outcome** + +- `publish`, `run --publish`, and reversible pre-push integration manage exact-SHA evidence refs without force, data loss, or hidden mutation. + +**Dependencies** + +- M5 activation surfaces and current verifier/gate contracts. + +**Exit evidence** + +- Local bare-remote concurrency, retry, stale receipt, network failure, conflicting ref, + interrupted transaction, hook coexistence, uninstall, and rollback tests pass; + one authorized live pilot succeeds exact-head. + +**Impact** + +- Removes manual worktree/ref choreography from the standard adoption path. + +**Residual risk** + +- Remote credentials and repository rules remain operator-controlled. + +### M7 — Cost intelligence + +**Outcome** + +- Local-only CSV analysis and explicit estimates compare retained remote work, + runner rates, rounding, included quota, gate cost, local cost, and break-even. + +**Dependencies** + +- Stable workflow vocabulary from M5/M6; dated official pricing source. + +**Exit evidence** + +- Golden fixtures cover zero-savings, under-quota, mixed-platform, malformed, + rounding, and large inputs; outputs label measured, supplied, and inferred values. + +**Impact** + +- Lets users evaluate value without universal or fabricated savings claims. + +**Residual risk** + +- Estimates are not billing statements and pricing can drift. + +### M8 — Native Linux x86_64 end-to-end qualification + +**Outcome** + +- Ubuntu LTS plus Docker Engine completes genuine Rust/Python/Node runner, + receipt, verifier, publication, and slim-gate paths including failure modes. + +**Dependencies** + +- M3-M6 complete; authorized native Linux host and exact images available. + +**Exit evidence** + +- Native PASS/FAIL/timeout/cancellation/cleanup/cache/receipt/publication receipts + retained with exact commits, binaries, image digests, host class, and policies. + +**Impact** + +- Promotes Linux from pending only on genuine native evidence. + +**Residual risk** + +- Windows complete run and other architectures remain separately scoped. + +### M9 — Optional A1 signed identity + +**Outcome** + +- A standards-aligned detached signing envelope, signer policy, expiry/revocation, + timestamp semantics, and offline failure modes extend A0 without breaking it. + +**Dependencies** + +- M2 stable core/verifier; approved signing and key-custody ADR; separate credential authority. + +**Exit evidence** + +- Valid, unknown, expired, revoked, tampered, offline, and unsigned-policy fixtures; + no credential or public key is created or published without authorization. + +**Impact** + +- Allows repositories to require an accepted declarant identity. + +**Residual risk** + +- A1 still does not prove truthful execution or a managed/attested device. + +### M10 — External proof and truthful stable release + +**Outcome** + +- Three consented public or anonymized case studies, launch materials, complete + support matrix, migration/rollback guidance, and `v0.1.0` stable release exist. + +**Dependencies** + +- M1-M9 applicable exit gates; real repositories and explicit publication consent. + +**Exit evidence** + +- Reproducible case-study inputs and receipts; artifact matrix matches qualification; + release checklist, fresh exact-head CCP qualification, hosted gates, install/rollback + smokes, tag, release assets, checksums, attestations, and post-publication verification. + +**Impact** + +- CCP becomes responsibly promotable to external maintainers. + +**Residual risk** + +- Future pricing, platforms, identities, and repository-specific outcomes remain variable. + +## Delegation and cost policy + +1. Use deterministic tools before LLMs. +2. Delegate read-heavy inventory, documentation drafts, mechanical isolated edits, + deterministic test execution, and bounded review to GPT-5.6 Luna. +3. Give each worker one owned file group and no overlapping writes. +4. Keep architecture, trust boundaries, security, cryptography, release qualification, + external publication, integration review, and merge decisions with the primary agent. +5. Stop a cheap attempt after one clear failure and one focused correction. +6. Verify every delegated change centrally from the diff and relevant tests. + +## Validation and publication gates + +### Per commit + +- Focused tests for the changed contract. +- `cargo fmt --all -- --check` when Rust or formatted Rust fixtures change. +- `CHANGELOG.md` updated for user-visible behavior. + +### Per pull request + +- Full deterministic suite: `cargo test --locked --workspace --all-targets --all-features`. +- Clippy: `cargo clippy --locked --workspace --all-targets --all-features -- -D warnings`. +- Documentation: `cargo doc --locked --workspace --no-deps` and release metadata parity. +- Exact-head code review and no unresolved material findings. +- CCP receipt qualification only with a fresh exact authorization envelope. + +### External mutations + +- Non-forced push, PR creation, ready transition, evidence publication, merge, + repository metadata, label/milestone edits, social-preview upload, release, + package publication, signing, and case-study publication are separately reported + and gated by live exact state. + +## Interruption and recovery + +Before restart or handoff: + +1. record worktree, branch, HEAD, base, dirty files, and remote state; +2. stop or record active workers and processes; +3. record terminal checks and explicitly unproven gates; +4. commit recoverable in-scope work when authorized; +5. preserve any receipt, artifact digest ledger, and rollback anchor; +6. write the exact next command and reread this specification before resuming. + +No temporary path alone counts as durable preservation. The branch commit in the +main Git object store is the minimum local checkpoint; remote publication remains +a separate gate. + +## Milestone report format + +- Result obtained +- Terminal validation evidence +- Claims or behavior changed +- Residual risks and explicit non-claims +- Exact next dependency and required authority + +## Completion checklist + +- [ ] M0 programme control is committed and recoverable. +- [ ] M1 new-user conversion surface is clear, tested, and live on GitHub. +- [ ] M2 verifier is physically independent and fixture-compatible. +- [ ] M3 prioritized artifacts are available, smoke-verified, and provenance-bound. +- [ ] M4 slim gate verifies with an immutable trusted artifact. +- [ ] M5 new users reach first value through documented short paths. +- [ ] M6 evidence publication and pre-push are transactional and reversible. +- [ ] M7 cost reports preserve assumptions and evidence classes. +- [ ] M8 native Linux complete run is genuinely qualified. +- [ ] M9 A1 identity is standards-aligned and correctly bounded, or explicitly deferred from stable scope by an approved revision. +- [ ] M10 three consented case studies and the stable release are published and verified. +- [ ] Every public claim maps to exact current evidence. +- [ ] Every release byte maps to an exact tag, checksum, SBOM, and provenance record. +- [ ] Installation, smoke, E2E qualification, and identity assurance remain visibly distinct. +- [ ] Documentation, examples, support matrix, and rollback guidance match current behavior. +- [ ] No required human, native-platform, consent, security, or publication gate is represented as complete without terminal evidence. + +Completion is unproven until every applicable item has authoritative current evidence. diff --git a/tests/public_documentation_contract.rs b/tests/public_documentation_contract.rs new file mode 100644 index 0000000..40b46f0 --- /dev/null +++ b/tests/public_documentation_contract.rs @@ -0,0 +1,242 @@ +use std::collections::HashSet; +use std::path::{Path, PathBuf}; + +const SOCIAL_PREVIEW_PNG: &[u8] = include_bytes!("../docs/assets/social-preview.png"); + +fn unique_fixture_root(name: &str) -> PathBuf { + let root = std::env::temp_dir().join(format!( + "ccp-public-docs-{name}-{}-{}", + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("clock") + .as_nanos() + )); + assert!(!root.exists(), "fixture path unexpectedly exists: {root:?}"); + root +} + +fn local_link_destinations(markdown: &str) -> Vec { + let mut destinations = Vec::new(); + let mut rest = markdown; + while let Some(start) = rest.find("](") { + let after = &rest[start + 2..]; + let Some(end) = after.find(')') else { break }; + let mut destination = after[..end].trim().to_owned(); + if destination.starts_with('<') && destination.ends_with('>') { + destination = destination[1..destination.len() - 1].to_owned(); + } + destinations.push(destination); + rest = &after[end + 1..]; + } + destinations +} + +fn markdown_heading_anchors(markdown: &str) -> HashSet { + markdown + .lines() + .filter_map(|line| line.strip_prefix('#')) + .filter(|line| line.starts_with([' ', '\t'])) + .map(|line| { + line.trim() + .trim_end_matches('#') + .trim() + .chars() + .filter_map(|c| { + if c.is_alphanumeric() || c == '_' || c == '-' || c == ' ' { + Some(c.to_ascii_lowercase()) + } else { + None + } + }) + .collect::() + .split_whitespace() + .collect::>() + .join("-") + }) + .collect() +} + +fn validate_local_links(root: &Path, document: &Path) -> Vec { + let document_path = root.join(document); + let markdown = std::fs::read_to_string(&document_path).expect("read document"); + let mut findings = Vec::new(); + for destination in local_link_destinations(&markdown) { + if destination.starts_with("http:") + || destination.starts_with("https:") + || destination.starts_with("mailto:") + || destination.starts_with('/') + { + continue; + } + if destination.contains('%') { + findings.push(format!( + "{}: unsupported percent-encoded local link {destination}", + document.display() + )); + continue; + } + let (path_part, fragment) = destination + .split_once('#') + .map_or((destination.as_str(), None), |(path, fragment)| { + (path, Some(fragment)) + }); + let base_depth = document + .parent() + .map_or(0, |parent| parent.components().count()); + let mut depth = base_depth as isize; + let escapes_root = Path::new(path_part).components().any(|component| { + match component { + std::path::Component::ParentDir => depth -= 1, + std::path::Component::Normal(_) => depth += 1, + _ => {} + } + depth < 0 + }); + if escapes_root { + findings.push(format!( + "{}: local target escapes repository root {destination}", + document.display() + )); + continue; + } + let target_document = if path_part.is_empty() { + document_path.clone() + } else { + document_path + .parent() + .expect("document parent") + .join(path_part) + }; + let relative_target = target_document.strip_prefix(root).map_err(|_| ()).ok(); + if relative_target.is_none() { + findings.push(format!( + "{}: local target escapes repository root {destination}", + document.display() + )); + continue; + } + if !target_document.is_file() { + findings.push(format!( + "{}: missing local target {}", + document.display(), + path_part + )); + continue; + } + if let Some(fragment) = fragment { + let target = std::fs::read_to_string(&target_document).expect("read link target"); + if !markdown_heading_anchors(&target).contains(&fragment.to_ascii_lowercase()) { + findings.push(format!( + "{}: missing fragment #{fragment} in {path_part}", + document.display() + )); + } + } + } + findings +} + +fn png_dimensions(bytes: &[u8]) -> Result<(u32, u32), String> { + const SIGNATURE: &[u8; 8] = b"\x89PNG\r\n\x1a\n"; + if bytes.len() < SIGNATURE.len() || &bytes[..8] != SIGNATURE { + return Err("invalid PNG signature".into()); + } + if bytes.len() < 16 || &bytes[12..16] != b"IHDR" { + return Err("missing IHDR chunk".into()); + } + let chunk_length = u32::from_be_bytes(bytes[8..12].try_into().expect("chunk length")); + if chunk_length != 13 || bytes.len() < 8 + 4 + 4 + 13 + 4 { + return Err("truncated IHDR chunk".into()); + } + let width = u32::from_be_bytes(bytes[16..20].try_into().expect("width")); + let height = u32::from_be_bytes(bytes[20..24].try_into().expect("height")); + if width == 0 || height == 0 { + return Err("PNG dimensions must be non-zero".into()); + } + Ok((width, height)) +} + +#[test] +fn local_link_validation_reports_missing_files_and_fragments() { + let root = unique_fixture_root("broken-links"); + std::fs::create_dir_all(root.join("docs")).expect("create docs"); + std::fs::write( + root.join("README.md"), + "# Root\n\n[missing](docs/missing.md)\n[bad anchor](docs/present.md#absent)\n", + ) + .expect("write README"); + std::fs::write(root.join("docs/present.md"), "# Present heading\n").expect("write target"); + + let findings = validate_local_links(&root, Path::new("README.md")); + + assert_eq!( + findings, + vec![ + "README.md: missing local target docs/missing.md", + "README.md: missing fragment #absent in docs/present.md", + ] + ); + std::fs::remove_dir_all(root).expect("remove owned fixture"); +} + +#[test] +fn png_dimensions_rejects_invalid_or_truncated_bytes() { + assert_eq!( + png_dimensions(b"not a png"), + Err("invalid PNG signature".into()) + ); + assert_eq!( + png_dimensions(b"\x89PNG\r\n\x1a\n"), + Err("missing IHDR chunk".into()) + ); + let truncated_ihdr = b"\x89PNG\r\n\x1a\n\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01"; + assert_eq!( + png_dimensions(truncated_ihdr), + Err("truncated IHDR chunk".into()) + ); +} + +#[test] +fn local_links_reject_traversal_and_percent_encoding() { + let root = unique_fixture_root("safety"); + std::fs::create_dir_all(&root).expect("create fixture root"); + std::fs::write( + root.join("README.md"), + "[escape](../outside.md) [encoded](docs/a%20b.md)", + ) + .expect("write README"); + let findings = validate_local_links(&root, Path::new("README.md")); + assert_eq!(findings.len(), 2); + assert!(findings[0].contains("escapes repository root")); + assert!(findings[1].contains("unsupported percent-encoded")); + std::fs::remove_dir_all(root).expect("remove owned fixture"); +} + +#[test] +fn current_public_documents_have_valid_local_links() { + let root = Path::new(env!("CARGO_MANIFEST_DIR")); + const PUBLIC_DOCUMENTS: &[&str] = &[ + "README.md", + "SUPPORT.md", + "docs/CASE_STUDY_PR71.md", + "docs/INSTALLATION.md", + "docs/TUTORIAL.md", + "docs/ADOPTION_GUIDE.md", + "docs/BETA_SUPPORT.md", + "docs/REPOSITORY_PRESENTATION.md", + "docs/THREAT_MODEL.md", + ]; + // Task 2 adds SUPPORT.md and docs/CASE_STUDY_PR71.md to this active slice. + let findings: Vec<_> = PUBLIC_DOCUMENTS + .iter() + .flat_map(|document| validate_local_links(root, Path::new(document))) + .collect(); + assert!(findings.is_empty(), "documentation findings: {findings:?}"); +} + +#[test] +fn social_preview_png_is_uploadable() { + assert_eq!(png_dimensions(SOCIAL_PREVIEW_PNG), Ok((1280, 640))); + assert!(SOCIAL_PREVIEW_PNG.len() < 1_048_576); +} diff --git a/tests/repository_hygiene_contract.rs b/tests/repository_hygiene_contract.rs index 3f855d1..c1b5c3d 100644 --- a/tests/repository_hygiene_contract.rs +++ b/tests/repository_hygiene_contract.rs @@ -22,6 +22,7 @@ use saphyr::{LoadableYamlNode, MappingOwned, YamlOwned}; const BUG_FORM: &str = include_str!("../.github/ISSUE_TEMPLATE/bug_report.yml"); const FEATURE_FORM: &str = include_str!("../.github/ISSUE_TEMPLATE/feature_request.yml"); const ADOPTION_FORM: &str = include_str!("../.github/ISSUE_TEMPLATE/adoption_report.yml"); +const ADOPTION_HELP_FORM: &str = include_str!("../.github/ISSUE_TEMPLATE/adoption_help.yml"); const ISSUE_CONFIG: &str = include_str!("../.github/ISSUE_TEMPLATE/config.yml"); const PR_TEMPLATE: &str = include_str!("../.github/PULL_REQUEST_TEMPLATE.md"); const ROADMAP: &str = include_str!("../ROADMAP.md"); @@ -212,6 +213,7 @@ fn issue_template_yaml_is_present_and_safe() { assert_yaml_mapping("bug report form", BUG_FORM, true); assert_yaml_mapping("feature request form", FEATURE_FORM, true); assert_yaml_mapping("adoption report form", ADOPTION_FORM, true); + assert_yaml_mapping("adoption help form", ADOPTION_HELP_FORM, true); assert!(contains_field(ISSUE_CONFIG, "blank_issues_enabled", false)); @@ -232,6 +234,14 @@ fn issue_template_yaml_is_present_and_safe() { assert!(contains_field(ADOPTION_FORM, "title", true)); assert!(contains_field(ADOPTION_FORM, "labels", true)); assert!(contains_field(ADOPTION_FORM, "body", true)); + + assert!(contains_field(ADOPTION_HELP_FORM, "name", true)); + assert!(contains_field(ADOPTION_HELP_FORM, "description", true)); + assert!(contains_field(ADOPTION_HELP_FORM, "title", true)); + assert!(contains_field(ADOPTION_HELP_FORM, "labels", true)); + assert!(contains_field(ADOPTION_HELP_FORM, "body", true)); + assert_yaml_labels_include_question(ADOPTION_HELP_FORM); + assert_adoption_help_body_contract(ADOPTION_HELP_FORM); } #[test] @@ -252,6 +262,7 @@ fn templates_do_not_include_unsafe_claim_phrases() { ("bug form", BUG_FORM), ("feature form", FEATURE_FORM), ("adoption form", ADOPTION_FORM), + ("adoption help form", ADOPTION_HELP_FORM), ("PR template", PR_TEMPLATE), ("roadmap", ROADMAP), ] { @@ -282,6 +293,7 @@ fn roadmap_and_templates_reference_existing_local_docs() { ".github/ISSUE_TEMPLATE/bug_report.yml", ".github/ISSUE_TEMPLATE/feature_request.yml", ".github/ISSUE_TEMPLATE/adoption_report.yml", + ".github/ISSUE_TEMPLATE/adoption_help.yml", ".github/ISSUE_TEMPLATE/config.yml", ".github/PULL_REQUEST_TEMPLATE.md", "ROADMAP.md", @@ -352,6 +364,76 @@ fn contains_field(raw_yaml: &str, field: &str, assert_scalar_or_array: bool) -> } } +fn assert_yaml_labels_include_question(raw_yaml: &str) { + let documents = YamlOwned::load_from_str(raw_yaml).expect("yaml"); + let mapping = documents[0].as_mapping().expect("mapping"); + let labels = mapping_get(mapping, "labels") + .and_then(YamlOwned::as_sequence) + .expect("adoption help labels sequence"); + assert!( + labels + .iter() + .any(|label| label.as_str() == Some("question")) + ); +} + +fn assert_adoption_help_body_contract(raw_yaml: &str) { + let documents = YamlOwned::load_from_str(raw_yaml).expect("yaml"); + let mapping = documents[0].as_mapping().expect("mapping"); + let body = mapping_get(mapping, "body") + .and_then(YamlOwned::as_sequence) + .expect("adoption help body sequence"); + let required_ids = [ + "ccp_version", + "project_runtime", + "platform", + "repository_language", + "attempted_step", + "error_summary", + "expected_outcome", + "privacy_confirmation", + ]; + for id in required_ids { + let item = body.iter().find(|item| { + item.as_mapping() + .and_then(|item| mapping_get(item, "id")) + .and_then(YamlOwned::as_str) + == Some(id) + }); + let item = item.unwrap_or_else(|| panic!("missing adoption-help field {id}")); + let item_mapping = item.as_mapping().expect("body item mapping"); + let item_type = mapping_get(item_mapping, "type") + .and_then(YamlOwned::as_str) + .expect("body item type"); + if id == "privacy_confirmation" { + assert_eq!(item_type, "checkboxes"); + let attributes = mapping_get(item_mapping, "attributes") + .and_then(YamlOwned::as_mapping) + .expect("checkbox attributes"); + let options = mapping_get(attributes, "options") + .and_then(YamlOwned::as_sequence) + .expect("checkbox options"); + assert!(options.iter().any(|option| { + option + .as_mapping() + .and_then(|option| mapping_get(option, "required")) + .and_then(YamlOwned::as_bool) + == Some(true) + })); + } else { + assert!(matches!(item_type, "input" | "textarea")); + let validations = mapping_get(item_mapping, "validations") + .and_then(YamlOwned::as_mapping) + .expect("required field validations"); + assert_eq!( + mapping_get(validations, "required").and_then(YamlOwned::as_bool), + Some(true), + "{id} must be required" + ); + } + } +} + fn mapping_get<'a>(mapping: &'a MappingOwned, key: &str) -> Option<&'a YamlOwned> { mapping .iter()