Skip to content

fix(deploy): keep on-chain validator off master hosts - #101

Merged
echobt merged 4 commits into
mainfrom
fix/master-no-validator-submitter
Aug 8, 2026
Merged

fix(deploy): keep on-chain validator off master hosts#101
echobt merged 4 commits into
mainfrom
fix/master-no-validator-submitter

Conversation

@echobt

@echobt echobt commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Prod master was running base-validator-1 alongside base-prod-validator, both with the 5Gzi… wallet — dual CRV4 submitters fighting WeightsSetRateLimit.
  • Profile validator under never in role-master.yml; env-local.yml re-enables co-located validator for local-e2e only.
  • remote-deploy.sh --role master force-removes any leftover validator and fails the deploy if it is still running.
  • Compose matrix asserts master renders no validator; docs call out the sole-submitter rule.

Test plan

  • ./deploy/scripts/assert-compose-matrix.sh
  • Ops: stopped/removed base-validator-1 on prod master 206.189.224.155; sole submitter remains 192.81.218.11
  • Next prod master deploy: confirm log line master: validator absent and no base-validator-1
  • After CRV4 reveal for epoch 24383: on-chain Weights for uid 0 show [94,102,214] (not 236 monopoly)

Summary by CodeRabbit

  • New Features

    • Added automatic leaf emission near design challenge epoch boundaries.
    • Emissions now continue when no administrative award occurs, helping seals advance consistently.
    • Local smoke-test environments now run a co-located validator.
  • Bug Fixes

    • Prevented duplicate validator submissions across deployment roles.
    • Improved deployment checks to detect and remove conflicting validator services.
  • Documentation

    • Clarified emission timing, validator responsibilities, and production deployment guidance.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@echobt, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a67ffcf3-82d8-4d53-9358-6cda183c49bd

📥 Commits

Reviewing files that changed from the base of the PR and between 6487490 and 58773e6.

📒 Files selected for processing (1)
  • crates/design-challenge/src/orchestrator.rs
📝 Walkthrough

Walkthrough

The PR adds near-epoch-boundary D24 leaf emission with a 15-second polling interval. It starts the emitter during server startup, documents the emission timing, and separates validator deployment responsibilities from master hosts.

Changes

D24 leaf emission

Layer / File(s) Summary
Emitter configuration and execution
crates/design-challenge/src/orchestrator.rs
The orchestrator tracks successful emissions, polls the chain schedule, emits missing leaf sets during the final 48 blocks, and retries failed ticks.
Emitter startup and D24 timing
bins/design-challenge/src/main.rs, docs/DESIGN_CHALLENGE.md
Server startup runs the emitter with a 15-second interval. Documentation covers near-boundary emission and NotAttempted leaves.

Validator deployment roles

