feat(workbench): bring up the LoopX Stage 2A stack from one command - #518
Merged
Merged
Conversation
LoopX qualifies its NoKV authority candidate with two environment-gated ladder rows that need an etcd control path, an S3-compatible object store, one serving owner, one existing workbench, a client configuration in the exact key shape of LoopX's JSON-lines helper, and thirteen environment variables. Until now that recipe lived only in a contributor's scratch directory, so the LoopX maintainer could not run the gate themselves. `scripts/workbench/loopx_stage2a_stack.py up` produces the whole stack from one command, reusing the parts CI already qualifies: an isolated etcd member, the digest-pinned RustFS container from `start_rustfs.sh` (or a `moto` S3 server without Docker), and the `provision` / `serve` argument shape of `live_workbench.py`. It refuses a wheel whose version differs from the owner binary or that lacks `WorkspaceIncarnationMismatch`, creates one workbench through the SDK and asserts exactly one incarnation, writes `nokv-client.json` and `live.env` as 0600 files, keeps every credential out of stdout, and refuses to write files whose leaves would trip LoopX's ladder privacy scan. `plan`, `status` and `down --purge` cover dry-run, liveness and teardown. The unit test freezes the command shapes, the LoopX key contracts, secret redaction and the fail-closed paths without starting a process; the workbench-contract CI job compiles and runs it. Signed-off-by: wchwawa <wch19961116@gmail.com>
7 of 17 tasks
huangruiteng
pushed a commit
to loopx-project/loopx
that referenced
this pull request
Sep 24, 2026
… qualification in the ledger (#4889) * docs(rfc): record NoKV v0 envelope capacity and the 0.11.1 fence live qualification in the ledger Two non-normative entries in the shared-goal-authority execution ledger (Appendix D), each with its Chinese mirror: - 2026-09-19: the measured capacity of the NoKV v0 single-envelope layout. The 21,858-byte production-scale history projection reaches the 16 MiB cap at commit 739 (about 0.86 days at the 864 commits/day continuity load) and a 64 KiB projection at commit 252 (0.29 days); live commit latency grows from 341 ms to 3,460 ms and reads are O(history). It also records the NoKV replay and admission facts that bound the bounded-layout design in #4727. - 2026-09-22: the live re-measurement of the incarnation fence connected by #4774 on a stack NoKV-Lab/NoKV#518 brings up from one command: LoopX main 4bed6ed, NoKV 590d3a4bdc (v0.11.1) owner built from that commit, the released 0.11.1 wheel; the complete 23-row ladder passes 22 rows with PostgreSQL unverified and the soak pending; the 0.11.0 wheel is refused typed at admission; the moto fallback passes; the macOS symlinked-TMPDIR condition that fails the s2c2 rows is recorded as a LoopX condition. Neither entry moves a qualification hold or edits an RFC clause; both end with what they do not establish. Signed-off-by: wchwawa <wch19961116@gmail.com> * docs(rfc): attribute the NoKV capacity measurement to the 0.11.0 owner it ran on The 2026-09-19 capacity entry said the live probe ran against a NoKV 0.11.1 owner. It ran against 0.11.0, the release current that day, as #4727 records; 0.11.1 (the incarnation fence) is a separate change recorded in the 2026-09-22 entry, and the capacity numbers were never re-measured on it. Both language mirrors now say so. Signed-off-by: wchwawa <wch19961116@gmail.com> --------- Signed-off-by: wchwawa <wch19961116@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue
Relates to #511 and to the LoopX shared-goal-authority qualification that consumed #514 (loopx-project/loopx#4774). No dedicated issue: this is a test-harness addition whose scope is defined by the LoopX ladder rows it serves; the approving review on loopx#4774 recorded that the LoopX maintainer had no live NoKV owner or workbench to rerun the write-producing Stage 2A probe, and this PR removes that gap.
Summary
scripts/workbench/loopx_stage2a_stack.py upbrings up, from one command, the single-node stack LoopX'ss0.nokv_live_matrixands2a.nokv_live_qualificationrows expect: an isolated etcd member, the digest-pinned RustFS container fromstart_rustfs.sh(or--object-store motowithout Docker), one provisioned owner (--metadata-create,provision/serveargv shape oflive_workbench.py), one workbench created through the SDK (asserting exactly one incarnation), and the two files those rows read:nokv-client.jsonin the exact key shape LoopX'snokv_jsonl_helper.pyadmits andlive.envwith the thirteenNOKV_*/LOOPX_NOKV_AUTHORITY_*variables. Both are written 0600; stdout carries only digests.--pythonmust report the same version asnokv --versionand exportWorkspaceIncarnationMismatch(LoopX pins a fenced 0.11.1 SDK); a non-empty stack directory, a missing binary, a missing etcd, or a generated leaf that would trip LoopX's ladder privacy scan all refuse before anything starts, and a failure after start stops what it started and records the exit codes instack.json.planprints the redacted plan without starting anything;statusreports process liveness (exit 1 when anything is gone);down [--purge]stops the owner, etcd, moto or the RustFS container.loopx_stage2a_stack_test.pyfreezes the command shapes, the LoopX key contracts, secret redaction, the privacy-collision check and the fail-closedplan/down/statuspaths without starting a process; theworkbench-contractCI job compiles and runs it.docs/development/loopx-stage2a-stack.mddocuments prerequisites, outputs, the LoopX commands and what the stack does not prove.Validation
python3 -m py_compile scripts/workbench/loopx_stage2a_stack.py;python3 scripts/workbench/loopx_stage2a_stack_test.py(17 tests);bash -n scripts/workbench/start_rustfs.shworkbench-contractjob lines)upin 5.8 s;statusready;downstops both processes and the container,statusthen exits 1--object-store moto:upin 4.0 s; LoopXs2a.nokv_live_qualificationpass (15 checks);down --purgeleaves nothing--buildfrom this checkout (590d3a4bdc, thev0.11.1tag): binary built withcargo build --release --locked -p nokv --bin nokv,upin 6.8 s--buildstack, LoopXmain4bed6ed3dclean tree, releasednokv==0.11.1wheel (checksum verified), Node 22.22.3: 22 pass,s2b.postgresql_conformance_liveunverified (no PostgreSQL),s2c2.sustained_parity_soakpending as declared, privacy scan 0 violations;s2areports 15 checks includingstale_incarnation_fence_rejectedandstale_incarnation_fence_left_generation_unchanged, final generation 3nokv==0.11.0wheel:s0pass,s2afails typed (nokv_transport_protocol_failed, helper refuses the wheel at admission; no publication reached the owner)--python(system interpreter withoutnokv), non-empty stack dir, unknownstack.jsonschemaTwo defects surfaced during validation and are fixed in this head:
require_executablemust keep a venv'sbin/pythonsymlink instead of resolving it (the resolved base interpreter has nonokv), and the privacy check must not list routing kinds as ladder vocabulary (the configuration's ownetcdleaf tripped it). One LoopX-side condition was observed and is recorded in the LoopX ledger entry, not here: under macOS's symlinkedTMPDIRthe ladder'ss2c2rows fail because LoopX digests the runtime root withrealpathSyncon the TypeScript side andos.path.abspathon the Python side; a symlink-freeTMPDIRpasses.Scope
Change Size And Review
Code Contract (Code Changes Only)
scripts/workbench/, its unit test, a development doc, one README bullet, one docs index link and two lines in theworkbench-contractCI job.