diff --git a/apps/site/learn/attention/LESSON.md b/apps/site/learn/attention/LESSON.md index 44c6c36..27df33c 100644 --- a/apps/site/learn/attention/LESSON.md +++ b/apps/site/learn/attention/LESSON.md @@ -15,3 +15,16 @@ Managed Chrome desktop (1363×936) and 390×844 iframe viewport; not physical-ph Observed: complete playback reached 48/48 and restored configuration. Backward seek 48→25→16 rebuilt earlier phases; resume/Escape pause, previous/next, Home/End, replay and reset were exercised. During playback configuration disappeared from the accessibility tree with focus on the persistent pause control. Reduced-motion toggle was enabled; t=31.1 displayed the stable full contribution bar. Query A produced 4.248; default C produced 15.752; changing future V to 1000 preserved output 15.752. The mobile quiz wrong/correct feedback and verify flow returned q=0, D=1000, output 10.000 and visible weights 1/3 each. Dialog fit in the narrow viewport. `evals/browser/attention-lifecycle.html` tested the actual app's visibility handler using controlled document-hidden events: hidden paused at ~0.05s, configuration restored; visible did not auto-resume or jump. This is event-path testing, not actual OS hidden-tab observation. OS-level preference switching, physical devices, screen-reader devices and other engines remain untested. Full-site checks including mechanical invariants passed. Preview and actual production evidence will be recorded separately. + + +## Rework draft — 2026-10-29 + +See `docs/ai-learning/reviews/2026-10-29-attention-rework.md`. Exact operation/row pose tests passed; preliminary desktop observation only. Not visually accepted or published. Original publication evidence does not validate this new candidate. + + +Q/K component follow-up adds paired multiplication wells, explicit merge and routed contribution paths. Desktop7.2/8.2/8.6/9.0/reverse8.2 and selected390px inspection completed; narrow type measured15.21px after repair. Rounded arithmetic uses≈. Full release review remains pending; see the same rework record. + + +## Reopened craft review follow-up — 2026-10-30 + +Persistent mathematical rows now carry exact values between chapters; Q/K component multiplication, denominator collection, normalized fractions, same-scaleV/pV and cumulative contributions are inspectable in intermediate frames.18-unit narrow SVG type, explicit front-face ports and consistent carrier depth were checked with native4× and390px browser evidence. Full tests and affected UI lifecycle/quiz checks passed; see [review with actual images, raw DOM records and limits](../../../../docs/ai-learning/reviews/2026-10-29-attention-rework.md#follow-up-2026-10-30--reviewed-candidate-release-verification-pending). Controlled hidden-event handling is covered; real background scheduling, physical devices and measured learning gains are not. This entry is candidate acceptance, not yet a production receipt. Skill/host compatibility is not newly claimed. diff --git a/apps/site/learn/attention/SCENE_SPEC.json b/apps/site/learn/attention/SCENE_SPEC.json index 7f7167d..d47ff34 100644 --- a/apps/site/learn/attention/SCENE_SPEC.json +++ b/apps/site/learn/attention/SCENE_SPEC.json @@ -1 +1,81 @@ -{"id":"attention","question":"当前查询如何把可见位置的 V 汇成一个输出?","durationSeconds":48,"inputs":{"alpha":[-1,0,1],"futureV":{"min":0,"max":1000,"step":10}},"queryPosition":2,"keyDimension":2,"valueDimension":1,"keys":[[-1,0],[0,0],[1,0],[2,0]],"values":[0,10,20,"futureV"],"relations":["q=[sqrt(2)*alpha,0]","s=qK^T/sqrt(2)","mask j>2 to -Infinity before Softmax","p=Softmax(masked scores)","o=sum(p_j*V_j)"],"mapping":{"color":"position identity","probabilityBar":"0..1 within each channel","contributionBar":"length of p_j*V_j; shared total scale 0..20","connections":"dependencies, not physical motion or measured timing"},"experiment":"Keep K/V fixed and change q; then vary masked future V and show output invariance.","transfer":"q=0, futureV=1000 gives mean of visible 0,10,20 = 10, not max or four-way mean.","sources":["https://arxiv.org/abs/1706.03762","https://docs.pytorch.org/docs/2.14/generated/torch.nn.functional.scaled_dot_product_attention.html"],"simplifications":["Authored Q/K/V, no model or semantic interpretation","One causal row and head; V scalar","No learned projection, positions, dropout, output projection, residual, training or token sampling","SVG teaching geometry, not actual model hardware"]} +{ + "id": "attention", + "question": "当前查询如何把可见位置的 V 汇成一个输出?", + "durationSeconds": 48, + "inputs": { + "alpha": [ + -1, + 0, + 1 + ], + "futureV": { + "min": 0, + "max": 1000, + "step": 10 + } + }, + "queryPosition": 2, + "keyDimension": 2, + "valueDimension": 1, + "keys": [ + [ + -1, + 0 + ], + [ + 0, + 0 + ], + [ + 1, + 0 + ], + [ + 2, + 0 + ] + ], + "values": [ + 0, + 10, + 20, + "futureV" + ], + "relations": [ + "q=[sqrt(2)*alpha,0]", + "s=qK^T/sqrt(2)", + "mask j>2 to -Infinity before Softmax", + "p=Softmax(masked scores)", + "o=sum(p_j*V_j)" + ], + "mapping": { + "color": "position identity", + "probabilityBar": "0..1 within each channel", + "contributionBar": "length of p_j*V_j; shared total scale 0..20", + "connections": "dependencies, not physical motion or measured timing", + "valueRead": "Dashed V and filled pV share a0..20 front-plane scale; masked D original V is not drawn beyond that range" + }, + "experiment": "Keep K/V fixed and change q; then vary masked future V and show output invariance.", + "transfer": "q=0, futureV=1000 gives mean of visible 0,10,20 = 10, not max or four-way mean.", + "sources": [ + "https://arxiv.org/abs/1706.03762", + "https://docs.pytorch.org/docs/2.14/generated/torch.nn.functional.scaled_dot_product_attention.html" + ], + "simplifications": [ + "Authored Q/K/V, no model or semantic interpretation", + "One causal row and head; V scalar", + "No learned projection, positions, dropout, output projection, residual, training or token sampling", + "SVG teaching geometry, not actual model hardware" + ], + "reworkReview": { + "date": "2026-10-30", + "status": "reviewed-candidate-pending-release", + "record": "docs/ai-learning/reviews/2026-10-29-attention-rework.md", + "layout": "Persistent rows, exact chapter carriers, paired QK wells/merge, common denominator collection, traced shared-scale fractions, V/pV comparison and nonzero routed contributions", + "limits": [ + "No physical phone/other engine/learner study", + "Controlled hidden event tested; native background scheduling not independently verified", + "Skill distribution alignment pending" + ] + } +} diff --git a/apps/site/learn/attention/app.mjs b/apps/site/learn/attention/app.mjs index 0af031a..5eab143 100644 --- a/apps/site/learn/attention/app.mjs +++ b/apps/site/learn/attention/app.mjs @@ -1,5 +1,6 @@ import {TOKENS,STARTS,DURATION,sample,narration} from './model.mjs'; import {createStage} from './stage.mjs'; +import {lessonPose,handoff} from './pose.mjs'; const $=s=>document.querySelector(s),$$=s=>[...document.querySelectorAll(s)],motion=matchMedia('(prefers-reduced-motion: reduce)'); let reduced=motion.matches; const stage=createStage($('#artwork'),{reducedMotion:()=>reduced}); @@ -7,7 +8,18 @@ let id=1,future=100,time=0,playing=false,raf=0,last=0,lastCopy='',dead=false; const names=['输入 Q/K/V','匹配分数','因果遮罩','分配权重','加权内容','求和与实验']; function focus(on){$('#app').classList.toggle('is-playing',on);$$('.secondary').forEach(x=>{x.inert=on;x.setAttribute('aria-hidden',String(on));});} function anchor(){const box=$('.exhibit').getBoundingClientRect(),bubble=$('#callout').getBoundingClientRect(),art=$('#artwork');art.style.top=Math.max(185,bubble.bottom-box.top+13)+'px';const a=art.getBoundingClientRect(),point=stage.projectAnchor();if(!point)return;const x=a.left-box.left+point.x*a.width,y=a.top-box.top+point.y*a.height,cx=Math.max(bubble.width/2+17,Math.min(box.width-bubble.width/2-17,x));$('#callout').style.left=cx+'px';$('#leader').setAttribute('viewBox',`0 0 ${box.width} ${box.height}`);const sy=bubble.bottom-box.top;const side=a.left-box.left+point.bendX*a.width,start=cx-bubble.width/2+10;$('#leader-line').setAttribute('d',point.routeLeft?`M${start} ${sy}C${side} ${sy+12},${side} ${sy+12},${side} ${sy+27}V${y-8}Q${side} ${y},${side+8} ${y}H${x-8}`:`M${cx} ${sy}C${cx} ${sy+20},${x} ${y-25},${x} ${y-8}`);$('#leader-dot').setAttribute('cx',x);$('#leader-dot').setAttribute('cy',y);} -function render(){if(dead)return;const f=sample(time,{id,future}),c=narration(f),key=JSON.stringify(c);stage.render(f);if(key!==lastCopy){lastCopy=key;$('#copy-eyebrow').textContent=c.eyebrow;$('#copy-title').textContent=c.title;$('#copy-body').textContent=c.body;}$('#phase-label').textContent=`0${f.phase+1} / 06 · ${names[f.phase]}`;$('#counts').textContent=`当前位置 C · 单头单行`;$$('[data-id]').forEach(b=>b.setAttribute('aria-pressed',String(+b.dataset.id===id)));$('#future').value=future;$('#future-value').textContent=future;$('#timeline').value=time;$('#timeline').style.setProperty('--fill',`${time/DURATION*100}%`);$('#time').textContent=`00:${String(Math.floor(time)).padStart(2,'0')} / 00:48`;$('#play-label').textContent=playing?'暂停':time>=DURATION?'再看一遍':time?'继续讲解':'播放讲解';$('#play-icon').textContent=playing?'Ⅱ':'▶';$('#play').setAttribute('aria-pressed',String(playing));$('#back').disabled=time===0;$('#next').disabled=time===DURATION;$('#play-note').textContent=playing?'配置已收起 · 空格暂停':'六个步骤 · 从查询到加权和';$('#challenge').hidden=timeb.setAttribute('aria-pressed',String(+b.dataset.id===id)));$('#future').value=future;$('#future-value').textContent=future;$('#timeline').value=time;$('#timeline').style.setProperty('--fill',`${time/DURATION*100}%`);$('#time').textContent=`00:${String(Math.floor(time)).padStart(2,'0')} / 00:48`;$('#play-label').textContent=playing?'暂停':time>=DURATION?'再看一遍':time?'继续讲解':'播放讲解';$('#play-icon').textContent=playing?'Ⅱ':'▶';$('#play').setAttribute('aria-pressed',String(playing));$('#back').disabled=time===0;$('#next').disabled=time===DURATION;$('#play-note').textContent=playing?'配置已收起 · 空格暂停':'六个步骤 · 从查询到加权和';$('#challenge').hidden=time一个词如何参考其他词? · Explain3D
e· Explain3DAI 原理课堂 / 03

