feat(settings): server settings.toml loader + SKIP_CANONICALS_FOR_UPGRADE + release-tag-first no-canonical fallback
Some checks failed
continuous-integration/drone/push Build is failing

- harness/settings.py: stdlib tomllib loader, [upgrade].skip_canonicals_for_upgrade
  (bool, default false), _SCHEMA single-source defaults+validation; graceful on
  absent/malformed (WARN+defaults), warn-and-ignore unknown keys/tables, TypeError on
  wrong type. Path $CCCI_SETTINGS / /etc/cc-ci/settings.toml. + tracked settings.toml.example.
- resolve_upgrade_base: flag true bypasses the canonical lookup -> no-canonical fallback;
  canonical-present path (incl. samever step-back) unchanged when false.
- _no_canonical_base (always-on, §2.C): newest release tag < head (reuse
  warm_reconcile.newest_older_version) -> main-tip -> skip; replaces jump-to-main-tip.
- unit: full resolution matrix + loader tests; 315 unit pass, ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 16:55:05 +00:00
committed by autonomic-bot
parent 90228cffc4
commit cd19c1b172
8 changed files with 556 additions and 5 deletions

View File

@ -1579,3 +1579,33 @@ OVERVIEW (`/`) and badges keep their Drone latest-per-recipe source unchanged. D
merge Drone live "running" status into history (optional per plan; re-adds the network dependency the
local source removes; overview already shows live status). Retention: 308 parseable runs present, no
trim job observed → adequate; revisit only if a cap is ever needed.
---
## Phase `settings` (2026-06-17) — server settings.toml + SKIP_CANONICALS_FOR_UPGRADE + release-tag-first fallback
- **Settings home = `harness/settings.py` (new), file `/etc/cc-ci/settings.toml` (override `$CCCI_SETTINGS`).**
No pre-existing cc-ci config module existed to extend (config was scattered `os.environ.get` reads);
a minimal stdlib-`tomllib` loader is the minimal+extensible mechanism. `_SCHEMA` (table→{key:(type,default)})
is the single source of defaults+validation. Tracked `settings.toml.example`; live file untracked/operator-
managed/no-secrets (secrets stay in sops). Default `/etc/cc-ci` chosen over the plan's suggested
`/srv/cc-ci` (orchestrator-ambiguous): `/etc/cc-ci` is where the harness already runs (`CCCI_REPO`),
absolute so Drone+sweep read the same file, untracked file survives deploy `git pull`.
- **`SKIP_CANONICALS_FOR_UPGRADE` scope = upgrade BASE only.** Wired into `resolve_upgrade_base`: flag
true → skip canonical lookup → no-canonical fallback (behaves as if no canonical). Does NOT touch
canonical *promotion* or the `--quick` warm-reattach — those are separate optimizations; a future
`SKIP_CANONICAL_SWEEP` / `SKIP_QUICK` could gate them (out of scope here).
- **No-canonical fallback (always-on, §2.C):** newest release TAG `< head` (reuse
`warm_reconcile.newest_older_version`, the single version-ordering source) → raw main-tip (no prior
release tag) → skip. Replaces the old jump-straight-to-main-tip path; improves this server too (false
flag, un-promoted recipes get a real release base).
- **Canonical-present path (incl. samever step-back) preserved byte-for-byte.** With flag false + a
canonical, behavior is unchanged. The step-back's "no older predecessor → skip" is intentionally NOT
routed to main-tip (would reintroduce the same-version no-op samever prevents); the §2.C "==head"
routing is satisfied because the step-back already takes the same release-tag helper as fallback step 1.
- **Validation:** absent/unreadable/malformed-TOML → WARN + all-defaults (cannot crash the harness);
unknown table/key → warn-and-ignore; present known key of wrong type → raise TypeError (loud typo).
- **OBSERVATION (not this phase's defect):** `scripts/lint.sh` (pinned ruff) reports
`dashboard/dashboard.py` + `tests/unit/test_dashboard.py` would be reformatted confirmed pre-existing
at HEAD f68f1c5, outside the settings diff. Flagged for the dashboard owner / orchestrator; not fixed
here (narrow scope).