From 98b52d3bee41930e75be1b972a2b83ab16a69ba2 Mon Sep 17 00:00:00 2001 From: Dragan Spiridonov Date: Sun, 4 Oct 2026 14:56:46 +0200 Subject: [PATCH 1/2] feat: add latest-tool workshop devcontainer and readiness checks --- .devcontainer/Dockerfile | 29 +++++++ .devcontainer/check-workspace.sh | 13 +++ .devcontainer/devcontainer.json | 28 +++++++ .devcontainer/post-create.sh | 28 +++++++ .devcontainer/prepare-workshop.sh | 30 +++++++ .devcontainer/smoke-app.sh | 26 ++++++ .devcontainer/test-lifecycle.sh | 93 +++++++++++++++++++++ .devcontainer/verify-data.cjs | 27 ++++++ .devcontainer/verify-mcp.mjs | 55 +++++++++++++ .devcontainer/verify.sh | 21 +++++ .github/workflows/devcontainer.yml | 26 ++++++ LAB.md | 2 +- README.md | 10 ++- docs/DEVCONTAINER-VERIFICATION.md | 59 +++++++++++++ docs/DEVCONTAINER.md | 128 +++++++++++++++++++++++++++++ docs/SLIDE-UPDATES-FOR-LALIT.md | 116 ++++++++++++++++++++++++++ 16 files changed, 688 insertions(+), 3 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/check-workspace.sh create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/post-create.sh create mode 100644 .devcontainer/prepare-workshop.sh create mode 100644 .devcontainer/smoke-app.sh create mode 100644 .devcontainer/test-lifecycle.sh create mode 100644 .devcontainer/verify-data.cjs create mode 100644 .devcontainer/verify-mcp.mjs create mode 100644 .devcontainer/verify.sh create mode 100644 .github/workflows/devcontainer.yml create mode 100644 docs/DEVCONTAINER-VERIFICATION.md create mode 100644 docs/DEVCONTAINER.md create mode 100644 docs/SLIDE-UPDATES-FOR-LALIT.md 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..4803741 --- /dev/null +++ b/.github/workflows/devcontainer.yml @@ -0,0 +1,26 @@ +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@v4 + - 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: | + 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..0d047af --- /dev/null +++ b/docs/DEVCONTAINER-VERIFICATION.md @@ -0,0 +1,59 @@ +# 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. + +## 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. From b58620d61328c94e8d64c7b5bd99e73e1131667c Mon Sep 17 00:00:00 2001 From: Dragan Spiridonov Date: Sun, 4 Oct 2026 15:01:31 +0200 Subject: [PATCH 2/2] ci: update checkout and preserve runner credential cleanup --- .github/workflows/devcontainer.yml | 7 ++++++- docs/DEVCONTAINER-VERIFICATION.md | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/devcontainer.yml b/.github/workflows/devcontainer.yml index 4803741..1d01ef2 100644 --- a/.github/workflows/devcontainer.yml +++ b/.github/workflows/devcontainer.yml @@ -11,7 +11,9 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - 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 @@ -20,6 +22,9 @@ jobs: 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 \ diff --git a/docs/DEVCONTAINER-VERIFICATION.md b/docs/DEVCONTAINER-VERIFICATION.md index 0d047af..7ab1cea 100644 --- a/docs/DEVCONTAINER-VERIFICATION.md +++ b/docs/DEVCONTAINER-VERIFICATION.md @@ -24,6 +24,9 @@ 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