ONE QUERY · A WEIGHTED MIXTURE

注意力,怎样汇成一个结果?

从匹配分数,到可见信息的加权和。

手写 Q/K/V · 单头单行 · 未运行语言模型
六个步骤 · 从查询到加权和00:00 / 00:48
Explain3D · AI 原理课堂Q/K 决定权重 · V 提供内容
-

SCALED DOT-PRODUCT ATTENTION

权重和内容,是两件事。

本页计算因果自注意力的一行:当前位置 C(从 0 开始索引 2),可以参考 A/B/C,不能参考未来的 D。Q、K、V 在真实网络中由输入表示经过学习到的线性投影得到;本页直接给定这些参数,不演示投影、训练、多头、位置编码、输出投影、残差或下一词采样。

q = [√2 × α, 0];α ∈ {−1, 0, 1}
K = [ [−1,0], [0,0], [1,0], [2,0] ]
V = [0, 10, 20, 未来值]
s = qKᵀ / √2 = [−α, 0, α, 2α]
s(遮罩后)= [−α, 0, α, −∞]
pⱼ = exp(sⱼ) / Σ exp(sₖ)
o = Σ pⱼVⱼ

V 为一维,只为看清乘法与求和。真实 V 通常是向量,逐分量使用同一组权重。因果遮罩包含当前位置自身,先应用遮罩再做 Softmax。没有 dropout。本页色彩只标识位置 A/B/C/D;卡片宽度不编码数值。概率条宽度表示权重,最终彩色条长度表示各项贡献(总长对应输出,刻度 0…20)。连接线表示依赖关系,不表示网络真实空间或耗时。

手写数字与符号 A/B/C/D 不代表任何真实语言模型或自然语言词义。本页的注意力权重也不是“解释模型推理”的充分证据。查询归零时,可见位置均分权重,输出为 (0+10+20)/3 = 10,未来值仍被排除。

原论文 §3.2 ↗ · PyTorch 官方公式与因果遮罩实现 ↗

PREDICT · TRY · EXPLAIN

查询归零,输出会是多少?

q = [0,0],可见位置 A/B/C 的 V 为 0/10/20;未来 D 的 V 为 1000。因果遮罩仍然启用。

\ No newline at end of file +一个词如何参考其他词? · Explain3D
e· Explain3DAI 原理课堂 / 03

ONE QUERY · A WEIGHTED MIXTURE

注意力,怎样汇成一个结果?

从匹配分数,到可见信息的加权和。

手写 Q/K/V · 单头单行 · 未运行语言模型
六个步骤 · 从查询到加权和00:00 / 00:48
Explain3D · AI 原理课堂Q/K 决定权重 · V 提供内容
+

SCALED DOT-PRODUCT ATTENTION

权重和内容,是两件事。

本页计算因果自注意力的一行:当前位置 C(从 0 开始索引 2),可以参考 A/B/C,不能参考未来的 D。Q、K、V 在真实网络中由输入表示经过学习到的线性投影得到;本页直接给定这些参数,不演示投影、训练、多头、位置编码、输出投影、残差或下一词采样。

q = [√2 × α, 0];α ∈ {−1, 0, 1}
K = [ [−1,0], [0,0], [1,0], [2,0] ]
V = [0, 10, 20, 未来值]
s = qKᵀ / √2 = [−α, 0, α, 2α]
s(遮罩后)= [−α, 0, α, −∞]
pⱼ = exp(sⱼ) / Σ exp(sₖ)
o = Σ pⱼVⱼ

V 为一维,只为看清乘法与求和。真实 V 通常是向量,逐分量使用同一组权重。因果遮罩包含当前位置自身,先应用遮罩再做 Softmax。没有 dropout。本页色彩只标识位置 A/B/C/D;卡片宽度不编码数值。概率条宽度表示权重,加权阶段虚线轮廓表示原始 V,实色表示 pV,二者与底部结果共用 0…20 刻度;被遮罩的 D 不绘制原始 V 长度(可超过刻度)。最终彩色条长度表示各项贡献,总长对应输出。连接线和依次描出的短条是教学指针,不表示网络真实空间、计算耗时或一组随时间改变的权重。暂停或拖动可检查中间过程;每行计算完成才显示其结果数字。

手写数字与符号 A/B/C/D 不代表任何真实语言模型或自然语言词义。本页的注意力权重也不是“解释模型推理”的充分证据。查询归零时,可见位置均分权重,输出为 (0+10+20)/3 = 10,未来值仍被排除。

原论文 §3.2 ↗ · PyTorch 官方公式与因果遮罩实现 ↗

PREDICT · TRY · EXPLAIN

查询归零,输出会是多少?

q = [0,0],可见位置 A/B/C 的 V 为 0/10/20;未来 D 的 V 为 1000。因果遮罩仍然启用。