Layer / File(s) Summary
Compose role matrix
deploy/AGENTS.md, deploy/compose/*, deploy/scripts/assert-compose-matrix.sh
Master deployments exclude validators, local overlays enable them, and Compose assertions enforce the expected service sets.
Remote deployment enforcement
deploy/scripts/remote-deploy.sh
Remote deployment removes role-incompatible containers, limits validator health checks to validator hosts, and rejects running validators on masters.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Main as design-challenge main
  participant Orchestrator
  participant ChainSchedule
  participant EmitLeaves as emit_leaves
  Main->>Orchestrator: start run_emitter()
  Orchestrator->>Orchestrator: poll emitter_tick()
  Orchestrator->>ChainSchedule: load current schedule
  Orchestrator->>EmitLeaves: submit missing leaf set
  EmitLeaves->>Orchestrator: record successful submission
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main deployment change: preventing on-chain validators from running on master hosts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/master-no-validator-submitter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

echobt added 3 commits August 8, 2026 20:52
Dual base-validator containers with the same 5Gzi wallet were fighting
WeightsSetRateLimit/CRV4. Profile validator out of role-master, force-remove
it on master deploys, and keep co-located validator only for local-e2e.
Seals stalled when design only emitted on admin award while prism posted
every epoch. Add a late-tempo emitter that fills NotAttempted coverage so
base-real-seal can advance; award_round still emits scored leaves first.
@echobt
echobt force-pushed the fix/master-no-validator-submitter branch from 3517b6d to 6487490 Compare August 8, 2026 20:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/design-challenge/src/orchestrator.rs`:
- Around line 314-330: Serialize D24 leaf projection updates between run_emitter
and award_round using one shared async lock or store transaction. Hold it across
score persistence and leaf submission in award_round, and acquire it in
emitter_tick before rechecking emitted_epoch and calling emit_leaves, so stale
NotAttempted leaves cannot be exposed before scored leaves.

In `@deploy/scripts/remote-deploy.sh`:
- Around line 427-428: Update the validator cleanup flow around the docker
compose rm command to fail closed: remove the unconditional “|| true” and
suppressed output, ensure removal errors are reported and terminate the master,
then perform an explicit absence check for the inactive validator container and
likewise exit loudly if it still exists. Preserve the existing validator removal
target and use the surrounding deployment error-handling conventions.
- Around line 422-425: Update the validator cleanup block in the role check to
include gateway alongside the existing challenge and proxy services passed to
docker compose rm. Ensure the cleanup does not suppress failure when gateway
remains, so the redeploy fails if the stale gateway container cannot be removed.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 43146592-0304-4428-826b-1a47ab17cc59

📥 Commits

Reviewing files that changed from the base of the PR and between 1e688ad and 3517b6d.

📒 Files selected for processing (8)
  • bins/design-challenge/src/main.rs
  • crates/design-challenge/src/orchestrator.rs
  • deploy/AGENTS.md
  • deploy/compose/env-local.yml
  • deploy/compose/role-master.yml
  • deploy/scripts/assert-compose-matrix.sh
  • deploy/scripts/remote-deploy.sh
  • docs/DESIGN_CHALLENGE.md

Comment on lines +314 to +330
let state = chain::gather_schedule_state(self.chain.as_ref(), self.cfg.netuid)
.map_err(|e| format!("schedule: {e}"))?;
let epoch = state.subnet_epoch_index;
if epoch == 0 {
return Ok(false);
}
if self.emitted_epoch.load(Ordering::Relaxed) >= epoch {
return Ok(false);
}
let tempo = u64::from(state.tempo.max(1));
// Prefer award_round's scored emit; only fill when ~last 48 blocks remain
// (~tempo-48 … tempo) so mid-epoch winners are not locked behind NoScore.
let near_end = state.blocks_since_last_step.saturating_add(48) >= tempo;
if !near_end {
return Ok(false);
}
self.emit_leaves().await?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Inspect all callers and the gateway submission contract.
ast-grep outline crates/design-challenge/src/orchestrator.rs --items all
rg -n -C 8 '\b(award_round|emitter_tick|emit_leaves|submit_signed_leaf_set)\b|emitted_epoch|/v1/weights/raw' crates bins

Repository: BaseIntelligence/base

Length of output: 50377


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Read the relevant orchestrator sections and design contract docs without modifying files.
sed -n '288,410p' crates/design-challenge/src/orchestrator.rs
printf '\n--- award_round scoring and emit section ---\n'
sed -n '404,570p' crates/design-challenge/src/orchestrator.rs
printf '\n--- emit_leaves section ---\n'
sed -n '1104,1157p' crates/design-challenge/src/orchestrator.rs

printf '\n--- design docs relevant excerpts ---\n'
fd -a . docs | sed 's#^\./##' | rg 'DESIGN_CHALLENGE|design_challenge|DESIGN.*CHALLENGE|challenge' | head -80
for f in $(fd -i 'design_challenge\.(md|json|yaml|yml)|DESIGN_CHALLENGE\.(md|json|yaml|yml)' docs); do
  echo "%%%%%% $f %%%%%%"
  wc -l "$f"
  rg -n -C 6 '(d24|D24|leaf set|leaf sets|weights.raw|weights/-raw|expected set|expected set|submission|scoring|award|NotAttempted|NoScore|sealed|emitter|emitter_tick|emitted_epoch)' "$f" || true
done

Repository: BaseIntelligence/base

Length of output: 26702


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo '--- BUNDLE_SPEC relevant leaf seal excerpts ---'
sed -n '1,260p' docs/BUNDLE_SPEC.md

echo '--- raw weight store implementation excerpts ---'
fd -a '.*' crates/gateway crates/challenge-common | rg 'weights_store|raw|submit|leaf' | head -80 || true
rg -n -C 5 'struct RawWeightStore|RawWeightStore|RawWeightAccepted|RawWeightRequest|get\(|accept_raw_weight|expected_set|sealed|signature|weights_store' crates/gateway crates/challenge-common crates/gateway-core 2>/dev/null || true

echo '--- async-lock availability and design-challenge Cargo deps ---'
rg -n 'tokio::sync::Mutex|async-lock|futures::lock::Mutex|Mutex<T>' crates/design-challenge Cargo.toml crates -g '*.toml' | head -40

Repository: BaseIntelligence/base

Length of output: 50380


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo '--- gateway raw weight acceptance ---'
sed -n '33,155p' crates/gateway/src/weights.rs

echo '--- raw weight store implementations ---'
rg -n -C 12 'impl RawWeightStore for MemoryRawWeightStore|AcceptError|raw_weight|Postgres.*raw|pgx|insert|Conflict|get_by_epoch|latest_epoch|get_by_epoch|epoch_end|epoch' crates/gateway crates/gateway-core crates -g 'weights_store.rs' -g 'sealer.rs' -g 'seal*.rs' | sed -n '1,240p'

echo '--- design store schema around scores_for_epoch ---'
rg -n -C 10 'scores_for_epoch|ratings|final_score|rating' crates/design-store crates/design-challenge src crates 2>/dev/null | sed -n '1,220p'

echo '--- Cargo dependencies Tokio/async lock ---'
rg -n 'tokio =|async-lock|futures|parking_lot' Cargo.toml devtools crates/design-challenge/Cargo.toml Cargo.lock || true

Repository: BaseIntelligence/base

Length of output: 34677


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo '--- all scores_for_epoch implementations ---'
rg -n -C 8 'async fn scores_for_epoch|fn scores_for_epoch|scores_for_epoch\(' crates/design-store crates -g '*.rs'

echo '--- gateway raw weight persistence implementations and list helper ---'
rg -n -C 12 'struct.*RawWeight|RawWeightStore for|impl RawWeightStore|insert\(|get\(|list_for_epoch|epochs_for_challenges|list_challenges|seal.*epoch|seal_epoch' crates/gateway crates -g '*.rs' | sed -n '1,260p'

echo '--- orchestrator award_round exact end ---'
sed -n '540,570p' crates/design-challenge/src/orchestrator.rs

Repository: BaseIntelligence/base

Length of output: 27022


Serialize D24 leaf projection with award_round.

run_emitter can submit NotAttempted leaves before award_round persists scores and submits scored leaves. Since emitted_epoch only guards the emitter and award_round does not recheck it, emit_leaves can expose a stale D24 projection to sealing. Use one shared async lock, or a store-backed transaction, held across score persistence and leaf submission in award_round; acquire it before rechecking emitted_epoch in emitter_tick as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/design-challenge/src/orchestrator.rs` around lines 314 - 330,
Serialize D24 leaf projection updates between run_emitter and award_round using
one shared async lock or store transaction. Hold it across score persistence and
leaf submission in award_round, and acquire it in emitter_tick before rechecking
emitted_epoch and calling emit_leaves, so stale NotAttempted leaves cannot be
exposed before scored leaves.

Source: Coding guidelines

Comment on lines 422 to 425
if [[ '$ROLE' == 'validator' ]]; then
docker compose ${COMPOSE_FILES[*]} rm -sf \
prism-challenge design-challenge design-egress-proxy socket-proxy \
>/dev/null 2>&1 || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)deploy/scripts/remote-deploy\.sh$|(^|/)deploy/.*/role-.*\.ya?ml$|(^|/)deploy/[^/]+\.ya?ml$|(^|/)docker-compose.*ya?ml$' || true

