From 61ddce808f28520aa685930ecec82d611cbb9152 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 15:59:26 +1000 Subject: [PATCH] Split the root: spec/ for the design, status/ for the as-built The root held five documents of two different kinds with nothing to tell them apart. This repo is being handed over as both design spec and as-built record, so the two are now separated by lifetime: spec/ BUILD-AI-CONTAINERS.md, YAU_Linux_Host_Onboarding.md normative and durable - what we agreed to build status/ workflow-map.html, current-state.html, REQUESTS.md snapshots that go stale and get edited constantly Nothing mechanical moved. The twelve code folders are deployment interface - compose builds from /home/azureuser/ai/api, /web, /ingest and deploy.sh copies from $HOME/ai/compose, /cube/model, /db - so they stay where they are. CLAUDE.md stays at root because Claude Code loads it from there, as do .gitignore and .gitattributes, which only apply repo-wide from the root. All 26 references to the build spec were bare filenames in prose, so the move broke no mechanism. The seven markdown links in README.md and the two pointers at the top of CLAUDE.md are repointed. docs/ is deleted. It only ever held .gitkeep - nothing mounted or read it, and ingest reads the host path /datadisk/ai-docs mounted at /docs inside the container. An empty docs/ invites the misreading "project documentation goes here". The ignore rule stays, now covering the whole folder, so a controlled document dropped there still cannot be committed. Co-Authored-By: Claude Opus 5 --- .gitignore | 9 ++++-- CLAUDE.md | 4 +-- README.md | 28 +++++++++++-------- docs/.gitkeep | 0 .../BUILD-AI-CONTAINERS.md | 2 +- .../YAU_Linux_Host_Onboarding.md | 0 REQUESTS.md => status/REQUESTS.md | 0 .../current-state.html | 0 workflow-map.html => status/workflow-map.html | 0 9 files changed, 26 insertions(+), 17 deletions(-) delete mode 100644 docs/.gitkeep rename BUILD-AI-CONTAINERS.md => spec/BUILD-AI-CONTAINERS.md (99%) rename YAU_Linux_Host_Onboarding.md => spec/YAU_Linux_Host_Onboarding.md (100%) rename REQUESTS.md => status/REQUESTS.md (100%) rename current-state.html => status/current-state.html (100%) rename workflow-map.html => status/workflow-map.html (100%) diff --git a/.gitignore b/.gitignore index ab097de..3eb9ec4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,9 +11,12 @@ authelia.env pg-ai.env api.env -# Real document content lives on /datadisk/ai-docs on lin001 -docs/* -!docs/.gitkeep +# Real document content lives on /datadisk/ai-docs on lin001, never in Git. +# The folder itself was removed deliberately - an empty docs/ reads as "project +# documentation goes here", which is wrong: that is spec/ and status/. The rule +# stays as a safety net, so a controlled document dropped into a local docs/ +# cannot be committed by accident. +docs/ # Python __pycache__/ diff --git a/CLAUDE.md b/CLAUDE.md index 6404a3c..00f9957 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,8 +1,8 @@ # CLAUDE.md — rules to keep front of mind Plant Operations Assistant for the **Waterloo Road Pump Station (WRPS)**, deployed onto an -existing, live, shared Docker host. Full detail: `BUILD-AI-CONTAINERS.md` (the build spec) and -`YAU_Linux_Host_Onboarding.md` (the host brief). **Where the two conflict, the host brief wins.** +existing, live, shared Docker host. Full detail: `spec/BUILD-AI-CONTAINERS.md` (the build spec) and +`spec/YAU_Linux_Host_Onboarding.md` (the host brief). **Where the two conflict, the host brief wins.** ## The three lines this system does not cross diff --git a/README.md b/README.md index e4eb3df..833baf3 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ returning. A response that fails its contract is regenerated once, then errors. It is never returned. `pytest api/tests` exercises every rule above without an API key or a database, because that is the point of putting them in Python. -Full detail: [`BUILD-AI-CONTAINERS.md`](BUILD-AI-CONTAINERS.md) §2. +Full detail: [`BUILD-AI-CONTAINERS.md`](spec/BUILD-AI-CONTAINERS.md) §2. --- @@ -96,7 +96,7 @@ operator ──► Caddy ──► Authelia (AD + Duo) ──► ai-web ── Everything runs on `yau-sls-poc-lin001` (`10.0.0.17`), a **shared, live** Docker host that already runs 22 containers including `openplc-runtime` — the PLC for -this demo. See [`YAU_Linux_Host_Onboarding.md`](YAU_Linux_Host_Onboarding.md). +this demo. See [`YAU_Linux_Host_Onboarding.md`](spec/YAU_Linux_Host_Onboarding.md). **There is no replication job and no mirror table.** `imh` is already an isolated copy of the raw SCADA historian, so Cube queries it directly with a @@ -233,7 +233,7 @@ Two consequences worth knowing before you read a number off this system: history carries no equipment column, because CI Server's section tree stops at the station and the three pumps and has no wet well to put there. -Full detail in [`BUILD-AI-CONTAINERS.md`](BUILD-AI-CONTAINERS.md) Phase 4, +Full detail in [`BUILD-AI-CONTAINERS.md`](spec/BUILD-AI-CONTAINERS.md) Phase 4, "Resolved 2026-08-31". Eval cases `H26`, `H27` and `H31` cover them, and `H29` covers the retention limit. @@ -263,7 +263,7 @@ should reach the assistant at all. Read this before relying on it. It is an **IP allowlist on a flat network with no OT/IT boundary**: anything that can take `10.0.0.21` inherits unauthenticated access. It is a demo affordance, not a security control, and it is listed as -such in [`BUILD-AI-CONTAINERS.md`](BUILD-AI-CONTAINERS.md) §14. It also makes +such in [`BUILD-AI-CONTAINERS.md`](spec/BUILD-AI-CONTAINERS.md) §14. It also makes Langfuse traces anonymous — there is no longer a record of who asked what — and it puts the assistant out of browser reach over the VPN, so engineers need an SSH tunnel. `api.yokogawa.tech` is unchanged and still fully gated; Phase 9 @@ -316,7 +316,7 @@ password, so anyone who reaches the page can claim it. Rows are marked authenticated ones later. And **the two ingest paths must not be used on the same document** — files published through the UI stay in the inbox and `ai-ingest --all` cannot see them. Full list of divergences in -[`BUILD-AI-CONTAINERS.md`](BUILD-AI-CONTAINERS.md) §14. +[`BUILD-AI-CONTAINERS.md`](spec/BUILD-AI-CONTAINERS.md) §14. The design below is what §16 specifies, and remains the target. @@ -366,7 +366,7 @@ Then the manual steps: the `copy_headers` change on the `api.yokogawa.tech` Caddy block, the `^/docs/.*` Authelia rule **above** the general one, and `AI_DocPublishers` in AD with **direct** membership. -Design and gate: [`BUILD-AI-CONTAINERS.md`](BUILD-AI-CONTAINERS.md) §16 and +Design and gate: [`BUILD-AI-CONTAINERS.md`](spec/BUILD-AI-CONTAINERS.md) §16 and Phase 9. Two gate items matter most. A user who is authenticated but not a publisher must get a **403 from the API**, tested by calling `api.yokogawa.tech` directly — the button being hidden proves nothing. And after withdrawing a @@ -434,10 +434,17 @@ pytest api/tests # contracts, classifier rules, SQL allow-list. No netw ``` CLAUDE.md short rules — what Claude Code keeps front of mind -workflow-map.html the non-technical explainer — how a question becomes + +spec/ what we agreed to build — normative, durable + BUILD-AI-CONTAINERS.md the build spec + YAU_Linux_Host_Onboarding.md the host brief (reference; wins on conflict) + +status/ where it got to — snapshots, go stale, edited often + workflow-map.html the non-technical explainer — how a question becomes an answer, and what is built. Open it in a browser -BUILD-AI-CONTAINERS.md the build spec -YAU_Linux_Host_Onboarding.md the host brief (reference; wins on conflict) + current-state.html what is actually running right now. Open it too + REQUESTS.md what is still needed from other people + compose/ deployed to ~/ai-compose.yml and ~/langfuse-compose.yml caddy/ai-routes.caddy blocks to paste into ~/Caddyfile authelia/access-rules.md the rule additions as text — never the real config @@ -449,7 +456,6 @@ ingest/ Docling → chunk → embed → pg-ai, plus the web/ React + Vite operator UI eval/ 62-case test set and the scorecard runner scripts/ deploy.sh, verify.sh -docs/ GITIGNORED — real content on /datadisk/ai-docs ``` --- @@ -457,7 +463,7 @@ docs/ GITIGNORED — real content on /datadisk/ai-docs ## Known shortcuts Deliberate, documented, and not to be shipped. Full list in -[`BUILD-AI-CONTAINERS.md`](BUILD-AI-CONTAINERS.md) §14. The ones that matter most: +[`BUILD-AI-CONTAINERS.md`](spec/BUILD-AI-CONTAINERS.md) §14. The ones that matter most: - Secrets in `0600` env files, not a vault - No OT/IT firewall boundary — one flat `10.0.0.0/24` PoC network diff --git a/docs/.gitkeep b/docs/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/BUILD-AI-CONTAINERS.md b/spec/BUILD-AI-CONTAINERS.md similarity index 99% rename from BUILD-AI-CONTAINERS.md rename to spec/BUILD-AI-CONTAINERS.md index 89d72fc..9e02da9 100644 --- a/BUILD-AI-CONTAINERS.md +++ b/spec/BUILD-AI-CONTAINERS.md @@ -2,7 +2,7 @@ > **Scope:** add new containers to an **existing, live Docker host**. No machines are being built. > -> **How to use:** keep this alongside `YAU_Linux_Host_Onboarding.md` in the project folder. That file +> **How to use:** keep this alongside `YAU_Linux_Host_Onboarding.md` in `spec/`. That file > describes the host and its rules; this file describes what we are adding. **Where the two conflict, > the host brief wins.** Work through the phases in order and pass each gate before proceeding. diff --git a/YAU_Linux_Host_Onboarding.md b/spec/YAU_Linux_Host_Onboarding.md similarity index 100% rename from YAU_Linux_Host_Onboarding.md rename to spec/YAU_Linux_Host_Onboarding.md diff --git a/REQUESTS.md b/status/REQUESTS.md similarity index 100% rename from REQUESTS.md rename to status/REQUESTS.md diff --git a/current-state.html b/status/current-state.html similarity index 100% rename from current-state.html rename to status/current-state.html diff --git a/workflow-map.html b/status/workflow-map.html similarity index 100% rename from workflow-map.html rename to status/workflow-map.html