Resilience Arc — Pipeline Failure Intelligence (v3.138.4)
One intent. Many hands.
This release lands the Resilience Arc: thirteen connected milestones
(M126–M138) that turn Tekhton's failure path into a first-class system. UI
gate execution becomes deterministic, build-fix gets a real adaptive
continuation loop instead of a single short attempt, failure context grows
into a v2 schema with explicit primary/secondary causes, recovery routing
reads that context, RUN_SUMMARY.json and tekhton --diagnose finally
report root cause instead of symptom, and an end-to-end integration harness
keeps the chain honest. CI environments now configure themselves.
The arc was driven by real-world failure traces seen while running Tekhton
against bifl-tracker and structural-divergence-indexer — interactive
Playwright HTML reporters hanging gates, mixed-log classification
over-escalating to code fixes, max-turns symptoms masking environment root
causes, and stale LAST_FAILURE_CONTEXT.json contaminating succeeding
runs.
A --migrate script lifts existing projects to config v3.2 in one step,
and four follow-up patches close TUI, --report, and artifact-location
bugs surfaced during the arc's own dogfooding.
Highlights
Resilience Arc (M126–M138)
- M126 — Deterministic UI gate execution. UI test commands like
Playwright'snpx playwright testcould enter an interactive HTML report
server (Serving HTML report at http://localhost:9323. Press Ctrl+C to quit.) and never terminate, hittingUI_TEST_TIMEOUTwith a useless
exit-124. The gate now normalises the env (PLAYWRIGHT_HTML_OPEN=never,
CI=1,PW_TEST_HTML_REPORT_OPEN=neverand friends) before invocation,
detects the interactive-reporter signature in output, and re-runs once
with a hardened non-interactive profile when configured to. New
TEKHTON_UI_GATE_FORCE_NONINTERACTIVE,UI_GATE_ENV_RETRY_ENABLED, and
UI_GATE_ENV_RETRY_TIMEOUT_FACTORconfig keys. - M127 — Mixed-log classification hardening.
classify_build_errors_all
no longer defaults every unmatched line tocode|code||Unclassified,
which used to drag pipelines into build-fix coder routing whenever test
output contained a few stray npm warnings or ANSI fragments.
Classification now produces a per-bucket confidence score; mixed-uncertain
outputs route to a single retry-then-save_exitpath instead of burning
build-fix turns on environment failures dressed up as code errors. New
BUILD_FIX_CLASSIFICATION_REQUIREDtoggle to revert pre-M130 behaviour. - M128 — Build-fix continuation loop with adaptive turn budgeting.
Replaced the single-attemptbase/3build-fix instages/coder.shwith
a bounded continuation loop owned bystages/coder_buildfix.sh. The loop
retries up toBUILD_FIX_MAX_ATTEMPTS(default 3), allocates an adaptive
per-attempt budget capped byBUILD_FIX_TOTAL_TURN_CAP(default 120),
and gates retries on a progress signal — if attempt N≥2 reports
unchangedorworsened, the loop halts immediately. Per-attempt
postmortems land inBUILD_FIX_REPORT.md. New keys:
BUILD_FIX_ENABLED,BUILD_FIX_MAX_ATTEMPTS,
BUILD_FIX_BASE_TURN_DIVISOR,BUILD_FIX_MAX_TURN_MULTIPLIER,
BUILD_FIX_REQUIRE_PROGRESS,BUILD_FIX_TOTAL_TURN_CAP,
BUILD_FIX_REPORT_FILE. - M129 — Failure context schema v2.
LAST_FAILURE_CONTEXT.jsongrew
from a flat record to a schema-versioned document with explicit
primary_causeandsecondary_causeobjects (each with
category/subcategory/evidence). Pipeline state, diagnose rules, and
recovery routing now read consistent keys instead of the old
best-effort field-by-field probing. The schema preserves backward
compatibility for v1 readers. - M130 — Causal-context-aware recovery routing.
_classify_failurein
lib/orchestrate_recovery.shnow consults the schema-v2 failure context
(and the M132 causal log) before branching.ENVIRONMENT/test_infra
failures whose primary cause is a UI-gate timeout retry once with
non-interactive env (instead of unconditionalsave_exit); max-turns
symptoms whose root cause is environmental are routed by root cause, not
symptom. Recovery decisions are stamped on_ORCH_RECOVERY_ROUTE_TAKEN,
_ORCH_ENV_GATE_RETRIED, and_ORCH_MIXED_BUILD_RETRIEDfor downstream
consumers. - M131 — Preflight UI test framework config audit. Detection moves
ahead of the gate. The preflight layer scans Playwright, Cypress, Jest,
and Vitest config for known interactive-mode settings (reporter: 'html'
withopen: 'always', watch-mode defaults, etc.), warns the operator,
and — whenPREFLIGHT_UI_CONFIG_AUTO_FIX=true— patches the offending
config in place with a backup under.claude/preflight_bak/. Emits
structured findings consumed by M126 and M130. New keys:
PREFLIGHT_UI_CONFIG_AUDIT_ENABLED,PREFLIGHT_UI_CONFIG_AUTO_FIX,
PREFLIGHT_BAK_DIR,PREFLIGHT_BAK_RETAIN_COUNT. - M132 — RUN_SUMMARY causal fidelity enrichment.
RUN_SUMMARY.json
now carries the M128/M129/M130/M131 signals (build_fix.attempts,
failure_context.primary_cause,recovery.route_taken,
preflight.ui_interactive_config_detected, etc.) instead of a flat
error_classes_encounteredlist. Watchtower and any external consumers
see root cause without re-scraping logs. - M133 — Diagnose rule enrichment.
tekhton --diagnoselearned five
new resilience-arc failure modes:
UI_GATE_INTERACTIVE_REPORTER,BUILD_FIX_EXHAUSTED,
PREFLIGHT_INTERACTIVE_CONFIG,MIXED_UNCERTAIN_CLASSIFICATION, and
MAX_TURNS_ENV_ROOT. Diagnose-only — no behavioural change to gates,
preflight, recovery, or context writes; consumes existing artifacts. - M134 — Resilience Arc integration test harness. End-to-end fixtures
exercise the full chain (preflight scan → gate normalisation → timeout
detection → classification → build-fix loop → failure context write →
recovery routing → RUN_SUMMARY enrichment →--diagnoseoutput) so
cross-cutting bugs that escape per-milestone unit tests get caught. - M135 — Artifact lifecycle management.
LAST_FAILURE_CONTEXT.jsonis
now cleared on successful runs (no more stale-failure diagnoses on
succeeding projects),BUILD_RAW_ERRORS.txtis removed on success, and
.claude/preflight_bak/is pruned to the most recent
PREFLIGHT_BAK_RETAIN_COUNTentries (default 10). - M136 — Config defaults and validation hardening. All thirteen
arc-introduced operator keys are declared inlib/config_defaults.sh,
picked up bypipeline.confoverrides, validated by
tekhton --validate-config, and documented in
templates/pipeline.conf.example. Mis-typed numeric values now error
loudly instead of silently being ignored. - M137 — V3.2 migration script.
migrations/031_to_032.shlifts
existing projects (config version3.1→3.2): adds the thirteen
arc keys topipeline.confwith sane defaults, registers new artifact
paths in.gitignore, and stampsTEKHTON_CONFIG_VERSION=3.2. Run via
tekhton --migrate. - M138 — Runtime CI environment auto-detection. When Tekhton starts
inside GitHub Actions, GitLab CI, Jenkins, CircleCI, Travis, or any
environment exporting$CI=1, and the operator hasn't explicitly set
TEKHTON_UI_GATE_FORCE_NONINTERACTIVEinpipeline.conf, the variable
is auto-set to1. Explicit values — including=0— always win.
Eliminates the silent-failure-in-CI footgun that motivated the arc.
Bug fixes and polish
tekhton --reportprinted literal ANSI escape sequences like
\033[0;32msuccess\033[0mon the Outcome / Coder / Security / Reviewer
/ Tester lines. Root cause: color constants inlib/common.share
stored as literal strings;_out_colorinlib/output_format.shwas
emitting them viaprintf '%s'instead ofprintf '%b'. Fixed without
touching the constants —%binterprets the backslash sequences and
the surrounding helpers (out_banner,out_section,out_kv, …) keep
working unchanged.HUMAN_ACTION_REQUIRED.mdand other artifacts written to project
root. A handful of pipeline files were still being written to the
pre-.tekhton/location. The fix relocates the writers and ships
migrations/032_to_033.sh+tests/test_migrate_033.shso existing
projects move root-level artifacts into.tekhton/(merging into any
existing canonical file rather than overwriting silently).- TUI sidecar silent death in
tekhton --human --complete. The
per-iteration reset path could leave the sidecar dead while the parent
loop kept writing status updates that nothing was rendering. Added
lib/tui_liveness.shwith a sampled liveness probe
(_tui_check_sidecar_liveness) that detects a dead sidecar and
surfaces a visible warning instead of silently no-op'ing.lib/tui.sh
shrinks back below the 300-line ceiling. - TUI status bar shows working directory. The top status bar now
appends· /<project_dir>after the Pass counter, transforming
fix-nb · Pass 1/5intofix-nb · Pass 1/5 · /name-of-folder— useful
when running multiple Tekhton invocations against different projects in
adjacent terminals. - Thirty open non-blocking notes addressed. A focused sweep through
.tekhton/NON_BLOCKING_LOG.mdresolved every open item: M127's magic
literal promoted to a named constant, M128's vestigialBUILD_GATE_RETRY
guard removed, M129's unsafeecho "$sub_block"replaced with
printf '%s ', M133's docstring/code numbering mismatch corrected, plus
smaller inconsistencies across tests, fixtures, and documentation.
Why it matters
- Failures now produce signal, not noise. Before the arc, a
Playwright HTML reporter hang surfaced asMAX_TURNS_EXHAUSTEDafter
Tekhton burned a build-fix attempt on what was actually an environment
problem. After the arc, the same failure surfaces as
UI_GATE_INTERACTIVE_REPORTERin--diagnose, retries once with a
hardened env, and either succeeds orsave_exits with the root cause
inRUN_SUMMARY.json. No more chasing symptoms. - CI gets the right defaults for free. The
TEKHTON_UI_GATE_FORCE_NONINTERACTIVEfootgun — the most common cause
of opaque CI hangs in the arc's failure traces — is closed without any
per-project YAML edits. M138 detects the CI environment at runtime and
defaults appropriately. - Build-fix has a real budget. A single
base/3-turn attempt was
too brittle for any non-trivial fix. The continuation loop now spends
up to three attempts inside aBUILD_FIX_TOTAL_TURN_CAPenvelope,
halts the moment progress stalls, and writes a per-attempt postmortem
for inspection. - Existing projects upgrade in one command. Two migration scripts
ship together:031_to_032.shfor the resilience arc config keys and
032_to_033.shfor the artifact-relocation fix.tekhton --migrate
walks both, stampingTEKHTON_CONFIG_VERSION=3.2and merging any stale
root-level artifacts into.tekhton/.
Upgrade notes
- Run
tekhton --migrateonce after upgrading. The migration is
idempotent and safe to re-run. It adds thirteen new keys to
pipeline.confwith conservative defaults (everything in the arc
defaults to "on" with budgets matching the prior implicit behaviour),
registers new gitignore entries, and moves any stale root-level
HUMAN_ACTION_REQUIRED.mdinto.tekhton/. - No breaking config changes. Every arc behaviour is gated behind a
config key with the same default as the prior implicit behaviour where
one existed. To revert mixed-log routing to pre-M130 behaviour, set
BUILD_FIX_CLASSIFICATION_REQUIRED=false. To opt out of the
M126 env-gate retry, setUI_GATE_ENV_RETRY_ENABLED=false. To opt
out of CI auto-detection, setTEKHTON_UI_GATE_FORCE_NONINTERACTIVE=0
explicitly inpipeline.conf. .tekhton/BUILD_FIX_REPORT.mdis a new artifact. It's added to
the migration's gitignore additions; if you don't run--migrateyou
may want to add it manually.- Brew tap users will pick up the release on next
brew upgrade tekhton.
Release: v3.138.4