docs: add build spec, support manual, and shared current-state context

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Kisa 2026-06-20 17:38:31 -04:00
parent 42a79c6682
commit 7053e4e061
3 changed files with 585 additions and 0 deletions

34
context/current-state.md Normal file
View file

@ -0,0 +1,34 @@
# current-state
ACTIVE: Build shared context + knowledge pipeline (Jun 20 design).
NEXT: Hand current-state.md + support-manual.md to Claude Code for build.
## Decisions (last 5)
- 2026-06-20 — current-state.md bridges Pi and Claude Code. Both read at start, both write at wrap-up.
- 2026-06-18 — SSA principle adopted: sparse, content-dependent, time-weighted retrieval.
- 2026-06-18 — TriLane Memory = permanent insight layer. research_insight category needed.
- 2026-06-18 — Graphify = monthly scan only. Not a daily driver.
- 2026-06-18 — Granola transcripts stay in Sessions workspace. Signal workspace = library. No mixing.
## Open Threads (max 5)
- Firecrawl key in .zshrc — needs pi restart from sourced shell
- 9 session summaries in Signal workspace — move to Sessions
- Insight Engine (Jul 4) — Railway deploy blocked on interactive auth
- labABLE Jun 26 call — deck built, needs review
- Clerk production — deferred, needs manual Google OAuth setup
## Stack
- signal-api: Railway (signal-api-production-91c2)
- signal-ui: Vercel (signal-ui-xi.vercel.app)
- Supabase: itmospnregdyiatbbdwl (JWT key)
- TriLane: localhost:8000 (signal/sessions/scale-software workspaces)
- Clerk: sandbox only
## Tip
TriLane Memory: 0 items. The permanent insight layer is empty. Every session brain should plant at least one.
## Updated: 2026-06-20 15:30 UTC

View file

