diff --git a/README.md b/README.md index 7e20455..a113c10 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,29 @@ # PatchGate [![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![TypeScript: Strict](https://img.shields.io/badge/TypeScript-Strict_100%25-blue.svg)](https://www.typescriptlang.org/) [![CI](https://github.com/daichunghy/patchgate/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/daichunghy/patchgate/actions/workflows/ci.yml) [![CodeQL](https://github.com/daichunghy/patchgate/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/daichunghy/patchgate/actions/workflows/codeql.yml) -PatchGate checks whether a GitHub pull request has the issue link, CI evidence, -code owners, and human approval a repository requires before a maintainer -reviews it. +PatchGate is a deterministic GitHub pull-request readiness check. It answers one +narrow question: -That is the job. PatchGate does not review code, detect AI authorship, or decide -whether a change should merge. +> Does this pull request contain the policy, evidence, ownership, and human +> approval signals that this repository requires before a maintainer reviews it? -The evaluator is deterministic and produces a receipt that explains which -requirements passed, which evidence is missing, and which human gate remains. -It cannot force external automation to stop working. +PatchGate is not a code-quality oracle, an AI-authorship detector, or a merge +decision-maker. It produces a receipt that explains what passed, what is +missing, and which human decision remains. -**Status (2026-08-30):** public pre-release, 1 GitHub star, 0 forks, and no -verified external users, downstream repositories, or pilots. The npm package -remains unpublished (`private: true`, `0.1.0-dev`). The current Action release is -[`v0.1.0-beta.5`](https://github.com/daichunghy/patchgate/releases/tag/v0.1.0-beta.5), -and consumers should pin the immutable commit shown on that release page for -**shadow** evaluation only. This is not production, not a `v0.1` claim, and -not evidence of external adoption. +## Why it exists -The four related repositories and the shared evidence rules are recorded in -[the repository portfolio audit](docs/reviews/2026-08-28-repository-portfolio-audit.md). +Coding agents make it easy to open a pull request before the repository's +contribution contract has been understood. Maintainers then spend review time +chasing missing issue links, unrecorded tests, unclear ownership, or an absent +human gate. -The shortest path to a user result is [one non-blocking first-use check](docs/first-use.md). -The workspace tracks this alongside the [continuous adoption loop](docs/adoption-loop.md). +PatchGate turns those expectations into an explicit, versioned policy and a +repeatable preflight. The evaluator is local and deterministic; the GitHub +adapter is an explicit boundary with a documented permission model. ## Try one real pull request in five minutes @@ -62,36 +57,31 @@ Remove the workflow after the trial, or follow the [shadow installation runbook](docs/pilots/g4-shadow-installation-runbook.md) before requesting any broader use. -## Try it locally +## Current status -The fastest first-run path is a direct GitHub install on Node 20+ — `npx` -clones the repository, builds it via the `prepare` script and runs the -`patchgate` binary. Do not run `npx patchgate`: that npm name belongs to a -different project and this package is unpublished. +**Status (2026-08-30):** public pre-release, 1 GitHub star, 0 forks, and no +verified external users, downstream repositories, or pilots. The npm package +remains unpublished (`private: true`, `0.1.0-dev`). The current Action release is +[`v0.1.0-beta.5`](https://github.com/daichunghy/patchgate/releases/tag/v0.1.0-beta.5), +and consumers should pin the immutable commit shown on that release page for +**shadow** evaluation only. This is not production, not a `v0.1` claim, and +not evidence of external adoption. -```bash -npx github:daichunghy/patchgate --version -npx github:daichunghy/patchgate doctor --base /path/to/your/repo -npx github:daichunghy/patchgate preflight --base main --repo /path/to/your/repo -``` +## Try it locally -A walkthrough with real captured output is in [docs/demo.md](docs/demo.md). To -work from a clone instead: +The fastest path runs against the repository's recorded fixture and needs no +token, network access, or pull-request checkout: ```bash git clone https://github.com/daichunghy/patchgate.git cd patchgate npm ci -npm run build -node dist/src/cli.js --help -node dist/src/cli.js init --path /tmp/patchgate-try -node dist/src/cli.js validate --policy /tmp/patchgate-try -node dist/src/cli.js validate --base /tmp/patchgate-try -node dist/src/cli.js preflight --base docs/patchgate.example.yml -node dist/src/cli.js doctor --base docs/patchgate.example.yml +npm run verify node dist/src/cli.js evaluate --event fixtures/pr-ready.json --report /tmp/patchgate-receipt.json ``` +To inspect the result: + `validate` accepts `--base` as an alias of `--policy`. `evaluate` writes receipts with `--report` (or `--output`, the shared write-path alias); `github snapshot` and `support-bundle` write files with `--output` only. Giving @@ -100,244 +90,121 @@ snapshot` and `support-bundle` write files with `--output` only. Giving Longer walkthrough: [Getting started](docs/getting-started.md). -## GitHub Action candidate +```bash +node dist/src/cli.js explain /tmp/patchgate-receipt.json +``` + +For a first-use walkthrough, see [docs/first-use.md](docs/first-use.md). To use +the CLI against a local repository: + +```bash +node dist/src/cli.js preflight --base main --repo /path/to/repository +node dist/src/cli.js doctor --base /path/to/repository +``` + +Run `npm run verify` after making a change. It covers type checking, builds, +deterministic fixtures, security cases, clean-room installation, and CLI +smoke tests. + +## What it checks + +A policy can require signals such as: + +- an issue or discussion link; +- recorded, allowlisted test evidence; +- CODEOWNERS or sensitive-path ownership; +- commit-bound status checks; +- a declared human review gate; +- repository and workflow permissions that stay within the policy. + +Every result is classified explicitly: ready, blocked, needs human review, +evidence missing, or policy ambiguous. Discovery findings are advisory and +cannot become enforcement by themselves. + +## GitHub Action + +The repository contains a GitHub Action candidate for non-blocking shadow +evaluation. Follow the [Action usage guide](docs/github-action-usage.md) before +installing it in another repository. -The Action is bundled for the repository's local shadow workflow. The tagged -pre-release [`v0.1.0-beta.5`](https://github.com/daichunghy/patchgate/releases/tag/v0.1.0-beta.5) +The tagged pre-release +[`v0.1.0-beta.5`](https://github.com/daichunghy/patchgate/releases/tag/v0.1.0-beta.5) is the current release; pin `34d998bbd59fa09dd9081e24f22abe812f97fbab` for shadow evaluation. Production consumers must still wait for a stable public release. Do not use the placeholder `patchgate/patchgate@v0.1.0-dev` as an installable public -reference. Consumer setup, permissions and the shadow workflow are documented -in the [Action usage guide](docs/github-action-usage.md). +reference. For this checkout, the source-of-truth workflow is [`.github/workflows/patchgate-shadow.yml`](.github/workflows/patchgate-shadow.yml). It uses `pull_request_target`, checks out the trusted base revision, builds the Action bundle from that base, runs with `fail-on: never`, and updates one check -run. Production consumers must wait for a public immutable Action release. A -consented non-blocking shadow pilot may use an explicitly approved full-SHA -pre-release commit by following the [G4 shadow-installation runbook](docs/pilots/g4-shadow-installation-runbook.md). +run. A consented non-blocking shadow pilot may use an explicitly approved +full-SHA pre-release commit by following the +[G4 shadow-installation runbook](docs/pilots/g4-shadow-installation-runbook.md). -## Local development +The trusted metadata lane uses `pull_request_target` only to read base-revision +policy and authenticated metadata. It never checks out or executes pull-request +code. Code that must run belongs in an unprivileged `pull_request` workflow. +Pin an immutable commit when testing the Action, and keep the check non-blocking +until a maintainer has reviewed the receipt and configured the repository rule +that should honor it. -```bash -npm install -npm run verify -npm run build -npm run bundle:action -node dist/src/cli.js init --path /tmp/my-repository -node dist/src/cli.js validate --policy docs/patchgate.example.yml -node dist/src/cli.js preflight --base docs/patchgate.example.yml -node dist/src/cli.js preflight --base main --repo /path/to/repository --json -node dist/src/cli.js doctor --base docs/patchgate.example.yml --json -node dist/src/cli.js evaluate --event fixtures/pr-ready.json --report /tmp/patchgate-receipt.json -npm run test:github -node dist/src/cli.js github snapshot --mock-fixture fixtures/api/happy-path.json --output /tmp/patchgate-github-snapshot.json -node dist/src/cli.js support-bundle --input /tmp/patchgate-github-snapshot.json --output /tmp/patchgate-support.json -``` +## Security model + +PatchGate separates three concerns: -`init` creates a version-1 draft only and refuses to overwrite an existing -policy. `validate` and local-file `preflight` read an explicit path. Git-ref -`preflight` reads `patchgate.yml` and the discovery-only guidance files from -the named commit using Git objects; it does not checkout or execute -pull-request code. `doctor` reports local capability without requiring a -token. All discovery findings are advisory, needs-confirmation, or -unsupported and can never become enforcement by themselves. - -The `evaluate` command consumes a normalized JSON snapshot so that policy -evaluation can be tested without network access. The GitHub adapter -produces this snapshot from recorded authenticated metadata and -base-revision content. Live mode is explicit, requires -`PATCHGATE_GITHUB_TOKEN`, and is documented in -[the adapter contract](docs/github-adapter-contract.md). - -## Trust model - -PatchGate uses three separate lanes: - -1. The trusted metadata lane reads base-revision policy, GitHub metadata, - rulesets, CODEOWNERS, reviews, and commit-bound check evidence. It never - checks out or executes pull-request code. -2. The untrusted verification lane may run contributor code in a separate +1. The trusted metadata lane reads policy, GitHub metadata, rulesets, CODEOWNERS, + reviews, and commit-bound checks from a trusted base revision. +2. The untrusted verification lane may run contributor code in a separate, read-only workflow with no repository secrets. -3. The decision lane evaluates authenticated metadata and explicitly bound - evidence, then emits a receipt. - -For GitHub Actions, a `pull_request_target` workflow may read metadata and post -results, but must never execute a checkout of pull-request code. A workflow -that needs to run contributor code belongs in the unprivileged -`pull_request` lane. See [the architecture note](docs/architecture.md) and -[the threat model](docs/threat-model.md). - -## Repository Organization - -The repository maintains a clean root directory structure (9 files max) with modular subdirectories: - -```text -. -├── .github/ # GitHub workflows, actions, CODEOWNERS, templates, community health files -│ ├── CODEOWNERS # Path ownership configuration -│ ├── CODE_OF_CONDUCT.md # Community Code of Conduct -│ ├── CONTRIBUTING.md # Contribution guidelines and development workflow -│ ├── SECURITY.md # Vulnerability reporting and security boundary policy -│ ├── SUPPORT.md # Getting support and communication channels -│ ├── dependabot.yml # Dependency update configuration -│ ├── community-posts.json # Scheduled community discussion content -│ ├── patchgate.yml # Repository review-readiness policy -│ ├── ISSUE_TEMPLATE/ # GitHub Issue forms -│ ├── PULL_REQUEST_TEMPLATE.md # PR description template -│ └── workflows/ # CI/CD and verification GitHub Actions -├── docs/ # Architecture, design decisions, research, and specifications -│ ├── PROJECT_CONSTITUTION.md # Authoritative charter and product constitution -│ ├── getting-started.md # Clone, build, init, validate, preflight, doctor, evaluate -│ ├── CHANGELOG.md # Release and development history -│ ├── NOTICE # Attribution and open source notices -│ ├── patchgate.example.yml # Example PatchGate policy specification -│ ├── architecture.md # System architecture and lanes -│ ├── implementation-roadmap.md # Delivery roadmap (G0-G8) -│ ├── receipt-contract.md # ContributionReceipt specification -│ ├── threat-model.md # Security threat scenarios and mitigations -│ ├── github-adapter-contract.md # Adapter specification and bounds -│ ├── github-api-support-matrix.md # API endpoints and versioning -│ ├── github-permissions.md # Permission model and least privilege -│ ├── github-action-usage.md # Consumer Action usage & shadow-mode guide -│ ├── support-bundle.md # Redacted diagnostic bundle spec -│ ├── research/ # Landscape and deep-dive research reports -│ ├── decisions/ # Architecture Decision Records (ADRs) -│ ├── product/ # User requirements and UX specs -│ ├── pilots/ # Usability session protocols & pilot results -│ ├── prompts/ # Task prompts and launcher specifications -│ ├── reviews/ # Milestone implementation reviews -│ ├── releases/ # Release records and the beta rollback runbook -│ ├── application/ # Codex for Open Source application evidence -│ ├── community/ # Community interaction and outreach records -│ └── security/ # GitHub adapter security boundary notes -├── src/ # Pure TypeScript implementation (Strict mode, zero `any`) -│ ├── types.ts # Canonical types and data models -│ ├── evaluator-core.ts # Deterministic requirement evaluation engine -│ ├── evaluator.ts # High-level evaluation runner with timestamping -│ ├── policy.ts # Policy parser and SHA-256 digest computation -│ ├── discovery.ts # Advisory guidance discovery -│ ├── canonical-json.ts # Deterministic JSON serialization and SHA-256 -│ ├── support-bundle.ts # Diagnostics bundle generator -│ ├── version.ts # Evaluator version constant -│ ├── contract/ # Schemas, status precedence, and validation -│ ├── evidence/ # Digest computation and check evidence verification -│ ├── github/ # Authenticated GitHub adapter, snapshot builder, and rate limiters -│ ├── cli.ts & cli/ # Command-line interface -│ └── action/ # GitHub Action runner -├── schemas/ # Versioned JSON Schemas (receipt, policy, evaluation-input) -├── fixtures/ # Deterministic test fixtures and API exchange recordings -├── test/ # Comprehensive unit, integration, security, and determinism tests -├── scripts/ # Linters, budget checkers, and verification harnesses -├── action.yml # GitHub Action metadata (not Marketplace-listed) -├── AGENTS.md # Repository guidance for automated contributors -├── LICENSE # Apache-2.0 License -├── README.md # Project overview and quickstart -├── package.json # Node package manifest -├── package-lock.json # Deterministic dependency lockfile -├── tsconfig.json # Strict TypeScript configuration -├── vitest.config.ts # Test runner configuration -└── .gitignore # Git ignore rules -``` +3. The decision lane evaluates normalized evidence and emits a receipt. -## Documentation +See the [architecture](docs/architecture.md), [threat model](docs/threat-model.md), +and [GitHub permission contract](docs/github-permissions.md) before enabling a +live adapter. + +## Contributing + +Start with [CONTRIBUTING.md](.github/CONTRIBUTING.md), then choose a bounded +issue: + +- [clean consumer-repository fixture](https://github.com/daichunghy/patchgate/issues/7); +- [CODEOWNERS conformance fixtures](https://github.com/daichunghy/patchgate/issues/6); +- [pilot request](https://github.com/daichunghy/patchgate/issues/4). + +A useful contribution includes a reproducible fixture, the expected receipt, +tests, and a short explanation of the boundary it exercises. Please open an +issue first for changes that alter policy semantics or the security model. + +For a consented maintainer walkthrough, use the [shadow-pilot brief](docs/pilots/patchgate-shadow-pilot-brief.md). +External pilots are non-blocking, require maintainer consent, and should report +both useful findings and false positives. + +## Documentation map - [Getting started](docs/getting-started.md) -- [Project constitution](docs/PROJECT_CONSTITUTION.md) -- [Example policy](docs/patchgate.example.yml) -- [Action usage guide](docs/github-action-usage.md) -- [v0.1.0-beta.5 release record](docs/releases/2026-08-23-beta.5.md) -- [Contributing](.github/CONTRIBUTING.md) -- [Security policy](.github/SECURITY.md) -- [Code of conduct](.github/CODE_OF_CONDUCT.md) -- [Support guide](.github/SUPPORT.md) -- [Community discussions](https://github.com/daichunghy/patchgate/discussions) -- [Non-blocking pilot request](https://github.com/daichunghy/patchgate/issues/4) -- [Independent review and pilot outreach drafts](docs/community/independent-review-and-pilot-outreach.md) -- [Marketing message kit and claims guardrail](docs/community/marketing-message-kit.md) - -### Contribution opportunities - -- [Clean consumer-repository Action fixture](https://github.com/daichunghy/patchgate/issues/7) -- [CODEOWNERS conformance fixtures](https://github.com/daichunghy/patchgate/issues/6) -- [Beta release and rollback guide](https://github.com/daichunghy/patchgate/issues/5) -- [Research and landscape review](docs/research/2026-08-12-patchgate-landscape.md) -- [Deep-dive research: API, state, threat tests and pilot](docs/research/2026-08-13-patchgate-deep-dive.md) -- [Architecture and evidence contract](docs/architecture.md) +- [Architecture](docs/architecture.md) - [Receipt contract](docs/receipt-contract.md) - [Threat model](docs/threat-model.md) - [GitHub adapter contract](docs/github-adapter-contract.md) -- [GitHub API and capability matrix](docs/github-api-support-matrix.md) -- [GitHub permission contract](docs/github-permissions.md) -- [GitHub adapter security boundary](docs/security/github-adapter-boundary.md) -- [Authorized live-smoke protocol](docs/github-live-smoke-protocol.md) -- [Redacted support bundle](docs/support-bundle.md) -- [Project-wide review and next-build checkpoint](docs/reviews/2026-08-13-project-wide-review.md) -- [Current G4/G0 continuation audit](docs/reviews/2026-08-20-g4-g0-audit.md) -- [Agent verification foundation](docs/reviews/2026-08-27-agent-verification-foundation.md) +- [Action usage](docs/github-action-usage.md) - [Implementation roadmap](docs/implementation-roadmap.md) -- [User requirements](docs/product/user-requirements.md) -- [User-needs and roadmap research](docs/research/2026-08-13-patchgate-user-needs-roadmap-review.md) -- [Detailed execution plan for agents](docs/agent-execution-plan.md) -- [Agent verification map](docs/agent-verification-map.md) -- [Agent evaluation protocol](docs/agent-evaluation-protocol.md) -- [Machine-readable agent work packages](docs/agent-work-packages.yml) -- [Prompt 1 implementation review](docs/reviews/2026-08-13-prompt-01-review.md) -- [Prompt 2 implementation report](docs/reviews/2026-08-13-prompt-02-implementation.md) -- [Roadmap 2.0 user-needs improvement report](docs/reviews/2026-08-13-roadmap-v2-user-needs.md) -- [G2 local onboarding implementation report](docs/reviews/2026-08-13-g2-local-onboarding-implementation.md) -- [G2 preflight, Git-ref and discovery checkpoint](docs/reviews/2026-08-13-g2-preflight-git-ref-discovery.md) -- [G2 usability session protocol](docs/pilots/g2-usability-session-protocol.md) -- [G4 shadow installation runbook](docs/pilots/g4-shadow-installation-runbook.md) -- [Beta release and rollback runbook](docs/releases/beta-release-and-rollback.md) -- [Prompt 2: observation contract and compatibility](docs/prompts/prompt-02-observation-contract-and-compatibility.md) -- [Prompt launcher for Prompt 2](docs/prompts/prompt-02-launcher.md) -- [Prompt 3: public foundation and maintainer decisions](docs/prompts/prompt-03-public-foundation-and-maintainer-decisions.md) -- [Prompt launcher for Prompt 3](docs/prompts/prompt-03-launcher.md) -- [Prompt 4: authenticated GitHub adapter](docs/prompts/prompt-04-authenticated-github-adapter.md) -- [Prompt launcher for Prompt 4](docs/prompts/prompt-04-launcher.md) -- [G0 maintainer decision brief](docs/decisions/2026-08-13-g0-maintainer-decision-brief.md) -- [Codex for Open Source evidence dossier](docs/application/codex-for-open-source-evidence-dossier.md) -- [Constitution readiness matrix](docs/application/constitution-readiness-matrix.md) -- [Codex for Open Source form draft](docs/application/codex-for-open-source-form-draft.md) - -## Evaluate or contribute - -PatchGate is still a public pre-release project. The clearest ways to help are -to run the [evidence review packet](docs/community/evidence-review-packet.md), -take one of the scoped [contribution issues](https://github.com/daichunghy/patchgate/issues), -or review the [non-blocking shadow pilot brief](docs/pilots/patchgate-shadow-pilot-brief.md). -For usability research, use the [consent-safe G2 session record](docs/pilots/g2-session-record-template.md). - -Maintainers can follow the public [community Project](https://github.com/users/daichunghy/projects/1) -and the [evidence index](docs/application/evidence-index.md). PatchGate does not -claim downstream adoption, a production release or successful external pilots until -those artifacts exist and can be checked independently. - -## Product boundary - -PatchGate can report `ready_for_review`, `blocked`, -`human_review_required`, `evidence_missing`, or `policy_ambiguous`. A status -check blocks a merge only when a maintainer configures the corresponding -GitHub rule or ruleset. `human_review_required` means that a declared human -gate remains unsatisfied; it is not proof that a human has reviewed the code. - -PatchGate must not claim a cryptographic signature, tamper-proof receipt, -compliance certification, or proof that the code is correct until the exact -mechanism and verification path exist and are tested. - -## Who this is for - -- Maintainers of public repositories who spend review time on pull requests - that arrive without the policy, evidence, or ownership signals the repo - requires. -- Teams whose coding agents open pull requests faster than humans can triage. -- Not a fit if you want authorship detection, correctness scoring, or blocking - without configuring a GitHub rule to honor the status check. - -If PatchGate saved you review time on one pull request, star the repository. It -helps other maintainers find the gate. - -Release history: [CHANGELOG.md](CHANGELOG.md). +- [Security policy](.github/SECURITY.md) +- [Support](.github/SUPPORT.md) +- [Changelog](CHANGELOG.md) + +## Boundaries + +PatchGate does not claim that code is correct, that a person reviewed code, +that a receipt is tamper-proof, or that a repository is compliant with a +standard. A status check can block a merge only after a repository maintainer +explicitly configures the corresponding branch rule or ruleset. + +The project is public pre-release software. Adoption means a separate +maintainer-consented result in a real repository; local fixtures, source +releases, and internal checks are not counted as external use. + +## License + +Apache-2.0. See [LICENSE](LICENSE). diff --git a/docs/github-action-usage.md b/docs/github-action-usage.md index 8c86c2a..c6ebd80 100644 --- a/docs/github-action-usage.md +++ b/docs/github-action-usage.md @@ -60,7 +60,8 @@ jobs: # with administration:read is required for a complete native-control # snapshot. The Check Run output shows the full tested SHA and its # binding to the PR head; a stale event is rejected before evaluation. - # snapshot-rejection Check Runs are included in beta.5. + # The public beta posts a Check Run for successful evaluations; + # snapshot-rejection Check Runs are included in the public beta. # Release identity before resolving the immutable commit: # uses: daichunghy/patchgate@v0.1.0-beta.5 - name: Run PatchGate Shadow Gate diff --git a/scripts/check-consumer-docs.mjs b/scripts/check-consumer-docs.mjs index 435ec78..4ae47ab 100644 --- a/scripts/check-consumer-docs.mjs +++ b/scripts/check-consumer-docs.mjs @@ -5,41 +5,65 @@ import { join } from "node:path"; import { fileURLToPath } from "node:url"; const root = fileURLToPath(new URL("..", import.meta.url)); -const currentTag = "v0.1.0-beta.5"; -const currentReleaseUrl = `https://github.com/daichunghy/patchgate/releases/tag/${currentTag}`; +const releaseDoc = readFileSync( + join(root, "docs/releases/beta-release-and-rollback.md"), + "utf8", +); +const releaseMatch = releaseDoc.match( + /\[\`(v\d+\.\d+\.\d+(?:-[A-Za-z0-9.]+)?)\`\]\(https:\/\/github\.com\/daichunghy\/patchgate\/releases\/tag\/\1\)/, +); +const failures = []; + +if (!releaseMatch) { + failures.push( + "release runbook must link the current public release using a self-consistent tag and URL", + ); +} + +const currentTag = releaseMatch?.[1] ?? ""; +const currentReleaseUrl = currentTag + ? `https://github.com/daichunghy/patchgate/releases/tag/${currentTag}` + : ""; +// The README is intentionally release-agnostic. Release assertions belong in +// the focused consumer and release runbooks so the front page can stay useful +// between releases. const surfaces = [ - "README.md", "docs/github-action-usage.md", "docs/getting-started.md", "docs/releases/beta-release-and-rollback.md", ]; -const failures = []; for (const relativePath of surfaces) { const text = readFileSync(join(root, relativePath), "utf8"); - if (!text.includes(currentTag)) failures.push(`${relativePath} must name ${currentTag}`); - if (!text.includes(currentReleaseUrl)) failures.push(`${relativePath} must link the ${currentTag} release`); + if (currentTag && !text.includes(currentTag)) { + failures.push(`${relativePath} must name ${currentTag}`); + } + if (currentReleaseUrl && !text.includes(currentReleaseUrl)) { + failures.push(`${relativePath} must link the ${currentTag} release`); + } } const usage = readFileSync(join(root, "docs/github-action-usage.md"), "utf8"); -if (!usage.includes(`uses: daichunghy/patchgate@${currentTag}`)) { - failures.push("docs/github-action-usage.md must pin the current beta in consumer examples"); +const normalizedUsage = usage.replace(/\s+/g, " "); +if (currentTag && !normalizedUsage.includes(`uses: daichunghy/patchgate@${currentTag}`)) { + failures.push( + "docs/github-action-usage.md must pin the current public release in consumer examples", + ); } -if (usage.includes("beta.2 posts a Check Run")) { +if (normalizedUsage.includes("beta.2 posts a Check Run")) { failures.push("docs/github-action-usage.md contains the stale beta.2 Check Run claim"); } -if (!usage.includes("snapshot-rejection Check Runs are included in beta.5")) { - failures.push("docs/github-action-usage.md must state the current snapshot-rejection Check Run behavior"); -} - -const readme = readFileSync(join(root, "README.md"), "utf8"); -if (readme.includes("uses: daichunghy/patchgate@v0.1.0-beta.2")) { - failures.push("README.md must not teach the superseded beta.2 Action reference"); +if (!normalizedUsage.includes("snapshot-rejection Check Runs are included in the public beta")) { + failures.push( + "docs/github-action-usage.md must describe snapshot-rejection Check Run behavior without a release-specific claim", + ); } if (failures.length > 0) { - process.stderr.write(`consumer documentation check failed:\n${failures.join("\n")}\n`); + process.stderr.write(`consumer documentation check failed:\\n${failures.join("\\n")}\\n`); process.exit(1); } -process.stdout.write(`consumer documentation check passed: ${surfaces.length} public surfaces reference ${currentTag}\n`); +process.stdout.write( + `consumer documentation check passed: ${surfaces.length} focused public surfaces follow the canonical release runbook\\n`, +);