Skip to content

chore(meta-factory): Phase 3 Step 0 retrofit + 3 MAJOR fixes - #3

Merged
artyhoo merged 4 commits into
mainfrom
chore/phase-3-aif-retrofit
May 7, 2026
Merged

chore(meta-factory): Phase 3 Step 0 retrofit + 3 MAJOR fixes#3
artyhoo merged 4 commits into
mainfrom
chore/phase-3-aif-retrofit

Conversation

@artyhoo

@artyhoo artyhoo commented May 7, 2026

Copy link
Copy Markdown
Owner

Summary

Apply EXECUTION-PLAN §5.5 «Existing solutions research» retroactively к Phase 3 (monorepo split, merged 2026-05-08) + close 3 MAJOR findings из reviewer verdict 2026-05-08.

Verdict: KEEP merged Phase 3 as-is. Все 5 capability decisions (workspaces, linking, build, tests, version mgmt) validate ex-post через context7 research; нет capability change worth revert+redo cost.

Commits

  • 3acf37a — Phase 3 Step 0 retrofit (Task 2 + bonus)
    • phase-3-research.md (136 lines) — context7 matrix против nx/turborepo/pnpm/lerna/changesets, KEEP verdict
    • PHASE-3-PROMPT-v0.2.0.md (108 lines) — counterfactual delta prompt
    • EXECUTION-PLAN.md §5.5 — closure pointer
  • 29acb8d — 3 MAJOR fixes (Task 1)
    • MAJOR-1: terminology two-AI reviewvia AIF review-sidecar (PROPOSAL §1.2, architecture L0, risks, EXECUTION-PLAN Phase 5)
    • MAJOR-2: 4 AIF coupling risks added к risks.md (version, adoption, API contract, identity dilution)
    • MAJOR-3: Phase 4-9 caveat pointer на §5.5 Step 0 gate
  • a5e8f56 — paper trail commit PHASE-3-RETROFIT-PROMPT.md

Reuse-vs-build matrix (from phase-3-research.md)

# Capability Decision Forward trigger
1 Workspace declaration KEEP npm watch pnpm catalog at ≥5 packages × ≥8 shared dev-deps
2 Cross-package linking KEEP * peerDeps switch to workspace:* if pnpm migration
3 Build orchestration DEFER (no Nx/Turbo) re-eval at ≥30s CI runtime OR cross-package compile chain
4 Cross-package tests KEEP npm --workspaces same threshold
5 Version management DEFER → Phase 8/11 (Changesets) pre-publish trigger

Test plan

  • Pre-commit hook (bash/JSON/YAML/markdown ≤500): green
  • Pre-push hook (actionlint, zizmor, principles 24/24, render-rules drift, spec validation): green
  • make self-audit: 5 pass / 0 fail
  • All 4 spec'd terminology edits applied (PROPOSAL:48, architecture:29, risks:18, EXECUTION-PLAN:500)
  • 4 AIF coupling risks count = 4
  • Phase 4-9 caveat at line 212
  • phase-3-research.md ≤200 lines (136)
  • CI on push: audit-self.yml green
  • Reviewer GO/REVISE on merge

References

artyhoo added 4 commits May 8, 2026 02:19
Three actions after independent validator pass 2026-05-08:

1. EXECUTION-PLAN §5.5 — Phase entry gate "context7-first research"
   mandatory for Phase 3 retrofit + Phase 4-9. Hard constraint:
   no git clone for external libraries, only context7 MCP queries.

2. aif-comparison.md corrections:
   - §4 split: 4 confirmed differentiators (mutation, manifest-SSOT,
     paired examples, recursive self-application) vs 2 conventions
     atop AIF infrastructure (two-AI tautology, stack scoping).
   - §9 reuse-vs-build matrix with per-Phase impact (3-9).
   - §10 confirmed differentiators after validator + alternatives
     research (Reflexion, LangGraph, AutoGen, CrewAI, Aider, etc).

3. PROPOSAL §1.4 — strategic positioning: project is plug-in for
   AIF runtime, not parallel framework. ~30-40% capability via
   AIF reuse; uniqueness is logical self-application layer.

Estimated reuse savings: 30-40% original Phase 4-9 scope.
Verification: all claims via context7 MCP, no source clones.
Apply EXECUTION-PLAN §5.5 «Existing solutions research» retroactively
to Phase 3 (monorepo split, merged 2026-05-08). Verdict: KEEP merged
work as-is; all 5 capability decisions validate ex-post.

Capability matrix (context7 queries against nx_dev, turborepo_dev,
pnpm.io, lerna, changesets — no source clones):

| Capability                      | Decision               |
|---------------------------------|------------------------|
| Workspace declaration           | KEEP npm; watch pnpm   |
| Cross-package linking           | KEEP `*` peerDeps      |
| Build orchestration             | DEFER (no Nx/Turbo)    |
| Cross-package test execution    | KEEP `npm --workspaces`|
| Version management              | DEFER → Phase 8/11     |

Acceptance per §5.5: 4 KEEP/DEFER + 1 forward-add (Changesets).

Files added:
- docs/meta-factory/phase-3-research.md — Step 0 matrix (136 lines,
  under §5.5 transient ≤200 cap)
- docs/meta-factory/PHASE-3-PROMPT-v0.2.0.md — counterfactual delta
  prompt; v0.1 body Blocks 2-6 unchanged (108 lines)

EXECUTION-PLAN §5.5 updated with closure pointer (2 lines).

Cost-benefit of revert+redo: discard ≥40h Phase 3+3.1 effort for zero
capability change at current scale (3 packages, <3s test runtime, no
cross-package compile chain). Verdict: KEEP.

Forward Step 0 triggers tracked: Phase 4 entry, Phase 8 (Changesets
pre-publish), Phase 9+ (pnpm catalog / Nx / Turbo re-eval thresholds).
…ixes)

After reviewer verdict 2026-05-08:
- MAJOR-1: terminology fix 'two-AI review' → 'via AIF review-sidecar'
  in PROPOSAL §1.2, architecture.md L0, risks.md, EXECUTION-PLAN Phase 5
- MAJOR-2: add 4 AIF coupling risks to risks.md (version, adoption, API, identity)
- MAJOR-3: Phase 4-9 caveat pointer to §5.5 Step 0 gate before drafts

Reference: aif-comparison.md §9 reuse matrix, §10 confirmed differentiators.
Self-contained delegation prompt that drove commits:
- 3acf37a (Task 2 retrofit research)
- 29acb8d (Task 1 — 3 MAJOR fixes)

Tracked alongside existing PHASE-N-PROMPT.md artifacts for orchestrator
audit trail consistency.
@artyhoo
artyhoo merged commit 12b4213 into main May 7, 2026
18 checks passed
artyhoo added a commit that referenced this pull request May 8, 2026
…(a))

Independent review (Opus 4.7) flagged L1 (a) idempotence test as vacuous on
this repo: husky cp/chmod blocks at setup.sh:339,345 gate on a templates
path that doesn't exist (templates moved in Phase 3.1), so dry-run
idempotence proves only non-husky steps. Lowering self-app score 9→7,
promoting Open question #3 from out-of-scope cleanup to Phase 5 entry
blocker. M2 (arch.md §2.3 drift) and m1 (aif-comparison.md §5 sync)
deferred to Phase 5 entry hygiene. Probes 1–10 still green; verdict
remains GO.
artyhoo added a commit that referenced this pull request May 8, 2026
… 7→8

Reflects state after 1555fb1 (setup.sh templates path fix). L1 (a)
idempotence criterion no longer vacuous: dry-run output includes 4
husky [dry-run] would: cp/chmod lines, proving the install path is
exercised. Score evolution now visible in retro:
  9/10 (initial Phase 4 close)
  7/10 (post-review calibration, reviewer M1)
  8/10 (post-fix, reversal-condition met)

Open question #3 closed; new Open question #6 logged for wider
Phase 3.1 fallout (react-next templates path rot in setup.sh:230-244,
stack-gated so doesn't affect this repo's L1 self-app, but will break
react-next consumers).

Probes 1-10 still green; verdict remains GO.
artyhoo added a commit that referenced this pull request May 8, 2026
Open #2 (Tailwind v3/v4 version-aware) closed by ea3e006 via
patterns[] field including tailwind-v3-config + tailwind-v4-css-tokens.
Mantine/Chakra additions remain additive scope.

New versioning entry covers Bundle 4-partial-extended completion:
- missing[] + patterns[] schema additions (v1-active partial)
- arch.md §2.3 v1.1 subset annotation (Q2/M2 partial closure)
- detector-v0 deprecation declared
- Test count semantics clarified per prior reviewer note

Phase 5 entry closures total: 5 of 6 (Open #2, #3, #5, #6 + m1).
Q2/M2: partial via annotation; full v2 deferred to Phase 7+.
artyhoo added a commit that referenced this pull request May 8, 2026
Phase 8.8.1 addendum push-based health check on 12 non-cascade §13.x
triggers (excluding §13.2 narrative, §13.3/§13.6/§13.7/§13.9 closed,
§13.11 cascade, §13.10 #5 cascade, §13.15 unused). For each entry:
decompose trigger into observable signals → run verification probe →
classify FIRED / STILL ARMED / CASCADE-DEPENDENT.

Result: 12/12 STILL ARMED or PENDING T7. Zero FIRED. No per-fire
trigger-fire-§<N>.md patches needed.

Probes consulted:
- §13.1: research-store file count (12 at 1-pattern-per-file granularity);
- §13.4 / §13.5 / §13.10 #4 / §13.12 / §13.13: consumer evidence (none);
- §13.8: self-application.md §3 row count (9, no 10th proposal);
- §13.10 #1: Phase 8 closure status (no curated-store gap);
- §13.10 #2: Phase 9 entry coverage gap recorded f92f60b — DEFER carries forward;
- §13.10 #3: Phase 9 implementation scope (housekeeping only — no new pattern);
- §13.14: rules-lock.json schemaVersion = 1 (no bump);
- §13.16: PENDING T7 self-review.

Sweep adds value most when external signals (consumer issues, version
bumps) accumulate between sessions OR a phase fires a trigger the
originating session didn't notice. Both vectors quiet at 2026-05-08;
unsurprising outcome.

Re-sweep cadence: next phase entry research session. T6 distillation
folds the sweep methodology into rule §1 as 6th checklist item.

Prior-art: skipped — docs-only sweep report companion to T5.5 audit, no new capability surface or explicit dependency added (per CLAUDE.md capability-commit definition).
artyhoo added a commit that referenced this pull request May 10, 2026
…-1, MAJOR-2, MINOR-1, MINOR-2)

MAJOR-1: §3 ATTN + REPORT ATTN — correct shipped-artefact paths (skills/, agents/ at
repo root, not .claude/skills/, .claude/agents/); narrow Claude-first bias claim to
.claude/skills/self-reflection/ + proposed harness-hook layer.

MAJOR-2: §0 row + §1 row 1 + §8 entry #16 + §11 sub-wave 7.1 + §12.1 — lint-staged is
NOT installed and root ESLint config does NOT exist; reframe as PRECONDITION for
sub-wave 7.1 (not baseline).

MINOR-1: cascade-table footnote — STILL ARMED includes deferred-with-armed-trigger.
MINOR-2: §13.23 trigger #3 (pre-push surface widening) satisfied by Wave 7 sub-waves
7.1.b/7.1.c — explicit note in §0.1 + §6.

Prior-art: skipped — text corrections to research patch, no new capability shipped
artyhoo added a commit that referenced this pull request May 11, 2026
…yer pre-push enforcement)

Adds §1.7 discipline trailer check as section 9 of .husky/pre-push, closing
§13.23 4th-layer enforcement per Wave 7 sub-wave 7.6 research (research patch
2026-05-11-§13.23-4th-layer-research.md) and review verdict GO Path F1
(2026-05-11-§13.23-4th-layer-review-verdicts.md).

Atomically lands SSOT entries #23-#26 in prior-art-evaluations.md per
CLAUDE.md «add a new SSOT entry … in the same commit as the capability
artifact». Precedent: sub-wave 7.1.d landed #16 atomically with D-3 BUILD
shipment; Round 1 cold-start review (2026-05-11) §3 adjudication
confirmed 7.1.d as exemplary same-commit pattern.
  - #23 commitlint — ADOPT VOCABULARY (push-time vs commit-time gap;
    grep-pattern borrowed by s17_check_trailer())
  - #24 semantic-release — DEFER (release automation, orthogonal)
  - #25 commitizen — DEFER (Python dep + FORMAT gap)
  - #26 git interpret-trailers — ADOPT VOCABULARY (bash case-match
    parallel; two-parser inconsistency avoided)

