Plans index¶
This page summarises every planning document in chronological order. Master plans decompose work into numbered phases, each with its own detailed plan file. Standalone plans track issues, follow-ups, or design decisions that do not require phased execution.
New plans should follow the structure in PLAN-TEMPLATE.md at the
repo root. For pre-push audits of our own work see
PUSH-AUDIT.md.
Master plans¶
| Date | Plan | Intent | Status | Phases |
|---|---|---|---|---|
| 2026-06-02 | Automated SPICE test harness | End-to-end SPICE test harness driving Uncalibrated Sextant via Ryll's control socket, with assertions against the visual digest and serial drain; replaces the OpenStack-dependent integration tests with a direct qemu/KVM lane | Complete | phase 1 (done), phase 2 (done), phase 3 (done), phase 4 (done), phase 5 (done), phase 6 (done), phase 7 (done), phase 8 (done) |
| 2026-07-04 | Rust SPICE proxy (kerbside-proxy) | Replace the Python SPICE proxy with a Rust kerbside-proxy that talks tonic/gRPC over a UDS to the Python daemon, reuses ryll's shakenfist-spice-protocol crate, enforces L0+L1 firewall policy from day one, and ships inside the kerbside pip install via a maturin bin wheel | Complete | phase 1 (done), phase 2 (done), phase 3 (done), phase 4 (done), phase 5 (done), phase 6 (done), phase 7 (done), phase 8 (done) |
| 2026-07-16 | Consistency audit compliance | Clear the backlog of open consistency issues filed by the daily shakenfist/development audit: four missing shared blocks in PUSH-AUDIT.md and PLAN-TEMPLATE.md, a vendored sfui copy two commits behind canonical, the retired comment addresser still deployed with contents: write on the pull request branch, and 70 files needing human review against a threshold of 5. Surveyed 2026-08-29: two of the six findings did not survive contact with the tree -- skillsaw does run in CI and the audit's own checker is what is wrong, and the review backlog is 70 files rather than the 152 the issue claims. Promoted from a standalone plan that tracked only two GitHub settings checkboxes |
In progress | phase 1 (planned and implemented 2026-08-29 -- the four shared blocks, the sfui stamp, and the settings closeout. audit-check.py against the branch goes from 6 failures to 3, leaving only phases 2-4. Two corrections landed during implementation: the plan had two block placements backwards, caught because the brief told the agent to read each block before placing it, and the master plan's own Execution table put Merged in the middle when the block it was adopting requires it last. The research step also killed the plan's assumption that the github-security audit covers the three settings ticked by hand in July: it does not check Dependabot at all, and returns pass when its API call fails), phase 2 (not started -- retire the comment addresser), phase 3 (not started -- skillsaw CI detection, lands in shakenfist/development), phase 4 (not started -- review coverage backlog), phase 5 (not started -- push audit) |
| 2026-07-17 | Backend host_subject enforcement | Restore hypervisor certificate subject pinning on the proxy's backend TLS leg, lost in the Rust proxy cutover: enforce spice-common host-subject matching semantics in ryll's shakenfist-spice-protocol verifier, adopt it in kerbside, and prove both accept and refuse paths in the direct-qemu CI lane | Complete | phase 1 (done, ryll PR #166), phase 2 (done, kerbside PR #114) |
| 2026-07-19 | Shaken Fist VDI console tokens | Cross-repo plan (master in shakenfist's docs/plans/): per-instance console authorisation via short-lived Ed25519-signed tokens minted by Shaken Fist and validated offline by kerbside; kerbside side adds an /sf-console.vv exchange endpoint mirroring the Nova flow, a jti replay table, cluster-wide scraping, and host_subject for SF consoles |
Complete | phase 5 (done), phase 6 (done), phase 7 (done, SF mint-path test; kerbside exchange lane moved to phase 9), phase 8 (done), phase 9 (done, lane green 2026-07-31, run 30608314535) — post-merge cross-repo e2e + kerbside exchange lane |
| 2026-08-02 | Two-tier CI | Adopt the shakenfist/shakenfist two-tier CI flow: smoke gates (sanity, direct-qemu, Rust, single-node sf-e2e) on PRs; oVirt and Kolla/OpenStack move to a merge-queue tier; fix the oVirt lane to actually deploy kerbside; record the oVirt front-door architecture decision | Complete | phase 1 (done), phase 2 (done, promoted on four green nightlies), phase 3 (done, queue live 2026-08-09; first entry caught a real failure), phase 4 (done) |
| 2026-08-08 | Convert the admin UI to sfui | Make kerbside the second sfui consumer: vendor sfui into the static assets, rebuild the six templates on tokens and sfui components (theme toggle, tab-strip nav, brand chrome, details disclosures, morphdom polling), drop Bootstrap/jQuery/axios, fix the accumulated markup defects, and add template smoke tests; resolves #244 and #133 | Complete | phase 1 (done), phase 2 (done), phase 3 (done), phase 4 (done), phase 5 (done — consoles page: disclosures, flattened connect actions, two-step terminate, inline theme-aware icons; sfui gained the .sf-btn underline suppression), phase 6 (done — sessions/sources/audit pages: disclosure-panel accordion, CA cert disclosure, total_events footnote, shared two-step terminate include; all five pages now on base-sfui.html, template-only phase), phase 7 (done — meta refresh replaced by a 30s fetch-and-morph poll with an onBeforeElUpdated hook preserving open disclosures and the armed terminate button; failed polls pin a stale-since stamp instead of reloading), phase 8 (done — both terminate routes are POST behind the X-CSRF-TOKEN double-submit header, with a SameSite=Lax cookie covering the one destructive GET that cannot convert; the survey found two CI callers the master plan missed, cleared two it named in error, and split that remaining GET out as #319), phase 9 (done — teardown: 47 files and 8.4 MB of Bootstrap, jQuery, axios and logo.svg deleted along with the base.html nothing extended, base-sfui.html renamed into place, the pre-commit and review-scope exclusions pruned, and a StaticAssetReferenceTestCase added so a dangling /static/ reference fails the unit tests. The deletion and the rename were split into two commits, against the plan, because doing both to one path in one commit made git record a delete plus a modify rather than a rename; the survey also missed tools/preview-templates.py as a live reference. #244 is closed by hand, with a comment drafted in the phase plan) |
| 2026-08-14 | A working installation path: the compose demo | docs/installation.md stops at acquisition, so a reader who follows it has software and no running system: it never mentions the two processes, the database, the TLS material, or a console source. Package the migrations and add kerbside db upgrade (a wheel install currently cannot create its own schema), write the missing etc/kerbside.conf.example, build a docker compose demo with a CI lane, and rewrite the page around it; resolves #3 |
Complete | phase 1 (done 2026-08-14 — migrations moved into the package, kerbside db upgrade/downgrade and kerbside demo token added; verified from an installed wheel run outside any checkout. Fixed two logging defects found on the failure path, including alembic's env.py disabling every kerbside logger), phase 2 (done 2026-08-15 — etc/kerbside.conf.example covers all 34 Config fields, 8 live and 26 commented at their defaults, with no value that would work if pasted; tests pin coverage in both directions and the environment-beats-INI precedence that nothing previously held, both demonstrated to fail before being trusted. Verified from the real /etc/kerbside/kerbside.ini path in a container. Found and filed #313: a malformed INI exits zero, and percent-encoded database passwords reach it through configparser interpolation), phase 3 (done 2026-08-16 — demo/ brings up MariaDB, a disk-less qemu SPICE target and kerbside under one docker compose up; verified end to end with remote-viewer over TLS, every socket on 5900 and none on 5901, with the CA travelling in the .vv. The survey caught a qemu invocation that fails on QEMU 10, which the image then confirmed at 10.0.11; implementation found three more: the then-current release predated kerbside db upgrade so the install source defaulted to the checkout until v0.5.0 shipped it, Debian trixie keeps SPICE in qemu-system-modules-spice, and docker compose exec inherits nothing the entrypoint exported), phase 4 (planned 2026-08-17 — an advisory, path-filtered lane bringing the compose stack up against the PR and asserting a proxied SPICE session. The survey rewrote the draft: every one of its five line citations now points at unrelated content, its ryll feature-flag claim is backwards, its four-step proxy-wheel recipe is one step calling a script that did not exist when it was written, and #314 removed the reason for the cargo build entirely — the dev-inclusive floor in pyproject.toml resolves kerbside-proxy 0.5.1.dev1 from PyPI on its own. Also found that no kerbside workflow uses Docker at all, so this would be the first container build in CI and the phase now leads with a runner probe; and that renovate had just bumped the demo database a major version untested, which the survey verified by hand. Done 2026-08-18 — the lane brings the stack up against the pull request in 4.5 minutes and asserts 11 things about it, including that the session crossed the TLS port and not the plaintext one (5900=12, 5901=0, matching phase 3's manual count). The probe earned its place: the runner image had no docker at all, and Debian 12 supplies neither a new enough engine nor a docker compose v2 plugin, so the lane installs from Docker's own repository in 12 seconds. Review then found three real defects, every one an assertion that reported the wrong thing — set -e had made the hang branch dead code and silently skipped everything after it, the TLS-port check was a startup-log tautology that passed whenever the proxy merely started, and the docker short-circuit skipped the proxy configuration it existed to apply; testing those fixes found three more of the same family. Also caught and fixed a MariaDB root password reaching a downloadable CI artifact, from the redaction step that ran before log collection and so could never have scrubbed it. One item was deferred to phase 5 and is now settled: PR #351 demonstrated both directions of the path filter -- no run while it held only the planning commit, a run within seconds of docs/installation.md joining the diff), phase 5 (done 2026-08-22 — docs/installation.md now runs from pip install to a proxied console, via the two-process model, kerbside db upgrade, the TLS material and the eight settings with no useful default, then the compose walkthrough, then a handoff to docs/use-cases/. Running every command from a clean clone found four defects the prose had wrong, two of them mine: docker compose ps does not print the columns claimed, ss without -H counts its own header so the socket split read 13/1 rather than 12/0, pip install does not give you demo/ so the walkthrough now starts with the clone, and remote-viewer was never installed anywhere. Review then caught a fifth, and it was the load-bearing one: the page put pip install before the OS packages it depends on, which a container test confirmed cannot work — mysqlclient ships no wheel, so a clean pip install kerbside dies in pkg-config. Verifying the fix found that bindep.txt was itself incomplete, missing python3-dev/python3-devel, so tox -e bindep would have reported the dependency list complete while an install from it still failed in gcc; confirmed on both debian:trixie and rockylinux:10 and fixed here. Also closed phase 3's inbound-link gap in README.md, docs/index.md and ARCHITECTURE.md. Planned 2026-08-16, re-surveyed 2026-08-22 before implementation because the draft predated phase 4's completion. Phases 1-3 hold and nothing links inward to demo/ yet, as phase 3 review said; but the page had grown 16 lines from another plan's docs pass that the rewrite must preserve, four of the draft's line citations had rotted, the docs/index.md ordering question was already settled, and phase 4's deferred checkbox — proving the demo-compose path filter does not fire for docs outside installation.md — was missing from the draft entirely and is now step 5e, takeable only while the pull request holds the planning commit alone. The conf-example rename and the .claude/CLAUDE.md row are both decided against rather than left open) |
| 2026-08-14 | Rolling kerbside-proxy dev releases | Publish PEP 440 dev releases of the kerbside-proxy wheel to PyPI when the binary's inputs change (path-filtered: rust/**, kerbside.proto), commit a dev-inclusive version specifier so unreleased git installs (notably upstream Kolla image builds) resolve a working binary with no upstream kolla changes, and add a proto-hash contract handshake between daemon and binary as the skew backstop | Complete | phase 1 (done, PR #314), phase 2 (done, PR #314), phase 3 (done, PR #314 — committed proto-hash constant, --contract-hash flag, startup refusal with KERBSIDE_SKIP_CONTRACT_CHECK escape hatch), phase 4 (docs done in PR #314; bootstrap wheel 0.4.1.dev184 published 2026-08-17 once the operator registered the trusted publisher, and the committed floor was verified against the live index to resolve it with no pre-release opt-in. Tail: 4b (patch175 simplification) withdrawn 2026-08-18 after measurement showed the fallback it would delete is inert — kolla's install_pip always passes --upgrade, which does not downgrade the newer dev wheel the committed floor already installed; the Gerrit recheck (4c) completed 2026-08-29 with every Gerrit review passing Zuul CI), phase 5 (done, PR #328 — survey found publishing denser than the master plan assumed, ~365 dev releases/year with 76% of triggers being Renovate dependency bumps. PyPI has no delete/yank API for any credential (Warehouse #12810 open and blocked), so this automates the watching rather than the deleting: a weekly credential-free storage monitor that files a tracking issue, Cargo.lock dropped from the publish trigger, and a manual pruning runbook), phase 6 (done 2026-08-29 — no critical, high or blocking findings. PUSH-AUDIT.md over the accumulated diff of phases 1-3, 4a and 5: 14b54f3^1..2e1fd43 scoped to the 40 paths those phases touched, 4,040 insertions. Survey found both audit scripts hard-code DIFF_BASE=develop, not just wave1.sh as the master plan said, so an unmodified run is a vacuous pass; that the Rust half of the range has no mechanical coverage at all; and one known wave-1 false positive, the two print() calls in tools/check-pypi-storage.py. The tooling step also caught wave 1's two fatal style checks never having inspected a line: a BRE grep -v '^\+\+\+' matched every added line rather than the diff headers, so $ADDED was empty for any diff at all. The audit produced five fixes — one correctness bug (get_binary_contract_hash() raised UnicodeDecodeError on a binary printing non-UTF-8, escaping its documented every-failure-returns-a-reason contract), two hardening fixes (an unanchored stamped-tree grep that could disagree with its two siblings, and an issue title interpolated into a jq program), and two documentation honesty fixes (the contract handshake is a compatibility check and not an integrity control; a git install resolves an unreviewed pre-release wheel and nothing on any install path verifies the build provenance attestations that are produced). Everything else is declined in writing in the master plan, and the finding that unattended OIDC publishes share a persistent runner pool with pull-request code is tracked as #374. The security review also refuted this phase plan's own claim that phases 3 and 4 describe the contract hash both ways) |
Standalone plans¶
| Date | Plan | Intent | Status |
|---|---|---|---|
| 2026-08-02 | Use case documentation | One docs page per deployment permutation (Shaken Fist, OpenStack, oVirt, multi-cloud aggregation, placement topologies, static, later Proxmox), each covering value proposition, how it works, and setup; the oVirt page is delivered by two-tier CI phase 4 as the format-setting first instance | In progress |