echo "== remote-deploy relevant =="
if [ -f deploy/scripts/remote-deploy.sh ]; then
  wc -l deploy/scripts/remote-deploy.sh
  sed -n '350,460p' deploy/scripts/remote-deploy.sh | cat -n
fi

echo "== compose service/profile snippets =="
rg -n "gateway|updater|validator|role-validator|role-master|profile:" deploy --glob '*.{yml,yaml,sh,tf,hcl}' | head -n 200

echo "== behavioral probe: docker compose rm semantics from compose docs? no runtime =="
echo "Inspect compose files for profiles explicitly to validate transition hypothesis:"
python3 - <<'PY'
from pathlib import Path
for p in sorted(Path('deploy').rglob('*')):
    if p.is_file() and p.suffix in {'.yml','.yaml'}:
        text=p.read_text(errors='ignore')
        if 'gateway' in text or 'updater' in text or 'profile:' in text:
            print(f'--- {p} ---')
            for i,line in enumerate(text.splitlines(),1):
                if any(s in line for s in ['gateway','updater','profile:','profiles:', 'profiles']):
                    print(f'{i}: {line}')
PY

Repository: BaseIntelligence/base

Length of output: 30485


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== role-validator.yml complete =="
cat -n deploy/compose/role-validator.yml

echo "== role-master.yml complete =="
cat -n deploy/compose/role-master.yml

