Investigation & fixes (failover committed-job loss): - root-cause bug-851 on an owned 3-node cluster: chaotic failover causes silent committed-prefix divergence (WAL hdr.term always 0; two leaders per term; no (term,lsn) reconcile). Evidence in repro-851/ + INVESTIGATION. - live-validated fixes 848/849/850 (recovery-on-promotion, advertise real applied_lsn, persist-layer contiguity guard); add waldump WAL inspector. Specs (strict raft.tla conformance — library owns the log): - TLA-gap-analysis.md: impl vs raft/raft.tla, gaps G1-G6. - raft-log-replication, raft-commit-safety, raft-sim-conformance: extend src/lib/raft to own log/commit/verification via callbacks (specs generated, cross-spec review passed). - ha-term-safety: controller-side adapter + config marker (R1-R7); design done. - config-upgrade-snapshot: R8 descoped here (deps entity-bearing-snapshots, bug-857). - roadmap + buglog (851/854/857) + .wolf knowledge updated.
8.5 KiB
Requirements Document
Introduction
This feature adds a small set of scripting primitives to the xce_test client so that a complete end-to-end scenario — submit work, kill the primary, wait for failover, restart/cold-restart nodes, and assert that committed work survived — can be driven from a single piped or scripted command sequence whose process exit code is the pass/fail verdict. Today xce_test is an interactive client whose success can only be inferred by grepping human-readable output (and which can emit a malformed JobId), so E2E scripts must filter prose, suppress sanitizer noise, and poll controller logs for cluster state. These primitives let the shell remain the orchestrator (node lifecycle, loops) while xce_test reliably reports outcomes.
Boundary Context
- In scope: command-failure tracking and a process exit code that reflects it; a
!-prefixed shell-escape command; a fixed set of tool-maintained auto-variables ($?,$jobid, optional$jobcount); await-primaryblocking command;expect-jobs/expect-jobassertion commands; script ergonomics (#comments, blank lines,echo); correctjobsubsuccess/failure reporting (bug-786); convertingsrc/tools/test-commit-durability.shto use these primitives. - Out of scope: structured/JSON output; a controller status/probe opcode; node-lifecycle commands inside
xce_test(kill/restart/deploy stay in the shell, reachable via!cmd); user-assignable variables, expression evaluation, conditionals, or loops (the shell owns these); any change to controller/replication behavior. - Adjacent expectations:
wait-primaryandjobsub/joblistrely on the existing libxce client-side master-rotation/failover already built intoxce_test; this feature consumes that behavior and does not change it.
Requirements
Requirement 1: Exit code reflects command outcomes
Objective: As an E2E script author, I want the xce_test process to exit non-zero when any command in the session failed, so that a shell can use the exit code alone as the pass/fail verdict.
Acceptance Criteria
- When a command in the session fails, the xce_test client shall record the session as failed.
- When the session ends and at least one command failed, the xce_test client shall exit with a non-zero status.
- When the session ends and every command succeeded, the xce_test client shall exit with status zero.
- While default (abort-on-failure) mode is active, when a command fails, the xce_test client shall stop executing subsequent commands and exit non-zero.
- Where
set continue-on-errorhas been issued, when a command fails, the xce_test client shall continue executing subsequent commands and still exit non-zero at session end. - The xce_test client shall send all human-readable log and diagnostic output in a way that does not corrupt the determination of the exit-code verdict.
Requirement 2: Shell-escape command
Objective: As an E2E script author, I want to run an arbitrary shell command from within an xce_test script, so that a single script can drive node lifecycle (kill, restart, deploy) and environment setup without a separate orchestrator.
Acceptance Criteria
- When a script line begins with
!, the xce_test client shall execute the remainder of the line as a shell command. - When the shell command exits zero, the xce_test client shall treat the
!command as successful. - If the shell command exits non-zero, then the xce_test client shall treat the
!command as failed (subject to Requirement 1's exit-code and abort/continue behavior). - When a
!command completes, the xce_test client shall set$?to the shell command's exit status.
Requirement 3: Tool-maintained auto-variables
Objective: As an E2E script author, I want a fixed set of auto-variables that later commands can reference, so that I can assert on outcomes without parsing client output in the shell.
Acceptance Criteria
- When any command completes, the xce_test client shall set
$?to that command's status (zero on success, non-zero on failure). - When a
jobsubcommand receives a successful acknowledgment, the xce_test client shall set$jobidto the acknowledged JobId. - When a subsequent command references
$jobid(e.g.expect-job $jobid), the xce_test client shall substitute the most recently acknowledged JobId. - Where the
$jobcountauto-variable is provided, when ajoblistcommand completes, the xce_test client shall set$jobcountto the number of jobs returned. - The xce_test client shall not provide user-assignable variables, arithmetic, or expression evaluation beyond substituting this fixed set of auto-variables.
- If a command references an auto-variable that has no current value, then the xce_test client shall fail that command rather than substitute an undefined or garbage value.
Requirement 4: Wait for an elected primary
Objective: As an E2E script author, I want a command that blocks until the cluster has a serving primary, so that scripts can proceed deterministically after a kill or restart without fixed sleeps or log polling.
Acceptance Criteria
- When
wait-primaryis issued, the xce_test client shall repeatedly attempt a client operation against the configured masters until one succeeds. - When a client operation succeeds within the timeout, the xce_test client shall complete
wait-primarysuccessfully. - If no client operation succeeds within the timeout, then the xce_test client shall fail
wait-primary. - Where a timeout argument is supplied (
wait-primary <timeout_ms>), the xce_test client shall use it as the maximum wait; where it is omitted, the client shall use a default timeout.
Requirement 5: Outcome assertions
Objective: As an E2E script author, I want assertion commands that fail the session on mismatch, so that durability/availability expectations are checked in-tool rather than by parsing output.
Acceptance Criteria
- When
expect-jobs Nis issued and the current job count equalsN, the xce_test client shall treat the assertion as passed. - If
expect-jobs Nis issued and the current job count does not equalN, then the xce_test client shall fail the assertion (non-zero status) and report the expected and actual counts. - When
expect-job <jobid>is issued and the given JobId is present in the job list, the xce_test client shall treat the assertion as passed. - If
expect-job <jobid>is issued and the given JobId is absent, then the xce_test client shall fail the assertion and report the missing JobId.
Requirement 6: Script ergonomics
Objective: As an E2E script author, I want comments, blank lines, and progress messages, so that scenario scripts are readable and self-documenting.
Acceptance Criteria
- When a script line's first non-whitespace character is
#, the xce_test client shall treat the line as a comment and ignore it. - When a script line is empty or whitespace-only, the xce_test client shall ignore it without error.
- When
echo <message>is issued, the xce_test client shall emit the message to output and treat the command as successful.
Requirement 7: Correct job-submission reporting
Objective: As an E2E script author, I want jobsub to report success only when a job was genuinely accepted, so that scripts never chase a job the cluster never committed (bug-786).
Acceptance Criteria
- When
jobsubreceives a successful acknowledgment carrying a valid JobId, the xce_test client shall report success and set$jobidto that JobId. - If
jobsubdoes not receive a successful acknowledgment with a valid JobId, then the xce_test client shall report a typed failure (e.g. redirect, no-master, not-ready, or timeout) and set a non-zero status. - The xce_test client shall never report
jobsubsuccess with a malformed or uninitialized JobId.
Requirement 8: Reference E2E driver
Objective: As a maintainer, I want the existing durability soak to use these primitives, so that there is a working reference for script-driven E2E and the primitives are exercised.
Acceptance Criteria
- The
test-commit-durability.shsoak shall be converted to drivexce_testusing the exit-code verdict and the new primitives instead of grepping prose and filtering sanitizer output. - When the converted soak runs against a healthy cluster, it shall report pass/fail using
xce_testexit codes and the assertion commands. - The converted soak shall preserve its existing coverage (rolling primary kill + restart, zero acknowledged-job loss across failover).