Settings exports merge line by line: no schema_hash line, a stamp entry per source

Merged
TE
17d ago
+717-48

Part of #21946 (deconflicting generated files). Two settings PRs could never merge, because each one rewrote two single lines: the source stamp schemas/settings-export/settings-schema.sources.sha256, which conflicted in 14 open PRs, and the schema_hash line of settings-schema.json, which was the whole conflict in 9 of the 12 PRs that conflict on that file.

What changes

  • settings-schema.json no longer commits schema_hash. The Rust owner (cmux-config) computes it when the schema loads, as SHA-256 of the compact rows JSON. settings.schema, the config snapshot and the editor JSON Schema still report it. It was only ever an opaque version id, and no client compares it with a Swift-computed value; the Swift page provider already sends "".
  • The stamp is now one sha256 path entry per CmuxNextSettings source and per export test, with a blank line between entries. PRs that edit different sources then change lines that git merges cleanly, and the merged stamp is exactly the stamp of the merged sources. check-fresh now names the files that moved instead of printing two digest prefixes.
  • SettingsSchemaExportTests writes that format, and defaults_guard.py computes it without a Swift build. The defaults approval guard still reads each PR's committed schema, and no workflow files change.

Tests (failing commit first)

  • tests/test_defaults_guard.py SettingsExportStampTests: a fresh manifest passes; an edited, added or removed source fails and is named; an old one-digest stamp fails; two branches that edit different sources merge with plain git merge into a stamp that check-fresh accepts; --ref behaves like a checkout.
  • cmux-config/tests/schema_hash.rs: a document without schema_hash parses, the hash moves with the rows and only with the rows, and the committed export has no hash.

Verified on Linux: cargo test/clippy -D warnings/fmt for cmux-config, all 28 guard tests, vp check, and the webviews settings tests (129 pass). I couldn't build Swift here, so Mac CI (action exports) is the compile and export check for the two Swift files. If the export bot rewrites the stamp, it should produce byte-for-byte what the guard computes.

After merge: each open settings PR gets one last stamp conflict, which the autofix bot or the fleet export resolves. After that, settings PRs that touch different files merge cleanly.

Red, then green: at the test commit, tests/test_defaults_guard.py fails 5 of 28 and cargo test -p cmux-config --test schema_hash fails 3 of 3. At the head, 28/28 and 3/3 pass. After merging the current base, defaults_guard.py check-stamp passes on the regenerated stamp. cmux-tui-core needs the ghostty submodule, so CI runs its config tests.

Limit: two settings PRs that both edit the same source file still conflict on that file's stamp entry. The most common case is CmuxNextSettings/Localizable.xcstrings. On the 14 PRs that conflicted on the stamp, only 2 changed a source file the base also changed.

Stale exports after a merge (coord-2 review). A stamp that merges by line matches the merged sources, while settings-schema.json and docs/mdm (cmux-generated-v1) keep one side's copy. So check-fresh would have called stale exports fresh. The stamp now takes the same driver:

  • Clones with the repo's drivers (the bots, a lane's local merge): merging two settings branches keeps one stamp, and check-fresh fails and names the other side's sources until the exports are regenerated. next_batch rebuilds the stamp along with the other Swift exports.
  • GitHub: it ignores drivers, so PRs still merge there by line. Afterwards the base autofix regenerates the exports, as it does on every push that changes CmuxNextSettings.
  • Rejected alternative: embedding a hash of the stamp in the exports would bring back a single line that every settings PR changes.
  • Tests: test_a_clone_with_the_merge_drivers_keeps_one_stamp_so_check_fresh_fails was committed red first (check-fresh returned 0 on stale exports) and is green at the head. Guard tests 29/29 and test_install_git_hooks.py pass.

Changelog

none

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Makes settings PRs mergeable (part of #21946): settings-schema.json no longer commits schema_hash, and the source stamp is now one sha256 path entry per CmuxNextSettings source and export test, so PRs editing different sources merge cleanly on GitHub.

  • cmux-config computes schema_hash at load as SHA-256 of the rows, so consumers like the config snapshot and editor JSON Schema still get one.
  • check-fresh names the files that moved instead of printing two digest prefixes and rejects a legacy one-digest stamp; new tests cover edited, added and removed sources, legacy stamps, and git merge of branches touching different files.
  • The stamp takes the cmux-generated-v1 merge driver: a merge in a configured clone keeps one stamp and fails check-fresh until exports regenerate, instead of a line-merged stamp calling the one-side exports fresh. GitHub ignores drivers, so PRs still merge there by line and the base autofix regenerates the exports.
  • The merged base's exports and schema are current, including its rows and the dropped hash line.

After this lands, each open settings PR needs one last stamp conflict resolution; afterwards settings PRs touching different files merge cleanly. A stamp that still conflicts after a merge should be regenerated, never hand-merged.