From 11bfcc763a3e48188c127b6ccf9deacb40a680f6 Mon Sep 17 00:00:00 2001 From: Sung-Kyu Yoo Date: Sun, 6 Sep 2026 17:10:30 +0900 Subject: [PATCH 1/3] fix: a release dry run discarded the artifacts it exists to produce The Upload assets step ran when dry_run was not set. So it uploaded on a real release, where GoReleaser has already attached the same archives and checksums to the GitHub Release, and skipped the one path that publishes nothing and therefore has no other output. RELEASE.md has described the intended behaviour all along: a dry run "builds artifacts and uploads them to the run, but publishes nothing". The condition was inverted, so a maintainer validating a build before committing to a tag got a green run with nothing to inspect. --- .github/workflows/release.yml | 8 +++++++- changes/unreleased/Fixed-20260906-231000.yaml | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 changes/unreleased/Fixed-20260906-231000.yaml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 17d63004..70294313 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -270,8 +270,14 @@ jobs: # variable is missing. On a dry run the minting step is skipped, and the # placeholder is never used because --snapshot publishes nothing. HOMEBREW_TAP_TOKEN: ${{ steps.tap_token.outputs.token || 'dry-run' }} + # A dry run exists to be looked at: --snapshot publishes nothing, so the run + # artifact is the only place its binaries and archives can be inspected. The + # condition was inverted — it uploaded on a real release, where GoReleaser + # has already attached the same files to the GitHub Release, and uploaded + # nothing on the one path that produces no other output. RELEASE.md has + # described the intended behaviour since the dry run was documented. - name: Upload assets - if: ${{ github.event.inputs.dry_run != 'true' }} + if: ${{ github.event.inputs.dry_run == 'true' }} uses: actions/upload-artifact@v7 with: name: devcloud diff --git a/changes/unreleased/Fixed-20260906-231000.yaml b/changes/unreleased/Fixed-20260906-231000.yaml new file mode 100644 index 00000000..f175a1d1 --- /dev/null +++ b/changes/unreleased/Fixed-20260906-231000.yaml @@ -0,0 +1,5 @@ +kind: Fixed +body: 'A release dry run keeps its artifacts. The `Upload assets` step ran when `dry_run` was not set, so it uploaded on a real release — where GoReleaser has already attached the same files to the GitHub Release — and skipped the one path that publishes nothing and therefore has no other output. RELEASE.md documents the dry run as building artifacts and uploading them to the run, so a maintainer validating a build before tagging got a green run with nothing to inspect' +time: 2026-09-06T23:10:00.000000+09:00 +custom: + Issue: "150" From e4d9e5a19ce00d5dd373fac53df54ba064b1b739 Mon Sep 17 00:00:00 2001 From: Sung-Kyu Yoo Date: Sun, 6 Sep 2026 17:10:30 +0900 Subject: [PATCH 2/3] docs: the compatibility policy quoted five figures the code had outgrown 775 boto3 tests, 948 auto-crud operations, 4,496 hand-verified, 148 registered services of which 31 served nothing, and a 93/11 split of model-backed to hand-written services. The measured values are 1,144, 5,193, 4,497, 205 with 4 serving nothing, and 193/12. Nothing caught the drift because nothing reads the file. cmd/devcloud/coverage_test.go gates docs/coverage.md, README.md and docs/README.md against the live registry in both directions; this document is not in that set, and the Go tests that do cite it (internal/config/config_test.go, internal/admin/api_test.go) lock the guaranteed surface by hardcoding keys rather than by parsing prose. The figures now come from the gated page or from a measurement, not from a restatement. This matters more than a stale number usually would: the document ships inside the release archive, so the copy in devcloud_vX.Y.Z_linux_amd64.tar.gz describes the binary beside it. --- .../unreleased/Documentation-20260906-232000.yaml | 5 +++++ docs/compatibility-policy.md | 14 +++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 changes/unreleased/Documentation-20260906-232000.yaml diff --git a/changes/unreleased/Documentation-20260906-232000.yaml b/changes/unreleased/Documentation-20260906-232000.yaml new file mode 100644 index 00000000..a1c8b0fd --- /dev/null +++ b/changes/unreleased/Documentation-20260906-232000.yaml @@ -0,0 +1,5 @@ +kind: Documentation +body: 'The compatibility policy states current figures. It had gone stale in five places — 775 boto3 tests, 948 `auto-crud` operations, 4,496 hand-verified, 148 registered services of which 31 served nothing, and a 93/11 split of model-backed to hand-written services — and nothing caught it, because nothing reads the file: `cmd/devcloud/coverage_test.go` gates docs/coverage.md, README.md and docs/README.md against the live registry, and docs/compatibility-policy.md is not in that set. It now reads 1,144 tests, 5,193 `auto-crud`, 4,497 hand-verified, 205 registered with 4 serving nothing, and 193/12 — each taken from the gated page or measured, not restated. The document ships inside the release archive, so a stale figure there describes the binary beside it' +time: 2026-09-06T23:20:00.000000+09:00 +custom: + Issue: "150" diff --git a/docs/compatibility-policy.md b/docs/compatibility-policy.md index 31abe861..1734b342 100644 --- a/docs/compatibility-policy.md +++ b/docs/compatibility-policy.md @@ -75,9 +75,9 @@ appears, and every operation the CRUD engine serves is present and not filed as [`cmd/devcloud/fidelity_test.go`](../cmd/devcloud/fidelity_test.go). What no test can catch is an operation that never reaches the manifest at all, and that is -bounded rather than eliminated: for the 93 services with an in-tree Smithy model the operation +bounded rather than eliminated: for the 193 services with an in-tree Smithy model the operation universe comes from the model, so an operation losing its implementation reclassifies to -`unimplemented` instead of disappearing. For the 11 without one, the universe *is* what the +`unimplemented` instead of disappearing. For the 12 without one, the universe *is* what the providers serve, so the manifest lists no unimplemented tail for them — `modelBacked` on `GET /devcloud/api/fidelity` reports which is which. @@ -98,7 +98,7 @@ reading closely: - `Runtime`, `Handler` and `MemorySize` are not asserted at all, so they carry no promise even though today's response includes them. -That narrowness is the point: it is the promise the repo can actually keep. The suite — 775 tests +That narrowness is the point: it is the promise the repo can actually keep. The suite — 1,144 tests driving real boto3 clients — runs in CI on every push and again against the tagged commit before a release publishes, so breaking an assertion fails the build rather than depending on review discipline. Anything the suite does not assert rests on nothing but intent. Widening the promise @@ -108,20 +108,20 @@ means adding or strengthening assertions, and such contributions are welcome. Depending on any of the following will break, and breaking it is **not** a major-version event. -- **`auto-crud` response content.** 948 operations are served by the +- **`auto-crud` response content.** 5,193 operations are served by the [generic CRUD engine](crud-engine.md) at fidelity that is deliberately *plausible, not faithful*: store-backed responses echoing your input plus synthesized ids and ARNs, with no validation, no cross-resource integrity, no pagination correctness and no business logic. Their shape and content may change in any release. Use them to wire an SDK up, nothing more. -- **Hand-verified operations with no compatibility test.** Of 4,496 hand-verified operations, +- **Hand-verified operations with no compatibility test.** Of 4,497 hand-verified operations, only what the suite covers is promised. The rest are best-effort. - **Data durability.** Stores are local development stores. Several are in-memory and per-process; on-disk layouts under `data_dir` may change format between releases without a migration. Do not treat DevCloud as a database. - **`unimplemented` → served transitions.** An operation that returns an error today may start returning a response. This is additive, and ships in a minor release. -- **Service coverage.** New services may be added in a minor release. The 148 services registered - today are a floor, not a ceiling — and not a promise of depth either: 31 of them serve no +- **Service coverage.** New services may be added in a minor release. The 205 services registered + today are a floor, not a ceiling — and not a promise of depth either: 4 of them serve no operation and only decline cleanly. See [coverage.md](coverage.md). - **Error codes, HTTP status and message wording.** What *is* guaranteed for an `unimplemented` operation is that it **fails** — an AWS-shaped error, never a fabricated success. Which error From 76fdd8cd3b44150759d96289ce18d57c85b1ddf9 Mon Sep 17 00:00:00 2001 From: Sung-Kyu Yoo Date: Sun, 6 Sep 2026 17:10:31 +0900 Subject: [PATCH 3/3] chore: add the changelog fragment PR #149 shipped without Release notes come from Changie fragments, not commits, so a merged user-facing change with no fragment is a change that will not appear in the release. PR #149 corrected four false claims in the contributor and getting-started guides and added none. Found by the pre-flight review for v1.1.0. The existing checks cannot see this: RELEASE.md's checklist verifies that every fragment carries an issue number and that the unreleased directory is not empty, neither of which notices a change that never wrote one. --- changes/unreleased/Documentation-20260906-230000.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/unreleased/Documentation-20260906-230000.yaml diff --git a/changes/unreleased/Documentation-20260906-230000.yaml b/changes/unreleased/Documentation-20260906-230000.yaml new file mode 100644 index 00000000..02882f0d --- /dev/null +++ b/changes/unreleased/Documentation-20260906-230000.yaml @@ -0,0 +1,5 @@ +kind: Documentation +body: 'The contributor guide no longer asks for a build toolchain and a server the project does not need. docs/contributing.md listed SQLite3 development headers as a prerequisite and said `make test` runs with CGO enabled — the driver has been pure Go since v1.0.0, and the Makefile, every workflow and every pre-commit hook set `CGO_ENABLED=0`. It also said the compatibility suite needs a running DevCloud instance; the `devcloud_server` fixture starts one itself on a free port against a temporary data dir it removes afterwards, and the three env vars that override that (`DEVCLOUD_EXTERNAL`, `DEVCLOUD_BIN`, `DEVCLOUD_PORT`) are now documented. docs/getting-started.md advertised a Next.js frontend on port 3000 under Docker Compose, where the compose file has one service and that frontend lives in a separate repository. Documented for the first time alongside: the `clean`, `changelog` and `stats` Make targets, the pre-commit and golangci-lint setup, and the `/devcloud/api/fidelity` and `/devcloud/api/unrouted` admin routes' +time: 2026-09-06T23:00:00.000000+09:00 +custom: + Issue: "149"