[ka:cli-build-out] ka-promote: implement resolver + cumulative + manifest.lock (closes #22) #23

Merged
marfrit merged 2 commits from claude-noether/kernel-agent:noether/ka-promote into main 2026-05-18 08:57:15 +00:00
Owner

Summary

Implements ka-promote, the first of three CLI verbs for kernel-agent (umbrella #21). Closes #22.

Resolves fleet/<host>.yaml → emits cumulative.patch + manifest.lock. Replaces the manual "concat patches into a cumulative" step that has been in the README as a "manual substitute" since 2026-05-09.

Phase-by-phase work in #22 comments:

  • Phase 0 substrate (#22 1124): two include shapes (single-file, series-dir); series-dirs exclude 0000-cover-letter.patch.
  • Phase 1 metric (#22 1125): byte-identical cumulative tree-state vs iterative apply.
  • Phase 2 parity host (#22 1126): fresnel first, ampere second.
  • Phase 3 baseline (#22 1127): empirically verified plain cat patches/*.patch | git apply reproduces iterative-apply tree state (no git format-patch needed).
  • Phase 4 plan (#22 1132): CLI surface, resolver pseudocode, manifest.lock schema.
  • Phase 5 review (#22 1135, sonnet outside-look): green with 5 followups — all addressed.
  • Phase 6 implement (#22 1141): 264 LoC python3 + 138 LoC test runner + 4 fixture YAMLs.
  • Phase 7 verify (#22 1152): both parity hosts byte-equal; multi-scope ampere (4 scopes, 7 patches) and flat fresnel (1 scope, 6 patches).

What ships

File Purpose
bin/ka-promote the verb
tests/ka-promote/run-tests.sh + fixtures/*.yaml 5 tests (parity, series-dir, bad-include, missing-patch, dup-include)
.gitignore excludes build/ and python cruft
fleet/fresnel.yaml baseline.tree mmind/linux-rockchip → torvalds/linux (mmind ships no plain v7.0 tag)
README.md CLI verb table updated; ka-promote marked implemented; ka-import is the new name for the original "promote patches into tree" semantic (still unimplemented); Bootstrap reference build section reframed

Test plan

  • tests/ka-promote/run-tests.sh runs all 5 tests, all PASS (verified on noether)
  • ka-promote fresnel b2sum matches Phase-3 ground truth bit-for-bit
  • ka-promote ampere b2sum matches independently-derived hand-cat b2sum on boltzmann
  • ka-promote fresnel --validate-against ~/src/linux-v7.0-worktree exits 0 on clean checkout
  • --validate-against exits 3 on dirty worktree
  • --validate-against exits 3 on tree-divergent HEAD
  • --validate-against exits 0 on HEAD-divergent-but-tree-identical (empty commit)
  • ka-promote --list-hosts / --version smoke OK

Follow-ups (not in scope)

  • ka-build (issue TBD): render PKGBUILD template, makepkg invoke.
  • ka-install (issue TBD): scp + pacman -U + extlinux/mkinitcpio + heartbeat.
  • ka-import (issue TBD): the original "promote patches from campaign into scope-tagged tree" semantic.
  • ohm migration (#5) paused while BESser is iterating on ohm.

Closes #22 (ka-promote verb).
Tracked by #21 (CLI build-out umbrella).

## Summary Implements `ka-promote`, the first of three CLI verbs for kernel-agent (umbrella #21). Closes #22. Resolves `fleet/<host>.yaml` → emits `cumulative.patch` + `manifest.lock`. Replaces the manual "concat patches into a cumulative" step that has been in the README as a "manual substitute" since 2026-05-09. Phase-by-phase work in #22 comments: - Phase 0 substrate (#22 1124): two include shapes (single-file, series-dir); series-dirs exclude `0000-cover-letter.patch`. - Phase 1 metric (#22 1125): byte-identical cumulative tree-state vs iterative apply. - Phase 2 parity host (#22 1126): fresnel first, ampere second. - Phase 3 baseline (#22 1127): empirically verified plain `cat patches/*.patch | git apply` reproduces iterative-apply tree state (no `git format-patch` needed). - Phase 4 plan (#22 1132): CLI surface, resolver pseudocode, manifest.lock schema. - Phase 5 review (#22 1135, sonnet outside-look): green with 5 followups — all addressed. - Phase 6 implement (#22 1141): 264 LoC python3 + 138 LoC test runner + 4 fixture YAMLs. - Phase 7 verify (#22 1152): both parity hosts byte-equal; multi-scope ampere (4 scopes, 7 patches) and flat fresnel (1 scope, 6 patches). ## What ships | File | Purpose | |---|---| | `bin/ka-promote` | the verb | | `tests/ka-promote/run-tests.sh` + `fixtures/*.yaml` | 5 tests (parity, series-dir, bad-include, missing-patch, dup-include) | | `.gitignore` | excludes `build/` and python cruft | | `fleet/fresnel.yaml` | baseline.tree mmind/linux-rockchip → torvalds/linux (mmind ships no plain v7.0 tag) | | `README.md` | CLI verb table updated; `ka-promote` marked implemented; `ka-import` is the new name for the original "promote patches into tree" semantic (still unimplemented); Bootstrap reference build section reframed | ## Test plan - [x] `tests/ka-promote/run-tests.sh` runs all 5 tests, all PASS (verified on noether) - [x] `ka-promote fresnel` b2sum matches Phase-3 ground truth bit-for-bit - [x] `ka-promote ampere` b2sum matches independently-derived hand-cat b2sum on boltzmann - [x] `ka-promote fresnel --validate-against ~/src/linux-v7.0-worktree` exits 0 on clean checkout - [x] `--validate-against` exits 3 on dirty worktree - [x] `--validate-against` exits 3 on tree-divergent HEAD - [x] `--validate-against` exits 0 on HEAD-divergent-but-tree-identical (empty commit) - [x] `ka-promote --list-hosts` / `--version` smoke OK ## Follow-ups (not in scope) - `ka-build` (issue TBD): render PKGBUILD template, makepkg invoke. - `ka-install` (issue TBD): scp + pacman -U + extlinux/mkinitcpio + heartbeat. - `ka-import` (issue TBD): the original "promote patches from campaign into scope-tagged tree" semantic. - ohm migration (#5) paused while BESser is iterating on ohm. Closes #22 (ka-promote verb). Tracked by #21 (CLI build-out umbrella).
marfrit added 2 commits 2026-05-18 08:54:46 +00:00
First of the three [ka:cli-build-out] verbs (umbrella #21). Reads
fleet/<host>.yaml, resolves includes[] (single-file + series-dir),
concatenates in apply order, emits build/<host>/<ref>/{cumulative.patch,
manifest.lock}. Phase-3 ground truth on fresnel parity: b2sum
4d9d93c655ea701b… matches bit-for-bit.

Five tests in tests/ka-promote/ (fresnel parity, series-dir resolver,
bad-include, missing-patch, dup-include) all pass.

Validator (--validate-against <linux-checkout>) hard-fails on: missing
.git, baseline.ref not in checkout, HEAD-tree != baseline.ref tree,
or uncommitted/untracked changes. Verified on boltzmann against the
torvalds v7.0 worktree (all 3 negative paths exit 3 with clear errors).

Side fix: fleet/fresnel.yaml baseline.tree mmind/linux-rockchip → torvalds/linux.
mmind doesn't ship a plain v7.0 tag; baseline was actually torvalds the
whole time. mmind kept as informational patch_authoring_context.

Phase-5 reviewer (sonnet outside-look, #22 comment 1135) followups
addressed: series-dir fixture count 7 (not 6), divergence = hard error,
raw-bytes manifest hash, duplicate-include pre-flight check, explicit
yaml.dump(sort_keys=True).

Language choice (vs ka-status's bash): pure python3 — YAML round-trip,
dict construction, and per-file hashing made bash+heredoc python quoting
hell with no readability gain.

Phase 7 (verify on ampere parity) + Phase 8 (close + README rewrite +
PR) to follow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CLI verb table updates:
- ka-promote: new signature `<host>` (read fleet/<host>.yaml → cumulative.patch +
  manifest.lock). Marked [bin/ka-promote — implemented Phase 6, issue #22].
- ka-import: new verb name carrying the original ka-promote semantic
  (`<campaign> <patch-or-glob> --to <scope>`, promote patches into the
  scope-tagged tree). Unimplemented; today this is the regular git+PR workflow.
- ka-build / ka-install: signatures elaborated, marked as the next two verbs
  to implement (issues TBD).

Bootstrap reference build section:
- Header reframed: "before ka-* verbs existed" → ka-promote replaces step #1
  as of 2026-05-18.
- Baseline corrected: torvalds/linux not mmind/linux-rockchip (mmind doesn't
  ship plain v7.0 tag — caught in ka-promote Phase 3, fleet/fresnel.yaml fixed
  in the implementation commit).
- "Manual substitute" table gets a Status column. Row for ka-promote split
  into the old "import" semantic vs the new "manifest resolve" semantic, with
  the latter marked **automated 2026-05-18**.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
marfrit merged commit 44c6c3fa4f into main 2026-05-18 08:57:15 +00:00
Sign in to join this conversation.