@ -0,0 +1,345 @@
# Build Spec: Shared Context + Knowledge Pipeline
**Date:** 2026-06-20
**Design session:** Pi (architecture)
**Build session(s):** Claude Code
**Verification:** Kisa reviews after each phase
---
## Phase 1 — Foundation (est. 1 session)
### 1.1 Add research_insight category to TriLane Memory
**Files to change:**
- [ ] `trilane/backend/app/models.py`
- Line ~79: Add `research_insight` to the allowed category values on `MemoryItem.category`
- Current: `category = Column(String(64), nullable=False) # decision, preference, open_loop, project_fact`
- Change comment to include `research_insight` or add enum validation
- [ ] `trilane/backend/app/schemas.py`
- Line ~65: Add `research_insight` to `MemoryItemOut` or `MemoryCreate` schema validation
- Ensure the field accepts the new category string
- [ ] Run DB migration (Alembic or manual)
- If using Alembic: `cd trilane && alembic revision --autogenerate -m "add research_insight category" && alembic upgrade head`
- If manual: `ALTER TABLE memory_items DROP CONSTRAINT IF EXISTS ...` or equivalent
- Verify migration ran: `curl http://localhost:8000/api/workspaces` — should still list all 3 workspaces
**Verification:**
```
curl -X POST http://localhost:8000/api/memory/16ee4620-4c81-48f9-bcd6-6c0a8fbbd71a \
-H "Content-Type: application/json" \
-d '{"category": "research_insight", "content": "test", "salience": 1.0}'
```
Should return 201 with memory item ID. Then delete the test item.
---
### 1.2 Plant the first real research_insight
- [ ] POST to TriLane Memory with the CGM→pharmacy insight
**Payload:**
```json
{
"workspace_id": "16ee4620-4c81-48f9-bcd6-6c0a8fbbd71a",
"category": "research_insight",
"content": "CGM is systematically moving to pharmacy channel. Payer rules in FL/CA/OH/NC have moved CGM to pharmacy-only. UHC MA requires Synapse Health enrollment. Humana MA has tied-routing rule. DMEPOS suppliers are being squeezed: paid less, held to stricter documentation requirements, pushed toward expensive TPA models. This trend Signal must track for supplier intelligence.",
"salience": 1.0,
"tags": ["cgm", "pharmacy", "payer_trend", "policy", "strategic"]
}
```
**Verification:**
```
curl http://localhost:8000/api/memory/16ee4620-4c81-48f9-bcd6-6c0a8fbbd71a
```
Should show 1 item with category "research_insight" and content matching above.
---
### 1.3 Move 9 leaked session summaries out of Signal workspace
- [ ] Identify all session summaries in Signal workspace (id: 16ee4620)
- Expected: 9 files from April/May 2026
- Filenames: `2026-04-24-session-summary*` through `2026-05-10-session-summary*`
- [ ] Find the TriLane API endpoint for moving/reassigning sources between workspaces
- If no move endpoint exists: DELETE from Signal, re-upload to Sessions workspace (id: 3446107c)
- If move endpoint exists: POST to move endpoint with source_id and target workspace_id
**Verification:**
```
# Signal workspace should have 38 docs (was 47, minus 9 summaries)
curl http://localhost:8000/api/sources/16ee4620 | python3 -c "import json,sys; print(len(json.load(sys.stdin)))"
# Sessions workspace should have 88 docs (was 79, plus 9 summaries)
curl http://localhost:8000/api/sources/3446107c | python3 -c "import json,sys; print(len(json.load(sys.stdin)))"
```
No session summaries should appear in the Signal workspace source list.
---
## Phase 2 — Session Brain Updates (est. 1 session)
### 2.1 Add current-state.md write to session brain
- [ ] Read `navaigate-session-brain/SKILL.md` to identify insertion point
- [ ] Add a substep between the current Step 3 (summary) and Step 4 (NotebookLM):
```
Step 3B — Write shared context file
- Update signal/context/current-state.md
- Set ACTIVE to what was accomplished
- Set NEXT to the next priority
- Add any new decisions (max 5, FIFO — oldest drops off)
- Update open threads
- Update stack state if anything changed
- Set timestamp to now
```
**Verification:**
```
cat signal/context/current-state.md
```
Should show the session's update after the next session brain run.
---
### 2.2 Add insight extraction to session brain
- [ ] Add a second substep between Step 3 (or after Step 3B):
```
Step 3C — Extract research insights
- Did this session produce cross-document synthesis?
- If yes: POST a research_insight memory item to TriLane Signal workspace
- Content: one paragraph describing the insight
- Salience: 1.0 (permanent)
- Tags: relevant category tags
- If no new insight: skip this step
```
**Verification:**
After the next session brain runs, TriLane Memory for Signal workspace should show
a new research_insight item (in addition to the CGM→pharmacy seed from Phase 1).
---
## Phase 3 — Startup Ritual (est. 30 min)
### 3.1 Update CLAUDE.md
- [ ] Read `signal/CLAUDE.md`
- [ ] Add near the top, after the project description:
```markdown
## Startup Ritual
At session start, in order:
1. Read signal/context/current-state.md to know the active priority
2. Check TriLane Memory for recent research_insights
3. Begin work
```
**Verification:**
```
grep "current-state" signal/CLAUDE.md
```
Should show the startup ritual section.
---
### 3.2 Create startup instruction for Pi
- [ ] Add to `~/.pi/agent/AGENTS.md` or a startup prompt:
```
At session start:
Read signal/context/current-state.md
Check TriLane Memory for new research_insights
```
**Verification:**
Pi reads current-state.md at session start.
---
## Phase 4 — Support Bot Foundation (est. 1 session)
### 4.1 Generate support-api-ref.json
- [ ] Write a Python script at `signal/scripts/gen-api-ref.py` that:
- Reads `python-backend/api/main.py`
- Parses FastAPI route decorators (@app.get, @app.post, etc.)
- Extracts route path, method, summary (from docstring first line)
- Extracts response model info
- Extracts error responses (from raise statements in the function body)
- Writes `signal/docs/support-api-ref.json`
**Expected output structure:**
```json
{
"generated": "2026-06-20",
"source": "python-backend/api/main.py",
"endpoints": [
{
"path": "/api/health",
"method": "GET",
"summary": "Health check endpoint",
"responses": [
{"code": 200, "description": "Service healthy"}
]
},
{
"path": "/api/upload-csv",
"method": "POST",
"summary": "Upload and process a CSV file",
"parameters": [
{"name": "file", "in": "formData", "type": "file", "required": true}
],
"responses": [
{"code": 200, "description": "CSV processed successfully"},
{"code": 400, "description": "Invalid CSV format or missing columns"},
{"code": 401, "description": "Invalid or missing API key"},
{"code": 500, "description": "Server error processing CSV"}
]
}
]
}
```
**Verification:**
```
python3 signal/scripts/gen-api-ref.py
cat signal/docs/support-api-ref.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(f'{len(d[\"endpoints\"])} endpoints extracted')"
```
Should show all real API endpoints from the backend.
---
### 4.2 Cross-reference support-manual.md with generated API ref
- [ ] Read both files and ensure:
- Error messages in the manual match actual error codes from the API ref
- Endpoint descriptions in the manual are consistent with the generated routes
- Any missing endpoints in the manual are added
- [ ] Add a note at the top of `support-manual.md` noting the generation timestamp
**Verification:**
The error tables in `support-manual.md` should reference real endpoints in
`support-api-ref.json`.
---
## Phase 5 — Session Brain Nugget Format Update (est. 30 min)
### 5.1 Compact nugget format
- [ ] Edit `navaigate-session-brain/SKILL.md` Step 3 (Write Session Summary)
- [ ] Change the format from verbose markdown to compact nugget (~400 bytes):
```markdown
## Session Nugget — YYYY-MM-DD
N themes · N tools touched · N insights
### Completed
- [action 1]
- [action 2]
- [action 3]
### Insight
One sentence if cross-document synthesis happened. Omit if not.
### Next (Top 1)
1. [single most important next step]
### Cross-Refs
- Tool/Project links
```
**Verification:**
After next session brain run, check the NotebookLM source to verify it's using
the compact format:
```
notebooklm source list --json
notebooklm source fulltext <source_id>
```
---
## Phase 6 — Startup Automation (est. 30 min)
### 6.1 Verify the full cycle works end-to-end
- [ ] Simulate a Pi session:
1. Pi reads current-state.md
2. Pi does design work
3. Pi writes decisions to current-state.md
4. Pi posts insight to TriLane Memory (if applicable)
5. Pi runs session brain → pushes nugget
- [ ] Simulate a Claude Code session:
1. Claude Code reads current-state.md
2. Claude Code sees Pi's design decisions
3. Claude Code builds the change
4. Claude Code updates current-state.md
5. Claude Code runs session brain → pushes nugget
**Verification:**
- current-state.md reflects the latest session
- TriLane Memory for Signal workspace has the planted insights
- NotebookLM Brain has nuggets from both sessions
- Barrier Log has any issues encountered (should be none for a clean build)
---
## Completion Report Template
When all phases are complete, fill in:
```markdown
## Build Complete: Shared Context + Knowledge Pipeline
### Phase 1 (Foundation)
- [x] research_insight category added to TriLane Memory
- [x] CGM→pharmacy insight planted (salience 1.0)
- [x] 9 session summaries moved from Signal → Sessions workspace
### Phase 2 (Session Brain)
- [x] current-state.md write added to session brain
- [x] Insight extraction added to session brain
### Phase 3 (Startup Ritual)
- [x] CLAUDE.md updated with startup ritual
- [x] Pi AGENTS.md updated
### Phase 4 (Support Bot)
- [x] support-api-ref.json generated
- [x] Manual cross-referenced against generated ref
### Phase 5 (Nugget Format)
- [x] Session brain nugget format compacted to ~400 bytes
### Phase 6 (Verification)
- [x] Full cycle verified end-to-end
```