Synthesis (from §11 Decision 1):
  - C4 scope predicate: file-glob (.claude/rules/, packages/core/principles/,
    .claude/skills/) ∧ content-marker (## § heading or top-level export const)
    ∧ NOT in D3 allow-list (docs(research-patches): / chore(snapshot-regen): /
    chore(prior-art-update):)
  - B1 bootstrap exemption: §1.7 Bootstrap: <≥20-char rationale> satisfies
    §1.7 at introduction-time commits (resolves chicken-and-egg)
  - T1 trailer format: separate stanza after Prior-art, ≥40-char payload, same
    placeholder-detection as pa_check_trailer()
  - D1 warn-only default: S17_WARN_ONLY=true for 30 days post-ship (TODO
    flip 2026-06-10); operator can flip locally for testing
  - UTF-8 locale guard: LC_ALL=en_US.UTF-8 wraps every grep matching §
    (fixup #3 from 7.6.b §4)

Adversarial test: 50-commit sweep against main HEAD pre-push.
  FP count: 0/50 (0%) — below threshold → 30-day calibration default retained.
  Predicate verified fires on branch commit 4ec69e5 (reviewer skill section add
  — confirmed true positive: touches .claude/skills/reviewer/SKILL.md + adds
  new ## § heading content). Predicate is sound.

Bootstrap: this commit introduces the §1.7 check; the rule cannot apply to its
own introduction without circular dependence.

Prior-art: prior-art-evaluations.md#23 (commitlint, ADOPT VOCABULARY — push-time-vs-commit-time framing borrowed; grep-pattern reused in s17_check_trailer()); prior-art-evaluations.md#26 (git interpret-trailers, ADOPT VOCABULARY — RFC 822 trailer convention, bash case-match parallel). Entries #24 (semantic-release DEFER) + #25 (commitizen DEFER) land in this commit per CLAUDE.md same-commit rule but are not positively cited — they document candidates considered + rejected.

§1.7 Bootstrap: introducing §1.7 pre-push enforcement section in .husky/pre-push — self-application would be circular at introduction time (the rule cannot apply to its own introducing commit; B1 exemption per 7.6.a research §4 + 7.6.b §2 Problem 2 verdict).
artyhoo added a commit that referenced this pull request May 16, 2026
Picks up EXEMPT_DIRS for research-patches/ from PR #57 (d189814)
to unblock CI overweight check on 786-line patch #3.

No file conflicts expected — PR #57 only touched .github/workflows/
while PR #55 only adds files under docs/meta-factory/research-patches/.
artyhoo added a commit that referenced this pull request May 22, 2026
… §0 snapshot) (#155)

Plan statuses had drifted (#stale-claim). Reconciled against merged PRs + per-wave patches:
- new §0 verified status snapshot (N1✅ N2🟡 N3✅ N4a✅ N4b🟡 N5🔲 N6a✅ N6b🔲 N7🟡 N8🟡)
- Status line: PLANNING ONLY → ACTIVE (committed #151)
- Track I.1 staging-trunk migration: awaits-execute → DONE (#144/#150)
- §5 decision #3 (migration execute/hold): struck → DONE
Companion=C (Track 0.2 / §5.1) already landed via #153; this builds on it.
@artyhoo
artyhoo deleted the chore/phase-3-aif-retrofit branch May 22, 2026 18:08
artyhoo added a commit that referenced this pull request May 28, 2026
… consolidation + F.6 self-contained rationale

Two of three MINOR findings from PR #261 Phase -1 cold-review applied (the third — SSOT #20 line-citation gap — was a false-positive; #20 already cites :L88 at patch:79 identical to peer rows).

MINOR #1 (#ai-traps-section-fragmented) — added new §4.5 "AI-traps applied (canonical + domain-specific)" consolidating the T-trap enumeration that was previously fragmented inline at §4 §1.7 line 333. Each T-number now names the specific action in this R-phase that honours it (T1 sampling floor=5 → §1.4 enumerated all 84 SSOT rows; T3 → file:line + verbatim excerpts at lines 140-143/87/93-95/101-105/109-113; etc.). T-N1/T-N2/T-N3/T-N4 listed with their honouring action too. The prior inline mention at §4 §1.7 line 333 now points forward to §4.5.

MINOR #3 (#f6-supplementary-rationale-relies-on-matrix-jump) — added "Supplementary, not subsumed by F.3 (self-contained statement)" paragraph at end of F.6 section. Now self-contained explanation: F.3-without-F.6 = Bug #3 fixed by side-effect but latent landmines remain; F.6-without-F.3 = Bugs #2/#4 unfixed → REJECT; combined F.3+F.6 = defence in depth on Bug #3. Reader no longer needs to jump to coverage matrix at lines 297-307 to understand why F.6 is additive not replacement.

MINOR #2 dropped — reviewer misread: #20 citation has explicit ":L88" line ref identical to peer rows (#9/#43/#68/#77). Verified at patch:79.

Prior-art: skipped — markdown polish on a research-patch; no new capability; per CLAUDE.md "Refactors, doc edits, test additions for existing capabilities ... NOT capability commits."
artyhoo added a commit that referenced this pull request Jun 1, 2026
Wire a SubagentStart hook (.claude/hooks/inject-subagent-digest.sh) that injects
the session-bootstrap digest into every dispatched junior at spawn — $0, zero
per-prompt boilerplate. Mechanizes the orchestrator's manual "anchor the junior"
discipline (SSOT #108).

STEP-1 dual-channel verification (WebFetch code.claude.com/docs/en/hooks + DeepWiki anthropics/claude-code)
confirmed the SubagentStart contract: NON-blocking, context via JSON
hookSpecificOutput.additionalContext — plain stdout is a silent no-op here (unlike
UserPromptSubmit), so the hook emits jq-wrapped JSON (mirrors inject-matching-rule.sh).
Single digest source: reuses inject-session-bootstrap.sh (no #two-prompts-drift).

Scope: only the verified candidate ships. ConfigChange settings-self-protection
(census #2) DROPPED — its matcher scopes on settings-tier (source), not actor, so it
cannot distinguish agent vs maintainer (T16); settings.json is already deny-listed for
agents, so a block would only hit the maintainer. SubagentStop/TaskCompleted REPORT-gate
(census #3) deferred as DECISION-NEEDED (block-vs-warn is a reviewer-discipline §2 fork).

Paired self-test packages/core/hooks/inject-subagent-digest.test.ts (4 tests, green):
asserts JSON contract (not plain stdout, T-108-A), digest content, verbatim
single-source equality, exit-0 non-blocking.

settings.json wiring is maintainer-landed (self-protected) — hook is INERT until then.

Prior-art: prior-art-evaluations.md#108 (CC orchestrator-gate hooks, ADOPT operator — SubagentStart digest-injection subset; ConfigChange dropped on T16, SubagentStop/TaskCompleted deferred).
artyhoo added a commit that referenced this pull request Jun 1, 2026
Wire a SubagentStart hook (.claude/hooks/inject-subagent-digest.sh) that injects
the session-bootstrap digest into every dispatched junior at spawn — $0, zero
per-prompt boilerplate. Mechanizes the orchestrator's manual "anchor the junior"
discipline (SSOT #108).

STEP-1 dual-channel verification (WebFetch code.claude.com/docs/en/hooks + DeepWiki anthropics/claude-code)
confirmed the SubagentStart contract: NON-blocking, context via JSON
hookSpecificOutput.additionalContext — plain stdout is a silent no-op here (unlike
UserPromptSubmit), so the hook emits jq-wrapped JSON (mirrors inject-matching-rule.sh).
Single digest source: reuses inject-session-bootstrap.sh (no #two-prompts-drift).

Scope: only the verified candidate ships. ConfigChange settings-self-protection
(census #2) DROPPED — its matcher scopes on settings-tier (source), not actor, so it
cannot distinguish agent vs maintainer (T16); settings.json is already deny-listed for
agents, so a block would only hit the maintainer. SubagentStop/TaskCompleted REPORT-gate
(census #3) deferred as DECISION-NEEDED (block-vs-warn is a reviewer-discipline §2 fork).

Paired self-test packages/core/hooks/inject-subagent-digest.test.ts (4 tests, green):
asserts JSON contract (not plain stdout, T-108-A), digest content, verbatim
single-source equality, exit-0 non-blocking.

settings.json wiring is maintainer-landed (self-protected) — hook is INERT until then.

Prior-art: prior-art-evaluations.md#108 (CC orchestrator-gate hooks, ADOPT operator — SubagentStart digest-injection subset; ConfigChange dropped on T16, SubagentStop/TaskCompleted deferred).
artyhoo added a commit that referenced this pull request Jun 1, 2026
…330)

Wire a SubagentStart hook (.claude/hooks/inject-subagent-digest.sh) that injects
the session-bootstrap digest into every dispatched junior at spawn — $0, zero
per-prompt boilerplate. Mechanizes the orchestrator's manual "anchor the junior"
discipline (SSOT #108).

STEP-1 dual-channel verification (WebFetch code.claude.com/docs/en/hooks + DeepWiki anthropics/claude-code)
confirmed the SubagentStart contract: NON-blocking, context via JSON
hookSpecificOutput.additionalContext — plain stdout is a silent no-op here (unlike
UserPromptSubmit), so the hook emits jq-wrapped JSON (mirrors inject-matching-rule.sh).
Single digest source: reuses inject-session-bootstrap.sh (no #two-prompts-drift).

Scope: only the verified candidate ships. ConfigChange settings-self-protection
(census #2) DROPPED — its matcher scopes on settings-tier (source), not actor, so it
cannot distinguish agent vs maintainer (T16); settings.json is already deny-listed for
agents, so a block would only hit the maintainer. SubagentStop/TaskCompleted REPORT-gate
(census #3) deferred as DECISION-NEEDED (block-vs-warn is a reviewer-discipline §2 fork).

Paired self-test packages/core/hooks/inject-subagent-digest.test.ts (4 tests, green):
asserts JSON contract (not plain stdout, T-108-A), digest content, verbatim
single-source equality, exit-0 non-blocking.

settings.json wiring is maintainer-landed (self-protected) — hook is INERT until then.

Prior-art: prior-art-evaluations.md#108 (CC orchestrator-gate hooks, ADOPT operator — SubagentStart digest-injection subset; ConfigChange dropped on T16, SubagentStop/TaskCompleted deferred).
artyhoo pushed a commit that referenced this pull request Aug 8, 2026
…r; the ping is two halves

§7d.3 as first written told the worker to route §7a #3's «one real minimal model call» through
`POST /runtime-profiles/validate` and left a falsifier for the case where that endpoint is only a
reachability check. The dispatcher fired that falsifier itself rather than shipping the trap:

- for `transport: "api"`, `validateClaudeConnection` returns ok after checking only that `apiKey`
  and `baseUrl` are non-empty — no network call (aif-handoff
  packages/runtime/src/adapters/claude/index.ts:468-479). Live 2026-08-09: `/validate` against the
  Qwen3.8-Max-Preview profile returned ok:true sub-second.
- `POST /runtime-profiles/models` is not a substitute — it returned a static Claude catalogue
  (Sonnet 4.6, Opus 4.6) for a Qwen profile, so it is not querying the provider.

So §7a #3 and §7c #3 cannot both be satisfied by one aif REST call. §7d.3 now binds both halves —
`/validate` for the route proof, plus one 1-token-scale completion against the `baseUrl` READ BACK
from that response (not a hardcoded `$GLM_BASE_URL`, which was run 2's W-3 defect). Provenance is
stated as dispatcher-authored and operator-overridable, matching §7b.

§7d.4 gains an exact, value-free verifier for §7b #3: `hasApiKey` is `Boolean(resolved.apiKey)` and
`resolved.apiKey` is `normalizeString(env[envVarName])` off the aif runtime's own process.env
(packages/runtime/src/resolution.ts:426, :217-219), so `hasApiKey:true` in the §7d.3(1) response IS
proof that §7b #1's outcome was achieved — without dereferencing the key, without argv exposure.

Prior-art: skipped — kickoff prose correction only, no new capability; markdown is exempt from the
capability-commit LOC triggers per CLAUDE.md.
artyhoo pushed a commit that referenced this pull request Aug 8, 2026
#1318 landed a §7d on the same file while this branch was in flight, so the block authored here is
renumbered §7d → §7e and rebuilt on top of #1318 rather than over it. #1318's content is kept intact.

Two corrections to §7d, both evidence-backed:

§7e.0 — §7d step 1 orders `git merge feature/beta-delivery-ux-92bf00`, which is run 2
(task 92bf0019, 2026-08-08T01:04Z). Run 3 (task e65989fa, commit 53fce45, 14:51Z) is newer and
already carries every §7c correction. Measured: getff-glm-onebutton.sh is 212 lines on 92bf00, still
holding `PATCH "$AIF_URL/project"` (:135) and the vendor-direct ping (:171), versus 361 lines at
53fce45 with the profile-routed path in place. Basing on 92bf00 re-does ~150 accepted lines and
re-opens two closed defects.

§7e.3 — §7d.1 states `POST /runtime-profiles/validate` «exercises the route the flow just built» and
is «exactly what §7a #3 / §7c #3 ask for». For `transport: "api"` it makes no network call at all —
it checks only that apiKey and baseUrl are non-empty (aif-handoff
packages/runtime/src/adapters/claude/index.ts:468-479); live, `/validate` against the
Qwen3.8-Max-Preview profile returned ok:true sub-second, and /runtime-profiles/models returned a
static Claude catalogue for that same Qwen profile. The ping is therefore split in two: /validate for
the route proof, plus one 1-token-scale completion against the baseUrl read back from that response.

Carried over unchanged in substance: §7e.1 (host-path retraction + the container base-URL trap —
localhost:3009 → 000, api:3009 → 200), §7e.2 (runtimeId/providerId required), §7e.4 (§7b #1
undelivered; hasApiKey as its exact value-free verifier), §7e.5 (companion install in a dead field),
§7e.6 (fail-closed mock, it.fails-as-delivery banned). §6 gains T-BDU-D and T-BDU-E.

Prior-art: skipped — kickoff prose revision only, no new capability; markdown is exempt from the
capability-commit LOC triggers per CLAUDE.md.
artyhoo added a commit that referenced this pull request Aug 8, 2026
… path, bind run-3 blockers (#1319)

* docs(beta-delivery-ux): S2 kickoff §8a — operator resolutions of the six #1284 parks (re-dispatch rev)

Records the operator's 2026-08-08 batch: Park-1 schema = flat Candidate A +
description field; Park-2 format = JSON (F-B' shell-sourced rejection recorded
with the WHY); Park-3 economy review = whole line on executor tier, aif cap 1
iteration, external cold fidelity mandatory; Park-4 CC detection =
CLAUDE_CODE_SESSION_ID env-presence capability check; Park-5 conditional park
did not fire (live runtime-profiles probe, no substring collision); Park-6 ship
the full functional set (create-worktree.sh + worktree-node-modules.sh +
link-coordination.sh) under the same $1j gate, fresh-consumer smoke AC added.
Unblocks the S2 re-dispatch (A4 presets + A5 status + A9 parts 2-3).

* docs(beta-delivery-ux): S4 kickoff §7b/§7c — close run-2 KICKOFF-AMBIGUOUS + host-verify contract

Run 2 (aif task 92bf0019) returned FIDELITY STOP with KICKOFF-AMBIGUOUS (PR #1300).
The kickoff's §7a never states how the aif runtime acquires the key VALUE: #1 stores
only the env-var NAME in the profile, #4(ii) writes the value to
~/.config/getff/glm.env, and #3 requires the validation ping to run through the
created profile. Verified against source: aif resolves the key from its own runtime
process.env by that name (aif-handoff packages/runtime/src/resolution.ts:217-219,
:247), and that env comes from the compose env-file (docker-compose.yml:15,59,94) —
so glm.env is a dead end as written and #3 is unreachable without dereferencing the
value, which #1 forbids.

§7b closes it by binding the OUTCOME (value reachable in the aif runtime process env
under the §7a #1 name, verified before the ping, honest objective-3 MISS on failure)
while leaving the wiring mechanism to the worker as a §7 technical fork. It is marked
as a dispatcher-authored completion, not an operator decision — the operator can
override it. §7c carries run 2's settled corrections: PUT /projects/:id with a full
body (aifHttp.ts:96) instead of the invented PATCH /project, no GET /projects/:id
(:90), both defaults halves, ping through the profile, 10-skills.sh untouched.

§4.1 adds the missing host-verify contract — the stage ships a shell helper, an
install-time gate and a tests/install-sh suite, i.e. exactly the container-vs-host
surface destination-environment-verification.md §1 exists for; the umbrella had no
contract on any of its six kickoffs (exit 2).

Prior-art: skipped — dispatch-input documentation only, no new capability; resolves an
ambiguity in an existing stage kickoff against in-repo source citations.

* docs(beta-delivery-ux): S4 kickoff §7d — retract the unreachable host path, bind run-3 blockers

§7d.0 retracts the §1 + §7a #1 instruction to re-read
`~/code/aif-handoff/packages/api/src/routes/runtimeProfiles.ts` at stage entry. That path is
host-only: the agent container mounts `$PROJECTS_DIR` (= `$PROJECTS_HOST_ROOT/projects`), so the
repo root holding `packages/api/` sits one level above the mount. The instruction was unexecutable
and run 3 guessed instead of parking — same class as state.md §2 decision 14.

Replacement is an oracle the container can actually reach: the live aif API. §7d.1 pins two probes
(required-field discovery + route-existence discovery) with the dispatcher's own 2026-08-09 outputs
recorded for reproduction, not for trust.

Run-3 blockers bound as corrections: §7d.2 `runtimeId`+`providerId` required in the create body;
§7d.3 the ping route is `POST /runtime-profiles/validate` (the guessed `/<id>/v1/messages` → 404);
§7d.4 §7b #1 still undelivered (the helper verifies reachability but never establishes it);
§7d.5 companion install is prose in a field `engine.sh:18` early-returns past; §7d.6 (MAJOR) the
suite mocks the non-existent endpoint and a body-blind 201, so §4.1 passed over §7d.2/§7d.3 —
the stub becomes fail-closed with a paired-negative that fails on the run-3 helper, and
`it.fails()`-as-delivery is banned.

Adds T-BDU-D: unreachable instructed source → probe, else PARK; never substitute a plausible shape.

Prior-art: skipped — kickoff prose revision only, no new capability; markdown is exempt from the
capability-commit LOC triggers per CLAUDE.md.

* docs(beta-delivery-ux): S4 kickoff §7d.1 — name the real base-URL var, and the container trap under it

Own cold-QA of #1319 caught two defects in §7d.1. (1) It invented `$AIF`; the helper actually
resolves `AIF_URL="${RUNTIME_BRIDGE_AIF_URL:-http://localhost:3009}"`
(scripts/getff-glm-onebutton.sh:94), so the probe block now uses that name.

(2) The more load-bearing half: that shipped default is unreachable from the agent container.
Measured 2026-08-09 from aif-handoff-agent-1 — `http://localhost:3009/runtime-profiles` → curl
exit 7 (000), `http://api:3009/runtime-profiles` → 200. `RUNTIME_BRIDGE_AIF_URL` is unset in the
container, so an in-container run of the run-3 helper could not have reached aif at all, which is
consistent with the suite mocking every call (§7d.6). §7d.1 now instructs the export for probing,
explicitly forbids changing the shipped consumer default, and §4 item 1 must quote the base URL
alongside any live end-to-end transcript.

Prior-art: skipped — kickoff prose correction only, no new capability; markdown is exempt from the
capability-commit LOC triggers per CLAUDE.md.

* docs(beta-delivery-ux): S4 kickoff §7d.3/§7d.4 — fire my own falsifier; the ping is two halves

§7d.3 as first written told the worker to route §7a #3's «one real minimal model call» through
`POST /runtime-profiles/validate` and left a falsifier for the case where that endpoint is only a
reachability check. The dispatcher fired that falsifier itself rather than shipping the trap:

- for `transport: "api"`, `validateClaudeConnection` returns ok after checking only that `apiKey`
  and `baseUrl` are non-empty — no network call (aif-handoff
  packages/runtime/src/adapters/claude/index.ts:468-479). Live 2026-08-09: `/validate` against the
  Qwen3.8-Max-Preview profile returned ok:true sub-second.
- `POST /runtime-profiles/models` is not a substitute — it returned a static Claude catalogue
  (Sonnet 4.6, Opus 4.6) for a Qwen profile, so it is not querying the provider.

So §7a #3 and §7c #3 cannot both be satisfied by one aif REST call. §7d.3 now binds both halves —
`/validate` for the route proof, plus one 1-token-scale completion against the `baseUrl` READ BACK
from that response (not a hardcoded `$GLM_BASE_URL`, which was run 2's W-3 defect). Provenance is
stated as dispatcher-authored and operator-overridable, matching §7b.

§7d.4 gains an exact, value-free verifier for §7b #3: `hasApiKey` is `Boolean(resolved.apiKey)` and
`resolved.apiKey` is `normalizeString(env[envVarName])` off the aif runtime's own process.env
(packages/runtime/src/resolution.ts:426, :217-219), so `hasApiKey:true` in the §7d.3(1) response IS
proof that §7b #1's outcome was achieved — without dereferencing the key, without argv exposure.

Prior-art: skipped — kickoff prose correction only, no new capability; markdown is exempt from the
capability-commit LOC triggers per CLAUDE.md.

---------

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 9, 2026
…with the three false greens fixed (#1323)

* feat(beta-delivery-ux-s4): GLM one-button helper + aif-handoff guided-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/).

* feat(beta-delivery-ux-s4): wire S4 automation into install.sh factory 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/).

* fix(beta-delivery-ux-s4): repair one-button helper per §7b/§7c/§7d — 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).

* fix(beta-delivery-ux-s4): point aif-handoff clone URL at lee-to upstream + 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.

* chore(beta-delivery-ux-s4): MINOR-4 manifest field + wire glm-onebutton.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.

* fix(beta-delivery-ux-s4): the one-button flow could not complete a single 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.

---------

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 9, 2026
…harvested, 995e9c dead-end) (#1324)

§7e was written before two things happened: run 3 got harvested to origin, and a
duplicate dispatch (995e9c) landed a dead-end branch in the container. §7f records
both so run 4 cannot repeat the base-selection mistake that produced the duplicate.

- §7f.0 — run 3 is now PR #1322 on origin (`feature/beta-delivery-ux-e65989`,
  `53fce45f51`); its body carries the round-3 watch-list W-1..W-6.
- §7f.1 — `feature/beta-delivery-ux-995e9c` is a dead end: do not base on it, do not
  delete it (T18). Its one salvageable item is the audit-self shard-A wiring, and only
  after the §7e.6 stub fix lands.
- §7f.2 — measured from `aif-handoff-agent-1`: `POST /runtime-profiles/:id/v1/messages`
  → 404, the exact path `scripts/getff-glm-onebutton.sh:53` targets. §7e.3's two-half
  split is the only reachable form of §7a #3, not a preference.
- §7f.3 — the §2.4 2-consecutive-REVISE cap counts unchanged scope; §7d/§7e are each a
  scope change, so run 4 is legitimate.

Prior-art: skipped — kickoff dispatch-facts addendum, markdown only, no new capability

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 9, 2026
…, name frozen against the live registry (#1336)

* docs(beta-delivery-ux): S2 kickoff §8a — operator resolutions of the six #1284 parks (re-dispatch rev)

Records the operator's 2026-08-08 batch: Park-1 schema = flat Candidate A +
description field; Park-2 format = JSON (F-B' shell-sourced rejection recorded
with the WHY); Park-3 economy review = whole line on executor tier, aif cap 1
iteration, external cold fidelity mandatory; Park-4 CC detection =
CLAUDE_CODE_SESSION_ID env-presence capability check; Park-5 conditional park
did not fire (live runtime-profiles probe, no substring collision); Park-6 ship
the full functional set (create-worktree.sh + worktree-node-modules.sh +
link-coordination.sh) under the same $1j gate, fresh-consumer smoke AC added.
Unblocks the S2 re-dispatch (A4 presets + A5 status + A9 parts 2-3).

* docs(beta-delivery-ux): S4 kickoff §7b/§7c — close run-2 KICKOFF-AMBIGUOUS + host-verify contract

Run 2 (aif task 92bf0019) returned FIDELITY STOP with KICKOFF-AMBIGUOUS (PR #1300).
The kickoff's §7a never states how the aif runtime acquires the key VALUE: #1 stores
only the env-var NAME in the profile, #4(ii) writes the value to
~/.config/getff/glm.env, and #3 requires the validation ping to run through the
created profile. Verified against source: aif resolves the key from its own runtime
process.env by that name (aif-handoff packages/runtime/src/resolution.ts:217-219,
:247), and that env comes from the compose env-file (docker-compose.yml:15,59,94) —
so glm.env is a dead end as written and #3 is unreachable without dereferencing the
value, which #1 forbids.

§7b closes it by binding the OUTCOME (value reachable in the aif runtime process env
under the §7a #1 name, verified before the ping, honest objective-3 MISS on failure)
while leaving the wiring mechanism to the worker as a §7 technical fork. It is marked
as a dispatcher-authored completion, not an operator decision — the operator can
override it. §7c carries run 2's settled corrections: PUT /projects/:id with a full
body (aifHttp.ts:96) instead of the invented PATCH /project, no GET /projects/:id
(:90), both defaults halves, ping through the profile, 10-skills.sh untouched.

§4.1 adds the missing host-verify contract — the stage ships a shell helper, an
install-time gate and a tests/install-sh suite, i.e. exactly the container-vs-host
surface destination-environment-verification.md §1 exists for; the umbrella had no
contract on any of its six kickoffs (exit 2).

Prior-art: skipped — dispatch-input documentation only, no new capability; resolves an
ambiguity in an existing stage kickoff against in-repo source citations.

* docs(beta-delivery-ux): S4 kickoff §7d — retract the unreachable host path, bind run-3 blockers

§7d.0 retracts the §1 + §7a #1 instruction to re-read
`~/code/aif-handoff/packages/api/src/routes/runtimeProfiles.ts` at stage entry. That path is
host-only: the agent container mounts `$PROJECTS_DIR` (= `$PROJECTS_HOST_ROOT/projects`), so the
repo root holding `packages/api/` sits one level above the mount. The instruction was unexecutable
and run 3 guessed instead of parking — same class as state.md §2 decision 14.

Replacement is an oracle the container can actually reach: the live aif API. §7d.1 pins two probes
(required-field discovery + route-existence discovery) with the dispatcher's own 2026-08-09 outputs
recorded for reproduction, not for trust.

Run-3 blockers bound as corrections: §7d.2 `runtimeId`+`providerId` required in the create body;
§7d.3 the ping route is `POST /runtime-profiles/validate` (the guessed `/<id>/v1/messages` → 404);
§7d.4 §7b #1 still undelivered (the helper verifies reachability but never establishes it);
§7d.5 companion install is prose in a field `engine.sh:18` early-returns past; §7d.6 (MAJOR) the
suite mocks the non-existent endpoint and a body-blind 201, so §4.1 passed over §7d.2/§7d.3 —
the stub becomes fail-closed with a paired-negative that fails on the run-3 helper, and
`it.fails()`-as-delivery is banned.

Adds T-BDU-D: unreachable instructed source → probe, else PARK; never substitute a plausible shape.

Prior-art: skipped — kickoff prose revision only, no new capability; markdown is exempt from the
capability-commit LOC triggers per CLAUDE.md.

* docs(beta-delivery-ux): S4 kickoff §7d.1 — name the real base-URL var, and the container trap under it

Own cold-QA of #1319 caught two defects in §7d.1. (1) It invented `$AIF`; the helper actually
resolves `AIF_URL="${RUNTIME_BRIDGE_AIF_URL:-http://localhost:3009}"`
(scripts/getff-glm-onebutton.sh:94), so the probe block now uses that name.

(2) The more load-bearing half: that shipped default is unreachable from the agent container.
Measured 2026-08-09 from aif-handoff-agent-1 — `http://localhost:3009/runtime-profiles` → curl
exit 7 (000), `http://api:3009/runtime-profiles` → 200. `RUNTIME_BRIDGE_AIF_URL` is unset in the
container, so an in-container run of the run-3 helper could not have reached aif at all, which is
consistent with the suite mocking every call (§7d.6). §7d.1 now instructs the export for probing,
explicitly forbids changing the shipped consumer default, and §4 item 1 must quote the base URL
alongside any live end-to-end transcript.

Prior-art: skipped — kickoff prose correction only, no new capability; markdown is exempt from the
capability-commit LOC triggers per CLAUDE.md.

* docs(beta-delivery-ux): S4 kickoff §7d.3/§7d.4 — fire my own falsifier; the ping is two halves

§7d.3 as first written told the worker to route §7a #3's «one real minimal model call» through
`POST /runtime-profiles/validate` and left a falsifier for the case where that endpoint is only a
reachability check. The dispatcher fired that falsifier itself rather than shipping the trap:

- for `transport: "api"`, `validateClaudeConnection` returns ok after checking only that `apiKey`
  and `baseUrl` are non-empty — no network call (aif-handoff
  packages/runtime/src/adapters/claude/index.ts:468-479). Live 2026-08-09: `/validate` against the
  Qwen3.8-Max-Preview profile returned ok:true sub-second.
- `POST /runtime-profiles/models` is not a substitute — it returned a static Claude catalogue
  (Sonnet 4.6, Opus 4.6) for a Qwen profile, so it is not querying the provider.

So §7a #3 and §7c #3 cannot both be satisfied by one aif REST call. §7d.3 now binds both halves —
`/validate` for the route proof, plus one 1-token-scale completion against the `baseUrl` READ BACK
from that response (not a hardcoded `$GLM_BASE_URL`, which was run 2's W-3 defect). Provenance is
stated as dispatcher-authored and operator-overridable, matching §7b.

§7d.4 gains an exact, value-free verifier for §7b #3: `hasApiKey` is `Boolean(resolved.apiKey)` and
`resolved.apiKey` is `normalizeString(env[envVarName])` off the aif runtime's own process.env
(packages/runtime/src/resolution.ts:426, :217-219), so `hasApiKey:true` in the §7d.3(1) response IS
proof that §7b #1's outcome was achieved — without dereferencing the key, without argv exposure.

Prior-art: skipped — kickoff prose correction only, no new capability; markdown is exempt from the
capability-commit LOC triggers per CLAUDE.md.

* docs(beta-delivery-ux): R1 stage kickoff — npm release mechanics (A6)

R1 is the last unstarted stage of the umbrella (S1-S5 all merged). This is its
dispatch input, scoped from the spec (§4 A6 `:278-284`, §11 F-C' `:467-468`) and
the binding input `launch-preannounce-track/s6-u10-handoff.md`.

Three things the kickoff decides, because a worker cannot:

1. Dispatchability (§0.1) — R1 IS aif-dispatchable. `private: true` STAYS on
   `packages/core/package.json` for the whole stage; npm refuses to publish a
   private package, so the publish guard is mechanical rather than a reminder
   (attention-is-not-a-mechanism §1). Verified `npm pack --dry-run` works on a
   private package, so the tarball loop runs with the guard armed.

2. Name architecture (§0.2) — probed the live registry, not the spec's prose:
   unscoped `getff` ALREADY EXISTS at 0.0.1, published 2026-06-23 by the
   maintainer as a reservation stub. So the registry-side freeze is done, 0.0.1
   is spent as a version, and `@getff` SCOPE ownership stays unproven (a 404 on
   `@getff/core` proves the package is free, not the scope) — that is an entry
   probe with a STOP attached.

3. Scope boundary (§0.3) — R1 does NOT execute the `@rules-as-tests/*` rename.
   Measured blast radius 33 tracked files / 55 occurrences; umbrella §3 puts the
   rename in U9 (post-announce), and the acceptance gate is name-independent
   because `npm i <tarball>` installs by path.

Also recorded: two gates of the binding input's §0 are SUPERSEDED by the
2026-07-23 amendment (U9 no longer the rename window; the private-drop ordering),
and the honest gap R1 does not close — U10's `npx getff init` gate needs a package
with `bin: getff`, which does not exist in this repo and which A6 does not ask R1
to build.

Host-verification contract declared (no opt-out): the new tarball cell plus the
existing pnpm start cell, which is the file-copy fallback the §4 rollback doctrine
requires to keep working. `scripts/host-verify.sh --list` parses both, exit 0.

Prior-art: skipped — dispatch-input authoring only; a markdown kickoff adds no
capability, no dependency, and no code module (CLAUDE.md doc-file carve-out).

---------

Co-authored-by: Test <test@example.com>
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>
artyhoo pushed a commit that referenced this pull request Aug 9, 2026
…un did not decide

night-mode delta item 1 says an unattended session resolves technical forks autonomously and
LOGS genuine owner forks instead of deciding them. Two blocked S4 from closing complete:

1. Spend authorisation for the §7a #3 model proof. The route is measured and proven; step D is
   ordinary work, but proving it on a cold install needs another real billed call, and the one
   the operator authorised is spent. Cost is ~$0.12 per run, not token-scale.
2. The terminal-token contract when a binding objective is undelivered — DONE vs FAILED vs a new
   PARTIAL token. Changing it touches what INSTALL-FOR-AI.md:184 tells consumer agents to report.

Also records what was NOT escalated and why: the round-4 KICKOFF-AMBIGUOUS dissolved under
measurement rather than needing an operator amendment, so it was resolved autonomously.

Prior-art: skipped — a decisions log for an existing umbrella; no capability, dependency, or module.
artyhoo pushed a commit that referenced this pull request Aug 9, 2026
…and correct how it pins

Operator authorised the spend, so the round-5 BLOCKER is closed by building the thing rather
than by re-parking it. Step D makes one real minimal completion through the profile the run just
created, which is what turns `GLM_PROVISION: DONE` from a claim about resolution into a claim
about the vendor accepting the key. Fork 2 dissolved rather than being decided: `DONE` became
true, so no new terminal token was needed.

The first implementation was WRONG, and the way it was wrong is the point. Step D was written as
a single `POST /chat` carrying `runtimeProfileId` — `chatRequestSchema` accepts that field, and
the call appeared to pass because the echoed `runtime.profileId` came back matching. It matched
by coincidence: the pinned profile was already the project's default. Fired against a freshly
created profile, the completion ran on the project default and echoed THAT back.
`chat.ts:1336` is why — `POST /chat` resolves the profile from the chat SESSION
(`existingSession?.runtimeProfileId ?? null`) and never reads the chat body's field when opening
a new conversation. Delivered form is therefore two calls: `POST /chat/sessions` pins the
profile, `POST /chat` sends the completion to that session. Without the cold-profile probe this
would have shipped as a proof that silently validated whatever the project already defaulted to.

Failure modes are covered rather than assumed: N7 (call unreachable), N8 (completion billed to a
DIFFERENT profile), N9 (zero-token "completion"), plus a §2 constraint 1 assertion that the
request body carries the profile id and never the key value. Removing the session pin from the
helper turns 3 assertions red, so the wiring is exercised, not decorated. Suite 53 → 60, green on
the host.

The park block is replaced by a record of why it was wrong: it generalised a handful of 404s into
"every aif-side completion route is closed", which is a negative-existence claim from a partial
probe. Option A's rejection stands (T16 — `curl --header @-` moves argv exposure but still needs
the helper to read the value); Option B was rejected on a false premise and is the delivery path.

HONEST GAP, stated in the code and in the decisions log: the full chain against a profile THIS
helper created could not be exercised on the verifying host. That aif has `ZAI_API_KEY` in its
process env and no `ANTHROPIC_AUTH_TOKEN` (measured — names only, never values), so a
helper-created profile returns CHAT_AUTH_ERROR there regardless of correctness. On a consumer
machine the §7b wiring supplies that var, which is the case the helper targets — but the first
consumer run is still the first end-to-end execution, and a `FAILED step-D` there means the
wiring did not land, not that the proof is broken.

INSTALL-FOR-AI.md now says DONE means the vendor accepted the key, that the call is billed, and
what a `FAILED step-D` line means.

Prior-art: skipped — completes an existing helper's declared objective using the aif REST API it
already speaks; no new capability, no dependency, no new module.
artyhoo pushed a commit that referenced this pull request Aug 9, 2026
…ertion that could not fail

Round-6 cold audit on `34ccc8cece` confirmed both round-5 carry-overs genuinely closed, and
found three MAJORs of its own. All three are closed here.

MAJOR-1 — the §2 constraint 1 assertion on the step-D surface was VACUOUS, and it is the third
time this branch has applied a principle to one branch and not its neighbour. It accumulated
request argv into the shell variable `_ND_SEEN`; the helper calls curl inside `$( )`, so every
stub call ran in its own subshell and the variable was empty at assertion time. The suite
reported the key never reaches the request while a deliberately injected key value sailed
straight past. The file-based fix for exactly this subshell trap was already documented and
applied twelve lines away, for the session pin. Now: capture goes to a file, a guard asserts the
capture is NON-EMPTY (so the check cannot pass on nothing), and a paired negative proves the
detector fires on a request that does carry the value. Verified by injecting a leak into step D's
body — the suite goes red, and green again when reverted. Same block, second defect: the create
arm answered 2xx with no body inspection, unlike every sibling stub — W-4's tell verbatim; it now
calls `_stub_create_body_ok`.

MAJOR-2 — `INSTALL-FOR-AI.md` promised the model call costs "a few cents at most". This branch's
own measurement is `costUsd:0.117219`, and its decisions log says "not token-scale". A
consumer-facing ceiling falsified by the author's own number in the same commit range is exactly
the false green this stage keeps producing. Corrected to the measured figure, and the sentence
now also states the two things it silently omitted: the helper runs `docker compose up -d`
against the consumer's aif (restarting their services), and every run leaves a chat session
titled "getff GLM provisioning proof" in their project.

MAJOR-3 — the research patch still carried "§7e.3 — model proof: PARKED", "the fork is genuine:
two binding constraints in conflict", and a run-5 §1.7 note calling the DONE gap "NOT fixed" —
all false at HEAD, and the newest dated section was among them, so a reader following the file's
own ordering would land on withdrawn claims. The folder is append-only, so a superseding addendum
now closes each of the three by name at the end of the file.

MINOR — narrowed, but not the way the audit proposed. The audit read "session pinning measured
live" as broader than the evidence, having seen only completions that ran on the project default.
The discriminating observation exists and is now named in the code: a session pinned to a
NON-default, freshly created profile returned CHAT_AUTH_ERROR. Had pinning fallen back to the
default, that call would have SUCCEEDED, since the default is a working profile — so the error is
positive evidence the pinned profile was used.

NOT closed — the audit's KICKOFF-AMBIGUOUS stands and is an owner question: §7a #3 binds a
"1-token-scale" call, but the only reachable route injects project context, so every consumer
provision bills ~$0.12. Recurring per-consumer spend was never decided by the kickoff.

Suite 60 → 62, green on the host.

Prior-art: skipped — test-material repair plus doc corrections to an existing helper; no new
capability, no dependency, no new module.
artyhoo pushed a commit that referenced this pull request Aug 9, 2026
… on step D

The round-6 audit flagged KICKOFF-AMBIGUOUS: §7a #3 binds a '1-token-scale' model call, but the
only reachable completion route injects project context — measured 39058 input tokens and
costUsd:0.117219 for a one-word prompt. Step D runs on every provision, so that is a recurring
charge on each consumer's plan rather than a one-off verification cost.

Logged, not decided: nothing in the code settles it, and whether ~$0.12 per provision is
acceptable is a product call about other people's money. INSTALL-FOR-AI.md states the measured
figure to the consumer either way, so nobody is billed by surprise while it is open.

Prior-art: skipped — decisions log entry for an existing umbrella; no capability, no dependency.
artyhoo added a commit that referenced this pull request Aug 9, 2026
…ree false greens closed (#1341)

* feat(beta-delivery-ux): S4 run-4 — §7e.4 wiring + §7e.3 refreshed park + cold-QA revisions

Run 4 closes the run-3 #warning-nobody-reads shape on the GLM one-button helper. The
helper now MAKES the key reachable in the aif runtime's process env (best-effort W1) and
the §7e.4 verifier (`.profile.hasApiKey` from POST /runtime-profiles/validate) is a binding
gate, not a printed warning.

Three substantive deliverables (T1–T5 of the dispatched plan):

1. §7e.4 wiring (W1 + W2). W1: when $AIF_HANDOFF_CHECKOUT/docker-compose.yml exists and
   no unmarked override collides, the helper writes a marker-bearing docker-compose.override.yml
   that adds $GLM_ENV_FILE to each detected service's env_file list. Idempotent (marker grep)
   + collision-back-off (unmarked override → rc=2 → W2 fallback). W2: instruction + the §7e.4
   binding gate (hasApiKey:false → FAILED step-C key-unreachable, objective-3 MISS). Live-fired
   evidence in the PR body.

2. §7e.3 model-proof — PARK refreshed. Re-probed every plausible aif completion route (404
   across /runtime-profiles/<id>/{v1/messages,chat/completions,...}, root-level /chat /prompt
   /infer, /openapi.json empty). Tested third options for the helper-direct route: `curl
   --header @-` and `curl --config -` both avoid argv exposure AND temp file, but require the
   helper to expand the env var — i.e. read the value — which §2 constraint 1 forbids
   ("automation reads the ENV VAR NAME (never the value) when calling the model"). Genuine
   fork between two binding constraints; parked per §7 with T16 verdict on the curl pattern
   (solves argv but presupposes the script reads the value).

3. .profile.hasApiKey parsing fix. Run 3 assumed top-level; live aif (probed 2026-08-09) nests
   under .profile: {"ok":true,"profile":{"hasApiKey":...}}. Helper now tries .profile.hasApiKey
   first (live-accurate) then top-level .hasApiKey (older-aif fallback) then .ok-only (oldest
   aif). Three paired-negatives cover each branch: N1 happy-path (live nested), N4
   hasApiKey:false (FAILED step-C key-unreachable), N5 defensive-fallthrough (older aif
   without the field anywhere).

Cold-QA revisions (T19 MAJOR + 2 MINOR, addressed before commit):
- M1: stubs now use the LIVE nested .profile.hasApiKey shape, not top-level. Previously the
  primary parse path (the one that fires against live aif) was untested — only the elif
  fallback was. The T-BDU-E shape the §7e.6 rule exists to prevent. Fixed.
- m1: N2b description corrected (it tests arm-ordering, not defensive parse); N5 added for
  the actual defensive-fallthrough branch.
- m2: W1-write test comment corrected — `docker() { return 127; }` is a function stub,
  `command -v docker` finds it (returns 0), so the helper takes the "docker compose up -d
  failed" branch, not the "docker not in PATH" branch. Comment now describes the actual path.

§4.1 host-verify contract CANNOT be exercised in-container (destination-environment-verification
rule's whole point is container≠host). The contract command `bash tests/install-sh/glm-onebutton.test.sh`
runs green (47/0) in-container; the host re-run is pending at PR merge.

§1.7 Forward-check: complies with §7 park-don't-guess (model proof parked, not guessed);
§7e.4 (verifier wired, not warning); §7e.6 (fail-closed + paired-negatives N1-N5); §2
constraint 1 (helper never expands the value); no-paid-llm-in-ci.md (no LLM in CI);
doc-authority-hierarchy.md §2-§3 (research-patch is folder-level authority, no per-file
header needed); language-discipline.md (all English machinery).

§1.7 Backward-check: Class of this change = "shell helper that auto-writes a
docker-compose.override.yml with an env_file path, gated by a binding validate-response
field". Surfaces where class-X occurs, per cold-agent sweep (backward-sweep-auditor, PR-blind):
- scripts/getff-glm-onebutton.sh — IN SCOPE (the changed file)
- setup.d/aif-handoff-guided-install.sh + setup.d/bridge-guided.sh + packages/runtime-bridge/scripts/* —
  SWEPT-CLEAN (no parallel docker-compose.override.yml writer exists; grep `docker-compose|env_file`
  across all deployment-writing helpers returns zero writers)
- POST /runtime-profiles/validate consumers — SWEPT-CLEAN (single consumer: the changed file)
- tests/install-sh/* fail-closed stub pattern — SWEPT-CLEAN (mirror of bridge-guided.test.sh;
  no other /validate consumer)
- INSTALL-FOR-AI.md + docs/runtime-bridge-setup.md consumer wiring instructions —
  SWEPT-CLEAN (INSTALL-FOR-AI.md:180 updated for W1; docs/runtime-bridge-setup.md:190 uses the
  same filename for a different purpose (operator-axis volume bind-mounts, not env_file
  injection); W1 collision-back-off handles the filename-sharing correctly).
Overall backward-sweep verdict: GO.

T-BDU-C/D/E tells countered: every aif API claim in the diff is established by a command
output in this PR body or the research-patch's run-4 update. The suite's green run is
disambiguated by the live end-to-end probe (T4) — both the W1 wire path (override written
with marker covering agent+api services) and the §7e.4 verifier firing on the throwaway
key (validate returned ok:false "Missing API key" because the env file was visible to the
helper but not to aif's process env — exactly the gap the verifier exists to detect).

Prior-art: skipped — refactor only, no new capability (no new dependency, no new file ≥80
LOC under packages/, no new packages/core/<new-dir>/ entry; the helper script + test suite +
research-patch + INSTALL-FOR-AI.md edits are all additions to existing surfaces).

Refs: .ai-factory/plans/feature-beta-delivery-ux-5cfe83.md (run-4 dispatched plan)

* fix(beta-delivery-ux): S4 run-5 — close both round-4 MAJORs, and fix what caused one of them

Round-4 cold fidelity audit returned REVISE on `91f99d06be` with two MAJORs and no BLOCKER.
Both are closed here, and the second turned out to have a fixable root cause rather than an
unavoidable degradation.

MAJOR-1 (W-4 REINTRODUCED) — the N5 block shipped a fail-OPEN `curl()` stub: its create arm
answered 200 with no body inspection and its catch-all returned rc=0 for any path, so it would
have green-lit run 3's invented `/v1/messages` ping and a create body missing the required ids.
The base stub and the round's own N4 stub both fail closed; N5 was a copy that drifted.
Fixed in place, and — because a copy that drifts is the actual defect class — a structural gate
now asserts the invariant over this file's own source: every case-based `curl()` stub must fail
closed on an unallowlisted path. A prose reminder rots under exactly the fatigue that causes the
drift (attention-is-not-a-mechanism.md §1). Its paired negative proves non-vacuity, and the gate
earned its keep immediately by flagging its own first fixture, which is why the fixture is now
assembled programmatically instead of written as a heredoc.

MAJOR-2 — on a failed per-mode-default PUT the helper warned an objective-3 MISS and continued,
then printed `GLM_PROVISION: DONE`. `INSTALL-FOR-AI.md:184` tells the consumer's agent to report
that line verbatim, so a missed binding objective surfaced as success. §2 constraint 4 is explicit
that a degrade to manual steps is a MISS, not a neutral fallback: the branch now emits
`GLM_PROVISION: FAILED step-B per-mode-defaults` and returns non-zero. N6 is the paired negative;
reverting the fix turns it red on 3 assertions.

ROOT CAUSE of that MISS, measured rather than reasoned about. The research patch attributed the
`rc=22` to a schema-shape incompatibility. One layer down:

    PUT /projects/<id>, GET body verbatim       -> 400  expected number, received null
                                                        path ["plannerMaxBudgetUsd"]
    same body, null *MaxBudgetUsd keys omitted  -> 200

`createProjectSchema` declares the four budget fields `z.number().positive().optional()` —
optional but NOT nullable — while `GET /projects` returns them as `null`. The helper mutated the
GET body and fed those nulls back. So objective 3 was missing on every consumer for a reason
unrelated to the fields it was setting. One jq filter drops null-valued `*MaxBudgetUsd` keys;
the 200 above was read back with `autoQueueMode`, both profile defaults and every other value
unchanged. Objective 3 is met, not degraded.

Suite: 47 → 53 assertions, green on the host (§4.1). The §7e.3 model proof stays parked: the
route is now proven reachable (kickoff §7f.2), but demonstrating it on a cold install costs a
real billed call and that spend is the operator's to authorise.

Prior-art: skipped — bug fix to an existing helper plus test material for it; no new capability,
no dependency, no new module.

* fix(beta-delivery-ux): S4 run-5 — round-5 audit MINORs, and the withdrawn park stated as undelivered

Round-5 cold fidelity audit returned STOP on `86b01848ed`. This commit closes the two MINORs
and stops the park from resting on a rationale the kickoff has withdrawn. The BLOCKER and the
MAJOR are deliberately NOT closed here — see below.

MINOR-1 — the §7e.6 meta-scanner caught only `return 0`. A case arm with no explicit `return`
inherits the exit status of its last command, so `*) printf 'x' ;;` is exactly as fail-open
while reading as if it were safe. Both shapes are now caught. The scanner is also scoped to
`curl()` blocks, which is its declared population: without that, the `_wrong_order` hazard
reproducer — not a stub — would be graded against a stub invariant and flagged falsely.
Verified: the widened rule flags the new shape (`FLAGGED line 3` on a fixture) and the real
file stays clean at 53/53.

MINOR-2 — the research patch's §1.7 note was labelled `(run-4)` and the run-5 addendum carried
none. Added, including the part that does not flatter this branch: the backward-check enumerates
the false-green shape across `do_provision` and records that the terminal `DONE` printf is a
GAP-FOUND that is NOT fixed.

Park text — the block claimed «Root-level completion routes also 404: /chat, …» and concluded
«Option B is a dead-end at the aif API surface as it stands today». Both are false, as §7f.2
records: `POST /chat/sessions` → 400 (exists), `POST /chat` returns a real billed completion,
and `chat.ts:923-937` project-scope-validates `runtimeProfileId`. The word «PARKED» is withdrawn
with the rationale: a park is an open question, and settled-but-unbuilt work called a park is the
shape §7d.2 already ruled against. It now reads as undelivered work, named as such.

NOT closed, and why:

- **BLOCKER (§7a #3 model proof absent).** Step D is buildable now that the route is measured.
  Verifying it on a cold install costs a real billed call (~$0.12/run), and that spend was
  authorised once, for the probe already spent. Logged as an owner fork.
- **MAJOR (`GLM_PROVISION: DONE` over an undelivered objective).** §7e.3 makes either half of
  the proof failing an objective-3 MISS, so the honest token is not `DONE` — but changing it
  changes the consumer-facing contract `INSTALL-FOR-AI.md:184` tells the consumer's agent to
  report verbatim, and the alternatives (always-FAILED, or a third `PARTIAL` token) are an owner
  call, not an implementation detail. Recorded in code and in the patch instead of being papered
  over; the inconsistency with the step-B fix twelve lines above is stated, not hidden.

The night-mode session-local fidelity cap of 2 rounds is reached (round 4 REVISE, round 5 STOP),
so this branch is pushed and NOT merged.

Prior-art: skipped — test-material widening plus comment corrections to an existing helper; no
new capability, no dependency, no new module.

* docs(beta-delivery-ux): S4 — log the two owner forks the unattended run did not decide

night-mode delta item 1 says an unattended session resolves technical forks autonomously and
LOGS genuine owner forks instead of deciding them. Two blocked S4 from closing complete:

1. Spend authorisation for the §7a #3 model proof. The route is measured and proven; step D is
   ordinary work, but proving it on a cold install needs another real billed call, and the one
   the operator authorised is spent. Cost is ~$0.12 per run, not token-scale.
2. The terminal-token contract when a binding objective is undelivered — DONE vs FAILED vs a new
   PARTIAL token. Changing it touches what INSTALL-FOR-AI.md:184 tells consumer agents to report.

Also records what was NOT escalated and why: the round-4 KICKOFF-AMBIGUOUS dissolved under
measurement rather than needing an operator amendment, so it was resolved autonomously.

Prior-art: skipped — a decisions log for an existing umbrella; no capability, dependency, or module.

* feat(beta-delivery-ux): S4 — deliver §7a #3's model proof as step D, and correct how it pins

Operator authorised the spend, so the round-5 BLOCKER is closed by building the thing rather
than by re-parking it. Step D makes one real minimal completion through the profile the run just
created, which is what turns `GLM_PROVISION: DONE` from a claim about resolution into a claim
about the vendor accepting the key. Fork 2 dissolved rather than being decided: `DONE` became
true, so no new terminal token was needed.

The first implementation was WRONG, and the way it was wrong is the point. Step D was written as
a single `POST /chat` carrying `runtimeProfileId` — `chatRequestSchema` accepts that field, and
the call appeared to pass because the echoed `runtime.profileId` came back matching. It matched
by coincidence: the pinned profile was already the project's default. Fired against a freshly
created profile, the completion ran on the project default and echoed THAT back.
`chat.ts:1336` is why — `POST /chat` resolves the profile from the chat SESSION
(`existingSession?.runtimeProfileId ?? null`) and never reads the chat body's field when opening
a new conversation. Delivered form is therefore two calls: `POST /chat/sessions` pins the
profile, `POST /chat` sends the completion to that session. Without the cold-profile probe this
would have shipped as a proof that silently validated whatever the project already defaulted to.

Failure modes are covered rather than assumed: N7 (call unreachable), N8 (completion billed to a
DIFFERENT profile), N9 (zero-token "completion"), plus a §2 constraint 1 assertion that the
request body carries the profile id and never the key value. Removing the session pin from the
helper turns 3 assertions red, so the wiring is exercised, not decorated. Suite 53 → 60, green on
the host.

The park block is replaced by a record of why it was wrong: it generalised a handful of 404s into
"every aif-side completion route is closed", which is a negative-existence claim from a partial
probe. Option A's rejection stands (T16 — `curl --header @-` moves argv exposure but still needs
the helper to read the value); Option B was rejected on a false premise and is the delivery path.

HONEST GAP, stated in the code and in the decisions log: the full chain against a profile THIS
helper created could not be exercised on the verifying host. That aif has `ZAI_API_KEY` in its
process env and no `ANTHROPIC_AUTH_TOKEN` (measured — names only, never values), so a
helper-created profile returns CHAT_AUTH_ERROR there regardless of correctness. On a consumer
machine the §7b wiring supplies that var, which is the case the helper targets — but the first
consumer run is still the first end-to-end execution, and a `FAILED step-D` there means the
wiring did not land, not that the proof is broken.

INSTALL-FOR-AI.md now says DONE means the vendor accepted the key, that the call is billed, and
what a `FAILED step-D` line means.

Prior-art: skipped — completes an existing helper's declared objective using the aif REST API it
already speaks; no new capability, no dependency, no new module.

* fix(beta-delivery-ux): S4 — round-6 REVISE, incl. a key-invariant assertion that could not fail

Round-6 cold audit on `34ccc8cece` confirmed both round-5 carry-overs genuinely closed, and
found three MAJORs of its own. All three are closed here.

MAJOR-1 — the §2 constraint 1 assertion on the step-D surface was VACUOUS, and it is the third
time this branch has applied a principle to one branch and not its neighbour. It accumulated
request argv into the shell variable `_ND_SEEN`; the helper calls curl inside `$( )`, so every
stub call ran in its own subshell and the variable was empty at assertion time. The suite
reported the key never reaches the request while a deliberately injected key value sailed
straight past. The file-based fix for exactly this subshell trap was already documented and
applied twelve lines away, for the session pin. Now: capture goes to a file, a guard asserts the
capture is NON-EMPTY (so the check cannot pass on nothing), and a paired negative proves the
detector fires on a request that does carry the value. Verified by injecting a leak into step D's
body — the suite goes red, and green again when reverted. Same block, second defect: the create
arm answered 2xx with no body inspection, unlike every sibling stub — W-4's tell verbatim; it now
calls `_stub_create_body_ok`.

MAJOR-2 — `INSTALL-FOR-AI.md` promised the model call costs "a few cents at most". This branch's
own measurement is `costUsd:0.117219`, and its decisions log says "not token-scale". A
consumer-facing ceiling falsified by the author's own number in the same commit range is exactly
the false green this stage keeps producing. Corrected to the measured figure, and the sentence
now also states the two things it silently omitted: the helper runs `docker compose up -d`
against the consumer's aif (restarting their services), and every run leaves a chat session
titled "getff GLM provisioning proof" in their project.

MAJOR-3 — the research patch still carried "§7e.3 — model proof: PARKED", "the fork is genuine:
two binding constraints in conflict", and a run-5 §1.7 note calling the DONE gap "NOT fixed" —
all false at HEAD, and the newest dated section was among them, so a reader following the file's
own ordering would land on withdrawn claims. The folder is append-only, so a superseding addendum
now closes each of the three by name at the end of the file.

MINOR — narrowed, but not the way the audit proposed. The audit read "session pinning measured
live" as broader than the evidence, having seen only completions that ran on the project default.
The discriminating observation exists and is now named in the code: a session pinned to a
NON-default, freshly created profile returned CHAT_AUTH_ERROR. Had pinning fallen back to the
default, that call would have SUCCEEDED, since the default is a working profile — so the error is
positive evidence the pinned profile was used.

NOT closed — the audit's KICKOFF-AMBIGUOUS stands and is an owner question: §7a #3 binds a
"1-token-scale" call, but the only reachable route injects project context, so every consumer
provision bills ~$0.12. Recurring per-consumer spend was never decided by the kickoff.

Suite 60 → 62, green on the host.

Prior-art: skipped — test-material repair plus doc corrections to an existing helper; no new
capability, no dependency, no new module.

* docs(beta-delivery-ux): S4 — log fork 3, recurring per-consumer spend on step D

The round-6 audit flagged KICKOFF-AMBIGUOUS: §7a #3 binds a '1-token-scale' model call, but the
only reachable completion route injects project context — measured 39058 input tokens and
costUsd:0.117219 for a one-word prompt. Step D runs on every provision, so that is a recurring
charge on each consumer's plan rather than a one-off verification cost.

Logged, not decided: nothing in the code settles it, and whether ~$0.12 per provision is
acceptable is a product call about other people's money. INSTALL-FOR-AI.md states the measured
figure to the consumer either way, so nobody is billed by surprise while it is open.

Prior-art: skipped — decisions log entry for an existing umbrella; no capability, no dependency.

---------

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 9, 2026
…age gate that fell open (#1350)

## Summary

The round-7 cold fidelity audit returned `FIDELITY: GO` against `e3e705eb26` and graded five findings MINOR, deliberately leaving them unfixed so the merged artefact would not differ from the audited one. This PR closes all five as follow-up work on `staging`. Four are in the S4 GLM one-button helper and its suite — one real fail-open branch in the helper, and three assertions that were weaker than the properties they protect. The fifth is a stale provenance label in the S4 research patch.

## Changes

- **`scripts/getff-glm-onebutton.sh` — step D's zero-usage gate fell OPEN on a non-numeric `totalTokens`.** `[ "$chat_tokens" -le 0 ] 2>/dev/null` errors on a non-numeric value, so the `if` is false and control reached `GLM_PROVISION: DONE`. `null` and an absent `usage` were always safe (jq's `// 0` → `0`) and aif types `RuntimeUsage.totalTokens` as `number`, so the window was narrow — but this was a fail-open branch inside the one step whose entire job is to fail closed. Replaced with an explicit numeric `case` test emitting a distinct terminal token, `FAILED step-D model-proof-unusable-usage`. Paired negatives **N10** (string `"abc"`) and **N10b** (non-integer `12.5` — valid JSON, and `[ -le ]` errors on it identically), plus paired positive **N10c** so the widened gate is not reject-all.
- **`tests/install-sh/glm-onebutton.test.sh` — the §2-constraint-1 guard-the-guard was weaker than the property it protects.** It asserted the capture file was non-empty, not that step D's completion request was in it. Now matches a whitespace-delimited token ending in `/chat` — `/chat/sessions` must not satisfy it alone.
- **Same file — the shipped paired-negative for the leak detector was a tautology.** It wrote a leak-shaped string to a temp file and grepped it back, proving `grep` works rather than that the capture wiring carries a real leak. It now builds a scratch copy of the helper with the key value injected into step D's chat body (`--arg LEAKV "${!GLM_ENV_VAR}"`), runs it against the same stub, and asserts the value lands in the capture — with a companion assertion that the injection actually applied, so a drifted `sed` anchor cannot make it vacuous.
- **Same file — the §7e.6 meta-scanner's declared population excluded one fail-open shape.** It scoped itself to `case`-based stubs, so a caseless stub — which answers 2xx-equivalent for *every* path — was invisible, and the file carried one (the preflight stub, harmless only by accident of call order). Declaring a population and scanning a subset of it is the same can't-fail shape this gate exists to reject, so the population was **widened** rather than narrowed in prose. Comment lines are now skipped, and one-line `case`-based stubs are graded on their catch-all. Preflight stub is now `return 1`.
- **`docs/.../2026-08-08-s4-glm-onebutton-entry-verification.md`** — the `SUPERSEDING ADDENDUM` was headed «(run-5, commit `34ccc8cece`)» but was added by `3bf1d18ce9`, and its body describes round-6 corrections postdating the commit named in its own heading. It now names its own commit, in the section whose entire subject is provenance honesty. The round-7 follow-ups are recorded in the same file's append-only tail.

## Prior-art consult

- [x] Capability commits in this PR carry a `Prior-art:` trailer (or `skipped — <≥20 chars rationale>` for hook-flagged commits that aren't real capability additions). Not a capability commit: no new dependency, no new file, edits only to an existing helper, its own suite, and one research patch.
- [x] If a new capability area surfaced during this PR: n/a — none surfaced.
- [x] If existing entries matched: n/a — no SSOT entry is cited or touched.
- [x] context7 queries (≥3 phrasings) for new capability areas were run and the results cited: n/a — no new capability area.

## Test plan

- [x] `bash tests/install-sh/glm-onebutton.test.sh` → **73/0** on the host (62/0 at the audited SHA)
- [x] `bash tests/install-sh/bridge-guided.test.sh` → **11/0** (sibling suite, unchanged)
- [x] `npm run --prefix packages/core test:principles` → **353 passed, 1 skipped, 37 files**
- [x] `bash -n` clean on both edited shell files; `shellcheck -S warning` on the helper shows only the two pre-existing `SC1090` hits (identical count on `staging`)
- [x] `markdownlint-cli2` clean on the edited research patch
- [x] Manual smoke — each fix watched FAIL before the fix, and each falsified after:
  - N10 pre-fix reported «non-numeric totalTokens fell through to DONE»; green post-fix.
  - Guard-the-guard: a scratch helper with an injected `return 1` after step A produced `✓ capture is non-empty (9 requests recorded)` under the old guard with **zero** `/chat` requests made; the new guard goes red on the same scratch copy.
  - Leak paired-negative: neutering the injection turns exactly those two assertions red and nothing else (66/2).
  - Meta-scanner: reintroducing `curl() { return 0; }` in the real file turns the meta assertion red, naming the line.

## Provenance

n/a — non-stage follow-up PR closing MINORs carried by the merged S4 stage PR #1341.

## Review findings

n/a — non-stage PR. Origin of the five items is #1341's round-7 audit (`FIDELITY: GO` against `e3e705eb26`), which graded them MINOR and left them for follow-up.

## Fidelity verdict

FIDELITY: skipped — non-stage follow-up bugfix PR; no kickoff or stage contract applies, and the five items originate from the already-merged #1341 round-7 verdict.

## Parked questions

The `§7a #3` per-consumer spend fork (≈$0.12 per `provision` run) is **not** re-opened here — it is recorded in `.claude/orchestrator-prompts/beta-delivery-ux/kickoff-s4.decisions.md` and is the operator's call.

One item is deliberately **not** closed: the §7e.6 gate remains scoped to its own file's source (`$0`), so the `bridge-guided.test.sh` sweep below is a one-off measurement, not a standing gate. Promoting the scanner to a shared checker over `tests/install-sh/**` is a capability commit needing its own prior-art consult, out of scope for a follow-up bugfix.

## §1.7 Self-discipline check (REQUIRED if PR touches discipline-bearing files)

### §1.7 Skipped: mechanical maintenance — this PR fixes a fail-open branch and three weak assertions in an existing helper plus its own test suite, and corrects one stale provenance label; it introduces and extends no discipline rule, and touches no file under .claude/rules/, packages/core/principles/, EXECUTION-PLAN.md, prior-art-evaluations.md, CLAUDE.md or any shipped template.

<!-- Backward-check recorded in the research patch rather than here, since no discipline rule is
introduced: class = "a fail-open curl() stub in an install-sh suite"; population enumerated by
`grep -lE 'curl\(\)[[:space:]]*\{' tests/install-sh/*.test.sh` → exactly 2 of ~100 suites;
glm-onebutton.test.sh GAP-FOUND (fixed), bridge-guided.test.sh SWEPT-CLEAN by running the
finished scanner over its seven stubs. The one-line case grading landed BEFORE that sweep on
purpose — without it the scanner would have reported the sibling clean while grading none of
its stubs. -->
artyhoo added a commit that referenced this pull request Aug 9, 2026
…h open forks (#1351)

Both questions the unattended run logged rather than decided are now answered, and the answers
are written where a later reader can judge them rather than inherit them.

§4 item 1 (live end-to-end on a clean machine) — ACCEPTED AS MET on block-level evidence. The
record states exactly what was measured (each step live against a running aif; step D's four
failure modes each with a paired negative observed RED before GREEN; 62/62 on the host) and
exactly what was not: those steps executing in sequence against a helper-created profile on a
machine where the §7b wiring supplied the key. The accepted risk is named — the first consumer
run is the first full-chain execution — together with its falsifier and the distinguishing
signal (`CHAT_AUTH_ERROR` from `POST /chat`, which the helper already hints at).

§7a #3 recurring per-consumer spend — ACCEPTED AS-IS. Step D bills ~$0.117 per provision because
aif prepends project context on the only reachable completion route. The kickoff's
«1-token-scale» wording is left standing and marked inaccurate-as-shipped rather than quietly
amended, since the measured figure is what governs and `INSTALL-FOR-AI.md:184` states it to the
consumer before the step runs. The two rejected alternatives are recorded so the choice is
legible.

Also corrects a framing error this session made twice in chat: `done.md` was described as blocked
by these forks. It is not. Per operational-conventions.md §1 it marks the UMBRELLA complete and is
written at the LAST stage's merge only — and `beta-delivery-ux` still has R1 in flight (aif task
`7a12c5bc`) plus S2's follow-up unharvested (`a8337963`), among 8 done-but-unharvested tasks.
Writing it now would make priority-score.sh Layer C3 score the umbrella DONE and stop dispatching
that work. S4 as a STAGE is closed; the umbrella is not.

Prior-art: skipped — decisions record for an existing umbrella; no capability, no dependency,
no new module.

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 18, 2026
…ws, routing bindings (#1462)

* feat(arch): frontier pacing delta in §1 — ADAPT of grill-me/grilling (SSOT #253)

Two deltas over the wrapped brainstorming loop: batch prerequisite-settled
questions per round (dependent ones stay serial), and enumerate-before-done —
the dialogue closes only when every design decision is answered or an explicit
operator fork. Superpowers 6.2.0 verified to lack the mechanism (grep over the
whole installed plugin: 0 hits; brainstorming pins one-question-per-message).

Prior-art: prior-art-evaluations.md#253 (grill-me/grilling, ADAPT — only the tree/frontier mechanic transfers; recommendation-per-question and probe-don't-ask already exist as H1 + T8/T20).

* feat(arch): grilling becomes the questioning engine — SSOT #253 lifted ADAPT→ADOPT

Operator-ratified design session (D1-D4): the compressed frontier-pacing
paraphrase measurably lost upstream's non-blocking probe rule (same-day cold
review vs the raw upstream text), so /arch §1 now consumes the grilling skill
AS IS via the mattpocock-skills companion plugin (MIT, versioned, precedent
#64 brainstorming) and keeps only a thin binding: brainstorming collision
resolution, probe routing (T20/§1.5), AskUserQuestion as the round carrier
(added to allowed-tools), and the spec's live decision register as the tree
surface. Register format lands in the spec-template obligation; SSOT #253
revisit triggers gain a named recording surface + a vendor-copy fallback arm.

Prior-art: prior-art-evaluations.md#253 (grill-me/grilling, ADOPT — companion plugin consumed AS IS; paraphrase channel measured lossy, hence the lift from ADAPT).

* feat(arch): §2 no-rerank rule — the two altitudes are never merged into one list

Adopted from mattpocock code-review's two-axis separation (one axis must not
mask the other) during the 2026-08-17 plugin sweep; the §2 seats already
report independently, this pins that their findings are presented side by
side and never reranked across altitudes.

Prior-art: prior-art-evaluations.md#253 (mattpocock-skills plugin sweep; doc-only edit, no new capability).

* docs(arch-prep): three-stack skill harmonization — collision map + raw ownership idea

Prep-doc for a future /arch design session: enumerates all three skill
populations (ours 16, superpowers 6.2.0 14, mattpocock-skills 1.2.3 35 — all
35 read in full), maps collisions per capability area (sharpest: Matt tdd vs
SP TDD contradict on refactor placement and seam scoping; diagnosing-bugs vs
systematic-debugging claim the same trigger space), lists the six available
resolution mechanisms with two unknowns (per-skill disable, routing
precedence) as probes, and drafts a one-owner-per-area map plus a live
decision register the design session starts from.

Prior-art: prior-art-evaluations.md#253 (grilling ADOPT — this prep extends the same three-stack comparison to the full plugin; doc-only, no capability).

* docs(arch-prep): §1.5 dependency edges — collision risk weighted by our hard references

Measured map of what our machinery hard-references upstream (grep over
skills/rules/agents/CLAUDE.md/templates): SDD is the most-referenced upstream
and crosses the shipped axis (tier-home.md); requesting-code-review is the
highest-risk collision zone because dispatcher/harvest contracts name it while
Matt's code-review claims the same trigger space; TDD/debugging collisions
carry routing risk only (zero hard edges from us). Also: D-H4 recorded as
answered (parallel commit 09569a3 landed mid-session), §7 gains the
re-probe-before-edit note.

Prior-art: prior-art-evaluations.md#253 (same three-stack comparison; doc-only edit).

* docs(arch-prep): DeepWiki pass on both satellites + our-side thinning audit

Per-repo DeepWiki interrogation folded in: (a) the measured routable surface
is exactly 11 mattpocock skills (user-invoked ones never enter the router —
his collision policy is the user/model-invoked split, confirmed live in this
session's skill listing); (b) Matt's refactor-out-of-loop is a June-2026
behavioral measurement («agents essentially never performed it»), not
doctrine — D-H2 needs our own corpus check; (c) TDD edge CORRECTED: SDD's
implementer-prompt.md:36 says bare «TDD», so the collision is
transitive-contract grade, not routing-only; (d) superpowers documents
Project > Personal > Plugin per-skill shadowing — new mechanism 7, P1
narrowed. New §4.5: our 16 skills audited — nothing deletable, orchestrator
is the one THIN candidate (D-H9); D-H10 TDD shadow, D-H11 domain-modeling
pairing added to the register.

Prior-art: prior-art-evaluations.md#253 (same three-stack comparison; doc-only edit).

* docs(arch-prep): slash-only planning skills evaluated as adoption candidates + 4 raw ideas

Operator correction folded in: «no collision» ≠ «no value» — the user-invoked
planning skills get per-skill adopt/adapt verdicts (wayfinder ADAPT strongest;
to-tickets ADAPT mechanizable; to-spec one section; implement REJECT; triage
two residues). New §4.6 carries four raw ideas for the design session: (1) the
decision map as the multi-session layer over /arch — D4's register lifted to
wayfinder shape, map-location sub-fork included; (2) kickoff Blocked-by edges
with a pipeline-computed frontier; (3) seams-first Testing-seams slot in the
spec template, unlocking the seams half of D-H2; (4) glossary SSOT as a
term-ownership generated index — the CONTEXT.md-free adaptation that makes the
grilling+domain-modeling pairing adoptable (D-H11 re-opened from defer).
Register grows D-H12-D-H14.

Prior-art: prior-art-evaluations.md#253 (same three-stack comparison; doc-only edit).

* docs(arch): three-stack skill harmonization — design spec + continuation handoff

Interview phase complete (frontier empty): P-1..P-6 operator premises,
15-area ownership map ratified (D-H1), decision register D-H0..D-H16 with
falsifiers, mechanism set (prune script, CONTEXT.md rule+test, claim
reorder, Blocked-by frontier, seams slot, aif plugin), probe register
P1/P2a-c/P5-pending/P6, routed-work inventory for §3 exit routing.

Awaiting §2 cold two-altitude review (this session's next step).

* docs(arch): harmonization spec v2 — round-1 cold-review dispositions landed

Both §2 seats returned REVISE (9 + 8 findings). All round-triggering
findings repaired in place: §1 restated as two declared lanes (TD-F1);
prune radius narrowed to 2 machine-globally-justified items per the
operator's F7 answer + --check pre-push drift detector (TD-F2/F7);
D-H17 completes the ownership map to all 11 model-invocable skills
(TD-F3); setup run re-bucketed attended (TD-F4); D-H5 claim mechanics
specified with real machinery + P4 restored (TD-F5, B-M1/M2); §5.6
non-target named (B-M3); /vitest transfer dissolved (B-M4); D-H7/D-H8
counter statuses corrected (B-M5); D-H13 adopts incumbent 'Depends on'
spelling (B-M6). New: P-7 premise + D-H18 consumer-axis contour routed
out via chip. Full dispositions: §9 v2 entry.

* docs(arch): harmonization spec v3 + SSOT #253 counter arm + REJECT rows #254-257

Round-2 delta review (both seats REVISE; all round-1 closures confirmed):
- --check channel corrected: owner:'maintainer' section in the pre-push.ts
  section registry (the file ships to consumers but maintainer sections
  never compose on a consumer layout, fail-closed) — .husky/pre-push is
  an exec dispatcher with no sections (convergent TD/B finding).
- D-H16 build item DISSOLVED: aif container mounts the host
  ~/.claude/plugins read-only (docker-compose.override.yml), so the
  plugin is already visible in-container and the prune/--check cover it
  by construction (measured round-2).
- 'counter armed' made true instead of re-worded: D-H7/D-H8 arm +
  observation No.0 appended to SSOT #253; REJECT rows #254-257 added
  (Matt implement, ADR dir, severity-less review model, total-sweep
  pruning). Spec SS8 item 5 DONE in-session.
Dispositions: spec SS9 v3 entry.

* docs(arch): harmonization contour GO — round-3 record + routed in-session edits

Round 3 (targeted delta): both cold seats GO. Spec header → REVIEWED-GO;
§9 round-3 entry (one TD MINOR accepted as recorded limit: container
premise rests on untracked local docker-compose.override.yml — covered
by D-H16 falsifier).

Routed §8 item 2 small edits, per spec:
- arch/SKILL.md §1: Testing seams slot added to the spec-template
  obligation (D-H14; seams-first adopted WITHOUT Matt's refactor placement)
- ai-doc/SKILL.md: skill-authoring ownership note (standard=ours,
  process=SP writing-skills, writing-for-agents=REFERENCE)
- rule-tests/SKILL.md: tautological-test anti-pattern REFERENCE note
  (D-H2 transfer (b))

* docs(arch): close harmonization contour handoff — full tail executed

Review GO (3 rounds), exit routing done (3 chips + in-session edits),
SSOT appends landed. Handoff retained as closure record; residue =
operator actions (spec SS8 item 1) + chip-routed umbrellas.

* docs(arch): consumer-axis satellite harmonization — design v1 + round-3 handoff

Round-2 /arch contour (D-H18): interview closed, D-C1..D-C8 ratified with
falsifiers; three-class collision model (factory CI / install-time census /
informed consent); detect+declare+prescribe mechanism recorded. Cold review
and exit routing DEFERRED behind the operator-mandated round-3 top-down
creative re-examination (P-C3) — handoff written for the fresh session.

* docs(arch): harmonization round 3 — registers amended, injected-context bindings land

Round 3 (D-C8, operator-mandated P-C3) executed per the handoff's membrane
phase order. Operator-axis spec v4: D-H15 SUPERSEDED — the prune apparatus
(script / wizard / --check pre-push section / gate P5) dissolved, replaced
by CLAUDE.md routing bindings (repo section + ~/.claude/CLAUDE.md
machine-global half, written in-session with live operator approval) +
meta-kickoff.template.md binding line (D-H10 fallback promoted to primary);
D-H8 gains a frontmatter-neutering ladder step. Round-2 spec v2: D-C1
re-cut to the thin form (static census prose + known-pair presence check;
inventory-join engine not built), D-C9 fourth-stack admission boundary
added (knowledge-work trio stays on SSOT #235). Round-3 handoff closed
with the continuation-state staleness correction; keen-shannon merged in
(3ae6981) so both specs live on one branch.

* docs(arch): P7 recorded — fresh-session bindings probe 2/2 vs P2 baseline

Both P2-class triggers flip with the CLAUDE.md bindings in context
(headless claude -p, fresh sessions reading the worktree CLAUDE.md from
disk). Method finding recorded: in-session subagent probes are invalid
for mid-session binding edits — subagents inherit the parent's
session-start CLAUDE.md snapshot (measured via a failed in-session probe
plus its diagnostic follow-up).

* docs(arch): round-3 review R1 — both seats REVISE, dispositions landed

Convergent BLOCKER fixed: the meta-kickoff.template.md binding line
REMOVED — .claude/skills/pipeline/ ships to consumers via GETFF_SKILLS_ENV
(setup.d/lib.sh:59) at the default env profile, so carrier #3 breached the
operator-axis membrane while buying no coverage; its removal restores all
8 install fingerprints to the baseline blob. §5.1's «no mechanical channel
at all» premise corrected (config layer only; frontmatter + a possible
Skill-matched PreToolUse hook priced — P8 records the hook UNVERIFIED:
guide claims no Skill matcher, live harness observation contradicts). P7
restated honestly (1 measured flip + 1 post-only confirmation). SSOT #253/
#257 got dated supersession notes (no prune ever executed). Five residual
prune assertions re-cut. Consumer spec: population corrected — TWO shipped
cc-plugin rows (superpowers + ast-grep, the latter disabled on the
operator's own machine); presence check re-keyed on installed_plugins.json
+ enabledPlugins; D-C5/D-C6 aligned; class-2 own-skills half recorded as
prose-only limit. ESCALATED to operator: ast-grep shipping fate (ESC-1) +
the detection-wire fork (TD-M2/P8). ~/.claude/CLAUDE.md section relocated
to file end (orphaned AIF bullet restored to its heading).

* docs(arch): round-3 review R2 — residuals closed, operator answers landed

Both R2 seats REVISE with a convergent root cause: R1 edited the surfaces
findings argued FROM, not every surface repeating the claim. Closed: §1
premise re-cut to config-layer wording; §1 scope guard now names the
pre-round-3 routed edits as verified degrade-safe REFERENCEs; sixth prune
assertion re-cut (D-H16); handoff header unmerged label; D-H15
exclusivity hedge; consumer D-C1/§7 re-keyed on installed_plugins.json +
enabledPlugins; both §8 inventories carry the escalations. Operator
answers recorded live: ESC-1 → retro-census BOTH shipped rows, keep
ast-grep on a clean census; P8 → VERIFY via the settings.json hand-off
(§8 item 7). Review round cap (2 REVISE) reached — residual state
surfaced in §9 instead of a third cold round.

* docs(kickoffs): round-3 exit routing — two build umbrellas authored

consumer-satellite-contract (thin form: retro-census of BOTH manifest
rows per the answered ESC-1, D-C2 principle test, AGENTS.md.template
section + parity line, install-registry-keyed presence check) and
skill-harmonization-mechanisms (CONTEXT.md pointer-rule test, four-part
claim machinery closing probe P4, Depends-on frontier). Both carry
host-verify contracts and the PR-pause note: they become dispatchable
only when the spec branch merges to staging.

* docs(kickoffs): declare the effort-worthiness L0 rigor label on both round-3 kickoffs

Principle 40 (`packages/core/principles/40-kickoff-rigor-label.test.ts`) requires every
post-cutoff kickoff to carry a `Rigor label … L0 …` line with a legal value. Both
round-3 kickoffs were authored without it and failed the gate at push time.

- skill-harmonization-mechanisms → `build-and-verify`: all three surviving stages are
  factory-internal and reversible, each with a live RED/GREEN seam proof.
- consumer-satellite-contract → `research-grade`: S3/S4 touch consumer-shipped
  surfaces (AGENTS.md.template, ./setup), which effort-worthiness §1 reserves for the
  research-grade contour.

Prior-art: skipped — mechanical gate compliance on two doc files, no new capability

* docs(arch): P8 CONFIRMED live — detection wire v0 declared; kickoff L0 labels

The operator-registered log-only PreToolUse Skill hook fired on a forced
model-invoked skill in a fresh headless session (JSON with tool_name=Skill
+ the skill name in tool_input). The guide-agent's 'skill loading bypasses
the tool pipeline' claim is falsified — the P6 failure class again.
Measured boundary: user-typed slash commands bypass the Skill tool
(invisible to the wire, irrelevant: misroutes are model-invocations).
TD-M2 closes — the log IS the v0 misroute detection wire feeding the D-H7
counter; spec §6 P8 + D-H8 + §8 item 7 updated. Both kickoffs gained
effort-worthiness L0 rigor labels (parallel session's edit kept as-is).

* test(install-sh): regenerate baselines for the three edited shipped skills

The branch edits `.claude/skills/{ai-doc,arch,rule-tests}/SKILL.md` — all three are
shipped artefacts, so their fingerprints move in every stack baseline that carries
them. Captured with `SNAPSHOT_MODE=capture bash tests/install-sh/snapshot.sh`.

Diff reviewed before committing (round-3 R1 precedent: an unreviewed template edit
turned 8 fingerprints stale): exactly three payload paths changed hash — rule-tests
(22 occurrences), arch (16), ai-doc (16) — and every fingerprint file is 1:1 on line
count, so no payload entered or left any stack.

Prior-art: skipped — snapshot regeneration after a shipped-file edit, no new capability

---------

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Aug 21, 2026
… carve-outs dropped (#1506 parked closure) (#1511)

* docs(corpus): legacy lint+link repair — orchestrator-prompts to markdownlint-zero and lychee-zero

Fires both re-entry triggers recorded in the host-verify retrofit (PR #1506):
the A/M carve-outs in the markdownlint arm and pre-push §8 can now be dropped
(next commit). Measured before: 401 markdownlint violations (MD040 ×326 bare
fences, MD007 ×44, MD034 ×19+3 bare emails, MD009 ×7, MD001 ×5) and 340
lychee offline errors across the dir. After: 0 / 956 files, 0 / 3670 links.

All repairs are machine-verified and content-preserving:
- MD040: bare fences (plain, indented, blockquoted) gain a 'text'
  info-string — fence content byte-identical
- MD007: dedent to the linter's own Expected value (CommonMark parses ≤3
  spaces as top-level; no AST change)
- MD009/MD034: trailing-space strips; bare URLs/emails wrapped in
  angle-bracket autolinks
- MD001: five h1→h3 skips re-levelled ### → ##
- links: 226 relinked to verified live targets (repair rewrites: renamed
  skill meta-orchestrator→orchestrator, doubled .claude/.claude, wrong
  relative roots; suffix search over git-tracked files, unique matches
  only, fragments preserved); 102 de-linked to code spans where the target
  is machine-local (~, file://, /private/tmp, .zcode), gitignored scratch
  (drafts/), or gone with no unique survivor (e.g. agents/docs-auditor.md,
  master-backlog-delta.md, meta-launch kickoffs never committed)
- two multi-line links (state.md 248, top-down-r1.md 331) hand-fixed to
  the correct relative depth
- lychee.toml: one unanchored exclude '/\.\.\.$' for the literal ellipsis
  placeholder quoted inside an escaped code span (migration-ast stage-1) —
  a parser phantom in the placeholder class, not a link

Stance note: lychee.toml's exclude_path keeps research-patches/retros as
'expected archaeology'; the orchestrator-prompts corpus instead gets
repaired-to-zero (PR #1506's shipped decision) so the LIVE kickoffs keep
full link checking with no exclusions at all.

* fix(hooks): drop both legacy-corpus carve-outs — re-entry triggers fired

The orchestrator-prompts corpus is now markdownlint-zero (956 files) and
lychee-zero (3670 links, offline + --root-dir) after the repair commit —
the re-entry conditions both carve-outs recorded. Dropping them:

- .husky/pre-commit markdownlint arm: back to the plain staged-*.md set;
  the A/M awk filter and its exclusion note replaced by a history note.
- packages/core/hooks/pre-push.ts §8: same removal; the lychee invocation
  gains --root-dir REPO_ROOT — root-relative links (leading /) now resolve
  against the repo instead of erroring unresolved (the class the repair
  surfaced; without a root dir lychee cannot form a URL for such links, so
  neither checking nor exclude patterns can see them). Consumer-layout
  narrowing (S2 Part 1) untouched — suite 32/32.
- packages/core/hooks/utils/git.ts: getAddedFiles() removed with its last
  caller (dead export; the A/M split was its only consumer).
- baselines regenerated (shipped bytes changed): exactly the pre-push.ts,
  git.ts and transitive refresh-baseline manifest hash lines ×8 npm cells.

Sweep: 35/35 gates, FULL mode (byte-identical 15/15, typecheck, all
vitest lanes, render/rule-index, format — clean).

* fix(review): cold-review round 1 — collapse 3 duplicate de-link code spans + on-disk precision in gate comments

Reviewer CLEAN verdict (0 blocker/major); folded the three MINORs:
- swarm-tools-research/kickoff.md:76 and wave-9 post-9 ×2 — the de-link
  transform appended the href code span even when the label already WAS
  that span ('label (label)'); collapsed to the single span. The foreign
  coordination mirror (repo-hygiene-cleanup) carries the same shape but
  is another session's artifact — left untouched.
- '956 files'/'3670 links' comments now say on-disk/checked — the corpus
  dir includes gitignored sidecars beyond the tracked set.
- stray state.md.tmp from the aborted first fixer attempt removed.

* fix(review): fidelity round 1 — relink the 3 live targets the de-link pass over-applied

Auditor MINOR: think-time-s17-gate/kickoff.md:32,:92,:172 were de-linked
although their targets are live and tracked (research-patch §13.24,
agents/compliance-verifier.md, README.md) — first-pass target matching
missed them (percent-encoded § in one report form; ambiguous bare
basenames in the others). Relinked to correct relative paths; both zero
states re-verified (markdownlint 0/956, lychee 0/3670 exit 0).

The ESCALATED finding is a wording correction only (recorded in the PR
body): the parked-#3 premise 'cli2 does not auto-read .markdownlint.json'
is empirically false — cli2 DOES auto-discover the v1 config from cwd
(auditor A/B: with the json present the corpus reported 1 error class;
with it removed, 3 — MD013/MD041 surface). In-repo the hook therefore
enforces the project's declared 6-rule set (shared with editors);
consumers, where install.sh ships no config, get cli2 defaults — the
strict side lands there. No wiring needed; the retrofit PR's parked
wording was wrong and this PR's body records the corrected decision.

* chore(lychee): exclude explainx.ai — 200 locally, deterministic TIMEOUT from GH runners

The live link audit (pre-existing link, docs/meta-factory/prior-art-
evaluations.md:167 + the companion-capability survey — NOT part of this
PR's diff) timed out twice from the CI runner on the same URL while a
local curl -I returns HTTP/2 200. Same unreachable-from-runner class as
the documented npmjs/gptlint entries: runner-path problem, not a dead
link. Documented with the measurement.

---------

Co-authored-by: Test <test@example.com>
artyhoo added a commit that referenced this pull request Sep 4, 2026
Promote staging → main #3 — beta candidate (682 commits since 2026-07-10)
artyhoo added a commit that referenced this pull request Sep 5, 2026
… economy → GLM-5.3 SDK (#1608)

## Summary

Two `/pipeline` launch presets named runtime profiles that no longer resolve on the live aif instance: `presets/aif.json` marker `Claude Opus (plan+review)` is a DISABLED profile (matches by exact name in `AifHandoffBackend._resolveProfileId`, then blocks at runtime auth — the `cf894220` shape), and `presets/economy.json` marker `Z.AI GLM-5.2 SDK` matches no profile at all (the instance runs 5.3; dispatch throws). Both were recorded as a live defect in `.claude/orchestrator-prompts/beta-docs-showcase/kickoff.decisions.md:53-54` and left for the pipeline skill owner; the operator invited the fix on 2026-09-05. Data fix, one concern.

## Changes

- `.claude/skills/pipeline/references/presets/aif.json` — `marker: null` (the preset dispatches on the project's per-mode default profiles — the ratified GLM-only posture of PR #1446 / kickoff.decisions.md Decision 1 — instead of forcing a disabled Claude profile); description says so.
- `.claude/skills/pipeline/references/presets/economy.json` — `marker: "Z.AI GLM-5.3 SDK"` (unique under the resolver's match; live list quoted below).
- `.claude/skills/pipeline/SKILL.md:56` — the Seam #3 sentence names the presets that now carry a marker (economy) and the null-marker set (aif/night/sdd).

Live profile list at authoring (`curl -s "$RUNTIME_BRIDGE_AIF_URL/runtime-profiles"`, 2026-09-05):

```text
41315ef6 | Claude Opus (plan+review)        | enabled=False
53eca24c | Z.AI GLM-5.3 SDK                 | enabled=True
b6f8d94e | Qwen3.8-Max-Preview              | enabled=True
088182b8 | Z.AI GLM-5.3 Flash (implementer) | enabled=True
```

`Z.AI GLM-5.3 SDK` is a strict prefix of nothing and a substring of exactly one row — the marker value rule (`packages/core/templates/shared/tier-home.md:63`) holds.

## Prior-art consult

- [x] Not a capability commit (two JSON values + one sentence; `packages/core/hooks/checks/prior-art.ts:142`).
- [x] No new capability area.
- [x] No SSOT entry matched.
- [x] context7 not applicable.

## Test plan

- [x] `bash .claude/skills/pipeline/helpers/list-presets.sh` — `aif` renders without a marker (null → no `marker=` suffix, same path as night/sdd, `list-presets.sh:45-47`), `economy` renders `marker=Z.AI GLM-5.3 SDK`.
- [x] `bash .claude/skills/pipeline/helpers/resolve-preset.sh aif` emits no `PRESET_MARKER` line (`resolve-preset.sh:74-75` handles null); `... economy` emits `PRESET_MARKER=Z.AI GLM-5.3 SDK`.
- [x] `grep -rn 'GLM-5.2 SDK\|plan+review' .claude/skills/pipeline` → only the two edited files before, zero stale hits after; historical kickoffs under `.claude/orchestrator-prompts/` keep their markers as records and are out of scope.

## Provenance

n/a

## Review findings

n/a

## Fidelity verdict

FIDELITY: skipped — data fix of two preset marker values plus one SKILL.md sentence; no stage kickoff applies.

## Parked questions

n/a

## §1.7 Self-discipline check (REQUIRED if PR touches discipline-bearing files)

### §1.7 Skipped: data fix of two preset marker values plus one descriptive SKILL.md sentence — no rule, principle or convention introduced; the marker value rule itself is unchanged



## Follow-ups landed in this PR

- Regenerated the 8 npm-stack + 3 python snapshot baselines (the pipeline skill payload and the re-rendered AI-USAGE-GUIDE §6a ship at every depth; cargo baselines untouched — green in CI).
- `packages/core/hooks/parse-preset.test.ts` follows the new markers (aif: no marker line; economy: GLM-5.3 SDK).
- `AI-USAGE-GUIDE.md` §6a re-rendered via `scripts/render-presets.mjs --write` (the Manifest → RULES.md drift job checks it).
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.

1 participant