\ No newline at end of file diff --git a/apps/site/learn/attention/model.mjs b/apps/site/learn/attention/model.mjs index f3c9788..d044a2d 100644 --- a/apps/site/learn/attention/model.mjs +++ b/apps/site/learn/attention/model.mjs @@ -3,8 +3,8 @@ export const STARTS=[0,7,15,23,31,40],DURATION=48; export function calculate(alpha=1,future=100){if(![-1,0,1].includes(alpha)||!Number.isFinite(future)||future<0||future>1000)throw new RangeError('Invalid teaching input');const q=[Math.SQRT2*alpha,0],keys=[[-1,0],[0,0],[1,0],[2,0]],values=[0,10,20,future],scores=keys.map(k=>(q[0]*k[0]+q[1]*k[1])/Math.sqrt(2)),masked=scores.map((s,i)=>i>2?-Infinity:s),max=Math.max(...masked),weights=masked.map(s=>Math.exp(s-max)),sum=weights.reduce((a,b)=>a+b),probs=weights.map(w=>w/sum),terms=values.map((v,i)=>v*probs[i]);return {alpha,future,q,keys,values,scores,masked,weights,probs,terms,output:terms.reduce((a,b)=>a+b)};} export function sample(t,{id=1,future=100}={}){t=Number.isFinite(t)?Math.max(0,Math.min(DURATION,t)):0;const phase=STARTS.findLastIndex(x=>t>=x);return {...calculate(id,future),time:t,phase,progress:(t-STARTS[phase])/((STARTS[phase+1]??DURATION)-STARTS[phase])};} export function narration(f){return [ -{title:'C 正在读取谁的信息?',body:'当前查询位置是 C。A、B、C 可以参与;D 在未来。本页只计算这一行、一个头,Q/K 是二维,V 用一个数简化展示。'}, -{title:'Q 和 K 相比,得到分数',body:`q = [${f.q[0].toFixed(3)}, 0];分数 sⱼ = q·kⱼ / √2。A、B、C、D 的分数为 ${f.scores.map(x=>x.toFixed(1)).join('、')}。分数还不是权重。`}, +{title:'C 正在读取谁的信息?',body:'在 C 的位置,用同一条查询读取 A/B/C;未来 D 不可见。这是手写的单头教学数据。'}, +{title:'Q 和 K 相比,得到分数',body:`当前匹配 ${TOKENS[Math.min(3,Math.floor(f.progress*4))]}:两个对应分量先相乘,再相加、除以 √2。匹配分数还不是权重。`}, {title:'先挡住未来,再分配权重',body:`D 的分数 ${f.scores[3].toFixed(1)} 被改为 −∞,指数为 0。它不进入分母;即使它的 V 是 ${f.future},也不能参与当前输出。`}, {title:'可见位置共同分到 100%',body:`指数归一化(Softmax)后:A ${(f.probs[0]*100).toFixed(1)}%、B ${(f.probs[1]*100).toFixed(1)}%、C ${(f.probs[2]*100).toFixed(1)}%、D 0%。这里是信息混合的权重,不是在抽取下一个 Token。`}, {title:'用权重乘 V,而不是乘 K',body:`各通道贡献为 ${f.terms.map(x=>x.toFixed(3)).join(' + ')}。Q/K 决定读多少,V 提供读出的内容;这些贡献会全部相加,不只取最大的一项。`}, diff --git a/apps/site/learn/attention/pose.mjs b/apps/site/learn/attention/pose.mjs new file mode 100644 index 0000000..d5058d7 --- /dev/null +++ b/apps/site/learn/attention/pose.mjs @@ -0,0 +1,32 @@ +// One deterministic teaching pose. Traversal is pedagogical, not compute latency. +const clamp=x=>Math.max(0,Math.min(1,x)); +export function lessonPose(f,reduced=false){ + const operation=f.phase>=2?clamp((f.progress-.18)/.82):clamp(f.progress); + const collect=f.phase===3?(reduced?1:clamp(operation/.2)):1; + const rowProgress=f.phase===3?clamp((operation-.2)/.8):operation; + const traversal=rowProgress*4,active=Math.min(3,Math.floor(traversal)),local=traversal-active; + const weights=f.masked.map(s=>Math.exp(s)),denominator=weights.reduce((a,b)=>a+b,0); + const mask=reduced?1:clamp(operation/.65); + const flights=f.terms.map((term,i)=>term===0?0:reduced?1:clamp((traversal-i-.55)/.45)); + return {operation,collect,active,travel:reduced?1:clamp(local),weights,denominator,mask,flights, + products:f.keys[active].map((k,j)=>k*f.q[j]), + cumulative:f.terms.map((_,i)=>f.terms.slice(0,i+1).reduce((a,b)=>a+b,0))}; +} + +export function pointOnPath(points,t){ + const lengths=points.slice(1).map((p,i)=>Math.hypot(p[0]-points[i][0],p[1]-points[i][1])); + let distance=clamp(t)*lengths.reduce((a,b)=>a+b,0),i=0; + while(ilengths[i])distance-=lengths[i++]; + const fraction=lengths[i]?distance/lengths[i]:1; + return points[i].map((v,j)=>v+(points[i+1][j]-v)*fraction); +} + +// A chapter output is carried to the next chapter's input without changing its value. +// exp / normalization / multiplication happen AFTER the carrier reaches that input. +export function handoff(f,reduced=false){ + if(f.phase<2||f.phase>5)return null; + const sets=[null,null,f.scores,f.masked,f.probs,f.terms]; + const names=[null,null,'s','s̃','p','t']; + const progress=reduced?1:clamp(f.progress/.18); + return {progress,unit:names[f.phase],values:[...sets[f.phase]],inTransit:progress<1}; +} diff --git a/apps/site/learn/attention/pose.test.mjs b/apps/site/learn/attention/pose.test.mjs new file mode 100644 index 0000000..542f2a0 --- /dev/null +++ b/apps/site/learn/attention/pose.test.mjs @@ -0,0 +1,52 @@ +import assert from 'node:assert/strict'; +import {sample} from './model.mjs'; +import {lessonPose,pointOnPath,handoff} from './pose.mjs'; +const near=(a,b)=>assert.ok(Math.abs(a-b)<1e-10); +let count=0; +for(const id of [-1,0,1])for(const future of [0,100,1000])for(const reduced of [false,true]){ + const snapshots=[]; + for(let tick=0;tick<=960;tick++){ + const f=sample(tick/20,{id,future}),p=lessonPose(f,reduced);snapshots.push(p); + assert.ok(p.active>=0&&p.active<4&&p.travel>=0&&p.travel<=1); + // Raw and max-shifted exponential normalizations encode the same distribution. + p.weights.forEach((w,i)=>near(w/p.denominator,f.probs[i])); + near(p.products.reduce((a,b)=>a+b,0)/Math.SQRT2,f.scores[p.active]); + near(p.cumulative[3],f.output);assert.equal(p.weights[3],0);assert.equal(p.flights[3],0); + for(let i=1;i<4;i++)assert.ok(p.cumulative[i]>=p.cumulative[i-1]); + assert.ok(p.flights.every(x=>x>=0&&x<=1));count++; + } + for(let tick=960;tick>=0;tick-=13)assert.deepEqual(lessonPose(sample(tick/20,{id,future}),reduced),snapshots[tick]); +} +console.log(`Attention teaching pose: ${count} cases; raw/stable normalization, dot products, cumulative sum, masked no-flight and reverse seek passed.`); + +const path=[[0,0],[10,0],[10,10],[30,10]]; +assert.deepEqual(pointOnPath(path,0),[0,0]);assert.deepEqual(pointOnPath(path,1),[30,10]); +assert.deepEqual(pointOnPath(path,.25),[10,0]);assert.deepEqual(pointOnPath(path,.5),[10,10]); +for(let i=0;i<=100;i++){const [x,y]=pointOnPath(path,i/100);assert.ok(y===0||x===10||y===10);} +console.log('Causal pointer path: exact junctions/endpoints and segment containment pass.'); + +for(const id of [-1,0,1])for(const future of [0,1000])for(const phase of [2,3,4,5]){ + const f={...sample(48,{id,future}),phase,progress:0}; + const expected=phase===2?f.scores:phase===3?f.masked:phase===4?f.probs:f.terms; + for(const progress of [0,.03,.09,.179,.18,1]){ + const h=handoff({...f,progress});assert.deepEqual(h.values,expected);assert.ok(h.progress>=0&&h.progress<=1);assert.equal(h.inTransit,progress<.18); + assert.equal(handoff({...f,progress},true).inTransit,false); + } +} +console.log('Chapter handoff: exact value/unit ownership and reduced-motion endpoints pass.'); + +// Causality boundaries, independently chosen from chapter start/end semantics. +for(const future of [0,1000])for(const id of [-1,0,1]){ + for(const phase of [2,3,4,5]){ + const base={...sample(48,{id,future}),phase}; + for(const progress of [0,.09,.179,.18]){ + const p=lessonPose({...base,progress});assert.equal(p.operation,0); + assert.ok(p.flights.every(x=>x===0)); + } + const end=lessonPose({...base,progress:1});assert.equal(end.operation,1);assert.equal(end.travel,1); + end.flights.forEach((x,i)=>assert.equal(x,base.terms[i]===0?0:1)); + } + const a=lessonPose({...sample(35,{id,future}),phase:4}),b=lessonPose({...sample(35,{id,future:1000-future}),phase:4}); + assert.deepEqual(a.flights,b.flights);assert.deepEqual(a.cumulative,b.cumulative); +} +console.log('Post-handoff operations wait for arrival, finish exactly, and preserve future isolation.'); diff --git a/apps/site/learn/attention/stage.mjs b/apps/site/learn/attention/stage.mjs index f386ca2..3e74e88 100644 --- a/apps/site/learn/attention/stage.mjs +++ b/apps/site/learn/attention/stage.mjs @@ -1,30 +1,128 @@ import {TOKENS,COLORS} from './model.mjs'; +import {lessonPose,pointOnPath,handoff} from './pose.mjs'; const NS='http://www.w3.org/2000/svg'; +const INKS=['#3f6092','#73568f','#3e7560','#925b43']; +const fmt=x=>Number.isFinite(x)?x.toFixed(3).replace(/\.?0+$/,''):'−∞'; export function createStage(host,{reducedMotion=()=>false}={}){ - const svg=document.createElementNS(NS,'svg');host.append(svg);svg.style.cssText='width:100%;height:100%;overflow:visible';svg.setAttribute('role','img');let last,key='',anchor=[250,0]; - function render(f){last=f;const mobile=host.clientWidth<600,W=mobile?500:900,H=360,cw=(W-70)/4,p=reducedMotion()?1:Math.min(1,f.progress*1.7),k=[W,f.phase,f.alpha,f.future,f.phase===4?Math.round(p*120):''].join('|');if(k===key)return;key=k;svg.setAttribute('viewBox',`0 0 ${W} ${H}`);svg.replaceChildren(); - const n=(tag,attrs)=>{const el=document.createElementNS(NS,tag);for(const[k,v]of Object.entries(attrs))el.setAttribute(k,v);svg.append(el);return el;}; - const text=(x,y,s,size=18,color='#6b6478',align='middle')=>{const el=n('text',{x,y,'font-family':'ui-monospace,monospace','font-size':size,fill:color,'text-anchor':align});el.textContent=s;}; - const rect=(x,y,w,h,fill,stroke='#ded8e3',rx=5)=>n('rect',{x,y,width:w,height:h,rx,fill,stroke,'stroke-width':.8}); - const line=(x,y,a,b,c='#d4cadc',dash='')=>n('path',{d:`M${x} ${y}L${a} ${b}`,stroke:c,fill:'none','stroke-dasharray':dash,'stroke-width':1}); - rect(W/2-140,3,280,33,'#f4f0f7');text(W/2,26,`查询 C:q = [${f.q[0].toFixed(2)}, 0]`,18,'#80669f'); - for(let i=0;i<4;i++){const x=35+i*cw,center=x+cw/2,c=COLORS[i],blocked=i===3&&f.phase>=2; - n('path',{d:`M${x} 58l5 -4h${cw-10}l-5 4Z`,stroke:'#d8d3df',fill:'#fff','stroke-width':.7});rect(x,58,cw-10,87,blocked?'#eeebe9':'#fffdfa',blocked?'#c9c3bd':c); - text(center-5,81,TOKENS[i]+(i===2?' · 当前':i===3?' · 未来':''),16,blocked?'#a2988f':c); - text(center-5,108,`K=[${f.keys[i].join(',')}]`,mobile?15:17,blocked?'#b4aaa2':'#7d7488');text(center-5,134,`V=${f.values[i]}`,18,blocked?'#b4aaa2':c); - if(f.phase>=1){text(center-5,172,blocked?'−∞':f.scores[i].toFixed(1),22,blocked?'#a99c91':c);if(blocked){line(x+8,92,x+cw-18,118,'#c8b9ae');text(center-5,195,'已遮罩',13,'#a8998e');}} - if(f.phase>=3){const bw=cw-24;rect(x+3,204,bw,10,'#eeebef');rect(x+3,204,bw*f.probs[i],10,c,c,2);text(center-5,239,`${(f.probs[i]*100).toFixed(1)}%`,19,blocked?'#ad9f93':c);} - if(f.phase===3)text(center-5,267,`exp=${i===3?'0':Math.exp(f.scores[i]).toFixed(3)}`,14,blocked?'#ad9f93':c); - if(f.phase>=4){const q=f.phase===4?p:1;line(center-5,249,center-5,249+11*q,c,blocked?'2 4':'');text(center-5,281,`${f.terms[i].toFixed(3)}`,17,blocked?'#ad9f93':c);} + const svg=document.createElementNS(NS,'svg');host.append(svg);svg.style.cssText='width:100%;height:100%;overflow:visible';svg.setAttribute('role','img');let last,anchor=[195,25]; + function render(f){last=f;const mobile=host.clientWidth<600,W=mobile?390:900,H=500,pose=lessonPose(f,reducedMotion()),phase=f.phase,transfer=handoff(f,reducedMotion()); + svg.setAttribute('viewBox',`0 0 ${W} ${H}`);svg.replaceChildren(); + const n=(tag,a,parent=svg)=>{const e=document.createElementNS(NS,tag);for(const[k,v]of Object.entries(a))e.setAttribute(k,v);parent.append(e);return e;}; + const text=(x,y,s,size=18,c='#515d70',align='middle',parent=svg)=>{if(mobile)size=Math.max(size,18);const e=n('text',{x,y,'font-family':'ui-monospace,monospace','font-size':size,fill:COLORS.includes(c)?INKS[COLORS.indexOf(c)]:c,'text-anchor':align},parent);e.textContent=s;return e;}; + const line=(x,y,ex,ey,c='#c5cdd7',parent=svg)=>n('path',{d:`M${x} ${y}L${ex} ${ey}`,stroke:c,fill:'none','stroke-width':.8,'vector-effect':'non-scaling-stroke'},parent); + const plate=(x,y,w,h,c='#f8f9fa',parent=svg)=>{ + // Quantitative faces stay frontal. Only the carrying plate has depth. + n('rect',{x:x+3,y:y+5,width:w+4,height:h+3,rx:5,fill:'#8f9baa',opacity:.08},parent); + n('path',{d:`M${x+w} ${y+4}l5 4v${h-4}l-5 -4Z`,fill:'#dfe5eb',stroke:'#b9c6d2','stroke-width':.7},parent); + n('path',{d:`M${x+4} ${y+h}H${x+w}l5 4H${x+9}Z`,fill:'#d0d9e2',stroke:'#b9c6d2','stroke-width':.7},parent); + n('rect',{x,y,width:w,height:h,rx:4,fill:c,stroke:'#bdcbd7','stroke-width':.85},parent); + line(x+5,y+1,x+w-5,y+1,'#fff',parent); + }; + const active=pose.active,c=COLORS[active],collecting=phase===3&&!transfer?.inTransit&&pose.collect<1; + const arrived=(i,t=.9)=>i=t; + plate(12,4,W-24,108); + const titles=['查询 C · 一条 Q,四组 K/V',`逐项匹配 · ${TOKENS[active]}`, '先遮住未来 D,再做 Softmax',transfer?.inTransit?'分数 → 指数 → 共同分母':collecting?'共同分母 · 汇集全部指数权重':`同一个分母 · Σ exp(s) ≈ ${fmt(pose.denominator)}`,`逐项读取 · ${TOKENS[active]}`,'所有贡献相加,不是挑最大的一项']; + text(W/2,25,titles[phase],mobile?17:19,phase===2?COLORS[3]:c); + let formula=`q ≈ [${fmt(f.q[0])}, 0]`; + if(phase===1)formula=mobile?`(${fmt(f.q[0])}×${f.keys[active][0]} + 0) / √2 ≈ ${fmt(f.scores[active])}`:`(${fmt(f.q[0])} × ${f.keys[active][0]} + 0 × ${f.keys[active][1]}) / √2 ≈ ${fmt(f.scores[active])}`; + if(phase===2)formula=`${fmt(f.scores[3])} → −∞ → exp(−∞) = 0`; + if(phase===3&&transfer?.inTransit)formula=`exp(${fmt(f.masked[active])}) ≈ ${fmt(pose.weights[active])}`; + if(phase===3&&!transfer?.inTransit)formula=`${fmt(pose.weights[active])} / ${fmt(pose.denominator)} ≈ ${(100*f.probs[active]).toFixed(1)}%`; + if(phase===4)formula=`${(100*f.probs[active]).toFixed(1)}% × ${f.values[active]} ≈ ${f.terms[active].toFixed(3)}`; + if(phase===5)formula=`${(active?pose.cumulative[active-1]:0).toFixed(3)} + ${f.terms[active].toFixed(3)} ≈ ${pose.cumulative[active].toFixed(3)}`; + if(phase!==1&&!collecting)text(W/2,66,formula,mobile?17:22,c); + if(collecting){ + const done=Math.min(4,Math.floor(pose.collect*4)),centers=[.15,.38,.61,.84].map(v=>v*W); + for(let i=0;i<4;i++){const x=centers[i],on=i<=done; + text(x,53,fmt(pose.weights[i]),mobile?17:21,on?COLORS[i]:'#a0a7af'); + if(i<3)text((x+centers[i+1])/2,53,'+',16); + line(x,60,x,70,COLORS[i]);line(x,70,W/2,70,COLORS[i]); + } + const part=pose.weights.slice(0,done).reduce((a,b)=>a+b,0); + formula=`Σ exp(s) ≈ ${fmt(part)}${done<4?' …':''}`; + text(W/2,91,formula,mobile?17:21); } - if(f.phase===0)text(W/2,213,'输入:一条查询 + 四组 K/V',18,'#8d7c9e'); - if(f.phase===1)text(W/2,223,'分数 sⱼ = q·kⱼ / √2',21,'#8d7c9e'); - if(f.phase===2)text(W/2,245,'未来 D:exp(−∞) = 0',21,'#9a8474'); - if(f.phase===3)text(W/2,329,`p = exp(s) / ${f.scores.slice(0,3).reduce((s,v)=>s+Math.exp(v),0).toFixed(3)}`,17,'#8d7c9e'); - if(f.phase>=3){text(W/2,f.phase===3?286:303,f.phase===3?'各条宽度:权重 0 → 100%':'每一项:pⱼ × Vⱼ',15,'#9b89a9');} - if(f.phase>=4){const bx=65,bw=W-130,q=f.phase===4?p:1;let offset=0;for(let i=0;i<4;i++){const w=bw*f.terms[i]/20*q;rect(bx+offset,314,w,17,COLORS[i],COLORS[i],0);offset+=w;}line(bx,336,bx+bw,336);text(bx,354,'0',12,'#aa9bb3');text(bx+bw,354,'20',12,'#aa9bb3');text(W/2,354,`输出 o = ${f.output.toFixed(3)}`,19,'#80669f');} - anchor=f.phase===0?[W/2,3]:f.phase===1?[28,165]:f.phase===2?[W-31,166]:f.phase===3?[30,209]:f.phase===4?[28,276]:[65,322]; - svg.setAttribute('aria-label',`当前位置 C,查询 ${f.alpha},阶段 ${f.phase+1};${f.phase>=3?'权重 '+f.probs.map(x=>x.toFixed(4)).join('、'):''}${f.phase>=4?';输出 '+f.output.toFixed(3):''}`); + if(phase===1){ + const centers=[W*.27,W*.73],merge=W/2; + for(let j=0;j<2;j++){ + const x=centers[j],on=pose.travel>=j*.28&&pose.travel<(j+1)*.28; + n('rect',{x:x-(mobile?72:125),y:33,width:mobile?144:250,height:38,rx:4,fill:on?'#edf2f6':'#fffdfa',stroke:c,'stroke-width':on?1.2:.6}); + text(x,49,`${fmt(f.q[j])} × ${f.keys[active][j]}`,mobile?17:19,c); + text(x,67,fmt(pose.products[j]),mobile?17:21,c); + const path=[[x,71],[x,81],[merge,81],[merge,87]]; + n('path',{d:path.map((p,i)=>`${i?'L':'M'}${p.join(' ')}`).join(''),fill:'none',stroke:c,'stroke-width':.7}); + if(pose.travel>=.56&&pose.travel<.75){const dot=pointOnPath(path,(pose.travel-.56)/.19);n('circle',{cx:dot[0],cy:dot[1],r:3,fill:c});} + } + text(merge,108,`(${fmt(pose.products[0])} + ${fmt(pose.products[1])}) / √2 ≈ ${fmt(f.scores[active])}`,mobile?17:20,c); } - return {render,projectAnchor(){const m=svg.getScreenCTM(),r=host.getBoundingClientRect();if(!m||!r.width)return null;const pt=svg.createSVGPoint();pt.x=anchor[0];pt.y=anchor[1];const z=pt.matrixTransform(m);return {x:(z.x-r.left)/r.width,y:(z.y-r.top)/r.height,routeLeft:last.phase>0&&last.phase!==2,bendX:(m.a*12+m.e-r.left)/r.width};},resize(){key='';if(last)render(last);},dispose(){svg.remove();}}; + if(phase===2)text(W/2,98,'展示遮罩规则;未来位置始终不参与',mobile?17:18,'#8e7466'); + if(phase===0)text(W/2,98,'同一行同色 · A → B → C → D',mobile?15:18); + if((phase===3||phase===4)&&!collecting)text(W/2,98,transfer?.inTransit?'完整精度计算 · 交接时数值不变':'完整精度计算 · 展示值已取近似',mobile?17:18); + + const col1=mobile?135:285,col2=mobile?280:645,rowTop=145,rowStep=64; + text(col1,133,['键 K','键 K','原始分数 s','指数权重 exp(s)','权重 × 内容 V','各位置贡献'][phase],16); + text(col2,133,['内容 V','匹配分数','遮罩后 s̃','归一化权重','贡献 p × V','累计相加'][phase],16); + for(let i=0;i<4;i++){ + const y=rowTop+i*rowStep,color=COLORS[i],g=n('g',{'data-position':TOKENS[i]}); + plate(20,y,W-40,50,i===3&&phase>=2?'#f2efeb':'#fffefa',g); + if(!transfer?.inTransit&&!collecting&&phase!==0&&phase!==2&&i===active)n('rect',{x:20,y,width:W-40,height:50,rx:4,fill:'none',stroke:color,'stroke-width':1.4},g); + n('rect',{x:21,y:y+5,width:3,height:40,rx:1,fill:color},g); + text(45,y+28,TOKENS[i],22,color,'middle',g); + let left='',right=''; + if(phase===0){left=`[${f.keys[i].join(', ')}]`;right=String(f.values[i]);} + if(phase===1){left=`[${f.keys[i].join(', ')}]`;right=fmt(f.scores[i]);} + if(phase===2){left=fmt(f.scores[i]);right=fmt(f.masked[i]);} + if(phase===3){left=fmt(pose.weights[i]);right=`${(100*f.probs[i]).toFixed(1)}%`;} + if(phase===4){left=`${(100*f.probs[i]).toFixed(1)}% × ${f.values[i]}`;right=f.terms[i].toFixed(3);} + if(phase===5){left=f.terms[i].toFixed(3);right=pose.cumulative[i].toFixed(3);} + if(transfer?.inTransit){ + const t=transfer.progress,x=col2+(col1-col2)*t; + line(col2,y+40,col1,y+40,color,g); + text(x,y+28,`${transfer.unit}${f.phase>=4?'≈':'='}${Number.isFinite(transfer.values[i])?f.phase===4?(100*transfer.values[i]).toFixed(1)+'%':fmt(transfer.values[i]):'−∞'}`,mobile?17:21,color,'middle',g); + }else{ + text(col1,y+28,left,mobile?17:21,color,'middle',g); + const scoreArrived=phase===1?arrived(i,.9):phase===3?!collecting&&arrived(i):phase===4?arrived(i,.55):phase===5?arrived(i,.6):true; + if(scoreArrived)text(col2,y+28,right,mobile?17:21,color,'middle',g); + } + if(phase===1&&i===active&&pose.travel>=.75&&pose.travel<.9){ + const path=[[W/2,114],[W-12,114],[W-12,y+28],[col2,y+28]],q=(pose.travel-.75)/.15,point=pointOnPath(path,q); + n('path',{d:path.map((p,j)=>`${j?'L':'M'}${p.join(' ')}`).join(''),fill:'none',stroke:color,'stroke-width':.7}); + text(point[0],point[1],fmt(f.scores[i]),mobile?17:21,color); + } + if(phase===3&&!transfer?.inTransit){ + const full=mobile?116:250,x=col2-full/2,reveal=collecting?0:i0)n('rect',{x,y:y+37,width:full*f.probs[i]*reveal,height:6,rx:2,fill:color},g); + for(const t of [0,.5,1])line(x+full*t,y+44,x+full*t,y+47,'#bbc5ce',g); + } + if(phase===4&&!transfer?.inTransit&&i<3){ + const full=mobile?110:230,x=col1-full/2,yb=y+36; + // Outline is V, filled length is pV, both on the same 0..20 scale. A zero V stays zero. + n('rect',{x,y:yb,width:full*f.values[i]/20,height:7,fill:'none',stroke:color,'stroke-width':.7,'stroke-dasharray':'2 2'},g); + const computed=arrived(i,.55),reveal=i0)n('rect',{x,y:yb,width:full*f.terms[i]/20*reveal,height:7,fill:color},g); + if(computed)line(x+full*f.terms[i]/20,yb-2,x+full*f.terms[i]/20,yb+10,color,g); + } + if(phase===2&&i===3){const x=W-23-(W-46)*pose.mask;n('rect',{x,y:y+2,width:(W-46)*pose.mask,height:46,fill:'#d6cbbf',opacity:.16},g);line(W-32,y+6,x+5,y+44,color,g);} + // Continuous trace links an exact operation to its owning row; values never interpolate. + if((phase===1||phase===3||phase===5)&&!transfer?.inTransit&&!collecting){const x=col1+(col2-col1)*pose.travel;if(i===active){line(col1,y+33,col2,y+33,color,g);n('circle',{cx:x,cy:y+33,r:3,fill:color,stroke:'#fff'},g);}} + } + // V contributions travel to cumulative slots; final segment lengths use shared 0..20 scale. + const bx=30,bw=W-60,by=438; + if(phase>=4){let start=0;for(let i=0;i<4;i++){ + const w=bw*f.terms[i]/20,x=bx+bw*start/20;const q=phase===5?1:pose.flights[i]; + if(w>0&&q===1)n('rect',{x,y:by,width:w,height:16,fill:COLORS[i]}); + const sx=W-20,sy=rowTop+i*rowStep+25,tx=x+w/2,corridor=W-14+i*3; + const path=[[sx,sy],[corridor,sy],[corridor,by-2],[tx,by-2],[tx,by+8]]; + if(phase===4&&!transfer?.inTransit&&w>0&&q>0){n('circle',{cx:sx,cy:sy,r:2.5,fill:'#fffdfa',stroke:COLORS[i],'stroke-width':1});n('path',{d:path.map((p,j)=>`${j?'L':'M'}${p.join(' ')}`).join(''),fill:'none',stroke:COLORS[i],'stroke-width':.7,'stroke-dasharray':'2 3'});} + if(phase===4&&w>0&&q>0&&q<1){const dot=pointOnPath(path,q);n('circle',{cx:dot[0],cy:dot[1],r:4,fill:COLORS[i],stroke:'#fff'});} + start+=f.terms[i]; + }line(bx,by+22,bx+bw,by+22);for(const v of [0,10,20]){const x=bx+bw*v/20;line(x,by+20,x,by+25);text(x,by+43,String(v),16);} + const allArrived=phase===5||pose.flights.every((q,i)=>f.terms[i]===0||q===1); + text(W/2,by-10,allArrived?`最终输出 o ≈ ${f.output.toFixed(3)}`:mobile?'虚线 V · 实色 pV · 同尺度 0→20':'虚线是 V,实色是 pV · 同一 0→20 刻度',mobile?17:20,'#66527e'); + }else text(W/2,474,phase===3?'每条长度用同一 0 → 100% 刻度':'手写教学 Q/K/V · 不运行真实模型',16,'#7d7285'); + anchor=phase===2?[24,rowTop+3*rowStep+25]:phase===4?[24,rowTop+active*rowStep+25]:[W/2,4]; + svg.setAttribute('aria-label',`当前位置 C;阶段 ${phase+1};${formula}。当前跟踪 ${TOKENS[active]};未来 D 不参与输出`); + } + return {render,projectAnchor(){const m=svg.getScreenCTM(),r=host.getBoundingClientRect();if(!m||!r.width)return null;const pt=svg.createSVGPoint();pt.x=anchor[0];pt.y=anchor[1];const z=pt.matrixTransform(m);return{x:(z.x-r.left)/r.width,y:(z.y-r.top)/r.height,routeLeft:last.phase===2||last.phase===4,bendX:12/(host.clientWidth<600?390:900)};},resize(){if(last)render(last);},dispose(){svg.remove();}}; } diff --git a/apps/site/learn/attention/style.css b/apps/site/learn/attention/style.css index 6948a2f..55b8514 100644 --- a/apps/site/learn/attention/style.css +++ b/apps/site/learn/attention/style.css @@ -20,3 +20,6 @@ dialog{border:1px solid #e5dce9;background:#fffdf8;border-radius:18px;max-width: .reduce-motion *{animation:none!important;transition:none!important}#reduce-motion{accent-color:#8b749e;margin-right:8px} #future{width:100px}.controls label{display:flex;align-items:center;gap:8px}.controls output{min-width:25px}.controls .presets button{padding:8px 10px}@media(max-width:700px){.controls{height:100px;max-height:100px}.controls label{font-size:10px;flex:1}#future{width:75px}.presets{justify-content:space-around}.controls .hint{display:none}.exhibit{min-height:435px}} +/* Keep quantitative type readable; narrow views recompose as persistent rows. */ +.exhibit{min-height:700px}.artwork svg text{stroke:none} +@media(max-width:700px){.exhibit{min-height:700px}.callout p{font-size:14px}} diff --git a/docs/ai-learning/STATUS.md b/docs/ai-learning/STATUS.md index 6754e7c..9a72339 100644 --- a/docs/ai-learning/STATUS.md +++ b/docs/ai-learning/STATUS.md @@ -1,10 +1,10 @@ # AI principles course status -Updated: 2026-10-28 (Asia/Shanghai). +Updated: 2026-10-30 (Asia/Shanghai). Current total: **4 / 10 published**. **Visual acceptance reopened for all four on 2026-10-28 after user feedback.** Token-choice follow-up has passed developer visual/teaching review and its checked release is verified in production; the other three remain open. Next rework: **Attention**. New topics, including Transformer, are on hold until the four-scene rework queue passes the updated review gates. -See [Anatomy comparison and concrete findings](reviews/2026-10-28-anatomy-quality.md). Rework order: token-choice → attention → tokenization → embedding. Keep existing routes and mathematical/release evidence. Publication status does not mean the renewed visual gate has passed. The initial comparison changed no website implementation or distributed Skill. A subsequent token-choice repair exists only on the draft branch described below. +See [Anatomy comparison and concrete findings](reviews/2026-10-28-anatomy-quality.md). Rework order: token-choice → attention → tokenization → embedding. Keep existing routes and mathematical/release evidence. Publication status does not mean the renewed visual gate has passed. The initial comparison changed no website implementation or distributed Skill. The token-choice repair was subsequently released; the draft paragraph below is historical and superseded by its production receipt. Historical “Next” statements below describe the release sequence at that time and are superseded by this active work item and roadmap. @@ -60,3 +60,18 @@ Browser returned; actual intermediate/reverse desktop frames,390px, native4× co PR #6 reviewed head `e6b74581f6a126e1d0fca9e3b72fa615407c35c2`: branch CI40676595210 success; READY preview `dpl_GqK2VrNBQNNF4WFbzUy1pKd3hJvm`. Authenticated preview HTML/app/model/stage/geometry/style responses returned200 and matched the reviewed source exactly. Preview HTTP evidence is distinct from same-source local browser actions. Merged source `26defa3024d64af69f8a4da8f66e8d23287cb523` reached production READY as `dpl_2BqeL1ySywcQwDayqUr8CqyPzoeW`; main CI40676875334 succeeded. Actual public route https://explain.funagent.app/learn/token-choice/ loaded without sign-in. Production browser inspected default32s label ownership and completed the prediction check: correctfloor feedback and return-to-diagramT=2,u=.6219,floor27.6%. The stable result withdraws the ruler, avoiding result-card/tick occlusion. Course remains4/10; next quality rework isAttention, with new topics held until the other three are reviewed. Original publication receipts remain intact. + + +## Attention causal rework draft — 2026-10-29 + +Branch `rework/attention-causal-20261029`: persistent position rows, exact operation rail, mask trace and nonzero contribution movement implemented. npm run check and17,298 new pose cases passed. Preliminary desktop Softmax observation completed. This is **not released or visually accepted**: component formation/chapter continuity and the390px/4×/lifecycle matrix still need work. Continue this candidate rather than starting a new topic. [Exact evidence and remaining gates](reviews/2026-10-29-attention-rework.md). Production remains unchanged. + + +### Attention follow-up — 2026-10-29 + +Same PR7 now has separate Q/K component wells and merge paths, routed contribution markers, correctedK header, darker text and measured15.21px narrow type. Rounded displayed arithmetic uses≈. Full tests passed; selected desktop intermediate/reverse and390px observations completed. Still draft: chapter handoffs and full4×/lifecycle/playing-layout gates remain open. No production update. + + +## Attention reviewed candidate — 2026-10-30 + +PR7 now has exact cross-chapter carriers, causal shared-denominator formation, delayed per-row result labels, same-scaleV/pV outlines and explicit source ports. Actual1×/native4×/390px intermediate evidence,31-frame narrow text/bounds checks and12 reverse geometry checks close the listed candidate craft findings. All numerical/site checks and affected playback/keyboard/manual-motion/quiz flows passed. A controlled hidden event was tested; native background scheduling, physical phones and learning-effect research remain unverified. Exact [record and screenshots](reviews/2026-10-29-attention-rework.md). Candidate passes developer review, but production is still unchanged until branch preview and source-matched release verification. Keep Attention active until that receipt; then Tokenization is next. Other published receipts and new-topic hold stay intact. Public Skill alignment remains pending. diff --git a/docs/ai-learning/reviews/2026-10-29-attention-rework.md b/docs/ai-learning/reviews/2026-10-29-attention-rework.md new file mode 100644 index 0000000..39e6833 --- /dev/null +++ b/docs/ai-learning/reviews/2026-10-29-attention-rework.md @@ -0,0 +1,77 @@ +# Attention causal rework — draft, 2026-10-29 + +Base main e26b3eb205717ca62c20020cc1dd2c134662f680. Local source tree matched latest remote main6384c685ccd49157c861d4b8872e9e6ca5280fda before changes. No AGENTS.md or openIssue/PR found. Active topic from roadmap isAttention; token-choice already has a verified release and is not redone. No production changes in this iteration. + +## Implemented candidate + +Replaced the four compressed vertical cards with persistent position rows. A single exact operation rail traces the current position through Q·K/√2, raw exponential normalization and weighted V. A/B/C/D retain color and row identity. Shared0..100% bars compare normalized weights, and contribution lengths use a shared0..20 scale. The future row receives a progressing mask shutter; nonzero V contributions travel toward cumulative slots. These are teaching traces, not simulated compute latency or physical hardware. Zero contributions, including maskedD, never emit a contribution trace. + +New independent lessonPose sampler derives products, raw exponential weights/denominator, mask progress and contribution travel from the existing sampled model. The mathematical model and counterfactual inputs are unchanged. The use of raw exponentials for the visible denominator is mathematically equivalent to the model's max-shifted stable computation; it is not a changed probability distribution. + +## Executed checks + +npm run check passed. New pose checks cover17,298 cases over3 query directions,3 futureV values, normal/reduced motion and961 times per combination. They verify exact dot-product reconstruction, raw/stable probability agreement, cumulative output, no masked contribution trace, finite bounded teaching progress and deterministic reverse seeking. Original independent Attention goldens and all other scene/mechanical checks retained. + +Official source revisited: https://docs.pytorch.org/docs/2.14/generated/torch.nn.functional.scaled_dot_product_attention.html . The scaled dot product, causal mask before softmax and weightedV remain the source-grounded relationships. + +Actual current cloud Chrome inspected the desktop initial layout and paused26s Softmax frame. The shared denominator4.086 and1/4.086=24.5% were visible in the operation rail, with the sameB row and its probability bar. This is a preliminary observation, not a complete visual acceptance. No new screenshots are represented as production evidence. + +## Why NOT released + +This is not yet the finish requested by the user. The operation rail and stable rows make numeric relationships easier to follow, but Q/K component formation is still shown mainly as a formula. Row content changes across chapters still need identity-preserving transitions rather than simple replacement. The narrow view reserves more height but has NOT been validated for actual font metrics, long values, one-screen playing behavior or collisions. Full4×/intermediate/reverse browser matrix and lifecycle/keyboard/hidden/reduced-motion/quiz tests have NOT been performed on this revision. The mask animation must also be reviewed so its progressive visual overlay is not mistaken for a gradually participating future token (the numerical mask is always exact). + +Next work on THIS branch/PR: improve component-level causality and explicit contribution connectors; inspect390px and4×, source-correct mask semantics, intermediate/reverse frames, actual controls and fixed-query/future invariance. Only then close visualAcceptance, inspect the checked branch preview, merge and verify matching production READY/SHA/domain. Do not create a new scene or duplicate this candidate. Keep Attention needs-rework, all four public routes and historical publication receipts. Skill alignment is pending and no new installation/host compatibility is claimed. No learner study or measured learning gains. + + +## Follow-up: component multiplication and phone inspection + +Continued existing PR7 from head8b6e041fc60b9ac9c09095a427ecf8b480efe92e; main unchanged. Added separate component wells forq₀k₀/q₁k₁, staged highlighting, exact product values, connected merge paths and a divide-by√2 readout. The single bubble names the currently matched position. Nonzero contribution markers now follow explicit orthogonal paths through the right margin instead of crossing unrelated rows diagonally. Mathematical lengths and values remain front-plane quantities; path animation is a teaching pointer. + +Actual desktop7.2/8.2/8.6/9.0s and reverse8.2s frames inspected. Initial390×844 iframe measured component input at13.655px, below target; increased mobile input type16→17 units, shortened repeated narration and measured resulting17-unit type at15.213 CSS px (SVG scale .89487). Corrected a semantic header bug: the left QK column containsK, so it is now labeledK rather than dot product. Darkened identity-hue text while retaining original accent colors. Inspected narrow34s withfutureV=1000, then query zero; output/model changed from15.752 to10 with future still masked. This is partial browser coverage, not a physical phone or complete matrix. + +Inspection also found misleading display arithmetic: rounded0.245×10 was printed with an equality to2.447, although internal full-precision arithmetic is correct. Changed rounded operation readouts to≈ and added a full-precision/display-rounding explanation. No values are rounded before model computation. The final wording change has source/build coverage; do not treat earlier screenshots as post-change browser proof. + +npm run check passes, retaining17,298 pose cases, original goldens and mechanical tests. Added independent path sampling checks for endpoints, exact junctions and segment containment. Official PyTorch reference rechecked at its algorithm lines459–480: scaling, mask bias, softmax then weightedV; the scene omits dropout and projections explicitly. + +Still NOT accepted or released: cross-chapter value handoffs are not yet continuous; full1×/4× craft, mask semantics, all phases/long values/mobile playing layout and lifecycle matrix remain to review. Stage height700px causes initial scrolling and must be judged against single-screen playing requirements. Avoid ending with another formula-heavy table merely because the equations pass. Continue this PR; preserve existing production and needs-rework status. No Skill sync or host-compatibility claim. + + +## Follow-up 2026-10-30 — reviewed candidate, release verification pending + +This section supersedes the earlier draft's pending craft/lifecycle items. Source changes remain on PR7 until the checked preview is inspected. No production release is claimed by this review alone. + +### Causal and craft corrections + +- Exact output carriers now move from the previous output column to the next input column during the first18% of chapters2–5. Identity, color, row and underlying value do not change; the next arithmetic operation waits for arrival. Moving displayed numbers are not interpolated into invented probabilities. +- Q/K products enter a shared merge/divide path; the computed score travels to its owning row, and future rows do not expose scores before their turn. Close inspection found a2-unit gap under a component well; its connector now starts at the well boundary. The formula has its own clearance below the merge endpoint. +- Softmax first collects raw exponential weights into one denominator. Only then does each row trace its fraction on the same0..100% ruler; its result number appears at completion. A traced bar is a teaching pointer, not a changing distribution or measured execution latency. The pending handoff heading no longer exposes the denominator result early. Narration and accessible operation description follow the same pose. +- V has a dashed original-length outline and a coloredpV portion on the same0..20 scale as the result. Nonzero contributions leave explicit ports on the row face and travel outside the data rows. A zeroV or maskedD does not emit a flight. Cumulative addition exposes exact operands, not merely a final total. +- Carrying plates now have separate front, side, bottom and contact-shadow surfaces. Quantitative lengths stay frontal and unskewed. Active outlines, component wells, common-denominator inputs, bar ticks and actual source/receiver connections provide functional detail rather than decorative parts. This is a mathematical exhibit, not a fictitious mechanical attention device or physical naked-eye stereo display. +- Key mobile SVG type has an18-unit floor and darker identity-hue ink; bubble body is14px. Displayed rounded quantities use≈, including the query, denominator and output. Internal calculations remain full precision. Corrected an old Embedding meta description on the Attention page. + +### Actual browser evidence + +Current cloud Chrome, desktop1363×936 and a390×844 iframe, same built source. The iframe is a real narrow browser layout, not a physical phone test. Native4× is CSS zoom of the vector-rendered1200×1000 iframe; screenshots are not enlarged rasters. QA controls and a repeatable output-port focus are saved in evals/browser/attention-review.html (not a public product route). + +| Evidence | Observed | +| --- | --- | +| [1× denominator](assets/2026-10-30/softmax-final.jpg) | Four colored inputs, summation bus, shared partial denominator, waiting row result slots; completed results are not all shown at chapter entry. | +| [4× component merge](assets/2026-10-30/qk-4x-final.jpg) | Both component paths meet the merge; boundary contact and formula clearance visible. | +| [4× output port](assets/2026-10-30/b-port-4x.jpg) | B's source port contacts its front face; side/bottom/shadow relationships remain coherent; the route stays outside other row data. | +| [390px handoff23.7s](assets/2026-10-30/handoff-final.jpg) | Each carried masked score retains its own row/color; no percentages or next result labels are assigned to other objects. | +| [390px weightedV38s, future1000](assets/2026-10-30/value-final.jpg) | DashedV and filledpV share a ruler; long future input remains readable; only nonzero visible-position contributions travel. | +| [390px playing](assets/2026-10-30/playing-final.jpg) | Header, one bubble, full mathematical stage, bounds label and transport fit in844px. Configuration/footer have eased out; pause restores them. Initial configuration view can scroll. | + +Browser DOM checks covered31 forward frames at0,7,8.2,8.6,8.9,14.95,15,15.7,16.5,20,22.95,23,23.7,24.5,25.5,26.5,28,30.95,31,31.8,32.8,34,36,38,39.95,40,40.7,42,44,47,48s. All SVG text stayed within its horizontal viewport. Smallest SVG type across that matrix was15.178 CSSpx; the final38s long-input frame measured the same. This is not a general proof against all font/device collisions. Twelve selected intermediate/end frames were replayed in reverse; DOM geometry attributes, text, colors and path coordinates matched their forward snapshots exactly. [Raw browser record](assets/2026-10-30/dom-checks.json). The saved matrix preceded final wording/port-only corrections; final affected23.7s/38s and4× port frames were rechecked after those corrections. + +Actual UI actions checked: Space on play, Escape pause, pause/continue, Home/End on timeline, reset, end→replay, natural47→48 completion and configuration return, info-open pause, manual reduced-motion toggle and immediate endpoints, query±/zero, future0/1000, incorrect/correct quiz feedback and verify-in-diagram return. Controlled document.hidden visibilitychange paused at1.05s and visible restoration did not auto-resume. The cloud surfaces kept document.visibilityState=visible when interacting with another tab, so OS/browser background scheduling is NOT independently verified; only the actual browser handler with a controlled hidden event is evidenced. Manual reduced motion was tested, not a device OS preference toggle. + +### Source and numerical review + +Official PyTorch2.14 source/algorithm revisited2026-10-30: scale1/sqrt(d), add causal−∞ bias before softmax, then weightedV; dropout omitted explicitly. Existing independent goldens still match outputs15.752103826,10,4.247896174, with futureV invariance. npm run check passes:17,298 pose cases, raw/stable normalization agreement, dot-product reconstruction, cumulative sums, no masked/zero flight, exact path endpoints/segments, reverse seeking, exact handoff ownership and additional post-arrival/end-boundary checks. All existing scene/mechanical tests retained; no claim that every mechanical UI was re-exercised. + +### Teaching review decision + +The input, question and changing output are explicit; the visible operation connects corresponding components, excludes a future row, divides by one denominator and combinesV contributions. The learner can pause each stage, predict the query-zero case, operate it, and inspect why the visible three-way mean is10 rather than20 or257.5. Query reversal changes the relative weights/output; changing only futureV leaves them invariant. The display distinguishes score from probability, attention mixture from token sampling, K fromV, percentage from output units, and annotation trace from actual model timing. + +Developer teaching/craft review closes the concrete reopened Attention findings for this candidate. It does not establish Anatomy equivalence, an award-level score or measured learning gains. No real learner study, physical phone, alternate browser engine or screen-reader-device study has been performed. Skill distribution alignment and untested hosts remain pending. Tokenization and Embedding reviews remain open. Release only after the exact preview head/checks and production SHA/READY/domain flow are verified; preserve original receipts. diff --git a/docs/ai-learning/reviews/assets/2026-10-30/b-port-4x.jpg b/docs/ai-learning/reviews/assets/2026-10-30/b-port-4x.jpg new file mode 100644 index 0000000..dbfb627 Binary files /dev/null and b/docs/ai-learning/reviews/assets/2026-10-30/b-port-4x.jpg differ diff --git a/docs/ai-learning/reviews/assets/2026-10-30/dom-checks.json b/docs/ai-learning/reviews/assets/2026-10-30/dom-checks.json new file mode 100644 index 0000000..c066179 --- /dev/null +++ b/docs/ai-learning/reviews/assets/2026-10-30/dom-checks.json @@ -0,0 +1,362 @@ +{ + "phoneWidth": 390, + "phoneHeight": 844, + "samples": [ + { + "label": "当前位置 C;阶段 1;q = [1.414, 0]。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A[-1, 0]0", + "B[0, 0]10", + "C[1, 0]20", + "D[2, 0]100" + ] + }, + { + "label": "当前位置 C;阶段 2;(1.414×-1 + 0) / √2 ≈ -1。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A[-1, 0]", + "B[0, 0]", + "C[1, 0]", + "D[2, 0]" + ] + }, + { + "label": "当前位置 C;阶段 2;(1.414×-1 + 0) / √2 ≈ -1。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A[-1, 0]", + "B[0, 0]", + "C[1, 0]", + "D[2, 0]" + ] + }, + { + "label": "当前位置 C;阶段 2;(1.414×-1 + 0) / √2 ≈ -1。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A[-1, 0]", + "B[0, 0]", + "C[1, 0]", + "D[2, 0]" + ] + }, + { + "label": "当前位置 C;阶段 2;(1.414×-1 + 0) / √2 ≈ -1。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A[-1, 0]-1", + "B[0, 0]", + "C[1, 0]", + "D[2, 0]" + ] + }, + { + "label": "当前位置 C;阶段 2;(1.414×2 + 0) / √2 ≈ 2。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A[-1, 0]-1", + "B[0, 0]0", + "C[1, 0]1", + "D[2, 0]2" + ] + }, + { + "label": "当前位置 C;阶段 3;2 → −∞ → exp(−∞) = 0。", + "minFont": 16.107692307692307, + "outside": [], + "rows": [ + "As=-1", + "Bs=0", + "Cs=1", + "Ds=2" + ] + }, + { + "label": "当前位置 C;阶段 3;2 → −∞ → exp(−∞) = 0。", + "minFont": 16.107692307692307, + "outside": [], + "rows": [ + "As=-1", + "Bs=0", + "Cs=1", + "Ds=2" + ] + }, + { + "label": "当前位置 C;阶段 3;2 → −∞ → exp(−∞) = 0。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A-1-1", + "B00", + "C11", + "D2−∞" + ] + }, + { + "label": "当前位置 C;阶段 3;2 → −∞ → exp(−∞) = 0。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A-1-1", + "B00", + "C11", + "D2−∞" + ] + }, + { + "label": "当前位置 C;阶段 3;2 → −∞ → exp(−∞) = 0。", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A-1-1", + "B00", + "C11", + "D2−∞" + ] + }, + { + "label": "当前位置 C;阶段 4;exp(-1) ≈ 0.368。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "As̃=-1", + "Bs̃=0", + "Cs̃=1", + "Ds̃=−∞" + ] + }, + { + "label": "当前位置 C;阶段 4;exp(-1) ≈ 0.368。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "As̃=-1", + "Bs̃=0", + "Cs̃=1", + "Ds̃=−∞" + ] + }, + { + "label": "当前位置 C;阶段 4;0.368 / 4.086 ≈ 9.0%。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A0.368", + "B1", + "C2.718", + "D0" + ] + }, + { + "label": "当前位置 C;阶段 4;0.368 / 4.086 ≈ 9.0%。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A0.368", + "B1", + "C2.718", + "D0" + ] + }, + { + "label": "当前位置 C;阶段 4;0.368 / 4.086 ≈ 9.0%。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A0.368", + "B1", + "C2.718", + "D0" + ] + }, + { + "label": "当前位置 C;阶段 4;1 / 4.086 ≈ 24.5%。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A0.3689.0%", + "B1", + "C2.718", + "D0" + ] + }, + { + "label": "当前位置 C;阶段 4;0 / 4.086 ≈ 0.0%。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "A0.3689.0%", + "B124.5%", + "C2.71866.5%", + "D00.0%" + ] + }, + { + "label": "当前位置 C;阶段 5;9.0% × 0 ≈ 0.000。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "Ap=9.0%", + "Bp=24.5%", + "Cp=66.5%", + "Dp=0.0%" + ] + }, + { + "label": "当前位置 C;阶段 5;9.0% × 0 ≈ 0.000。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "Ap=9.0%", + "Bp=24.5%", + "Cp=66.5%", + "Dp=0.0%" + ] + }, + { + "label": "当前位置 C;阶段 5;9.0% × 0 ≈ 0.000。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A9.0% × 0", + "B24.5% × 10", + "C66.5% × 20", + "D0.0% × 100" + ] + }, + { + "label": "当前位置 C;阶段 5;9.0% × 0 ≈ 0.000。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A9.0% × 00.000", + "B24.5% × 10", + "C66.5% × 20", + "D0.0% × 100" + ] + }, + { + "label": "当前位置 C;阶段 5;24.5% × 10 ≈ 2.447。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A9.0% × 00.000", + "B24.5% × 102.447", + "C66.5% × 20", + "D0.0% × 100" + ] + }, + { + "label": "当前位置 C;阶段 5;66.5% × 20 ≈ 13.305。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A9.0% × 00.000", + "B24.5% × 102.447", + "C66.5% × 2013.305", + "D0.0% × 100" + ] + }, + { + "label": "当前位置 C;阶段 5;0.0% × 100 ≈ 0.000。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A9.0% × 00.000", + "B24.5% × 102.447", + "C66.5% × 2013.305", + "D0.0% × 1000.000" + ] + }, + { + "label": "当前位置 C;阶段 6;0.000 + 0.000 ≈ 0.000。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "At=0", + "Bt=2.447", + "Ct=13.305", + "Dt=0" + ] + }, + { + "label": "当前位置 C;阶段 6;0.000 + 0.000 ≈ 0.000。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 16.034625, + "outside": [], + "rows": [ + "At=0", + "Bt=2.447", + "Ct=13.305", + "Dt=0" + ] + }, + { + "label": "当前位置 C;阶段 6;0.000 + 0.000 ≈ 0.000。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A0.000", + "B2.447", + "C13.305", + "D0.000" + ] + }, + { + "label": "当前位置 C;阶段 6;0.000 + 2.447 ≈ 2.447。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A0.0000.000", + "B2.447", + "C13.305", + "D0.000" + ] + }, + { + "label": "当前位置 C;阶段 6;15.752 + 0.000 ≈ 15.752。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A0.0000.000", + "B2.4472.447", + "C13.30515.752", + "D0.000" + ] + }, + { + "label": "当前位置 C;阶段 6;15.752 + 0.000 ≈ 15.752。权重 0.09003057317038046、0.24472847105479764、0.6652409557748218、0", + "minFont": 15.1779375, + "outside": [], + "rows": [ + "A0.0000.000", + "B2.4472.447", + "C13.30515.752", + "D0.00015.752" + ] + } + ], + "reversePass": true, + "reverseTimes": [ + 8.2, + 8.6, + 16.5, + 23.7, + 25.5, + 28, + 31.8, + 36, + 38, + 40.7, + 44, + 48 + ] +} \ No newline at end of file diff --git a/docs/ai-learning/reviews/assets/2026-10-30/handoff-final.jpg b/docs/ai-learning/reviews/assets/2026-10-30/handoff-final.jpg new file mode 100644 index 0000000..abc3882 Binary files /dev/null and b/docs/ai-learning/reviews/assets/2026-10-30/handoff-final.jpg differ diff --git a/docs/ai-learning/reviews/assets/2026-10-30/playing-final.jpg b/docs/ai-learning/reviews/assets/2026-10-30/playing-final.jpg new file mode 100644 index 0000000..85e5502 Binary files /dev/null and b/docs/ai-learning/reviews/assets/2026-10-30/playing-final.jpg differ diff --git a/docs/ai-learning/reviews/assets/2026-10-30/qk-4x-final.jpg b/docs/ai-learning/reviews/assets/2026-10-30/qk-4x-final.jpg new file mode 100644 index 0000000..ea48657 Binary files /dev/null and b/docs/ai-learning/reviews/assets/2026-10-30/qk-4x-final.jpg differ diff --git a/docs/ai-learning/reviews/assets/2026-10-30/softmax-final.jpg b/docs/ai-learning/reviews/assets/2026-10-30/softmax-final.jpg new file mode 100644 index 0000000..8ff6910 Binary files /dev/null and b/docs/ai-learning/reviews/assets/2026-10-30/softmax-final.jpg differ diff --git a/docs/ai-learning/reviews/assets/2026-10-30/value-final.jpg b/docs/ai-learning/reviews/assets/2026-10-30/value-final.jpg new file mode 100644 index 0000000..e32686d Binary files /dev/null and b/docs/ai-learning/reviews/assets/2026-10-30/value-final.jpg differ diff --git a/docs/ai-learning/roadmap.json b/docs/ai-learning/roadmap.json index 874eed8..b0f1368 100644 --- a/docs/ai-learning/roadmap.json +++ b/docs/ai-learning/roadmap.json @@ -1,6 +1,6 @@ { "version": 1, - "updated": "2026-10-28", + "updated": "2026-10-30", "target": 10, "cadenceHours": 12, "releasePolicy": "One reviewed scene per iteration; continue a failed scene before advancing.", @@ -63,9 +63,10 @@ "verifiedDeployment": "dpl_H4cKbv114YSRUKfzEGFXcdUXfE9P", "verifiedOn": "2026-10-28", "visualAcceptance": { - "status": "needs-rework", - "reviewDate": "2026-10-28", - "review": "docs/ai-learning/reviews/2026-10-28-anatomy-quality.md" + "status": "reviewed-pass", + "reviewDate": "2026-10-30", + "review": "docs/ai-learning/reviews/2026-10-29-attention-rework.md", + "evidenceType": "developer teaching/craft and actual browser review; no learner-effect study" } }, { @@ -163,11 +164,11 @@ ], "resumeAfter": "All four published scenes pass the reopened craft and causal-motion gates.", "candidate": { - "scene": "token-choice", - "branch": "fix/token-choice-morph-craft-20261028", - "status": "published-and-production-verified", - "record": "docs/ai-learning/reviews/2026-10-28-token-choice-rework.md", - "productionChanged": true + "scene": "attention", + "branch": "rework/attention-causal-20261029", + "status": "reviewed-awaiting-preview-and-release", + "record": "docs/ai-learning/reviews/2026-10-29-attention-rework.md", + "productionChanged": false } } } diff --git a/evals/browser/attention-review.html b/evals/browser/attention-review.html new file mode 100644 index 0000000..8a77f51 --- /dev/null +++ b/evals/browser/attention-review.html @@ -0,0 +1,12 @@ +Attention visual QA diff --git a/package.json b/package.json index 6323817..4ba0415 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "build": "node scripts/build.mjs", - "test": "node evals/verify.mjs && node apps/site/learn/token-choice/model.test.mjs && node apps/site/learn/token-choice/geometry.test.mjs && node evals/verify-token-choice.mjs && node evals/verify-course.mjs && node apps/site/learn/tokenization/model.test.mjs && node apps/site/learn/embedding/model.test.mjs && node apps/site/learn/attention/model.test.mjs", + "test": "node evals/verify.mjs && node apps/site/learn/token-choice/model.test.mjs && node apps/site/learn/token-choice/geometry.test.mjs && node evals/verify-token-choice.mjs && node evals/verify-course.mjs && node apps/site/learn/tokenization/model.test.mjs && node apps/site/learn/embedding/model.test.mjs && node apps/site/learn/attention/model.test.mjs && node apps/site/learn/attention/pose.test.mjs", "check": "npm test && npm run build" }, "engines": {