diff --git a/decnet_web/src/components/Config.tsx b/decnet_web/src/components/Config.tsx
index fe438382..fa194020 100644
--- a/decnet_web/src/components/Config.tsx
+++ b/decnet_web/src/components/Config.tsx
@@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
import api from '../utils/api';
import { Settings, Users, Sliders, Trash2, UserPlus, Key, Save, Shield, AlertTriangle, Palette, Activity, Square, RefreshCw, Play } from '../icons';
import { useToast } from './Toasts/useToast';
+import RuleStateControls from './RuleStateControls';
import './Dashboard.css';
import './Config.css';
@@ -238,6 +239,7 @@ const Config: React.FC = () => {
{ key: 'globals', label: 'GLOBAL VALUES', icon:
},
{ key: 'appearance', label: 'APPEARANCE', icon:
},
...(isAdmin ? [{ key: 'workers', label: 'WORKERS', icon:
}] : []),
+ ...(isAdmin ? [{ key: 'ttp', label: 'TTP RULES', icon:
}] : []),
];
return (
@@ -494,6 +496,12 @@ const Config: React.FC = () => {
)}
+ {/* TTP RULES TAB — admin only. RuleStateControls also self-gates
+ on /config?.role so a state leak can't render it. */}
+ {activeTab === 'ttp' && isAdmin && (
+
+ )}
+
{/* APPEARANCE TAB */}
{activeTab === 'appearance' && (
diff --git a/decnet_web/src/components/IdentityDetail.tsx b/decnet_web/src/components/IdentityDetail.tsx
index 8a46fee7..84474e4a 100644
--- a/decnet_web/src/components/IdentityDetail.tsx
+++ b/decnet_web/src/components/IdentityDetail.tsx
@@ -3,6 +3,7 @@ import { useParams, useNavigate } from 'react-router-dom';
import { ArrowLeft, Crosshair, Filter, Fingerprint, Globe, Radio } from '../icons';
import api from '../utils/api';
import EmptyState from './EmptyState/EmptyState';
+import TTPsObservedSection from './TTPsObservedSection';
import { useIdentityStream } from './useIdentityStream';
import './Dashboard.css';
@@ -195,6 +196,8 @@ const IdentityDetail: React.FC = () => {
+