Update README.md #597
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Smoke Test | |
| on: [push, pull_request] | |
| jobs: | |
| smoke-test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| # 1. Bootstrap a real project from scratch | |
| - name: "Bootstrap: create project via root wrapper" | |
| run: python3 scripts/bootstrap_knowledge_system.py /tmp/smoke-project "Smoke Test Project" | |
| - name: "Bootstrap: verify 33 files created" | |
| run: | | |
| COUNT=$(find /tmp/smoke-project -type f | wc -l) | |
| echo "Files created: $COUNT" | |
| [ "$COUNT" -eq 33 ] || { echo "FAIL: expected 33 files, got $COUNT"; exit 1; } | |
| # 2. Run ALL validation scripts on the bootstrapped project | |
| - name: "Validate: wiki_check.py" | |
| run: cd /tmp/smoke-project && python3 scripts/wiki_check.py | |
| - name: "Validate: raw_manifest_check.py" | |
| run: cd /tmp/smoke-project && python3 scripts/raw_manifest_check.py | |
| - name: "Validate: untracked_raw_check.py" | |
| run: cd /tmp/smoke-project && python3 scripts/untracked_raw_check.py | |
| - name: "Ingest: register raw files into manifest and lock" | |
| run: | | |
| mkdir -p /tmp/smoke-raw/inbox /tmp/smoke-raw/customer_answers | |
| printf 'sku,price\nA,10\n' > /tmp/smoke-raw/inbox/spec_matrix.csv | |
| python3 - <<'PY' | |
| from pathlib import Path | |
| import zipfile | |
| path = Path("/tmp/smoke-raw/customer_answers/sample_bundle.zip") | |
| with zipfile.ZipFile(path, "w") as zf: | |
| zf.writestr("note.txt", "hello") | |
| PY | |
| cd /tmp/smoke-project && PROJECT_RAW_ROOT=/tmp/smoke-raw python3 scripts/ingest_raw.py | |
| grep -q "spec_matrix.csv" /tmp/smoke-project/manifests/raw_sources.csv || { echo "FAIL: ingest did not register csv"; exit 1; } | |
| [ -f /tmp/smoke-project/manifests/raw_index.json ] || { echo "FAIL: missing raw_index.json"; exit 1; } | |
| [ -f /tmp/smoke-project/manifests/intake_report.md ] || { echo "FAIL: missing intake_report.md"; exit 1; } | |
| python3 - <<'PY' | |
| import json | |
| from pathlib import Path | |
| lock = json.loads(Path("/tmp/smoke-project/manifests/raw_index.json").read_text()) | |
| summary = lock.get("summary") or {} | |
| assert summary.get("tracked_files") == 2, summary | |
| assert summary.get("new") == 2, summary | |
| assert "inbox/spec_matrix.csv" in lock.get("files", {}), lock | |
| PY | |
| - name: "Stale report: fresh page passes" | |
| run: | | |
| python3 - <<'PY' | |
| import json | |
| from pathlib import Path | |
| project = Path("/tmp/smoke-project") | |
| lock = json.loads((project / "manifests" / "raw_index.json").read_text()) | |
| rel = "inbox/spec_matrix.csv" | |
| meta = lock["files"][rel] | |
| page = project / "docs" / "wiki" / "intake-check.md" | |
| page.write_text( | |
| f"---\n" | |
| f"title: Intake Check\n" | |
| f"source: {meta['source_id']}\n" | |
| f"source_hash: {meta['content_hash']}\n" | |
| f"compiled_at: 2026-04-07T00:00:00+00:00\n" | |
| f"compiled_from: [{meta['source_id']}]\n" | |
| f"created: 2026-04-07\n" | |
| f"status: current\n" | |
| f"---\n\n" | |
| f"# Intake Check\n\n" | |
| f"Tracks {rel}.\n", | |
| encoding="utf-8", | |
| ) | |
| index = project / "docs" / "wiki" / "index.md" | |
| index.write_text(index.read_text(encoding="utf-8") + "- [intake-check.md](./intake-check.md)\n", encoding="utf-8") | |
| PY | |
| cd /tmp/smoke-project && PROJECT_RAW_ROOT=/tmp/smoke-raw python3 scripts/stale_report.py | |
| - name: "Stale report: source change gets caught" | |
| run: | | |
| printf 'B,11\n' >> /tmp/smoke-raw/inbox/spec_matrix.csv | |
| cd /tmp/smoke-project && PROJECT_RAW_ROOT=/tmp/smoke-raw python3 scripts/stale_report.py 2>&1 && exit 1 || echo "PASS: stale source caught" | |
| - name: "Delta compile: writes manual draft stubs" | |
| run: | | |
| cd /tmp/smoke-project && PROJECT_RAW_ROOT=/tmp/smoke-raw python3 scripts/delta_compile.py --write-drafts | |
| [ -f /tmp/smoke-project/manifests/delta_compile_report.md ] || { echo "FAIL: missing delta compile report"; exit 1; } | |
| DRAFT=$(find /tmp/smoke-project/docs/wiki/drafts -type f -name '*.md' | head -n 1) | |
| [ -n "$DRAFT" ] || { echo "FAIL: missing delta draft"; exit 1; } | |
| grep -q "compiled_at:" "$DRAFT" || { echo "FAIL: draft missing compiled_at"; exit 1; } | |
| grep -q "compiled_from:" "$DRAFT" || { echo "FAIL: draft missing compiled_from"; exit 1; } | |
| # 3. Test frontmatter validation catches missing frontmatter | |
| - name: "Validate: frontmatter enforcement" | |
| run: | | |
| echo "# Page without frontmatter" > /tmp/smoke-project/docs/wiki/bad-page.md | |
| echo "- [bad-page.md](./bad-page.md)" >> /tmp/smoke-project/docs/wiki/index.md | |
| cd /tmp/smoke-project && python3 scripts/wiki_check.py 2>&1 && exit 1 || echo "PASS: missing frontmatter caught" | |
| # 4. Test untracked raw detection catches orphan files | |
| - name: "Validate: untracked file detection" | |
| run: | | |
| touch /tmp/smoke-project/stray_report.pdf | |
| cd /tmp/smoke-project && python3 scripts/untracked_raw_check.py 2>&1 && exit 1 || echo "PASS: untracked PDF caught" | |
| # 5. Test --dry-run creates nothing | |
| - name: "Dry-run: verify no files written" | |
| run: | | |
| python3 scripts/bootstrap_knowledge_system.py /tmp/dry-test "Dry Test" --dry-run | |
| [ ! -d /tmp/dry-test ] || { echo "FAIL: dry-run created directory"; exit 1; } | |
| echo "PASS: dry-run wrote nothing" | |
| # 6. Test --force overwrites existing | |
| - name: "Force: verify overwrite works" | |
| run: | | |
| python3 scripts/bootstrap_knowledge_system.py /tmp/force-project "Force Test Project" | |
| echo "original" > /tmp/force-project/AGENTS.md | |
| python3 scripts/bootstrap_knowledge_system.py /tmp/force-project "Force Test Project" --force | |
| grep -q "wiki-first" /tmp/force-project/AGENTS.md || { echo "FAIL: force did not overwrite"; exit 1; } | |
| echo "PASS: --force overwrote existing file" | |
| # 7. Test provenance hash script | |
| - name: "Provenance: stale hash gets caught" | |
| run: | | |
| cd /tmp/smoke-project && PROJECT_RAW_ROOT=/tmp/smoke-raw python3 scripts/provenance_check.py 2>&1 && exit 1 || echo "PASS: stale source hash caught" | |
| - name: "Provenance: unresolved source fails loudly" | |
| run: | | |
| python3 - <<'PY' | |
| from pathlib import Path | |
| project = Path("/tmp/smoke-project") | |
| page = project / "docs" / "wiki" / "unresolved.md" | |
| page.write_text( | |
| "---\n" | |
| "title: Unresolved\n" | |
| "source: src_missing\n" | |
| "source_hash: deadbeefdeadbeef\n" | |
| "created: 2026-04-07\n" | |
| "status: draft\n" | |
| "---\n\n" | |
| "# Unresolved\n", | |
| encoding="utf-8", | |
| ) | |
| index = project / "docs" / "wiki" / "index.md" | |
| index.write_text(index.read_text(encoding="utf-8") + "- [unresolved.md](./unresolved.md)\n", encoding="utf-8") | |
| PY | |
| cd /tmp/smoke-project && PROJECT_RAW_ROOT=/tmp/smoke-raw python3 scripts/provenance_check.py 2>&1 && exit 1 || echo "PASS: unresolved source caught" | |
| # 8. Verify all platform configs generated | |
| - name: "Platform configs: all 4 present" | |
| run: | | |
| for f in AGENTS.md CLAUDE.md .cursorrules .windsurfrules; do | |
| [ -f "/tmp/smoke-project/$f" ] || { echo "FAIL: missing $f"; exit 1; } | |
| done | |
| echo "PASS: all 4 platform configs present" | |
| # 10. Verify demo project structure | |
| - name: "Demo: validate example project" | |
| run: | | |
| for f in CLAUDE.md AGENTS.md .cursorrules .windsurfrules; do | |
| [ -f "examples/demo-project/$f" ] || { echo "FAIL: demo missing $f"; exit 1; } | |
| done | |
| [ -f "examples/demo-project/docs/wiki/index.md" ] || { echo "FAIL: demo missing wiki"; exit 1; } | |
| [ -f "examples/demo-project/manifests/raw_sources.csv" ] || { echo "FAIL: demo missing manifest"; exit 1; } | |
| echo "PASS: demo project complete" |