Skip to content

feat(workbench): bring up the LoopX Stage 2A stack from one command - #518

Merged
wchwawa merged 1 commit into
mainfrom
feat/loopx-stage2a-stack
Sep 22, 2026
Merged

wchwawa merged 1 commit into
mainfrom
feat/loopx-stage2a-stack

Conversation

@wchwawa

@wchwawa wchwawa commented Sep 22, 2026

Copy link
Copy Markdown
Member

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 up brings up, from one command, the single-node stack LoopX's s0.nokv_live_matrix and s2a.nokv_live_qualification rows expect: an isolated etcd member, the digest-pinned RustFS container from start_rustfs.sh (or --object-store moto without Docker), one provisioned owner (--metadata-create, provision / serve argv shape of live_workbench.py), one workbench created through the SDK (asserting exactly one incarnation), and the two files those rows read: nokv-client.json in the exact key shape LoopX's nokv_jsonl_helper.py admits and live.env with the thirteen NOKV_* / LOOPX_NOKV_AUTHORITY_* variables. Both are written 0600; stdout carries only digests.
  • Admission is fail-closed: the wheel under --python must report the same version as nokv --version and export WorkspaceIncarnationMismatch (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 in stack.json.
  • plan prints the redacted plan without starting anything; status reports process liveness (exit 1 when anything is gone); down [--purge] stops the owner, etcd, moto or the RustFS container.
  • loopx_stage2a_stack_test.py freezes the command shapes, the LoopX key contracts, secret redaction, the privacy-collision check and the fail-closed plan/down/status paths without starting a process; the workbench-contract CI job compiles and runs it. docs/development/loopx-stage2a-stack.md documents prerequisites, outputs, the LoopX commands and what the stack does not prove.

Validation

Check Result
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.sh passed (the exact workbench-contract job lines)
Cold start, RustFS, prebuilt 0.11.1 binary: up in 5.8 s; status ready; down stops both processes and the container, status then exits 1 passed
Cold start, --object-store moto: up in 4.0 s; LoopX s2a.nokv_live_qualification pass (15 checks); down --purge leaves nothing passed
Cold start with --build from this checkout (590d3a4bdc, the v0.11.1 tag): binary built with cargo build --release --locked -p nokv --bin nokv, up in 6.8 s passed
LoopX complete 23-row ladder against the --build stack, LoopX main 4bed6ed3d clean tree, released nokv==0.11.1 wheel (checksum verified), Node 22.22.3: 22 pass, s2b.postgresql_conformance_live unverified (no PostgreSQL), s2c2.sustained_parity_soak pending as declared, privacy scan 0 violations; s2a reports 15 checks including stale_incarnation_fence_rejected and stale_incarnation_fence_left_generation_unchanged, final generation 3 passed
Negative pairing on the same stack with the released nokv==0.11.0 wheel: s0 pass, s2a fails typed (nokv_transport_protocol_failed, helper refuses the wheel at admission; no publication reached the owner) passed (expected refusal)
Wrong --python (system interpreter without nokv), non-empty stack dir, unknown stack.json schema refused with typed messages, exit 2

Two defects surfaced during validation and are fixed in this head: require_executable must keep a venv's bin/python symlink instead of resolving it (the resolved base interpreter has no nokv), and the privacy check must not list routing kinds as ladder vocabulary (the configuration's own etcd leaf tripped it). One LoopX-side condition was observed and is recorded in the LoopX ledger entry, not here: under macOS's symlinked TMPDIR the ladder's s2c2 rows fail because LoopX digests the runtime root with realpathSync on the TypeScript side and os.path.abspath on the Python side; a symlink-free TMPDIR passes.

Scope

  • This PR changes one logical boundary only.
  • No unrelated refactor, benchmark, metadata model, Holt layout, object-store, agent interface, or docs change is mixed in.
  • The linked issue describes the user-visible problem, design decision, or maintenance task this PR resolves.
  • Any breaking change is intentional and documented. (None.)
  • No compatibility shim, deprecated alias, or forwarding wrapper was added without a removal condition.

Change Size And Review

  • I checked GitHub's additions plus deletions for this pull request.
  • If the total is more than 5,000 lines, one core maintainer other than the current-head pusher approved the exact current head commit. (Not applicable: about 1,240 lines.)
  • This change is still small enough for a focused review; approval count is not being used to justify mixed package or lifecycle boundaries.

Code Contract (Code Changes Only)

  • Not applicable to the Rust packages; this adds a Python test harness under scripts/workbench/, its unit test, a development doc, one README bullet, one docs index link and two lines in the workbench-contract CI job.

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>
@feichai0017 feichai0017 moved this to In Progress in NoKV Delivery Sep 22, 2026
@wchwawa
wchwawa merged commit 020b3f4 into main Sep 22, 2026
9 checks passed
@wchwawa
wchwawa deleted the feat/loopx-stage2a-stack branch September 22, 2026 09:27
@github-project-automation github-project-automation Bot moved this from In Progress to Done in NoKV Delivery Sep 22, 2026
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>
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.

2 participants