Compare commits

..

2 commits

2 changed files with 319 additions and 5 deletions

View file

@ -73,7 +73,7 @@ All data in transit is encrypted via HTTPS (TLS 1.2 or higher). All data at rest
Your uploaded CSV data and scored records are retained for the duration of your subscription plus 90 days. Upon termination of your subscription or pilot agreement, all data associated with your account will be deleted within 10 business days of your written request, and we will confirm deletion in writing. Your uploaded CSV data and scored records are retained for the duration of your subscription plus 90 days. Upon termination of your subscription or pilot agreement, all data associated with your account will be deleted within 10 business days of your written request, and we will confirm deletion in writing.
Audit logs (records of actions taken on the platform) are retained for 7 years for compliance purposes. Audit logs (records of actions taken on the platform) are retained for a minimum of 6 years, consistent with 45 CFR §164.530(j), for compliance purposes.
--- ---
@ -85,9 +85,7 @@ Audit logs (records of actions taken on the platform) are retained for 7 years f
## HIPAA ## HIPAA
Signal processes de-identified operational data. To the extent that any data processed by Signal could be considered protected health information under HIPAA, STTIL Solutions has executed a Business Associate Agreement (BAA) with its cloud infrastructure providers and operates appropriate administrative, physical, and technical safeguards. Signal processes de-identified operational data. The architecture is designed so that the data is not protected health information under HIPAA. A Business Associate Agreement (BAA) may not be required for your engagement with Signal. We encourage you to consult your own compliance advisors to determine whether a BAA is needed for your use case before uploading any data.
If you believe a Business Associate Agreement is required for your engagement with Signal, please contact us at the address below before uploading any data.
--- ---
@ -102,7 +100,7 @@ In the event of a security incident affecting your organization's data, STTIL So
Questions about this Privacy Policy or your data: Questions about this Privacy Policy or your data:
**STTIL Solutions LLC** **STTIL Solutions LLC**
Email: kisasttil@gmail.com Email: <kisasttil@gmail.com>
Web: signal.sttilsolutions.com Web: signal.sttilsolutions.com
--- ---

View file

