Commit Graph
339 Commits
Author SHA1 Message Date
Nick 299f68886d merge master (behind-base update, round 2)
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / lint (push) Successful in 24s
CI Pipeline / unit-tests (push) Successful in 34s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / type-check (push) Successful in 23s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Successful in 24s
CI Pipeline / canary (pull_request) Successful in 26s
CI Pipeline / type-check (pull_request) Successful in 23s
CI Pipeline / unit-tests (pull_request) Successful in 34s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Successful in 1s
2026-09-07 22:45:36 +01:00
Nick 79ea4bcf95 merge master (behind-base update, round 2)
CI Pipeline / lint (push) Successful in 29s
CI Pipeline / canary (push) Successful in 38s
CI Pipeline / unit-tests (push) Successful in 45s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / type-check (push) Successful in 23s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Successful in 28s
CI Pipeline / canary (pull_request) Successful in 24s
CI Pipeline / unit-tests (pull_request) Successful in 34s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / type-check (pull_request) Successful in 22s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / required-checks (pull_request) Successful in 0s
2026-09-07 22:45:34 +01:00
Nick 61485e2fdc fix(pipeline): merge-robot identity check hits instance root /user, handles non-JSON error bodies
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Successful in 26s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / type-check (push) Successful in 22s
CI Pipeline / unit-tests (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Skipped
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Successful in 27s
CI Pipeline / canary (pull_request) Successful in 30s
CI Pipeline / type-check (pull_request) Successful in 22s
CI Pipeline / unit-tests (pull_request) Successful in 35s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / required-checks (pull_request) Successful in 1s
Red-first discharge (#214 follow-up): verify_identity built a repo-scoped URL
(.../repos/o/r/user -> 404 plain-text body) which crashed json.loads before
MergeRefused could fire — the robot never ran successfully since #211. Three
stacked defects: missing checkout (#214), reserved-secret auth (#213), and
repo-scoped identity URL (this commit).

- verify_identity now derives the instance root itself (defense in depth:
  never trust caller scope)
- _api converts non-JSON error bodies into MergeRefused instead of an
  unhandled JSONDecodeError
- 2 red tests added first, frozen green; suite 615+84
2026-09-07 22:22:42 +01:00
Nick bf8a612e94 Merge remote-tracking branch 'gitea/master' into release-safety-net
CI Pipeline / lint (pull_request) Successful in 23s
CI Pipeline / unit-tests (pull_request) Successful in 31s
CI Pipeline / canary (pull_request) Successful in 24s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 20s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Successful in 0s
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / lint (push) Successful in 37s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / canary (push) Failing after 35s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / unit-tests (push) Failing after 39s
CI Pipeline / required-checks (push) Skipped
2026-09-07 21:01:14 +01:00
Nick 50eac65d18 Merge remote-tracking branch 'gitea/master' into ci-dependency-lock
CI Pipeline / lint (pull_request) Successful in 24s
CI Pipeline / unit-tests (pull_request) Successful in 34s
CI Pipeline / canary (pull_request) Successful in 23s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 22s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Successful in 1s
auto-version.yml (push) Invalid workflow file
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / lint (push) Failing after 38s
CI Pipeline / canary (push) Failing after 41s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / unit-tests (push) Failing after 49s
CI Pipeline / required-checks (push) Skipped
2026-09-07 21:01:11 +01:00
Nick 65b76afb8c Merge remote-tracking branch 'gitea/master' into bugfix-contract
CI Pipeline / lint (pull_request) Successful in 24s
CI Pipeline / unit-tests (pull_request) Successful in 58s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 21s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Successful in 0s
auto-version.yml (push) Invalid workflow file
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / canary (push) Failing after 35s
CI Pipeline / lint (push) Successful in 41s
CI Pipeline / unit-tests (push) Failing after 47s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / required-checks (push) Skipped
2026-09-07 21:00:58 +01:00
Nick 31d849eff4 style: ruff format remaining added files
CI Pipeline / lint (push) Failing after 45s
CI Pipeline / unit-tests (push) Failing after 17s
CI Pipeline / canary (push) Successful in 26s
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / type-check (push) Successful in 21s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / lint (pull_request) Failing after 23s
CI Pipeline / unit-tests (pull_request) Failing after 16s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / type-check (pull_request) Successful in 55s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 5s
2026-09-07 21:00:44 +01:00
Nick 49d7924c74 Merge remote-tracking branch 'gitea/master' into umbrella-pipeline
CI Pipeline / unit-tests (push) Failing after 33s
CI Pipeline / canary (push) Successful in 25s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / type-check (push) Successful in 22s
CI Pipeline / gitea-offline (push) Successful in 27s
CI Pipeline / lint (pull_request) Failing after 28s
CI Pipeline / unit-tests (pull_request) Failing after 59s
CI Pipeline / canary (pull_request) Successful in 35s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 47s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / required-checks (pull_request) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 14s
CI Pipeline / lint (push) Failing after 47s
CI Pipeline / required-checks (push) Skipped
2026-09-07 20:56:55 +01:00
Nick 62abca0538 style: ruff format discharge checker (CI lint format-check)
CI Pipeline / lint (push) Failing after 17s
CI Pipeline / unit-tests (push) Successful in 55s
CI Pipeline / canary (push) Successful in 25s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / type-check (push) Failing after 21s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / lint (pull_request) Failing after 24s
CI Pipeline / unit-tests (pull_request) Successful in 30s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / type-check (pull_request) Failing after 21s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Skipped
2026-09-07 20:46:41 +01:00
Nick 62705bb219 ci(lint): silent-handler ratchet — S110+BLE001 selection with shrinking baseline (#126)
CI Pipeline / lint (push) Failing after 16s
CI Pipeline / unit-tests (push) Failing after 31s
CI Pipeline / canary (push) Successful in 25s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / type-check (push) Successful in 20s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / lint (pull_request) Failing after 16s
CI Pipeline / unit-tests (pull_request) Failing after 30s
CI Pipeline / canary (pull_request) Successful in 26s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 21s
CI Pipeline / gitea-offline (pull_request) Successful in 26s
CI Pipeline / required-checks (pull_request) Skipped
Spec gate (headless) / spec-gate (pull_request) Successful in 9s
Blast radius at ab4dbf8: BLE001 455 / S110 117 over src/ shared/ scripts/
(T201 1625 measured, not enforced). Enforcement mirrors the pyright ratchet:
scripts/lint_ratchet.py + lint-baseline.json, wired as an append-only step in
the ci.yml lint job. Contract tests red->green in
tests/test_ci_lint_contract.py; debt ledger docs/silent-handler-debt.md.
2026-09-07 20:42:41 +01:00
Nick c3c95688f7 docs(fixtures): fixture pipeline workflow + seed fixture (#157)
Seeds the pipeline with the REAL #192 CONVERGED case-mismatch payload: the
safety-net convergence step exported Python-cased True/False from
json.load while the steps compared env.CONVERGED == 'false' — both
conditionals unreachable (discharged on the release-safety-net branch,
public in PR #211's diff). Captured via the pipeline itself
(--class env-case-mismatch --source ci, 0 redactions — the payload is
already public and credential-free). The generated regression test asserts
the boolean-export checker still FLAGS the recorded payload
(checker_expectation: flags), so a recurrence of the class fails CI.

Manifest gains checker_expectation: capture records whether the class's
checker raises on the payload ('flags' — the raise IS the recurrence alarm)
or must stay quiet ('passes'); the generated tests enforce the recorded
expectation, so a checker that stops catching its recorded defect rots the
suite red.

Docs: bugfix-contract §10 gains the operational capture step + explicit
trivial-bug exemption list; README dev section points at the pipeline;
tests/fixtures/production/README.md documents the flow.

Henxels: capture_failure.py required in scripts/; production fixtures
governed (manifest.json + README.md required); payload.json and
manifest.json travel together (changed_with both directions, verified to
bite on a payload-only staged change).
2026-09-07 19:51:36 +01:00
Nick a0ec8f2a84 feat(fixtures): manifest-driven regression tests (#157)
capture_failure.py now generates tests/test_production_fixtures.py (template
embedded, written once — manifest-driven parametrization means regeneration
would be churn). One regression test per manifest fixture asserts the
system's CURRENT handling of the historical payload: sha256 tamper-evidence
(a payload edited without re-running capture fails), sanitiser idempotence,
metadata shape, and per-class checker dispatch — the recorded payload must
be CAUGHT by its class's checker so a recurrence fails CI. First checker:
env-case-mismatch (#192's CONVERGED casing defect), mirroring the boolean
env-export guard from the #192 discharge.
2026-09-07 19:40:17 +01:00
Nick 5458585e84 feat(fixtures): production failure capture with redaction (#157)
scripts/capture_failure.py: one command turns a raw failure payload into a
sanitised fixture under tests/fixtures/production/<class>/<id>/ plus a
manifest.json entry carrying the payload's sha256 (tamper-evidence for the
generated regression tests). Redaction reuses #122's filer patterns (query
creds, DSN userinfo, bearer, assignments) — copied with attribution because
the filer module ships on the failure-auto-filing branch; parity is pinned
on the filer's own test literals. After redaction an independent residual
scan aborts the capture loudly (exit 3, nothing persisted) when a
credential-shaped span survives — over-redaction is a shape witness, a
leaked fixture is an incident.
2026-09-07 19:33:46 +01:00
Nick 3e0b74873f merge: union bugfix-contract rules with umbrella rules — complementary contract surfaces 2026-09-07 18:40:39 +01:00
Nick c00c0093e6 feat(pipeline): umbrella impact map + propagation gate — change-propagation contract via pipeline, runner, henxels (#204, T32)
CI Pipeline / lint (push) Successful in 24s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / unit-tests (push) Successful in 32s
CI Pipeline / canary (push) Successful in 26s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / type-check (push) Successful in 20s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / lint (pull_request) Successful in 23s
CI Pipeline / unit-tests (pull_request) Successful in 30s
CI Pipeline / canary (pull_request) Successful in 23s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 20s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Successful in 0s
2026-09-07 18:32:17 +01:00
Nick 7402a68095 fix(pipeline): merge-robot fails loudly on refusals, verifies token identity, extracted testable script — red-first discharge of the silent no-op (bug-fix contract) (#147)
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / lint (push) Successful in 24s
CI Pipeline / unit-tests (push) Successful in 32s
CI Pipeline / canary (push) Successful in 26s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / type-check (push) Successful in 22s
CI Pipeline / gitea-offline (push) Successful in 13s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / lint (pull_request) Successful in 23s
CI Pipeline / unit-tests (pull_request) Successful in 31s
CI Pipeline / canary (pull_request) Successful in 30s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 2s
CI Pipeline / type-check (pull_request) Successful in 21s
CI Pipeline / gitea-offline (pull_request) Successful in 13s
CI Pipeline / required-checks (pull_request) Successful in 0s
2026-09-07 18:14:10 +01:00
Nick a78588048b feat(contract): bug-fix discharge contract — red-first fixes, full pipeline re-entry, frozen regression tests (#147)
CI Pipeline / lint (push) Failing after 17s
CI Pipeline / unit-tests (push) Successful in 55s
CI Pipeline / canary (push) Successful in 26s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / type-check (push) Successful in 40s
CI Pipeline / gitea-offline (push) Successful in 20s
CI Pipeline / required-checks (push) Skipped
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Failing after 17s
CI Pipeline / unit-tests (pull_request) Successful in 30s
CI Pipeline / canary (pull_request) Successful in 25s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / type-check (pull_request) Successful in 21s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / required-checks (pull_request) Skipped
2026-09-07 16:59:04 +01:00
Nick fa29a70ff3 refactor(pipeline): drop pointless f-string on plain AUTO_BUMPED print (#192) 2026-09-07 15:34:27 +01:00
Nick 179893039e fix(pipeline): catch URLError in create_release error path (#192) 2026-09-07 15:26:33 +01:00
Nick 48d2cd8491 style(ci): ruff format check_dep_lock.py (#150)
Quote-style only (double -> single for the line containing \$PWD);
battery re-verified after format (15 checker tests pass).
2026-09-07 15:10:37 +01:00
Nick 3c9a3f034f fix(pipeline): anchor attribution guard to the in-flight bump version (#192)
Quality-gate finding 7a: bump_branch_in_flight matched ANY chore/auto-bump-*
branch, so one stale historical branch (branches are never cleaned up) stood
the safety net down permanently. The guard now matches exactly
chore/auto-bump-{NEW} — the in-flight version — with new_version=None as the
documented legacy escape hatch; wait_out_closed_path passes NEW_VERSION
through.

Quality-gate finding 7b (docs): release-flow.md claimed the closed path was
'genuinely absent, not merely slow' and that the paths 'can never
double-bump'. Rewritten: attribution is best-effort; a >90s delayed closed
path can race into a double-bump, bounded by tag idempotency (duplicate
release creation is a no-op); stale-branch cleanup is a known limitation.

Red evidence: anchored-match tests failed against the prefix-wide guard.
Green: 12/12.
2026-09-07 15:08:02 +01:00
Nick d3c70393dd docs(ci): disclose drift-checker limitations in module docstring (#150)
Gate-review F4: two known blind spots were undocumented — (1) marker-only
drift (env-marker changes with identical pins) is invisible to the pin
diff, (2) direct-URL requirement lines are skipped by the old parser /
now fail loudly instead of being compared. Both disclosed in the module
docstring with guidance; no behavior change.

RED->GREEN: docs-only finding; red evidence is the pre-existing docstring
lacking the disclosure (gate finding itself). Checker behavior and tests
unchanged (15 pass).
2026-09-07 15:02:38 +01:00
Nick 82bd50f410 fix(pipeline): send release-drift label as integer IDs, not names (#192)
Quality-gate finding 6: POST /issues 'labels' requires integer IDs in Gitea;
the script sent the label NAME string, so the label never attached. Label
names are now resolved server-side via GET /labels (repo convention per
shared/custodian.py), created when missing, and skipped — issue still files —
when resolution and creation both fail. main() gains an injectable api
client so the flow is testable with a fake API.

Red evidence: 3 fake-client tests failed against the pre-fix code (network
URLError — no injectable seam; name-string payload). Green: 13/13.
2026-09-07 15:00:53 +01:00
Nick 084778d884 fix(ci): actionable message when uv is missing; suppress compile stdout (#150)
Gate-review F3: with uv absent, run_uv_compile() let subprocess raise a
raw FileNotFoundError traceback. Now caught (sentinel -1) and main()
prints the house actionable pattern: what to install (pinned uv into
.ci-venv), what command (pip install + PATH export), local install doc.

Gate-review F5: uv's full resolution listing went to stdout even on
success, polluting CI logs. stdout/stderr are now captured and printed
only on compile failure.

RED->GREEN: new test (uv_binary stubbed to a missing binary, PATH
stripped) failed with FileNotFoundError, passes with exit 1 + actionable
stderr. Real smoke: successful run no longer prints uv's 'Resolved 37
packages' listing.
2026-09-07 14:58:58 +01:00
Nick b7aa770d0f fix(ci): lock checker fails loudly on non-pinned requirement lines (#150)
Gate-review F2: lock_requirements() silently skipped any requirement
line lacking '==', so a degraded floor-style lock (e.g. 'rune>=0.49.0')
would pass the drift diff with its floor pins intact. Options
(-r/--index-url/...) remain the only tolerated non-pin lines; any other
non-pinned form (floor, range, wildcard, bare name) now exits 1 with an
actionable message naming the offending line and the regen command.

RED->GREEN: two new tests (floor fixture + unpinned/wildcard variants)
failed against the skip behavior, pass after the loud-failure fix. The
pre-existing skip-options test was updated to match the tightened
contract; the committed lock (37 pins) still parses clean.
2026-09-07 14:55:19 +01:00
Nick 8568e57640 fix(ci): drift checker resolves the pinned uv, not a stray PATH uv (#150)
Gate-review F1: the drift-ratchet step installed uv==0.10.11 into
.ci-venv but never exported PATH, so check_dep_lock.py resolved
/usr/bin/uv (0.12.10) and re-compiled the lock with a different
resolver than generated it. Both ends fixed:

- ci.yml drift step: export PATH="$PWD/.ci-venv/bin:$PATH" before
  invoking the checker.
- check_dep_lock.uv_binary(): prefer the interpreter-adjacent uv
  (sys.executable's dir — where CI pins it) over shutil.which.

RED->GREEN: two new tests (PATH-stripped + decoy-uv-on-PATH) failed
against the old resolver order, pass after the fix.
2026-09-07 14:52:13 +01:00
Nick 44323ce9b1 fix(pipeline): make the version surface failure fatal in auto_bump_pr (#192)
Spec-gate finding 4: a GET failure on src/rune/__init__.py was skipped like
an optional surface, so a bump PR could silently bump nothing. The version
surface is now fatal (exit 1 before any PR is filed); the other surfaces
stay optional (pattern absent — skip). The surface-edit loop is extracted to
apply_surface_edits() with an api callable seam for testing.

Red evidence: 4 new tests failed (no is_surface_fatal/apply_surface_edits;
abort test found no SystemExit). Green: 10/10.
2026-09-07 14:45:43 +01:00
Nick a7b9639a2e fix(pipeline): report version-behind-tag as drift with an anomaly flag (#192)
Spec-gate finding 3: assemble_release_decision returned converged=True when
master's __version__ was BELOW the latest tag — silent convergence for a
state that is drift (a bump merged without riding a release, or a tag moved
backwards). The decision now returns converged=False, warranted_bump=None
(the net must not act: bumping master cannot converge with a tag already
ahead) and a new 'anomaly': 'version_behind_tag' field (None otherwise).
The maintenance reconciler files the issue as before (DRIFT=true) and the
issue body now flags the anomaly explicitly.

Red evidence: 2 new decision tests failed with converged=True; the
drift-body anomaly-flag test failed; real-repo tag-ahead test added.
Green: 91/91 across convergence, drift-issue, and contract tests.
2026-09-07 14:29:02 +01:00
Nick a6a94c7352 fix(pipeline): classify merge-commit subjects by inner PR title (#192)
Spec-gate finding 2: classify_subject anchored at string start, so Gitea
merge commits ('Merge pull request <feat: x> (#N)') classified as 'other' —
a no-bump feat PR merged via merge-commit was invisible to the safety net
and to maintenance drift attribution.

Subjects matching the merge-commit form are now pre-processed: the quoted
inner title is classified; anything else classifies as before.

Red evidence: 6 new merge-commit fixtures failed (feat/feat(scope)/fix/
fix(scope)/feat!/perf inner titles all classified 'other'). Green: 64/64.
2026-09-07 13:56:19 +01:00
Nick 52e0bb0034 fix(pipeline): derive release API URLs in-script from workflow base coordinates (#192)
Spec-gate finding 1: create_release.py hard-read LIST_API_URL/RELEASE_API_URL
but auto-version.yml only ever passed RELEASE_SERVER_URL/RELEASE_REPO —
KeyError at runtime on both the PR-closed and safety-net release paths.

The script now derives both URLs from the base coordinates (explicit env
still overrides for direct use), and the workflow env blocks stay unchanged.
Adds tests/test_workflow_script_contract.py: a systematic guard that parses
every workflow env contract (step env + $GITHUB_ENV exports + shell exports)
against each invoked script's hard os.environ reads, plus an honesty check
that derived-default keys are never bare-subscripted.

Red evidence: contract test failed on both create_release invocations
(missing LIST_API_URL/RELEASE_API_URL); honesty test failed on the bare
subscripts. Green: 18/18.
2026-09-07 13:49:33 +01:00
Nick 160681cedd feat(ci): pinned CI dependency lock (#150)
requirements-ci.txt: fully-pinned output of
'uv pip compile pyproject.toml -o requirements-ci.txt --extra dev --extra
memory --python-version 3.11' (plain pip format; runners need no uv).
scripts/check_dep_lock.py: drift ratchet — regenerates the compile into a
temp file, diffs requirement pins against the committed lock, exits 1 with
the regeneration command on drift. Unit-tested against fixture files.
2026-09-07 13:45:54 +01:00
Nick 98afcd7ded feat(pipeline): maintenance drift reconciliation (#192) 2026-09-07 12:19:30 +01:00
Nick 98bdd5a70d feat(pipeline): push-triggered release safety net (#192) 2026-09-07 12:04:59 +01:00
Nick 76baaf9873 feat(pipeline): version convergence checker (#192) 2026-09-07 11:46:48 +01:00
Nick edcde05deb fix: format type_check_ratchet.py (ruff format)
CI Pipeline / lint (push) Successful in 1m20s
CI Pipeline / unit-tests (push) Successful in 2m5s
CI Pipeline / canary (push) Successful in 1m32s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / type-check (push) Successful in 2m3s
CI Pipeline / gitea-offline (push) Successful in 39s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / lint (pull_request) Successful in 1m28s
CI Pipeline / unit-tests (pull_request) Successful in 2m0s
CI Pipeline / canary (pull_request) Successful in 1m34s
CI Pipeline / best-practices (pull_request) Successful in 5s
CI Pipeline / documentation (pull_request) Successful in 5s
CI Pipeline / type-check (pull_request) Successful in 2m3s
CI Pipeline / gitea-offline (pull_request) Successful in 40s
CI Pipeline / required-checks (pull_request) Successful in 0s
Auto-version and Release / release (pull_request) Failing after 4s
2026-09-04 21:57:38 +01:00
Nick 9bafc4aefd fix(types): update baseline to CI runner counts (114/451); fix pyright binary path
CI Pipeline / lint (push) Successful in 1m15s
CI Pipeline / unit-tests (push) Successful in 2m10s
CI Pipeline / canary (push) Successful in 1m27s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Successful in 2m8s
CI Pipeline / gitea-offline (push) Successful in 39s
CI Pipeline / required-checks (push) Skipped
The arm64 CI runner reports different pyright counts than x86_64 local
(114 errors / 451 warnings vs 121/445). The baseline must be measured on
the same platform that enforces it. Also: pyright binary path fix for
the canary (Node.js wrapper, not a Python module).
2026-09-04 21:27:03 +01:00
Nick b23448012d fix(types): replace inline Python with script file (YAML indentation bug)
CI Pipeline / lint (push) Failing after 1m16s
CI Pipeline / unit-tests (push) Successful in 2m9s
CI Pipeline / canary (push) Successful in 1m25s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / type-check (push) Failing after 2m12s
CI Pipeline / gitea-offline (push) Successful in 39s
CI Pipeline / required-checks (push) Skipped
The type-check ratchet used inline python3 -c with multi-line code that
broke YAML indentation. Moved to a standalone script file for reliability.
Same logic: compare current pyright counts against the committed baseline.
2026-09-04 21:17:36 +01:00
Nick a9496d1b06 feat(gitea): make governance and recovery reproducible
CI Pipeline / lint (push) Failing after 55s
CI Pipeline / canary (push) Successful in 6s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / gitea-offline (push) Successful in 39s
CI Pipeline / required-checks (push) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / lint (pull_request) Failing after 22s
CI Pipeline / canary (pull_request) Successful in 5s
CI Pipeline / best-practices (pull_request) Successful in 5s
CI Pipeline / documentation (pull_request) Successful in 5s
CI Pipeline / gitea-offline (pull_request) Successful in 39s
CI Pipeline / required-checks (pull_request) Skipped
Track branch policy, labels, milestones, and wiki content as declarative state with a read-only-by-default provisioner.

Harden off-disk backup publication and add a rootless, networkless restore drill that validates SQLite, application data, and database-declared bare repositories.

Run offline contracts in CI, pin audited dependencies, document operations, and bump Rune to 0.43.0.
2026-08-30 17:10:32 +01:00
Nick 6378c22fb5 feat(gitea): complete governance and recovery tiers
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Successful in 21s
CI Pipeline / canary (pull_request) Successful in 3s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / required-checks (pull_request) Successful in 1s
2026-08-24 14:37:58 +01:00