feat: execute DeepSeek absorbed MLA cache
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
---
|
||||
import rawTrace from "@/data/deepseek-v2-lite-trace.json";
|
||||
import rawRepro from "@/data/deepseek-v2-lite-trace-repro.json";
|
||||
import rawAbsorb from "@/data/deepseek-v2-lite-absorb.json";
|
||||
import rawAbsorbRepro from "@/data/deepseek-v2-lite-absorb-repro.json";
|
||||
|
||||
const trace = rawTrace as any;
|
||||
const repro = rawRepro as any;
|
||||
const absorb = rawAbsorb as any;
|
||||
const absorbRepro = rawAbsorbRepro as any;
|
||||
const absorbExact = JSON.stringify(absorb) === JSON.stringify(absorbRepro);
|
||||
const bytes = (value: number) => value >= 1024
|
||||
? `${(value / 1024).toFixed(2)} KiB`
|
||||
: `${value.toLocaleString()} B`;
|
||||
const scientific = (value: number) => value.toExponential(2);
|
||||
const compact = {
|
||||
prompts: trace.prompts.map((prompt: any) => ({
|
||||
id: prompt.id,
|
||||
@@ -46,7 +55,7 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
</div>
|
||||
<p>
|
||||
固定官方 revision、tokenizer、模型代码和 BF16 第一分片;RTX 5090 连续执行 layer 0–6,
|
||||
捕获真实 MLA 状态与 3,240 次 routed-expert 选择。所有结论都带证据身份与停止线。
|
||||
捕获 3,240 次真实路由,并让 layer-1 权重继续走入官方吸收式 cache。所有结论都带证据身份与停止线。
|
||||
</p>
|
||||
</header>
|
||||
|
||||
@@ -67,8 +76,11 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
<button type="button" role="tab" data-artifact-tab="cache" aria-selected="false" tabindex="-1">
|
||||
<span>03</span><b>缓存实现账</b><small>latent vs HF eager</small>
|
||||
</button>
|
||||
<button type="button" role="tab" data-artifact-tab="absorb" aria-selected="false" tabindex="-1">
|
||||
<span>04</span><b>吸收式执行</b><small>real cache · SM120</small>
|
||||
</button>
|
||||
<button type="button" role="tab" data-artifact-tab="evidence" aria-selected="false" tabindex="-1">
|
||||
<span>04</span><b>证据断面</b><small>revision · shards · rerun</small>
|
||||
<span>05</span><b>证据断面</b><small>revision · shards · rerun</small>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -243,7 +255,114 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
|
||||
<div class="artifact-boundary">
|
||||
<b>IMPLEMENTATION CONTRACT</b>
|
||||
<p>算法上“可以缓存 576 元素”与本次框架“实际缓存 5,120 元素”同时为真;生产吞吐还需要真实 latent-cache kernel 与 serving runtime。</p>
|
||||
<p>算法上“可以缓存 576 元素”与 HF eager“实际缓存 5,120 元素”同时为真;下一页继续执行官方 absorb 参考路径,生产吞吐仍需要受支持的优化 kernel 与 serving runtime。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="artifact-panel" data-artifact-panel="absorb" hidden>
|
||||
<div class="panel-lead">
|
||||
<div><span>X + O / WEIGHT ABSORPTION</span><h4>这一次 576 元素真的进入了缓存</h4></div>
|
||||
<p>
|
||||
同一组真实 V2-Lite layer-1 权重、同一条 26-token hidden-state 轨迹:
|
||||
先用 V3 官方 naive 路径展开 K/V,再用官方 absorb 路径做 25-token prefill + 1-token decode。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="absorb-algebra" aria-label="MLA 权重吸收的两条代数变换">
|
||||
<article>
|
||||
<span>SCORE / 把 Wᴷ 搬到 query</span>
|
||||
<code>qᵀ(Wᴷc) = (Wᴷᵀq)ᵀc</code>
|
||||
<p>不再为每个历史 token、每个 head 存展开后的 no-RoPE key;query 先变成 512 维,再与 latent <i>c</i> 相乘。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span>VALUE / 把 Wⱽ 搬到 attention 后</span>
|
||||
<code>Σ pₜ(Wⱽcₜ) = Wⱽ(Σ pₜcₜ)</code>
|
||||
<p>先对 512 维 latent 做加权和,再展开成各 head 的 value。含位置的 64 维 RoPE key 不能这样吸收,必须单独缓存。</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="absorb-cache-flow">
|
||||
<article class="naive">
|
||||
<header><span>X / V3 NAIVE · BF16</span><b>{bytes(absorb.cache_accounting.naive_active_bytes)}</b></header>
|
||||
<div>
|
||||
<code>K [1, 26, 16, 192]</code>
|
||||
<code>V [1, 26, 16, 128]</code>
|
||||
</div>
|
||||
<p>26 × 5,120 元素;与 HF eager 是同一种展开状态。</p>
|
||||
</article>
|
||||
<i aria-hidden="true">→</i>
|
||||
<article class="absorbed">
|
||||
<header><span>X / V3 ABSORB · BF16</span><b>{bytes(absorb.cache_accounting.absorb_active_bytes)}</b></header>
|
||||
<div>
|
||||
<code>latent [1, 26, 512]</code>
|
||||
<code>RoPE [1, 26, 64]</code>
|
||||
</div>
|
||||
<p>26 × 576 元素;两个官方 buffer 的真实 active slice。</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="absorb-metrics">
|
||||
<article><span>REAL CACHE RATIO</span><b>{absorb.cache_accounting.naive_over_absorb_ratio.toFixed(4)}×</b><p>展开 K/V ÷ latent + RoPE</p></article>
|
||||
<article><span>BF16 MAX |Δ|</span><b>{absorb.correctness.v3_naive_vs_absorb_bfloat16.max_abs}</b><p>官方 V3 naive ↔ absorb decode</p></article>
|
||||
<article><span>FP32 MAX |Δ|</span><b>{scientific(absorb.correctness.v3_naive_vs_absorb_float32.max_abs)}</b><p>同一 BF16 权重转 FP32 做代数审计</p></article>
|
||||
<article class="exact"><span>INDEPENDENT RERUN</span><b>{absorbExact ? "BYTE-EXACT" : "MISMATCH"}</b><p>完整 JSON SHA-256 6b4c714a…e63d</p></article>
|
||||
</div>
|
||||
|
||||
<div class="precision-lens">
|
||||
<div>
|
||||
<span>HF EAGER ↔ V3 NAIVE / BF16</span>
|
||||
<i><em style={`--error:${absorb.correctness.hf_eager_vs_v3_naive_bfloat16.max_abs / .004}`}></em></i>
|
||||
<b>max {absorb.correctness.hf_eager_vs_v3_naive_bfloat16.max_abs}</b>
|
||||
</div>
|
||||
<div>
|
||||
<span>V3 NAIVE ↔ ABSORB / BF16</span>
|
||||
<i><em style={`--error:${absorb.correctness.v3_naive_vs_absorb_bfloat16.max_abs / .004}`}></em></i>
|
||||
<b>max {absorb.correctness.v3_naive_vs_absorb_bfloat16.max_abs}</b>
|
||||
</div>
|
||||
<div>
|
||||
<span>V3 NAIVE ↔ ABSORB / FP32</span>
|
||||
<i><em style={`--error:${absorb.correctness.v3_naive_vs_absorb_float32.max_abs / .004}`}></em></i>
|
||||
<b>max {scientific(absorb.correctness.v3_naive_vs_absorb_float32.max_abs)}</b>
|
||||
</div>
|
||||
<p>
|
||||
三组输出均 finite。FP32 不是新的 checkpoint 精度,而是把同一组 BF16 权重提升后,
|
||||
隔离矩阵乘法顺序造成的舍入误差。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="kernel-contract">
|
||||
<div>
|
||||
<span>OFFICIAL FLASHMLA / PINNED {absorb.flashmla_boundary.official_revision.slice(0, 8)}</span>
|
||||
<h5>算法路径已执行,不等于优化 kernel 已执行</h5>
|
||||
<p>官方支持矩阵与编译目标只覆盖 SM90 / SM100;本机 RTX 5090 是 SM120。</p>
|
||||
</div>
|
||||
<div class="kernel-matrix" role="table" aria-label="FlashMLA 官方架构支持矩阵">
|
||||
<div class="head" role="row"><b>KERNEL</b><b>SM90</b><b>SM100</b><b>LOCAL SM120</b></div>
|
||||
<div role="row"><span>dense decode</span><i class="yes">支持</i><i>—</i><i class="no">未支持</i></div>
|
||||
<div role="row"><span>sparse decode</span><i class="yes">支持</i><i class="yes">支持</i><i class="no">未支持</i></div>
|
||||
<div role="row"><span>dense prefill</span><i>—</i><i class="yes">支持</i><i class="no">未支持</i></div>
|
||||
<div role="row"><span>sparse prefill</span><i class="yes">支持</i><i class="yes">支持</i><i class="no">未支持</i></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="execution-split">
|
||||
<article><span>EXECUTED</span><b>官方 V3 pure-PyTorch absorb</b><p>真实权重、真实 latent / RoPE buffers、真实 incremental decode。</p></article>
|
||||
<article><span>BUILD ATTEMPTS</span><b>2 个环境,均未产出 wheel</b><p>host 编译器边界;隔离 CUDA 13 环境缺少 <code>cuda/std/utility</code>。</p></article>
|
||||
<article class="blocked"><span>NOT EXECUTED</span><b>FlashMLA optimized kernel</b><p>源码只生成 <code>sm_90a</code> / <code>sm_100f</code>,dense decode 运行时还拒绝非 SM90a。</p></article>
|
||||
</div>
|
||||
|
||||
<div class="evidence-links">
|
||||
<a href="https://github.com/deepseek-ai/DeepSeek-V3/blob/main/inference/model.py" rel="noreferrer">官方 V3 absorb 参考实现 ↗</a>
|
||||
<a href="https://github.com/deepseek-ai/FlashMLA" rel="noreferrer">官方 FlashMLA 支持矩阵 ↗</a>
|
||||
<a href="https://arxiv.org/abs/2405.04434" rel="noreferrer">DeepSeek-V2 MLA 报告 ↗</a>
|
||||
</div>
|
||||
|
||||
<div class="artifact-boundary">
|
||||
<b>CORRECT CLAIM</b>
|
||||
<p>
|
||||
本实验复现的是“真实权重 + 官方参考实现中的压缩缓存与 decode 等价性”,不是 FlashMLA 性能、
|
||||
生产 serving 吞吐或 V2 论文完整模型相对 MHA 的 93.3% 缓存降幅。
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -328,15 +447,16 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
|
||||
<div class="artifact-boundary">
|
||||
<b>U / STILL OPEN</b>
|
||||
<p>完整 27 层生成、真实 latent-cache kernel、生产服务、训练负载、FP8/pipeline 与 R1-like 训练 trace 仍未覆盖。</p>
|
||||
<p>完整 27 层生成、受支持硬件上的 FlashMLA 优化 kernel、生产服务、训练负载、FP8/pipeline 与 R1-like 训练 trace 仍未覆盖。</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<figcaption>
|
||||
<span>可复现入口</span>
|
||||
<code>experiments/deepseek/v2_lite_trace.py</code> ·
|
||||
<code>experiments/deepseek/v2_lite_absorb_probe.py</code> ·
|
||||
<code>src/data/deepseek-v2-lite-trace.json</code> ·
|
||||
<code>research/DEEPSEEK_V2_LITE_TRACE.md</code>
|
||||
<code>research/DEEPSEEK_MLA_ABSORB_AUDIT.md</code>
|
||||
</figcaption>
|
||||
|
||||
<script is:inline type="application/json" data-dsv2-trace set:html={compactJson}></script>
|
||||
@@ -575,6 +695,11 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.jaccard-block span,
|
||||
.observed-cache span,
|
||||
.artifact-identity span,
|
||||
.absorb-algebra span,
|
||||
.absorb-cache-flow span,
|
||||
.absorb-metrics span,
|
||||
.kernel-contract span,
|
||||
.execution-split span,
|
||||
.repro-gate span,
|
||||
.dependency-split span,
|
||||
.checksum-grid span {
|
||||
@@ -631,7 +756,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(4, 1fr);
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
background: var(--ink);
|
||||
}
|
||||
.artifact-tabs button {
|
||||
@@ -792,6 +917,7 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.route-metrics,
|
||||
.cache-ratio,
|
||||
.load-lessons,
|
||||
.absorb-metrics,
|
||||
.artifact-identity,
|
||||
.checksum-grid {
|
||||
display: grid;
|
||||
@@ -802,6 +928,7 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.route-metrics article,
|
||||
.cache-ratio article,
|
||||
.load-lessons article,
|
||||
.absorb-metrics article,
|
||||
.artifact-identity article,
|
||||
.checksum-grid article {
|
||||
padding: .8rem;
|
||||
@@ -810,20 +937,24 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.route-metrics article:last-child,
|
||||
.cache-ratio article:last-child,
|
||||
.load-lessons article:last-child,
|
||||
.absorb-metrics article:last-child,
|
||||
.artifact-identity article:last-child,
|
||||
.checksum-grid article:last-child { border-right: 0; }
|
||||
.route-metrics span,
|
||||
.cache-ratio span,
|
||||
.load-lessons span {
|
||||
.load-lessons span,
|
||||
.absorb-metrics span {
|
||||
display: block;
|
||||
color: var(--blue);
|
||||
font: 700 .61rem/1 var(--font-mono);
|
||||
}
|
||||
.route-metrics b,
|
||||
.cache-ratio b { display: block; margin-top: .35rem; font: 750 1.25rem/1 var(--font-display); }
|
||||
.cache-ratio b,
|
||||
.absorb-metrics b { display: block; margin-top: .35rem; font: 750 1.25rem/1 var(--font-display); }
|
||||
.route-metrics p,
|
||||
.cache-ratio p,
|
||||
.load-lessons p { margin: .3rem 0 0; color: rgba(32,32,39,.56); font-size: .65rem; line-height: 1.45; }
|
||||
.load-lessons p,
|
||||
.absorb-metrics p { margin: .3rem 0 0; color: rgba(32,32,39,.56); font-size: .65rem; line-height: 1.45; }
|
||||
.artifact-boundary {
|
||||
display: grid;
|
||||
grid-template-columns: 11rem 1fr;
|
||||
@@ -950,6 +1081,127 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.cache-ledger p { margin: .35rem 0 0; color: rgba(32,32,39,.58); font-size: .68rem; line-height: 1.45; }
|
||||
.cache-ratio { grid-template-columns: repeat(3, 1fr); }
|
||||
.cache-ratio .warning { background: rgba(186,118,44,.09); }
|
||||
.absorb-algebra {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: .8rem;
|
||||
}
|
||||
.absorb-algebra article {
|
||||
padding: 1rem;
|
||||
border: 1px solid rgba(32,32,39,.15);
|
||||
background: #fffdf8;
|
||||
}
|
||||
.absorb-algebra code {
|
||||
display: block;
|
||||
margin: .75rem 0;
|
||||
color: var(--ink);
|
||||
font: 750 clamp(.88rem, 1.7vw, 1.2rem)/1.2 var(--font-mono);
|
||||
}
|
||||
.absorb-algebra p,
|
||||
.absorb-cache-flow p,
|
||||
.kernel-contract p,
|
||||
.execution-split p {
|
||||
margin: 0;
|
||||
color: rgba(32,32,39,.62);
|
||||
font-size: .69rem;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.absorb-cache-flow {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: .8rem;
|
||||
align-items: center;
|
||||
margin-top: .8rem;
|
||||
}
|
||||
.absorb-cache-flow > i { color: var(--teal); font: 800 1.5rem/1 var(--font-display); }
|
||||
.absorb-cache-flow article {
|
||||
padding: 1rem;
|
||||
border: 1px solid rgba(32,32,39,.15);
|
||||
}
|
||||
.absorb-cache-flow article.naive { background: rgba(161,77,77,.07); }
|
||||
.absorb-cache-flow article.absorbed { background: rgba(57,120,110,.09); }
|
||||
.absorb-cache-flow header { display: flex; justify-content: space-between; gap: 1rem; align-items: center; }
|
||||
.absorb-cache-flow header b { font: 760 1.25rem/1 var(--font-display); }
|
||||
.absorb-cache-flow div { display: flex; flex-wrap: wrap; gap: .4rem; margin: .75rem 0; }
|
||||
.absorb-cache-flow code {
|
||||
padding: .35rem .45rem;
|
||||
background: rgba(32,32,39,.08);
|
||||
font-size: .66rem;
|
||||
}
|
||||
.absorb-metrics { grid-template-columns: repeat(4, 1fr); }
|
||||
.absorb-metrics article.exact { background: rgba(57,120,110,.1); }
|
||||
.precision-lens {
|
||||
display: grid;
|
||||
gap: .55rem;
|
||||
margin-top: .8rem;
|
||||
padding: 1rem;
|
||||
background: var(--ink);
|
||||
color: white;
|
||||
}
|
||||
.precision-lens > div {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(13rem, 1.3fr) 1fr minmax(8rem, auto);
|
||||
gap: .8rem;
|
||||
align-items: center;
|
||||
}
|
||||
.precision-lens span,
|
||||
.precision-lens b { font: 650 .62rem/1.3 var(--font-mono); }
|
||||
.precision-lens b { text-align: right; }
|
||||
.precision-lens i { height: 7px; overflow: hidden; background: rgba(255,255,255,.13); }
|
||||
.precision-lens em {
|
||||
display: block;
|
||||
width: max(calc(var(--error) * 100%), 2px);
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
background: #b7bce5;
|
||||
}
|
||||
.precision-lens > div:last-of-type em { background: #91cfc1; }
|
||||
.precision-lens > p {
|
||||
margin: .25rem 0 0;
|
||||
padding-top: .7rem;
|
||||
border-top: 1px solid rgba(255,255,255,.15);
|
||||
color: rgba(255,255,255,.58);
|
||||
font-size: .66rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.kernel-contract {
|
||||
display: grid;
|
||||
grid-template-columns: .7fr 1.3fr;
|
||||
gap: 1rem;
|
||||
margin-top: .8rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid rgba(32,32,39,.15);
|
||||
background: #e6dfd3;
|
||||
}
|
||||
.kernel-contract h5 { margin: .45rem 0; font: 720 1rem/1.15 var(--font-display); }
|
||||
.kernel-matrix { overflow-x: auto; border: 1px solid rgba(32,32,39,.14); background: #fffdf8; }
|
||||
.kernel-matrix > div {
|
||||
display: grid;
|
||||
grid-template-columns: 1.4fr repeat(3, minmax(5rem, .7fr));
|
||||
min-width: 520px;
|
||||
}
|
||||
.kernel-matrix b,
|
||||
.kernel-matrix span,
|
||||
.kernel-matrix i {
|
||||
padding: .55rem;
|
||||
border-right: 1px solid rgba(32,32,39,.1);
|
||||
border-bottom: 1px solid rgba(32,32,39,.1);
|
||||
font: 650 .61rem/1.2 var(--font-mono);
|
||||
}
|
||||
.kernel-matrix .head { background: var(--ink); color: white; }
|
||||
.kernel-matrix i { color: rgba(32,32,39,.45); font-style: normal; text-align: center; }
|
||||
.kernel-matrix i.yes { color: var(--teal); background: rgba(57,120,110,.08); }
|
||||
.kernel-matrix i.no { color: var(--red); background: rgba(161,77,77,.08); }
|
||||
.execution-split {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
margin-top: .8rem;
|
||||
border: 1px solid rgba(32,32,39,.14);
|
||||
}
|
||||
.execution-split article { padding: .9rem; border-right: 1px solid rgba(32,32,39,.12); }
|
||||
.execution-split article:last-child { border-right: 0; }
|
||||
.execution-split article.blocked { background: rgba(161,77,77,.08); }
|
||||
.execution-split b { display: block; margin: .4rem 0; font-size: .77rem; }
|
||||
.artifact-identity { grid-template-columns: repeat(3, 1fr); }
|
||||
.artifact-identity article { display: grid; gap: .35rem; }
|
||||
.artifact-identity b { font-size: .78rem; }
|
||||
@@ -1030,7 +1282,8 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.panel-lead,
|
||||
.heat-head,
|
||||
.aggregate-card,
|
||||
.jaccard-block { grid-template-columns: 1fr; }
|
||||
.jaccard-block,
|
||||
.kernel-contract { 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; }
|
||||
@@ -1039,7 +1292,8 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.route-stage > i { transform: rotate(90deg); justify-self: center; }
|
||||
.cache-controls { grid-template-columns: 1fr 1fr; }
|
||||
.route-metrics,
|
||||
.checksum-grid { grid-template-columns: 1fr 1fr; }
|
||||
.checksum-grid,
|
||||
.absorb-metrics { grid-template-columns: 1fr 1fr; }
|
||||
.layer-evidence { grid-template-columns: repeat(9, 1fr); }
|
||||
.repro-gate { grid-template-columns: 1fr 1fr; }
|
||||
.repro-gate > p { grid-column: 1 / -1; padding: .8rem 0 0; border-left: 0; border-top: 1px solid rgba(255,255,255,.18); }
|
||||
@@ -1062,20 +1316,28 @@ const shardFraction = trace.provenance.shard_1_bytes / trace.provenance.checkpoi
|
||||
.route-metrics,
|
||||
.cache-ratio,
|
||||
.load-lessons,
|
||||
.absorb-metrics,
|
||||
.artifact-identity,
|
||||
.checksum-grid,
|
||||
.cache-ledger { grid-template-columns: 1fr; }
|
||||
.route-metrics article,
|
||||
.cache-ratio article,
|
||||
.load-lessons article,
|
||||
.absorb-metrics article,
|
||||
.artifact-identity article,
|
||||
.checksum-grid article { border-right: 0; border-bottom: 1px solid rgba(32,32,39,.12); }
|
||||
.artifact-boundary { grid-template-columns: 1fr; }
|
||||
.load-dials { grid-template-columns: 1fr; }
|
||||
.observed-cache,
|
||||
.dependency-split { grid-template-columns: 1fr; }
|
||||
.dependency-split,
|
||||
.absorb-algebra,
|
||||
.absorb-cache-flow,
|
||||
.execution-split { grid-template-columns: 1fr; }
|
||||
.observed-cache > i,
|
||||
.dependency-split > i { transform: rotate(90deg); justify-self: center; }
|
||||
.absorb-cache-flow > i { transform: rotate(90deg); justify-self: center; }
|
||||
.precision-lens > div { grid-template-columns: 1fr; }
|
||||
.precision-lens b { text-align: left; }
|
||||
.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