@ -0,0 +1,316 @@
# Build Spec Phase 4 — Support Bot Foundation
**Date:** 2026-06-22
**Design:** Pi
**Build:** Claude Code
**Est:** 1 session
**Depends on:** Phase 3 (startup ritual) complete — shared-context pointers wired
---
## Overview
Phase 4 builds the foundation for a support bot by generating a machine-readable API reference from the backend source and cross-referencing it with the existing support manual. This enables automated troubleshooting support and sets up the data layer the bot will query.
Two substeps:
- **4.1** — Write `gen-api-ref.py` script to parse FastAPI routes from `main.py`
- **4.2** — Cross-reference `support-manual.md` with generated ref, fix gaps
---
## 4.1 Generate support-api-ref.json
### File to create
`signal/scripts/gen-api-ref.py`
### What to build
A Python script that:
1. Reads `python-backend/api/main.py`
2. Parses the AST for FastAPI route decorators (`@app.get`, `@app.post`, `@app.put`, `@app.delete`, `@app.patch`, `@router.*`)
3. Extracts for each route:
- Path (e.g., `/api/upload-csv`)
- HTTP method (GET, POST, etc.)
- Summary (first line of function docstring)
- Parameters (from function signature — path params, query params, body params)
- Response codes and descriptions (from `raise HTTPException(...)` calls in function body, plus the implicit 200)
4. Writes `signal/docs/support-api-ref.json`
### AST parsing approach
Use Python's `ast` module (stdlib — no external dependencies). Parse for:
- `@app.<method>` decorators and `@router.<method>` decorators
- Extract the route string from the decorator argument
- Get the function name from the decorated `FunctionDef`
- Extract docstring first line for summary
- Scan `raise` statements inside the function body for `HTTPException(status_code=...)`
- Detect `Request` and `UploadFile` params for the parameters list
### Expected output
```json
{
"generated": "2026-06-22",
"source": "python-backend/api/main.py",
"endpoints": [
{
"path": "/api/health",
"method": "GET",
"summary": "Health check endpoint",
"parameters": [],
"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"}
]
}
]
}
```
### Script structure
```python
#!/usr/bin/env python3
"""Generate support-api-ref.json from FastAPI backend source."""
import ast
import json
from pathlib import Path
BACKEND_DIR = Path(__file__).parent.parent / "python-backend"
OUTPUT = Path(__file__).parent.parent / "docs" / "support-api-ref.json"
MAIN_FILE = BACKEND_DIR / "api" / "main.py"
# Route decorator prefixes to match
HTTP_METHODS = {"get", "post", "put", "delete", "patch", "options", "head"}
# Known module names that may contain route definitions
SHARED_ROUTER_MODULES = [
"api.routes",
]
def extract_route(node):
"""Given a decorator Call node, return (method, path) or None."""
# Handle @app.get, @router.post, etc.
if (isinstance(node.func, ast.Attribute)
and isinstance(node.func.value, ast.Name)
and node.func.attr in HTTP_METHODS):
path = node.args[0].value if node.args else ""
return node.func.attr.upper(), path
return None
def extract_summary(docstring):
"""Get the first line of a docstring."""
if not docstring:
return ""
lines = docstring.strip().split("\n")
return lines[0].strip()
def extract_error_codes(body):
"""Scan a function body for HTTPException raises and extract status codes."""
codes = [{"code": 200, "description": "Success"}]
for node in ast.walk(body):
if (isinstance(node, ast.Raise)
and isinstance(node.exc, ast.Call)
and isinstance(node.exc.func, ast.Name)
and node.exc.func.id == "HTTPException"):
for kw in node.exc.keywords:
if kw.arg == "status_code" and isinstance(kw.value, ast.Constant):
detail = ""
for kw2 in node.exc.keywords:
if kw2.arg == "detail" and isinstance(kw2.value, ast.Constant):
detail = kw2.value.value
break
codes.append({
"code": kw.value.value,
"description": detail or f"HTTP {kw.value.value}"
})
return codes
def extract_function_parameters(func_def):
"""Extract parameter info from a function definition."""
params = []
for arg in func_def.args.args:
arg_name = arg.arg
if arg_name == "request":
params.append({"name": arg_name, "in": "path", "type": "Request", "required": True})
elif arg_name in ("file", "csv_file"):
params.append({"name": arg_name, "in": "formData", "type": "file", "required": True})
else:
params.append({"name": arg_name, "in": "query", "type": "string", "required": False})
return params
def parse_file(filepath):
"""
Parse a single Python file for FastAPI route decorators.
Returns list of endpoint dicts.
"""
endpoints = []
tree = ast.parse(filepath.read_text())
for node in ast.walk(tree):
if not isinstance(node, ast.FunctionDef):
continue
func_def = node
for decorator in func_def.decorator_list:
route = extract_route(decorator)
if route:
method, path = route
endpoints.append({
"path": path,
"method": method,
"summary": extract_summary(ast.get_docstring(func_def)),
"parameters": extract_function_parameters(func_def),
"responses": extract_error_codes(func_def),
})
return endpoints
def main():
endpoints = parse_file(MAIN_FILE)
# Optional: scan shared router modules
# for module_name in SHARED_ROUTER_MODULES:
# module_path = BACKEND_DIR / module_name.replace(".", "/") + ".py"
# if module_path.exists():
# endpoints.extend(parse_file(module_path))
output = {
"generated": "2026-06-22",
"source": str(MAIN_FILE.relative_to(BACKEND_DIR.parent)),
"endpoints": endpoints,
}
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
OUTPUT.write_text(json.dumps(output, indent=2) + "\n")
print(f"Generated {len(endpoints)} endpoints → {OUTPUT}")
if __name__ == "__main__":
main()
```
### Verification
```bash
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 from {d[\"source\"]}')
for ep in d['endpoints']:
codes = [str(r['code']) for r in ep['responses']]
print(f' {ep[\"method\"]:6} {ep[\"path\"]:30} → {ep[\"summary\"][:40]} [{','.join(codes)}]')
"
```
### Acceptance
- [ ] Script runs without external dependencies (stdlib only)
- [ ] Output file written to `signal/docs/support-api-ref.json`
- [ ] All real API endpoints extracted (health, upload, export, etc.)
- [ ] Error codes from `raise HTTPException(...)` captured
- [ ] Parameter lists populated
---
## 4.2 Cross-reference support-manual.md with API ref
### What to do
1. Read both `signal/docs/support-manual.md` and the generated `support-api-ref.json`
2. For each endpoint in the API ref, check the support manual for:
- Does the manual mention this endpoint? If not, add a section or a link
- Do the error messages in the manual's tables match the actual HTTPException codes from the API ref?
- Do the parameter descriptions match what the backend actually accepts?
3. Add a note at the top of `support-manual.md` noting the generation timestamp:
```markdown
*Auto-generated API reference: signal/docs/support-api-ref.json (generated YYYY-MM-DD)*
```
1. Add any missing endpoints to the manual as a section:
```markdown
---
## [METHOD] /api/endpoint-name
**Summary:** description
**Error codes:**
| Code | Description |
|------|-------------|
| 200 | Success |
| 4xx | Error type |
```
### Verification
```bash
# Count endpoints in API ref
ENDPOINTS=$(python3 -c "import json; d=json.load(open('signal/docs/support-api-ref.json')); print(len(d['endpoints']))")
# Count sections in support manual that mention endpoints
MANUAL_COVERAGE=$(grep -c '/api/' signal/docs/support-manual.md)
echo "API ref: $ENDPOINTS endpoints, Manual covers: $MANUAL_COVERAGE /api/ references"
```
If `MANUAL_COVERAGE` is significantly less than `ENDPOINTS`, more manual sections are needed.
### Acceptance
- [ ] support-manual.md has a generation timestamp note at the top
- [ ] All API ref endpoints have a corresponding section in the manual
- [ ] Error code tables in the manual match the actual codes from the API ref
- [ ] No stale/incorrect error descriptions in the manual
---
## Implementation Order
1. Write `signal/scripts/gen-api-ref.py`
2. Run it to generate `signal/docs/support-api-ref.json`
3. Read the generated ref alongside the manual
4. Update `signal/docs/support-manual.md`:
- Add generation timestamp note
- Add missing endpoint sections
- Fix any error code mismatches
5. Commit both files
## Completion Report Template
```markdown
### Phase 4 (Support Bot Foundation)
#### 4.1 API ref generation
- [ ] gen-api-ref.py written to signal/scripts/
- [ ] Runs with stdlib only (no pip install)
- [ ] support-api-ref.json generated with all N endpoints
#### 4.2 Manual cross-reference
- [ ] Generation timestamp added to support-manual.md
- [ ] All endpoints cross-referenced
- [ ] Error codes match between manual and API ref
```