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-gatewayon:18789is not stable enough to assume green from docs alone; the same day2026-06-20showed both a restart loop withInvalid config at /home/node/.openclaw/openclaw.json/agents.defaults.subagents: Invalid inputand a later temporary healthy readback, so the flapping runtime remains tracked injhf-openclaw-env#1270and must be re-read live before voice RTT claims.jhf-fabric-apiis live on:28080.jhf-voice-asterisk-ariis live on:19088.jhf-voice-asterisk-guiis live on:19089.jhf-heddle-keycloakis 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> configbash scripts/run-asterisk-stack.sh --ari-env-file <ari.env> --gui-env-file <gui.env> --remove-orphans upbash scripts/run-asterisk-stack.sh --ari-env-file <ari.env> --gui-env-file <gui.env> restartbash 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.envand.runtime/asterisk-gui-live/gui.env - the helper now force-recreates the tenter stack on
upandrestartso changed env/config truth is applied instead of leaving stale bridge container env in place, and it explicitly repairsunless-stoppedrestart policy forjhf-voice-asterisk-ari,jhf-voice-asterisk-gui, andjhf-voice-softphone-agent-bridge - the helper now enforces a single-flight compose apply lock for
up,down, andrestart; concurrent reruns fail fast with exit75instead of stacking another tenter compose client on the shared host - the helper now bounds compose apply runtime with
JHF_TENTER_COMPOSE_APPLY_TIMEOUT_SECONDS(default240s) 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 -ddocker compose -f runtime/asterisk-ari-live/docker-compose.yml --env-file runtime/asterisk-ari-live/ari.env.example downdocker 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 -ddocker compose -f runtime/asterisk-gui-live/docker-compose.yml --env-file runtime/asterisk-gui-live/gui.env.example downdocker 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.pypython3 scripts/ci/verify_scan_and_fix.pybash scripts/fabric-selfcheck.shpython3 scripts/export-fabric-metadata.py --checkpython3 scripts/ci/verify_runtime_materialization_drift.pypython3 scripts/ci/verify_asterisk_stack_source_of_truth.pypython3 scripts/ci/verify_cpu_safe_runtime_guardrails.pypython3 scripts/ci/verify_softphone_agent_bridge_restart_health.pypython3 scripts/ci/verify_realtime_voice_wave3_router.pypython3 scripts/ci/verify_realtime_voice_wave4_async_mode.pypython3 scripts/ci/verify_realtime_voice_wave5_guarded_speculative.pypython3 scripts/ci/verify_realtime_voice_wave6_shadow_mode_cutover.pypython3 scripts/ci/profile_phone_rtt_budget.py --output test-results/phone-rtt-budget.jsonbash scripts/verify-realtime-voice-v6-acceptance.shpython3 scripts/ci/verify_voice_host_near_bringup.pypython3 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.jsonpython3 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/offlineprobe before computing the floor; use--skip-local-refresh-probeonly 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 Host172openclaw-gatewaystate over SSH, and optionally consumes direct warm OpenClaw TTFT evidence to compute the current composite floor against the1.3s-1.7sphone target - when Host172 is red, the profiler fails closed into
blocked_externalclassification instead of pretending the repo-owned phone lane is green
Strict handset-call acceptance boundary:
python3 scripts/ci/verify_windows_softphone_handset_acceptance.pypython3 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 bridgeturn-statuswhen transientbridge.ok/bridge.failmarkers 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-tenterowns:- stack definition
- non-secret runtime wiring
- repo verification
jhf-deploymentowns:- rollout execution
- host-side automation
jhf-heddleowns:- GUI authentication and IdP semantics
helpifyr-fabricowns:- shared contract and combination truth
Compatibility Window
- Host ports
19088and19089are 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.exampleand manifest contracts but missing from the active compose materialization - containers still present on the host with stale
Config.Imageafter repo-owned image pinning - containers started without the canonical
HostConfig.RestartPolicy.Name=unless-stopped - stale env copies forcing
JHF_TENTER_SOFTPHONE_AGENT_SHARED_DIRback to another checkout and silently remounting the bridge shared path away from the active repo/worktree - live
com.docker.compose.project.working_dirorconfig_fileslabels 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
/healthzor 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>:18180instead of the canonical LAN runtime at<internal-runtime-redacted>:18180 - unbounded
docker logs -for 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, andgit rev-parse origin/mainfor that canonical checkout and fail closed when the host path is not on exactmaintruth - 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(default240s) - 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 logsordocker exechelpers - 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 productivemain:main-voice-defaultconversation 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
acceptedfeedback - 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
warmrun must be cross-checked against a direct Host172 owner-sidePOST /voice/turnprobe 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
mainpath and the async-bounded worker lane should use the canonical OpenClawPOST /voice/turngateway 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.jsonis the machine-readable benchmark matrix- the benchmark must keep
first_audible_response_msseparate fromfirst_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=1posture - local STT/TTS candidates may be recorded as
host_not_materialized_current_mainlinewhen 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_mainlineuntil the workstation actually has a repo-owned direct low-latency provider key - GPU decommission readiness may be recorded as
decommission_not_satisfied_current_mainlinewhile bounded Voxtral STT still occupies the RTX 3080 - external voice candidates may be recorded as
proxy_only_not_realtime_admitted_current_mainlinewhen they are visible only behind the non-admitted OpenRouter TTS proxy contract - acoustic scenarios may be recorded as
aec_missing_current_mainlinewhile 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.jsonis the machine-readable contract for the baseline shapedocs/VOICE_LANE_BASELINE.mdis the canonical readback doctest-results/voice_lane_baseline.jsonis the checked-in baseline report- the baseline must explicitly document the current
6201path asfallback_bounded_voice_lane 6200and6201must stay separate in evidence posture, because6200still lacks a dedicated automated echo-latency probe on current mainline- productive
6201telephony 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_detectedwhenever 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_piperremains the current productive default and utility providerlocal_gpt_sovitsremains 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.Speechreference WAV must not keeplocal_gpt_sovitsactive by default; the startup path must fall back tolocal_piperunless 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.jsonis the machine-readable follow-up contractdocs/VOICE_REALTIME_FOLLOWUP.mdis the canonical readbacktest-results/voice_realtime_followup.jsonis the checked-in follow-up report- the follow-up keeps
fallback_bounded_voice_laneexplicit while binding the next work to:jhf-tenter#588residual-stage breakout and early playback evidencejhf-tenter#594Host150 quality TTS materializationjhf-tenter#590AEC/session-state/barge-in contract
- the same follow-up keeps
jhf-jadda-interface#88consumer-only andjhf-warp#512policy-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.jsonis the machine-readable contractdocs/VOICE_BOUNDED_RESIDUAL_STAGE_BREAKOUT.mdis the canonical readbacktest-results/voice_bounded_residual_stage_breakout.jsonis 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_laneorearly_final_lanebefore 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.jsonis the machine-readable contractdocs/VOICE_QUALITY_TTS_MATERIALIZATION.mdis the canonical readbacktest-results/voice_quality_tts_materialization_source.jsonis the live Host150 source readbacktest-results/voice_quality_tts_materialization.jsonis the checked-in report- the report keeps
local_piperexplicit as the utility lane and classifieslocal_gpt_sovitsas 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>:18180in the Wave-2 lane - after a bounded restart,
jhf-voice-softphone-agent-bridgemust return to Dockerhealthyand serve a green/healthzresponse 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 --jsonwrapper is still an external blocker for parts of the deepest live verification chain. - After the
2026-04-25VM130 restore reroll, the tenter-owned Asterisk/bridge stack is back on repo-canonicalorigin/main, but the external warm-lane owner still has to materialize the separatedvoice_runtime_target_refcontract on<internal-runtime-redacted>; host-near LAN TTS to<internal-runtime-redacted>:18180stays 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.
Related Issues
jhf-tenter#87jhf-tenter#88jhf-deployment#170openclaw-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.shmust enforce runner timeout + single-run lock +.envfallback to<local-env-redacted>and<local-env-redacted>.scripts/scan_open_issues_repo_only.shmust 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_unknownstates.
Incident Playbook (git.exe storm)
- Identify parent of
git.exe(usually oneCodex.exe). - Stop only the offending process tree.
- Restart session on concrete repo path.
- Reduce parallel sessions.
- Verify
git.execount drops within 30-60s.