From cc15bdd1d924ffcfdec0f8793085190cb7bcbe9b Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 3 Sep 2026 22:30:02 +0200 Subject: [PATCH 1/6] Run the merge gate only for changes its tests read --- .github/workflows/test.yml | 18 +++++++++++++++++- README.md | 12 +++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 04fcf19..03ccd42 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,12 +16,28 @@ jobs: - uses: actions/checkout@v6 with: persist-credentials: false + fetch-depth: 0 + - name: Relevant changes + id: changes + run: | + if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then + git fetch --no-tags origin "$GITHUB_BASE_REF" + base="origin/$GITHUB_BASE_REF" + else + base="HEAD^" + fi + if git diff --quiet "$base"...HEAD -- '*.go' go.mod go.sum Dockerfile .dockerignore .github data README.md; then + echo "code=false" >> "$GITHUB_OUTPUT" + else + echo "code=true" >> "$GITHUB_OUTPUT" + fi # `docker build` streams the context to the daemon. A compose bind-mount of # `.` mounts an empty host dir instead, because the job is itself a container. - name: Latest supported Go + if: ${{ steps.changes.outputs.code == 'true' }} run: docker build . # Runs even when the step above failed, so a red build says whether the # failure is version-specific. - name: Lowest supported Go - if: ${{ !cancelled() }} + if: ${{ !cancelled() && steps.changes.outputs.code == 'true' }} run: docker build --build-arg GO_VERSION=1.22.12 . diff --git a/README.md b/README.md index ab1d65d..727c6c3 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,13 @@ tokens add cost in proportion to the output. almost always costs an allocation too (a lost pre-size, a per-item map, an extra copy). The benchmark suite (see Development) reports time for a human, not as a pass/fail gate. +- **The gate runs only when something it consumes changes.** A PR that touches + none of the Go and module files, the Dockerfile, `.dockerignore`, the + workflow, the shipped data nor the README skips `docker build` and passes + as-is — those are what the build feeds or the tests read (`data_test.go` and + `loading_test.go` load `data/`, `readme_test.go` renders every README + example), so any other change is a verdict already decided, and waiting would + be idle. The check still reports success, so the merge gate stays whole. ## Development @@ -485,7 +492,10 @@ docker compose run --rm --user "$(id -u):$(id -g)" tidy # go mod tidy Every pull request runs `docker build .` against both the latest and the lowest supported Go, and must pass before it can be merged. That build is the whole -gate — vet, complexity, format check and tests — so run it locally before pushing: +gate — vet, complexity, format check and tests — so run it locally before pushing. +A PR that touches none of the Go and module files, the Dockerfile, +`.dockerignore`, the workflow, the shipped data nor the README skips the build +and passes as-is (see [Decisions](#decisions)): ```sh docker build . # latest From 2d282208690f2a10d9f387d6d5d4f88eb907d2c0 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 3 Sep 2026 22:36:48 +0200 Subject: [PATCH 2/6] Diff the whole push range and de-duplicate the gate-skip note --- .github/workflows/test.yml | 2 +- README.md | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 03ccd42..d6336ba 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: git fetch --no-tags origin "$GITHUB_BASE_REF" base="origin/$GITHUB_BASE_REF" else - base="HEAD^" + base='${{ github.event.before }}' fi if git diff --quiet "$base"...HEAD -- '*.go' go.mod go.sum Dockerfile .dockerignore .github data README.md; then echo "code=false" >> "$GITHUB_OUTPUT" diff --git a/README.md b/README.md index 727c6c3..e0ccb1b 100644 --- a/README.md +++ b/README.md @@ -491,11 +491,10 @@ docker compose run --rm --user "$(id -u):$(id -g)" tidy # go mod tidy ``` Every pull request runs `docker build .` against both the latest and the lowest -supported Go, and must pass before it can be merged. That build is the whole -gate — vet, complexity, format check and tests — so run it locally before pushing. -A PR that touches none of the Go and module files, the Dockerfile, -`.dockerignore`, the workflow, the shipped data nor the README skips the build -and passes as-is (see [Decisions](#decisions)): +supported Go, and must pass before it can be merged — unless it touches none of +the files the build and its tests read, in which case it's skipped (see +[Decisions](#decisions)). That build is the whole gate — vet, complexity, format +check and tests — so run it locally before pushing: ```sh docker build . # latest From 19aae8bbfe72e6bb05dd2364cccfe1d2a1197e39 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Thu, 3 Sep 2026 22:40:31 +0200 Subject: [PATCH 3/6] Name the workflow in the gate-skip note --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e0ccb1b..fae61c0 100644 --- a/README.md +++ b/README.md @@ -491,10 +491,10 @@ docker compose run --rm --user "$(id -u):$(id -g)" tidy # go mod tidy ``` Every pull request runs `docker build .` against both the latest and the lowest -supported Go, and must pass before it can be merged — unless it touches none of -the files the build and its tests read, in which case it's skipped (see -[Decisions](#decisions)). That build is the whole gate — vet, complexity, format -check and tests — so run it locally before pushing: +supported Go, and must pass before it can be merged — unless it changes none of +the files the build and its tests read, nor the workflow itself, in which case +it's skipped (see [Decisions](#decisions)). That build is the whole gate — vet, +complexity, format check and tests — so run it locally before pushing: ```sh docker build . # latest From 314ba49b9d4e0bc599c4b889b2c751290c19b3ee Mon Sep 17 00:00:00 2001 From: lilleman Date: Thu, 3 Sep 2026 23:05:27 +0200 Subject: [PATCH 4/6] README redaction --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index fae61c0..c1b21da 100644 --- a/README.md +++ b/README.md @@ -460,13 +460,6 @@ tokens add cost in proportion to the output. almost always costs an allocation too (a lost pre-size, a per-item map, an extra copy). The benchmark suite (see Development) reports time for a human, not as a pass/fail gate. -- **The gate runs only when something it consumes changes.** A PR that touches - none of the Go and module files, the Dockerfile, `.dockerignore`, the - workflow, the shipped data nor the README skips `docker build` and passes - as-is — those are what the build feeds or the tests read (`data_test.go` and - `loading_test.go` load `data/`, `readme_test.go` renders every README - example), so any other change is a verdict already decided, and waiting would - be idle. The check still reports success, so the merge gate stays whole. ## Development From b17106afab4e6c7c7a520213f269c7fa2fe90dbf Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sat, 5 Sep 2026 12:12:58 +0200 Subject: [PATCH 5/6] Record the release checklist and the later data de-duplication --- .gitignore | 3 +-- todo.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 todo.md diff --git a/.gitignore b/.gitignore index 28f4f54..5995de4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .claude *.out -__pycache__/ -todo.md \ No newline at end of file +__pycache__/ \ No newline at end of file diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..e38f182 --- /dev/null +++ b/todo.md @@ -0,0 +1,28 @@ +# Release checklist + +What to settle before the first tag, then the work that follows in a later, +data-heavy release. + +## Before the first release — settle the record flag and API contract + +- `--format` vocabulary — confirm `text`, `json`, `ndjson`, `csv`, `sql`; the + `json`-as-array vs `ndjson`-as-lines split; `--table` (the SQL INSERT target); + the `--separator` rejection on record formats; and the exit codes (misuse 2, + runtime 1). +- Library surface — confirm `Record`, `FakeRecord`, `NewRecordTemplate`, + `RecordTemplate`, `Column`/`Columns()`, and the `JSON()`, `CSVHeader()`, + `CSVLine()`, `SQLInsert()` serializers. +- Typed scalars — columns are strings today (`"42"`, quoted SQL). Confirm that + stays out of scope, or add a per-column `kind` before the tag. +- Struct-filling — `fake:"..."` tags (reflection over an arbitrary struct) stay + out of scope; `Columns()` hands the caller the values to map themselves. + Confirm. +- Independent reference draw — within one record every tailed reference to a + category is one draw, with no spelling for "these columns should disagree". + Confirm the per-record contract, or add the spelling. + +## Later, in a data-heavy release + +- Shipped-data de-duplication — `email.json`'s `local` is a drifted copy of + `username.json`; fold it in when the shipped set grows and we add lots more + data. From 5d981a7304ec9f106b2530193a2e33544b4c431f Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sat, 5 Sep 2026 15:30:02 +0200 Subject: [PATCH 6/6] Drop the deferred section, superseded by todo.md --- AGENTS.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 75d511e..28cf18d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,11 +8,3 @@ - A standing choice a reader would relitigate goes under Decisions in the README, not in a comment. - A README example is a `json` block that loads and renders as a category; `readme_test.go` runs every one. - Cyclomatic complexity is gated at 14: the table-shaped dispatches (`eachToken`, `calc.factor`, `walkPath`) sit at 13–14 and stay whole; anything else that reaches 14 is decomposed. - -# Deferred - -- **Shipped-data de-duplication (2026-09-02).** `email.json`'s `local` is a - drifted copy of `username.json`, and no shipped file yet uses a held path, an - operand or a reference. Fixed in the data fill before the first tag, when the - shipped set is rewritten anyway; premise: nothing depends on the shipped data's - shape until then. Not raised in review before that.