feat: add DeepSeek chat-template routing probe
This commit is contained in:
@@ -10,6 +10,8 @@ import rawMatched16Repro from "@/data/deepseek-v2-lite-routing-matched16-repro.j
|
||||
import rawMatched24 from "@/data/deepseek-v2-lite-routing-matched24.json";
|
||||
import rawMatched24Repro from "@/data/deepseek-v2-lite-routing-matched24-repro.json";
|
||||
import rawLengthSensitivity from "@/data/deepseek-v2-lite-routing-length-sensitivity.json";
|
||||
import rawTemplate from "@/data/deepseek-v2-lite-routing-template.json";
|
||||
import rawTemplateRepro from "@/data/deepseek-v2-lite-routing-template-repro.json";
|
||||
|
||||
const trace = rawTrace as any;
|
||||
const repro = rawRepro as any;
|
||||
@@ -22,10 +24,13 @@ const matched16Repro = rawMatched16Repro as any;
|
||||
const matched24 = rawMatched24 as any;
|
||||
const matched24Repro = rawMatched24Repro as any;
|
||||
const lengthSensitivity = rawLengthSensitivity as any;
|
||||
const template = rawTemplate as any;
|
||||
const templateRepro = rawTemplateRepro as any;
|
||||
const absorbExact = JSON.stringify(absorb) === JSON.stringify(absorbRepro);
|
||||
const corpusExact = JSON.stringify(corpus) === JSON.stringify(corpusRepro);
|
||||
const matched16Exact = JSON.stringify(matched16) === JSON.stringify(matched16Repro);
|
||||
const matched24Exact = JSON.stringify(matched24) === JSON.stringify(matched24Repro);
|
||||
const templateExact = JSON.stringify(template) === JSON.stringify(templateRepro);
|
||||
const bytes = (value: number) => value >= 1024
|
||||
? `${(value / 1024).toFixed(2)} KiB`
|
||||
: `${value.toLocaleString()} B`;
|
||||
@@ -82,6 +87,63 @@ const corpusCompact = {
|
||||
lengthSensitivity,
|
||||
};
|
||||
const corpusCompactJson = JSON.stringify(corpusCompact).replaceAll("<", "\\u003c");
|
||||
const aggregateTemplateAlignment = (layer: any, domain: string) => {
|
||||
const rows = layer.prompts
|
||||
.filter((prompt: any) => prompt.domain === domain)
|
||||
.map((prompt: any) => prompt.alignments.raw_to_user_content);
|
||||
const aligned = rows.reduce((sum: number, row: any) => sum + row.aligned_tokens, 0);
|
||||
const setExact = rows.reduce((sum: number, row: any) => sum + row.set_topk_exact, 0);
|
||||
const orderedExact = rows.reduce((sum: number, row: any) => sum + row.ordered_topk_exact, 0);
|
||||
const weightedJaccard = rows.reduce(
|
||||
(sum: number, row: any) => sum + row.mean_jaccard * row.aligned_tokens,
|
||||
0,
|
||||
);
|
||||
return {
|
||||
aligned,
|
||||
setExactRate: setExact / aligned,
|
||||
orderedExactRate: orderedExact / aligned,
|
||||
meanJaccard: weightedJaccard / aligned,
|
||||
};
|
||||
};
|
||||
const templateCompact = {
|
||||
domains: template.corpus_contract.domains,
|
||||
labels: template.corpus_contract.domain_labels,
|
||||
inference: template.inference_contract,
|
||||
template: {
|
||||
sha256: template.template_contract.chat_template_sha256,
|
||||
bos: template.template_contract.bos_token_id,
|
||||
},
|
||||
exact: templateExact,
|
||||
layers: template.layers.slice(1).map((layer: any) => ({
|
||||
layer: layer.layer,
|
||||
invariant: layer.causal_suffix_invariant,
|
||||
alignment: Object.fromEntries(
|
||||
template.corpus_contract.domains.map((domain: string) => [
|
||||
domain,
|
||||
aggregateTemplateAlignment(layer, domain),
|
||||
]),
|
||||
),
|
||||
scopes: Object.fromEntries(
|
||||
["content_only", "full_input"].map((scope) => [
|
||||
scope,
|
||||
{
|
||||
modes: Object.fromEntries(
|
||||
["prompt_balanced", "token_weighted"].map((mode) => [
|
||||
mode,
|
||||
{
|
||||
rawToUser: layer.statistics[scope].modes[mode]
|
||||
.comparisons.raw_to_user,
|
||||
userToGeneration: layer.statistics[scope].modes[mode]
|
||||
.comparisons.user_to_generation,
|
||||
},
|
||||
]),
|
||||
),
|
||||
},
|
||||
]),
|
||||
),
|
||||
})),
|
||||
};
|
||||
const templateCompactJson = JSON.stringify(templateCompact).replaceAll("<", "\\u003c");
|
||||
const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoint_tensor_bytes;
|
||||
---
|
||||
|
||||
@@ -93,7 +155,7 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
</div>
|
||||
<p>
|
||||
固定官方 revision、tokenizer、模型代码和 BF16 第一分片;RTX 5090 连续执行 layer 0–6,
|
||||
从 3,240 次 token 显微轨迹扩到 488,880 次公开语料路由,并让 layer-1 权重继续走入官方吸收式 cache。
|
||||
从 3,240 次 token 显微轨迹扩到 870,912 次公开语料路由,并让 layer-1 权重继续走入官方吸收式 cache。
|
||||
所有结论都带证据身份与停止线。
|
||||
</p>
|
||||
</header>
|
||||
@@ -121,8 +183,11 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
<button type="button" role="tab" data-artifact-tab="corpus" aria-selected="false" tabindex="-1">
|
||||
<span>05</span><b>128 样本区间</b><small>4 domains · bootstrap</small>
|
||||
</button>
|
||||
<button type="button" role="tab" data-artifact-tab="template" aria-selected="false" tabindex="-1">
|
||||
<span>06</span><b>官方模板扰动</b><small>raw → user → assistant</small>
|
||||
</button>
|
||||
<button type="button" role="tab" data-artifact-tab="evidence" aria-selected="false" tabindex="-1">
|
||||
<span>06</span><b>证据断面</b><small>revision · shards · rerun</small>
|
||||
<span>07</span><b>证据断面</b><small>revision · shards · rerun</small>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -541,6 +606,117 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="artifact-panel" data-artifact-panel="template" hidden>
|
||||
<div class="panel-lead">
|
||||
<div><span>X / OFFICIAL CHAT TEMPLATE</span><h4>同一段内容,只在前面加上「User:」</h4></div>
|
||||
<p>
|
||||
三种输入使用同一 checkpoint、同一批 128 条 source prompt、同一 padded batch。
|
||||
既比较真实整段输入,也只比较字符跨度与 token ID 都完全对齐的 2,874 个内容 token。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="template-ledger">
|
||||
<article><span>SOURCE PROMPTS</span><b>128</b><p>四域 × 32 · 固定哈希选样</p></article>
|
||||
<article><span>PROMPT VARIANTS</span><b>384</b><p>raw · user · generation</p></article>
|
||||
<article><span>INPUT TOKENS</span><b>10,612</b><p>三种协议的真实输入总数</p></article>
|
||||
<article><span>REAL ROUTES</span><b>382,032</b><p>三种协议 × 前六个 MoE 层</p></article>
|
||||
<article><span>CAUSAL PREFIX</span><b>21,852 / 21,852</b><p>追加 Assistant: 后 ordered top-6 exact</p></article>
|
||||
<article class="exact"><span>INDEPENDENT RERUN</span><b>{templateExact ? "BYTE-EXACT" : "MISMATCH"}</b><p>完整 JSON SHA-256 da1f1033…bc1b9</p></article>
|
||||
</div>
|
||||
|
||||
<div class="template-protocol" aria-label="DeepSeek V2-Lite 三种输入协议">
|
||||
<article>
|
||||
<span>RAW</span>
|
||||
<div><i>BOS</i><b>相同内容</b></div>
|
||||
<p>每条固定 24 input tokens:1 BOS + 23 content。</p>
|
||||
</article>
|
||||
<i aria-hidden="true">→</i>
|
||||
<article>
|
||||
<span>OFFICIAL USER</span>
|
||||
<div><i>BOS</i><em>User:</em><b>相同内容</b><small>↵↵</small></div>
|
||||
<p><code>apply_chat_template</code> 的单轮 user 渲染。</p>
|
||||
</article>
|
||||
<i aria-hidden="true">→</i>
|
||||
<article>
|
||||
<span>GENERATION PROMPT</span>
|
||||
<div><i>共享前缀</i><em>Assistant:</em></div>
|
||||
<p>只在末尾追加 suffix;不能反向改变此前 token。</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="template-controls">
|
||||
<div>
|
||||
<span>MOE LAYER</span>
|
||||
<div class="layer-switch template-layer-switch" role="group" aria-label="选择模板敏感性层">
|
||||
{[1, 2, 3, 4, 5, 6].map((layer) => (
|
||||
<button type="button" data-template-layer={layer} class={layer === 1 ? "active" : ""}>L{layer}</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>MEASUREMENT SCOPE</span>
|
||||
<div class="template-scope-switch" role="group" aria-label="选择模板统计范围">
|
||||
<button type="button" data-template-scope="content_only" aria-pressed="true">精确对齐内容</button>
|
||||
<button type="button" data-template-scope="full_input" aria-pressed="false">完整输入</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>AGGREGATION</span>
|
||||
<div class="template-mode-switch" role="group" aria-label="选择模板聚合口径">
|
||||
<button type="button" data-template-mode="prompt_balanced" aria-pressed="true">prompt 等权</button>
|
||||
<button type="button" data-template-mode="token_weighted" aria-pressed="false">token 加权</button>
|
||||
</div>
|
||||
</div>
|
||||
<p data-template-note>
|
||||
精确对齐内容:三种条件只保留相同相对字符跨度与相同 token ID;wrapper 和边界重切分 token 同时剔除。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="template-domain-grid" data-template-domain-grid></div>
|
||||
|
||||
<div class="template-negative-control">
|
||||
<article>
|
||||
<span>USER → GENERATION / SHARED PREFIX</span>
|
||||
<b data-template-prefix-exact></b>
|
||||
<p>同一 batch 内逐 token ordered top-6;未来 suffix 不得改写过去。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span>CONTENT-ONLY DELTA</span>
|
||||
<b data-template-content-zero></b>
|
||||
<p>CV Δ / TV / JSD;对齐内容不包含新追加的 Assistant:。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span>FULL-INPUT TV</span>
|
||||
<b data-template-suffix-tv></b>
|
||||
<p>整段统计会变化,因为 generation 条件确实加入了新的 suffix token。</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="template-depth">
|
||||
<div>
|
||||
<span>DEPTH MAP / Δ CV(USER − RAW)</span>
|
||||
<h5>角色前缀没有一个跨层恒定方向</h5>
|
||||
<p>每格是一层;绿色表示 USER 更平,红色表示 USER 更集中。切换 scope / aggregation 后重新计算。</p>
|
||||
</div>
|
||||
<div data-template-depth-map></div>
|
||||
</div>
|
||||
|
||||
<div class="evidence-links">
|
||||
<a href="https://huggingface.co/deepseek-ai/DeepSeek-V2-Lite/blob/main/tokenizer_config.json" rel="noreferrer">官方 tokenizer_config ↗</a>
|
||||
<a href="https://huggingface.co/deepseek-ai/DeepSeek-V2-Lite" rel="noreferrer">官方 V2-Lite 模型卡 ↗</a>
|
||||
<a href="https://arxiv.org/abs/2405.04434" rel="noreferrer">DeepSeek-V2 技术报告 ↗</a>
|
||||
</div>
|
||||
|
||||
<div class="artifact-boundary">
|
||||
<b>PROTOCOL SENSITIVITY, NOT CAPABILITY</b>
|
||||
<p>
|
||||
RAW→USER 的变化只描述固定 23-content-token 探针中的协议敏感性;不能命名专家,
|
||||
不能推出完整 27 层或线上对话流量,也没有生成答案。USER→GENERATION 的共享前缀 exact
|
||||
是 causal-mask 实现负对照,不是“Assistant: 没有作用”——新增 suffix 自己仍有路由。
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="artifact-panel" data-artifact-panel="evidence" hidden>
|
||||
<div class="panel-lead">
|
||||
<div><span>O + X / EVIDENCE SLICE</span><h4>为什么执行到 layer 6 就停,而不是把“部分下载”写成“完整复现”</h4></div>
|
||||
@@ -632,11 +808,14 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
<code>experiments/deepseek/v2_lite_absorb_probe.py</code> ·
|
||||
<code>experiments/deepseek/v2_lite_routing_corpus.py</code> ·
|
||||
<code>experiments/deepseek/compare_routing_length_control.py</code> ·
|
||||
<code>research/DEEPSEEK_ROUTING_LENGTH_CONTROL_AUDIT.md</code>
|
||||
<code>research/DEEPSEEK_ROUTING_LENGTH_CONTROL_AUDIT.md</code> ·
|
||||
<code>experiments/deepseek/v2_lite_routing_template_probe.py</code> ·
|
||||
<code>research/DEEPSEEK_ROUTING_TEMPLATE_AUDIT.md</code>
|
||||
</figcaption>
|
||||
|
||||
<script is:inline type="application/json" data-dsv2-trace set:html={compactJson}></script>
|
||||
<script is:inline type="application/json" data-dsv2-corpus set:html={corpusCompactJson}></script>
|
||||
<script is:inline type="application/json" data-dsv2-template set:html={templateCompactJson}></script>
|
||||
</figure>
|
||||
|
||||
<script>
|
||||
@@ -649,9 +828,11 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
};
|
||||
const payloadNode = one<HTMLScriptElement>("[data-dsv2-trace]");
|
||||
const corpusNode = one<HTMLScriptElement>("[data-dsv2-corpus]");
|
||||
if (!payloadNode?.textContent || !corpusNode?.textContent) return;
|
||||
const templateNode = one<HTMLScriptElement>("[data-dsv2-template]");
|
||||
if (!payloadNode?.textContent || !corpusNode?.textContent || !templateNode?.textContent) return;
|
||||
const data = JSON.parse(payloadNode.textContent);
|
||||
const corpusData = JSON.parse(corpusNode.textContent);
|
||||
const templateData = JSON.parse(templateNode.textContent);
|
||||
|
||||
const tabs = all<HTMLButtonElement>("[data-artifact-tab]");
|
||||
const panels = all<HTMLElement>("[data-artifact-panel]");
|
||||
@@ -1088,6 +1269,142 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
});
|
||||
});
|
||||
renderCorpus();
|
||||
|
||||
let templateLayerNumber = 1;
|
||||
let templateScope = "content_only";
|
||||
let templateMode = "prompt_balanced";
|
||||
const templateResult = (layerNumber: number, domain: string) => {
|
||||
const layer = templateData.layers.find((item: any) => item.layer === layerNumber);
|
||||
return {
|
||||
layer,
|
||||
comparison: layer.scopes[templateScope].modes[templateMode].rawToUser[domain],
|
||||
suffix: layer.scopes.full_input.modes[templateMode].userToGeneration[domain],
|
||||
contentSuffix: layer.scopes.content_only.modes[templateMode]
|
||||
.userToGeneration[domain],
|
||||
alignment: layer.alignment[domain],
|
||||
};
|
||||
};
|
||||
const deltaClass = (ci: number[]) =>
|
||||
ci[1] < 0 ? "down" : ci[0] > 0 ? "up" : "neutral";
|
||||
const renderTemplate = () => {
|
||||
all<HTMLButtonElement>("[data-template-layer]").forEach((button) => {
|
||||
button.classList.toggle(
|
||||
"active",
|
||||
Number(button.dataset.templateLayer) === templateLayerNumber,
|
||||
);
|
||||
});
|
||||
all<HTMLButtonElement>("[data-template-scope]").forEach((button) => {
|
||||
button.setAttribute(
|
||||
"aria-pressed",
|
||||
String(button.dataset.templateScope === templateScope),
|
||||
);
|
||||
});
|
||||
all<HTMLButtonElement>("[data-template-mode]").forEach((button) => {
|
||||
button.setAttribute(
|
||||
"aria-pressed",
|
||||
String(button.dataset.templateMode === templateMode),
|
||||
);
|
||||
});
|
||||
set(
|
||||
"[data-template-note]",
|
||||
templateScope === "content_only"
|
||||
? "精确对齐内容:三种条件只保留相同相对字符跨度与相同 token ID;wrapper 和边界重切分 token 同时剔除。"
|
||||
: "完整输入:BOS、User:、换行与 content 全部进入统计;它回答真实协议流量,不等同于内容本身的变化。",
|
||||
);
|
||||
|
||||
const grid = one<HTMLElement>("[data-template-domain-grid]");
|
||||
if (grid) {
|
||||
grid.replaceChildren(...templateData.domains.map((domain: string) => {
|
||||
const result = templateResult(templateLayerNumber, domain);
|
||||
const cv = result.comparison.metrics.cv;
|
||||
const card = document.createElement("article");
|
||||
const label = document.createElement("span");
|
||||
const values = document.createElement("b");
|
||||
const delta = document.createElement("strong");
|
||||
const ci = document.createElement("p");
|
||||
const distance = document.createElement("small");
|
||||
const stability = document.createElement("em");
|
||||
label.textContent = corpusLabels[domain];
|
||||
values.textContent = `${cv.before.toFixed(3)} → ${cv.after.toFixed(3)}`;
|
||||
delta.textContent = `Δ ${signed(cv.delta_after_minus_before)}`;
|
||||
delta.className = deltaClass(cv.delta_ci95);
|
||||
ci.textContent = `paired 95% ${formatSignedCi(cv.delta_ci95)}`;
|
||||
distance.textContent = `TV ${result.comparison.total_variation.point.toFixed(3)} · JSD ${result.comparison.js_divergence.point.toFixed(3)}`;
|
||||
stability.textContent = `aligned ${result.alignment.aligned} · top-6 set exact ${(result.alignment.setExactRate * 100).toFixed(1)}% · J ${result.alignment.meanJaccard.toFixed(3)}`;
|
||||
card.append(label, values, delta, ci, distance, stability);
|
||||
return card;
|
||||
}));
|
||||
}
|
||||
|
||||
const currentLayer = templateData.layers.find(
|
||||
(item: any) => item.layer === templateLayerNumber,
|
||||
);
|
||||
set(
|
||||
"[data-template-prefix-exact]",
|
||||
`${currentLayer.invariant.ordered_topk_exact.toLocaleString()} / ${currentLayer.invariant.shared_prefix_tokens.toLocaleString()} EXACT · L${templateLayerNumber}`,
|
||||
);
|
||||
const contentSuffixZero = templateData.domains.every((domain: string) => {
|
||||
const result = templateResult(templateLayerNumber, domain).contentSuffix;
|
||||
return result.metrics.cv.delta_after_minus_before === 0
|
||||
&& result.total_variation.point === 0
|
||||
&& result.js_divergence.point === 0;
|
||||
});
|
||||
set(
|
||||
"[data-template-content-zero]",
|
||||
contentSuffixZero ? "4 / 4 DOMAINS · Δ 0" : "CHECK FAILED",
|
||||
);
|
||||
const suffixTv = templateData.domains.map(
|
||||
(domain: string) =>
|
||||
templateResult(templateLayerNumber, domain).suffix.total_variation.point,
|
||||
);
|
||||
set(
|
||||
"[data-template-suffix-tv]",
|
||||
`${Math.min(...suffixTv).toFixed(3)}–${Math.max(...suffixTv).toFixed(3)} · L${templateLayerNumber}`,
|
||||
);
|
||||
|
||||
const depth = one<HTMLElement>("[data-template-depth-map]");
|
||||
if (depth) {
|
||||
depth.replaceChildren(...templateData.domains.map((domain: string) => {
|
||||
const row = document.createElement("div");
|
||||
const label = document.createElement("b");
|
||||
label.textContent = corpusLabels[domain];
|
||||
row.append(label);
|
||||
templateData.layers.forEach((layer: any) => {
|
||||
const cv = layer.scopes[templateScope].modes[templateMode]
|
||||
.rawToUser[domain].metrics.cv;
|
||||
const cell = document.createElement("span");
|
||||
cell.className = deltaClass(cv.delta_ci95);
|
||||
cell.style.setProperty(
|
||||
"--strength",
|
||||
String(Math.min(1, Math.abs(cv.delta_after_minus_before) / 0.14)),
|
||||
);
|
||||
cell.textContent = `L${layer.layer} ${signed(cv.delta_after_minus_before)}`;
|
||||
cell.title = `${corpusLabels[domain]} · L${layer.layer} · Δ CV ${signed(cv.delta_after_minus_before)} · paired 95% ${formatSignedCi(cv.delta_ci95)}`;
|
||||
row.append(cell);
|
||||
});
|
||||
return row;
|
||||
}));
|
||||
}
|
||||
};
|
||||
all<HTMLButtonElement>("[data-template-layer]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
templateLayerNumber = Number(button.dataset.templateLayer);
|
||||
renderTemplate();
|
||||
});
|
||||
});
|
||||
all<HTMLButtonElement>("[data-template-scope]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
templateScope = button.dataset.templateScope ?? "content_only";
|
||||
renderTemplate();
|
||||
});
|
||||
});
|
||||
all<HTMLButtonElement>("[data-template-mode]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
templateMode = button.dataset.templateMode ?? "prompt_balanced";
|
||||
renderTemplate();
|
||||
});
|
||||
});
|
||||
renderTemplate();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1137,7 +1454,13 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.corpus-heat-head span,
|
||||
.corpus-comparison span,
|
||||
.corpus-findings span,
|
||||
.length-sensitivity span {
|
||||
.length-sensitivity span,
|
||||
.template-ledger span,
|
||||
.template-protocol > article > span,
|
||||
.template-controls > div > span,
|
||||
.template-domain-grid > :global(article > span),
|
||||
.template-negative-control span,
|
||||
.template-depth span {
|
||||
margin: 0;
|
||||
color: var(--blue);
|
||||
font: 700 .69rem/1.3 var(--font-mono);
|
||||
@@ -1191,7 +1514,7 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.artifact-status b { color: var(--ink); font-size: .72rem; }
|
||||
.artifact-tabs {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
background: var(--ink);
|
||||
}
|
||||
.artifact-tabs button {
|
||||
@@ -1787,6 +2110,237 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
font-size: .63rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.template-ledger {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
border: 1px solid rgba(32,32,39,.14);
|
||||
}
|
||||
.template-ledger article {
|
||||
padding: .85rem;
|
||||
border-right: 1px solid rgba(32,32,39,.12);
|
||||
}
|
||||
.template-ledger article:last-child { border-right: 0; }
|
||||
.template-ledger article.exact { background: rgba(57,120,110,.1); }
|
||||
.template-ledger b {
|
||||
display: block;
|
||||
margin-top: .4rem;
|
||||
font: 750 1.05rem/1.05 var(--font-display);
|
||||
}
|
||||
.template-ledger p {
|
||||
margin: .3rem 0 0;
|
||||
color: rgba(32,32,39,.56);
|
||||
font-size: .61rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.template-protocol {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1.3fr auto 1.15fr;
|
||||
gap: .55rem;
|
||||
align-items: stretch;
|
||||
margin-top: .8rem;
|
||||
}
|
||||
.template-protocol > i {
|
||||
align-self: center;
|
||||
color: rgba(32,32,39,.35);
|
||||
font-style: normal;
|
||||
}
|
||||
.template-protocol article {
|
||||
padding: .9rem;
|
||||
border: 1px solid rgba(32,32,39,.14);
|
||||
background: #fffdf8;
|
||||
}
|
||||
.template-protocol article > div {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .22rem;
|
||||
margin-top: .55rem;
|
||||
}
|
||||
.template-protocol article > div > * {
|
||||
padding: .35rem .45rem;
|
||||
border: 1px solid rgba(32,32,39,.14);
|
||||
font: 650 .66rem/1 var(--font-mono);
|
||||
font-style: normal;
|
||||
}
|
||||
.template-protocol article > div > i { background: var(--ink); color: white; }
|
||||
.template-protocol article > div > em { background: rgba(98,105,155,.15); color: var(--blue); }
|
||||
.template-protocol article > div > b { background: rgba(57,120,110,.12); color: var(--teal); }
|
||||
.template-protocol article > div > small { color: rgba(32,32,39,.58); }
|
||||
.template-protocol p {
|
||||
margin: .55rem 0 0;
|
||||
color: rgba(32,32,39,.58);
|
||||
font-size: .64rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.template-controls {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1.15fr 1fr;
|
||||
gap: 1rem;
|
||||
align-items: end;
|
||||
margin-top: .8rem;
|
||||
padding: .85rem;
|
||||
border: 1px solid rgba(32,32,39,.14);
|
||||
background: #e8e2d7;
|
||||
}
|
||||
.template-controls > div { display: grid; gap: .45rem; }
|
||||
.template-controls .layer-switch { margin: 0; }
|
||||
.template-scope-switch,
|
||||
.template-mode-switch { display: flex; }
|
||||
.template-scope-switch button,
|
||||
.template-mode-switch button {
|
||||
padding: .58rem .72rem;
|
||||
border: 1px solid rgba(32,32,39,.22);
|
||||
background: #fffdf8;
|
||||
color: var(--ink);
|
||||
font: 650 .65rem/1 var(--font-mono);
|
||||
cursor: pointer;
|
||||
}
|
||||
.template-scope-switch button + button,
|
||||
.template-mode-switch button + button { border-left: 0; }
|
||||
.template-scope-switch button[aria-pressed="true"],
|
||||
.template-mode-switch button[aria-pressed="true"] {
|
||||
border-color: var(--blue);
|
||||
background: var(--blue);
|
||||
color: white;
|
||||
}
|
||||
.template-controls > p {
|
||||
grid-column: 1 / -1;
|
||||
margin: 0;
|
||||
padding-top: .75rem;
|
||||
border-top: 1px solid rgba(32,32,39,.12);
|
||||
color: rgba(32,32,39,.62);
|
||||
font-size: .69rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.template-domain-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
margin-top: .8rem;
|
||||
border: 1px solid rgba(32,32,39,.14);
|
||||
background: #fffdf8;
|
||||
}
|
||||
.template-domain-grid > :global(article) {
|
||||
padding: .85rem;
|
||||
border-right: 1px solid rgba(32,32,39,.12);
|
||||
}
|
||||
.template-domain-grid > :global(article:last-child) { border-right: 0; }
|
||||
.template-domain-grid > :global(article > b) {
|
||||
display: block;
|
||||
margin-top: .45rem;
|
||||
font: 730 .88rem/1.1 var(--font-mono);
|
||||
}
|
||||
.template-domain-grid > :global(article > strong) {
|
||||
display: inline-block;
|
||||
margin-top: .4rem;
|
||||
padding: .24rem .38rem;
|
||||
font: 750 .7rem/1 var(--font-mono);
|
||||
}
|
||||
.template-domain-grid > :global(article > strong.down),
|
||||
.template-depth :global(span.down) {
|
||||
background: rgba(57,120,110,.13);
|
||||
color: var(--teal);
|
||||
}
|
||||
.template-domain-grid > :global(article > strong.up),
|
||||
.template-depth :global(span.up) {
|
||||
background: rgba(161,77,77,.12);
|
||||
color: var(--red);
|
||||
}
|
||||
.template-domain-grid > :global(article > strong.neutral),
|
||||
.template-depth :global(span.neutral) {
|
||||
background: rgba(186,118,44,.12);
|
||||
color: var(--amber);
|
||||
}
|
||||
.template-domain-grid > :global(article > p) {
|
||||
margin: .4rem 0 0;
|
||||
color: rgba(32,32,39,.56);
|
||||
font: .59rem/1.4 var(--font-mono);
|
||||
}
|
||||
.template-domain-grid > :global(article > small),
|
||||
.template-domain-grid > :global(article > em) {
|
||||
display: block;
|
||||
margin-top: .35rem;
|
||||
color: rgba(32,32,39,.57);
|
||||
font: .58rem/1.4 var(--font-mono);
|
||||
font-style: normal;
|
||||
}
|
||||
.template-domain-grid > :global(article > em) {
|
||||
padding-top: .35rem;
|
||||
border-top: 1px solid rgba(32,32,39,.1);
|
||||
}
|
||||
.template-negative-control {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
margin-top: .8rem;
|
||||
border: 1px solid rgba(32,32,39,.14);
|
||||
background:
|
||||
linear-gradient(115deg, rgba(57,120,110,.11), transparent 48%),
|
||||
#e8e2d7;
|
||||
}
|
||||
.template-negative-control article {
|
||||
padding: .9rem;
|
||||
border-right: 1px solid rgba(32,32,39,.12);
|
||||
}
|
||||
.template-negative-control article:last-child { border-right: 0; }
|
||||
.template-negative-control b {
|
||||
display: block;
|
||||
margin-top: .4rem;
|
||||
font: 730 .88rem/1.1 var(--font-mono);
|
||||
}
|
||||
.template-negative-control p {
|
||||
margin: .4rem 0 0;
|
||||
color: rgba(32,32,39,.58);
|
||||
font-size: .64rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.template-depth {
|
||||
display: grid;
|
||||
grid-template-columns: .55fr 1.45fr;
|
||||
gap: 1rem;
|
||||
margin-top: .8rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid rgba(32,32,39,.14);
|
||||
}
|
||||
.template-depth h5 {
|
||||
margin: .4rem 0;
|
||||
font: 720 1rem/1.15 var(--font-display);
|
||||
}
|
||||
.template-depth p {
|
||||
margin: 0;
|
||||
color: rgba(32,32,39,.58);
|
||||
font-size: .66rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.template-depth > :global([data-template-depth-map]) {
|
||||
display: grid;
|
||||
gap: .35rem;
|
||||
}
|
||||
.template-depth :global([data-template-depth-map] > div) {
|
||||
display: grid;
|
||||
grid-template-columns: 5.5rem repeat(6, 1fr);
|
||||
gap: .25rem;
|
||||
}
|
||||
.template-depth :global([data-template-depth-map] > div > b),
|
||||
.template-depth :global([data-template-depth-map] > div > span) {
|
||||
display: grid;
|
||||
align-items: center;
|
||||
min-height: 2.2rem;
|
||||
padding: .35rem;
|
||||
font: 650 .57rem/1.2 var(--font-mono);
|
||||
}
|
||||
.template-depth :global([data-template-depth-map] > div > b) {
|
||||
color: var(--blue);
|
||||
}
|
||||
.template-depth :global([data-template-depth-map] > div > span.down) {
|
||||
background: color-mix(in srgb, var(--teal) calc(var(--strength) * 55%), #eef0e9);
|
||||
color: var(--ink);
|
||||
}
|
||||
.template-depth :global([data-template-depth-map] > div > span.up) {
|
||||
background: color-mix(in srgb, var(--red) calc(var(--strength) * 48%), #f3ebe6);
|
||||
color: var(--ink);
|
||||
}
|
||||
.template-depth :global([data-template-depth-map] > div > span.neutral) {
|
||||
background: rgba(186,118,44,.1);
|
||||
color: var(--ink);
|
||||
}
|
||||
.observed-cache {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1.25fr;
|
||||
@@ -2022,7 +2576,10 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.corpus-controls,
|
||||
.corpus-heat-head,
|
||||
.corpus-comparison,
|
||||
.length-sensitivity-head { grid-template-columns: 1fr; }
|
||||
.length-sensitivity-head,
|
||||
.template-protocol,
|
||||
.template-controls,
|
||||
.template-depth { grid-template-columns: 1fr; }
|
||||
.artifact-status { grid-template-columns: 1fr 1fr; }
|
||||
.artifact-tabs { grid-template-columns: 1fr 1fr; }
|
||||
.route-controls { grid-template-columns: 1fr 1fr; }
|
||||
@@ -2034,6 +2591,9 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.checksum-grid,
|
||||
.absorb-metrics { grid-template-columns: 1fr 1fr; }
|
||||
.corpus-ledger { grid-template-columns: repeat(3, 1fr); }
|
||||
.template-ledger { grid-template-columns: repeat(3, 1fr); }
|
||||
.template-domain-grid { grid-template-columns: 1fr 1fr; }
|
||||
.template-protocol > i { transform: rotate(90deg); justify-self: center; }
|
||||
.length-delta-grid { grid-template-columns: 1fr 1fr; }
|
||||
.corpus-heat-head p { text-align: left; }
|
||||
.layer-evidence { grid-template-columns: repeat(9, 1fr); }
|
||||
@@ -2065,7 +2625,10 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.corpus-ledger,
|
||||
.corpus-findings,
|
||||
.length-delta-grid,
|
||||
.length-pair-summary { grid-template-columns: 1fr; }
|
||||
.length-pair-summary,
|
||||
.template-ledger,
|
||||
.template-domain-grid,
|
||||
.template-negative-control { grid-template-columns: 1fr; }
|
||||
.route-metrics article,
|
||||
.cache-ratio article,
|
||||
.load-lessons article,
|
||||
@@ -2073,11 +2636,18 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.artifact-identity article,
|
||||
.checksum-grid article { border-right: 0; border-bottom: 1px solid rgba(32,32,39,.12); }
|
||||
.corpus-ledger article,
|
||||
.corpus-findings article { border-right: 0; border-bottom: 1px solid rgba(32,32,39,.12); }
|
||||
.corpus-findings article,
|
||||
.template-ledger article,
|
||||
.template-domain-grid > :global(article),
|
||||
.template-negative-control article { border-right: 0; border-bottom: 1px solid rgba(32,32,39,.12); }
|
||||
.corpus-mode-switch,
|
||||
.corpus-cohort-switch { display: grid; grid-template-columns: 1fr; }
|
||||
.corpus-cohort-switch,
|
||||
.template-scope-switch,
|
||||
.template-mode-switch { display: grid; grid-template-columns: 1fr; }
|
||||
.corpus-mode-switch button + button,
|
||||
.corpus-cohort-switch button + button { border-left: 1px solid rgba(32,32,39,.22); border-top: 0; }
|
||||
.corpus-cohort-switch button + button,
|
||||
.template-scope-switch button + button,
|
||||
.template-mode-switch button + button { border-left: 1px solid rgba(32,32,39,.22); border-top: 0; }
|
||||
.length-delta-grid > :global(article),
|
||||
.length-pair-summary article { border-right: 0; border-bottom: 1px solid rgba(32,32,39,.11); }
|
||||
.artifact-boundary { grid-template-columns: 1fr; }
|
||||
@@ -2092,6 +2662,8 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.absorb-cache-flow > i { transform: rotate(90deg); justify-self: center; }
|
||||
.precision-lens > div { grid-template-columns: 1fr; }
|
||||
.precision-lens b { text-align: left; }
|
||||
.template-depth { overflow-x: auto; }
|
||||
.template-depth > :global([data-template-depth-map]) { min-width: 620px; }
|
||||
.layer-evidence { grid-template-columns: repeat(7, 1fr); }
|
||||
.repro-gate { grid-template-columns: 1fr; }
|
||||
.repro-gate > p { grid-column: auto; }
|
||||
|
||||
Reference in New Issue
Block a user