Skip to content

Refuse extraction records that squash or rebase merges dropped from main - #4

Merged
anth-volk merged 4 commits into
mainfrom
claude/extraction-requires-merge-commits
Oct 20, 2026
Merged

anth-volk merged 4 commits into
mainfrom
claude/extraction-requires-merge-commits

Conversation

@anth-volk

@anth-volk anth-volk commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #3

tools/extract-from-calibration-diagnostics.sh exited 0 after a carry-over pull request had been squash-merged or rebase-merged, although merging its output then adds the carried-over commits a second time. This PR makes it refuse that case and documents that carry-over pull requests must be merged with a merge commit. It also corrects three README and workflow-comment inaccuracies from the same post-merge review of #2. Merging releases 0.3.1 (one fixed fragment; main released 0.3.0 with #9 after this PR was opened). Deployment stays off.

The bug and the fix

The script only checked git merge-base --is-ancestor <recorded extracted_commit> <new extraction> inside the output directory. A squash or rebase merge puts a carry-over's changes and updated tools/extraction-source.env on main under new commits, so main no longer contains the recorded extracted commit. Nothing checked that.

When a record exists, the script now requires the current directory to be a git work tree whose HEAD contains the recorded extracted commit. It checks this before creating the output directory or rewriting the record. If the check fails, it exits 1 and says that carry-over pull requests must be merged with a merge commit. The README's carry-over section now states the rule and a recovery: merge the squashed pull request's original head (pull/<number>/head) into the next carry-over branch with git merge -s ours, which records those commits as merged without changing any file. A test covers that recovery.

The tests now use merge-commit topology, as calibration-diagnostics does. git-filter-repo (--prune-degenerate auto) keeps a pull request's merge commit when the branch was up to date with main, and prunes it when main moved on meanwhile. The fixtures produce both cases. Re-run tests run from a collector checkout fixture: the first extraction's history plus a commit that adds the record, as #2 did. Carry-over branches land on main by merge commit, squash or rebase, the way GitHub's merge methods do.

Commits

Commit Red (before the change) Green
e983c99 Refuse an extraction record that is not in HEAD's history tests/test_extraction.py: 4 failed, 9 passed. The squash and rebase cases exited 0 with an empty "New since the last extraction" list, as in the reproduction. A record naming an unknown commit got the old message after the output directory was created. Running outside a git work tree exited 0. 13 passed
01dc2e9 List the CI quality script among the README's test commands tests/test_quality_check.py: 1 failed, 3 passed (bash tools/check-quality.sh missing from the README's Tests block) 4 passed
84e1c5d Describe finished deployment provisioning and the always-true main check none: README prose and a YAML comment only workflow and README tests (test_deployment_workflow.py, test_release_workflow.py, test_quality_check.py): 24 passed
56aaeae Merge main into this branch none: a merge with no conflicts. main's new commits (#9's Orrery projection and the 0.3.0 release) touch none of this PR's files except README.md, where git merged the two changes in separate sections. tests/test_extraction.py and tests/test_quality_check.py: 17 passed. bash tools/check-quality.sh passed; bash tools/check-changelog.sh: 0.3.0 -> 0.3.1

The merge-topology re-run test and the recovery test passed before the fix too. They guard the merge-commit path, which the old tests did not exercise. Before the fix, in the squash fixture, a merge of the re-run's output would have added Merge pull request #219, Document …, Test … and Apply event batches incrementally again.

