Add full capability readiness matrix

This commit is contained in:
2026-06-30 14:37:02 +08:00
parent d9ea249ff0
commit 0c239483a9
8 changed files with 570 additions and 11 deletions

View File

@@ -193,6 +193,44 @@ type RuntimeReadinessPayload = {
};
};
type CapabilityDomain = {
id: string;
label: string;
ready: boolean;
tasks: {
total: number;
required: number;
required_ready: number;
examples: string[];
missing_required: string[];
unbuildable_required: string[];
};
runtime: Array<{ role: string; name: string; passed: boolean }>;
evidence: {
count: number;
artifacts: Array<{ name: string; relative_path: string; role?: string; family?: string }>;
curves: Array<{ name: string; relative_path: string; family?: string; row_count?: number }>;
};
gaps: string[];
};
type CapabilityPayload = {
passed: boolean;
generated_at: string;
summary: {
ready_domains: number;
total_domains: number;
mapped_user_scripts: number;
user_scripts_total: number;
uploaded_datasets: number;
artifacts: number;
curves: number;
weights: number;
};
requirements: Array<{ id: string; label: string; passed: boolean; detail: string }>;
domains: CapabilityDomain[];
};
async function api<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(`${API_BASE}${path}`, {
headers: { "Content-Type": "application/json" },
@@ -266,14 +304,16 @@ function useData() {
const [acceptance, setAcceptance] = useState<AcceptancePayload | null>(null);
const [deepAcceptance, setDeepAcceptance] = useState<DeepAcceptancePayload | null>(null);
const [runtimeReadiness, setRuntimeReadiness] = useState<RuntimeReadinessPayload | null>(null);
const [capabilities, setCapabilities] = useState<CapabilityPayload | null>(null);
const [error, setError] = useState<string>("");
async function refresh() {
try {
const [catalogNext, gpusNext, readinessNext, jobsNext, resultsNext, curvesNext, datasetsNext, coverageNext, acceptanceNext, deepAcceptanceNext] = await Promise.all([
const [catalogNext, gpusNext, readinessNext, capabilitiesNext, jobsNext, resultsNext, curvesNext, datasetsNext, coverageNext, acceptanceNext, deepAcceptanceNext] = await Promise.all([
api<Catalog>("/api/catalog"),
api<GpuPayload>("/api/system/gpus"),
api<RuntimeReadinessPayload>("/api/system/readiness"),
api<CapabilityPayload>("/api/capabilities"),
api<Job[]>("/api/jobs"),
api<ResultItem[]>("/api/results"),
api<TrainingCurve[]>("/api/results/curves"),
@@ -285,6 +325,7 @@ function useData() {
setCatalog(catalogNext);
setGpus(gpusNext);
setRuntimeReadiness(readinessNext);
setCapabilities(capabilitiesNext);
setJobs(jobsNext);
setResults(resultsNext.slice(0, 80));
setCurves(curvesNext.slice(0, 12));
@@ -316,7 +357,7 @@ function useData() {
return () => window.clearInterval(timer);
}, []);
return { catalog, gpus, runtimeReadiness, jobs, results, curves, datasets, datasetValidations, coverage, acceptance, deepAcceptance, error, refresh };
return { catalog, gpus, runtimeReadiness, capabilities, jobs, results, curves, datasets, datasetValidations, coverage, acceptance, deepAcceptance, error, refresh };
}
function StatusPill({ status }: { status: string }) {
@@ -339,7 +380,7 @@ function JobProgressBar({ progress }: { progress?: JobProgress }) {
}
function App() {
const { catalog, gpus, runtimeReadiness, jobs, results, curves, datasets, datasetValidations, coverage, acceptance, deepAcceptance, error, refresh } = useData();
const { catalog, gpus, runtimeReadiness, capabilities, jobs, results, curves, datasets, datasetValidations, coverage, acceptance, deepAcceptance, error, refresh } = useData();
const [taskType, setTaskType] = useState("mock.echo");
const [params, setParams] = useState(JSON.stringify(defaultParams["mock.echo"], null, 2));
const [selectedJob, setSelectedJob] = useState<Job | null>(null);
@@ -529,6 +570,7 @@ function App() {
</div>
<nav>
<a href="#jobs"><Terminal size={18} /></a>
<a href="#capabilities"><Gauge size={18} /></a>
<a href="#datasets"><Boxes size={18} /></a>
<a href="#gpu"><Cpu size={18} />GPU</a>
<a href="#runtime"><ShieldCheck size={18} /></a>
@@ -579,6 +621,48 @@ function App() {
</div>
</section>
<section className="panel" id="capabilities">
<div className="panelHead">
<div>
<p className="eyebrow">Capability Matrix</p>
<h2></h2>
</div>
<StatusPill status={capabilities?.passed ? "success" : "queued"} />
</div>
<div className="capSummary">
<div><span></span><strong>{capabilities?.summary.ready_domains ?? 0}/{capabilities?.summary.total_domains ?? 0}</strong></div>
<div><span></span><strong>{capabilities?.summary.mapped_user_scripts ?? 0}/{capabilities?.summary.user_scripts_total ?? 0}</strong></div>
<div><span></span><strong>{capabilities?.summary.uploaded_datasets ?? 0}</strong></div>
<div><span></span><strong>{capabilities?.summary.artifacts ?? 0}</strong></div>
<div><span>线</span><strong>{capabilities?.summary.curves ?? 0}</strong></div>
<div><span></span><strong>{capabilities?.summary.weights ?? 0}</strong></div>
</div>
<div className="capabilityGrid">
{(capabilities?.domains ?? []).map((domain) => (
<div key={domain.id} className={`capCard ${domain.ready ? "ok" : "bad"}`}>
<div className="capHead">
<strong>{domain.label}</strong>
<span>{domain.ready ? "READY" : "CHECK"}</span>
</div>
<div className="capNumbers">
<span>{domain.tasks.required_ready}/{domain.tasks.required} required</span>
<span>{domain.evidence.count} evidence</span>
</div>
<div className="capTags">
{domain.tasks.examples.slice(0, 4).map((task) => <small key={task}>{task}</small>)}
</div>
</div>
))}
</div>
<div className="requirementStrip">
{(capabilities?.requirements ?? []).map((item) => (
<span key={item.id} className={item.passed ? "ok" : "bad"} title={item.detail}>
{item.label}
</span>
))}
</div>
</section>
<section className="grid two" id="jobs">
<div className="panel taskPanel">
<div className="panelHead">