echo "== base docker service profile definitions for gateway/updater =="
python3 - <<'PY'
from pathlib import Path
import re
for p in [Path('docker-compose.yml'), Path('docker-compose.e2e.yml')]:
    if p.exists():
        text=p.read_text(errors='ignore')
        lines=text.splitlines()
        in_svc=False
        svc=None
        for i,line in enumerate(lines,1):
            if re.match(r'^[A-Za-z0-9_\-=/.]+\s*:$', line):
                in_svc=True; svc=line.split(':')[0]
                if svc in {'gateway','updater'}:
                    print(f'{p}:{i}: {line.strip()}')
                    while i < len(lines) and (not re.match(r'^[A-Za-z0-9_][A-Za-z0-9_./-]*:', lines[i]) or lines[i].startswith(' ') or lines[i].startswith('\t')):
                        print(f'{i+1}: {lines[i]}')
                        i+=1
                    break
PY

echo "== master profile arguments context =="
sed -n '60,85p;230,255p;396,440p' deploy/scripts/remote-deploy.sh | cat -n

echo "== read-only compose YAML service/profile model =="
python3 - <<'PY'
from pathlib import Path
import re
def parse_overrides(fname):
    hits=[]
    t=Path(fname).read_text(errors='ignore').splitlines()
    for i,line in enumerate(t,1):
        m=re.match(r'^\s+(gateway|updater|validator|prism-challenge|design-challenge|design-egress-proxy|socket-proxy):\s*(.*)?$', line)
        if m:
            svc=m[1]; tail=m[2]
            profiles=[]
            while i < len(t):
                nxt=t[i]
                if re.match(r'^\s{4}profiles:\s*\[([^\]]*)\]', nxt):
                    profiles=profiles + [x.strip().strip('"\'') for x in re.findall(r'[^,\]\s"]+', nxt)]
                elif nxt.strip().startswith('profiles:'):
                    profiles=[]
                elif re.match(r'^[A-Za-z0-9_][A-Za-z0-9_./-]*:', nxt):
                    break
                i+=1
            hits.append((svc, tail or '', profiles))
    return hits
for f in ['deploy/compose/role-master.yml','deploy/compose/role-validator.yml']:
    print(f'--- {f} ---')
    for h in parse_overrides(f):
        print(h)
PY

Repository: BaseIntelligence/base

Length of output: 8422


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== docker compose files =="
git ls-files | rg '(^docker-compose\.ya?ml$|(^|/)compose/.*\.ya?ml$)'

echo "== gateway/updater definitions in base compose =="
for f in docker-compose.yml docker-compose.e2e.yml; do
  [ -f "$f" ] || continue
  echo "--- $f ---"
  rg -n "gateway|updater|profiles:" "$f" -A 8 -B 2 || true
done

echo "== all gateway/updater occurrences =="
rg -n "^\s*gateway:\s*$|^\s*updater:\s*$|profiles:" deploy docker-compose.yml docker-compose.e2e.yml -A 5 -B 2 || true

Repository: BaseIntelligence/base

Length of output: 15895


Remove stale gateways during validator redeploy.

