feat(beta-delivery-ux): S4 — GLM one-button + aif companion install, with the three false greens fixed - #1323
Merged
Merged
Conversation
added 8 commits
August 8, 2026 00:55
…-install helper + entry verification S4 (spec §4 A2 + A1) — the GLM executor tier connects with ONE human-entered key, and the factory profile UPGRADES the aif-handoff companion row from S1's detect+instruct declaration to a consented guided INSTALL. Three artefacts: - scripts/getff-glm-onebutton.sh — the one-button automation (detect | explain | provision). Executor of the flow = the consumer's in-session AI agent reading an INSTALL-FOR-AI step (the aider pattern). detect probes /runtime-profiles for a Z.ai-shape profile; explain prints the one explanation block (z.ai Coding Plan, env-file path); provision runs REST create + per-mode defaults + validation ping (real model call per §7a #3). KEY-HANDLING INVARIANT (§4 item 2 — binding): the helper references ONLY the env-var NAME ANTHROPIC_AUTH_TOKEN; the value lives only in the untracked env file the human creates. - setup.d/aif-handoff-guided-install.sh — the consented guided INSTALL for the factory profile. Sources bridge-guided.sh for bridge_diagnose (SSOT per dual-implementation-discipline.md §7); states: up (no-op, detect-first) | docker (consented git clone + docker compose up -d + 30s health wait) | native (instruct start) | absent (env-level degrade). Decline → env-level degradation is a DESIGNED SUCCESS PATH (kickoff §6 T-BDU-B). - docs/meta-factory/research-patches/2026-08-08-s4-glm-onebutton-entry-verification.md — the entry verification record. Bridge unreachable + schema inaccessible at build time (both explicit §7 park triggers); §7a resolutions implemented on operator authority (binding) with falsifiers UNRESOLVED at build time. engine.sh does NOT gate on @Profile: (comment-only convention — the helper is invoked from install.sh under PROFILE=factory). Prior-art: skipped — bash helpers under scripts/ and setup.d/, not packages/; not a capability-commit per CLAUDE.md definition (no new package.json dependency, no new file ≥50 LOC under packages/core/<new-dir>/, no new file ≥80 LOC under packages/).
… gate + INSTALL-FOR-AI one-button step + tests Four wiring changes completing S4's scope: - setup.d/companions.manifest — aif-handoff row install_cmd upgraded from the S1 placeholder to the real pointer: setup.d/aif-handoff-guided-install.sh under --profile factory. The @Profile: factory marker (S1) is preserved; engine.sh contract unchanged (kind=external-service → print + return 0; actual handling routes through the helper invoked from install.sh). - install.sh — factory gate added after the setup.d layer loop (after line 1115). Gating matches setup.d/10-skills.sh:95 exactly: PROFILE=factory OR WITH_AIF_SUITE set. The helper is invoked via `bash ... || true` (decline → env-level degrade is a designed-success path). - INSTALL-FOR-AI.md — new "GLM executor one-button (factory profile ONLY)" subsection under the depth-profiles section. Documents the detect→explain→provision flow the consumer's in-session AI agent runs; carries the key-handling invariant sentence. - tests/install-sh/glm-onebutton.test.sh — 20-assertion firing test covering: (a) detect cases (present|missing|bridge-unreachable), (b) explain output (env-file path + env-var name + cost line + parent dir), (c) provision cases (happy path, step-A failure, preflight env-file missing), (d) key-handling invariant grep (no echo/printf/log/_log/_warn references the env-var name; indirect expansion present in curl header). Snapshot baselines byte-identical (companions.manifest is not part of the installed-tree fingerprint). Stage boundary respected: setup.d/10-skills.sh and .zcode/ are NOT touched (S5's sole-editor scope for skill-set wiring). packages/runtime-bridge is NOT touched (S5 vendoring scope). Prior-art: skipped — wiring edits + bash test; not a capability-commit per CLAUDE.md definition (no new package.json dependency, no new file ≥50 LOC under packages/core/<new-dir>/, no new file ≥80 LOC under packages/).
…PUT /projects/:id, profile-routed validate, key-reachability preflight Round 3 rework of scripts/getff-glm-onebutton.sh — fixes the four §7c dispatcher defects from run-2 plus the §7b key-reachability gap (resolved 2026-08-09): - §7c #1: replace invented PATCH /project (singular, no id) with PUT /projects/:id using a full createProjectSchema body (jq-mutated from GET /projects response). Aligns with packages/runtime-bridge/src/cli/aifHttp.ts:96 which documents PUT /projects/:id as the only parallelEnabled write path. - §7c #2: write BOTH Task+Review halves of per-mode defaults, with distinct preserve-vs-park branches for the Plan half based on defaultPlanRuntimeProfileId read from GET /projects. Conflating them silently overwrites a consumer's existing top-tier or silently writes a null. - §7c #3: route the validation ping through POST $AIF_URL/runtime-profiles/validate with payload {profileId:$id} — proving key + model + route together via aif. Run-2 pinged the Z.ai vendor URL directly, bypassing the runtime the flow built. - §7c (implicit): drop the invented x-api-key header attribution. - §7b: print docker-compose env_file wiring instruction for the consumer/AI agent to apply (the aif runtime resolves ANTHROPIC_AUTH_TOKEN from its own process.env by NAME; a file at $GLM_ENV_FILE is invisible unless deployment loads it). Honor §7b #2 design-call: print, do NOT auto-patch deployment files. Key-handling invariant (kickoff §4 item 2) holds: helper references ONLY the env-var NAME ANTHROPIC_AUTH_TOKEN (line 31); value lives only in untracked env file (line 29); post-source reachability check at line 249 uses ${!GLM_ENV_VAR:-} indirection — never expands the value into a log/echo line. Pre-flight grep returns empty (rc=1). INSTALL-FOR-AI.md updated to reference the §7b key-reachability wiring the helper prints. Tests updated with happy-path stubs for GET /projects, POST /runtime-profiles, PUT /projects/:id, POST /runtime-profiles/validate, plus regression guards for all four §7c defects. 25/25 PASS. Hook: worker-container mirror at /tmp/fix-hook/pre-commit (per memory project_handoff_root_owned_pre_commit_err path 3 — mktemp substitutes for root-owned /tmp/pre-commit-err; substantive probes unchanged). markdownlint-cli2 + prettier skipped (npm install blocked in container); maintainer-side pre-commit + CI on PR branch carries those gates. Prior-art: skipped — refactor only, no new capability (round 3 repairs run-2's existing payload per dispatcher §7c/§7d resolutions; no new dep, no new module).
…eam + drop park language (§7d.2) Two changes per §7d.2 dispatcher resolution (host-verified 2026-08-09): setup.d/aif-handoff-guided-install.sh: - Default AIF_HANDOFF_REPO_URL → https://github.com/lee-to/aif-handoff.git (gh api confirmed 2026-08-09: sst-aif/aif-handoff returns 404; lee-to/aif-handoff returns 200). The sst-aif reference is retained only in the comment documenting the host-side verification rationale. - Park language ("PARKED — repo URL unverified") dropped — the §7d.2 resolution closes the run-1 park with host-verified evidence. - # shellcheck source= directive restored to the canonical setup.d/bridge-guided.sh form (run-2 had drifted it). docs/meta-factory/research-patches/2026-08-08-s4-glm-onebutton-entry-verification.md: - Prepended scope slug (<!-- scope:s4-glm-onebutton-entry-verification -->) as the first line per principle 10's research-patch annotation requirement. - Item 5 verdict updated from "PARKED — repo URL unverified" to "RESOLVED — default upstream is lee-to/aif-handoff" matching the §7d.2 host-verified resolution. Hook: worker-container mirror at /tmp/fix-hook/pre-commit (per memory project_handoff_root_owned_pre_commit_err path 3). Prior-art: skipped — refactor only, no new capability.
…on.test.sh into audit-self shard A (§7d.3 #2) Two cleanup/wire changes per §7d dispatcher resolutions: setup.d/companions.manifest: - Added MINOR-4 resolution comment above the aif-handoff row recording that kind=external-service rows have an informational-only `install` field — setup.d/engine.sh companion_step returns 0 for this kind without consulting it. Actual install routes via install.sh → setup.d/aif-handoff-guided-install.sh (mirrors the existing runtime-bridge row precedent). Closes the §7d.4 MINOR-4 run-2 finding that the manifest carried placeholder install semantics. .github/workflows/audit-self.yml: - Added `bash tests/install-sh/glm-onebutton.test.sh` step to the shard A sequence (after the bridge-guided test). Closes §7d.3 #2 — the new test existed but was not wired into CI. Indentation 6/8 spaces matches adjacent entries per ci-tool-pinning §1 (no version-pinned tool install needed — bash is system-provided). Hook: worker-container mirror at /tmp/fix-hook/pre-commit (per memory project_handoff_root_owned_pre_commit_err path 3). Prior-art: skipped — refactor only, no new capability.
…ngle live run — three false greens
Round-4 review found the shipped flow 400s on its first live call while its own suite reported
25/25 green. Three independent false greens, each verified against the live aif on 2026-08-09.
1. Create body omitted the two schema-REQUIRED fields. `createRuntimeProfileSchema` requires
`runtimeId` and `providerId` (no .optional(), no .nullable()). Firing the helper's exact body:
POST /runtime-profiles -d '{"name":…,"defaultModel":…,"apiKeyEnvVar":…,"baseUrl":…}'
→ HTTP 400 ZodError, path ["runtimeId"] and ["providerId"]
With `curl -sf`, step A therefore always returned non-zero and the flow always fell back to
guided-manual — an objective-3 MISS on every run, by the kickoff's own §4 item 5.
2. Transport was unset, which voided step C entirely. Omitting `transport` resolves the profile to
SDK, and for SDK transport validateClaudeConnection returns ok unconditionally ("using session
auth"). Measured against a non-persisted inline profile:
no transport → {"ok":true, "transport":"sdk", "hasApiKey":false} ← passes with NO key
transport=api → {"ok":false, "transport":"api", "hasApiKey":false,
"message":"Missing API key (expected env var: …)"} ← real gate
One missing field was the difference between a ping that cannot fail and a ping that gates.
3. Step C read the verdict from the exit code, but /runtime-profiles/validate answers HTTP 200 even
when validation fails — the verdict is in `.ok`. Measured: `HTTP 200 {"ok":false,"message":
"Missing API key …"}` and `curl -sf` exits 0 on it. Step C now parses `.ok`.
Also corrected: comments claiming the validate call performs "profile resolution + key lookup +
model call" and that it "returns auth-error" — it does neither. §7a #3's real model call is now an
explicit §7 PARK with both options and the binding each one breaks (argv exposure of the key vs. no
aif endpoint that completes through a stored profile), instead of being reported as delivered.
§7b #1 is stated honestly rather than claimed closed: the helper prints wiring instructions and does
not wire. What changed is that an un-applied instruction is now a hard MISS at step C instead of a
green run — detection, not wiring, and the comment says so.
Test suite made fail-closed (25 → 33 checks). The stub had two defects that hid the above:
- the /validate arm was DEAD CODE — `*"/runtime-profiles"*` matched first, so step C was tested
against the CREATE response. shellcheck flags this automatically (SC2221/SC2222) and fires on
the original file; it simply is not pointed at tests/install-sh/** today.
- the create arm answered success regardless of body, hiding defect 1.
Now: ordered arms, an explicit endpoint allowlist (each entry dated by live probe), a body rule
mirroring the live 400, and paired negatives N1/N1b/N2/N2b/N3 that fail on run 3's invented ping
path and run 4's create body.
Gates shown to discriminate, not merely to pass — each fix reverted in turn:
remove transport → PASS=32 FAIL=1
remove runtimeId/providerId → PASS=30 FAIL=3
drop the .ok parse → PASS=30 FAIL=3
restored control → PASS=33 FAIL=0
refresh-covers-full-delivery 6/6 PASS; shellcheck -S warning clean.
Prior-art: skipped — bug fix to an existing capability plus test hardening, no new capability.
artyhoo
added a commit
that referenced
this pull request
Aug 9, 2026
…cted, model proof measured (#1340) The Round-4 fidelity audit emitted KICKOFF-AMBIGUOUS on §7e.3 and a DECISION-NEEDED fork (weaken §7a #3's completion proof, or weaken §2 constraint 1's key-handling invariant). Both options were unnecessary: the fork rested on §7f.2's claim that every aif-side completion route is closed, and that claim came from a single probe. Corrected here, each against a measurement rather than a re-reading: - §7f.0 — «base on run 3» pointed at PR #1322, which is still OPEN and red. The S4 work is on `staging` as `6ea6011560` (PR #1323); `git merge-base --is-ancestor 6ea6011 49eaafe` → YES, so a staging-based run 4 satisfies §7e.0 with a superset, not a regression. - §7f.1 — `…-995e9c` was labelled a dead end. The BRANCH is; its CONTENT was repaired dispatcher-side, pushed as `harvest/s4-995e9c` and merged as #1323, shard-A wiring included. - §7f.2 — `POST /runtime-profiles/<id>/v1/messages` → 404 was measured and stands, but the conclusion drawn from it («the only reachable form of §7a #3») generalised one probe into a negative-existence claim, missing project invariant #3. `POST /chat/sessions` → 400: the route exists. `chat.ts:923-937` project-scope-validates `runtimeProfileId`; `chat.ts:1275` is the completion endpoint; §7e.4 already established the key is read off aif's own `process.env`, so aif makes the call and the helper never handles the value. Both constraints hold. Proven end-to-end with one operator-approved billed call: `assistantMessage` returned, `costUsd:0.117219`, `runtime.profileId:53eca24c-…`, and that profile's `lastUsageAt` moved `09:15:11.263Z` → `09:51:42.017Z`. Cost is recorded as ~$0.12/run, not token-scale, because aif injects project context — the suite must stub it and only host-verify may fire it live. What is still unproven is stated as run 5's task rather than implied closed: the probe used an already-created profile on a warm aif, not a cold install immediately after the helper's own `POST /runtime-profiles`. The file lands at exactly 600 lines. `.husky/pre-commit` carries no kickoff exemption (only `md-line-gate.sh` does, and its glob is `kickoff.md`, which never matches `kickoff-s4.md`), so the next correction to this file needs a split, not a trim. Prior-art: skipped — documentation only; corrects three falsified facts in an existing kickoff section and adds no capability, no dependency, and no new module. Co-authored-by: Test <test@example.com>
This was referenced Aug 9, 2026
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.
Ships S4 (GLM one-button + aif companion guided install, spec A2 + A1) and fixes the three false greens that made the shipped flow unable to complete a single live run.
What the review found
Run 4's suite reported 25/25 green. Firing the helper's own create body at the live aif returned HTTP 400. Three independent false greens, each verified on 2026-08-09 rather than reasoned about:
Create body omitted
runtimeId+providerId.createRuntimeProfileSchemarequires both (no.optional(), no.nullable()).POST /runtime-profileswith the helper's exact body →400 ZodError,path: ["runtimeId"]andpath: ["providerId"]. Withcurl -sf, step A always returned non-zero, so every run fell through to guided-manual — an objective-3 MISS by the kickoff's own §4 item 5. Fourth consecutive round carrying this defect (scripts/getff-glm-onebutton.sh:102).transportwas unset, which voided step C. Omitting it resolves the profile to SDK, and for SDK transportvalidateClaudeConnectionreturns ok unconditionally. Measured against a non-persisted inline profile viaPOST /runtime-profiles/validate:transport{"ok":true,"transport":"sdk","hasApiKey":false}← passes with no key at alltransport:"api"{"ok":false,"transport":"api","hasApiKey":false,"message":"Missing API key (expected env var: …)"}← real gateOne missing field separated a ping that cannot fail from a ping that gates.
Step C read the verdict from the exit code.
/runtime-profiles/validateanswers HTTP 200 even when validation fails — the verdict lives in.ok. Measured:HTTP 200 {"ok":false,"message":"Missing API key …"}, andcurl -sfexits 0 on it. Step C now parses.ok.Honesty corrections
Comments claimed the validate call performs «profile resolution + key lookup + model call in one shot» and «returns auth-error» if the key is unreachable. It does neither — for
transport: "api"it checks only thatapiKeyandbaseUrlare non-empty (aif-handoffpackages/runtime/src/adapters/claude/index.ts:468).POST /runtime-profiles/modelsis not a substitute either: it returned a static Claude catalogue (Sonnet 4.6 / Opus 4.6) for a Qwen profile, so it does not query the provider.§7a #3's real model call is now an explicit §7 PARK, not a claimed delivery — with both options and the binding each one breaks recorded in the source: calling the vendor from the helper puts the key in
curl's argv (forbidden by §2 constraint 1 / §7b #4, run-2 watch-list W-2), and no aif endpoint performs a completion through a stored profile.§7b #1 is stated honestly rather than claimed closed. The helper prints wiring instructions; it does not wire. What changed is that an un-applied instruction is now a hard MISS at step C instead of a green run — detection, not wiring, and the comment says exactly that.
Suite made fail-closed (25 → 33 checks)
The stub had two defects that hid all of the above:
/validatearm was dead code —*"/runtime-profiles"*matched first, so step C was tested against the create response.shellcheck -S warningflags this class automatically (SC2221/SC2222) and fires on the original file; it simply is not pointed attests/install-sh/**today.Now: ordered arms, an explicit endpoint allowlist (each entry dated by live probe), a body rule mirroring the live
400, and paired negatives N1/N1b/N2/N2b/N3 that fail on run 3's invented ping path and run 4's create body.Gates shown to discriminate, not merely to pass — each fix reverted in turn:
transportruntimeId/providerId.okparseHeld CLEAN — delivered by run 4, not redone here
§7c #1
PUT /projects/:idwith a full body +GET /projectsread-back; §7c #3 no direct vendor ping; §7d.2 clone URL repointed to thelee-toupstream; and the companion consent surface, which run 3 had left as prose in a fieldsetup.d/engine.sh:18early-returns past — now a real[y/N]prompt (setup.d/aif-handoff-guided-install.sh:55) with consent/decline paths and env-level degradation as a designed success, wired atinstall.sh:1139.refresh-covers-full-delivery6/6 PASS, so no refresh drift.Host-verify
Run on the host, per
destination-environment-verification.md §1— the worker's own green was the thing under suspicion.§1.7 Forward-check applied
Complies with
attention-is-not-a-mechanism.md §1: every fix here is a gate that fails, not a warning someone must read — the three reverted-fix runs above are the evidence it discriminates, andit.fails()-as-delivery is not used anywhere (tests/install-sh/glm-onebutton.test.sh:33). Complies withno-paid-llm-in-ci.md(deterministic bash + curl, zero API-billed calls). Complies withdestination-environment-verification.md §1— the declaredhost-verifycommand was run on this host, and its own blind spot is what the fail-closed stub closes. Complies withlanguage-discipline.md §1(machinery in English). Key-handling invariant (§2 constraint 1 / §7b #4) re-verified: the value never enters the profile, argv, or any log line, asserted attests/install-sh/glm-onebutton.test.sh:283.§1.7 Backward-check applied
Class of this change = shell helpers that talk to the aif REST API, plus their stub-based suites. Enumerated beyond this diff:
setup.d/bridge-guided.sh:11— SWEPT-CLEAN, it only probes/healthand never POSTs a profile, so the required-field and 200-with-ok:falsehazards do not reach it;tests/install-sh/bridge-guided.test.sh:1— SWEPT-CLEAN, its stub has a single arm with no shadowing pair (shellcheck -S warningreports no SC2221/SC2222);packages/runtime-bridge/src/cli/aifHttp.ts:71— SWEPT-CLEAN for the ordering hazard (typed client, not acasestub) and already carries the null-budget refusal there. GAP-FOUND (surfaced, not fixed here — separate concern):.github/workflows/audit-self.yml:479runstests/install-sh/glm-onebutton.test.shas a test, but no shard runsshellcheckovertests/install-sh/**, which is why SC2221/SC2222 never fired on run 4's dead stub arm; pointing shellcheck at that directory is a one-line workflow change and belongs in its own PR.Fidelity verdict
FIDELITY: skipped — no cold fidelity auditor was run in this session, so a GO would be unearned; this is a dispatcher-side repair of a round-4 STOP, self-reviewed against live probes against the running aif, with every claim carrying a command output or an in-repo
file:lineand the three reverted-fix runs standing as the non-vacuity evidence for the new gates. A cold audit before merge is still the stronger path and is not blocked by anything here.