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>
199 lines
5.6 KiB
Markdown
199 lines
5.6 KiB
Markdown
# UAT: Layered Consensus (Per-Tier Positions)
|
|
|
|
**Date:** YYYY-MM-DD
|
|
**Feature:** LayeredLens Resolution
|
|
**Status:** [ ] PASS / [ ] FAIL / [ ] BLOCKED
|
|
|
|
## Scenario
|
|
|
|
Different source tiers may hold different positions on the same question. The Layered Consensus lens should show:
|
|
1. What each tier says (per-tier winners)
|
|
2. Within-tier conflict (do sources within a tier agree?)
|
|
3. Cross-tier conflict (do tiers agree with each other?)
|
|
4. Overall winner (from highest authority tier)
|
|
|
|
## Acceptance Criteria
|
|
|
|
| Criterion | Expected | Met? |
|
|
|-----------|----------|------|
|
|
| Per-tier breakdown | All populated tiers shown | [ ] |
|
|
| Within-tier conflict | Calculated per tier | [ ] |
|
|
| Cross-tier conflict | Calculated across tiers | [ ] |
|
|
| Overall winner | From highest authority | [ ] |
|
|
| Empty tiers omitted | Not in response | [ ] |
|
|
|
|
## Test Matrix
|
|
|
|
| Step | Action | Expected | Actual | Status |
|
|
|------|--------|----------|--------|--------|
|
|
| 1 | Ingest Clinical assertions (conflicting) | 2 hashes | | [ ] |
|
|
| 2 | Ingest Anecdotal assertions (unanimous) | 50 hashes | | [ ] |
|
|
| 3 | Query layered consensus | Per-tier breakdown | | [ ] |
|
|
| 4 | Check Tier 1 conflict | > 0.5 (contested) | | [ ] |
|
|
| 5 | Check Tier 5 conflict | ~ 0.0 (unanimous) | | [ ] |
|
|
| 6 | Check overall conflict | > 0 (tiers disagree) | | [ ] |
|
|
|
|
## Setup Commands
|
|
|
|
```bash
|
|
# Start StemeDB
|
|
cargo run --bin stemedb-api &
|
|
sleep 2
|
|
```
|
|
|
|
## Test Commands
|
|
|
|
### Step 1: Ingest Conflicting Clinical Assertions (Tier 1)
|
|
|
|
```bash
|
|
# Study A: Weight loss causes muscle loss
|
|
curl -X POST http://localhost:18180/v1/assertions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"subject": "Semaglutide:BodyComposition",
|
|
"predicate": "lean_mass_preserved",
|
|
"object": {"Boolean": false},
|
|
"confidence": 0.85,
|
|
"source_class": "Clinical",
|
|
"source_hash": "0000000000000000000000000000000000000000000000000000000000000030"
|
|
}'
|
|
|
|
# Study B: Lean mass preserved with exercise
|
|
curl -X POST http://localhost:18180/v1/assertions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"subject": "Semaglutide:BodyComposition",
|
|
"predicate": "lean_mass_preserved",
|
|
"object": {"Boolean": true},
|
|
"confidence": 0.82,
|
|
"source_class": "Clinical",
|
|
"source_hash": "0000000000000000000000000000000000000000000000000000000000000031"
|
|
}'
|
|
```
|
|
|
|
**Expected:** 2 hashes returned
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 2: Ingest Unanimous Anecdotal Assertions (Tier 5)
|
|
|
|
```bash
|
|
# 50 Reddit users saying lean mass NOT preserved
|
|
for i in $(seq 1 50); do
|
|
HASH=$(printf '%064d' $((2000 + i)))
|
|
curl -s -X POST http://localhost:18180/v1/assertions \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"subject\": \"Semaglutide:BodyComposition\",
|
|
\"predicate\": \"lean_mass_preserved\",
|
|
\"object\": {\"Boolean\": false},
|
|
\"confidence\": 0.75,
|
|
\"source_class\": \"Anecdotal\",
|
|
\"source_hash\": \"$HASH\"
|
|
}" > /dev/null
|
|
done
|
|
echo "Created 50 anecdotal assertions"
|
|
```
|
|
|
|
**Expected:** 50 assertions created
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 3: Query with Layered Consensus Lens
|
|
|
|
```bash
|
|
curl "http://localhost:18180/v1/query?subject=Semaglutide:BodyComposition&predicate=lean_mass_preserved&lens=layered-consensus"
|
|
```
|
|
|
|
**Expected:**
|
|
```json
|
|
{
|
|
"tiers": [
|
|
{
|
|
"tier": 1,
|
|
"source_class": "Clinical",
|
|
"candidates_count": 2,
|
|
"conflict_score": 0.88, // Contested within tier
|
|
"winner": {"object": {"Boolean": false}, ...}
|
|
},
|
|
{
|
|
"tier": 5,
|
|
"source_class": "Anecdotal",
|
|
"candidates_count": 50,
|
|
"conflict_score": 0.0, // Unanimous within tier
|
|
"winner": {"object": {"Boolean": false}, ...}
|
|
}
|
|
],
|
|
"overall_winner": {...}, // From Tier 1 (Clinical)
|
|
"overall_conflict_score": 0.0, // Tier winners agree (both say false)
|
|
"total_candidates": 52
|
|
}
|
|
```
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 4: Check Tier 1 (Clinical) Conflict
|
|
|
|
From Step 3 response, find the tier with `tier: 1`.
|
|
|
|
**Expected:** `conflict_score > 0.5` (two studies disagree)
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 5: Check Tier 5 (Anecdotal) Conflict
|
|
|
|
From Step 3 response, find the tier with `tier: 5`.
|
|
|
|
**Expected:** `conflict_score ~ 0.0` (all 50 agree)
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Step 6: Check Cross-Tier Conflict
|
|
|
|
In this case, both tier winners say `lean_mass_preserved: false`, so cross-tier conflict should be low.
|
|
|
|
**Expected:** `overall_conflict_score ~ 0.0` (tier winners agree)
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
### Bonus: Create Cross-Tier Disagreement
|
|
|
|
```bash
|
|
# Add a Regulatory assertion that says lean mass IS preserved
|
|
curl -X POST http://localhost:18180/v1/assertions \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"subject": "Semaglutide:BodyComposition",
|
|
"predicate": "lean_mass_preserved",
|
|
"object": {"Boolean": true},
|
|
"confidence": 0.95,
|
|
"source_class": "Regulatory",
|
|
"source_hash": "0000000000000000000000000000000000000000000000000000000000000032"
|
|
}'
|
|
|
|
# Query again
|
|
curl "http://localhost:18180/v1/query?subject=Semaglutide:BodyComposition&predicate=lean_mass_preserved&lens=layered-consensus"
|
|
```
|
|
|
|
**Expected:** `overall_conflict_score > 0.5` (Tier 0 says true, others say false)
|
|
**Actual:**
|
|
**Status:** [ ]
|
|
|
|
## Sign-Off Checklist
|
|
|
|
- [ ] Layered lens returns per-tier breakdown
|
|
- [ ] Within-tier conflict calculated correctly
|
|
- [ ] Cross-tier conflict calculated correctly
|
|
- [ ] Overall winner from highest authority tier
|
|
- [ ] Empty tiers not included in response
|
|
|
|
## Notes
|
|
|
|
*Layered consensus is the foundation for "disagreement dashboards" - showing users WHERE the disagreement is, not just WHETHER there's disagreement.*
|
|
|
|
---
|
|
|
|
**Tester:**
|
|
**Date:**
|
|
**Result:**
|