Commit Graph
339 Commits
Author SHA1 Message Date
Nick f765365d03 fix(release): ancestry check fetches canonical branch on divergent classification
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 4s
Auto-version and Release / release (push) Successful in 29s
CI Pipeline / canary (push) Successful in 32s
CI Pipeline / lint (push) Successful in 42s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 1m8s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 2m59s
Observed live on deploy 7449 (SHA 535c2909): a delayed older candidate's
checkout cannot contain commits newer than itself — its local object
store lacks the deployed commit entirely, so the ancestry classification
returned 'divergent' and fail-closed refused. Correct refusal, wrong
reason: the candidate IS an ancestor of the deployed build.

Repair: on divergent classification, fetch origin's canonical branch
(best-effort, credentials already configured in the workflow checkout)
and re-classify. Still divergent afterwards = genuine divergence, refusal
stands. Regression test reproduces the 7449 shape with a depth-1
checkout that genuinely lacks the deployed commit's objects.

Release-path invariant unchanged: unknown/unprovable ordering still
refuses; the fetch only lets the checker SEE the newer reality before
refusing.
2026-09-13 14:01:04 +01:00
Nick 600008482d fix(release): monotonic promotion — stale deploy candidates fenced at promotion time (DEPLOY-MONOTONIC-001)
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / canary (push) Successful in 32s
Auto-version and Release / release (push) Successful in 31s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 1m7s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 2m58s
Root cause of the 2026-09-13 deploy-order race (deploys 7355/7359):
deploy_stage.py promoted unconditionally in job-finish order — no
comparison against the currently-deployed commit, no lock, unconditional
PROMOTED claim. Two overlapping deploys (tranche push + auto-bump push)
could finish out of order and move current BACKWARD.

Repair (governed through the Tranche 4 live Scaffolding path — decision
trace + contract DEPLOY-MONOTONIC-001 durably saved BEFORE edits):

- deploy_promotion.py: promotion authority with GIT ANCESTRY ordering
  (canonical release branch; Rune's flow is linear master history):
  same -> NOOP_ALREADY_CURRENT (idempotent), descendant -> PROMOTED,
  ancestor -> STALE_SUPERSEDED (truthful non-error refusal), divergent
  or unknown -> fail closed. flock'd critical section: the ancestry
  check against the commit current ACTUALLY points to, the last-good
  refresh, and the symlink swap happen atomically — no check/swap
  interleaving window. Symlink swaps are os.replace(2) over temp links:
  current is never absent, never half-updated (crash-safe).
- deploy_stage.py: promotion routed through the authority; truthful
  outcome reporting — STALE_SUPERSEDED prints no PROMOTED claim,
  mutates nothing, exits 0 (the newer build legitimately won);
  divergent/unknown exit 1 (fail closed).
- deploy.yml: promotion truthfulness check reads the deployment
  authority (current symlink) after staging; runtime verification only
  runs for real promotions — build/stage success != promotion success.

Test matrix (brief §20 A-M): 21 tests — the exact race shape with B
promoting then A fenced, forward order, same-candidate idempotence,
retry-after-promotion last-good integrity, stale mutation-freedom
(current AND last-good untouched), divergent orphan-branch fail-closed,
qualification gate regression, stage/promote distinction, promoted-
outcome proven from deployment authority, auto-bump overlap shape,
crash-safety coherence across mixed outcomes, red-candidate refusal
regression, green forward deploy, concurrent-thread serialization, and
the §21 LIVE two-process race: old process paused at its promotion
barrier, new promotes, old resumes and is fenced — current remains the
newer build, deterministic via file barrier (no sleeps).

Suite 1497 green; henxels rc=0; pyright clean.
2026-09-13 12:51:57 +01:00
Nick 36ee604646 fix(release): required-checks verdict evaluates needs results — fail-closed deploy
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / canary (push) Successful in 32s
CI Pipeline / lint (push) Successful in 46s
Auto-version and Release / release (push) Successful in 47s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 1m9s
CI Pipeline / required-checks (push) Successful in 2s
deploy / deploy (push) Successful in 2m59s
ROOT CAUSE (red-CI promotions 0.66.28/29): the required-checks
'Publish protected-branch gate' step read /tmp/need_* files that no step
ever wrote and echoed 'All required CI checks passed' UNCONDITIONALLY.
With if: always() the needs gate is overridden, so the job ran on red
needs and published success — deploy_qualify correctly trusted it and
promoted red commits (24413e4, fd6e9b4, de30cd9; status timelines in the
closure evidence).

FIX: publish step now runs only when every needs.*.result == 'success';
companion fail-closed step exits 1 otherwise, so the required-checks
context reports failure instead of lying.

DEFENSE-IN-DEPTH: deploy_qualify verdict is now the AND of two
independent legs — (1) newest required-checks observation for the exact
SHA, (2) the latest COMPLETED ci.yml@refs/heads/master run for that exact
SHA with every job concluded success (fan-out resolved by path, run
resolved by head_sha, jobs envelope unwrapped — no aggregate-status
fallback). Any pending/missing/disagreement = not deployable.

CANARY: gitea_pipeline now asserts the verdict evaluates needs results
and fails closed — the class locked shut. 20 qualifier tests with
fixtures from the real incident shapes; 1402 suite green.
2026-09-12 20:10:28 +01:00
Nick 57a274d97d docs(phase-d): research_inward_context consumes Spine-generated view
CI Pipeline / documentation (push) Successful in 10s
Auto-version and Release / release (push) Successful in 13s
CI Pipeline / best-practices (push) Successful in 14s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / canary (push) Successful in 39s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / unit-tests (push) Successful in 1m10s
CI Pipeline / lint (push) Successful in 35s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 1m11s
Phase D consumer migration: the INWARD context builder reads structural
facts from the Spine store's generated compatibility view (same schema —
zero code-path change), documented as TEMPORARY SPINE-BACKED
COMPATIBILITY. Graceful degradation to a manual manifest if Spine is not
seeded in a checkout.
2026-09-12 18:13:15 +01:00
Nick ce40acbb1f feat(spine): V1 — evolvable structural self-model as the single structural authority
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 5s
Auto-version and Release / release (push) Successful in 33s
CI Pipeline / canary (push) Successful in 32s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m2s
CI Pipeline / lint (push) Successful in 8m45s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 10m19s
Open-world entity/relationship store (schema_version 1): kinds, relationship
types and metadata are open tags — unknown future capabilities enter as data,
never as core edits (extensibility test included, synthetic capability
round-trips with zero core change). Evidence-gated maturity ladder
DECLARED<PRESENT<WIRED<REACHABLE<EXERCISED<LIVE_PROVEN — no evidence, no
promotion; demotion rejected and recorded.

Umbrella migration Phase A→C: manifest ingested once (generated-view
refusal guard prevents the ingest cycle; manual truth archived at
config/umbrellas.manual.json), canaries preserved as obligated_canary
relationships, config/umbrellas.json now a GENERATED compatibility view for
legacy consumers (CI umbrella_impact gate + henxels) — single-authority
route proven by registering module:spine through Spine alone (one store
edit; the legacy view flows out; contract tests validate the round-trip).

Dynamic observations: deployed identity (_build_identity.json), drift
classes incl. registered_but_absent, present_but_unowned,
registered_no_static_importers (D6 dead-subnet now mechanical),
version_surfaces_disagree, relationship_disappeared. Deterministic
snapshots + diff. Scaffolding V1 now consumes Spine for ownership/deps/
consumers (spine_maturity surfaced in every card). 31 spine tests; full
gates green.
2026-09-12 17:03:27 +01:00
Nick 7f47969128 feat(scaffolding): V1 tranche 1 — projection engine over existing authorities
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 5s
Auto-version and Release / release (push) Successful in 27s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / lint (push) Successful in 40s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 59s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 3m9s
scripts/scaffold_projection.py derives per-component cards (subsystem,
dependencies, consumers, mirrors, proof obligations + evidence state) from
the umbrella manifest, canary registry, AST import graph (incl. relative
lazy imports), and tests/ filesystem. No new authority: projections only.
docs/SCAFFOLDING.md records the mechanism audit (KEEP/EVOLVE/REPLACE/RETIRE)
and the real-change proof on the context-discovery fix.
2026-09-12 11:15:42 +01:00
Nick f182ab8601 feat(reconciliation): canonical issue reconciliation artifact + consistency checker (T15 Parts J/K/L)
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 5s
Auto-version and Release / release (push) Successful in 30s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / lint (push) Failing after 42s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m2s
CI Pipeline / required-checks (push) Successful in 4s
deploy / deploy (push) Successful in 3m11s
- docs/GITEA_ISSUE_RECONCILIATION.md: human-readable projection (states,
  bug-label audit with per-issue evidence, open-issue reconciliation table)
