refactor(agents): migrate .agent/ planning tree to .agents/

Standardize on the .agents/ directory (shared with project skills):
phases/, user_stories/, reports/, screenshots/, validate.sh, and
phase-sessions/ + pipeline.log all move to .agents/ (git mv preserves
history; runtime artifacts move alongside).

Updates every reference in AGENTS.md, README.md, .gitignore, app
docstrings, and test story headers. Historical KB content in data/
and the runtime pipeline.log transcript are left untouched.
This commit is contained in:
2026-09-05 10:57:07 -04:00
parent 766702c750
commit dbf2af26c6
1118 changed files with 664 additions and 664 deletions
@@ -0,0 +1,42 @@
# Phase 51 — Share a Chat by Link (Anonymous View)
**Source:** `TODO.md` L6 — "Need a way to share a chat with a link so others can see it anonymously."
**Story:** n/a (TODO-derived — owner roadmap confirmation 2026-08-29)
**Context:** Builds on phase 50's `saved_chats` rows: sharing is a token on a saved chat. The public surface is a **new anonymous page** `/shared/<token>` (a real route — the static mount cannot serve a dynamic path) rendering a read-only copy of the conversation through the same record shape (thinking block, tool lines, source chips, stopped note) — no composer, no controls. The documents API is admin-only (phase 16), so a guest's source chips are plain text (owner-locked). The cache-busting middleware treats known HTML paths (the `HTML_PAGES` tuple in `app/core/caching.py`) as revalidate + `?v=`-rewrite pages; the shared page joins that contract by path prefix.
## Objective
The owner can turn a saved chat into a public link (`/shared/<token>`); anyone with the link sees the conversation read-only, anonymously; unsharing revokes it.
## Dependencies
- `50_chat_history` (todo) — the `saved_chats` row, the Save flow, and the History table the share actions extend.
## Tasks
1. `01_share_token.md` — migration `0009_saved_chat_share_token` + the share/unshare/public-read API + the `/shared/<token>` page route + the middleware prefix.
2. `02_share_ui.md` — the Share button (chat page, save-then-share in one action) + the History table's share column (create/copy/unshare).
3. `03_shared_page.md` — `shared.html` + `shared.js`: the anonymous read-only rendering.
4. `04_e2e_share_chat.md` — the story Playwright suite + regressions + commit.
## Testing & Quality
- Integration: share/unshare/public-read contract (token shape, idempotent share, unshare revokes, a wrong token 404s, no admin needed to read, `updated_at` untouched by share/unshare) + `tests/integration/test_migration_0009.py`.
- Coverage: **>90%** on `app/`.
- E2E (mandatory, A16): `tests/e2e/test_share_chat.py`, run in isolation.
## Completion Criteria
- [ ] Admin: the Share button on the chat page (saved or unsaved conversation) and the History row both produce/copy the `/shared/<token>` link; an unsaved conversation is saved + shared in one action.
- [ ] A fresh anonymous context opening `/shared/<token>` sees the full conversation read-only (thinking collapsed, tool lines, the stopped note where present, source chips as plain text) with **no** composer, Save, Share, Tune, or Retry anywhere; a wrong/revoked token shows the "invalid or revoked" state.
- [ ] Unshare revokes: the same URL shows the invalid state afterwards; the served shared page carries the cache-busting contract (no-cache + `?v=` rewrite).
- [ ] `uv run pytest` green; coverage TOTAL >90%.
- [ ] `uv run pytest tests/e2e/test_share_chat.py -v --no-cov` green in isolation (DB up).
- [ ] Regression E2E suites green in isolation: `test_chat_history.py`, `test_chat_persistence.py`, `test_smoke.py`, `test_cache_busting.py`.
- [ ] `uv run ruff check . && uv run pyright` clean.
- [ ] One `--no-gpg-sign` commit; phase dir moved to `.agents/phases/complete/`.
## Locked decisions
- **Owner-locked (2026-08-29, roadmap confirmation):** share links are public by design (128-bit `uuid4` token; unshare revokes); the shared page renders the full conversation read-only (thinking collapsed) with **zero** interactive controls; source chips are plain text (guests cannot open documents — the documents API is admin-only); clipboard copy with an inline-link fallback (a homelab http origin may not be a secure context).
- **The A10 extension (phase 50, owner permission 2026-08-29) unchanged** — sharing reuses the already-stored row; no new storage beyond the token column.
- **A16/A17 honoured** — one story E2E suite, one atomic commit.
## Commit
```bash
git add -A .agents/ app/ alembic/versions/ frontend/ tests/ && git commit --no-gpg-sign -m "feat(chat): share a chat by link — anonymous read-only /shared/<token> page, share/unshare"
```