plan(settings): add release-tag-first no-canonical fallback; bump to opus
Operator 2026-06-17: (1) no-canonical upgrade base should prefer the most recent release TAG < head (a real published predecessor, reusing samever's helper), with raw main-tip only as a last resort, then skip — always-on, improves this server too. (2) SKIP_CANONICALS_FOR_UPGRADE=true feeds that same release-tag-first fallback (so it swaps canonical->latest-release base without losing upgrade coverage). (3) model bumped sonnet->opus.
This commit is contained in:
@@ -164,6 +164,6 @@ phases = [
|
|||||||
{ id = "canon", plan = "plan-phase-canon-canonical-sweep.md", status = "STATUS-canon.md", models = { builder = "claude-opus-4-8", adversary = "claude-opus-4-8" } },
|
{ id = "canon", plan = "plan-phase-canon-canonical-sweep.md", status = "STATUS-canon.md", models = { builder = "claude-opus-4-8", adversary = "claude-opus-4-8" } },
|
||||||
# fix incomplete per-recipe run history on the CI dashboard (capped at latest 100 Drone builds; 362 runs exist) — source from local /var/lib/cc-ci-runs (opus) — see plan-phase-dash-*.md (operator 2026-06-17)
|
# fix incomplete per-recipe run history on the CI dashboard (capped at latest 100 Drone builds; 362 runs exist) — source from local /var/lib/cc-ci-runs (opus) — see plan-phase-dash-*.md (operator 2026-06-17)
|
||||||
{ id = "dash", plan = "plan-phase-dash-recipe-history.md", status = "STATUS-dash.md", models = { builder = "claude-opus-4-8", adversary = "claude-opus-4-8" } },
|
{ id = "dash", plan = "plan-phase-dash-recipe-history.md", status = "STATUS-dash.md", models = { builder = "claude-opus-4-8", adversary = "claude-opus-4-8" } },
|
||||||
# minimal CI-server settings.toml + SKIP_CANONICALS_FOR_UPGRADE (default false; canonicals are optional for the upgrade base) — see plan-phase-settings-*.md (operator 2026-06-17)
|
# CI-server settings.toml + SKIP_CANONICALS_FOR_UPGRADE + release-tag-first no-canonical fallback (opus) — see plan-phase-settings-*.md (operator 2026-06-17)
|
||||||
{ id = "settings", plan = "plan-phase-settings-ci-server-config.md", status = "STATUS-settings.md", models = { builder = "claude-sonnet-4-6", adversary = "claude-sonnet-4-6" } },
|
{ id = "settings", plan = "plan-phase-settings-ci-server-config.md", status = "STATUS-settings.md", models = { builder = "claude-opus-4-8", adversary = "claude-opus-4-8" } },
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
# Phase `settings` — minimal CI-server settings.toml + `SKIP_CANONICALS_FOR_UPGRADE`
|
# Phase `settings` — CI-server settings.toml + `SKIP_CANONICALS_FOR_UPGRADE` + release-tag-first fallback
|
||||||
|
|
||||||
**Mission (operator-specified 2026-06-17):** introduce a **minimal, extensible server-level settings file**
|
**Mission (operator-specified 2026-06-17):** two cohesive `resolve_upgrade_base` changes for the cc-ci
|
||||||
(TOML) for the cc-ci server, and add its first value: **`SKIP_CANONICALS_FOR_UPGRADE`** (bool, **default
|
server:
|
||||||
`false`**, and `false` on this server). When `true`, the upgrade tier resolves its base **without
|
1. A **minimal, extensible server-level `settings.toml`** with its first value
|
||||||
canonicals** — i.e. it falls back to the main-tip predecessor — codifying that canonicals are an optional
|
**`SKIP_CANONICALS_FOR_UPGRADE`** (bool, **default `false`**, `false` on this server). When `true`, the
|
||||||
optimization (a switch an operator can flip). The settings file is structured to hold **other CI-server
|
upgrade tier resolves its base **without canonicals** — codifying that canonicals are an optional
|
||||||
configs** later, but ship it minimal (just this one value for now).
|
optimization (an operator switch). The file is structured to hold other CI-server configs later; ship
|
||||||
|
it minimal.
|
||||||
|
2. An **improved no-canonical fallback (always-on, not flag-gated):** when no canonical is used — none
|
||||||
|
exists, its promote failed, or the flag is `true` — the base should be the **most recent release TAG on
|
||||||
|
`main` older than the PR head** (a real published predecessor), with the **raw `main`-tip only as a
|
||||||
|
further fallback** if the recipe has no prior release, then skip. Today the no-canonical path jumps
|
||||||
|
straight to `main`-tip, which may be an untagged WIP commit.
|
||||||
|
|
||||||
|
These compose: `SKIP_CANONICALS_FOR_UPGRADE=true` always takes the improved release-tag-first fallback.
|
||||||
|
|
||||||
State files: `STATUS-settings.md`, `BACKLOG-settings.md`, `REVIEW-settings.md`, `JOURNAL-settings.md`. DECISIONS.md shared.
|
State files: `STATUS-settings.md`, `BACKLOG-settings.md`, `REVIEW-settings.md`, `JOURNAL-settings.md`. DECISIONS.md shared.
|
||||||
|
|
||||||
@@ -38,33 +46,50 @@ hatch.
|
|||||||
|
|
||||||
**B. `SKIP_CANONICALS_FOR_UPGRADE` (bool, default `false`).**
|
**B. `SKIP_CANONICALS_FOR_UPGRADE` (bool, default `false`).**
|
||||||
- Wire into `resolve_upgrade_base` (`run_recipe_ci.py`): guard the canonical (`version`) branch — when the
|
- Wire into `resolve_upgrade_base` (`run_recipe_ci.py`): guard the canonical (`version`) branch — when the
|
||||||
flag is `true`, **skip the canonical lookup entirely** and fall through to the existing main-tip ref path
|
flag is `true`, **skip the canonical lookup entirely** and fall through to the **improved no-canonical
|
||||||
(→ skip if head == main-tip). Effectively: behave as if no canonical exists.
|
fallback (§2.C)**. Effectively: behave as if no canonical exists.
|
||||||
- **Scope it narrowly to the upgrade BASE** (its name says so). Do NOT change canonical *promotion* or the
|
- **Scope it narrowly to the upgrade BASE** (its name says so). Do NOT change canonical *promotion* or the
|
||||||
`--quick` warm-reattach with this flag — those are separate optimizations (a future `SKIP_CANONICAL_SWEEP`
|
`--quick` warm-reattach with this flag — those are separate optimizations (a future `SKIP_CANONICAL_SWEEP`
|
||||||
/ `SKIP_QUICK` could gate them; out of scope here — note in DECISIONS).
|
/ `SKIP_QUICK` could gate them; out of scope here — note in DECISIONS).
|
||||||
- **Note the sweep interaction** (document, don't fight it): with the flag `true`, a cold-on-latest sweep
|
|
||||||
run's upgrade tier resolves base = main-tip = head → the upgrade tier **skips** (no predecessor delta
|
**C. Improved no-canonical fallback — release tag before main-tip (always-on).** Replace the current
|
||||||
without the canonical). That's consistent — an "upgrade" in a cold-on-latest run only exists relative to
|
"jump straight to `main`-tip" no-canonical path with:
|
||||||
the canonical. PR runs are unaffected (base = main-tip = real predecessor). This server runs `false`, so
|
1. **most recent release TAG with version strictly older than the PR head** — reuse `samever`'s existing
|
||||||
no change here.
|
helper (newest published version `< head`, from `recipe_tags`, version-ordered); deploy that tag (a
|
||||||
|
clean published predecessor) as the base.
|
||||||
|
2. **raw `main`-tip** (the target-branch tip) — only if the recipe has **no** prior release tag at all.
|
||||||
|
3. **skip** — if neither (no predecessor / head == main-tip with no older tag).
|
||||||
|
This applies whenever no canonical is used (none exists, promote failed, or the flag is `true`), so it
|
||||||
|
improves this server too (false flag, but un-promoted recipes get a real release base instead of a WIP
|
||||||
|
commit). The unified chain becomes: `canonical (unless flag/none/==head) → newest release tag < head →
|
||||||
|
main-tip → skip`, with `samever`'s step-back and this fallback sharing the same release-tag helper.
|
||||||
|
- **Sweep interaction (now better):** with the flag `true`, a cold-on-latest sweep run resolves
|
||||||
|
base = newest release tag `< latest` = the **previous release** → the upgrade tier still runs a **real**
|
||||||
|
`previous-release → latest` upgrade (not a skip, not a no-op). So `SKIP_CANONICALS_FOR_UPGRADE` swaps the
|
||||||
|
base from *last-green canonical* to *latest published predecessor* without losing upgrade coverage. PR
|
||||||
|
runs likewise get a real release base. This server runs `false`, so the canonical path is unchanged.
|
||||||
|
|
||||||
## 3. Gates
|
## 3. Gates
|
||||||
|
|
||||||
**M1 — implemented + unit-tested.** Settings loader (TOML, stdlib, defaults, validation, graceful on
|
**M1 — implemented + unit-tested.** Settings loader (TOML, stdlib, defaults, validation, graceful on
|
||||||
absent/malformed file); `SKIP_CANONICALS_FOR_UPGRADE` wired into `resolve_upgrade_base`. Unit tests: flag
|
absent/malformed file); `SKIP_CANONICALS_FOR_UPGRADE` wired into `resolve_upgrade_base`; the release-tag-first
|
||||||
`false` (and absent file / absent key) → canonical used exactly as today; flag `true` → canonical branch
|
no-canonical fallback (§2.C) implemented by reusing `samever`'s newest-release-tag-`<`-head helper. Unit
|
||||||
skipped, resolver returns the main-tip/skip path; malformed file handled. Adversary cold-verifies: the
|
tests for the **full resolution matrix**: flag `false` + canonical present → canonical (unchanged); flag
|
||||||
**default is false** (this server's behavior is byte-for-byte unchanged); `true` genuinely bypasses the
|
`false` + no canonical → **newest release tag `< head`** (NOT main-tip); no canonical AND no older release
|
||||||
canonical (not just cosmetically); the loader can't crash the harness on a bad/absent file; scope is the
|
tag → main-tip; none → skip; flag `true` → canonical skipped → same release-tag-first fallback; absent
|
||||||
upgrade base only (promote/`--quick` untouched).
|
file / absent key → default false; malformed file handled. Adversary cold-verifies: **default is false**
|
||||||
|
(this server byte-for-byte unchanged); the no-canonical fallback returns a real older **release tag**
|
||||||
|
(main-tip only as last resort); `true` genuinely bypasses the canonical; the loader can't crash the harness
|
||||||
|
on a bad/absent file; scope is the upgrade base only (promote/`--quick` untouched); the fallback reuses the
|
||||||
|
`samever` helper (no divergent version-ordering).
|
||||||
|
|
||||||
**M2 — verified on the server.** The live server reads the settings (file present with
|
**M2 — verified on the server.** The live server reads the settings (file present with
|
||||||
`SKIP_CANONICALS_FOR_UPGRADE = false`, or absent → default false) and the upgrade path **still uses
|
`SKIP_CANONICALS_FOR_UPGRADE = false`, or absent → default false) and the upgrade path **still uses
|
||||||
canonicals — unchanged**. Then a controlled demonstration: flip it `true` (in a test/scratch context, not
|
canonicals — unchanged**. Demonstrate, with evidence: (a) a recipe **without** a canonical resolves its
|
||||||
permanently), show the upgrade base resolves to main-tip (canonical bypassed), then restore `false`.
|
base to the **newest release tag `< head`** (a real published predecessor), not the raw main-tip; (b)
|
||||||
Confirm the harness actually picks up the file on the server. Fresh Adversary PASS on both milestones →
|
flipping `SKIP_CANONICALS_FOR_UPGRADE = true` (test/scratch, not permanent) makes a canonical-bearing
|
||||||
`## DONE`.
|
recipe ALSO resolve to that release-tag base (canonical bypassed), then restore `false`. Confirm the
|
||||||
|
harness picks up the file on the server. Fresh Adversary PASS on both milestones → `## DONE`.
|
||||||
|
|
||||||
## 4. Guardrails
|
## 4. Guardrails
|
||||||
|
|
||||||
@@ -81,7 +106,9 @@ Confirm the harness actually picks up the file on the server. Fresh Adversary PA
|
|||||||
|
|
||||||
A minimal, extensible CI-server `settings.toml` (+ tracked `.example`, defaults in the loader) is read by
|
A minimal, extensible CI-server `settings.toml` (+ tracked `.example`, defaults in the loader) is read by
|
||||||
the harness; `SKIP_CANONICALS_FOR_UPGRADE` (default `false`, `false` on this server) is wired into the
|
the harness; `SKIP_CANONICALS_FOR_UPGRADE` (default `false`, `false` on this server) is wired into the
|
||||||
upgrade-base resolver so `true` bypasses the canonical (main-tip path) and `false`/absent leaves current
|
upgrade-base resolver; AND the no-canonical fallback now prefers the **most recent release tag `< head`**
|
||||||
behavior byte-for-byte unchanged; unit-tested; verified live on the server (false = unchanged; true =
|
(reusing `samever`'s helper) with raw `main`-tip only as a last resort. `false`/absent leaves current
|
||||||
canonical bypassed, then restored). Scope limited to the upgrade base (promote/`--quick` noted as separate).
|
behavior byte-for-byte unchanged; `true` bypasses the canonical into the same release-tag-first fallback.
|
||||||
M1 + M2 fresh Adversary PASSes in REVIEW-settings.md.
|
Unit-tested across the full resolution matrix; verified live on the server (false = unchanged; no-canonical
|
||||||
|
recipe → release-tag base; true = canonical bypassed, then restored). Scope limited to the upgrade base
|
||||||
|
(promote/`--quick` separate). M1 + M2 fresh Adversary PASSes in REVIEW-settings.md.
|
||||||
|
|||||||
Reference in New Issue
Block a user