diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..70ed20c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,29 @@ +FROM mcr.microsoft.com/devcontainers/typescript-node:22-bookworm + +USER root +RUN apt-get update \ + && apt-get install -y --no-install-recommends sqlite3 jq ripgrep \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# GitHub's signed apt repository supplies current gh releases on both CPU families. +RUN mkdir -p -m 755 /etc/apt/keyrings \ + && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ + -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ + > /etc/apt/sources.list.d/github-cli.list \ + && apt-get update && apt-get install -y --no-install-recommends gh \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Resolve the latest AQE release; post-create also refreshes cached images. +# Transformers is the tutorial's explicit local-embedding opt-in (see README). +ARG AQE_VERSION=latest +ARG TRANSFORMERS_VERSION=4.2.0 +ARG CLAUDE_VERSION=latest +ARG CODEX_VERSION=latest +USER node +RUN npm install -g --no-fund --no-audit \ + "agentic-qe@${AQE_VERSION}" \ + "@huggingface/transformers@${TRANSFORMERS_VERSION}" \ + "@anthropic-ai/claude-code@${CLAUDE_VERSION}" \ + "@openai/codex@${CODEX_VERSION}" diff --git a/.devcontainer/check-workspace.sh b/.devcontainer/check-workspace.sh new file mode 100644 index 0000000..9fbe5ec --- /dev/null +++ b/.devcontainer/check-workspace.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Sourced before any mutation: refuse an AQE development checkout or another repo. +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" +node -e 'const p=require("./package.json"); if(p.name!=="checkout-demo" || !p.private) { console.error("Refusing setup outside the checkout-demo tutorial repository."); process.exit(1) }' +test -f LAB.md && test -f seed/aqe-seed-patterns.json || { + echo 'Tutorial LAB.md / seed files missing; refusing setup.' >&2 + exit 1 +} +if [ -L .agentic-qe ] || [ -L .agentic-qe/memory.db ]; then + echo 'Refusing linked AQE data: the tutorial must not write another workspace memory.' >&2 + exit 1 +fi diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..a66ebe3 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,28 @@ +{ + "name": "HUSTEF 2026 · The 70% Problem", + "build": { "dockerfile": "Dockerfile", "context": "." }, + "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/tutorial,type=bind", + "workspaceFolder": "/workspaces/tutorial", + "remoteUser": "node", + "updateRemoteUserUID": true, + "hostRequirements": { "cpus": 4, "memory": "8gb", "storage": "32gb" }, + "containerEnv": { "NEXT_TELEMETRY_DISABLED": "1" }, + "forwardPorts": [3000], + "portsAttributes": { + "3000": { "label": "Checkout demo", "onAutoForward": "notify" } + }, + "otherPortsAttributes": { "onAutoForward": "ignore" }, + "postCreateCommand": "bash .devcontainer/post-create.sh", + "waitFor": "postCreateCommand", + "customizations": { + "vscode": { + "extensions": ["anthropic.claude-code", "openai.chatgpt", "esbenp.prettier-vscode"], + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "editor.fontSize": 16, + "terminal.integrated.fontSize": 16 + } + }, + "codespaces": { "openFiles": ["docs/DEVCONTAINER.md", "LAB.md"] } + } +} diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh new file mode 100644 index 0000000..0305981 --- /dev/null +++ b/.devcontainer/post-create.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "${BASH_SOURCE[0]}")/check-workspace.sh" + +# Do not echo environment variables: Codespaces can inject participant secrets. +sudo -n apt-get update -qq +sudo -n apt-get install -y --no-install-recommends gh +npm install -g --no-fund --no-audit agentic-qe@latest @anthropic-ai/claude-code@latest @openai/codex@latest +npm ci --no-fund --no-audit + +# A rebuild/resume must never reinitialize a participant's existing learning DB. +if [ ! -e .agentic-qe ]; then + aqe init --auto --skip-code-index +elif [ ! -f .agentic-qe/memory.db ]; then + echo 'Incomplete existing AQE setup. Preserve .agentic-qe and ask a facilitator to inspect it.' >&2 + exit 1 +else + echo 'Preserving existing AQE setup and learning data.' +fi +node -e 'const p=require("node:child_process").execSync("npm root -g").toString().trim(); console.log(`Using AQE ${require(`${p}/agentic-qe/package.json`).version}`)' + +# No fake payment keys, and no overwriting a participant's .env.local. +if [ ! -e .env.local ] && [ ! -L .env.local ]; then + (umask 077; printf '# Optional: add your own Stripe TEST keys from .env.example.\n' > .env.local) +fi + +printf '\nContainer ready. Next run: bash .devcontainer/prepare-workshop.sh\n' +printf 'Then: bash .devcontainer/verify.sh, sign in to your agent, and open LAB.md.\n' diff --git a/.devcontainer/prepare-workshop.sh b/.devcontainer/prepare-workshop.sh new file mode 100644 index 0000000..afdbddf --- /dev/null +++ b/.devcontainer/prepare-workshop.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Explicit participant action, never a restart hook: indexing and seed import write memory. +set -euo pipefail +source "$(dirname "${BASH_SOURCE[0]}")/check-workspace.sh" +test -f .agentic-qe/memory.db || { echo 'Run post-create.sh first.' >&2; exit 1; } +MARKER=.agentic-qe/devcontainer-workshop-prepared +if [ -f "$MARKER" ]; then + echo 'Workshop baseline already prepared; preserving your graph and learned patterns.' + bash .devcontainer/verify.sh + exit 0 +fi + +# SQLite backup includes committed WAL content. Keep a timestamped copy before writes. +mkdir -p .agentic-qe/backups +BACKUP=".agentic-qe/backups/pre-workshop-$(date -u +%Y%m%dT%H%M%SZ)-$$.db" +sqlite3 .agentic-qe/memory.db ".backup '$BACKUP'" +test "$(sqlite3 -readonly "$BACKUP" 'PRAGMA integrity_check;')" = ok +printf 'Pre-workshop memory backup: %s\n' "$BACKUP" + +# Indexing with a provider key can make paid LLM calls. Prepare a purely local baseline. +# A minimal child environment excludes every provider credential/endpoint rather +# than maintaining a list of key names. Parent-shell credentials stay untouched. +env -i HOME="$HOME" PATH="$PATH" aqe code index src/ +aqe hg stats +aqe memory usage +aqe learning import -i seed/aqe-seed-patterns.json +aqe learning stats +# Verification must succeed before the completion marker is written. +bash .devcontainer/verify.sh +date -u +%FT%TZ > "$MARKER" diff --git a/.devcontainer/smoke-app.sh b/.devcontainer/smoke-app.sh new file mode 100644 index 0000000..fc3abfa --- /dev/null +++ b/.devcontainer/smoke-app.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Exercise the no-key app surfaces without calling Stripe or making a payment. +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/.." +LOG="$(mktemp)" +PAGE="$(mktemp)" +if curl -s http://127.0.0.1:3000/ > /dev/null; then + echo 'Port 3000 is already in use; stop that server before the smoke check.' >&2 + exit 1 +fi +node node_modules/next/dist/bin/next dev --hostname 0.0.0.0 --port 3000 > "$LOG" 2>&1 & +SERVER_PID=$! +trap 'kill "$SERVER_PID" 2>/dev/null || true; wait "$SERVER_PID" 2>/dev/null || true; rm -f "$LOG" "$PAGE"' EXIT +ready=0 +for _ in $(seq 1 90); do + if curl -fsS http://127.0.0.1:3000/ > /dev/null 2>&1; then ready=1; break; fi + if ! kill -0 "$SERVER_PID" 2>/dev/null; then cat "$LOG"; exit 1; fi + sleep 1 +done +if [ "$ready" != 1 ]; then cat "$LOG"; exit 1; fi +curl -fsS http://127.0.0.1:3000/ -o "$PAGE" +rg -q 'Premium Wireless Headphones' "$PAGE" +curl -fsS http://127.0.0.1:3000/cart -o "$PAGE" +rg -q 'cart' "$PAGE" +test "$(curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/api/orders)" = 400 +echo 'Catalog, cart, and missing-order validation: OK (no payment attempted)' diff --git a/.devcontainer/test-lifecycle.sh b/.devcontainer/test-lifecycle.sh new file mode 100644 index 0000000..de3eba0 --- /dev/null +++ b/.devcontainer/test-lifecycle.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Focused failure/preservation tests with fake tooling, never a real learning DB. +set -euo pipefail +SOURCE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FIXTURE="$(mktemp -d)" +trap 'rm -rf "$FIXTURE"' EXIT +mkdir -p "$FIXTURE/.devcontainer" "$FIXTURE/bin" +cp "$SOURCE/post-create.sh" "$SOURCE/prepare-workshop.sh" "$SOURCE/check-workspace.sh" "$FIXTURE/.devcontainer/" +mkdir -p "$FIXTURE/seed" +mkdir -p "$FIXTURE/global/agentic-qe" +printf '{"version":"latest-test-double"}\n' > "$FIXTURE/global/agentic-qe/package.json" +printf '{"name":"checkout-demo","private":true}\n' > "$FIXTURE/package.json" +touch "$FIXTURE/LAB.md" "$FIXTURE/seed/aqe-seed-patterns.json" +cat > "$FIXTURE/bin/npm" <<'MOCK' +#!/usr/bin/env bash +if [ "${1:-}" = root ]; then echo "$FAKE_GLOBAL"; fi +exit "${NPM_FAIL:-0}" +MOCK +printf '#!/usr/bin/env bash\nexit 0\n' > "$FIXTURE/bin/sudo" +cat > "$FIXTURE/bin/sqlite3" <<'MOCK' +#!/usr/bin/env bash +if [ "$1" = -readonly ]; then echo ok; exit 0; fi +# Simulate a successful backup only; no SQLite database is used by these tests. +if [[ "$2" == .backup* ]]; then dest="${2#*\'}"; dest="${dest%\'}"; cp "$1" "$dest"; fi +MOCK +cat > "$FIXTURE/bin/aqe" <<'MOCK' +#!/usr/bin/env bash +if [ "$1" = --version ]; then echo latest-test-double; exit 0; fi +TRACE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/trace" +printf '%s\n' "$*" >> "$TRACE" +if [ "$1" = init ]; then mkdir -p .agentic-qe; printf 'fake database' > .agentic-qe/memory.db; fi +if [ "$1" = code ] && [ -n "${ANTHROPIC_API_KEY:-}" ]; then exit 99; fi +exit 0 +MOCK +printf '#!/usr/bin/env bash\nexit "${VERIFY_FAIL:-0}"\n' > "$FIXTURE/.devcontainer/verify.sh" +chmod +x "$FIXTURE/bin/"* +export PATH="$FIXTURE/bin:$PATH" TRACE="$FIXTURE/trace" FAKE_GLOBAL="$FIXTURE/global" +cd "$FIXTURE" + +# Running in the AQE development repo (or any other package) must fail before npm. +printf '{"name":"agentic-qe"}\n' > package.json +if bash .devcontainer/post-create.sh; then exit 1; fi +test ! -e "$TRACE" +printf '{"name":"checkout-demo","private":true}\n' > package.json + +# Failed dependency install must not initialize memory or create env configuration. +if NPM_FAIL=1 bash .devcontainer/post-create.sh; then exit 1; fi +test ! -e .agentic-qe +test ! -e .env.local + +# A fresh setup initializes once and reruns preserve participant files byte-for-byte. +bash .devcontainer/post-create.sh +test "$(wc -l < "$TRACE")" -eq 1 +printf 'participant secret placeholder\n' > .env.local +cp .env.local original-env +cp .agentic-qe/memory.db original-db +bash .devcontainer/post-create.sh +test "$(wc -l < "$TRACE")" -eq 1 +cmp .env.local original-env +cmp .agentic-qe/memory.db original-db + +# Linked AQE data must be refused, including a dangling link. +mv .agentic-qe held-fake-aqe +ln -s held-fake-aqe .agentic-qe +if bash .devcontainer/post-create.sh; then exit 1; fi +rm .agentic-qe +mv held-fake-aqe .agentic-qe + +# Even a dangling .env.local link is left untouched. +mv .env.local held-env +ln -s nonexistent-participant-env .env.local +bash .devcontainer/post-create.sh +test -L .env.local +test ! -e nonexistent-participant-env +rm .env.local +mv held-env .env.local + +# Partial setup is never silently replaced. This is a fake fixture, not a DB. +mv .agentic-qe/memory.db held-fake-db +if bash .devcontainer/post-create.sh; then exit 1; fi +test ! -e .agentic-qe/memory.db +mv held-fake-db .agentic-qe/memory.db + +# A failed verification leaves no marker; retry works and credentials stay local. +if VERIFY_FAIL=1 ANTHROPIC_API_KEY=fake bash .devcontainer/prepare-workshop.sh; then exit 1; fi +test ! -e .agentic-qe/devcontainer-workshop-prepared +ANTHROPIC_API_KEY=fake bash .devcontainer/prepare-workshop.sh +test -f .agentic-qe/devcontainer-workshop-prepared +cp "$TRACE" original-trace +bash .devcontainer/prepare-workshop.sh +cmp "$TRACE" original-trace +cmp .agentic-qe/memory.db original-db +echo 'Lifecycle preservation, incomplete setup, dependency failure, and retry checks: OK' diff --git a/.devcontainer/verify-data.cjs b/.devcontainer/verify-data.cjs new file mode 100644 index 0000000..04ebc5c --- /dev/null +++ b/.devcontainer/verify-data.cjs @@ -0,0 +1,27 @@ +// Validate persisted tutorial data read-only, rather than trusting AQE's import counter. +const { execFileSync } = require('node:child_process'); +const { readdirSync } = require('node:fs'); +const path = require('node:path'); +const db = '.agentic-qe/memory.db'; +function query(sql) { + return JSON.parse(execFileSync('sqlite3', ['-readonly', '-json', db, sql], { encoding: 'utf8' }) || '[]'); +} +const seeds = require('../seed/aqe-seed-patterns.json').patterns; +const patterns = query('SELECT p.name, e.dimension, length(e.embedding) AS bytes FROM qe_patterns p LEFT JOIN qe_pattern_embeddings e ON e.pattern_id = p.id'); +for (const seed of seeds) { + if (!patterns.some(p => p.name === seed.name && p.dimension === 384 && p.bytes > 0)) { + throw new Error(`Seed pattern missing or unembedded: ${seed.name}. Run prepare-workshop.sh; see TROUBLESHOOTING.md.`); + } +} +function files(dir) { + return readdirSync(dir, { withFileTypes: true }).flatMap(e => { + const file = path.join(dir, e.name); + return e.isDirectory() ? files(file) : /\.(ts|tsx)$/.test(e.name) ? [path.resolve(file)] : []; + }); +} +const sourceFiles = files('src'); +const indexed = new Set(query("SELECT file_path FROM hypergraph_nodes WHERE type = 'file'").map(r => r.file_path)); +for (const file of sourceFiles) { + if (!indexed.has(file)) throw new Error(`Source file absent from graph: ${file}`); +} +console.log(`${sourceFiles.length} source files indexed; ${seeds.length}/${seeds.length} checkout seed patterns with 384-dimensional embeddings; ${patterns.length} total patterns: OK`); diff --git a/.devcontainer/verify-mcp.mjs b/.devcontainer/verify-mcp.mjs new file mode 100644 index 0000000..153412f --- /dev/null +++ b/.devcontainer/verify-mcp.mjs @@ -0,0 +1,55 @@ +// Real stdio handshake; no provider credentials and no paid model calls. +import { spawn } from 'node:child_process'; +import { createInterface } from 'node:readline'; +const server = spawn('aqe-mcp', [], { + stdio: ['pipe', 'pipe', 'pipe'], + env: { ...process.env, AQE_WORKERS_ENABLED: 'false' }, +}); +let nextId = 0; +const pending = new Map(); +const lines = createInterface({ input: server.stdout }); +lines.on('line', line => { + let message; + try { message = JSON.parse(line); } catch { return; } + const waiter = pending.get(message.id); + if (waiter) { pending.delete(message.id); message.error ? waiter.reject(new Error(JSON.stringify(message.error))) : waiter.resolve(message.result); } +}); +server.stderr.resume(); +server.on('error', error => { for (const waiter of pending.values()) waiter.reject(error); }); +server.on('exit', code => { for (const waiter of pending.values()) waiter.reject(new Error(`MCP exited: ${code}`)); }); +function request(method, params = {}) { + const id = ++nextId; + return new Promise((resolve, reject) => { + pending.set(id, { resolve, reject }); + server.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id, method, params })}\n`); + }); +} +const deadline = setTimeout(() => { console.error('MCP handshake timed out'); server.kill('SIGKILL'); process.exitCode = 1; }, 60000); +try { + await request('initialize', { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'hustef-readiness', version: '1.0.0' } }); + server.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' })}\n`); + const tools = []; + let cursor; + do { + const result = await request('tools/list', cursor ? { cursor } : {}); + tools.push(...result.tools); + cursor = result.nextCursor; + } while (cursor); + const query = tools.find(t => t.name === 'memory_query'); + if (!query) throw new Error('AQE memory_query tool missing'); + console.log(`AQE MCP handshake and tools/list: OK (${tools.length} tools)`); + const memory = await request('tools/call', { name: 'memory_query', arguments: { pattern: 'payment retry checkout', semantic: true, limit: 2 } }); + if (memory.isError) throw new Error(`MCP memory_query failed: ${JSON.stringify(memory.content)}`); + const payload = JSON.parse(memory.content.find(c => c.type === 'text').text); + if (!payload.success || !Array.isArray(payload.data?.entries)) throw new Error(`MCP memory query failed: ${JSON.stringify(payload)}`); + console.log(`AQE MCP memory_query protocol: OK (${payload.data.entries.length} entries returned)`); + if (!payload.data.entries.length) { + console.warn('Recall limitation: this MCP query did not return persisted tutorial data. SQLite seed verification is separate; use LAB.md reports fallback for Exercise 5.'); + if (process.argv.includes('--require-recall')) process.exitCode = 1; + } +} finally { + clearTimeout(deadline); + lines.close(); + server.stdin.end(); + server.kill(); +} diff --git a/.devcontainer/verify.sh b/.devcontainer/verify.sh new file mode 100644 index 0000000..41260a3 --- /dev/null +++ b/.devcontainer/verify.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Read-only readiness checks. Never import patterns, index code, or initialize a DB here. +set -euo pipefail +source "$(dirname "${BASH_SOURCE[0]}")/check-workspace.sh" +node -e 'const [a,b]=process.versions.node.split(".").map(Number); if(a<22 || (a===22 && b<13)) process.exit(1)' +node -e 'const p=require("node:child_process").execSync("npm root -g").toString().trim(); for (const n of ["agentic-qe","@huggingface/transformers"]) { const pkg=require(`${p}/${n}/package.json`); console.log(`${n} ${pkg.version}`) }' +command -v claude >/dev/null +command -v codex >/dev/null +command -v gh >/dev/null +test -d node_modules/next +test -f .mcp.json +test -f .claude/agents/v3/qe-test-architect.md +test -f .claude/agents/v3/qe-defect-predictor.md +test -f .claude/agents/v3/qe-queen-coordinator.md +test -f .claude/agents/v3/qe-product-factors-assessor.md +test -f .claude/skills/qcsd-ideation-swarm/SKILL.md +test -f .claude/skills/exploratory-testing-advanced/SKILL.md +test -f .agentic-qe/memory.db +test "$(sqlite3 -readonly .agentic-qe/memory.db 'PRAGMA integrity_check;')" = ok +echo 'Tooling, exercise assets, and SQLite integrity: OK' +node .devcontainer/verify-data.cjs diff --git a/.github/workflows/devcontainer.yml b/.github/workflows/devcontainer.yml new file mode 100644 index 0000000..1d01ef2 --- /dev/null +++ b/.github/workflows/devcontainer.yml @@ -0,0 +1,31 @@ +name: Workshop devcontainer +on: + pull_request: + push: + branches: [main] + workflow_dispatch: +permissions: + contents: read +jobs: + workshop: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v7.0.1 + with: + persist-credentials: false + - name: Check lifecycle preservation and shell syntax + run: | + for script in .devcontainer/*.sh; do bash -n "$script"; done + bash .devcontainer/test-lifecycle.sh + - name: Build workshop tools with latest AQE + run: docker build -t hustef-workshop .devcontainer + - name: Prepare and exercise the Linux container + run: | + WORKSHOP_RUNNER_UID="$(id -u)" + WORKSHOP_RUNNER_GID="$(id -g)" + trap 'sudo chown -R "$WORKSHOP_RUNNER_UID:$WORKSHOP_RUNNER_GID" "$PWD"' EXIT + docker run --rm --user root \ + -v "$PWD:/workspaces/tutorial" -w /workspaces/tutorial \ + -e NEXT_TELEMETRY_DISABLED=1 hustef-workshop \ + bash -lc 'chown -R node:node /workspaces/tutorial && su node -c "bash .devcontainer/post-create.sh && bash .devcontainer/prepare-workshop.sh && node .devcontainer/verify-mcp.mjs && npm run test:coverage && npx --no-install tsc --noEmit && bash .devcontainer/smoke-app.sh"' diff --git a/LAB.md b/LAB.md index ff43217..5b83c61 100644 --- a/LAB.md +++ b/LAB.md @@ -8,7 +8,7 @@ Six steps on this deliberately-flawed checkout app: **build a local knowledge gr Both write to the same report and end with **"Save learnings and persist patterns."** *(Step 0 is three terminal commands and step 5 is one prompt, so both are identical on every tool and have no split.)* -**Before you start:** finish the [README](./README.md) Setup (clone → `npm install -g agentic-qe@3.14.1` → `aqe init --auto --with-` → `npm install` → `aqe code index src/` → `npm install -g @huggingface/transformers@4.2.0`), then launch your agent here. **Don't skip `aqe init`** (it installs the agents, MCP config, and memory DB) and **run the exercises in order** (2b and 3 read 2's output; 3 and 4 act on 2c's ranking; 5 recalls what 0–4 saved). Paths are relative to the repo root. +**Before you start:** finish the [container setup](./docs/DEVCONTAINER.md) or the [README](./README.md) manual Setup (Node 22.13+ → clone → `npm install -g agentic-qe@latest` → `aqe init --auto --with-` → `npm install` → `aqe code index src/` → `npm install -g @huggingface/transformers@4.2.0`), then launch your agent here. **Don't skip `aqe init`** (it installs the agents, MCP config, and memory DB; container setup does this for you) and **run the exercises in order** (2b and 3 read 2's output; 3 and 4 act on 2c's ranking; 5 recalls what 0–4 saved). Paths are relative to the repo root. --- diff --git a/README.md b/README.md index 31e2836..98075c8 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The SDLC exercises have **two prompt versions** — one for **Claude Code users* A tutorial day is not enough time to fix a laptop. Please get through Setup at home. -- **Node.js 20 or newer, and npm 10 or newer.** Check with `node -v` and `npm -v`. AQE 3.14 declares Node 22.13 in its `engines` field, so on Node 20 npm prints an `EBADENGINE` warning and installs anyway. Verified on Node 20.20.2: install, `aqe init`, the code index and the test suite all behave identically to Node 22. The one setup that does fail is npm with `engine-strict=true`, which turns that warning into an error; there, use Node 22.13 or newer. +- **Node.js 22.13 or newer, and npm 10 or newer.** Check with `node -v` and `npm -v`. Use a supported Node release that satisfies the latest AQE package's engine requirement; the devcontainer supplies Node 22. - **Rights to install a global npm package.** Setup runs `npm install -g agentic-qe`. If your machine blocks that, bring a laptop that does not. - **A coding agent you already use, signed in and working.** Claude Code, GitHub Copilot, Cursor, AWS Kiro, OpenAI Codex CLI, Windsurf, Cline, OpenCode, Kilo Code, Roo Code or Continue.dev. AQE drives whichever one you have, through one MCP server. - **Your own model access.** Steps 1 to 5 spend your tokens on your own key or subscription. Step 0 spends none. Budget about what an hour of ordinary agent use costs you. @@ -44,6 +44,12 @@ A tutorial day is not enough time to fix a laptop. Please get through Setup at h ## Setup +**Prefer a ready-to-use container?** Open this repository in GitHub Codespaces, +or run it locally with DevPod + Docker / VS Code Dev Containers. Follow +[the container setup guide](./docs/DEVCONTAINER.md) instead of the manual steps +below. It installs the latest AQE; you still use your own agent +account and optional Stripe test keys. + **1. Get this repo.** Clone it (or download the ZIP from the green **Code** button and unzip), then move into the folder: ```bash @@ -56,7 +62,7 @@ cd HUSTEF-70-Percent-Problem-Tutorial **2. Install AQE and set it up for your coding agent.** Run these once, from inside the folder: ```bash -npm install -g agentic-qe@3.14.1 # the AQE CLI (global, one-time) +npm install -g agentic-qe@latest # the latest published AQE CLI aqe init --auto # set up AQE for YOUR coding agent — see the table below ``` diff --git a/docs/DEVCONTAINER-VERIFICATION.md b/docs/DEVCONTAINER-VERIFICATION.md new file mode 100644 index 0000000..7ab1cea --- /dev/null +++ b/docs/DEVCONTAINER-VERIFICATION.md @@ -0,0 +1,62 @@ +# Container verification and adversarial review + +Verified 4 October 2026 against tutorial base +`42f7e0854ab24302122875ac90a6929b6ef763a3`. + +| Check | Result | +|---|---| +| Docker build on Linux arm64 / Apple Silicon | Passed | +| Dev Container CLI 0.89.0 `up` and post-create | Passed | +| DevPod with Docker, isolated test workspace | Passed | +| Runtime tools | Node 22.23.2; AQE 3.14.8; Claude 2.1.289; Codex 0.160.0; gh 2.102.0 | +| `npm run test:coverage` | 12 files, 333 tests passed; 61.62% statements overall | +| `npx --no-install tsc --noEmit` | Passed | +| `npm run build` without Stripe credentials | Passed | +| `bash .devcontainer/smoke-app.sh` | Catalog, cart, missing-order HTTP 400 passed; no payment attempted | +| `bash .devcontainer/verify.sh` | All 21 source files indexed; 6/6 seeds with 384-dimensional embeddings; 76 patterns; integrity `ok` | +| MCP handshake/tool catalog | Passed; 91 tools | +| MCP seeded-data recall | Not qualified: tested queries returned zero entries; reports fallback documented | +| Re-run post-create and preparation | Test database SHA-256 unchanged; seed/graph verification passed | +| `bash .devcontainer/test-lifecycle.sh` | Wrong repository, linked memory, dangling env link, incomplete setup, failed install, failed verification, retry, and repeated preparation checks passed | +| Shell syntax and `git diff --check` | Passed | + +The GitHub Actions workflow repeats the container build, fresh preparation, +MCP protocol check, unit coverage, TypeScript check, and app smoke check on Linux +amd64. The MCP protocol check explicitly reports empty recall; CI success must +not be described as qualification of the memory-learning exercise. +The first Linux amd64 run also passed all 333 tests and verified the 21 source +paths and six embedded seed patterns. CI uses current `actions/checkout` with +credential persistence disabled, and restores runner file ownership after Docker. + +## Adversarial findings and resolution + +1. AQE `--version` can create an empty `.agentic-qe` directory before init. + Setup now reads package metadata for its version report. +2. Root-owned global npm packages blocked latest-tool updates by the workspace + user. The image installs npm tools as `node`; post-create refreshes latest. +3. CLI import output said zero imported even when seed writes succeeded. + Readiness verifies each seed name and embedding in SQLite instead. +4. A shallow graph counter alone could conceal skipped API routes. Readiness + checks the persisted path for every source file, including both API routes. +5. Automatic setup could damage existing memory or overwrite `.env.local`. + Init is gated on absent AQE data; partial setups stop; symlinks are refused; + env files/links are preserved; preparation backs up before initial writes; + no post-start mutation hook is installed. +6. Provider keys injected by Codespaces could make indexing spend tokens. + Indexing receives a minimal child environment without provider credentials. +7. Passing setup could be mistaken for working Stripe payments or memory recall. + Those limits are separated in participant docs and the slide handoff. + +## Remaining acceptance limits + +Actual Codespaces creation was unavailable because the current GitHub token +lacks Codespaces scope. The standards-based config is validated locally; +Lalit/Dragan should create a Codespace from the PR branch before the workshop. +Agent sign-in and paid QCSD exercises were not executed. External product +images may fail independently of the container. Intentional application defects +and the existing app dependency lockfile were preserved. + +All database operations occurred only in the disposable tutorial test workspace +under `/private/tmp`, with backups before preparation. The local AQE development +checkout and its learning database were never mounted in these containers or +modified by these setup scripts. diff --git a/docs/DEVCONTAINER.md b/docs/DEVCONTAINER.md new file mode 100644 index 0000000..ac6e011 --- /dev/null +++ b/docs/DEVCONTAINER.md @@ -0,0 +1,128 @@ +# Workshop container — Codespaces or local Docker + +For the **6 October 2026** tutorial, this is an alternative to the manual Setup +in README. It uses the same app and exercises, **latest published AQE**, and local +embedder **4.2.0**. Node 22 satisfies AQE's engine requirement. The presentation +mentions AQE 3.14.1; this container and the updated manual setup use the latest +release instead (3.14.8 at verification on 4 October 2026). + +## GitHub Codespaces + +1. Open the repository → **Code → Codespaces → Create codespace on main**. + Before this PR is merged, select its `codex/workshop-devcontainer` branch. +2. Allow the container build and setup to finish. Select a 4-core machine with + 8 GB RAM if available. Your own GitHub Codespaces allowance/billing applies. +3. In the terminal run: + + ```bash + bash .devcontainer/prepare-workshop.sh + bash .devcontainer/verify.sh + node .devcontainer/verify-mcp.mjs + npm run test:run + ``` + +4. Sign in to your coding agent **inside the container**. Run `claude` for + Claude Code, trust the workspace and approve the `agentic-qe` MCP server. + Codex CLI is also installed: run `aqe init --auto --with-codex` deliberately + if choosing Codex, then `codex login --device-auth`. This configuration step + is manual so a restart cannot overwrite your chosen agent configuration. + Other agents use the matching README setup flag and their own authentication. +5. Open **LAB.md**. The preparation command already performed Exercise 0 and + loaded the six checkout seed patterns; inspect the output as your baseline. + +The first preparation downloads the embedding model. Do this **before arriving**; +neither first-time setup nor agent use is offline. Indexing and embeddings run +inside the container. In Codespaces that means on GitHub's machine; agent +exercises still use your chosen model provider and tokens. + +## DevPod + Docker on your laptop + +Start Docker Desktop (or your Linux Docker daemon), install DevPod, then: + +```bash +git clone https://github.com/fndlalit/HUSTEF-70-Percent-Problem-Tutorial +cd HUSTEF-70-Percent-Problem-Tutorial +# Before merge: git switch codex/workshop-devcontainer +devpod provider add docker # once; skip if already configured +devpod up . --provider docker --id hustef-70-percent +``` + +Run the same preparation, verification and sign-in steps in the new workspace. +The image supports Linux amd64 and arm64 (Apple Silicon uses Linux containers); +there is no forced amd64 emulation. Allow at least 8 GB RAM and 32 GB disk. +Alternatively, open this clone in VS Code and choose **Dev Containers: Reopen +in Container** with the Dev Containers extension installed. + +## Run the subject app + +```bash +npm run dev -- --hostname 0.0.0.0 --port 3000 +``` + +Open port **3000** in the editor's Ports view. In Codespaces keep its visibility +**Private**; its forwarded URL is HTTPS. In local DevPod use the forwarded +localhost address. If port 3000 is already occupied on your laptop, choose a +different local forwarded port. Do not change the app port without updating +the forwarding configuration. + +The catalog, cart, tests, static analysis, and QCSD exercises need **no Stripe +keys**. A real checkout requires your own Stripe **test-mode** publishable and +secret keys in the ignored `.env.local` file (see `.env.example`), or Codespaces +secrets; restart Next.js after setting them. Placeholder keys are not working +credentials. Never use live keys or real card data for this deliberately flawed +app. Without keys the Stripe checkout/payment route is expected to fail; a +green environment check does not claim a completed payment. + +Product images load from an external placeholder host and may be unavailable. +Orders live in process memory; restarting Next.js loses those demo orders. +Kafka is a test abstraction using an injected send function, so no broker, +PostgreSQL, Redis, Rust, or Docker socket is needed in the workspace. + +## What setup changes and preserves + +- The image installs latest AQE, Claude Code, Codex, and GitHub CLI, plus Transformers 4.2.0. + The base Node 22 image receives upstream maintenance updates. +- `post-create.sh` refreshes AQE, Claude Code, Codex, and GitHub CLI to latest even with a cached Docker image, + runs `npm ci` against the committed app lockfile and initializes + AQE only if `.agentic-qe` does not exist. It creates an empty private `.env.local` + only if absent. It never installs dependencies or rewrites memory on resume. +- `prepare-workshop.sh` is an explicit first-run action that indexes `src/`, + warms the embedding model, and imports the seed. After successful verification, + a marker makes subsequent runs a no-op. It creates a timestamped SQLite backup + before these writes and checks integrity afterward. It does not erase existing data. +- `verify.sh` checks tooling, exercise assets, all source files in the graph, + all six seed patterns with embeddings, and the existing database read-only. + Run tests/coverage separately; verification never runs a paid agent exercise. +- Reports and AQE's SQLite database remain in your workspace across restarts. + Back up/export work before deleting a Codespace or DevPod workspace. A model + cached in the container home may need downloading again after a rebuild. + +Transformers is the same explicit local-embedding opt-in described in README, +including its dependency advisory caveat. If your policy forbids it, use manual +setup with a trusted embedding endpoint rather than this default image. + +## Troubleshooting + +- **Incomplete `.agentic-qe`:** setup stops instead of repairing or deleting it. + Ask a facilitator to inspect it. Never delete a learning database to make a + setup check green. +- **Import says `Imported: 0`:** see TROUBLESHOOTING.md. SQLite is authoritative; + verify the actual six seed patterns, not that misleading import counter. +- **Model download fails:** check proxy/network access to npm and Hugging Face, + then rerun preparation. The completion marker is only written after success. +- **Agent signed in on the host only:** container credentials are separate. + Use its login flow, or supply your own provider key as a Codespaces secret. +- **Graph counts differ:** counts can vary with the index pass and configured + providers. Check all 21 source files are indexed; do not treat one total as + proof that every file was included. +- **MCP memory on non-Claude agents:** TROUBLESHOOTING.md describes a limitation + observed on AQE 3.14.1. Do not assume a newer version behaves identically; + verify recall on your chosen agent, and use LAB.md's reports fallback if needed. + On AQE 3.14.8 our isolated MCP handshake exposed 91 tools, but both a glob + query of the graph namespace and a semantic payment-retry query returned zero + entries despite the verified SQLite seed. The MCP smoke check reports this + limitation explicitly; `--require-recall` makes it fail. This is transport + validation, not proof that Exercise 5 can recall your agent's learnings. + +References: [port forwarding in Codespaces](https://docs.github.com/en/codespaces/developing-in-a-codespace/forwarding-ports-in-your-codespace), +[Dev Container configuration](https://containers.dev/implementors/json_reference/). diff --git a/docs/SLIDE-UPDATES-FOR-LALIT.md b/docs/SLIDE-UPDATES-FOR-LALIT.md new file mode 100644 index 0000000..4708753 --- /dev/null +++ b/docs/SLIDE-UPDATES-FOR-LALIT.md @@ -0,0 +1,116 @@ +# Slide update handoff for Lalit + +Deck reviewed: [HUSTEF2026-Agentic-QCSD-Tutorial_4.pptx](https://docs.google.com/presentation/d/1Ee9y8tHL4n8rWdCikyhNwlpWEVxXr6wT/edit). +This note proposes edits; the presentation itself has not been changed. + +## Slide 4 — replace setup instructions + +Change the heading to **“Setup in your workshop workspace”**. Present two paths: + +**Recommended: Codespaces or DevPod + Docker** + +1. Open the tutorial repo in Codespaces, or `devpod up . --provider docker`. +2. Wait for setup, then run `bash .devcontainer/prepare-workshop.sh`. +3. Run `bash .devcontainer/verify.sh` and `npm run test:run`. +4. Sign in to your agent inside the container; trust the workspace and approve AQE MCP. +5. Open `LAB.md` and inspect Exercise 0's prepared baseline. + +Link to `docs/DEVCONTAINER.md` in the tutorial repository. Keep manual setup as +the alternative, but change **`agentic-qe@3.14.1` → `agentic-qe@latest`** and +**“Node 20 or newer / EBADENGINE expected” → “Node 22.13 or newer and npm 10+”**. +Container tooling includes latest AQE, Claude Code CLI, Codex CLI, and GitHub CLI. +The local embedder is installed before the container's seed import. + +Replace “Everything after this runs against your laptop” with: + +> Work in your own workshop workspace. DevPod runs locally through Docker; +> Codespaces runs on GitHub. Agent exercises use your own model access and tokens. + +Speaker note: use a fresh tutorial workspace; never point it at an existing AQE +development checkout or copy over its learning database. On manual setup, +install the embedder and prepare the local baseline before adding provider keys. + +## Slide 5 — distinguish baseline counters and hosting + +Keep **21 files / 102 nodes / 117 edges** as the observed index-command output, +and **21 entries / 102 vectors** as the memory-usage baseline. These were +reproduced with AQE 3.14.8. Replace “the same graph, counted by node type” with: + +> `aqe hg stats` shows the persisted hypergraph separately. Check every source +> file is present; its totals differ from the index command's counters. + +Observed persisted graph: **110 nodes / 89 edges**, with 21 file nodes, 21 module +nodes, and 68 function nodes. Avoid promising those totals across future AQE +releases; the readiness check verifies all source paths instead. + +Replace “Your code never leaves the machine” with: + +> This baseline uses static analysis and local embeddings inside your workspace. +> It needs no provider key. In Codespaces, the workspace is hosted by GitHub. +> Later agent exercises use your selected model provider. + +Speaker note: a container has already prepared Exercise 0. Inspect its output +instead of reinitializing memory. Preparation makes a backup before initial +index/seed writes and does not repeat them after successful completion. + +## Slides 10, 11 and any repeated fleet-count claims + +Remove stale hard-coded **“60 QE agents”** unless we establish which count the +slide means. The fresh AQE 3.14.8 initialization installed **53 `qe-*.md` files** +and **86 skill entrypoints**. These file counts do not prove a runtime fleet size +or the number of agents in a particular swarm. Suggested wording: + +> A specialized QE agent fleet and skills spanning the QCSD lifecycle. + +Keep the phase architecture, but verify per-swarm headcounts against the skills +installed in the latest package before retaining the numerical labels. + +## Slides 18, 21, 23, 25, 27 and 29 — add a setup prerequisite note + +The named agents and the `qcsd-ideation-swarm` and +`exploratory-testing-advanced` skill files were present in the fresh container. +Add a single shared note, or cover it verbally before Exercise 1: + +> Your chosen agent must be signed in inside this workspace. Approve the AQE +> MCP server and verify the skills load before starting the timed exercises. + +Do not imply that host-machine login automatically carries into a container. +Manual configuration flags for other agents remain in README. + +## Slides 32–33 — make the memory fallback explicit + +Keep the instruction to list recalled findings before composing the brief. +Add this fallback box: + +> If AQE memory recall returns no checkout findings, use your saved reports from +> Exercises 1–4. Label the brief **REPORTS-BASED**, and say that memory recall was +> unavailable. Do not present it as evidence that the memory loop succeeded. + +Latest-version evidence: AQE 3.14.8 stored all six seed patterns with +384-dimensional embeddings in SQLite (76 patterns total). Its MCP server +completed a handshake and exposed 91 tools, but the tested graph-namespace and +semantic checkout queries returned **zero entries**. Stored seed data and +successful agent-side recall are separate gates. The container smoke check +prints this limitation; adding `--require-recall` makes that check fail. + +## What can remain as written + +- Slide 29's existing coverage numbers were reproduced: **61.62% overall**; + payment-retry **100% statements / 97.29% branches**. The code's intentional + idempotency and jitter flaws remain available for the exercises. +- The epic, stories, acceptance criteria, output paths, and exercise order are unchanged. +- The catalog, cart, unit tests, and static QCSD work need no Stripe credentials. + Actual payment checkout requires participants' own Stripe **test-mode** keys; + optional app demonstrations should say this before opening checkout. + +## Facilitator preflight before 6 October + +Create a fresh workspace, allow latest tool updates, and run preparation, +readiness, tests, and the MCP smoke check. Record the actual AQE/agent versions +used that day. Test sign-in and one scoped agent exercise with your own account; +the automated container checks deliberately do not spend model tokens. + +Local DevPod/Docker and Dev Container CLI startup were exercised on Apple +Silicon. GitHub Codespaces creation could not be exercised with the available +GitHub token (missing Codespaces scope); confirm the browser-based Codespaces +path from the PR branch before recommending it to the whole room.