Skip to main content

Operations

Tool / Contract Summary

This page describes how jhf-tenter is operated in practice:

  • what the repo owns directly
  • what must be verified on the live host
  • which commands are the canonical start, stop, restart, and verify paths

Business Value

  • Operators get one place for the verified runtime contract instead of piecing it together from multiple repos.
  • Deployment and validation repos can consume a stable operations baseline.
  • Wiki.js and deep-dive readers can separate contract truth from temporary runtime state.

Current Verified State

Current host evidence from <internal-runtime-redacted>:

  • openclaw-gateway on :18789 is not stable enough to assume green from docs alone; the same day 2026-06-20 showed both a restart loop with Invalid config at /home/node/.openclaw/openclaw.json / agents.defaults.subagents: Invalid input and a later temporary healthy readback, so the flapping runtime remains tracked in jhf-openclaw-env#1270 and must be re-read live before voice RTT claims.
  • jhf-fabric-api is live on :28080.
  • jhf-voice-asterisk-ari is live on :19088.
  • jhf-voice-asterisk-gui is live on :19089.
  • jhf-heddle-keycloak is live on :18090.

Available now

  • Canonical Asterisk stack source-of-truth docs and compose files.
  • CPU-safe runtime guardrails for shared-host ARI and GUI execution.
  • Repo-local smoke and Fabric self-check commands.
  • Host-near stack verification.
  • Voice runtime bring-up and live-call verification.
  • Package build and verify operations.
  • Repo-owned Windows install-root synchronization before tray/runtime shortcuts are refreshed.

Optional / Extended

  • deployment-executed rollout from the tenter-owned stack artifacts
  • GUI runtime plus SSO attachment
  • optional carrier slice operations when Fabric later publishes an enabled state

Planned / Not in current scope

  • CI-driven host mutation
  • repo-owned infrastructure provisioning
  • repo-owned secrets rotation

Public Surfaces

Start / stop / restart surfaces

Windows install-root sync and tray/runtime refresh:

  • powershell -ExecutionPolicy Bypass -File .\scripts\sync-install-root.ps1 -InstallRoot <local-user-path-redacted>
  • powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1 -InstallRoot <local-user-path-redacted>
  • the install flow must synchronize the current repo-owned script/runtime set into the canonical install root before startup shortcuts or tray relaunch are trusted

Full tenter-owned stack:

  • bash scripts/run-asterisk-stack.sh --ari-env-file <ari.env> --gui-env-file <gui.env> config
  • bash scripts/run-asterisk-stack.sh --ari-env-file <ari.env> --gui-env-file <gui.env> --remove-orphans up
  • bash scripts/run-asterisk-stack.sh --ari-env-file <ari.env> --gui-env-file <gui.env> restart
  • bash scripts/run-asterisk-stack.sh --ari-env-file <ari.env> --gui-env-file <gui.env> down
  • the helper renders repo-owned ARI config templates into .runtime/asterisk-ari-live/generated-config
  • the helper also materializes canonical tenter-owned runtime env copies into .runtime/asterisk-ari-live/ari.env and .runtime/asterisk-gui-live/gui.env
  • the helper now force-recreates the tenter stack on up and restart so changed env/config truth is applied instead of leaving stale bridge container env in place, and it explicitly repairs unless-stopped restart policy for jhf-voice-asterisk-ari, jhf-voice-asterisk-gui, and jhf-voice-softphone-agent-bridge
  • the helper now enforces a single-flight compose apply lock for up, down, and restart; concurrent reruns fail fast with exit 75 instead of stacking another tenter compose client on the shared host
  • the helper now bounds compose apply runtime with JHF_TENTER_COMPOSE_APPLY_TIMEOUT_SECONDS (default 240s) and cleans stale project compose CLI processes after timeout

ARI:

  • docker compose -f runtime/asterisk-ari-live/docker-compose.yml --env-file runtime/asterisk-ari-live/ari.env.example up -d
  • docker compose -f runtime/asterisk-ari-live/docker-compose.yml --env-file runtime/asterisk-ari-live/ari.env.example down
  • docker compose -f runtime/asterisk-ari-live/docker-compose.yml --env-file runtime/asterisk-ari-live/ari.env.example restart

