M07: ZCode adapter: feasibility proof and experimental integration #92
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
P1
P2
P3
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Depends on
#85 A0: Architecture, decisions, and contracts for the optional execution gateway
Creatidy/scarcity-router
Reference
Creatidy/scarcity-router#92
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Determine whether local ZCode can be safely and usefully integrated — without falsely claiming a stable public headless API or guaranteed promotional benefits — and implement only an evidenced, explicitly experimental subset.
Module of the execution-gateway program. This is an independent research/integration track: ZCode may remain experimental, disabled by default, or unsupported for some capabilities without blocking the rest of the execution-gateway program.
User value
If feasible, ZCode subscription/idle-time access becomes an additional execution channel; if not, the program ends up with honest dated evidence instead of a fragile undocumented integration.
Relationship to current code
providers/zai*.py), the GLM-5.3 reasoning-effort identities (catalog v3, D-038) and the campaign-window policy (D-035) already express Z.ai-side routing preferences; ZCode as an execution surface is new.Stage 1: feasibility verification (no dependencies; evidence may start immediately)
Check current: vendor documentation; vendor terms; local runtime/protocol behavior; runtime discovery; authentication; headless execution; output format; cancellation; tool behavior; permissions; version stability; actual usage/quota accounting.
Unofficial wrappers (e.g. https://github.com/valeriikot/zcode-cli) are research evidence only — never proof of official API support, long-term compatibility, right to redistribute the runtime, or promotional eligibility.
Stage 2: supported-subset implementation (depends on A0 #85 and M05)
Only after feasibility has been established.
Non-goals
Contracts / interfaces affected
Execution adapter contract (A0); compatibility matrix (M03); potentially eligibility reports extended to the ZCode surface (explicit, versioned).
Dependencies
Acceptance criteria
Security considerations
Session, filesystem and tool isolation per A0's threat model; no accidental import of unrelated conversation history or global plugins; the permission model is explicitly mapped before any execution; no prompt/response logging; provider subscription and promotional terms are respected (https://zcode.z.ai/en/terms re-verified with date at implementation time).
Risks
Evidence still required
M07 closeout — Stage 1 COMPLETE; Stage 2 NO-GO / cancelled (owner decision, D-047)
Stage 1: COMPLETE. Dated feasibility evidence is merged at
develop@85b55d3(PR #100) indocs/zcode-adapter-stage1-evidence.md(all sources retrieved 2026-09-19; local runtime 3.14.0; no live inference probes). Headline: no official, stable, headless ZCode execution path exists as of 2026-09-19 — no official CLI, public execution API, SDK or external trigger surface; the only headless mechanism is an undocumented internal Unix-socket IPC path in desktop-attached mode.Stage 2: NO-GO / CANCELLED. The owner reviewed the Stage-1 evidence and decided not to implement a ZCode execution adapter. Recorded durably as D-047 in
docs/decisions.md(documentation-alignment PR: #103). Reasons:No runtime adapter was implemented. This issue closes as completed feasibility research, not as active implementation work. U-013 in
docs/decisions.mdis resolved by the Stage-1 evidence plus this decision; its historical question list and answer provenance are preserved.Reopening condition (the only path back): M07 may be reconsidered only when ZCode ships an official supported programmatic interface (CLI, API, SDK or headless automation surface) — or another official supported integration surface becomes available — AND applicable vendor terms permit the intended use, through a new superseding decision. No repository-side polling/monitoring is implemented; the trigger is evaluated from external vendor observation.
ZCode Desktop ≠ Z.ai API: supported Z.ai Coding Plan execution remains in scope under M04 (#89) through the vendor-documented OpenAI-compatible HTTP endpoint (distinct resource/entitlement per D-042; terms suitability under U-009). This NO-GO does not remove Z.ai HTTP/API support.
Closing as completed: Stage 1 acceptance evidence exists and Stage 2 is cancelled by owner decision.
Stage 2 reopen evaluation executed (D-061) — Stage 2 remains NO-GO; interface gate now passes, terms gate does not
Per D-047 point 4, the reopen condition was evaluated against current official ZCode state. Evidence:
docs/zcode-adapter-stage2-evidence.mdon branchadapter/zcode-cli-stage2(PR follows). All sources retrieved/probed 2026-09-28.Gate results
29628c9) ships a first-party Apache-2.0 CLI (apps/zcode-cli):--prompt/-p,--target,--cwd,--mode, strict--output-format text|json|stream-json(unknown values error, never silently text), NDJSON events + typed final result,--disallowed-tools,--resume,app-server/agent-server,doctor --json.NOTICE.mddocuments the non-interactive--promptpath in the vendor's own words. Stage 1's "no supported programmatic surface" finding no longer holds.--promptdefaults to yolo (help text, NOTICE.md,DEFAULT_HEADLESS_PROMPT_MODEin source all agree) — the hazard is real. But--mode build|plan|editis officially supported, and under non-yolo modes every side-effecting/high/critical tool returnsask, which a headless run cannot answer: the defaultDenyPermissionBrokerdenies it (fail-closed). Any future adapter must always pass an explicit safe mode.MODEL_TLS_VALIDATION_FAILED); the CLI refused the endpoint rather than bypassing validation (favorable evidence in itself).Consequence
No adapter is implemented. D-047 is not superseded — D-061 updates its factual basis: reopen condition 1 (official interface) is now met and dated; reopen condition 2 (terms) remains unmet. Stage 2 may reopen only with (a) written vendor authorization for proxy-style automation scoped to owner-account, single-administrator deployments, or (b) a vendor-official integration surface whose terms clearly cover router-style execution. The implementation path is already sketched (D-056 boundary + Codex worker-adapter reuse patterns; explicit
--mode buildas a hard design constraint).Docs-only PR follows against
develop; left open for human review; not merged. Full validation gate green on the exact head (2190 tests, basedpyright clean).Gate C re-evaluated on the owner's direction — M07 Stage 2 is REOPENED (D-061 revised, 2026-09-28)
The reopen evaluation in PR #157 originally concluded the vendor-terms gate UNCLEAR/BLOCKED from a Stage-1-style reading ("proxy-style use lacks vendor authorization"). The owner rejected that reasoning as conflating Scarcity Router's architectural role with the Terms' "unauthorized proxy server" clause, and directed a re-evaluation of gate C only, against the concrete single-owner deployment scope, using current official sources. That re-evaluation is now recorded (evidence doc §5, D-061 revised, head
3be4b6b):--promptpath and automation surfaces confirm automation is supported and regulated (oversight, security-file constraints), not forbidden.Result: Gates A, B, C (scoped), D all pass → Stage 2 REOPENED; D-047's NO-GO superseded via its own point-4 reopen procedure. Implementation of the ZCode CLI adapter is authorized subject to recorded constraints (explicit safe mode always passed; typed denials; credentials never extracted; supported-tools-only quota use; operator oversight) and retained exclusions (third-party/multi-user exposure, resale, pooling, quota circumvention, security-config bypass, direct coding-endpoint calls). The adapter implementation is a follow-up task; PR #157 remains documentation-only and open for human review.
Sources (all official, retrieved 2026-09-28, quoted verbatim in the evidence document): ZCode Terms of Service (effective 2026-06-15), Z.AI Terms of Use (2026-04-14), GLM Coding Plan Usage Policy, Subscription Terms §4, devpack Overview, devpack guide "Using GLM Coding Plan in ZCode".
An independent adversarial review of the gate C reasoning confirmed quote accuracy, soundness and classification; its two documentation-consistency blockers were remediated on the pushed head. Validation gate green on
3be4b6b(2190 tests OK, basedpyright clean, git diff --check clean).Implementation started — M07 Stage 2: official ZCode CLI execution source
develop:59538e9(merge of PR #157 — D-061 verified present)task/92-zcode-stage2scarcity-router-task-92-zcode-stage2zcode:<source_id>) behind the existing M05LocalAdapterseam and the D-053 source architecture — no second runtime, no new execution channel.zcode_subscription(providerzai), extension of the closed kind vocabulary per D-061's implementation authorization.zcodesubprocess per dispatched call, argv-only (prompt/path/mode strictly data; never a shell),--mode buildalways explicit (never the yolo default), explicit--cwdinto an adapter-owned per-attempt scratch workspace,--output-format stream-jsonconsumed incrementally under bounded budgets, bounded stderr drain, cancellation/timeout via the existing process-lifecycle semantics, typed failure classification, no blind retry.plan-managed, no variant/effort claims); server-side adoption stays closed (visible, never routable) until owner-approved zai track evidence lands — the D-053 behavior for unevidenced slugs. Observed identities from structured results are provenance only, never advertised capability.unverified(never "healthy because the binary exists");auth_requiredis only claimed when evidence supports it. Credentials are never read, copied, wrapped or logged; the owner's officialzcode login zaistays the only auth path.LIVE_ACCEPTANCE_NOT_RUNis reported with the exact reason.develop, not merged by agents.Implementation complete — PR #161 open, review APPROVED, live-acceptance status recorded
Ship it: base
develop59538e9→ branchtask/92-zcode-stage2(worktreescarcity-router-task-92-zcode-stage2) → PR #161 → headb0bf858(single commit, no merge commits, files in scope). Design record D-063; D-061 treated as settled throughout.Architecture (concise): one worker-side source adapter (
zcode:<source_id>, new closed kindzcode_subscription, providerzai) behind the existing M05LocalAdapterseam and the D-053 source machinery — no second runtime. One headless official-CLI run per dispatched call:zcode --prompt <text> --cwd <adapter-owned per-attempt workspace> --mode build --output-format stream-json --no-browser, argv-only (no shell anywhere), safe mode always explicit (yolo default never relied on), bounded NDJSON consumption via the shared bounded reader, terminal contract = result line AND exit 0 (every other ending is a typed failure or an explicitunknown), exactly one invocation per call, no retry, stderr counted-never-read, minimal child environment. Process lifecycle seam imported unchanged from the proven Codex adapter.Reused components: Codex spawn spec / spawner / terminate-with-reap-proof; Codex acquisition bounded line reader; D-053
SourceRegistryadoption/inventory paths (zero worker-loop changes — duck-typed hooks); M05 allowlist; capacity v3 snapshots; gateway normalized seam (AdapterCall/Result/Chunks).Files changed (13): new
scarcity_router/worker_zcode_adapter.py,tests/test_worker_zcode_adapter.py(85 tests),tests/zcode_fake_cli.py; modifiedexecution_sources.py(per-kind surface capabilities + adapter prefix + floor-entry provider fix),model_inventory.py+server_config.py(kind vocabulary, provider map, entitlement pin),worker_client.py(--zcode-source/--zcode-bin),test_execution_sources.py(5 server-side tests),test_openai_http_adapter.py(one guardrail modernized, intent preserved),docs/decisions.md(D-063),docs/providers.md,docs/architecture.md,docs/roadmap.md.Validation (exact head
b0bf858):uv sync --only-devOK;make checkgreen — 2280 tests OK; basedpyright 0 errors / 0 warnings / 0 notes;git diff --checkclean. One earlier full-suite run hit the documented pre-existing #143-familytest_scenario_11cancel-race flake (passed in isolation and in the final run; path untouched).Independent review: exact-head adversarial review — APPROVED, 0 MERGE_BLOCKER, 8 DEFER (recorded on the PR; reviewer verified the SHA and ran the suites; reviewer substitution disclosed there: preferred GPT-5.6 Sol High unreachable — its gateway is the recorded broken
new-providerendpoint — independent GLM-5.3-Flash instance used). UX impact: minor, non-blocking (UI add-source form stays codex-only — recorded follow-up).Live acceptance: PARTIAL — discovery path LIVE-VERIFIED; execution path
LIVE_ACCEPTANCE_NOT_RUNwith reasons.0.16.9— the evidenced v3.14.3 artifact;doctor --jsonmatches the evidenced shape) was driven through the REAL adapter's discovery path: binary discovery via pin → version probe0.16.9→ doctor probe validated → inventory{kind: zcode_subscription, auth_state: unverified, models: [plan-managed]}→ lane resourcelive-check:plan-managedserved → snapshot honestlyunknown/telemetry_unknown. Acceptance items 1 and the probe halves of 3–8 verified live; item 10 verified structurally (no credential material read at any point — the shared config was never opened by the adapter).new-providerendpoint that fails the CLI's TLS validation (D-061 §4 — unchanged), so a green completion cannot occur here; the only credentials present are the shared harness credentials whose interactive login/session state must not be exercised by headless automation (D-061 constraint 2);zcode login zaiis interactive browser OAuth and is never automated. The owner-run acceptance remains open at the human decision point, exactly like theLIVE_TOOL_BRIDGE_NOT_VERIFIEDprecedent on #137/PR #159.Remaining limitations (recorded in D-063 / providers.md): the plan lane is visible-but-not-routable until owner-approved
zaitrack evidence lands inmodel-tracks.json(follow-up decision); auth converges only tounverifieduntil ZCode ships a non-inference auth probe; review DEFERs 1–8 recorded for owner selection.Not merged — PR #161 stays open for human review per governance.
Remediation round complete — review APPROVED (0 blockers) — live acceptance
LIVE_ACCEPTANCE_BLOCKEDwith owner procedureShip it: PR #161 head
b795ec6(base59538e9; commitsb0bf858implementation +b795ec6remediation; no merge commits). Starting SHA of the round:b0bf858. D-063 amended in place (2026-09-29).The three blockers — exact corrections
--zcode-workspace, REQUIRED with--zcode-source): realpath-canonicalized at construction, verified (missing/non-directory → loud construction failure), re-validated fresh before every run, passed as BOTH--cwdand the process cwd. Request content can never supply or select a path — no request field reaches the workspace decision. The scratch machinery was removed, not fallback-ed (state/workspace separation is structural). Design reuse: construction-time authority is the existing adapter-configuration pattern (the loopback adapter's host allowlist), not a new system.--mode edit(wasbuild), with first-party proof. Officialpermission/service.tsat the D-061-pinned commit29628c9, verified identical in the shipped 0.16.9 bundle:buildallows only read-only + low-risk session-local tools — every workspace-writing tool returnsaskand is DENIED headless, sobuildcannot edit.editis the least-authority officially supported mode that permits the workflow: its first check explicitly allows workspace-scoped file edits (mode.edit.fileEdit); every other side-effecting or high/critical-risk tool (command execution included) still requires anaska headless run cannot answer → the vendor's default broker denies it, fail closed. The CLI confines file tools to the workspace (outside paths rejected, symlinks judged by real path). yolo never relied on, restored, or fallen back to.plan-managedroutes through the NORMAL selector. Owner-reviewedzai/plantrack inmodel-tracks.json(plan_managed: true, minimum-of-scale floor, plan-family continuity 1M/128K) + the smallest generic adoption extension: an effort-less plan-managed lane adopts from a HEALTHY source observation as ONE variant-less resource with ONE effort-less catalog entry (variantplan, effort null, no reasoning support). A plainmodel: "plan-managed"request resolves via normal D-055 resolution and routes with no pin and no bypass; an effort-bearing request is a typed 400unsupported_reasoning_effort; physical slugs (glm-5.3) classify nowhere onzai— no physical model is invented, exact-identity untouched for enforceable resources (codex gates unchanged, tests green unchanged). Auth honesty preserved:unverifiedis the honest steady state (no non-inference auth probe exists); healthy-unverified adoption and probe-health snapshots are scoped viaAUTH_UNPROBEABLE_KINDS; an actual sign-in failure is a typed execution failure.Request shape (§5)
One non-empty user message is the entire evidenced CLI surface; with the authorized workspace it is SUFFICIENT for the coding workflow (the acceptance performs a real file edit through it). Richer shapes stay typed rejections — refuse-not-drop, no pseudo-transcript concatenation.
Evidence
notes.txt,git statusclean otherwise) → honest audit against the lane; effort request → 400 with zero spawns; admission-deadline cancellation → 408 +timed_outaudit + child reaped. (tests/test_e2e_zcode_acceptance.py)LIVE_ACCEPTANCE_BLOCKED— upstream, not code. The real router path was exercised live against the REAL official CLI (0.16.9): discovery ✓, lane routable ✓, request routed ✓, real CLI launched in the authorized repo ✓ — then the run failed TYPED (HTTP 502backend_failure, auditfailed) at the shared ZCode configuration's pinned provider endpoint (https://192.168.2.13:8787/v1):providerErrorCode: MODEL_TLS_VALIDATION_FAILED, "TLS validation failed for the provider request.",retryable: false— the CLI refuses fail-closed (unchanged since D-061 §4; quota untouched; no credential read/copied/configured). Cancellation could not be meaningfully exercised live against a ~1 s failing provider; the deterministic cancellation acceptance plus the D-061 live SIGTERM bounding stand in.b795ec6:make checkgreen — 2294 tests OK; basedpyright 0/0/0;git diff --checkclean.Owner-run acceptance procedure (unblocks
READY_FOR_OWNER_MERGE)new-provider → https://192.168.2.13:8787/v1, whose certificate the CLI refuses (MODEL_TLS_VALIDATION_FAILED). Either fix that endpoint's certificate (CA trusted by the CLI) or re-bind the shared configuration to the Z.ai login path via the official interactivezcode login zai.zcode --prompt "reply with: ok" --cwd /tmp --mode plan --output-format stream-json --no-browseruv run scarcity-router-worker run --zcode-source zai1 --zcode-workspace /path/to/disposable-repo(pair first as usual; configure the server sourcekind: zcode_subscription, worker bound, providerzai).{"model": "plan-managed", "messages": [{"role": "user", "content": "Append exactly this line to notes.txt: LIVE-ACCEPTANCE-SENTINEL"}]}notes.txt;git status --porcelainshows onlynotes.txt; auditexecuted_target.resource_id == "zai1:plan-managed",result_status == "completed". Then repeat with a stuck task (e.g. a long prompt) to observe the bounded 408 cancellation.Final state:
BLOCKED— solely on the live-acceptance condition (upstream provider endpoint outside this repository's control). Everything the code and this repository own is green and reviewed: authorized-workspace execution, evidenced least-authority edit mode, normally routable honest lane, full deterministic acceptance, zero blockers on the exact head. PR #161 stays open, unmerged.FINAL LIVE ACCEPTANCE: PASS — normal Scarcity Router path, real edit, on unchanged head
b795ec6The upstream prerequisite is resolved (complete official CLI build +
login zai; the removednew-providerendpoint no longer participates). The final M07 Stage 2 acceptance ran through the normal Scarcity Router execution path — not an adapter-direct call — on the exact reviewed head.Path exercised:
POST /v1/chat/completions {"model": "plan-managed"}(plain logical request) → normal selector →zai-plan-1:plan-managedplan-managed lane → worker dispatch → official ZCode CLI → authorized disposable Git repository → real file edit.Evidence (all mechanical):
--version→0.16.9,doctor --jsonvalidated; configured binary:/home/adrian/workspace/zcode/apps/zcode-cli/packages/cli/dist/zcode.cjs(via the adapter's pinned-binary seam; the host bundle was NOT used)wait_for_lanerequired a FRESH applied lane snapshot before the request; the plain request (no pin) returned HTTP 200 withmodel: "plan-managed"result_status: "completed",executed_target = {"resource_id": "zai-plan-1:plan-managed", "provider": "zai", "model": "plan-managed", "variant": "plan"}--mode edit--prompt <task> --cwd <repo> --mode edit --output-format stream-json --no-browser--cwdAND subprocess cwd = the disposable repoCWD=/tmp/.../repofor the run invocation;ARGV4=/tmp/.../repostream-jsonto the terminal contract; the gateway answered a well-formed completion (finish_reason: "stop")sample.txtreads exactlyZCODE_ROUTER_LIVE_ACCEPTANCE_OKgit diff --stat:sample.txt | 2 +-(1 insertion, 1 deletion);git status --short:M sample.txtonly; no unexpected new filescompletedagainst the laneResponse content (the CLI's own answer): "Done.
sample.txtpreviously containedbeforeand now contains exactlyZCODE_ROUTER_LIVE_ACCEPTANCE_OK."Provider path: the official/default Z.ai Coding Plan configuration was used — the run completed, which the removed
new-providerendpoint could not do (its TLS failure produced a typed 502 in the pre-fix probe); the owner-established active model isaccount:zai-individual-coding-plan/GLM-5.3vialogin zai.Cancellation: not repeated live, per the task's economy rule — the deterministic composed acceptance at this exact head already proves the same process/cancellation path (admission deadline → 408
execution_time_limit_exceeded,timed_outaudit against the lane, child terminated and reaped;tests/test_e2e_zcode_acceptance.py), and no production code has changed since the exact-head review.Repository state: head unchanged at
b795ec63ea5319c15d62a8b15a8ab3f7f3499bf3;git statusclean in the PR worktree; this acceptance caused no repository code change, no new commit, and no re-review. The disposable repository and rig were deleted after evidence collection. PR #161 remains open — owner merge is manual.completed