MasteryMade · Foundation PRD
Gates prevent content contamination across contexts. The suggest engine prevents clutter by requiring approval before connections become retrievable. Without these, every vector similarity match auto-injects — burning tokens, costing money, degrading output quality.
When content enters the system via universal ingest, it must be tagged with a gate. Assignment rules, evaluated in order:
Gate assignment happens in the universal ingest service (PRD 3) at write time. The gate column is NOT NULL — content cannot be stored without a gate.
ALTER TABLE content ADD COLUMN gate INT NOT NULL CHECK (gate IN (1,2,3,4));
ALTER TABLE content ADD COLUMN entity_id UUID REFERENCES entities(id);
CREATE INDEX idx_content_gate ON content(gate);
CREATE INDEX idx_content_entity ON content(entity_id);
CREATE INDEX idx_content_gate_entity ON content(gate, entity_id);
CREATE FUNCTION retrieve_content(
p_gate INT,
p_entity_id UUID DEFAULT NULL,
p_embedding vector(1536) DEFAULT NULL,
p_limit INT DEFAULT 20
) RETURNS SETOF content AS $$
SELECT * FROM content
WHERE gate = p_gate
AND (p_entity_id IS NULL OR entity_id = p_entity_id)
ORDER BY CASE WHEN p_embedding IS NOT NULL
THEN embedding <=> p_embedding ELSE 0 END
LIMIT p_limit;
$$ LANGUAGE sql;
CREATE FUNCTION retrieve_cross_gate(
p_content_id UUID,
p_target_gate INT
) RETURNS SETOF content AS $$
SELECT c.* FROM content c
INNER JOIN suggested_edges e ON (
(e.source_content_id = p_content_id AND e.target_content_id = c.id)
OR (e.target_content_id = p_content_id AND e.source_content_id = c.id)
)
WHERE c.gate = p_target_gate AND e.status = 'approved'
ORDER BY e.confidence DESC;
$$ LANGUAGE sql;
Hard rules enforced at data layer:
Gate 4 → Gate 3 blocked structurally. No SQL function exists that allows Gate 4 content to appear in Gate 3 retrieval. This is architecture, not policy.
Cross-gate requires approved edge. The retrieve_cross_gate function INNER JOINs on suggested_edges WHERE status='approved'. No approved edge = no results. No exception path.
CREATE TABLE suggested_edges (
edge_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
source_content_id UUID NOT NULL REFERENCES content(id),
target_content_id UUID NOT NULL REFERENCES content(id),
edge_type TEXT NOT NULL CHECK (edge_type IN (
'same-topic','extends','contradicts',
'competitive-positioning','same-framework','updates'
)),
crosses_gates BOOLEAN NOT NULL DEFAULT FALSE,
source_gate INT NOT NULL,
target_gate INT NOT NULL,
confidence FLOAT NOT NULL CHECK (confidence >= 0 AND confidence <= 1),
reason TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'suggested' CHECK (status IN (
'suggested','approved','suppressed','deferred'
)),
reviewed_by TEXT,
pattern_id UUID,
suggested_at TIMESTAMPTZ NOT NULL DEFAULT now(),
reviewed_at TIMESTAMPTZ,
CONSTRAINT no_self_edge CHECK (source_content_id != target_content_id),
CONSTRAINT unique_edge UNIQUE (source_content_id, target_content_id, edge_type)
);
CREATE INDEX idx_edges_status ON suggested_edges(status);
CREATE INDEX idx_edges_pending ON suggested_edges(status)
WHERE status = 'suggested';
CREATE INDEX idx_edges_crosses ON suggested_edges(crosses_gates)
WHERE crosses_gates = TRUE;
Trigger: Runs after every content INSERT via Supabase trigger or n8n webhook.
def detect_same_gate_edges(new_content_id, gate, embedding):
similar = supabase.rpc('match_embeddings', {
'query_embedding': embedding,
'match_gate': gate,
'match_threshold': 0.6,
'match_count': 10,
'exclude_id': new_content_id
})
for match in similar:
edge_type = classify_edge(new_content, match)
confidence = match.similarity_score
if confidence > 0.85:
status = 'approved' # auto-approve same-gate high confidence
reviewed_by = 'auto'
else:
status = 'suggested' # surface for review
insert_edge(source=new_content_id, target=match.id,
edge_type=edge_type, crosses_gates=False,
confidence=confidence, status=status)
same-topic: Both discuss same subject. extends: New adds depth. updates: New supersedes older (same topic, newer date). contradicts: Disagreement. same-framework: Both reference same named methodology.
Trigger: n8n cron — daily at 2 AM CT, or manual trigger.
def detect_cross_gate_edges():
new_content = get_content_since(yesterday)
for item in new_content:
for target_gate in [1, 2, 3, 4]:
if target_gate == item.gate:
continue
# HARD BLOCK: Never suggest Gate 4 → Gate 3
if item.gate == 4 and target_gate == 3:
continue
similar = match_embeddings(
embedding=item.embedding,
gate=target_gate,
threshold=0.7, # higher for cross-gate
count=5
)
for match in similar:
insert_edge(
crosses_gates=True,
status='suggested', # ALWAYS review, never auto
...
)
notify_pending_count()
Forge sends pending edges one at a time. Format: "[Source: Gate 1 — HN article about agentic frameworks] ↔ [Target: Gate 2 — Samuel's coaching methodology] | Confidence: 0.73 | Type: same-framework". Buttons: ✅ Approve | ❌ Suppress | ⏸ Defer. Tap to decide — 5 seconds per edge.
Published at plan.jasondmacdonald.com/edge-review. Table of pending suggestions sorted by confidence DESC. Bulk approve/suppress/defer. Filter by gate pair, edge type, confidence range.
Forge reviews using prompt: "Should these two pieces of content from the same gate be connected? Would retrieving one when working with the other add value or noise?" Auto-approve if Forge confidence >0.9 AND same-gate. Auto-suppress if <0.3. Escalate to human if between 0.3-0.9 or cross-gate.
CREATE TABLE detection_patterns (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
pattern_type TEXT NOT NULL,
pattern_config JSONB NOT NULL,
weight FLOAT NOT NULL DEFAULT 0.5,
approve_count INT NOT NULL DEFAULT 0,
suppress_count INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT now(),
last_triggered TIMESTAMPTZ
);
On approve: weight += 0.05 (capped at 1.0). On suppress: weight -= 0.1 (floored at 0.0). Suppress decays faster than approve grows — conservative by design. Over time, patterns that produce approved edges lower the review threshold. Patterns that produce suppressed edges eventually stop triggering.
Trigger: Supabase webhook on INSERT to suggested_edges WHERE crosses_gates = TRUE.
MASTERYMADE — PRD 2 of 12 — plan.jasondmacdonald.com
Dominia Facta. Build what compounds.