GUI:

  • docker compose -f runtime/asterisk-gui-live/docker-compose.yml --env-file runtime/asterisk-gui-live/gui.env.example up -d
  • docker compose -f runtime/asterisk-gui-live/docker-compose.yml --env-file runtime/asterisk-gui-live/gui.env.example down
  • docker compose -f runtime/asterisk-gui-live/docker-compose.yml --env-file runtime/asterisk-gui-live/gui.env.example restart

Resource posture (mem_limit/cpus/pids_limit/restart/logging) for jhf-voice-asterisk-ari, jhf-voice-asterisk-gui, and jhf-voice-softphone-agent-bridge is materialized from jhf-openclaw-env deploy/fleet/fleet-resource-manifest.v1.json (ref jhf-openclaw-env#2855, jhf-tenter#694); it only takes live effect on the next redeploy or via WP-E/E2, not from a compose-file edit alone.

Verify surfaces

  • python3 scripts/ci/verify_repo.py
  • python3 scripts/ci/verify_scan_and_fix.py
  • bash scripts/fabric-selfcheck.sh
  • python3 scripts/export-fabric-metadata.py --check
  • python3 scripts/ci/verify_runtime_materialization_drift.py
  • python3 scripts/ci/verify_asterisk_stack_source_of_truth.py
  • python3 scripts/ci/verify_cpu_safe_runtime_guardrails.py
  • python3 scripts/ci/verify_softphone_agent_bridge_restart_health.py
  • python3 scripts/ci/verify_realtime_voice_wave3_router.py
  • python3 scripts/ci/verify_realtime_voice_wave4_async_mode.py
  • python3 scripts/ci/verify_realtime_voice_wave5_guarded_speculative.py
  • python3 scripts/ci/verify_realtime_voice_wave6_shadow_mode_cutover.py
  • python3 scripts/ci/profile_phone_rtt_budget.py --output test-results/phone-rtt-budget.json
  • bash scripts/verify-realtime-voice-v6-acceptance.sh
  • python3 scripts/ci/verify_voice_host_near_bringup.py
  • python3 scripts/ci/verify_voice_live_call.py

Split-host RTT budget profiling:

  • python3 scripts/ci/profile_phone_rtt_budget.py --output test-results/phone-rtt-budget.json
  • python3 scripts/ci/profile_phone_rtt_budget.py --openclaw-evidence-json <warm-ttft-evidence.json> --output test-results/phone-rtt-budget.json
  • by default the profiler refreshes Host150 latency with a seeded-loopback tts/offline -> stt/offline probe before computing the floor; use --skip-local-refresh-probe only when you explicitly need the existing runtime snapshot readback
  • the profiler reads current Host150 local audio latency truth from http://<internal-runtime-redacted>:18180, inspects Host172 openclaw-gateway state over SSH, and optionally consumes direct warm OpenClaw TTFT evidence to compute the current composite floor against the 1.3s-1.7s phone target
  • when Host172 is red, the profiler fails closed into blocked_external classification instead of pretending the repo-owned phone lane is green

Strict handset-call acceptance boundary:

  • python3 scripts/ci/verify_windows_softphone_handset_acceptance.py
  • python3 scripts/ci/verify_windows_softphone_handset_acceptance.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter
  • this verifier now performs a bounded repo-owned Python UDP SIP/RTP handset call to 6201, captures the real media roundtrip, and reads back the freshest matching bridge turn-status when transient bridge.ok / bridge.fail markers have already been cleaned by the live dialplan loop
  • it remains one-turn only and must not be read as full conversational softphone or browser/WebRTC proof

Scan&Fix automation

Canonical entrypoint:

bash scripts/scan_and_fix.sh --dry-run

Default behavior scans and processes all matching open issues in priority order. Use --max-issues <n> only when the operator intentionally wants a smaller bounded batch.

Targeted issue selection:

bash scripts/scan_and_fix.sh --dry-run --issue 155
bash scripts/scan_and_fix.sh --dry-run --labels runtime,bug --max-issues 2

Live run with explicit executor:

SCAN_AND_FIX_EXECUTOR='codex' bash scripts/scan_and_fix.sh --issue 155 --host <internal-runtime-redacted> --user administrator

Failure modes:

  • no matching open issue after filters
  • missing or unreadable Gitea credentials
  • no runnable executor configured for non-dry-run mode
  • executor exits non-zero after the prompt handoff

The automation is bounded on purpose:

  • it only scans the current repo
  • it emits the selected issue context plus the checked-in execution standard
  • it fails closed if the executor path is not available
  • on Windows-mounted worktrees reached through WSL or Bash, it must derive branch and repo status through the native Git checkout view instead of Linux-side CRLF drift
  • it does not bypass branch/PR policy; the delegated execution must still create or update a PR instead of writing directly to main

Contract Families

  • runtime stack source
  • voice runtime slices
  • Fabric governance adoption
  • Fabric combinations consumer
  • GUI handoff and operator-surface consumer

Producer-/Consumer-Zuordnung

  • jhf-tenter owns:
    • stack definition
    • non-secret runtime wiring
    • repo verification
  • jhf-deployment owns:
    • rollout execution
    • host-side automation
  • jhf-heddle owns:
    • GUI authentication and IdP semantics
  • helpifyr-fabric owns:
    • shared contract and combination truth

Compatibility Window

  • Host ports 19088 and 19089 are static-required.
  • ARI and GUI stack files in this repo are the only canonical stack definitions for tenter-owned Asterisk surfaces.
  • Fabric versions must continue to match the read-only adoption verifier.

Lifecycle Status

  • Repo operations layer:
    • active
  • Live runtime:
    • live-readback verified
  • CI posture:
    • smoke-only and non-mutating

Readiness / Drift / Monitoring

Readiness is green when:

  • repo-local checks pass
  • Fabric surfaces are reachable
  • stack source-of-truth verification passes
  • live runtime presence matches the tenter-owned contract

Common drift patterns:

  • ports guessed from nearby services instead of the stack contract
  • Fabric state assumed from docs instead of live readback
  • deployment-local copies drifting from tenter-owned compose files
  • repo-owned env truth present in *.env.example and manifest contracts but missing from the active compose materialization
  • containers still present on the host with stale Config.Image after repo-owned image pinning
  • containers started without the canonical HostConfig.RestartPolicy.Name=unless-stopped
  • stale env copies forcing JHF_TENTER_SOFTPHONE_AGENT_SHARED_DIR back to another checkout and silently remounting the bridge shared path away from the active repo/worktree
  • live com.docker.compose.project.working_dir or config_files labels pointing at /home/administrator/_worktrees/... instead of the canonical host checkout /home/administrator/jhf-tenter
  • container env and mounted generated config disagreeing with the repo-owned stack contract
  • app /healthz or status readback disagreeing with active container env
  • undocumented host override files under ~/.config/helpifyr/runtime/jhf-tenter/
  • split-host local-audio bridge defaults drifting back to <internal-runtime-redacted>:18180 instead of the canonical LAN runtime at <internal-runtime-redacted>:18180
  • unbounded docker logs -f or repeated restart loops used as ad hoc diagnostics on a shared host

Canonical materialization-drift verifier:

python3 scripts/ci/verify_runtime_materialization_drift.py
python3 scripts/ci/verify_runtime_materialization_drift.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter

Host172 runtime-authority cutover rule:

  • exactly one admitted live authority path: /home/administrator/jhf-tenter
  • worktree-backed live authority is runtime_drift, not an admitted steady state
  • the live verifier must also read back git branch --show-current, git rev-parse HEAD, and git rev-parse origin/main for that canonical checkout and fail closed when the host path is not on exact main truth
  • before any host mutation, capture docker/git/runtime snapshots and a bounded pre-change verify matrix
  • after cutover, rerun the same live verifiers and confirm that working_dir, config_files, and repo-owned mounts all read back from /home/administrator/jhf-tenter

CPU-safe runtime guardrails

Canonical low-pressure rules for the tenter-owned Asterisk stack:

  • default healthcheck interval is 60s
  • compose apply uses a single-flight lock under .runtime/locks
  • overlapping tenter docker compose --project-name jhf-tenter ... apply runs are forbidden
  • compose apply is bounded by JHF_TENTER_COMPOSE_APPLY_TIMEOUT_SECONDS (default 240s)
  • diagnostics are bounded:
    • timeout 15s docker logs --since 15m --tail 120 ...
  • restart checks use bounded backoff instead of tight polling
  • post-deploy cleanup must leave no hanging docker logs or docker exec helpers
  • reruns must stay idempotent

Canonical guardrail verifier:

python3 scripts/ci/verify_cpu_safe_runtime_guardrails.py
python3 scripts/ci/verify_cpu_safe_runtime_guardrails.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter
python3 scripts/ci/verify_cpu_safe_runtime_guardrails.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter --exercise-restart

Deployment / Verify

Fast path:

python3 scripts/ci/verify_repo.py
bash scripts/fabric-selfcheck.sh
python3 scripts/export-fabric-metadata.py --check
python3 scripts/ci/verify_runtime_materialization_drift.py
python3 scripts/ci/verify_asterisk_stack_source_of_truth.py
python3 scripts/ci/verify_cpu_safe_runtime_guardrails.py
python3 scripts/ci/verify_softphone_agent_bridge_restart_health.py
python3 scripts/ci/verify_realtime_voice_wave3_router.py
python3 scripts/ci/verify_realtime_voice_wave4_async_mode.py
python3 scripts/ci/verify_realtime_voice_wave5_guarded_speculative.py
python3 scripts/ci/verify_realtime_voice_wave6_shadow_mode_cutover.py
bash scripts/verify-realtime-voice-v6-acceptance.sh

Live host path:

python3 scripts/ci/verify_asterisk_stack_source_of_truth.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter
python3 scripts/ci/verify_runtime_materialization_drift.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter
python3 scripts/ci/verify_cpu_safe_runtime_guardrails.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter
python3 scripts/ci/verify_softphone_agent_bridge_restart_health.py --check-live --host <internal-runtime-redacted>
python3 scripts/ci/verify_softphone_agent_bridge_restart_health.py --check-live --exercise-restart --host <internal-runtime-redacted>
python3 scripts/ci/verify_realtime_voice_wave3_router.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter
python3 scripts/ci/verify_realtime_voice_wave4_async_mode.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter
python3 scripts/ci/verify_realtime_voice_wave5_guarded_speculative.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter
python3 scripts/ci/verify_realtime_voice_wave6_shadow_mode_cutover.py --check-live --host <internal-runtime-redacted>
VOICE_V6_VERIFY_LIVE=1 bash scripts/verify-realtime-voice-v6-acceptance.sh
python3 scripts/ci/verify_fabric_contract_adoption.py --fabric-base-url http://<internal-runtime-redacted>:28080
python3 scripts/ci/verify_fabric_combination_profiles.py --fabric-base-url http://<internal-runtime-redacted>:28080
python3 scripts/ci/verify_voice_host_near_bringup.py

Wave-3 realtime bridge router

The bounded softphone bridge now exposes an explicit Wave-3 router posture:

  • hot agents route through warm-gateway
  • the hot route must prewarm a separated voice_runtime_target_ref; it must not continuously warm the productive main:main-voice-default conversation session
  • explicit async turns return an accepted turn id plus pollable /turn-status
  • per-session/per-turn coordination replaces the old global bridge lock
  • stale turn completions are quarantined under .runtime/softphone-agent-bridge/shared/late-results

Canonical verifier:

python3 scripts/ci/verify_realtime_voice_wave3_router.py
python3 scripts/ci/verify_realtime_voice_wave3_router.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter

Wave-4 async default and quarantine

The bounded bridge now also exposes a Wave-4 async default posture for non-hot agents:

  • non-hot agents default to async-bounded
  • async turns must return immediate accepted feedback
  • non-hot async work must not block a later hot turn in the same session
  • stale async completions are quarantined instead of overwriting the active session result

Canonical verifier:

python3 scripts/ci/verify_realtime_voice_wave4_async_mode.py
python3 scripts/ci/verify_realtime_voice_wave4_async_mode.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter

Wave-5 guarded speculative and barge-in

The bounded bridge now also exposes a Wave-5 guarded speculative posture on the existing /one-turn surface:

  • speculation stays fail-closed until policy risk, confidence, and stable-word guards are all satisfied
  • diverging final transcripts must quarantine the speculative turn instead of publishing its audio
  • barge-in marks the superseded turn terminal with cancel or quarantine semantics from the backend matrix

Canonical verifier:

python3 scripts/ci/verify_realtime_voice_wave5_guarded_speculative.py
python3 scripts/ci/verify_realtime_voice_wave5_guarded_speculative.py --check-live --host <internal-runtime-redacted> --host-checkout /home/administrator/jhf-tenter

Wave-6 shadow-mode cutover and latency evidence

The bounded bridge now also exposes a Wave-6 cutover-evidence posture:

  • cold, warm, and restart runs must emit one machine-readable evidence report
  • the report must keep warm-lane refs separate from productive conversation refs
  • the report must include bridge contract readback, local audio latency readback, and warm-gateway metrics snapshots
  • external hot-path drift must be classified as blocked_external, not hidden as a generic bridge failure
  • the live warm run must be cross-checked against a direct Host172 owner-side POST /voice/turn probe before the verifier admits a green cutover result
  • the stack helper must preserve repo-owned warm-lane keys when materializing canonical .runtime/asterisk-ari-live/ari.env, even if stale host override files still carry older values
  • the productive hot main path and the async-bounded worker lane should use the canonical OpenClaw POST /voice/turn gateway path when the local warm-gateway lane is live
  • text-only Wave-6 acceptance runs must keep STT bypass explicit; stale STT health samples stay informational while the bridge gates those turns on TTS readiness plus the live TTS/playback/end-to-end and per-run hot-turn diagnostics remain fail-closed

Canonical verifier:

python3 scripts/ci/verify_realtime_voice_wave6_shadow_mode_cutover.py
python3 scripts/ci/verify_realtime_voice_wave6_shadow_mode_cutover.py --check-live --host <internal-runtime-redacted>
bash scripts/verify-realtime-voice-v6-acceptance.sh

Wave-0.5 benchmark contract

The sub-300ms rebuild now has a canonical benchmark contract before any realtime cutover claim:

  • maintenance/voice_latency_benchmark.json is the machine-readable benchmark matrix
  • the benchmark must keep first_audible_response_ms separate from first_real_word_ms
  • the matrix must include OpenRouter, direct low-latency LLM candidates, local STT/TTS candidates, consent-safe external voice candidates, AEC-sensitive double-talk scenarios, and the RTX 3080 max_concurrent_voice_sessions=1 posture
  • local STT/TTS candidates may be recorded as host_not_materialized_current_mainline when the current install-root runtime still exposes the bounded Voxtral/OpenClaw-native lane instead of the target provider family
  • direct Groq/Cerebras LLM candidates may be recorded as provider_not_configured_current_mainline until the workstation actually has a repo-owned direct low-latency provider key
  • GPU decommission readiness may be recorded as decommission_not_satisfied_current_mainline while bounded Voxtral STT still occupies the RTX 3080
  • external voice candidates may be recorded as proxy_only_not_realtime_admitted_current_mainline when they are visible only behind the non-admitted OpenRouter TTS proxy contract
  • acoustic scenarios may be recorded as aec_missing_current_mainline while bounded barge-in is live but no repo-owned AEC/self-echo suppression surface exists
  • the repo verifier may read Host172 turnaround evidence plus local Windows runtime footprint, but must not emit secrets or raw customer audio

Canonical verifier:

python3 scripts/ci/verify_voice_latency_benchmark.py
python3 scripts/ci/verify_voice_latency_benchmark.py --check-live --host <internal-runtime-redacted> --output test-results/voice-latency-benchmark-live.json
python3 scripts/ci/profile_voice_latency_baseline.py --host <internal-runtime-redacted> --iterations 3 --output test-results/voice-latency-baseline.json
python3 scripts/ci/profile_synthetic_voice_transport.py --host <internal-runtime-redacted> --samples 5 --output test-results/synthetic-voice-transport.json
python3 scripts/ci/profile_local_voice_candidate_posture.py --base-url http://<internal-runtime-redacted>:18180 --output test-results/local-voice-candidate-posture.json
python3 scripts/ci/profile_llm_ttft_candidates.py --output test-results/llm-ttft-candidates.json
python3 scripts/ci/profile_gpu_residency_and_host_pressure.py --output test-results/gpu-residency-and-host-pressure.json
python3 scripts/ci/profile_external_voice_candidate_posture.py --output test-results/external-voice-candidate-posture.json
python3 scripts/ci/profile_acoustic_risk_posture.py --host <internal-runtime-redacted> --output test-results/acoustic-risk-posture.json

Voice lane baseline contract

Before further bounded-fix, TTS-provider, or realtime-lane changes, the repo now also owns a separate baseline readback for the currently admitted telephone lane:

  • maintenance/voice_lane_baseline.json is the machine-readable contract for the baseline shape
  • docs/VOICE_LANE_BASELINE.md is the canonical readback doc
  • test-results/voice_lane_baseline.json is the checked-in baseline report
  • the baseline must explicitly document the current 6201 path as fallback_bounded_voice_lane
  • 6200 and 6201 must stay separate in evidence posture, because 6200 still lacks a dedicated automated echo-latency probe on current mainline
  • productive 6201 telephony timing must stay explicitly separate from the Host150 local runtime timing; a fast local runtime readback is not evidence that the live telephone roundtrip is already fast
  • provider truth may be classified as runtime_drift_detected whenever the latest bounded live readback diverges from older benchmark/mainline provider observations

Canonical verifier:

python3 scripts/ci/verify_voice_lane_baseline.py
python3 scripts/ci/verify_voice_lane_baseline.py --check-live --host <internal-runtime-redacted> --output test-results/voice_lane_baseline.json

voice_tts_target_path contract

The TTS quality upgrade path now has its own canonical verifier instead of living only in the plan:

  • local_piper remains the current productive default and utility provider
  • local_gpt_sovits remains the target quality provider for fixed-agent speech
  • production-like GPT-SoVITS use stays blocked until model-weight and voice-sample provenance are attested
  • a bootstrap-generated System.Speech reference WAV must not keep local_gpt_sovits active by default; the startup path must fall back to local_piper unless an explicit bounded-lab override is present

Canonical verifier:

python3 scripts/ci/verify_voice_tts_target_path.py
python3 scripts/ci/verify_voice_tts_target_path.py --check-live --base-url http://<internal-runtime-redacted>:18180 --output test-results/voice_tts_target_path.json

voice_realtime_followup contract

After the baseline and GPT-SoVITS target-path slices, the repo now also owns a measured follow-up contract for the next bounded realtime work:

  • maintenance/voice_realtime_followup.json is the machine-readable follow-up contract
  • docs/VOICE_REALTIME_FOLLOWUP.md is the canonical readback
  • test-results/voice_realtime_followup.json is the checked-in follow-up report
  • the follow-up keeps fallback_bounded_voice_lane explicit while binding the next work to:
    • jhf-tenter#588 residual-stage breakout and early playback evidence
    • jhf-tenter#594 Host150 quality TTS materialization
    • jhf-tenter#590 AEC/session-state/barge-in contract
  • the same follow-up keeps jhf-jadda-interface#88 consumer-only and jhf-warp#512 policy-owned

Canonical verifier:

python3 scripts/ci/verify_voice_realtime_followup.py
python3 scripts/ci/verify_voice_realtime_followup.py --write-report
python -m pytest -q tests/test_verify_voice_realtime_followup.py

voice_bounded_residual_stage_breakout contract

The repo now also owns a bounded stage-breakout contract for jhf-tenter#588:

  • maintenance/voice_bounded_residual_stage_breakout.json is the machine-readable contract
  • docs/VOICE_BOUNDED_RESIDUAL_STAGE_BREAKOUT.md is the canonical readback
  • test-results/voice_bounded_residual_stage_breakout.json is the checked-in report
  • the report breaks the bounded wait into named stages instead of leaving one opaque residual bucket
  • the report proves that the bounded recording path still gates OpenClaw behind final STT
  • the report proves that bounded playback can already start from preview_lane or early_final_lane before the full final response body

Canonical verifier:

python3 scripts/ci/verify_voice_bounded_residual_stage_breakout.py
python3 scripts/ci/verify_voice_bounded_residual_stage_breakout.py --write-report --source test-results/voice_bounded_residual_stage_breakout_source.json
python -m pytest -q tests/test_verify_voice_bounded_residual_stage_breakout.py

voice_quality_tts_materialization contract

The repo now also owns a Host150 quality-TTS materialization contract for jhf-tenter#594:

  • maintenance/voice_quality_tts_materialization.json is the machine-readable contract
  • docs/VOICE_QUALITY_TTS_MATERIALIZATION.md is the canonical readback
  • test-results/voice_quality_tts_materialization_source.json is the live Host150 source readback
  • test-results/voice_quality_tts_materialization.json is the checked-in report
  • the report keeps local_piper explicit as the utility lane and classifies local_gpt_sovits as either materially present or owner-blocked on current mainline

Canonical verifier:

python3 scripts/ci/profile_local_voice_candidate_posture.py --base-url http://<internal-runtime-redacted>:18180 --output test-results/voice_quality_tts_materialization_source.json
python3 scripts/ci/verify_voice_quality_tts_materialization.py --write-report --source test-results/voice_quality_tts_materialization_source.json
python3 scripts/ci/verify_voice_quality_tts_materialization.py
python -m pytest -q tests/test_verify_voice_quality_tts_materialization.py tests/test_profile_local_voice_candidate_posture.py

Softphone bridge restart-health

The bounded softphone bridge is green only when restart behavior stays aligned with the split-host local-audio contract:

  • the bridge defaults must point at the Windows LAN runtime http://<internal-runtime-redacted>:18180
  • the bridge may not silently fall back to <internal-runtime-redacted>:18180 in the Wave-2 lane
  • after a bounded restart, jhf-voice-softphone-agent-bridge must return to Docker healthy and serve a green /healthz response within the verify budget

Canonical verifier:

python3 scripts/ci/verify_softphone_agent_bridge_restart_health.py
python3 scripts/ci/verify_softphone_agent_bridge_restart_health.py --check-live --host <internal-runtime-redacted>
python3 scripts/ci/verify_softphone_agent_bridge_restart_health.py --check-live --exercise-restart --host <internal-runtime-redacted>

Known Limits

  • The host-side openclaw status --json wrapper is still an external blocker for parts of the deepest live verification chain.
  • After the 2026-04-25 VM130 restore reroll, the tenter-owned Asterisk/bridge stack is back on repo-canonical origin/main, but the external warm-lane owner still has to materialize the separated voice_runtime_target_ref contract on <internal-runtime-redacted>; host-near LAN TTS to <internal-runtime-redacted>:18180 stays green while warm-lane readback and handoff still depend on owner-side runtime rollout.
  • This repo cannot guarantee that deployment has actually executed the newest stack revision unless host readback confirms it.
  • Windows operator flows still exist, but the current voice and Fabric runtime posture is Linux-host-near first.

Exceptions / Waivers

  • Optional carrier slices may remain disabled.
  • GUI runtime health should be interpreted through the tenter-owned stack verifier and deployment execution evidence, not a second local health contract.
  • jhf-tenter#87
  • jhf-tenter#88
  • jhf-deployment#170
  • openclaw-environment#30

License

AGPLv3. Learn more at helpifyr.com.

Workspace Git/Scan Guardrails (Mandatory)

  • Gitea is Source of Truth; local Windows workspaces are disposable working copies.
  • Never run Codex sessions on <local-workspace-redacted> root; always use a concrete repo path.
  • Limit active repo sessions to 2-3 in parallel.
  • Before each run in a repo: git fetch --prune, git checkout <branch>, git pull --ff-only.
  • No background git discovery loops (git status, git ls-files, worktree scans) without explicit scoped need.
  • Automation scripts must run repo-scoped only, never global over <local-workspace-redacted>.

scan_and_fix Standard

  • scripts/scan_and_fix.sh must enforce runner timeout + single-run lock + .env fallback to <local-env-redacted> and <local-env-redacted>.
  • scripts/scan_open_issues_repo_only.sh must exist and query only current repo open issues via Gitea API.

Workspace Hygiene

  • Daily cleanup: stale _worktrees/*, _tmp/*, test-results/*, large temporary artifacts.
  • Weekly cleanup: stale local branches/worktrees.
  • Never leave valuable artifacts as untracked files in workspace root.

Dirty-State Policy

  • Dirty state is allowed while actively implementing.
  • Before new scan/automation runs: commit/stash, or use a dedicated worktree.
  • Never propagate dirty_unknown states.

Incident Playbook (git.exe storm)

  1. Identify parent of git.exe (usually one Codex.exe).
  2. Stop only the offending process tree.
  3. Restart session on concrete repo path.
  4. Reduce parallel sessions.
  5. Verify git.exe count drops within 30-60s.