206
docs/support-manual.md Normal file
View file

@ -0,0 +1,206 @@
# Signal Support Manual
Curated operations knowledge for the Signal CGM documentation readiness platform.
Support bot reads this + support-api-ref.json + Barrier Log for troubleshooting.
See signal/docs/support-api-ref.json for auto-generated API routes and error codes.
---
## CSV Import
Signal ingests order data from any DME order management CSV export.
### Required Columns
Column names are matched case-insensitively. At minimum, the CSV must contain
identifying and status fields. Signal evaluates each row against documentation
requirements and produces a status per patient.
| Column | Required | Purpose |
|--------|----------|---------|
| patient_name | Yes | Patient identifier |
| cgm_type | Yes | Device type for LCD rule matching |
| sw0_status | No | Signed written order status |
| qualifying_visit_date | No | Last qualifying visit date |
| pa_status | No | Prior authorization status |
| next_shipment_date | No | Expected resupply date |
| payer | No | Payer name for routing checks |
If a column is absent, Signal treats the requirement as "not evaluated" —
not a gap. This prevents false negatives when a supplier's export format
omits fields they don't track.
### Validation Rules
- Rows with empty patient_name are skipped
- Unknown cgm_type values log a warning and skip LCD matching
- Date columns must be ISO 8601 (YYYY-MM-DD) or a parseable US format
- Files over 10MB are rejected (supplier sends manageable subsets)
### Error Messages (common)
| Error | Cause | Fix |
|-------|-------|-----|
| "Missing required columns" | CSV missing patient_name or cgm_type | Check export template |
| "Upload failed — auth error" | API key missing or expired | Generate new key in Railway env |
| "Upload failed — CORS error" | Frontend domain not in allow list | Add domain to ALLOWED_ORIGINS_REGEX |
| "Upload failed — server error" | Backend crashed or timed out | Check Railway logs |
| "No parsable rows found" | All rows failed validation | Check column names in export |
---
## API Reference
See `signal/docs/support-api-ref.json` for full auto-generated route listing.
### Authentication
- All endpoints require `X-API-Key` header matching the value in Railway env vars
- Clerk-authenticated endpoints use Bearer JWT tokens
- Dev keys are for sandbox only; rotate before any external user accesses the app
### Key Endpoints
| Endpoint | Method | Purpose |
|----------|--------|---------|
| /api/health | GET | Health check — returns {"status": "ok"} |
| /api/upload-csv | POST | Upload and process CSV file |
| /api/patients | GET | List all patients with status summary |
| /api/patients/{id} | GET | Single patient detail and cascade |
| /api/confirm-visit | POST | Record qualifying visit confirmation |
| /api/update-doc-status | POST | Update document status for a requirement |
| /api/export | GET | Download Signal Report as CSV |
### Common Response Codes
| Code | Meaning | Likely Cause |
|------|---------|--------------|
| 200 | Success | — |
| 400 | Bad request | Missing or malformed parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | Valid key, insufficient scope |
| 404 | Not found | Patient ID doesn't exist |
| 500 | Server error | Backend exception (check logs) |
| 503 | Service unavailable | Database connection issue or deployment cycling |
---
## Status Labels
Signal uses 4 UI tabs. The backend computes 8 internal flags that map to these.
### Internal Flags (backend)
| Flag | Meaning | Trigger |
|------|---------|---------|
| SUPPLY_LAPSED | Patient is past resuppy date | next_shipment_date passed |
| VISIT_REQUIRED | 6-month qualifying visit expired | qualifying_visit_date > 6 months ago |
| RENEWAL_CRITICAL | Prescription renewal due within 15 days | Calculated from renewal date |
| RENEWAL_ELEVATED | Renewal due within 30 days | |
| RENEWAL_SOON | Renewal due within 60 days | |
| RESUPPLY_READY | All requirements met, ready to ship | SWO on file + PA approved + visit current + no cascade gaps |
| ACTIVE | Patient is stable, no flags | Nothing due, no gaps |
| TRANSFER_PENDING | Incoming from another supplier | Set manually in CSV or UI |
### UI Tabs (frontend, mapped from internal flags)
| Tab | Internal Flags Included |
|-----|------------------------|
| At Risk | SUPPLY_LAPSED |
| Action Needed | VISIT_REQUIRED, RENEWAL_CRITICAL, RENEWAL_ELEVATED |
| Clear to Ship | RESUPPLY_READY (with no cascade items) |
| On Track | ACTIVE, RENEWAL_SOON, TRANSFER_PENDING, NO_RECENT_SHIPMENT |
---
## Documentation Requirements (Cascade)
Each patient has a cascade — a list of documentation actions needed to
reach Clear to Ship. Cascade items are only shown when their source column
was supplied in the CSV.
### Possible Cascade Items
| Item | Cause | Cleared By |
|------|-------|------------|
| Signed Written Order (SWO) | sw0_status is not "On File" | Update sw0_status or use "Confirm Visit" |
| Qualifying Visit | qualifying_visit_date missing or > 6 months | Schedule and confirm visit |
| Prior Authorization | pa_status is not "Approved" | Submit PA and update status in CSV |
| Prescription Renewal | renewal_date approaching or passed | Obtain new prescription |
---
## Common Failures & Resolutions
Issues from the Barrier Log that appear most often. Full history at
`STTIL-Vault/Projects/Barrier-Log.md`.
### Uploads Fail Silently
**Symptoms:** CSV uploads return success but worklist stays empty or shows
wrong statuses. No error message shown to user.
**Root cause:** `api.js` had `catch { return null }` blocks swallowing all
errors. Fixed by re-throwing real errors and adding toast notifications.
**Status:** Fixed and deployed. If it recurs, check that:
1. The frontend is deployed from the fix branch (vercel --prod)
2. The backend is deployed from the matching fix (railway up --detach)
3. ALLOWED_ORIGINS_REGEX includes the domain
### Clear to Ship Never Goes Green
**Symptoms:** All patients show amber status, even resupply-ready ones.
Green count is permanently 0.
**Root cause:** The backend scored missing CSV columns as doc gaps. An
absent "sw0_status" column meant every patient had a "missing SWO" cascade
item. Green = "no cascade items" so green was unreachable.
**Fix:** Added "supplied" sentinel flags. An absent column is "not evaluated,"
not a gap. Green means "no known blocker from the data provided."
**Status:** Fixed and deployed. Verify by uploading a CSV with resupply-ready
patients — they should show green.
### CORS Errors on Vercel Deploy
**Symptoms:** Upload fails with browser CORS error on preview URLs.
**Root cause:** ALLOWED_ORIGINS was a fixed list. Vercel preview URLs
(project-xxxx.vercel.app) weren't included.
**Fix:** Changed to ALLOWED_ORIGINS_REGEX to accept *.vercel.app patterns.
### Status Count Mismatch (Stat Card vs Row Count)
**Symptoms:** The stat card shows a different green count than filtering
by "Clear to Ship" tab.
**Root cause:** Stat card counted RESUPPLY_READY. Tab counted
RESUPPLY_READY AND cascade empty. Cascade was never empty (see above).
**Fix:** Both now use the same logic: RESUPPLY_READY with no cascade gaps.
---
## Known Issues (Active)
| Issue | Status | Workaround |
|-------|--------|------------|
| Clerk production migration deferred | Blocking real supplier login | Use sandbox keys for dev; manual Google OAuth setup needed |
| Gaboro demo API key in Railway env | Security risk before external access | Rotate before Robert Robinson pilot |
| granola-ingest portable path | Needs path update | Script works from full path; symlink/alias pending |
---
## Cross-References
- **State machine code:** python-backend/core/doc_state_machine.py
- **Cascade builder:** python-backend/core/doc_state_machine.py (_build_cascade)
- **Frontend status mapping:** signal-ui/src/components/WorklistTable.jsx
- **Upload handler:** signal-ui/src/lib/api.js
- **API auth:** python-backend/api/main.py (X-API-Key middleware)
- **Barrier Log (all resolved issues):** STTIL-Vault/Projects/Barrier-Log.md
- **TriLane research library:** Signal workspace (research docs, payer matrix, synthesis)