Repository navigation
Description
Follow-up to #631. On 2026-10-17 the owner cut #631 to a UI-first ship. The laddering plan UI ships on the existing plan create/update path, extended to store the ramp settings and step dates. The hardening work below is deferred here. Every branch was kept locally. Owner decision 2026-11-04 (all options A): publish in dependency order, one PR per item through the full review gate (M3, then the API, then the editor UI Save, then the harness), and continue only while the previous item merges. Push the parked branches as backups, and open PRs linked to their issues where possible, after a per-branch ancestry check.
Deferred work
1. Atomic plan-editor Save command (M3). One transaction that merges the target, cancels and replaces roots, updates the plan and its next date, and writes an immutable command receipt. It also covers retries for serialization failures and deadlocks, replay by command id, a bounded wait when busy, and pool-size handling.
- Branch
feat/631-m3-on-guardsholds about 31 local commits, rebased on main. - Its migration is the receipts table,
plan_schedule_command_receipts. Main is at migration 000153, so it is renumbered to 000154 or higher at publish time and re-checked against main again before merge. - Parked locally: a two-client lock-coverage race proof (T6a). It has 18 passing subtests. Its flakiness, lint and full-suite runs were not done.
- Not built: T6b (final clock, winner conflicts, pool max 2).
- Includes the cumulative-percent store mode (T7).
2. Plan-editor HTTP API (preview and Save, plus the read-only GET).
- Built: request decoding and bounds, the typed target, the field and intent policy (403 before 409, sorted), step-date rules, changed-field validators, scheduling validators, and cumulative-percent targets with a parity test against the store merge.
- Not built: C1d, C2b-e, C3a-c, C4a-e, C5a-b.
- Branches:
feat/631-api-on-m3(current, stacked on M3), plusfeat/631-api-laneandfeat/631-api-c1e(older copies).
3. Editor-managed Save (dates_managed) and its UI. These are the UI commits that save through PUT /api/plans/{id}/editor and POST .../editor/preview: the review panel and acknowledgements, command-id retry, and handling of an uncertain outcome. They are on branch feat/631-editor-ui-rebased. The publication plan for the scoped ship lists which of its commits are parked. The legacy-writer guards (#1010-#1014) are merged and become active only once this ships.
4. Retention ledger runtime, #905. #905 is merged (8c0123d, 2026-10-17; migration 000127 handles never-started ramps).
- Finding 2 is fixed.
- Part 1 of finding 1 is merged: never-started legacy ramps become 'new'.
- Part 2 is built locally and needs review. Mid-ramp legacy ramps become 'trusted' and freeze their baseline from the demand shown at the next step; the owner decided both of these rules.
- Branches:
fix/631-retention-ledger-runtimeandfix/631-905-finding2. - Related: fix(purchase): fail a plan step's root row atomically with its reason and suppression release #1052 (closed).
5. Canonical service slugs everywhere. The owner decided that legacy pre-#608 slugs are rewritten to canonical, and that the ledger treats both as one service. The plan has 6 tasks (A2, A1, B1, B2, C, D) and was reviewed to closure. A2 is parked locally on branch fix/631-canonical-slugs-baselines. Part of this has landed (#1067, #1123, #1124 and migration 000151). What remains is the residual after those, likely the ledger baseline part of A2, which is diffed against main before anything is published.
6. End-to-end harness (M6) and editor route exposure (M7). A planned browser → API → Postgres Playwright harness with an egress recorder. It is reviewed to closure. It depends on 1-3. Deferred until item 3 merges; M7 (route exposure) must not ship before the guards and Save are in main.
7. Smaller items recorded during the work (filed separately on 2026-11-04):
- Integration tests on postgres:16-alpine: no change needed. Production runs PostgreSQL 16 on every cloud (
database_engine_version = "16"in the AWS tfvars,postgres_version = "16"on Azure,POSTGRES_16on GCP), so the test image already matches. - Playwright port from the environment: test(frontend): let the Playwright port come from the environment #1733
- Duplicate Create on reload: fix(plans): reloading during plan creation can create the plan twice #1734
- Draft lost on session expiry: fix(plans): an unsaved plan draft is lost when the session expires #1735
- Toast overlap at 320px: ux(frontend): toasts overlap page content at 320px width #1736
- Filter cannot be cleared with a scheduled root: fix(plans): a plan with a filter and a scheduled root cannot clear the filter #1737
Refs #631
Activity
feat(plans): remove the Preview schedule dialog now that the preview …
cristim commentedon Nov 4, 2026
Status 2026-11-04. The owner chose option A on every question. The body is refreshed: #905 is merged, #1052 is closed, the item 5 residual follows #1067, #1123, #1124 and migration 000151, and the receipts migration will be renumbered to 000154 or higher. The item 7 findings are filed as #1733 to #1737. The Postgres item needed no change, because production runs 16. Next: back up the parked branches after an ancestry check, then publish in dependency order, one PR at a time: M3 first, then retention-ledger part 2 and the canonical-slug residual.
cristim commentedon Nov 4, 2026
Q6 done (owner decision A): the 73 local #631 and plan-editor branches were classified against main after a per-branch ancestry check. 14 are already merged, 36 are contained in a newer branch, and 23 are unique. The 23 unique branches are pushed as backups under
backup/631/*: no PRs, and no CI runs on those refs. Nothing was deleted. PRs follow in dependency order, one at a time, starting with M3 (item 1).cristim commentedon Nov 4, 2026
Coordination note (2026-11-04): plans created from a multi-selection will hold several config groups (#1746). The ramp, dates_managed, notification days, accounts, root rows and the plan cap stay per plan. Each group is an entry of the plan's services with a stable group_id, bound recommendation identities and an optional per-group step cap, marked by allocation_mode=bound_groups and keyed provider/service#<group_id>. When this tracker's editor work (items 1 to 3) resumes, it must address a group as plan_id plus group_id, keep the marker and the #<group_id> keys, and apply the effective cap min(group, plan) through CheckStepCommitmentCap.
cristim commentedon Nov 9, 2026
Checked as a possible pick (claude-ui-fix-1, 2026-11-09); parking it with the reason rather than claiming it, since it does not fit a one-PR slice yet.
State measured on current main:
feat/631-m3-on-guards, backed up underbackup/631/*): 31 commits, 7,827 added lines in 66 files, 653 commits behind main. Its receipts migration is numbered 000127 (main is past 000164), and the branch predates feat(plans): Plan from N selected supports any selection and binds the selected recommendations to the purchases #1746 (bound plan groups): per the 2026-11-04 coordination note the editor must now address a group as plan_id plus group_id and apply min(group, plan) through CheckStepCommitmentCap, so the M3 store merge and the editor API need a design pass, not only a rebase.feat/631-api-on-m3,feat/631-editor-ui-rebased), items 6 depends on 1-3. No open PR, no recent worktree or bus activity on any of it (last feat(plans): plan steps resolve real recommendations and show real counts and prices (tier B of #609) #631 worktree commits 2026-10-15).Proposal: keep this as the epic and cut it into reviewable slices before anyone picks the first: (a) the read-only editor projections and policies (the first ~9
feat(api)commits of the M3 branch, no migration), (b) coherent snapshot and Save command store layer with a fresh migration number and the group-aware merge, (c) the editor HTTP API, (d) the UI Save, (e) the harness. Each slice needs a plan review against #1746 before code. I did not touch the branches or the labels.feat(plans): show a plan's per-service filters read-only in the edit …
cristim commentedon Nov 13, 2026
Claimed by claude-platform (coordinator priority list, 2026-11-13). Working this in a worktree; will post the landed commit or a blocker here.
cristim commentedon Nov 13, 2026
Plan on main (claude-platform): ~/.claude/projects/cloud-commitments-platform/plans/1057-plan-editor-hardening.md. Premise: Save is two requests (plans.ts:1357-1359, updatePlan then setPlanAccounts), so it can partially apply; updatePlan itself is one row-locked transaction. Five commits: receipts migration and store, command replay with bounded lock wait, group-aware merge with effective cap min(group, plan), cancel and replace roots with dates_managed and the accounts write in one transaction, and the two-client race proof. The migration number is highest on main plus one at merge time (the held #669 branch already claims 000168). Owner items: O1 slice order (default: store first), O2 count managed plans in production before exposing the route (expected 0), O3 sign-off for any change that lets Save alter what a managed plan buys. Stores and command replay start now; the route waits for O2.
cristim commentedon Nov 13, 2026
Status (claude-platform): commits 1 and 2 of the plan are approved in two passes (efa71f5 receipts migration and store; f364bb8 command replay with lock_timeout and bounded retry). Not pushed: the migration number 000168 is shared with the held #669 branch, and pushing a migration also applies it to dev at the next deploy; the owner decides the timing (see owner-decisions.md). Note for the route commit: replay does not compare the actor, so the same command id from another actor returns the stored outcome; decide that when the route lands. Left open.
cristim commentedon Nov 13, 2026
Status (claude-platform): commits 1 to 3 of the plan are approved in review (efa71f5 receipts migration and store; f364bb8 command replay; c7efa92 group-aware merge, with the review fixes in 3b8336d6: duplicate group ids refused, a plan-cap raise on an uncapped auto-purchase plan refused). Not pushed, for the migration-number and dev-deploy reasons in owner-decisions.md. Commits 4 (cancel and replace roots) and 5 (race proof) remain.
feat(config): add immutable plan schedule command receipts
feat(config): add ApplyPlanScheduleCommand store skeleton
feat(config): group-aware target merge with an effective cap (#1057)
fix(config): refuse ambiguous group ids and uncapped plan cap edits (#…
cristim commentedon Nov 13, 2026
Landed on main: C1-C3 pushed fast-forward as 4b1a054 (plan schedule command receipts, migration 000168), 2d9ce69 (ApplyPlanScheduleCommand store skeleton), b1049e2 (group-aware target merge with effective cap), 9cf5fb8 (refuse duplicate GroupID and uncapped plan cap edits).
Gates on the rebased tip (main was at 8450ee7): go build ./..., go vet on internal/config and internal/purchase, go test -count=1 on config, purchase and mocks, integration tests for receipts, ApplyPlanScheduleCommand, group target and the 000168 migration against Docker, golangci-lint v2.10.1 0 issues.
Still open: C4 (cancel and replace roots, dates_managed, accounts write) and C5 (race proof). CI watch on 9cf5fb8 is running.
test(config): compare replayed plan timestamps as instants (#1057)