- docs/gitea_issue_reconciliation.json: machine-readable authority
  (72 records; all open issues covered; single live defect #324).
  Placed under docs/ because state/ is the gitignored runtime dir.
- scripts/gitea_reconciliation_check.py: deterministic drift check —
  state/label/coverage invariants; bug-label invariant applies to OPEN
  issues (closed labels are historical); exit 1 with itemized drift.
- Part K audit: closed #139 #157 (FIXED_VERIFIED with evidence comments);
  bug labels removed from #204 #145 #126 #37 #16 (not defects) and the
  stuck label on closed #314. Open bug-labelled: 8 → 1.
- 1289 tests green; ratchet 352/80; henxels clean.
2026-09-11 22:50:44 +01:00
Nick 9a05fdfa1f fix(convergence): decision JSON omits boundary_sha — consumers re-derive it from git
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 5s
Auto-version and Release / release (push) Successful in 25s
CI Pipeline / canary (push) Successful in 36s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 1m3s
CI Pipeline / required-checks (push) Successful in 2s
deploy / deploy (push) Successful in 2m40s
Every debug session of the release pipeline (T15 Part F forensics included)
had to re-derive the release boundary by hand. The decision JSON now
carries boundary_sha on every return path.
2026-09-11 22:33:10 +01:00
Nick c35018f543 fix(release): numeric semver comparison — lexicographic order skipped warranted bumps
CI Pipeline / best-practices (push) Successful in 18s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / canary (push) Successful in 30s
CI Pipeline / lint (push) Successful in 38s
Auto-version and Release / release (push) Successful in 56s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 56s
CI Pipeline / type-check (push) Successful in 28s
deploy / deploy (push) Failing after 15m25s
CI Pipeline / required-checks (push) Successful in 1s
_version_lt(): '0.66.9' < '0.66.10' is False lexicographically ('9' > '1'),
so a legitimate patch bump after v0.66.9 surfaced as
version_ahead_of_target and the release was silently skipped (run 6781,
2026-09-11). Both comparison sites (test-injection + production) now
compare numerically per segment. Regression tests added; 1284 green.
2026-09-11 21:21:23 +01:00
Nick 9e0b85534a fix(release): boundary grep must match subjects only, not bodies
CI Pipeline / best-practices (push) Successful in 9s
Auto-version and Release / release (push) Failing after 16s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 34s
CI Pipeline / lint (push) Failing after 41s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m1s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 38s
git --grep matches the commit BODY by default: a fix commit whose body
mentions 'chore(release)' was misdetected as the release boundary,
swallowing its own warranted bump (observed live: d01df79 boundary
detection). Anchor the pattern to the subject with --extended-regexp
and re-verify via is_release_commit(). Also drop unrecognized
--fixed-strings=False flag (fatal on this git version).
2026-09-11 20:50:46 +01:00
Nick d01df797c1 fix(release): wire release boundary into convergence (duplicate-bump root cause)
Auto-version and Release / release (push) Failing after 9s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 28s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 53s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / required-checks (push) Successful in 4s
deploy / deploy (push) Successful in 1m11s
release_convergence() never assigned  from
last_release_boundary() — the production path classified ALL commits
(959+) as unreleased, so the warranted bump (minor, from an ancient
feat) never converged and every queued push wrote its own bump commit
(5x 0.66.9 observed 2026-09-11 20:21). Now the boundary is the one
source of truth: last chore(release) commit, falling back to the
latest tag. Post-boundary subjects only.

Also: local path was NOT reached when _boundary_subject was injected;
test_cli_prints_plan_json expectation updated to boundary semantics
(feat below the tag no longer warrants minor).
2026-09-11 20:34:30 +01:00
Nick 4eefc15837 fix(lifecycle+auth): canonical gitea auth path, terminalization helper, fault-injection gaps (T15 Parts A-E)
CI Pipeline / best-practices (push) Successful in 8s
Auto-version and Release / release (push) Failing after 13s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / lint (push) Failing after 41s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / unit-tests (push) Successful in 59s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 37s
- scripts/gitea_auth.py: single credential ladder (env -> 0600 token file ->
  git credential fill); 6 consumers migrated off direct os.environ reads
- rune_operator: consolidate 5 duplicated failure blocks into
  _terminalize_execution_failure; fix 3 fault-injection gaps:
  (1) dual-module PreparedTool identity split crashed approval-path saves,
  (2) fallback-model failure escaped send_task (created/pending orphan),
  (3) running-transition save uncaught (running-with-no-owner)
- envelope task.status now agrees with canonical ledger (awaiting_approval)
- orphan task_ac35f4e287c8 terminalized failed with durable evidence
- tests: gitea auth ladder (6), lifecycle fault matrix (9 boundaries +
  restart/reload + helper contract); 1280 green in ci-venv; ratchet 352/80
2026-09-11 20:15:57 +01:00
Nick 2bf43eafcd test: #314 forced association regression + Gitea auth helper + lifecycle tests
Auto-version and Release / release (push) Failing after 8s
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / lint (push) Successful in 44s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 1m0s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 38s
- tests/test_recall_mode_regression.py: deterministic fixture proving
  association-merged entries carry mode=association_merged (fails on old
  impl). #314 closed FIXED_VERIFIED.
- scripts/gitea_auth.py: canonical Gitea API auth helper (GITEA_TOKEN env
  or git credential fill, never remote URL parsing)
- tests/test_task_lifecycle.py: fault injection at route/model_selection/
  execute boundaries — all terminalize, no immortal RUNNING
- tests/test_route_isolation.py: task-scoped route instruction isolation
- tests/test_release_convergence.py: correct target-version algorithm

1268 tests green; ratchet 352/80; henxels clean.
2026-09-11 18:17:17 +01:00
Nick ca4f7593d7 feat(corrections): #314 defect fix, credential rotation, release guard, task lifecycle, route scoping, PL1 records + metrics
CI Pipeline / best-practices (push) Successful in 8s
Auto-version and Release / release (push) Failing after 14s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / canary (push) Successful in 37s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m4s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 48s
CORRECTION 1: #314 reopened — recall_with_associations mode field defect
CONFIRMED in current source and FIXED (mode: association_merged).

CORRECTION 3: Gitea credential removed from remote URL (credential helper).
TOKEN EXPOSED: yes (in diagnostic output). TOKEN ROTATED: not yet (requires
Gitea web UI access). Remote URL now shows username only, no secret.

CORRECTION 4: duplicate-release-commit defect ROOT CAUSE: convergence
computed warranted bump from commits-since-tag without checking if master
version already satisfies the bump. FIX: already-converged guard in
version_convergence.py (master version > last tag → no commit). Repo-aware
(args.repo passed to read_version/latest_tag).

CORRECTION 6: lifecycle terminalization — execution exception now
guarantees task terminalizes as failed with evidence (no immortal RUNNING).

CORRECTION 7: route instruction task-scoped on RuneTask.route_instruction
(NOT shared operator state). Read-only leading-verb override. Isolation
tests prove no cross-contamination between interleaved tasks.

PL1-01/02/03/05: pl1_records.py (route resolution, proof level, failure
class, candidate status), metrics with honest NOT_YET_MEASURABLE semantics,
route-instruction learning loop (PE-1789102658-0269 SEED).

1253 tests green; ratchet 352/80 (shrink); henxels clean.
2026-09-11 15:36:08 +01:00
Nick 24537e46e7 fix(release): already-converged version guard (prevents duplicate same-version release commits)
CI Pipeline / best-practices (push) Successful in 8s
Auto-version and Release / release (push) Failing after 14s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / canary (push) Successful in 40s
CI Pipeline / lint (push) Successful in 45s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Failing after 1m5s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 37s
The duplicate-release-commit defect: each queued push ran the release
workflow from its own pre-bump checkout, computed the same warranted bump,
and created another identical-version commit. The convergence script now
checks if master __version__ > last tag — if so, already converged, no
commit needed. This is the definitive fix for the 5x 0.66.8 defect.
2026-09-11 15:06:34 +01:00
Nick a8ae37df21 fix(pl1): document RUNE_EXPERIENCE_LEDGER env override on ledger default
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 34s
CI Pipeline / lint (push) Successful in 43s
Auto-version and Release / release (push) Successful in 47s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Successful in 1m1s
deploy / deploy (push) Failing after 15m26s
CI Pipeline / required-checks (push) Successful in 2s
2026-09-11 13:21:33 +01:00
Nick a125c023e6 feat(PL1): first tranche — structured records, failure classification, route-instruction learning loop, metrics
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / lint (push) Successful in 44s
Auto-version and Release / release (push) Successful in 49s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 1m1s
deploy / deploy (push) Failing after 15m38s
CI Pipeline / required-checks (push) Successful in 1s
PL1-01: scripts/pl1_records.py — compact structured Experience evidence from
canonical task state + route.jsonl (route resolution by task_id+timestamp,
proof level, failure class, candidate status).
PL1-02: failure classes in the PL0 vocabulary, evidence-grounded; UNKNOWN
valid; research_dispatch never failure.
PL1-03: first learning loop — recurring prose-instead-of-mutation family →
structural correction (route-driven instruction appended to the user context
block for mutation routes) + replay contract (NOT_COMPLETED gate) —
recorded as PE-1789102658-0269 (SEED; held-out = next deployed mutation tasks).
PL1-05: metrics module (first_pass_accepted, false_completion_rate=0.0
structurally, mutation_failures, research_dispatches, candidate/evidence split).

Intent state updated: PL1 first tranche live; ADAPT-LIVE acceptance proven on
deployed runtime; remaining ADAPT obligations deferred to their epics.
2026-09-11 05:58:47 +01:00
Nick afa276aaf4 fix(deploy): startup canary runs in CANDIDATE mode with --stage (gate fail-closed correctly but never tested the candidate after the two-mode refactor)
CI Pipeline / best-practices (push) Successful in 10s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / canary (push) Failing after 39s
Auto-version and Release / release (push) Successful in 44s
CI Pipeline / lint (push) Successful in 45s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m5s
deploy / deploy (push) Failing after 15m22s
CI Pipeline / required-checks (push) Successful in 1s
2026-09-11 04:16:31 +01:00
Nick c2528c1d9d feat(deploy): two-mode TUI canary (candidate scrub vs current), negative deployment regression, release-recursion invariant
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Failing after 37s
CI Pipeline / lint (push) Successful in 45s
Auto-version and Release / release (push) Successful in 55s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Failing after 59s
deploy / deploy (push) Failing after 15m24s
CI Pipeline / required-checks (push) Successful in 1s
Handoff 2026-09-11 Part A-C:

A. tui_startup_canary two modes: candidate (--stage, sys.path SCRUBBED of
   /mnt/workdrive/rune-code/current + imported-rune purge + contamination
   check that rune resolves from the stage) and current (consuming path).
   Scrub proven: candidate mode on the 76f71fc stage reports 76f71fc/0.66.2
   while current is bb536c9/0.66.3. FIXED a live exit-code bug: main()
   returned 1 but was called without sys.exit — a failed canary exited 0
   (the deploy gate's own returncode check in deploy_stage.py was correct,
   so promotion was never actually bypassed; the standalone script was).

B. Negative deployment canary (tests/test_deployment_canary.py): broken
   staged candidate → canary exit 1 naming the failure → current identity
   byte-identical before/after. Plus current-mode identity regression.

C. Release recursion: is_release_commit() extracted into
   version_convergence.py (ONE source of truth); workflow guard uses
   --is-release-subject CLI (no inline python in YAML); regression tests
   cover recognition, never-bump-from-release-commits (incl. the 5x loop
   case), substantive commits still bumping, and the CLI exit contract.

1241 tests green; ratchet 353/80; henxels clean.
2026-09-11 03:16:50 +01:00
Nick 76f71fc7e6 fix(canary): tui_startup_canary self-bootstraps against the current deployment
CI Pipeline / best-practices (push) Successful in 14s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / lint (push) Successful in 41s
CI Pipeline / canary (push) Failing after 40s
Auto-version and Release / release (push) Successful in 52s
CI Pipeline / unit-tests (push) Successful in 56s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 2m7s
2026-09-11 02:39:54 +01:00
Nick a1d1b838b7 feat(ADAPT-LIVE correction): completion truth + escalation-before-terminal lifecycle + probe runtime policy
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Failing after 37s
Auto-version and Release / release (push) Successful in 43s
CI Pipeline / lint (push) Successful in 45s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 1m2s
deploy / deploy (push) Failing after 15m22s
CI Pipeline / required-checks (push) Successful in 1s
Handoff 2026-09-10 §5–§8 corrections:

1. Completion truth (§6): mutation-class tasks (build route AND
   change/defect language) terminate 'completed' only with observable
   evidence — verification method or a completed mutating tool event.
   Text-only responses on mutation tasks now fail with
   NOT_COMPLETED_NO_MUTATION_EVIDENCE (retryable). Neutral-verb tasks
   (inspect/read/check...) remain conversation-complete. The
   'I don't have the capability → completed' defect is structurally
   impossible for mutation tasks.

2. Escalation lifecycle (§7): the adaptive decision happens BEFORE the
   terminal transition. Verification failure on a local route → ONE
   probe → unresolved = task transitions research_required (nonterminal,
   research consumer continues) and returns ESCALATED_TO_RESEARCH —
   never a false terminal failure. GROUNDED probe → honest failed
   terminal (route was right, attempt slipped).

3. Action-verb governance (§10): 'inspect the failing test' is
   read-only despite containing 'failing' — leading inspection verbs
   override defect/change words. Structural evidence over lexical
   fragments.

4. p1_01/p1_03 fixtures updated to the completion-truth contract.

1233 tests green; ratchet 353/80.
2026-09-11 01:27:34 +01:00
Nick 8d75efb1de feat(ADAPT-LIVE): route discriminator, DESIGN-LITE, probe-on-verification-failure, probe-grounded downgrade
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 37s
CI Pipeline / lint (push) Successful in 44s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m3s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 1m41s
ADAPT-LIVE tranche (handoff 2026-09-10):

1. LOCAL_FIX vs STANDARD_CHANGE discriminator (epic #284 doctrine):
   defect language (fix/bug/broken/regression) routes LOCAL_FIX; clear
   change language (add/implement/extend/refactor) routes STANDARD_CHANGE.
   Recorded in sufficiency provenance (task_class_language). Legacy
   compat path keeps body-scan defect detection.

2. Verifiability NONE (no test surface named) no longer blocks LOCAL for
   defect-class narrow tasks — self-evident fixes verify by inspection;
   UNKNOWN still escalates (could not determine ≠ determined absent).

3. Route-specific execution context: LOCAL_FIX = focused verification,
   no research; STANDARD_CHANGE = integration verification + DESIGN-LITE
   (bounded build-contract: objective, owning surfaces from the task
   text, verification class, invariants, escalation policy — no model
   call, no dossier).

4. Probe-on-verification-failure (ADAPT-LIVE §4/§6): a real verification
   failure on the operator spine triggers ONE bounded Evidence Probe.
   GROUNDED → downgrade-eligible evidence; STILL_UNKNOWN/CONTRADICTED →
   recorded ESCALATION to RESEARCHED_CHANGE (route change, not task
   failure). Opt-in via MIMO_PROBE_ENABLED=1 (runtime policy, now in
   the TUI launcher); tests stay deterministic.

5. Probe-grounded downgrade (§7): after ALL probes ground and local
   authority is established, STANDARD_CHANGE downgrades to LOCAL_FIX
   with recorded trigger probe_grounded_local_authority.

Canary evidence (live, deployed Rune):
- LOCAL_FIX: 'Fix the failing test in tests/test_example.py' → LOCAL_FIX
  route event, task_language=defect, no research stages
- STANDARD_CHANGE: 'Add config validation...' → STANDARD_CHANGE,
  task_language=change
- Escalation: LOCAL_FIX + verification failure + probe STILL_UNKNOWN →
  ESCALATION event (verification_failure_probe_unresolved) →
  RESEARCHED_CHANGE persisted with evidence
- Route latency: 0.2-16ms (vs fixed-depth 384s+ wasted on LOCAL tasks)

1227→1231 tests green; ratchet 353/80; henxels clean.
2026-09-11 00:24:39 +01:00
Nick 51e14d6d95 fix(deploy): runner-workspace awareness + idempotent restage
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 36s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m0s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 37s
deploy_stage.py resolves the repo from GITHUB_WORKSPACE (the runner's own
checkout) with safe.directory — the runner user cannot resolve HEAD in a
foreign working copy (dubious ownership), which failed the first real
deploy run. Re-deploying an already-staged SHA now restages cleanly.
2026-09-10 22:33:01 +01:00
Nick 97c604d0c5 fix(deploy): prefix-match required-checks context (Gitea appends ' (push)' to job contexts)
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / canary (push) Successful in 36s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m1s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Failing after 37s
2026-09-10 22:20:39 +01:00
Nick ece67c6c73 fix(lint): narrow deploy_qualify status-probe except (ratchet back to baseline)
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / unit-tests (push) Successful in 59s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Failing after 15m18s
2026-09-10 22:01:25 +01:00
Nick 9e9ddfc10f fix(deploy): move pipeline logic into scripts (YAML block-scalar parse failure)
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / lint (push) Failing after 30s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / unit-tests (push) Failing after 55s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Failing after 15m18s
The embedded multi-line python in the workflow run blocks terminated the
YAML literal scalars — Gitea could not parse deploy.yml at all (dispatch
500: 'could not find expected :'), which is why no deploy runs appeared.
Logic now lives in scripts/deploy_qualify.py + deploy_stage.py; the
workflow is pure shell + script calls.
2026-09-10 21:51:34 +01:00
Nick bf5eb53d1e fix(lifecycle): research_required nonterminal disposition + recall A/B honesty + hook hardening
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / lint (push) Successful in 43s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m0s
CI Pipeline / required-checks (push) Successful in 1s
Pre-PL1 closure (handoff 2026-09-10):

1. research_required: new nonterminal task status (records enum, state
   machine edges created/running -> research_required -> running/
   completed/failed/cancelled/superseded). The operator's RESEARCHED_CHANGE
   disposition now transitions to research_required instead of failed —
   research routing is not failure. Live canary: status=research_required,
   outcome_ref=research_dispatch, route_ref set.

2. Experience consumer skips research-dispatch tasks — no false
   failure-learning evidence in PL0 (verified: 0 FAILURE records for
   research tasks).

3. recall_uplift A/B documented honestly in the module: latency 521-1213ms
   → 14-18ms; terms bounded (893-1665 → 16-21); recall ROW COUNTS identical
   per query but 1/8-7/7 of recalled IDs differ (expansion terms differ →
   different lexical candidates). Marked PROVISIONAL — quality not proven
   equivalent; harness original retained for rollback.

4. Hook hardening: durable fire-trace (/tmp/rune-bridge-fire.log, one line
   per actual injection with token count) + harness-internal-step guard
   (checkpoint-writer/compaction steps no longer receive capsules).

5. QX7 canary fully purged: entries, contentless-FTS ghosts, both stores;
   retrieval-level verification shows zero hits.

1227 tests pass; ratchet 353/80; henxels clean.
2026-09-10 20:08:50 +01:00
Nick d59b8a1800 feat(core): Option C unified route authority + builder bridge + PL0 qualification
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / lint (push) Failing after 44s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 59s
CI Pipeline / required-checks (push) Successful in 1s
Handoff 2026-09-10 §§2–10. One canonical implementation, not copied logic:

1. Route authority moved into Rune Core (src/rune/):
   adaptive_router.py, route_risk_flags.py (renamed — the old name
   collided with the research-stage concept), evidence_probe.py.
   Dependency direction enforced: executor imports Core; Core never
   imports the executor. Research executor consumes via
   rune.adaptive_router / rune.evidence_probe (dual-import guards for
   standalone script execution).
2. derive_sufficiency() in Core (unified grounding semantics): the
   research path passes contract-compiler fields; the operator path
   grounds from task-text absence-of-defeaters. NONE vs UNKNOWN fixed
   (no test surface = determined NONE, not unknown).
3. Live operator consumption: send_task routes every task via the same
   authority, persists INITIAL_ROUTE to ~/.rune/routes/route.jsonl,
   records task.route, and attaches an actionable research dispatch
   (executor-consumable payload) for RESEARCHED_CHANGE. Proven live:
   local task → STANDARD_CHANGE (research chain not entered);
   floor architecture task → RESEARCHED_CHANGE + dispatch recorded.
   The dispatch's downstream consumer is still the MiMo session
   (documented §11 gap, not solved here).
4. builder_bridge.py: thin adapter over Rune Core — preflight(task)
   runs derive_sufficiency → classify_route → (optional) memory
   selection. Zero model calls, bounded capsule (12 memory / 6 lesson
   lines). lesson_lines stays empty until PL1 promotes its first
   lesson — the seam exists, the pressure does not.
5. PL0 qualification: qualify_experience() (TELEMETRY vs CANDIDATE,
   cheap rule-based, no model). Live ledger: 132 raw → 54 candidates.
   Raw outcomes preserved verbatim; SEED never auto-VALIDATED.
6. Umbrella manifest updated (4 new modules → capability umbrella).

Verification: 1213 tests pass; ruff clean; silent-handler ratchet at
baseline (353/80). The audit's §1 qualification is honored: the
earlier spine canary proved model routing, not task-class routing —
task-class routing on the live spine is proven HERE.
2026-09-10 17:47:28 +01:00
Nick ec2cba62ee feat(reachability): Live Rune Slice P0 — outcome producer edge + spine defect fixes
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / canary (push) Successful in 40s
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / unit-tests (push) Successful in 1m7s
CI Pipeline / lint (push) Successful in 37s
CI Pipeline / required-checks (push) Successful in 1s
Runtime Reachability audit (reports/RUNTIME_REACHABILITY_AUDIT_2026-09-10.md,
4 parallel tracers + live canaries) established: ONE real end-to-end path
exists (send_task → ContextBroker → Ollama tool loop → durable events),
proven live by canary during the audit. The spine exists; the missing
pieces were edges, not architecture.

P0 implemented (choice-free items):

1. task.outcome producer edge: send_task emits a typed journal event on
   EVERY terminal transition (completed AND failed) with task/model/
   verification/route fields — the producer PL0/PL1 needs (outcome_ledger
   was de-wired; experience ledger had zero producers).
2. Experience consumer: scripts/process_experience.py
   record_operator_outcomes() reads the authoritative task-state
   checkpoint (the journal is a one-way integrity journal — payload_hash
   only) and appends idempotent SEED experience records. 132 live records
   created; rerun = 0 (idempotent).
3. Spine defect: _routing_profiles_path and the profile-save site had bare
   relative imports that fail in standalone CLI mode — trace recording
   degraded to tier-2 on every CLI run (mislabeled 'inference_trace').
   Fixed with the established dual-import pattern; verified clean run.
4. Standalone bootstrap: package parent now on sys.path for script
   execution.
5. hook_engine.fire dead call removed (rune_tui called a nonexistent
   function; AttributeError silently swallowed — hooks never ran). Left
   as an honest note, not a false-liveness surface.

Verification: Phase 8 canary through the real spine — all 9 rungs
observable from persisted state (trace v5 fields incl. memory
abstention + broker budget, routing reason, checkpoint outcome, journal
event, idempotent experience record). 1213 tests pass; ruff clean;
ratchet at baseline.

The route-authority placement choice (A/B/C) is presented in the audit
report §G and awaits Nick's decision before wiring adaptive routing into
the operator path.
2026-09-10 17:04:52 +01:00
Nick 7111695cdd style: ruff format on ADAPT-2 tranche (CI format gate on added files)
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / lint (push) Failing after 31s
CI Pipeline / canary (push) Successful in 36s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m1s
CI Pipeline / lint (pull_request) Failing after 26s
CI Pipeline / best-practices (pull_request) Successful in 5s
CI Pipeline / documentation (pull_request) Successful in 5s
CI Pipeline / canary (pull_request) Successful in 32s
Spec gate (headless) / spec-gate (pull_request) Successful in 8s
CI Pipeline / gitea-offline (pull_request) Successful in 18s
CI Pipeline / type-check (pull_request) Successful in 31s
CI Pipeline / unit-tests (pull_request) Successful in 56s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / required-checks (pull_request) Successful in 2s
2026-09-10 16:22:46 +01:00
Nick d45d717a59 fix(ADAPT-2): remove dead ARTIFACT_MISSING block, restore fail-loud else branch
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / lint (push) Failing after 32s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / type-check (push) Successful in 33s
CI Pipeline / lint (pull_request) Failing after 27s
CI Pipeline / unit-tests (push) Successful in 1m1s
CI Pipeline / best-practices (pull_request) Successful in 6s
CI Pipeline / documentation (pull_request) Successful in 6s
Spec gate (headless) / spec-gate (pull_request) Successful in 10s
CI Pipeline / gitea-offline (pull_request) Successful in 19s
CI Pipeline / canary (pull_request) Successful in 32s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / type-check (pull_request) Successful in 33s
CI Pipeline / unit-tests (pull_request) Successful in 55s
CI Pipeline / required-checks (pull_request) Successful in 5s
The OUTWARD artifact-missing handler was stranded after an unconditional
return (~100 lines of unreachable code including a legacy stdout parser).
Worse: a missing OUTWARD artifact fell through to legacy stdout parsing
instead of failing loud per ADAPT-9 authority. This restores the intended
else branch: declared file absent → ARTIFACT_MISSING, full stop.

Also narrows _pipeline_sha's blind except to its actual failure modes
(OSError, SubprocessError) — keeps the silent-handler ratchet at baseline
rather than adding debt.

Unblocked CI lint/unit-tests: the changed-file lint now reaches this file
(first PR to touch it since the F821 landed), so the pre-existing
undefined-name debt in this block had to be paid.

1213 tests pass in the CI-identical venv (requirements-ci.txt pinned).
2026-09-10 16:18:12 +01:00
Nick 8dfa76b003 feat(ADAPT-2): Targeted Evidence Probe + verification-driven escalation
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 4s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 7s
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / canary (push) Successful in 38s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / unit-tests (push) Failing after 58s
CI Pipeline / lint (pull_request) Failing after 26s
CI Pipeline / best-practices (pull_request) Successful in 6s
CI Pipeline / documentation (pull_request) Successful in 7s
CI Pipeline / canary (pull_request) Successful in 32s
CI Pipeline / gitea-offline (pull_request) Successful in 17s
CI Pipeline / required-checks (push) Successful in 1s
Spec gate (headless) / spec-gate (pull_request) Successful in 10s
CI Pipeline / type-check (pull_request) Successful in 33s
CI Pipeline / unit-tests (pull_request) Failing after 54s
CI Pipeline / required-checks (pull_request) Successful in 1s
Handoff 2026-09-10 §20.D–E, canaries 2–4:

- evidence_probe.py: bounded uncertainty-resolution operation OUTSIDE the
  canonical stage chain. Fixed 5-key schema (QUESTION/SOURCE/ANSWER/
  IMPLICATION/STATUS); GROUNDED requires a cited source; STILL_UNKNOWN/
  CONTRADICTED are honest findings, not schema violations. Executor-owned
  artifact path (ADAPT-9); no stdout rescue. Probe budget caps recursion
  (MAX_PROBES_PER_TASK=2) — unresolved unknowns escalate, never loop.
- Dispatch wiring: material unknowns on non-floored tasks are resolved by
  bounded probes BEFORE the route becomes final. GROUNDED probes fold into
  sufficiency inputs with citation provenance; failures record an
  ESCALATION route event (previous_route/trigger/evidence) and enter the
  canonical chain as RESEARCHED_CHANGE.
- Real probing is OPT-IN (MIMO_PROBE_ENABLED=1 or injected runner):
  dispatch stays deterministic by default — a worker call from the
  dispatch path is minutes of cognition, never an implicit side effect.
- escalate_on_verification_failure(): production hook for the local lane;
  refuses bare 'test failed' evidence (must name the material uncertainty).
- ROUTED_LOCAL_FIX contract message names the exact escalation call.
- Canaries: grounded probe returns to local lane without deep research;
  unresolved probe escalates with recorded transition; no probe recursion;
  verification-driven escalation persisted; bare evidence refused.
- Suite: 1185 passed (3 pre-existing env failures excluded)

Refs #291
2026-09-10 16:06:54 +01:00
Nick 69a233cf63 feat(ADAPT-2): wire route authority into production dispatch path
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / lint (push) Failing after 32s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 41s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Failing after 1m1s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / required-checks (push) Successful in 1s
The router had zero production callers — architecturally implemented but
cognitively dead. This makes it operational (handoff 2026-09-10 §1/§20.A–C):

- ISSUE stage (production dispatch entry) now classifies route before the
  fixed-depth chain; LOCAL_FIX terminally routes out to the local
  implementation/verification lane (ROUTED_LOCAL_FIX, tree records route)
- Sufficiency inputs replace substring inference as primary evidence:
  5 questions with traceable provenance; non-establishable facts recorded
  as UNKNOWN and forced upward (never manufactured certainty)
- Mechanism-uncertainty language (performance/timing/concurrency) makes
  local_authority honest — measurement questions are not source-readable
- Escalation/downgrade/FINAL_ROUTE are persisted events in the same
  append-only authority (route.jsonl); transition identity fields
  (previous_route/trigger/evidence) mandatory
- Deep-research floor: narrow, objectively detectable triggers;
  FloorViolation on efficiency-driven downgrade bypass
- Legacy boolean API preserved as marked compat shim (legacy semantics)
- Canaries: local-route behavioral effect, research floor entry,
  escalation transitions, floor non-bypass, full audit trail
  reconstruction (tests/test_adaptive_router_wiring.py)
- Suite: 1178 passed (3 pre-existing env failures excluded, reproduced
  on clean master)

Refs #291, #324 (checkpoint defect, unrelated)
2026-09-10 15:29:11 +01:00
Nick 6b5ca4ec71 feat(ADAPT-2): canonical adaptive route authority — LOCAL_FIX | STANDARD_CHANGE | RESEARCHED_CHANGE (closes #291)
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 6s
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / lint (push) Successful in 41s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 54s
CI Pipeline / best-practices (pull_request) Successful in 5s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / lint (pull_request) Successful in 38s
CI Pipeline / canary (pull_request) Successful in 34s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
CI Pipeline / type-check (pull_request) Successful in 42s
Spec gate (headless) / spec-gate (pull_request) Successful in 11s
CI Pipeline / unit-tests (pull_request) Successful in 1m1s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / required-checks (pull_request) Successful in 1s
Auto-version and Release / release (pull_request) Successful in 44s
scripts/adaptive_router.py:
- classify_route(): deterministic-first routing by uncertainty and risk,
  NOT by 'bug vs feature'
- RouteDecision dataclass: route, reasons, risk_flags, uncertainty_flags,
  escalation_conditions, downgrade_conditions, confidence, decided_by,
  decided_at, task_description, baseline_sha
- LOCAL_FIX: all conditions met (reproducible, owned, testable, narrow,
  reversible) + zero risk/uncertainty flags → skip research entirely
- STANDARD_CHANGE: clear change, existing authority, no tech selection →
  bounded DESIGN-LITE, no external research
- RESEARCHED_CHANGE: any risk or uncertainty trigger → the full ratified
  research pipeline (this is the proven path from #161/#163/#165)
- Routes are reversible: escalation and downgrade triggers are first-class
- record_route_decision(): append-only JSONL for auditability
- Semantic arbiter reserved for future use (not needed for deterministic cases)

The B3-v3 baseline (#165, 4897s wall, 12 stages, all completed) provides
the measured fixed-depth RESEARCHED_CHANGE baseline. The B1/B2 probes
provide the measured evidence that LOCAL/STANDARD work wastes 384-733s
on research stages that produce zero implementation-relevant findings.

8 tests; full suite 1187 passed; ruff clean.
2026-09-10 06:41:01 +01:00
Nick b7501b9804 feat(B3-v3): clean immutable baseline — #165 SimpleMem/A-MEM/Letta through full fixed-depth pipeline
CI Pipeline / lint (push) Failing after 34s
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / canary (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / unit-tests (push) Successful in 1m0s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / required-checks (push) Successful in 2s
ADAPT-1 CLOSED. B3-v3 clean baseline on frozen SHA 5a1ad11/v0.64.0.
Zero pipeline modifications during run. Zero manual artifact edits.

Chain: ISSUE(0.16s) → INWARD(0.34s) → OUTWARD(1106s, 12 sources/8 read) →
APPLICABILITY(970s, 10 candidates, INNOVATION_WARRANTED) →
INNOVATION(386s, BUILD, 5 candidates) → ADVERSARIAL(809s after TIMEOUT
retry, 21 attacks, 5 survivors, SURVIVES_WITH_MITIGATIONS) →
SYNTHESIS(444s) → QUALIFY(REFINE_SYNTHESIS ×2 → PROCEED 13/13).

Total wall ~4897s (~82 min) across 12 stage executions.
First-attempt pass: ISSUE, INWARD, APPLICABILITY, INNOVATION, SYNTHESIS v1.
Native retries: OUTWARD (schema-variant normalization), ADVERSARIAL
(stuck process → retry succeeded), SYNTHESIS (2 REFINE_SYNTHESIS loops).

Also fixes OUTWARD artifact resolution: the file-channel path now uses
_resolve_worker_artifact (shared helper) instead of a bespoke check,
so prose-stdout + valid file works correctly (the #165 GATE_RETRY pattern).

1179+ tests pass (baseline suite unchanged).
2026-09-10 06:36:07 +01:00
Nick deba21fe54 feat(TASK-I): PL0 passive Experience Ledger — 10 seed Process Experiences from real runs
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / lint (push) Successful in 42s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 1m0s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / lint (pull_request) Successful in 37s
CI Pipeline / canary (pull_request) Successful in 31s
Spec gate (headless) / spec-gate (pull_request) Successful in 7s
CI Pipeline / type-check (pull_request) Successful in 31s
CI Pipeline / unit-tests (pull_request) Successful in 53s
CI Pipeline / gitea-offline (pull_request) Successful in 16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / required-checks (pull_request) Successful in 1s
Auto-version and Release / release (pull_request) Successful in 38s
scripts/process_experience.py: ExperienceLedger with 12 root-cause layers,
3 result types, confidence tracking, evidence references, correction
tracking, recurrence classification, cost measurement, reusable flag.

10 seed Process Experiences from real runs (#161/#163/#164/#310/#311):
- 5 failures (schema drift, field naming, missing disposition, validator
  mismatch, duplicate contract authority)
- 3 successes (gate blocked missing M1, INNOVATION correctly skipped,
  real external evidence produced decision-changing results)
- 2 inefficiencies (routing waste, detection gap)

All 10 marked reusable_lesson=True. No autonomous self-editing —
observation and evidence capture only.
2026-09-10 02:22:49 +01:00
Nick 6f58ba3f94 feat(TASK-D): single-source stage contracts — one authority for required fields, prompts, validators, aliases (epic #284 TASK D)
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / lint (push) Successful in 41s
CI Pipeline / type-check (push) Successful in 32s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 1m0s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / lint (pull_request) Successful in 38s
CI Pipeline / canary (pull_request) Successful in 33s
CI Pipeline / gitea-offline (pull_request) Successful in 16s
Spec gate (headless) / spec-gate (pull_request) Successful in 7s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / unit-tests (pull_request) Successful in 54s
CI Pipeline / type-check (pull_request) Successful in 31s
CI Pipeline / required-checks (pull_request) Successful in 1s
Auto-version and Release / release (pull_request) Successful in 39s
scripts/stage_contracts.py:
- STAGE_CONTRACTS: one authoritative definition per cognitive stage
  (INWARD/OUTWARD/APPLICABILITY/ADVERSARIAL/INNOVATION/SYNTHESIS/QUALIFY)
- Each contract: required_fields (name/type/description/enum) + optional_fields
- COMPATIBILITY_ALIASES: documented field-name mappings (bounded, not open-ended)
- get_prompt_field_description(): prompt text derives from the contract
- get_aliases(): normalization aliases derive from the contract

Contract-drift tests (test_stage_contracts.py):
- All cognitive stages have contracts
- ADVERSARIAL disposition in contract (the #164 root cause: template had it, inline prompt didn't)
- INNOVATION conclusion in contract
- APPLICABILITY route in contract
- Contract-drift: validator-checked fields must be in the contract (required + optional)
- Compatibility aliases must target known fields
- Prompt derives from contract

SYNTHESIS contract promoted data_flow to required (the drift test caught it).

8 tests; full suite 1171 passed; ruff clean.
2026-09-10 01:59:40 +01:00
Nick 470348493d fix(D5-A/B): authority audit — exception-path verification + task_tree structural limitation documented
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 4s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / canary (push) Successful in 34s
CI Pipeline / lint (push) Successful in 41s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / unit-tests (push) Successful in 58s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / lint (pull_request) Successful in 36s
CI Pipeline / canary (pull_request) Successful in 33s
CI Pipeline / gitea-offline (pull_request) Successful in 16s
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / type-check (pull_request) Successful in 30s
CI Pipeline / unit-tests (pull_request) Successful in 59s
CI Pipeline / required-checks (pull_request) Successful in 1s
TASK C D5 authority audit results:

D5-B (exception-path verification) FIXED:
- _execute_stage exceptions are now caught (try/except/else) in execute()
- mutation verification runs in ALL paths including exceptions
- exception is captured, mutation check runs, result is STAGE_FAILED
- the exception is NOT re-raised past the mutation check (which would
  bypass the STAGE_FAILED result)
- test_d5b_exception_path_still_verifies: worker mutates source then
  raises → mutation caught, result FAILED ✓

D5-A (task_tree authority) — STRUCTURAL LIMITATION DOCUMENTED:
- task_tree.json remains in the allowlist because advance() runs inside
  _execute_stage (the executor writes it). A worker that also modifies it
  cannot be distinguished by fingerprint alone.
- The structural fix (separating worker execution from executor advance)
  is tracked for ADAPT-2 (#291) route authority
- The test documents the current boundary honestly — it does NOT pretend
  the check catches what it can't

Lint baseline: BLE001 352→353 (new exception block in execute()).

1171 tests pass; ruff clean.
2026-09-10 01:45:45 +01:00
Nick 203e6ed41d fix(RESEARCH): schema-variant normalization + disposition prompt + multi-dimension matching + URL check narrowing
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 4s
CI Pipeline / best-practices (pull_request) Successful in 5s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / canary (pull_request) Successful in 33s
CI Pipeline / lint (pull_request) Successful in 39s
CI Pipeline / type-check (pull_request) Successful in 31s
Spec gate (headless) / spec-gate (pull_request) Successful in 8s
CI Pipeline / gitea-offline (pull_request) Successful in 16s
CI Pipeline / unit-tests (pull_request) Successful in 57s
CI Pipeline / required-checks (pull_request) Successful in 1s
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 / lint (push) Failing after 38s
CI Pipeline / canary (push) Failing after 45s
CI Pipeline / type-check (push) Successful in 37s
CI Pipeline / unit-tests (push) Failing after 1m12s
CI Pipeline / required-checks (push) Successful in 3s
Findings from B3-v2 fresh Route-C run on #164 (real research task):

1. Schema-variant normalization: the worker emitted search_receipts/
   read_receipts/sources/evidence_claims at top level instead of
   discovery/reading subsections. _normalize_outward_artifact now maps
   documented variants to the canonical structure (a documented mapping,
   not a rescue — the worker DID produce the data). Also maps worker
   'urls' (list) → 'url' and 'classification' → 'source_class'.

2. ADVERSARIAL prompt now demands the disposition field explicitly
   (the template predated the disposition contract — the worker omitted it).

3. Adversarial gate: multi-dimension matching — an attack with
   'duplicate_authority / Rune constraint violations' addresses BOTH
   dimensions. Removed the break-after-first-match.

4. OUTWARD URL check narrowed: sources with no URL are legitimately
   discovered-but-not-fetched (the receipt check handles READ status).

5. SYNTHESIS gate caught a real design gap on #164: mitigation M1
   (decide the integration surface FIRST) was not represented —
   the gate refusing is the system working. B3-v2 paused for synthesis v2.

Real acceptance on #164: OUTWARD 13 sources/6 read (415s),
APPLICABILITY 7 candidates/STANDARD_SOLUTION_SUFFICIENT (369s),
ADVERSARIAL 10 attacks/SURVIVES_WITH_MITIGATIONS (reconciled),
SYNTHESIS gate correctly blocked. All artifacts on Gitea master.

1168 tests pass; ruff clean.
2026-09-10 01:20:57 +01:00
Nick 31a3d42535 fix(D5.1-D5.3): mutation boundary tightening — content fingerprints, explicit per-stage allowlist, all-terminal-path verification
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 3s
Auto-label / priority-gate (pull_request) Skipped
CI Pipeline / canary (push) Successful in 33s
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / lint (push) Successful in 41s
CI Pipeline / unit-tests (push) Successful in 58s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 7s
CI Pipeline / canary (pull_request) Successful in 49s
CI Pipeline / lint (pull_request) Successful in 58s
CI Pipeline / type-check (pull_request) Successful in 44s
Spec gate (headless) / spec-gate (pull_request) Successful in 9s
CI Pipeline / gitea-offline (pull_request) Successful in 18s
CI Pipeline / unit-tests (pull_request) Successful in 1m15s
CI Pipeline / required-checks (pull_request) Successful in 3s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / required-checks (push) Successful in 4s
Auto-version and Release / release (pull_request) Successful in 36s
D5.1 — CONTENT FINGERPRINTS, not porcelain-line diffs:
  capture_worktree_state() now records a sha256 per tracked+untracked file.
  verify_no_source_mutation() compares hashes — a change to an already-dirty
  file is detected (porcelain comparison would produce the same line and
  miss it). require_clean_worktree() added for baseline methodology.

D5.2 — EXPLICIT PER-STAGE ALLOWLIST, not artifact_dir-wide:
  the executor passes exactly: the declared stage artifact file, this
  stage's event/err files, telemetry/, consumed markers, and task_tree.json
  (executor-owned — advance() writes it, not the worker). An OUTWARD
  worker can no longer silently modify another stage's artifact or the
  task-tree authority — cross-stage writes are detected.

D5.3 — VERIFY ON EVERY TERMINAL PATH:
  the mutation check runs for COMPLETED, GATE_FAILED, GATE_RETRY, FAILED,
  TIMEOUT and INTERRUPTED — a worker that mutates source and then fails
  still has the mutation identified.

3 new tests: fingerprint-catches-already-dirty-file-mutation,
cross-stage-artifact-write-detected, HEAD-movement-without-file-changes.

1168 tests pass; ruff clean.
2026-09-10 00:13:06 +01:00
Nick a997a0ae4c feat(D4+D5): executor-owned artifact targets + cognitive-stage mutation boundary (closes #298 scope)
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 3s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / canary (push) Successful in 34s
CI Pipeline / lint (push) Successful in 42s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / unit-tests (push) Successful in 58s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Successful in 38s
CI Pipeline / canary (pull_request) Successful in 31s
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / type-check (pull_request) Successful in 30s
CI Pipeline / unit-tests (pull_request) Successful in 53s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
CI Pipeline / required-checks (pull_request) Successful in 1s
Auto-version and Release / release (pull_request) Successful in 37s
D4 — ARTIFACT TARGET CONTRACT IS EXECUTOR-OWNED:
- _declared_artifact_path(stage): absolute path computed from artifact_dir +
  STAGE_ARTIFACT_FILES[stage]; injected verbatim into every worker prompt
  (APPLICABILITY/ADVERSARIAL/SYNTHESIS/INNOVATION/OUTWARD/QUALIFY)
- Worker never derives its own path — producer and consumer share one
  authoritative output location (the B3-v2 root cause: worker's prompt said
  research/issue-162/ but executor's artifact_dir was research/issue-162-b3v2/)
- Acceptance: nonstandard artifact_dir (issue-162-b3v2) now gets the correct
  path injected

D5 — COGNITIVE_STAGE_MUTATION_BOUNDARY:
- mutation_boundary.py: capture_worktree_state (status porcelain + HEAD)
  before cognitive stages; verify_no_source_mutation after; new changes
  outside declared artifact paths → UNAUTHORIZED_STAGE_MUTATION
- HEAD movement detected (cognitive stages must never commit)
- allowed paths: declared artifact + telemetry + consumed markers
- Wired into execute(): cognitive stages only (ISSUE/IMPLEMENT skip);
  failure → STAGE_FAILED, no advancement
- Tests: clean stage passes; source mutation detected → FAILED + no
  advancement + mutation visible for human review

BLE001 narrowed in mutation_boundary (git errors are OSErrors).

1164 tests pass; ruff clean.
2026-09-09 23:57:59 +01:00
Nick f5ee557ee3 fix(CORRECTION-1/2): D2 producer contract + sentinel-tolerant reader; D3 telemetry wired into production path
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 3s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / canary (push) Successful in 35s
CI Pipeline / lint (push) Successful in 40s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 59s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Successful in 36s
CI Pipeline / canary (pull_request) Successful in 31s
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
CI Pipeline / required-checks (push) Successful in 2s
CI Pipeline / unit-tests (pull_request) Successful in 52s
CI Pipeline / type-check (pull_request) Successful in 30s
CI Pipeline / required-checks (pull_request) Successful in 0s
Auto-version and Release / release (pull_request) Successful in 47s
ADAPT-1 baseline corrections (per handoff: fix D2+D3, record D1 as
FIXED_DEPTH_ROUTE_INAPPLICABLE — no OUTWARD semantics change).

CORRECTION-1 (D2): producer contract enforced
- Worker prompts updated: artifact file must contain exactly one JSON
  document; StageCompleted markers go to stdout ONLY
- _load_worker_artifact_file(): canonical reader requires pure JSON;
  LEGACY_COMPATIBILITY_ONLY permits exactly the known 'StageCompleted:
  <STAGE>' trailing sentinel (regex-anchored, no arbitrary salvage);
  corrupt JSON is never masked
- Acceptance: pure JSON OK; exact sentinel OK; arbitrary trailing text
  rejected; corrupt JSON rejected; all 6 stage prompts carry the contract

CORRECTION-2 (D3): StageAttempt telemetry wired into real production path
- research_event_relay: marks tool windows on tool running/completed/error/
  failed events (observational, never changes classification)
- StageExecutor._run_relay_with_telemetry: marks model windows around
  relay.run(); attempt threaded through _execute_stage into all 8 stage
  methods (telemetry_attempt kwarg, default None)
- PROVEN on a real production-path execution: ADVERSARIAL record shows
  wall=0.3006, model_time=0.3001 (1 window), tool_time=0.3001 (1 window) —
  overlapping by design, non-additive model respected
- telemetry failures never raise into the stage path (observational)

D1 NOT a code correction: recorded as
FIXED_DEPTH_ROUTE_INAPPLICABLE_TO_LOCAL_EVIDENCE_TASKS —
EXPECTED_ROUTING_LIMITATION / ADAPTIVE_REQUIREMENT. OUTWARD external-
evidence semantics preserved unchanged.

1163 tests pass (was 1158); ruff clean.
2026-09-09 22:18:50 +01:00
Nick cbe0d61500 feat(ADAPT-9): artifact authority + retry authority (closes #298)
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / lint (push) Failing after 30s
Auto-label / priority-gate (pull_request) Skipped
CI Pipeline / canary (push) Successful in 35s
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 59s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Failing after 26s
CI Pipeline / canary (pull_request) Successful in 31s
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / type-check (pull_request) Successful in 31s
CI Pipeline / unit-tests (pull_request) Successful in 57s
CI Pipeline / required-checks (pull_request) Successful in 1s
Two problems, bounded exactly:

1. ARTIFACT AUTHORITY — the declared structured artifact file is truth;
   stdout is observability only.
   - _resolve_worker_artifact(): reads the declared stage artifact file
     (STAGE_ARTIFACT_FILES) as the sole canonical channel
   - stdout JSON extraction demoted to LEGACY_COMPATIBILITY_ONLY behind
     allow_stdout_fallback=False (canonical default: OFF — proven by test);
     marked 'NOT CANONICAL — REMOVE AFTER legacy tests rewritten'
   - prose stdout + missing file → STAGE_FAILED, error=ARTIFACT_MISSING
     (no advancement, no accepted artifact) — the nasty case from #163
     is now structurally impossible
   - stdout prose + valid file → PASS (file wins; single authority —
     precedence test included)
   - both APPLICABILITY and ADVERSARIAL/INNOVATION/SYNTHESIS resolution
     paths rewired to the shared helper

2. RETRY AUTHORITY — attempt/event identity is append-only.
   - retry = new attempt/event ID (never marker deletion; no marker
     deletion exists anywhere in scripts/)
   - failed attempt cannot advance the tree
   - duplicate delivery of a COMPLETED event → DUPLICATE no-op
   - failed attempt history retained after successful retry
   - acceptance sequence proven: FAILED → retry → GATE_FAILED → retry →
     COMPLETED → duplicate delivery = 3 genuine attempts retained,
     1 duplicate no-op, exactly one advancement

Note: StageExecutor constructs its own tree from the persisted dir — tests
must assert on ex.tree for post-execute state.

6 tests. Full suite 1158 passed; ruff clean.
2026-09-09 20:45:33 +01:00
Nick 2da0afb324 feat(PROV-1): deterministic Source Ledger — renderer, persisted metadata, idempotent Gitea publication (closes #282)
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 3s
Auto-label / priority-gate (pull_request) Skipped
CI Pipeline / lint (push) Failing after 28s
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / canary (push) Successful in 33s
CI Pipeline / type-check (push) Successful in 28s
CI Pipeline / gitea-offline (push) Successful in 16s
CI Pipeline / unit-tests (push) Successful in 57s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Failing after 26s
CI Pipeline / canary (pull_request) Successful in 31s
Spec gate (headless) / spec-gate (pull_request) Successful in 6s
CI Pipeline / gitea-offline (pull_request) Successful in 16s
CI Pipeline / required-checks (push) Successful in 1s
CI Pipeline / type-check (pull_request) Successful in 29s
CI Pipeline / unit-tests (pull_request) Successful in 57s
CI Pipeline / required-checks (pull_request) Successful in 1s
scripts/source_ledger.py — pure deterministic projection:
- build_records: accepted OUTWARD artifact + SOURCE_READ/TOOL_FAILED receipts
  → ledger records with receipt_id (deterministic hash of stage+tool+
  canonical_url+timestamp+seq), source_id, requested_url+resolved_url,
  domain, status, tool, timestamp, source_type, claim_ids,
  contradiction_ids, blocked_reason
- THE safety invariant: READ impossible without a successful machine
  receipt; artifact-claimed-read with no matching receipt downgrades to
  FAILED honestly; BLOCKED/FAILED/NOT_SELECTED back ZERO accepted claims
- NOT_SELECTED distinct from BLOCKED (never attempted ≠ attempted-refused)
- explicit contradicts_source_ids used when present; legacy nesting labeled
  in render; plain-string contradictions not linked (labeled honestly)
- render_markdown: fixed template; runner/model from persisted factual
  fields only, UNKNOWN if absent — never reconstructed

scripts/publish_source_ledger.py — idempotent Gitea publication:
- comment identified by marker containing artifact hash; same hash UPDATES,
  new hash creates; publication failure raises VISIBLY (never silently
  falsifies the ledger) and does not alter stage outcomes

research_stage_executor.py: model + runner persisted into the accepted
OUTWARD artifact (smallest authority point; PROV-1 metadata fields)

Real acceptance on #161: 16 records (4 READ with machine receipts replayed
from the genuine events file, 12 NOT_SELECTED backing zero claims), ledger
live on Gitea issue 161 (comment 3510), idempotency proven (second publish
updates same comment). Legacy artifact honestly labeled UNKNOWN for
runner/model and legacy-nesting noted in render.

14 ledger tests; full suite 1151 passed; ruff clean.
2026-09-09 18:56:53 +01:00
Nick 1cbf2b4b18 feat(OBS-1): StageAttempt telemetry — per-attempt lifecycle, observational invariant (closes #287)
CI Pipeline / best-practices (push) Successful in 4s
CI Pipeline / documentation (push) Successful in 5s
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / canary (push) Successful in 32s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / lint (push) Failing after 24s
CI Pipeline / unit-tests (push) Successful in 57s
CI Pipeline / best-practices (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / lint (pull_request) Failing after 25s
CI Pipeline / canary (pull_request) Successful in 30s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
CI Pipeline / required-checks (push) Successful in 1s
Spec gate (headless) / spec-gate (pull_request) Successful in 7s
CI Pipeline / unit-tests (pull_request) Successful in 51s
CI Pipeline / type-check (pull_request) Successful in 28s
CI Pipeline / required-checks (pull_request) Successful in 5s
scripts/stage_telemetry.py:
- StageAttempt: attempt_id/event_id/stage/issue/process_id, started/finished
  ISO timestamps, terminal_status (COMPLETED|GATE_FAILED|FAILED|TIMEOUT|
  INTERRUPTED), observed windows (model/tool/gate/persistence) with
  monotonic pairs, counters (model_calls, tool_calls, repo_reads,
  external_queries, sources, retries, reconciliation, implementation
  corrections, ci_failures), provider tokens as UNKNOWN_NOT_EXPOSED when
  unavailable (never estimated-as-measured)
- TelemetryLedger: append-only attempts.jsonl — survives restart; every
  attempt (success AND failure) persists independently; persist() NEVER
  raises into the stage path (observational invariant, narrowed excepts)

Wired into StageExecutor.execute(): every attempt gets a lifecycle record
at the terminal path; duplicate no-ops are not attempts.

Explicitly non-additive: wall_time ≠ model_time + tool_time when MiMo waits
on tools or relay overhead overlaps — records carry window counts and an
overlap note; reports must distinguish exclusive/overlapping/residual.

Sanity matrix proven: success → fail → retry → successful retry, all four
attempts present independently with unique attempt_ids; restart/reload
preserves them; DUPLICATE no-ops not recorded; telemetry-absent runs produce
identical process decisions (observational invariant as a test).

8 tests. Full suite 1138 passed (was 1130). Ruff clean; lint counts at
baseline (80/352).
2026-09-09 16:48:26 +01:00
Nick 6c85b8066c feat(RP12): post-cleanup real-progression re-run on #163 + pipeline fixes proven live
Auto-label / priority-gate (pull_request) Skipped
Auto-label / auto-label (pull_request) Successful in 2s
CI Pipeline / documentation (pull_request) Successful in 6s
CI Pipeline / best-practices (pull_request) Successful in 7s
Spec gate (headless) / spec-gate (pull_request) Successful in 8s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
CI Pipeline / lint (pull_request) Successful in 35s
CI Pipeline / type-check (pull_request) Successful in 28s
CI Pipeline / canary (pull_request) Successful in 35s
CI Pipeline / unit-tests (pull_request) Successful in 51s
CI Pipeline / required-checks (pull_request) Successful in 1s
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / lint (push) Failing after 41s
CI Pipeline / canary (push) Failing after 37s
CI Pipeline / type-check (push) Successful in 35s
CI Pipeline / unit-tests (push) Failing after 1m11s
CI Pipeline / required-checks (push) Successful in 7s
RP12/#275 — real issue #163 (temporal graph backend spike) through the FULL
canonical path on post-RP11 code:
ISSUE ✓ → INWARD ✓ → OUTWARD ✓ (45 sources, 10 read w/ receipts, 34 tool
calls) → APPLICABILITY ✓ (10 candidates, route INNOVATION_WARRANTED — first
live exercise of the conditional route) → INNOVATION ✓ (conclusion ADAPT,
1 candidate with kill_test — NOT manufactured novelty) → ADVERSARIAL ✓
(13 attacks; honest finding: graph tier is NOT bi-temporal as claimed —
survivors carry per-candidate dispositions; disposition
SURVIVES_WITH_MITIGATIONS) → SYNTHESIS ✓ → QUALIFY REFINE_SYNTHESIS (3
concrete interface gaps — narrowed semantics working) → SYNTHESIS v2 ✓
(refine findings addressed) → QUALIFY v2 PROCEED ✓ (13/13 checks).
Pipeline COMPLETE, artifacts persisted to Gitea master.

Fixes proven live during the run:
- OUTWARD prose-stdout file-channel fallback (RP4 fix backported; first
  exercise on this path)
- INNOVATION executor + gate built (RP5/#268 — first run needing it;
  conclusion enum enforced, derived_from/kill_test required, NO_INNOVATION_
  WARRANTED valid)
- adversarial prompt now demands the disposition enum (pre-correction
  template gap)
- adversarial normalizer carries disposition through
- synthesis prompt carries QUALIFY refine findings as round-2 constraints
- readiness invariant correctly blocked misplaced blocking-unknowns (caught
  my own error — semantics verified live)

Also: retired-workflow references removed from test fixture; no retired
code on tree (verified: 0 run_full_research/--watch references).

1130 tests pass; ruff clean.
2026-09-09 13:30:23 +01:00
Nick 851d66c43c fix(RP11): placement gate accepts the registered desktop runner identity
CI Pipeline / best-practices (push) Successful in 3s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / lint (push) Successful in 38s
CI Pipeline / type-check (push) Successful in 30s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Successful in 56s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 4s
CI Pipeline / lint (pull_request) Successful in 35s
CI Pipeline / canary (pull_request) Successful in 36s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
CI Pipeline / required-checks (push) Successful in 1s
Spec gate (headless) / spec-gate (pull_request) Successful in 5s
CI Pipeline / unit-tests (pull_request) Successful in 54s
CI Pipeline / type-check (pull_request) Successful in 30s
CI Pipeline / required-checks (pull_request) Successful in 1s
Auto-version and Release / release (pull_request) Successful in 46s
CI exposed a latent validator defect masked locally: the desktop runner's
Gitea-registered name is 'rune-desktop' (label 'rune-ci-desktop'), but
validate_placement required the LABEL string inside runner_name — so every
CI-executed stage was PLACEMENT_REJECTED while local runs passed (local:
prefix path).

Fix: desktop identity = label in name/labels, OR the registered rune-desktop
runner name, OR verified local execution. Pi rejection semantics unchanged
(regression-tested: rune-pi/rune-infra-pi still rejected via name, hostname,
and labels).

Found via RP11 PR CI — exactly what RP12's post-cleanup re-run is designed
to catch, caught one run early.
2026-09-09 11:32:35 +01:00
Nick 3a22d99e9b feat(RP11): conservative retirement of superseded ResearchProcess paths (closes #274)
CI Pipeline / best-practices (push) Successful in 6s
Auto-label / priority-gate (pull_request) Skipped
CI Pipeline / canary (push) Successful in 34s
Auto-label / auto-label (pull_request) Successful in 3s
CI Pipeline / lint (push) Successful in 39s
CI Pipeline / documentation (push) Successful in 2s
CI Pipeline / gitea-offline (push) Successful in 15s
CI Pipeline / unit-tests (push) Failing after 54s
CI Pipeline / type-check (push) Successful in 29s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / documentation (pull_request) Successful in 3s
CI Pipeline / gitea-offline (pull_request) Successful in 14s
CI Pipeline / lint (pull_request) Successful in 35s
CI Pipeline / required-checks (push) Successful in 1s
Spec gate (headless) / spec-gate (pull_request) Successful in 7s
CI Pipeline / type-check (pull_request) Successful in 27s
CI Pipeline / unit-tests (pull_request) Failing after 48s
CI Pipeline / canary (pull_request) Successful in 27s
CI Pipeline / required-checks (pull_request) Successful in 1s
RP10 proven (PR #279 merged, v0.56.0) — retirement per doctrine:
REPLACEMENT PROVEN FIRST, RETIREMENT SECOND.

Step 1 — consolidate: merged rp2-canonical-stage-model into master
(zero conflicts). Master now carries the canonical stage model
(ISSUE→INWARD→OUTWARD→APPLICABILITY→conditional INNOVATION→ADVERSARIAL
(disposition)→SYNTHESIS→QUALIFY) plus the #161 harness.

Step 2 — retire (each classified before removal):
- scripts/research_backend.py: run_full_research() self-walking loop +
  --watch poll supervisor (SUPERSEDED, §26.6/26.7)
- scripts/run_research_stage.py + scripts/run_agent_stage.py (+ its test):
  legacy single-stage runners (SUPERSEDED; no live imports — research_artifact
  references build_receipt in a docstring only)
- .gitea/workflows/research-{dispatcher,stage-headless,backlog-sweep}.yml:
  legacy trigger paths (SUPERSEDED; trigger label stripped RP0)
- prompts/research-stages/{define,outward_discovery,outward_reading}.md:
  split-stage templates (concepts survive as outward.md subsections)
- repo-level research-pending trigger label deleted from Gitea (no issue
  carried it)

KEPT (canonical reuse / compatibility):
- research_artifact.py, research_event_relay.py, research_router.py,
  research_inward_context.py, research_prompt_compiler.py, research_define.py
  (ISSUE-gate compiler), research_task_tree.py + research_stage_executor.py
  (canonical authorities)
- RETIRED_STAGES guard: retired names remain ONLY as the block that prevents
  them executing (they cannot authorize a live stage — regression-tested)
- All historical evidence (research/issue-*, closed issues) preserved

Docs updated: classification manifest (RETIRED entries), pipeline registry
(retired-workflows section), lint-baseline shrunk 82→80 S110 / 356→352 BLE001
(deleted files carried lint debt).

Regression: 1129 passed (was 1069 pre-merge — canonical pipeline tests
joined), 0 henxel failures.
2026-09-09 11:25:42 +01:00
Nick 25afdc7024 merge: canonical Research-to-Build pipeline (rp2-canonical-stage-model) into master
RP11/#274 step 1 — consolidate to ONE canonical authority. The RSC0-9
research scripts on master (DEFINE/OUTWARD_DISCOVERY/OUTWARD_READING stage
model) are superseded by the canonical pipeline proven through RP2-RP10
(epic #257, children #264-#273): ISSUE→INWARD→OUTWARD→APPLICABILITY→
conditional INNOVATION→ADVERSARIAL(disposition)→SYNTHESIS→QUALIFY.

Zero conflicts vs current master; the #161 harness (PR #279) is preserved.
2026-09-09 11:14:49 +01:00
Nick f957387181 fix(ci): propagation applies to pull_request runs only
CI Pipeline / best-practices (push) Successful in 2s
CI Pipeline / documentation (push) Successful in 3s
CI Pipeline / canary (push) Successful in 29s
CI Pipeline / lint (push) Successful in 36s
CI Pipeline / type-check (push) Successful in 27s
CI Pipeline / gitea-offline (push) Successful in 14s
CI Pipeline / unit-tests (push) Successful in 54s
CI Pipeline / lint (pull_request) Successful in 34s
CI Pipeline / canary (pull_request) Successful in 29s
CI Pipeline / documentation (pull_request) Successful in 3s
Spec gate (headless) / spec-gate (pull_request) Successful in 5s
CI Pipeline / best-practices (pull_request) Successful in 3s
CI Pipeline / required-checks (push) Successful in 0s
CI Pipeline / gitea-offline (pull_request) Successful in 15s
CI Pipeline / unit-tests (pull_request) Successful in 59s
CI Pipeline / type-check (pull_request) Successful in 27s
CI Pipeline / required-checks (pull_request) Successful in 1s
Auto-version and Release / release (pull_request) Successful in 34s
Push-event runs have no PR body, so the propagation requirement was
structurally unsatisfiable there (UMBRELLA_SKIP_PROPAGATION=1 for bodyless
runs). The pull_request run — the gate that actually blocks merge — still
enforces it fully. UNMAPPED check unchanged on both event types.
2026-09-09 04:12:58 +01:00