Replace Vite/React scaffold with Go build spec
- AGENTS.md: build spec for Paperclip (constraints, conventions, 7 phases) - docs/phase-1..7: per-phase work, DoD, out-of-scope, risks - reference/: frozen decisions, stack+ports+budgets, content map, acceptance tests - agents/: persona and security policy drafts - Retires the React scaffold; history retained as record of the false start
This commit is contained in:
83
docs/phase-1-content-source.md
Normal file
83
docs/phase-1-content-source.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Phase 1 — Content source of truth
|
||||
|
||||
**Goal:** `content/` exists, is schema-valid, and covers all six areas. Both later renderers read from it. No site code yet.
|
||||
|
||||
**Depends on:** nothing. This is the critical path.
|
||||
|
||||
---
|
||||
|
||||
## Inputs
|
||||
|
||||
| Source | Location | What it gives |
|
||||
|---|---|---|
|
||||
| Evidence notes | `../resume_ai_system/plan/EVIDENCE-NOTES.md` | Devices, systems, platforms, AI work, career, interests — **Sam's own words, the authority** |
|
||||
| Recovered content | `../resume_ai_system/plan/draft-content.md` | Client wall, skills, non-IT history, project index |
|
||||
| Content spine | `../resume_ai_system/plan/20-content-spine.md` | Areas, claims, metric chips, metadata schema |
|
||||
| Résumé | `.27:/home/sam/Downloads/resume_2025.docx` + `.../05_documents/*.docx` | 2000–2020 engagements, education |
|
||||
| Old project notes | `../resume_ai_system/old_projects.md` | Code exhibit locations, IoT grouping |
|
||||
| Web archive | `03_projects/web_work/` (read-only) | Code excerpts only where named |
|
||||
|
||||
These paths are outside the repo. **Read them, do not edit them, do not depend on them at build time.** Everything needed must land in `content/`.
|
||||
|
||||
---
|
||||
|
||||
## Work
|
||||
|
||||
1. **Implement the schema** from `AGENTS.md` §7 as a validator (Go or Python — one file, no framework).
|
||||
2. **Create the area structure:**
|
||||
```
|
||||
content/
|
||||
ai/ # harnesses, routing, RAG, voice, guardrails, observability
|
||||
platform/ # NixOS, packaging, docker, network, backups, signage infra
|
||||
edge/ # devices, radio, audio distribution, sensors, failures
|
||||
products/ # Audas Media, WebsiteBuilder, Where-Woof
|
||||
history/ # 2000–2014 client wall and engagements
|
||||
about/ # narrative, non-IT background, education, interests
|
||||
assets/ # diagrams, screenshots, logos — optimised
|
||||
```
|
||||
3. **Author L1 for all six areas** — one screen each: claim, three metric chips, tech chips, one link.
|
||||
4. **Author L2 for three areas in full** — `ai`, `platform`, `edge`. These are the three target roles and the proof that the template works.
|
||||
5. **Author `products` and `history` at L2** — the commercial story and the client wall. These carry disproportionate weight; do not skimp.
|
||||
6. **Author `about` at L2** — narrative, the 2020–2026 framing, non-IT work history, education, interests.
|
||||
7. **Create L3 stubs** for every artefact referenced by an L2 page, even if the artefact lands later. A dangling reference fails validation.
|
||||
8. **Redaction pass:** no family names, no address, no phone unless Sam confirms, no credentials, no personal data.
|
||||
|
||||
---
|
||||
|
||||
## Non-negotiables in content
|
||||
|
||||
- **Confidence labels are set honestly.** `EVIDENCE-NOTES.md` distinguishes finished, in-progress, postponed and failed. Preserve that distinction exactly.
|
||||
- **Numbers must trace to the evidence notes.** The known corrections: **3 businesses currently active** (~12 adopted over time); **Where-Woof deployed, not yet to market**; drop unverified figures like "42 devices" and "800ms end-to-end".
|
||||
- **Failures stay in.** The lizard feeder destroyed by the lizard, the postponed garden cameras, the doorbell being rebuilt. They are evidence of production experience.
|
||||
- **Framing rule** from `AGENTS.md` §7 — capability first, product name second.
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] `content/` validates cleanly against the schema; validator exits non-zero on any violation.
|
||||
- [ ] Six areas exist, each with an L1 entry.
|
||||
- [ ] `ai`, `platform`, `edge`, `products`, `history`, `about` each have an L2 entry.
|
||||
- [ ] Every L2 references only artefacts that exist as L3 stubs.
|
||||
- [ ] Every `metric` value appears in the evidence notes — **no invented numbers**.
|
||||
- [ ] Every entry has a `confidence` and a `last_verified` date.
|
||||
- [ ] The redaction pass is documented (a list of what was excluded and why).
|
||||
- [ ] `git log` shows the content commit; `make validate` (or equivalent) passes.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Rendering. No HTML, no templates, no CSS.
|
||||
- Choosing a logo set — Phase 7.
|
||||
- Writing the persona or security policy — Phase 5/6, drafts exist in `agents/`.
|
||||
|
||||
---
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| Content drifts into invented detail (the historical failure) | Every metric must trace to evidence; the validator enforces a `confidence` field; Sam reviews before Phase 2 signs off |
|
||||
| Over-authoring — 40 pages where 12 suffice | L1 ×6, L2 ×6, L3 stubs only. Depth is added when a specific question demands it |
|
||||
| Schema churn after content is written | Freeze the schema in this phase. Changing it later means re-touching every file — treat it as a breaking change |
|
||||
83
docs/phase-2-static-site.md
Normal file
83
docs/phase-2-static-site.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Phase 2 — Mode A static site
|
||||
|
||||
**Goal:** a fast, browsable, pre-rendered site served by one Go binary, working with every AI service stopped.
|
||||
|
||||
**Depends on:** Phase 1 (content + schema).
|
||||
|
||||
---
|
||||
|
||||
## Work
|
||||
|
||||
### 2.1 Service skeleton
|
||||
- Go module, `net/http` or `chi`, config from environment (no flags-only config).
|
||||
- `/healthz` returning **separate** readiness for static (always) and AI (separate field).
|
||||
- Bind `127.0.0.1:8096`.
|
||||
- Compose file with `mem_limit` = `memswap_limit` = `120m`, log rotation, restart policy.
|
||||
|
||||
### 2.2 Rendering
|
||||
- `templ` components: `Layout`, `Nav`, `PillarCard`, `Stage`, `EvidenceTable`, `CodeBlock`, `Timeline`, `Footer`.
|
||||
- `templ generate` wired into `make build` / `go generate`.
|
||||
- Server-side Markdown (`goldmark`) and code highlighting (`chroma`). **No client-side rendering of content.**
|
||||
- Static pre-render: content → HTML at build time. The binary serves files; it does not render per request for Mode A.
|
||||
|
||||
### 2.3 Navigation and depth
|
||||
- Left nav on desktop, hamburger below 900 px. Six areas from `reference/content-map.md`.
|
||||
- L1 → L2 → L3 drill-down, ≤ 3 clicks from landing to any artefact.
|
||||
- Breadcrumbs. Visible current-location state. Keyboard navigable.
|
||||
|
||||
### 2.4 The stage panel — build it as a **content sink**
|
||||
This is the important design decision. The presentation panel takes content from a **driver**:
|
||||
|
||||
```
|
||||
Stage ← driver(route) // Mode A: HTMX fragment swap
|
||||
Stage ← driver(SSE) // Mode B: streamed response (Phase 5)
|
||||
```
|
||||
|
||||
Build it generic now. If it is built as a page renderer, Phase 5 becomes a rewrite.
|
||||
|
||||
- Panel clears on navigation and on a new AI response.
|
||||
- Panel accepts: text, code block, image, video, diagram, link list.
|
||||
- HTMX handles fragment swaps and the panel-cleared event.
|
||||
|
||||
### 2.5 Search and cache
|
||||
- SQLite + FTS5 over page titles and body text. Keyword search across the static site.
|
||||
- This same FTS5 index is the keyword half of Phase 4's hybrid retrieval. Build it once, here.
|
||||
|
||||
### 2.6 Quality floor
|
||||
- Print stylesheet.
|
||||
- Works with JavaScript disabled (nav degrades to links; search degrades to a form post).
|
||||
- Focus states, contrast, semantic landmarks.
|
||||
- Dark theme by default, matching Sam's existing design language.
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] **A1:** with Qdrant, OmniRoute and any query service stopped, every page renders correctly.
|
||||
- [ ] One binary serves the whole site; no Node, no bundler, no `node_modules` in the repo.
|
||||
- [ ] `templ generate` produces no diff on a clean checkout (build is reproducible).
|
||||
- [ ] L1 (6) and L2 (6) pages complete, L3 stubs reachable in ≤ 3 clicks.
|
||||
- [ ] FTS5 search returns sensible results for "zigbee", "signage", "routing".
|
||||
- [ ] Lighthouse ≥ 95 performance and ≥ 95 accessibility, mobile and desktop.
|
||||
- [ ] First byte < 100 ms over LAN.
|
||||
- [ ] Stage panel renders from a route driver and can be re-pointed at a stream without touching layout code.
|
||||
- [ ] Prints legibly.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Any AI call, embedding, vector store or model integration.
|
||||
- Deployment (Phase 3).
|
||||
- Logos and final diagrams (Phase 7) — use typographic placeholders.
|
||||
|
||||
---
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| `templ` friction mid-build | It is a build-time codegen step, not a framework. If it genuinely blocks, stop and ask — do not silently switch to `html/template` |
|
||||
| Panel built as a page renderer | §2.4 is a design contract. Review this before writing layout code |
|
||||
| Design invented from scratch | Reuse Sam's existing dark surface/type language from the retired `sam-*` sites |
|
||||
| Scope creep into interactivity | If it needs client state beyond the console, it is Phase 5's problem, not Phase 2's |
|
||||
102
docs/phase-3-deploy.md
Normal file
102
docs/phase-3-deploy.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# Phase 3 — Public deployment
|
||||
|
||||
**Goal:** a live URL Sam can send someone. Early, deliberately — not at the end.
|
||||
|
||||
**Depends on:** Phase 2.
|
||||
|
||||
> **Read `AGENTS.md` §4.2 first.** This phase touches a shared host. The Caddy change is **Sam's to apply**, not the agent's.
|
||||
|
||||
---
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|---|---|
|
||||
| Public hostname | `resume.lab.audasmedia.com.au` |
|
||||
| DNS | Wildcard `*.lab.audasmedia.com.au` already resolves publicly — **no DNS work needed** |
|
||||
| TLS | Terminated by Caddy on `.35` |
|
||||
| App port | `8096` on `.13` (verify free; 8095 belongs to `offsite.lab`) |
|
||||
| Release path | `/home/sam/deployment/resume/` |
|
||||
|
||||
---
|
||||
|
||||
## Work
|
||||
|
||||
### 3.1 The release mechanism
|
||||
|
||||
```
|
||||
deploy.sh
|
||||
├─ build + test (fail fast)
|
||||
├─ copy to releases/<timestamp>/
|
||||
├─ flip `current` symlink (atomic)
|
||||
├─ docker compose up -d
|
||||
├─ curl http://127.0.0.1:8096/healthz → must be ready
|
||||
└─ on failure: flip back to `previous`, exit non-zero
|
||||
```
|
||||
|
||||
- `deploy.sh --rollback` restores the previous release in one command.
|
||||
- No agent hand-edits files on a production host. Agents invoke the script or fix the script in git.
|
||||
- Deploy is a **script**, not a model decision. `AGENTS.md` §4.6.
|
||||
|
||||
### 3.2 Container
|
||||
- `mem_limit` = `memswap_limit` = `120m`.
|
||||
- `ports: ["127.0.0.1:8096:8096"]` — never `0.0.0.0`.
|
||||
- `logging` capped (`max-size: 10m`, `max-file: 3`).
|
||||
- `restart: unless-stopped`.
|
||||
|
||||
### 3.3 Caddy — **produce the diff, Sam applies it**
|
||||
|
||||
Agent output is the exact block to add to `.35`'s Caddyfile, plus the reload command. Do not apply it.
|
||||
|
||||
```caddy
|
||||
resume.lab.audasmedia.com.au {
|
||||
encode zstd gzip
|
||||
reverse_proxy 192.168.20.13:8096
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||
X-Content-Type-Options "nosniff"
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
X-Frame-Options "SAMEORIGIN"
|
||||
Content-Security-Policy "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'"
|
||||
}
|
||||
@static path *.css *.js *.svg *.png *.jpg *.webp *.woff2
|
||||
header @static Cache-Control "public, max-age=31536000, immutable"
|
||||
}
|
||||
```
|
||||
|
||||
Apply with `caddy reload` (not restart). Verify the other hostnames still resolve afterwards.
|
||||
|
||||
### 3.4 Repo visibility
|
||||
Repo stays private through this phase. Sam decides on public visibility after the URL is verified.
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] `deploy.sh` and `deploy.sh --rollback` both work; a deliberate bad build proves rollback.
|
||||
- [ ] `https://resume.lab.audasmedia.com.au` serves the site.
|
||||
- [ ] Container bound to `127.0.0.1` only; confirmed with `ss -ltn`.
|
||||
- [ ] `memswap_limit == mem_limit`; confirmed with `docker inspect`.
|
||||
- [ ] Security headers present; CSP does not break the page.
|
||||
- [ ] A1 still passes over the public URL with the AI layer stopped.
|
||||
- [ ] Sam has applied the Caddy block and confirmed the other lab hostnames still work.
|
||||
- [ ] Rollback rehearsed once and documented.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Rate limiting for the AI endpoint (Phase 6).
|
||||
- Monitoring, alerting, restore drills — add a minimal uptime check only.
|
||||
- Any change to other sites, containers or the NixOS config.
|
||||
|
||||
---
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| Caddy change breaks another site | Additive block only; `caddy reload` not restart; Sam verifies the other hostnames immediately after |
|
||||
| Deploying a half-finished build | `deploy.sh` health gate + rollback; the site is designed to be useful at every stage |
|
||||
| Port 8096 occupied | Verify before compose; pick the next free port and record it in `reference/stack.md` |
|
||||
| Host memory pressure | 120 m cap; the app is static-serving and should idle well under it. Measure and record actual RSS |
|
||||
81
docs/phase-4-corpus.md
Normal file
81
docs/phase-4-corpus.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Phase 4 — Corpus and retrieval
|
||||
|
||||
**Goal:** `content/` becomes a retrievable corpus with filters that work before the vector search, and a freshness audit that cannot silently rot.
|
||||
|
||||
**Depends on:** Phase 1 (content), Phase 2 (FTS5 index exists).
|
||||
|
||||
---
|
||||
|
||||
## Work
|
||||
|
||||
### 4.1 Pipeline
|
||||
|
||||
```
|
||||
content/ ──► validate ──► chunk ──► enrich ──► embed ──► upsert Qdrant
|
||||
│
|
||||
SQLite FTS5 (from Phase 2) ┘
|
||||
```
|
||||
|
||||
- **Chunking:** 400–800 tokens, ~12% overlap, **code-aware** — never split inside a fenced block, table or front-matter.
|
||||
- **Deterministic IDs:** `sha256(source_path + chunk_index + content_hash)`. Re-running must update, not duplicate.
|
||||
- **Incremental:** hash the source set; only changed documents are re-chunked and re-embedded.
|
||||
- **One command** rebuilds from scratch. Deleting the Qdrant volume is always recoverable.
|
||||
|
||||
### 4.2 Payload schema (the retrieval filter)
|
||||
|
||||
```json
|
||||
{
|
||||
"area": "ai|platform|edge|products|history|about",
|
||||
"level": 1,
|
||||
"source_type": "doc|code|adr|metric",
|
||||
"confidence": "delivered|running|in-progress|abandoned|historic",
|
||||
"period": "2023–",
|
||||
"artefacts": ["..."],
|
||||
"last_verified": "2026-10-20",
|
||||
"text": "..."
|
||||
}
|
||||
```
|
||||
|
||||
`area` and `confidence` are the two that matter: they let the query path filter *before* searching, and they let the answer qualify unfinished work.
|
||||
|
||||
### 4.3 Embeddings
|
||||
- Batch, low volume, incremental.
|
||||
- **Record the embedding model and dimension per collection.** A provider change is a governed migration, not a silent corruption.
|
||||
- Provider decision pending Sam — see `reference/stack.md`. Build provider-agnostic behind one interface.
|
||||
|
||||
### 4.4 Scheduling
|
||||
- Prefect deployment on the existing Prefect server; **worker only**, do not deploy a second server.
|
||||
- Trigger: git push to `content/`, plus a nightly audit.
|
||||
- Nightly audit reports documents past their `last_verified` horizon and alerts via the existing Apprise service.
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] One command rebuilds the corpus from an empty volume.
|
||||
- [ ] Running it twice produces no duplicate vectors (count is stable).
|
||||
- [ ] No chunk boundary lands inside a code fence, table or front-matter block.
|
||||
- [ ] Every chunk carries all payload fields; a missing field fails the run rather than defaulting.
|
||||
- [ ] Payload filtering demonstrably narrows results — demonstrate the same query with and without an `area` filter.
|
||||
- [ ] Incremental mode re-embeds only changed documents; prove it with the provider call count.
|
||||
- [ ] Freshness audit runs and reports stale documents.
|
||||
- [ ] Qdrant memory measured at 500 / 5,000 / 20,000 chunks and recorded in `reference/stack.md`, within its cap.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Answering questions. Phase 4 ends at "retrieval returns the right chunks".
|
||||
- Query graphs, prompts, guardrails — Phase 5 and 6.
|
||||
- Ingesting anything outside `content/`. Four sources maximum, and this phase uses one: the repo.
|
||||
|
||||
---
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| Corpus grows beyond RAM | Incremental by default; measure at three corpus sizes; cap Qdrant with `mem_limit` |
|
||||
| Duplicate vectors on re-run | Deterministic IDs are mandatory, not optional |
|
||||
| Silent staleness | Nightly audit + Apprise alert; a stale index is otherwise an invisible quality failure |
|
||||
| Provider rate limits during bulk embed | Batch with retry/backoff; ingest is low-volume and incremental |
|
||||
82
docs/phase-5-ai-overlay.md
Normal file
82
docs/phase-5-ai-overlay.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Phase 5 — Mode B console (the AI overlay)
|
||||
|
||||
**Goal:** a prompt box that streams a short, cited answer and can take over the stage panel. The AI is a second driver for the same panel, not a second site.
|
||||
|
||||
**Depends on:** Phase 3 (live URL), Phase 4 (corpus).
|
||||
|
||||
---
|
||||
|
||||
## Work
|
||||
|
||||
### 5.1 Query path
|
||||
|
||||
```
|
||||
question
|
||||
→ rate limit (per IP)
|
||||
→ CLASSIFY fast tier intent · injection score · off-topic · PII
|
||||
├─ refuse → fixed message, zero model spend
|
||||
└─ allow
|
||||
→ ROUTE fast tier which area(s) to search
|
||||
→ RETRIEVE Qdrant (payload-filtered) + SQLite FTS5
|
||||
→ reciprocal rank fusion → cross-encoder rerank top-20 → top-5
|
||||
→ COMPOSE mid tier answer ONLY from context, inline citations
|
||||
→ VERIFY citation presence + claim supported by context
|
||||
→ STREAM SSE
|
||||
```
|
||||
|
||||
Four nodes. If the graph needs more than four to work, stop and report — complexity growth here is the failure mode this project exists to avoid.
|
||||
|
||||
### 5.2 Transport
|
||||
- `GET /api/ask` as Server-Sent Events.
|
||||
- Three event types: `token`, `meta` (route, timings, tokens, cost), `done`.
|
||||
- **Never buffer SSE.** Verify with `flush_interval -1` on the proxy if streams stall. No gzip on the API path.
|
||||
|
||||
### 5.3 The console (the only client-side code in the project)
|
||||
One hand-written TypeScript island, ES modules, no framework, no bundler.
|
||||
|
||||
- `xterm.js` console showing the pipeline live: route, retrieval count, timings, tokens, cost.
|
||||
- Prompt box with submit and stop.
|
||||
- Stage panel driven by the `token` stream — the driver built in Phase 2 §2.4.
|
||||
- Panel clears on new response and on navigation.
|
||||
- Footer strip: model · latency · tokens · cost.
|
||||
|
||||
### 5.4 Citations
|
||||
- Every factual claim carries a citation to a `content/` page or artefact.
|
||||
- Citation URLs validated against the known-artefact allow-list; unknown URLs dropped, not rendered.
|
||||
- Answer shape: direct answer → specifics → evidence pointer → optional single suggestion (per `agents/persona.md`).
|
||||
|
||||
### 5.5 Persona
|
||||
- Load `agents/persona.md` at runtime. It is a file, versioned, not a string in code.
|
||||
- Test the tone: a short answer, an honest "not in the corpus" answer, and a "here's the better example for your role" answer.
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] First token < 4 s; complete answer < 15 s at p90, measured and recorded.
|
||||
- [ ] Every claim in ten sample answers resolves to a real page or artefact. No dangling citations.
|
||||
- [ ] The panel is driven by the SSE stream without changes to layout code (proves Phase 2 §2.4 held).
|
||||
- [ ] The island is the **only** client-side application code; no framework, no bundler, no `node_modules`.
|
||||
- [ ] A and B do not drift: for any question, the answer's claims exist on the site.
|
||||
- [ ] SSE streams untruncated at p90 with no cancellation leak when the client disconnects.
|
||||
- [ ] All model calls go through OmniRoute; grep proves no direct provider call exists.
|
||||
- [ ] Asking an off-topic question produces a short refusal and costs nothing.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Guardrail hardening, cost ceilings and the kill switch — **Phase 6**. Phase 5 runs with a permissive guard and no public traffic.
|
||||
- Voice input.
|
||||
- Hub `/ask` registration (a follow-on task, not this phase).
|
||||
|
||||
---
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| Graph grows past four nodes | Hard review gate: report and justify before adding a fifth |
|
||||
| Panel refactor needed | Phase 2 §2.4 contract; if it fails, fix the panel contract, do not fork the UI |
|
||||
| Streaming stalls behind Caddy | Explicit flush settings; p90 measurement, not a spot check |
|
||||
| Answers drift from the site | Citation verification is a node, not a hope |
|
||||
82
docs/phase-6-guardrails.md
Normal file
82
docs/phase-6-guardrails.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Phase 6 — Guardrails, cost and kill switch
|
||||
|
||||
**Goal:** safe to leave running in public. This is a **release gate**, not a follow-up.
|
||||
|
||||
**Depends on:** Phase 5.
|
||||
|
||||
**Policy source:** `agents/security.md` (authoritative) and `agents/persona.md`. Both are runtime files, versioned in this repo.
|
||||
|
||||
---
|
||||
|
||||
## Work
|
||||
|
||||
### 6.1 any-guardrail is the mechanism
|
||||
|
||||
Input and output validation is performed by **[`mozilla-ai/any-guardrail`](https://github.com/mozilla-ai/any-guardrail)**, pinned to an exact version.
|
||||
|
||||
- **Inbound:** prompt injection · jailbreak · scope violation · personal-data requests · system-prompt extraction.
|
||||
- **Outbound:** policy violation · disclosure of persona/security files · personal or infrastructure detail · claims outside the corpus.
|
||||
- **Fail closed.** Error, timeout or ambiguous verdict ⇒ refuse.
|
||||
- Rules live in this repo, not in library defaults.
|
||||
- **If a rule cannot be enforced with this library, report it — do not quietly drop the rule.**
|
||||
|
||||
### 6.2 The architectural guardrail
|
||||
|
||||
The public agent has **no tools**: no shell, no filesystem, no network fetch, no write path, no memory between visitors. This removes tool abuse, SSRF, exfiltration-by-callback and cross-visitor poisoning as attack classes rather than defending them. Add an assertion to the test suite that no tool or function definitions are registered.
|
||||
|
||||
### 6.3 Output safety
|
||||
- Model output never reaches the DOM as raw HTML; strict allow-list.
|
||||
- Citation URLs allow-listed.
|
||||
- Canary string in the system prompt; any appearance ⇒ discard answer, log incident, terminate session.
|
||||
|
||||
### 6.4 Cost and abuse
|
||||
|
||||
| Control | Value | Enforced at |
|
||||
|---|---|---|
|
||||
| Requests per IP | 10/min · 100/day | Caddy + app |
|
||||
| Questions per session | 20 | App |
|
||||
| Max output tokens | 600 | Request + gateway |
|
||||
| Monthly ceiling | hard stop, alert at 60% | **OmniRoute** |
|
||||
| Kill switch | Mode B off, Mode A unaffected | App config |
|
||||
|
||||
Refusals state that the visitor is rate-limited. Never silently drop a request.
|
||||
|
||||
### 6.5 Red team — **release gate**
|
||||
|
||||
Build and run a payload suite of **≥ 25** attacks, including **≥ 5 indirect** (malicious instructions embedded in ingested content):
|
||||
|
||||
- direct injection · persona override · system-prompt extraction · roleplay jailbreaks · encoding tricks · cost-exhaustion loops · citation forgery · off-topic misuse
|
||||
- and specifically: **overstate Sam's experience** and **ask about a technology not in the corpus**
|
||||
|
||||
Pass = 0 disclosures, 0 bypasses, 0 unbounded-cost responses. The honesty payloads must produce a refusal and an honest alternative, not a hedge.
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] All four guards (limits, classify, retrieve, compose/sanitise) individually testable and fail closed.
|
||||
- [ ] ≥ 25 payloads executed; results tabulated with actual responses; 0 bypasses.
|
||||
- [ ] ≥ 5 indirect injections from inside ingested content; untrusted-data framing holds.
|
||||
- [ ] Canary detected test passes.
|
||||
- [ ] Monthly ceiling demonstrably enforced — a deliberate over-budget request is refused.
|
||||
- [ ] Kill switch stops Mode B and **leaves Mode A fully working** (re-verify A1).
|
||||
- [ ] Test proves the agent has no tool definitions.
|
||||
- [ ] `agents/persona.md` and `agents/security.md` loaded at runtime, not inlined in code.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Changing any existing system's guardrails or limits.
|
||||
- Voice input, if not yet added.
|
||||
|
||||
---
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| Prompt-only defence | Architecture first (no tools), classification second, prompt third |
|
||||
| "Just for testing" cap removal on a live endpoint | Any change to a cap or guard requires Sam's approval, recorded |
|
||||
| Red team run after launch | This phase **is** the release gate; nothing goes public without it |
|
||||
| Guardrail makes the demo timid | Publish the security design and the passing results as site content — "25 payloads, 0 bypasses" is a stronger claim than an unprotected demo |
|
||||
74
docs/phase-7-polish.md
Normal file
74
docs/phase-7-polish.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Phase 7 — Polish
|
||||
|
||||
**Goal:** make it look like it was made by someone with a design degree. Nothing here blocks launch.
|
||||
|
||||
**Depends on:** Phase 3. Can run in parallel with 4–6.
|
||||
|
||||
---
|
||||
|
||||
## Work
|
||||
|
||||
### 7.1 Logos — wordmark wall, not a logo collage
|
||||
|
||||
Audit result (tested against Simple Icons):
|
||||
|
||||
**Available:** McDonald's · Accenture · Bank of America · PlayStation · HSBC · DHL · Shell · Channel 4 · Autodesk (AutoCAD) · Pearson
|
||||
|
||||
**Not available, and won't be:** BBC · Reuters · KPMG · Ogilvy · Diageo · Volvic · Penguin · Stella Artois · Baileys · Carlton Draught · Cottees · Parkgate Homes · all agencies. **AWS and OpenAI have been removed from Simple Icons** (trademark policy).
|
||||
|
||||
**Decision:** render the 46 client names as a **typographic wall** — same typeface, same size, even grid — with real SVG marks only where they exist. It looks deliberate rather than broken, and it sets cleanly beside a technical site.
|
||||
|
||||
**Own brands** (Audas Media, Where-Woof, WebsiteBuilder) need their own marks — ask Sam whether they exist before inventing any.
|
||||
|
||||
### 7.2 Diagrams
|
||||
Eight, one visual language, light and dark variants, SVG:
|
||||
|
||||
1. Homelab topology — hosts, roles, trust boundaries
|
||||
2. Agent architecture — Hub, OmniRoute, Paperclip, peers, `/ask`
|
||||
3. RAG pipeline — ingest and query side by side
|
||||
4. Edge architecture — devices → MQTT → automation → actuation
|
||||
5. Distributed audio — sources → Snapcast → endpoints → voice injection
|
||||
6. Media pipeline — download → fingerprint → audit → review → library
|
||||
7. Cost/resource engineering — the memory budget, measured
|
||||
8. Era timeline — Flash → PHP → React → server-driven → AI (2000–2026)
|
||||
|
||||
### 7.3 Code exhibits — six, ~40 lines each
|
||||
|
||||
| # | Era | Source | Shows |
|
||||
|---|---|---|---|
|
||||
| 1 | AS3 OO | `Carlton_Draught/src/thebeer/` or Brief Case Builder | class, imports, encapsulation |
|
||||
| 2 | Custom JS engine | `text_effects.js` (2,156 lines) | easing + timeline core |
|
||||
| 3 | PHP media pipeline | `setMediaEncoder.php` (3,402 lines) | one encode op + FFmpeg piping |
|
||||
| 4 | TypeScript | `CAR_GPS_REACT` Prisma + tRPC router | types, interfaces, service layer |
|
||||
| 5 | Embedded C++ | `WiFiMgr.hpp` / `.cpp` | interface vs implementation |
|
||||
| 6 | Declarative infra | `/etc/nixos/pkgs/tuios.nix` (25 lines) | whole file: fetchurl + hash, override rationale, removal condition |
|
||||
|
||||
Source files live in the archive — read-only, copy excerpts into `content/assets/code/`, never link to the archive.
|
||||
|
||||
Each exhibit gets two sentences on **why it is good code**, not what it does.
|
||||
|
||||
### 7.4 Screenshots and recordings
|
||||
- TUIOS fleet running the actual build — 30–60 s, real work, not staged.
|
||||
- The agent console in operation.
|
||||
- Home Assistant and Snapcast, if a still adds something a diagram doesn't.
|
||||
|
||||
### 7.5 Optional: voice input
|
||||
Whisper STT already runs on `.13`. Microphone button → transcription → normal query path. **Voice input is untrusted input** and passes through the same guard unchanged. Voice *output* is out of scope.
|
||||
|
||||
---
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- [ ] Client wall reads as deliberate: consistent grid, no broken images, no empty placeholders.
|
||||
- [ ] Eight diagrams present, both themes, readable at 1× and on mobile.
|
||||
- [ ] Six code exhibits with a two-sentence rationale each.
|
||||
- [ ] Every image optimised; total page weight budgeted and recorded.
|
||||
- [ ] Lighthouse scores held at ≥ 95 / ≥ 95 after assets are added.
|
||||
- [ ] Archive never linked or exposed from the public site.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Any change to a running system.
|
||||
- Video production beyond screen recordings.
|
||||
Reference in New Issue
Block a user