Gates on each commit: uv sync --locked --dev, the touched test files plus test_collector_uses_store_vocabulary, bash tools/check-quality.sh, bash tools/check-changelog.sh (0.2.0 -> 0.2.1), and shellcheck 0.11.0 on tools/*.sh and scripts/*.sh. On the last commit, actionlint 1.7.12 too. CI runs the full suite.

Other corrections

  • README Tests section: lists bash tools/check-quality.sh, which runs both Ruff checks and bash -n over tools/ and scripts/, instead of the two Ruff commands. A test now requires every command in that block to be one the validation workflow runs.
  • README "Enabling deployment" (was "Deployment gate"): describes the provisioning as done and lists what remains, in order. First, carry over outstanding telemetry-service/ changes. Then stop calibration-diagnostics deploying the service through telemetry-service.yml. Then set COLLECTOR_DEPLOY_ENABLED.
  • README "Google Cloud access" and the Push workflow's header comment: the github.event_name == 'push' && github.ref == 'refs/heads/main' condition is always true, because the Push workflow runs only for pushes to main. It guards only against a later trigger change. The released 0.2.0 changelog entry is unchanged.

Environment variables (push.yaml changed: comments only)

No variable, secret, trigger or condition changed. For completeness, here is everything .github/workflows/push.yaml reads. I checked names only, read-only, and printed no values.

Variable Provider Wiring State
TELEMETRY_GCP_PROJECT_ID, TELEMETRY_GCP_REGION, TELEMETRY_ARTIFACT_REGISTRY_NAME, TELEMETRY_CLOUD_SQL_CONNECTION, TELEMETRY_RUNTIME_SERVICE_ACCOUNT, TELEMETRY_MIGRATION_SERVICE_ACCOUNT, TELEMETRY_SERVICE, TELEMETRY_MIGRATION_JOB, TELEMETRY_IMAGE_NAME, TELEMETRY_DATABASE_SECRET_NAME, TELEMETRY_MIGRATION_DATABASE_SECRET_NAME, TELEMETRY_JWT_SECRET_NAME, TELEMETRY_READ_SECRET_NAME, TELEMETRY_PRODUCTION_CLOUD_SQL_CONNECTION, TELEMETRY_PRODUCTION_SERVICE GitHub environment variables (staging, production) job-level env: through vars.* in deploy-staging and deploy-production, which declare environment: staging / production all 15 present in both environments
TELEMETRY_GCP_WIF_PROVIDER, TELEMETRY_GCP_DEPLOY_SERVICE_ACCOUNT GitHub environment secrets (staging, production) with: of google-github-actions/auth in both deployment jobs both present in both environments
COLLECTOR_DEPLOY_ENABLED GitHub repo variable if: of both deployment jobs unset (intended until the cutover)
APP_ID, APP_PRIVATE_KEY GitHub organization secrets with: of actions/create-github-app-token in versioning listed for this repo
DEPLOYMENT_ENVIRONMENT; IMAGE_URI, REVISION literals in the workflow; step outputs job env:; step env: defined in the file

Unverified by me: the microcosm-collector Workload Identity provider's attribute condition and the deployment service account's roles/iam.workloadIdentityUser binding. Reading them needs gcloud reauthentication, which is not possible non-interactively. They were verified read-only when #2 was provisioned. I also did not re-check that the variable values still equal calibration-diagnostics' values.

Merge methods (now enforced in the repository settings)

When this PR was opened, the repo settings and the "Protect main" ruleset still allowed squash and rebase merges. They have since been changed outside this PR. Checked read-only on 2026-10-20:

  • repo settings: allow_merge_commit: true, allow_squash_merge: false, allow_rebase_merge: false;
  • "Protect main" ruleset: allowed_merge_methods: [merge].

So GitHub now refuses to squash or rebase any pull request into main, carry-overs included. The script's check still matters: it catches a record that is not in HEAD's history for any other reason, such as running the script from a checkout other than main or a branch created from it, or a future change to these settings. This PR itself changes no settings or rulesets.

Status (2026-10-20)

  • Head 56aaeae: main (eac60d4, 0.3.0) merged in with a merge commit, because the branch was 5 commits behind. No conflicts.
  • CI on 56aaeae: Lint workflows, Check changelog fragment, verify / Test, lint, and build, and Required checks all passed.
  • Merge it before the next carry-over of telemetry-service/ (calibration-diagnostics#219), with a merge commit, the only method the repo now allows. Merging releases 0.3.1; with COLLECTOR_DEPLOY_ENABLED unset, nothing deploys.

🤖 Generated with Claude Code

anth-volk and others added 4 commits October 19, 2026 17:24
The extraction script checked only that the recorded extracted commit is an
ancestor of the new extraction, inside the output directory. It never checked
the collector checkout that will merge the output. The repo settings and the
main ruleset allow squash and rebase merges, and either one lands a carry-over
pull request's changes and updated record on main under new commits, without
the extracted commits themselves. A re-run then exited 0 and listed nothing
new, yet merging its output added the carried-over commits a second time.

When a record exists, the script now requires the current directory to be a
git work tree whose HEAD contains the recorded extracted commit, and refuses
before creating the output directory or rewriting the record otherwise. The
message says carry-over pull requests must be merged with a merge commit, and
the README documents the rule and a recovery (an `ours` merge of the squashed
pull request's original head).

The extraction tests now build calibration-diagnostics look-alikes whose
collector changes arrive through merge commits, both kinds the filter
produces (merges it prunes and merges it keeps), and land carry-over branches
on main by merge commit, squash and rebase. Re-run tests run from a collector
checkout, as the README does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI runs `bash tools/check-quality.sh`, which runs both Ruff checks and
syntax-checks every script in tools/ and scripts/. The README still listed
the two Ruff commands, so a developer following it skipped the shell syntax
checks that CI enforces. A test now requires every command in the README's
Tests block to be one that the validation workflow runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README listed the Workload Identity provider and the environment secrets
and variables as preconditions still to meet. They are provisioned: both
environments hold the 15 TELEMETRY_* variables and the 2 identifier secrets,
and the microcosm-collector provider and the deployment service account's
binding exist. The section now says so and lists only what remains, in order:
carry over outstanding telemetry-service changes, stop calibration-diagnostics
deploying the service, then set COLLECTOR_DEPLOY_ENABLED.

The README and the Push workflow's header comment also said the
`github.event_name == 'push' && github.ref == 'refs/heads/main'` condition
makes tag, pull request and other-branch runs skip deployment. The Push
workflow runs only for pushes to main, so the condition is always true and
only guards against a later change to its triggers. Both now say that. The
released 0.2.0 changelog entry is left as published.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in the Orrery projection (#9) and the 0.3.0 release. No conflicts;
none of main's new commits touch the extraction tool, its tests or the
push workflow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk merged commit 6017fda into main Oct 20, 2026
4 checks passed
@anth-volk
anth-volk deleted the claude/extraction-requires-merge-commits branch October 20, 2026 14:28
anth-volk pushed a commit that referenced this pull request Oct 27, 2026
Brings in #6 (the submission contract, released as 0.4.0), #4, #11 and #23.
No conflicts: README.md, pyproject.toml and uv.lock merged automatically, and
the consumed fragment changelog.d/artifact-submission-contract.added.md is
removed, leaving only this branch's artifact-intake.added.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extraction tool misses squash- and rebase-merged carry-over pull requests

1 participant