Major additions: - Staged scanning modes (working tree, staged, committed) with git integration - Drift detection for baseline vs current state comparisons - Hosted API handlers for policy CRUD operations via StemeDB API - stemedb-ontology crate with domain definitions and medical extractors - Consumer health vertical UAT scenarios (GLP-1, gastroparesis, etc.) - Aphoria development skill documentation Code organization: - Split large files into focused modules to stay under 500-line limit - Extracted config tests, episteme helpers/drift/aliases, API helpers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
171 lines
4.7 KiB
Markdown
171 lines
4.7 KiB
Markdown
# UAT: Anecdotal Signal Precedence (Cluster Escalation)
|
|
|
|
**Date:** YYYY-MM-DD
|
|
**Feature:** Escalation Signals
|
|
**Status:** [ ] PASS / [ ] FAIL / [ ] BLOCKED
|
|
|
|
## Scenario
|
|
|
|
When 500+ Tier 5 (Anecdotal) reports cluster around a subject with NO Tier 0-2 coverage, this should trigger an **escalation signal**. This represents "something the community is seeing that hasn't been validated yet."
|
|
|
|
Key validation: The system detects an information gap that needs expert investigation.
|
|
|
|
## Acceptance Criteria
|
|
|
|
| Criterion | Expected | Met? |
|
|
|-----------|----------|------|
|
|
| 500+ Tier 5 assertions exist | All ingested | [ ] |
|
|
| No Tier 0-2 for same subject | Verified | [ ] |
|
|
| Escalation signal created | event_type = "anecdotal_cluster" | [ ] |
|
|
| Signal includes cluster metadata | count, subject, predicate | [ ] |
|
|
| Threshold is configurable | Can adjust 500 limit | [ ] |
|
|
|
|
## Test Matrix
|
|
|
|
| Step | Action | Expected | Actual | Status |
|
|
|------|--------|----------|--------|--------|
|
|
| 1 | Ingest 500 Tier 5 assertions | 500 hashes returned | | [ ] |
|
|
| 2 | Verify no Tier 0-2 exists | Empty result | | [ ] |
|
|
| 3 | Query escalation events | Signal present | | [ ] |
|
|
| 4 | Check signal metadata | count >= 500 | | [ ] |
|
|
| 5 | Add Tier 1 assertion | Signal resolved | | [ ] |
|
|
|
|
## Escalation Logic
|
|
|
|
```
|
|
IF count(subject, predicate, tier=5) >= threshold
|
|
AND count(subject, predicate, tier IN [0,1,2]) == 0
|
|
THEN create_escalation_signal({
|
|
event_type: "anecdotal_cluster",
|
|
level: "investigate",
|
|
subject: subject,
|
|
predicate: predicate,
|
|
cluster_count: count,
|
|
message: "High-volume anecdotal reports with no authoritative coverage"
|
|
})
|
|
```
|
|
|
|
## Setup Commands
|
|
|
|
```bash
|
|
# Start StemeDB
|
|
cargo run --bin stemedb-api &
|
|
sleep 2
|
|
```
|
|
|
|
## Test Commands
|
|
|
|
### Step 1: Ingest 500 Anecdotal Reports (New Symptom)
|
|
|
|
```bash
|
|
# A new symptom not yet documented by FDA/clinical
|
|
for i in $(seq 1 500); do
|
|
HASH=$(printf '%064d' $((1000 + i)))
|
|
curl -s -X POST http://localhost:18180/v1/assertions \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"subject\": \"Semaglutide\",
|
|
\"predicate\": \"hair_loss_reported\",
|
|
\"object\": {\"Boolean\": true},
|
|
\"confidence\": 0.70,
|
|
\"source_class\": \"Anecdotal\",
|
|
\"source_hash\": \"$HASH\"
|
|
}" > /dev/null
|
|
done
|
|
echo "Created 500 anecdotal hair loss reports"
|
|
```
|
|
|
|
**Expected:** 500 assertions created
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 2: Verify No Authoritative Coverage
|
|
|
|
```bash
|
|
# Check for Tier 0-2 assertions on hair_loss
|
|
curl "http://localhost:18180/v1/query?subject=Semaglutide&predicate=hair_loss_reported&source_class=Regulatory"
|
|
curl "http://localhost:18180/v1/query?subject=Semaglutide&predicate=hair_loss_reported&source_class=Clinical"
|
|
curl "http://localhost:18180/v1/query?subject=Semaglutide&predicate=hair_loss_reported&source_class=Observational"
|
|
```
|
|
|
|
**Expected:** All queries return empty results
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 3: Query Escalation Events
|
|
|
|
```bash
|
|
curl "http://localhost:18180/v1/escalations?subject=Semaglutide"
|
|
```
|
|
|
|
**Expected:**
|
|
```json
|
|
{
|
|
"events": [
|
|
{
|
|
"event_type": "anecdotal_cluster",
|
|
"level": "investigate",
|
|
"subject": "Semaglutide",
|
|
"predicate": "hair_loss_reported",
|
|
"cluster_count": 500,
|
|
"message": "High-volume anecdotal reports with no authoritative coverage",
|
|
"created_at": "..."
|
|
}
|
|
]
|
|
}
|
|
```
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 4: Check Signal Metadata
|
|
|
|
From Step 3 response, verify:
|
|
- `cluster_count >= 500`
|
|
- `subject` and `predicate` match
|
|
- `level` is "investigate"
|
|
|
|
**Expected:** All metadata correct
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 5: Resolve by Adding Authoritative Source
|
|
|
|
```bash
|
|
# Clinical study addresses the hair loss question
|
|
curl -X POST http://localhost:18180/v1/assertions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"subject": "Semaglutide",
|
|
"predicate": "hair_loss_reported",
|
|
"object": {"Text": "Post-hoc analysis shows 2.3% incidence, similar to placebo"},
|
|
"confidence": 0.88,
|
|
"source_class": "Clinical",
|
|
"source_hash": "0000000000000000000000000000000000000000000000000000000000000099"
|
|
}'
|
|
|
|
# Check if escalation is resolved
|
|
curl "http://localhost:18180/v1/escalations?subject=Semaglutide&status=active"
|
|
```
|
|
|
|
**Expected:** Escalation marked as "resolved" or removed from active list
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
## Sign-Off Checklist
|
|
|
|
- [ ] 500 anecdotal assertions ingested
|
|
- [ ] Escalation triggered for coverage gap
|
|
- [ ] Signal includes cluster count and metadata
|
|
- [ ] Adding authoritative source resolves signal
|
|
- [ ] Threshold is configurable (default 500)
|
|
|
|
## Notes
|
|
|
|
*Escalation signals are for investigation workflow. They don't change assertion storage or query results - they're a separate alert system.*
|
|
|
|
---
|
|
|
|
**Tester:**
|
|
**Date:**
|
|
**Result:**
|