docker compose ... without --profile master leaves an existing gateway container running; deselecting the master profile does not remove it. The validator cleanup now only removes challenges, so a master-to-validator role switch can leave gateway serving on the validator host. Remove gateway from the validator cleanup path and fail if it remains afterward.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/scripts/remote-deploy.sh` around lines 422 - 425, Update the validator
cleanup block in the role check to include gateway alongside the existing
challenge and proxy services passed to docker compose rm. Ensure the cleanup
does not suppress failure when gateway remains, so the redeploy fails if the
stale gateway container cannot be removed.

Source: Coding guidelines

Comment on lines +427 to +428
docker compose ${COMPOSE_FILES[*]} ${PROFILE_ARGS[*]} rm -sf validator \
>/dev/null 2>&1 || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -u

echo "== locate file =="
git ls-files | rg '(^|/)remote-deploy\.sh$' || true

echo "== file stats =="
wc -l deploy/scripts/remote-deploy.sh

echo "== relevant lines 380-460 =="
sed -n '380,460p' deploy/scripts/remote-deploy.sh | cat -n -v | sed 's/^/L/'

echo "== search validator/profile/compose refs =="
rg -n "validator|base-validator-1|base-prod-validator|profile|PROFILE_ARGS|COMPOSE_FILES|docker compose ps|profile:|profiles:" deploy -S

Repository: BaseIntelligence/base

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -u

echo "== compose files and profiles =="
fd -e yml -e yaml . deploy | sort | xargs -r rg -n "name:|services:|profiles:|profile:" -S || true

echo "== validator occurrences in repo =="
rg -n "\bvalidator\b|base-validator-1|base-prod-validator|ROLE|role-master" deploy -S

Repository: BaseIntelligence/base

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -u

echo "== remote-deploy master profile and validator check =="
sed -n '236,260p;416,448p' deploy/scripts/remote-deploy.sh | cat -n

echo "== master role compose =="
cat -n deploy/compose/role-master.yml

echo "== env compose validator sections =="
for f in deploy/compose/env-prod.yml deploy/compose/env-staging.yml deploy/compose/env-local.yml; do
  echo "--- $f ---"
  cat -n "$f" | sed -n '1,70p'
done

echo "== script error handling/exit behavior around absent validator message =="
rg -n "set -[ef]|trap|main|function main|\\}# exit|exit 0|echo \"remote-deploy: done|echo \"master: validator absent" deploy/scripts/remote-deploy.sh

Repository: BaseIntelligence/base

Length of output: 16582


🌐 Web query:

Docker Compose profiles ps --status running includes containers of inactive services

💡 Result:

The docker compose ps command is not currently profile-aware, meaning it does not automatically filter its output to match the profiles specified in the command [1][2]. Even if you execute docker compose --profile ps, the command will typically list all containers defined in your project, regardless of whether those containers belong to an active profile or an inactive one [1][2]. This behavior is a known limitation of the docker compose ps command, which was designed to maintain backward compatibility by listing all containers associated with the project [2]. While you can use the --status flag to filter by the state of the containers (e.g., --status running), this does not implicitly filter out containers based on their configured profiles [3][4]. If you need to limit the output to specific containers, you may need to rely on alternative methods such as using standard CLI tools (e.g., piping to grep) or specifically targeting the service names directly in the command (e.g., docker compose ps <service_name>), as the project continues to prioritize compatibility over adding profile-aware filtering to the ps command [2][5].

Citations:


Fail closed on validator removal and inspection.

rm -sf validator >/dev/null 2>&1 || true can hide a failed cleanup, and a later Compose/Docker failure can leave a stale dual-submit base-validator-1 container. Make the master remove the inactive validator container and exit loudly if removal or the subsequent absence check fails.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/scripts/remote-deploy.sh` around lines 427 - 428, Update the validator
cleanup flow around the docker compose rm command to fail closed: remove the
unconditional “|| true” and suppressed output, ensure removal errors are
reported and terminate the master, then perform an explicit absence check for
the inactive validator container and likewise exit loudly if it still exists.
Preserve the existing validator removal target and use the surrounding
deployment error-handling conventions.

Source: Coding guidelines

@echobt
echobt merged commit 8eb2fb5 into main Aug 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant