[{"data":1,"prerenderedAt":4413},["ShallowReactive",2],{"site-settings":3,"writing-\u002Fwriting\u002F2026-07-26-btc-synthetic-futures-arbitrage":83,"writing-navigation":295},{"id":4,"title":5,"currentFocus":6,"description":7,"extension":8,"footer":9,"headline":12,"home":14,"introduction":7,"location":28,"meta":29,"name":5,"pages":30,"services":49,"stem":72,"theme":73,"writingTopics":75,"__hash__":82},"site\u002Fsettings\u002Fsite.yml","Quilibra","正在上班当牛马。","这是我自己部署的个人主页，用于记录我的一些事情并维护我的一些服务。","yml",{"icp":10,"credit":11},"皖ICP备2026023522号","DESIGNED & BUILT BY GPT-5.6 IN CODEX",{"prefix":13,"emphasis":5},"你好，这里是",{"kicker":15,"systemsLabel":16,"latestWriting":17,"modules":23,"dock":24},"个人主页 \u002F 持续施工中","SYSTEMS",{"enabled":18,"title":19,"linkLabel":20,"emptyLabel":21,"limit":22},true,"最近写下","全部文章","暂无文章",3,{"services":18,"rgbAssembly":18},{"writing":25,"services":26,"about":27},"文章","服务","关于","China · UTC+8",{},{"writing":31,"services":35,"about":43},{"intro":32,"seoDescription":33,"emptyLabel":34},"随笔、学习、交易，以及对日常变化的观察。","随笔、学习、交易与观察。","没有找到匹配的文章。",{"intro":36,"seoDescription":37,"accessTitle":38,"accessNotes":39},"统一入口，分别运行。尚未开放的服务会在域名和登录保护完成后上线。","开发环境、相册、NAS 和运行状态。","访问说明",[40,41,42],"公开入口由 VPS 上的 Nginx 提供 HTTPS 与反向代理。","家中服务通过 Tailscale 连接，不直接暴露 NAS 或路由器端口。","开发环境、相册与影音库仍需各自完成身份验证。",{"seoDescription":44,"focusLabel":45,"topicsLabel":46,"contactLabel":47,"contactCopy":48},"一些基本信息，以及这个网站目前用来做什么。","正在做的事","关注的主题","联系","不是，你联系我干嘛？",[50,56,61,66],{"name":51,"description":52,"href":53,"state":54,"icon":55,"showOnHome":18},"Code","浏览器里的开发环境","https:\u002F\u002Fcode.example.com","soon","code",{"name":57,"description":58,"href":59,"state":54,"icon":60,"showOnHome":18},"Photos","照片备份和浏览","https:\u002F\u002Fphotos.example.com","image",{"name":62,"description":63,"href":64,"state":54,"icon":65,"showOnHome":18},"NAS","文件与存储管理","https:\u002F\u002Fnas.example.com","hard-drive",{"name":67,"description":68,"href":69,"state":70,"icon":71,"showOnHome":18},"Status","服务可用性与故障记录","https:\u002F\u002Fstatus.example.com","online","activity","settings\u002Fsite",{"defaultAccent":74},"#006eff",[76,77,78,79,80,81],"看盘看线","捣鼓电脑","折腾NAS","踢踢野球","看看科普","玩币练胆","rzNwl0NJTHNz-9N0akkaLLep7T3BRIkBtg-HrZ3RTZ8",{"id":84,"title":85,"body":86,"category":276,"date":277,"description":278,"extension":279,"meta":280,"navigation":18,"path":281,"publishedAt":282,"seo":283,"slug":284,"stem":285,"tags":286,"updated":293,"__hash__":294},"writing\u002Fwriting\u002F2026-07-26-btc-synthetic-futures-arbitrage.md","BTC期权合成期货套利：用定价偏差锁定无风险利润",{"type":87,"value":88,"toc":265},"minimark",[89,93,98,101,104,108,116,126,129,132,135,141,147,150,154,157,160,164,171,177,180,183,197,202,210,216,221,235,240,252,255,259,262],[90,91,92],"p",{},"看到一套量化交易系统看板：年化 197%、极低回撤、多平仓少持仓。核心策略是利用 Deribit 期权市场合成的虚拟期货价格与 Binance 永续合约价格之间的定价偏差进行对冲套利。当时对着看板追问了 AI 几轮，才把这套合成期货套利的逻辑理清楚。这篇文章是给自己留的复盘笔记。",[94,95,97],"h2",{"id":96},"deribit-是什么","Deribit 是什么",[90,99,100],{},"Deribit 是目前加密货币期权交易量最大的交易所，总部在巴拿马，2016 年上线。BTC 和 ETH 期权的主流流动性都在这里，行权价、到期日覆盖范围广，机构参与度高。它的期权以币本位结算（BTC 期权用 BTC 结算），也支持永续合约和交割期货。",[90,102,103],{},"正因为 Deribit 在期权市场的深度优势，它的期权定价成为合成期货策略的基础端。另一端选 Binance 永续合约，是因为 Binance 流动性最好、API 稳定、支持开空，适合做对冲腿。",[94,105,107],{"id":106},"核心概念合成期货","核心概念：合成期货",[90,109,110,111,115],{},"期权平价公式告诉我们：",[112,113,114],"strong",{},"买入 Call + 卖出 Put = 合成期货多头","。",[117,118,119,123],"ul",{},[120,121,122],"li",{},"买入 Call（看涨期权）：涨了赚，跌了不亏",[120,124,125],{},"卖出 Put（看跌期权）：涨了没事，跌了亏",[90,127,128],{},"两者组合后的盈亏轨迹，与直接持有 BTC 现货或期货完全一致——涨了赚、跌了亏。这就是\"合成期货\"。",[94,130,131],{"id":131},"两种套利方向",[90,133,134],{},"关键在于：Deribit 期权合成的期货价格，和 Binance 永续合约的价格，经常不一致。",[90,136,137,140],{},[112,138,139],{},"转换套利（Conversion \u002F SF+BS）","：当合成期货价格 > Binance 期货价格时，在 Deribit 卖出合成期货（卖出 Call + 买入 Put），同时在 Binance 买入永续合约。",[90,142,143,146],{},[112,144,145],{},"反转套利（Reversal \u002F BF+SS）","：当合成期货价格 \u003C Binance 期货价格时，在 Deribit 买入合成期货（买入 Call + 卖出 Put），同时在 Binance 卖出永续合约。",[90,148,149],{},"本质上就是\"哪边便宜哪边买，哪边贵了哪边卖\"。",[94,151,153],{"id":152},"对冲机制为什么涨跌都不怕","对冲机制：为什么涨跌都不怕",[90,155,156],{},"币安端永远做与 Deribit 完全相反的动作。Deribit 开合成多头，Binance 必开永续空头。BTC 暴涨暴跌时，两端的盈亏完全抵消，行情风险归零。",[90,158,159],{},"利润不来自方向判断，而是开仓瞬间两端的定价差。期权到期结算时，合成价格强制回归现货价，基差收敛完成无风险落袋。",[94,161,163],{"id":162},"一个关键区分行权价-现价","一个关键区分：行权价 ≠ 现价",[90,165,166,167,170],{},"看板中的合约代码 ",[55,168,169],{},"BTC-10JUN26-62000","，62000 是行权价，不是当时的市场现价。当时 Binance 的标记价约为 62,991 美元。因为现价高于行权价，看涨期权呈浮盈状态，看跌期权的权利金已被吃满。",[90,172,173,174,115],{},"比对套利机会时，标的不是行权价本身，而是",[112,175,176],{},"合成总成本 = 行权价 + 买Call权利金 - 卖Put权利金",[94,178,179],{"id":179},"完整数值演练",[90,181,182],{},"设定场景：",[117,184,185,188,191],{},[120,186,187],{},"Binance 现价：$63,000",[120,189,190],{},"Deribit 行权价 $62,000 的期权：Call 权利金 $1,500，Put 权利金 $300",[120,192,193,194],{},"合成空头总成本：$62,000 + $1,500 - $300 = ",[112,195,196],{},"$63,200",[90,198,199],{},[112,200,201],{},"开仓动作：",[117,203,204,207],{},[120,205,206],{},"Binance 开多，$63,000",[120,208,209],{},"Deribit 合成空头（卖 Call + 买 Put），$63,200",[90,211,212,213],{},"开仓瞬间锁定利润：$63,200 - $63,000 = ",[112,214,215],{},"$200",[90,217,218],{},[112,219,220],{},"极端行情 A - 暴涨至 $80,000：",[117,222,223,226,229],{},[120,224,225],{},"Binance 多头盈利：+$17,000",[120,227,228],{},"Deribit 合成空头亏损：-$16,800",[120,230,231,232],{},"合计：",[112,233,234],{},"+$200",[90,236,237],{},[112,238,239],{},"极端行情 B - 暴跌至 $40,000：",[117,241,242,245,248],{},[120,243,244],{},"Binance 多头亏损：-$23,000",[120,246,247],{},"Deribit 合成空头盈利：+$23,200",[120,249,231,250],{},[112,251,234],{},[90,253,254],{},"无论涨跌，总利润始终为开仓时锁定的 $200。到期自动结算收敛，整个过程是左手倒右手，利润在开仓那一下就已经确定了。",[94,256,258],{"id":257},"模型不难难的是工程","模型不难，难的是工程",[90,260,261],{},"这套套利的交易系统作者说过一句话：套利模型倒是不难，难的是一些工程上的事情。",[90,263,264],{},"确实，逻辑上这就是一个低买高卖的价差捕捉，但实际跑起来要处理的问题远比模型复杂：两个交易所的 API 延迟差异、订单簿深度和滑点、手续费摩擦对利润空间的侵蚀、资金在两个平台之间的划转效率、期权到期时的自动结算对齐、极端行情下的风控（硬止损、Gamma 检查、行情降级）、以及资金容量上限——能套的价差就那么多，资金量大了反而吃不掉。这些工程细节才是决定系统能不能真正赚钱的关键。",{"title":266,"searchDepth":267,"depth":267,"links":268},"",2,[269,270,271,272,273,274,275],{"id":96,"depth":267,"text":97},{"id":106,"depth":267,"text":107},{"id":131,"depth":267,"text":131},{"id":152,"depth":267,"text":153},{"id":162,"depth":267,"text":163},{"id":179,"depth":267,"text":179},{"id":257,"depth":267,"text":258},"交易","2026-07-26","看到一套量化套利系统后追问AI，拆解Deribit合成期货与Binance永续合约之间的跨平台套利逻辑，含完整数值演练。","md",{},"\u002Fwriting\u002F2026-07-26-btc-synthetic-futures-arbitrage","2026-07-26T13:37:11+08:00",{"title":85,"description":278},"btc-synthetic-futures-arbitrage","writing\u002F2026-07-26-btc-synthetic-futures-arbitrage",[287,288,289,290,291,292],"BTC","期权","套利","合成期货","Deribit","Binance",null,"dVKWlNkJcxTfn3YYwF5uVjOPge4iiTrAaM6UeVy3dTE",[296,396,452,495,626,848,951,3920,4092,4271],{"id":297,"title":298,"body":299,"category":276,"date":383,"description":384,"extension":279,"meta":385,"navigation":18,"path":386,"publishedAt":387,"seo":388,"slug":389,"stem":390,"tags":391,"updated":293,"__hash__":395},"writing\u002Fwriting\u002F2026-07-27-crypto-40u-experiment.md","40U学费：从负和博弈到跨市场认知",{"type":87,"value":300,"toc":375},[301,304,307,310,313,317,320,323,327,330,333,336,340,343,346,350,353,356,359,362,366,369,372],[94,302,303],{"id":303},"永续合约是负和博弈",[90,305,306],{},"抖音上有一段对话：我说永续合约是散户对定价没有意义的负和博弈，靠这个发财基本不可能；作者回的是任何行业顶端才能赚钱；我又说自己只是普通人，稳定赚钱只有量化套利，但那需要工程和数学能力，主观交易做不到。",[90,308,309],{},"永续合约负和博弈的判断是准确的，散户无定价权也是事实。之前看到一个爆仓博主 3k 做到几百万 U 再爆仓，大概率是高杠杆顺势重仓，运气成分大于能力。作者那句\"顶端才能赚钱\"是正确的废话。",[90,311,312],{},"但\"只有量化套利\"这句话，我说的时候不是在指路，是一种无奈的总结。我知道答案在那里，但那条路跟我没关系--期权、滑点、费率是什么都要从头研究，根本不懂套利，也不愿意投入时间去尝试。",[94,314,316],{"id":315},"_40u当学费","40U当学费",[90,318,319],{},"我只有 40U，考虑用永续合约当赌场，目的是了解这个生态、DEX、去中心化交易所、加密货币逻辑、衍生品交易是什么。不考虑靠这个赚钱。",[90,321,322],{},"这个框架是合理的。40U 当学费做实操学习，比看文章有效得多，亏完也就 40U，但获得的是真实系统认知。唯一要提前做的是在心里把这 40U 标记为已花出去的学费，不要因为小赚了就开始加仓--那是体验性操作滑向真实赌博最常见的节点。",[94,324,326],{"id":325},"区块链被ai抢了梦","区块链被AI抢了梦？",[90,328,329],{},"刷到一个叫 Danielli 的视频，说 AI 好像把区块链的梦抢走了，区块链十几年发展远不如 AI 两年影响大，现在只剩投机资产和交易所收割流动性。",[90,331,332],{},"论点有观察基础但逻辑跳跃。AI 和区块链解决的不是同一类问题，拿改变日常生活的速度来比较是错误框架。评论区多数是噪音，少数有效观点比如\"全球支付是真实用例\"、\"AI 是科技升级、区块链是金融升级\"。",[90,334,335],{},"我在评论区说了区块链牛逼的是去中心化可编程智能合约，未来作为数字支付基础设施、跨国转账、大宗商品定价都大有所为，加了个 🌝。",[94,337,339],{"id":338},"的社交防御","🌝 的社交防御",[90,341,342],{},"在抖音评论区这种环境里，凭啥要和这帮人认真讨论？要么骗流量要么情绪化。加 🌝 是主动压低信噪比，预防别人觉得我懂得多喜欢装然后骂我。这是理性的社交防御策略，不是不自信。认真展开论证的成本远大于收益。",[90,344,345],{},"唯一要注意的是这个习惯用久了可能迁移到不该用的场合，在真正值得认真讨论的地方也习惯性给观点加保护性包装。",[94,347,349],{"id":348},"加密市场能给a股投资者提供什么","加密市场能给A股投资者提供什么",[90,351,352],{},"突然想到，我现在主战场是 A 股，加密货币市场不就相当于给我提供了一个对冲的方法吗？",[90,354,355],{},"严格说，\"对冲 A 股\"这个表述不准确。对冲成立的前提是两资产之间有稳定相关性，但加密和 A 股的相关性不稳定。更现实的问题是 40U 和 A 股仓位规模差距悬殊，对冲不了任何波动。",[90,357,358],{},"但换一个角度看，BTC\u002FETH 走势和美国流动性、通胀、美股走势高度相关，A 股有自己的政策逻辑，和美股加密的分离有时是真实存在的。链上永续合约平台还能交易股票永续合约等其他品种，相当于一个低成本的跨市场观察窗口。",[90,360,361],{},"所以 40U 的战略意义不只是学费，也是扩展市场认知边界的实验仓。跨市场配置降低单一市场风险敞口，这个思维框架本身是成熟的。",[94,363,365],{"id":364},"从40u到1w-usdt","从40U到1w USDT",[90,367,368],{},"之后可能有 1w USDT，可以考虑试一试。",[90,370,371],{},"1w USDT 规模下对冲逻辑开始有实际意义。但前提是 40U 阶段要真的学到东西：搞清楚资金费率机制、爆仓逻辑、链上平台的清算机制和中心化交易所的区别、自己的操作纪律能否和 A 股一样有框架。40U 如果只是随便玩没有形成结构性认知，1w USDT 进去大概率重复散户路径。",[90,373,374],{},"等 40U 跑完一个周期再说，到时候自己会知道准没准备好。",{"title":266,"searchDepth":267,"depth":267,"links":376},[377,378,379,380,381,382],{"id":303,"depth":267,"text":303},{"id":315,"depth":267,"text":316},{"id":325,"depth":267,"text":326},{"id":338,"depth":267,"text":339},{"id":348,"depth":267,"text":349},{"id":364,"depth":267,"text":365},"2026-07-27","从一段抖音评论出发，梳理永续合约、区块链价值和加密市场作为A股投资者认知补充的实际意义。",{},"\u002Fwriting\u002F2026-07-27-crypto-40u-experiment","2026-07-27T00:18:24+08:00",{"title":298,"description":384},"crypto-40u-experiment","writing\u002F2026-07-27-crypto-40u-experiment",[276,392,393,394],"加密货币","区块链","认知","OjTLJ5ZBfXbUP2-ux-98zAUFVtqDclQ6IfelwXfjUnM",{"id":397,"title":398,"body":399,"category":438,"date":383,"description":439,"extension":279,"meta":440,"navigation":18,"path":441,"publishedAt":442,"seo":443,"slug":444,"stem":445,"tags":446,"updated":293,"__hash__":451},"writing\u002Fwriting\u002F2026-07-27-intp-sbti-personality-review.md","INTP的执行折扣：从SBTI测试到性格复盘",{"type":87,"value":400,"toc":433},[401,404,407,410,414,417,421,424,427,430],[90,402,403],{},"做了个 SBTI 测试，结果 THAN-K（感恩者），匹配度 73%，15 个维度命中 8 个。SBTI 本身是娱乐向的东西，B 站起源，讽刺行为类型指标，不用太当真。但测试维度里有些数据值得看看。",[90,405,406],{},"我的关键维度：S1 自尊自信偏低（3），S2 自我清晰度高（5），E1 依恋安全感高（6）。低自信 + 高自我清晰度，意思是知道自己是什么样的人，但对自己的评价偏低。73% 匹配度本身说明测试只照到了对外包容的那一面，没照到对内自我批判的那一面。",[90,408,409],{},"我的 MBTI 是 INTP。两个东西不是同一赛道--MBTI 有荣格理论背书，SBTI 是纯娱乐传播工具。但 INTP + THAN-K 的组合有内在逻辑：INTP 是冷的逻辑解构内核，THAN-K 是温和包容的外壳，两者分层而非矛盾。S1 低自信 + S2 高自我清晰度是典型的 INTP 内耗特征。",[94,411,413],{"id":412},"intp-的优势","INTP 的优势",[90,415,416],{},"逻辑强、系统思维、不受框架约束。看问题习惯拆到底层逻辑，不会被表面叙事带着走。这些东西在之前的交易认知讨论里已经验证过--看到量化系统会去拆合成期货的机制，看到抖音观点会自动分析信息源动机和逻辑链条。",[94,418,420],{"id":419},"intp-的核心缺陷","INTP 的核心缺陷",[90,422,423],{},"执行折扣。完美主义卡在启动条件上，想清楚了但做的时候摩擦极高。情感处理滞后，不是没有感受，是感受排在逻辑后面，等逻辑处理完了情绪才冒出来，有时候已经晚了。",[90,425,426],{},"THAN-K 的包容性其实是在给 INTP 的高标准兜底--对自己要求高，但对外表现温和，这是一种自我保护机制。整体来说是工具箱强但使用说明书烂，上限高但实现率取决于能不能跨越执行折扣。",[94,428,429],{"id":429},"回到测试本身",[90,431,432],{},"THAN-K 实际占比 7.76%，不算真正罕见。这类测试的价值不在于结果准不准，而在于给了个外部视角看自己。73% 匹配度恰好说明了一个人格标签装不下完整的自我，剩下 27% 的不匹配可能比匹配的部分更有信息量。",{"title":266,"searchDepth":267,"depth":267,"links":434},[435,436,437],{"id":412,"depth":267,"text":413},{"id":419,"depth":267,"text":420},{"id":429,"depth":267,"text":429},"随笔","做了SBTI测试得到THAN-K，结合MBTI的INTP，梳理理性内核与温和外壳的组合以及执行摩擦的根源。",{},"\u002Fwriting\u002F2026-07-27-intp-sbti-personality-review","2026-07-27T00:26:15+08:00",{"title":398,"description":439},"intp-sbti-personality-review","writing\u002F2026-07-27-intp-sbti-personality-review",[447,448,449,450,394],"MBTI","SBTI","INTP","性格","gd3Zm2yODzA0PcysBaNZOxUUS_CkxThxsq0Fdri1SSY",{"id":453,"title":454,"body":455,"category":438,"date":383,"description":483,"extension":279,"meta":484,"navigation":18,"path":485,"publishedAt":486,"seo":487,"slug":488,"stem":489,"tags":490,"updated":293,"__hash__":494},"writing\u002Fwriting\u002F2026-07-27-transition-meaninglessness.md","悬空期：什么都没意思的时候",{"type":87,"value":456,"toc":481},[457,460,463,466,469,472,475,478],[90,458,459],{},"感到迷茫。人活着要么劳碌要么做自己的事，但没有产出。不工作就没收入，工作了就是出卖劳动力。上班是牛马，不上班又该干嘛？",[90,461,462],{},"不是找不到具体的事做，是什么都没意思。项目做好了也就几个 star，打游戏、做项目都感觉在虚度。有钱没钱又怎样？钱够花就行，就算有 10 亿也就是有底气，但实际又怎样？金钱、名誉、权力，似乎都无所谓。",[90,464,465],{},"不是不想活。活着挺好的，只是不知道做什么有意义，意义是什么。",[90,467,468],{},"想了一圈，最后落到的结论很朴素：人活着就行了，该做什么做什么，尽量多元化，保证好身体。给自己立一条底线：保证身体，做项目时多站站走走。",[90,470,471],{},"但现在这些都做不到。懒。",[90,473,474],{},"不想被安慰，想听客观理性的。直说就是：状态是执行摩擦高 + 外部锚点少。论文还没交、还没去合肥、项目没成型，处在一个悬空期，目标完成后的锚点缺失加上输入输出失衡，空洞感是这个阶段的正常产物。",[90,476,477],{},"悬空期不适合想大问题。两个实际的事：一是久坐不动会加剧懒和无意义感，每天走 30 分钟有数据支撑，不是鸡汤；二是启动成本问题，目标要小到可笑，不要一上来就规划宏大计划。项目短期给不了意义感，但能给具体感--有具体的事做，至少不会整天想\"意义是什么\"这种没有答案的问题。",[90,479,480],{},"等落地了节奏自然会起来。现在能做的最小动作是什么，比想清楚人生意义重要得多。",{"title":266,"searchDepth":267,"depth":267,"links":482},[],"一段找不到意义感的时期，关于劳碌、回报和执行摩擦的诚实记录。",{},"\u002Fwriting\u002F2026-07-27-transition-meaninglessness","2026-07-27T00:21:58+08:00",{"title":454,"description":483},"transition-meaninglessness","writing\u002F2026-07-27-transition-meaninglessness",[491,492,493],"迷茫","意义","状态","t7T4SfZ_rtsAVrgWujfPWgj8LfEq3D_dAaWMtlfCxQ8",{"id":84,"title":85,"body":496,"category":276,"date":277,"description":278,"extension":279,"meta":623,"navigation":18,"path":281,"publishedAt":282,"seo":624,"slug":284,"stem":285,"tags":625,"updated":293,"__hash__":294},{"type":87,"value":497,"toc":614},[498,500,502,504,506,508,512,518,520,522,524,528,532,534,536,538,540,542,546,550,552,554,564,568,574,578,582,592,596,606,608,610,612],[90,499,92],{},[94,501,97],{"id":96},[90,503,100],{},[90,505,103],{},[94,507,107],{"id":106},[90,509,110,510,115],{},[112,511,114],{},[117,513,514,516],{},[120,515,122],{},[120,517,125],{},[90,519,128],{},[94,521,131],{"id":131},[90,523,134],{},[90,525,526,140],{},[112,527,139],{},[90,529,530,146],{},[112,531,145],{},[90,533,149],{},[94,535,153],{"id":152},[90,537,156],{},[90,539,159],{},[94,541,163],{"id":162},[90,543,166,544,170],{},[55,545,169],{},[90,547,173,548,115],{},[112,549,176],{},[94,551,179],{"id":179},[90,553,182],{},[117,555,556,558,560],{},[120,557,187],{},[120,559,190],{},[120,561,193,562],{},[112,563,196],{},[90,565,566],{},[112,567,201],{},[117,569,570,572],{},[120,571,206],{},[120,573,209],{},[90,575,212,576],{},[112,577,215],{},[90,579,580],{},[112,581,220],{},[117,583,584,586,588],{},[120,585,225],{},[120,587,228],{},[120,589,231,590],{},[112,591,234],{},[90,593,594],{},[112,595,239],{},[117,597,598,600,602],{},[120,599,244],{},[120,601,247],{},[120,603,231,604],{},[112,605,234],{},[90,607,254],{},[94,609,258],{"id":257},[90,611,261],{},[90,613,264],{},{"title":266,"searchDepth":267,"depth":267,"links":615},[616,617,618,619,620,621,622],{"id":96,"depth":267,"text":97},{"id":106,"depth":267,"text":107},{"id":131,"depth":267,"text":131},{"id":152,"depth":267,"text":153},{"id":162,"depth":267,"text":163},{"id":179,"depth":267,"text":179},{"id":257,"depth":267,"text":258},{},{"title":85,"description":278},[287,288,289,290,291,292],{"id":627,"title":628,"body":629,"category":833,"date":277,"description":834,"extension":279,"meta":835,"navigation":18,"path":836,"publishedAt":837,"seo":838,"slug":839,"stem":840,"tags":841,"updated":277,"__hash__":847},"writing\u002Fwriting\u002F2026-07-26-fields-medal-claiming-connections.md","【转载】我反感菲尔兹奖成功后，一群人到处认领关系",{"type":87,"value":630,"toc":827},[631,649,653,656,659,662,665,668,671,674,677,680,683,686,689,692,695,698,701,704,707,710,713,716,719,726,729,732,735,738,741,744,747,750,753,756,759,762,765,768,771,774,777,780,783,786,789,792,795,798,801,804,807,810,813,816,819],[632,633,634],"blockquote",{},[90,635,636,637,644,645,115],{},"转载自B站专栏 ",[638,639,643],"a",{"href":640,"rel":641},"https:\u002F\u002Fwww.bilibili.com\u002Fopus\u002F1229213047382343689",[642],"nofollow","@漫士沉思录","，",[638,646,648],{"href":640,"rel":647},[642],"原文链接",[94,650,652],{"id":651},"当时无人看见成名后都是故交","当时无人看见，成名后都是故交",[90,654,655],{},"最近，王虹和邓煜获得菲尔兹奖，这是一个非常让人兴奋的消息。这是中国数学史上真正重要的时刻。一个解决了三维挂谷猜想，一个与合作者完成了从微观粒子系统推导玻尔兹曼方程的重大突破。无论从数学史、科学史，还是朴素的民族情感来说，这都值得中国人感到自豪。我非常兴奋，迅速研究了两人的工作一个多星期，熬了好几个夜，在第一时间做了科普视频。还烧了几千块的AI额度。",[90,657,658],{},"这次中国一下子有了两个菲尔兹奖，最让人兴奋和自豪的地方在于，中国扎实的基础教育确实构成了他们成长中重要的一部分。中国教育能够让大量普通家庭的孩子，在相对有限的资源下，获得系统而高强度的数学训练。从代数、几何到分析和组合，一整套成熟的课程、考试和竞赛体系，训练了学生的计算能力、抽象能力和逻辑能力。邓煜接受过完整的竞赛训练，获得国际奥数金牌，进入北大学习；王虹虽然不是竞赛明星，也同样受益于扎实的本科课程和同学之间的讨论。这是中国基础教育的成绩，也是值得认真总结和珍惜的财富。",[90,660,661],{},"但这场兴奋中，也混杂着一种令人不适的刻奇。",[90,663,664],{},"很多人似乎并不真正关心两位数学家究竟解决了什么问题，也不关心他们怎样一步步成长为今天的数学家。大家更关心他们是哪所中学毕业的，在哪所大学待过，上过哪位教授的课，和哪个老师说过话，能不能把他们请回来。甚至是戴什么手环、玩什么手办、穿什么名牌。",[90,666,667],{},"仿佛一个人一旦获得世界级成就，他人生中接触过的每个机构、每门课程、每位老师，都突然变成了奖牌的共同缔造者。",[90,669,670],{},"尤其是王虹，当年根本不引人注意，现在人人都在她成功之后开始沾亲带故、认领关系。",[94,672,673],{"id":673},"弹冠相庆",[90,675,676],{},"获奖消息公布后，有一场由北大数院老领导、相关领域教授和获奖者导师参与的直播。整场气氛当然非常热烈。中国数学等了这么多年，终于迎来两位中国籍菲尔兹奖得主，兴奋完全可以理解。",[90,678,679],{},"但直播越往后，越显得空洞。谈到王虹和邓煜，反复出现的是\"调和分析领域好起来了\"\"邓煜当年选过我的课，考得很好\"\"希望他们以后回北大带带学生\"。然而当主持人追问三维挂谷问题究竟难在哪里，王虹的证明跨越了什么障碍，邓煜的工作为什么能够连接微观可逆的粒子运动与宏观不可逆的玻尔兹曼方程时，回答迅速变得含混，或者干脆顾左右而言他。又变成了\"我认识那个谁谁谁……\"",[90,681,682],{},"问人工智能会怎样改变数学研究，回答是\"没有人能预测未来\"，或者忽然跳到\"AI比人聪明太多，人类会遭到毁灭性打击\"。主持人请教授给年轻观众一些寄语，几个教授领导最后仍然落回\"希望两位回来，帮助北大培养学生\"。",[90,684,685],{},"至于王虹当年在北大读书时为何没有受到注意，回答倒十分坦率：\"从来没有注意到。毕业论文选的确实比较难。\"说到邓煜时说，\"当时都说是邓神，我们当时就觉得，这种人才应该尽快到国际上跟真正的大师学习，我们别耽误他。\"",[90,687,688],{},"这两句话反而成了整场直播中最真实的话。",[90,690,691],{},"在整场直播和舆论场中，数学工作、研究道路几乎从来没有被认真讨论，他曾经面对的困境也无人关心。可是一旦奖项公布，所有人立刻开始翻阅旧名单、追溯选课记录、确认师承关系。数学本身退到背景，关系和归属占据舞台中央。祝贺变成了攀亲，学术变成了族谱。我后来想明白，这不是哪个人的问题。在那个场域里，唯一可以流通的货币就是关系和归属：谁教过、谁认识、谁哪一年注意到过、谁的课他考得好、哪个学院哪个学科该记这一笔。数学本身不是货币，因为它换不来任何东西。",[94,693,694],{"id":694},"除非能得菲尔兹奖",[90,696,697],{},"中国教育的功劳不需要否认，问题在于，一套擅长提供基础训练的体系，未必同样擅长识别、容纳和培养真正的原创研究者。会做题不等于会做研究。快速掌握前人已经整理好的知识，也不等于能够在没有标准答案的荒野里发现问题、发明工具，并忍受漫长的失败。",[90,699,700],{},"考试面对的是确定性：题目一定有答案，方法大致存在，时间有限，做得越快越好。研究面对的却是不确定性：问题可能根本是错的，方法可能不存在，做了几年什么也得不到，甚至连\"应该往哪里走\"都无人知道。",[90,702,703],{},"前一种能力，中国教育极其擅长训练。而后一种能力，却需要完全不同的土壤：允许迟疑，允许绕路，允许犯错，允许一个暂时没有成果的人长时间追随自己的好奇，甚至能在学生困顿时告诉他也许怎么做会有转机和进展。",[90,705,706],{},"王虹的经历恰好体现了这种断裂。她最初进入北大地球与空间科学学院，后来转入数学系。为了转系，她需要同时应付原专业课程和数学课程，还要自学部分受选课限制无法直接修读的内容。进入数学系以后，周围是大量竞赛高手和奥赛金牌得主。她并不是最耀眼的学生，本科阶段始终处在一种艰难追赶的状态。",[90,708,709],{},"这种环境并非全无价值。同学组织的讨论班、扎实的课程训练和高水平同侪，都给了她重要帮助。但它也有另一面：当周围人都在炫技、刷题、比较成绩时，一个不以竞赛速度见长、需要慢慢形成数学品味的人，很容易不断怀疑自己是否适合数学。",[90,711,712],{},"后来她去了法国。巴黎综合理工允许学生自由选择课程，她去学习建筑、绘画，也曾认真考虑自己究竟要不要继续做数学。在许多高度标准化的培养体系中，这样的经历大概会被评价为\"不够专注\"\"路线不清晰\"或者\"浪费时间\"。但正是这种绕路，让她有机会重新确认自己真正想做的事情。",[90,714,715],{},"再后来，她到了MIT，遇见导师Larry Guth。当她的想法模糊、混乱，甚至很可能不成立时，导师不会立刻打断，也不会急于给出一个正确答案，而是耐心听她把想法讲完，让她逐渐学会怎样深入一个思路，怎样判断什么值得继续，哪里出了问题。",[90,717,718],{},"导师的价值，不是随时证明自己比学生聪明，而是帮助学生长出独立判断的能力。王虹在采访中说，\"那是第一次我感受到自己不必独自解决所有问题。\"",[90,720,721],{},[722,723],"img",{"alt":724,"src":725},"Documentary Interview in a Sunlit Garden","\u002Fuploads\u002Ffields-medal-garden.png",[90,727,728],{},"很多人习惯于把这总结成\"轻松教育\"和\"刻苦教育\"的区别，但其实太扁平了。这背后的核心，是把学生当作正在形成的研究者，还是把学生当作等待验收的标准化产品之间的区别。",[90,730,731],{},"邓煜的道路有所不同。他是典型的竞赛天才，国际奥数金牌，进入北大后成绩优异，却在大二转学MIT。北大的前两年为他打下了扎实的数学基础，到了MIT以后，他迅速接触前沿研究报告，在教师帮助下开始处理具体的随机初值偏微分方程问题。相比之下，MIT的师生关系更加松弛，学生更早接近研究前沿，交流方式也更平等随意。",[90,733,734],{},"所以，坦诚的说：中国的基础教育和北大本科训练的确提供了坚实起点；而法国和美国的学术环境提供了更大的探索空间、更靠近前沿的问题和不同方式的导师支持；最后真正把难题做出来的，是他们自己长期的思考和合作者共同完成的工作。",[90,736,737],{},"没有必要把一个人的全部成功据为己有。承认教育体系的长处，也承认别的环境提供过关键帮助，并不会损害中国教育的尊严。",[90,739,740],{},"更令人侧目的，是一种反复出现的模式。当初人在这里的时候，成绩不够耀眼，没有足够资源，没有人注意，只能自己想办法在压抑的环境里生存。等到去了法国、MIT、普林斯顿，做出世界级成果，所有人忽然开始翻通讯录：她是我们学院的，他上过我的课，我们早就知道他很优秀，欢迎回来建设母校。",[90,742,743],{},"一个年轻人尚未成功时，系统要求他不断证明自己配得上资源；等他终于不再需要这些资源时，系统又要求他回来证明这个系统的成功。",[90,745,746],{},"这很难称为培养，更像是收割。",[90,748,749],{},"\"希望他们回来带学生\"尤其耐人寻味。为什么第一反应总是让成功者回来\"带一带\"现有体系？为什么不是先问，今天的学生得到了足够的指导吗？年轻教师有稳定研究长期问题的空间吗？那些暂时没有论文、没有基金、成绩不够漂亮，却真正喜欢数学的人，有没有可能被看见？",[90,751,752],{},"仿佛体系本身从来不需要改变，只缺少几个世界冠军回来输血。",[90,754,755],{},"每当一个华人在海外获得巨大成就，国内舆论总会条件反射地追问\"什么时候回来\"。这背后仍是一种资源逻辑：把顶尖学者看作可以引进、争抢、挂牌的稀缺资产。似乎只要把人请回来，建一个中心，给一个头衔，再招一批学生，世界一流的学术文化就会自动生成。",[90,757,758],{},"但一个人为什么能够成为王虹？不仅因为她聪明、努力，也因为当她的想法尚且混乱时，有人愿意认真听她讲完。一个人为什么能够成为邓煜？不仅因为他是奥数金牌，也因为他在本科阶段就有机会进入研究前沿，得到具体问题，并沿着真正感兴趣的方向深入下去。",[90,760,761],{},"真正值得追问的，不是怎样让已经成功的王虹回来，而是怎样让下一个尚未成功、成绩并不耀眼、暂时做不出结果的王虹，在这里就能获得耐心、尊重和机会。不是怎样让邓煜回来带学生，而是怎样让一个有潜力的本科生，不必先成为标准化考试中的冠军，也能接触真正的研究。",[90,763,764],{},"读博期间最深切的感受，是许多研究从一开始就不是由问题驱动，而是由风口、项目、政策和履历驱动。",[90,766,767],{},"这个方向最近比较热，看看能不能做一个A+B；这个概念现在很多人关注，赶紧跟上；这个方向政策在推，容易申请项目和基金；这个题目适合创业，方便获得横向经费。",[90,769,770],{},"这些考虑并非全无道理。科研需要资源，学者也要生活，国家投入资金当然会有战略方向，应用研究也应回应现实需求。但当所有人都按照同一套风口和考核表选择问题，得到的通常不是伟大的创新，而是一群训练有素的人在同一个狭窄区域里重复施工。",[90,772,773],{},"真正原创的工作，在开始时经常显得没有用、不热门、不保险，甚至有些荒唐。三维挂谷猜想并不是某个年度指南里的热门任务，从微观粒子严格推导玻尔兹曼方程也不是一个容易结项的项目。吸引数学家投入多年时间的，首先是问题本身：它重要，它困难，它让人无法停止思考。",[90,775,776],{},"而短周期、强考核、零容错的制度，会系统性地消灭这种选择。探索失败的代价由年轻人承担，探索成功的功劳却可以由导师、学院、学校乃至整个体系共同认领。在这样的收益结构下，最理性的选择不是冒险，而是跟随；不是追问真正重要的问题，而是在热门方向上快速制造一个可以发表的差异。",[90,778,779],{},"久而久之，科研只剩下亦步亦趋的平庸、包装精致的空洞和围绕权力关系形成的利益链条。真正的学术能力退居其次，最重要的是项目、头衔、行政资源和技术官僚身份。",[90,781,782],{},"有些老师把博士生当作自己的低成本项目执行人员。学生需要打卡上班，替老师完成横向项目、写材料、跑报销、接待、演示，维护各种与自身研究无关的系统。项目拿到大量经费，真正做事的学生却只能得到象征性的补贴。学生承担了雇员的工作，却没有雇员的工资、合同和边界，同时还要接受\"老师是在培养你\"的道德规训。",[90,784,785],{},"另一种极端则是完全放养。没有稳定讨论，没有具体指导，不帮助学生寻找问题，也不关心学生陷入什么困境。学生如果自己长出来了，便成了导师和学校培养有方；如果没有长出来，就是学生能力不足、不够努力。",[90,787,788],{},"一种把学生当工具，另一种把学生当彩票。看似相反，本质上都没有把学生当作一个需要被认真培养、逐渐独立的人。真正的指导既不是把学生攥在手里，让他替自己完成任务，也不是把人扔进荒野，等待幸存者回来报喜。",[90,790,791],{},"还有一种更加隐蔽的情形：那些像韦东奕一样极其纯粹、极具天赋，却不擅长经营关系和适应行政秩序的人，会被当成一种特殊符号。但一旦有了成果，又会立刻被包装成学校精神和培养成绩的一部分。",[90,793,794],{},"人在其中时，感受到的是放养、压抑、内卷和无聊的应制。等到做出成绩，外界看到的却只剩下一张可以宣传的天才名片。",[90,796,797],{},"王虹和邓煜获得菲尔兹奖，中国人当然可以自豪。可以为中国基础教育所提供的扎实训练自豪，可以为普通家庭的孩子依靠教育走向世界前沿自豪，也可以为中国学者已经有能力参与乃至领导最核心的数学问题自豪。",[90,799,800],{},"但成熟的自豪不应害怕承认缺陷。一个真正自信的教育体系，应该能够坦然地说：这里有我们提供的基础，那里有别人提供的环境；这个地方做得很好，那个地方曾经没有看见她；这些经验值得继承，那些问题必须改变。",[90,802,803],{},"最廉价的爱国，是成功以后把一个人搬回族谱。最廉价的学术庆祝，是翻出选课记录，证明自己曾经与菲尔兹奖有过一面之缘。最廉价的反思，则是再次高喊\"把人才请回来\"，却不改变那些迫使人才离开的结构。",[90,805,806],{},"真正的庆祝，应该是认真理解他们究竟做了什么，认真理解伟大研究需要怎样的好奇、自由、耐心和容错，然后回头看看那些仍然坐在教室和实验室里，成绩不够漂亮，论文尚未发表，想法听起来有些古怪，甚至正在怀疑自己究竟适不适合科研的年轻人。",[90,808,809],{},"基础教育可以教会一个人怎样解决已有的问题，但一个文明能否产生真正伟大的学术，最终取决于它是否允许人提出无人要求的问题，追寻暂时无用的答案，走一条没有人保证正确的道路。",[90,811,812],{},"真正值得骄傲的一天，不是一个人在外面成名以后，所有人终于认出了他。",[90,814,815],{},"而是当他还只是一个小透明，还在挣扎，还在犯错，还无法证明自己将会成功时，这个体系就愿意认真地看见他。",[94,817,818],{"id":818},"来源与延伸阅读",[117,820,821],{},[120,822,823],{},[638,824,826],{"href":640,"rel":825},[642],"原文 - 哔哩哔哩专栏",{"title":266,"searchDepth":267,"depth":267,"links":828},[829,830,831,832],{"id":651,"depth":267,"text":652},{"id":673,"depth":267,"text":673},{"id":694,"depth":267,"text":694},{"id":818,"depth":267,"text":818},"观察","王虹和邓煜获菲尔兹奖后，国内学术圈纷纷攀亲认关系，本文反思中国教育体系在培养原创研究者方面的缺失。",{},"\u002Fwriting\u002F2026-07-26-fields-medal-claiming-connections","2026-07-26T13:56:35+08:00",{"title":628,"description":834},"fields-medal-claiming-connections","writing\u002F2026-07-26-fields-medal-claiming-connections",[842,843,844,845,846],"菲尔兹奖","王虹","邓煜","中国教育","学术反思","jwvp054ZJWI_LrptvQv7qj9iqxK_5lwHWCWDsb_ORGI",{"id":849,"title":850,"body":851,"category":276,"date":277,"description":939,"extension":279,"meta":940,"navigation":18,"path":941,"publishedAt":942,"seo":943,"slug":944,"stem":945,"tags":946,"updated":293,"__hash__":950},"writing\u002Fwriting\u002F2026-07-26-market-strategy-exploration-price-route.md","从非农数据到价格路线：一段市场策略探索的复盘",{"type":87,"value":852,"toc":930},[853,857,860,863,867,870,873,877,880,883,886,889,892,896,899,902,905,908,912,915,918,921,924,927],[94,854,856],{"id":855},"非农数据与黄金这不是统计套利","非农数据与黄金：这不是统计套利",[90,858,859],{},"非农就业数据弱 -> 黄金上涨 -> 次日继续上涨，这个现象看起来像可以利用的统计套利。但仔细想，这不算真正的统计套利，因为有方向暴露--你在赌一个特定方向，而不是对冲掉方向只赚价差。",[90,861,862],{},"更关键的问题是样本量。非农一个月才一次，几十年历史也就几百次，难以做统计显著性检验。即使这个 post-announcement drift 效应真实存在，也早被机构交易了，edge 很薄。执行容量不是瓶颈，edge 太薄才是真正的问题。当作研究练习或者辅助过滤条件可以，单独开策略不值得。",[94,864,866],{"id":865},"个人能靠容量小机构看不上获利吗","个人能靠\"容量小、机构看不上\"获利吗",[90,868,869],{},"逻辑方向是对的。机构受监管约束、有容量天花板、策略需要可标准化，这些结构性门槛留出了一些空间。比如小盘股流动性缺口、可转债条款博弈、打新、低流动性 LOF 折溢价。",[90,871,872],{},"但要注意，这块地已经有游资和量化工作室在挖了。竞争对手从机构换成了游资，不等于没竞争。",[94,874,876],{"id":875},"景气度投资有启发但不是我的方向","景气度投资：有启发但不是我的方向",[90,878,879],{},"看到一个基金经理的访谈思路：从申万一级行业中找成长性好的行业，挑龙头公司，买在基本面右侧、卖在行业周期走完。",[90,881,882],{},"这是主流的\"景气度投资\"框架，不是独创。\"买基本面右侧、不买股价右侧\"这个核心洞察确实有价值，和我自己的均线系统是正交的。但判断行业成长性和周期拐点本质是主观判断力，不可回测、有后视镜偏差。而且标的多为大市值龙头，容量大，机构挤满，和\"容量小、机构看不上\"的思路完全相反。",[90,884,885],{},"同时接触量化研究和主观判断型方法论两条路，注意力是零和的。新内容可以当认知输入，但要警惕把它变成新的主线分走注意力。",[94,887,888],{"id":888},"为什么选择先走量化路线",[90,890,891],{},"更系统化、止损清晰有预期、不会亏大钱。机构能扛判断错误，我扛不住。以后系统成熟了可以考虑拓展，但拓展的触发条件要具体化--回测引擎完成、多周期验证执行纪律、资金曲线连续达标，而不是凭模糊感觉判断\"时候到了\"。",[94,893,895],{"id":894},"创新药etf与横截面动量","创新药ETF与横截面动量",[90,897,898],{},"抖音上看到关于创新药 ETF 的评论：赢家通吃导致个股难选，不如买 ETF，\"别自己选啊，市场资金帮你选了\"。结合盘面观察，强势股跌得少、弱势股跌停。",[90,900,901],{},"这个逻辑其实是自洽的：用价格的相对强度（横截面动量）代替基本面判断。赢家通吃 -> 个股难选 -> 价格显示资金持续认可的方向 -> 跟着价格走等于间接跟着选股结果走。和我自己的技术分析哲学同源，是对现有时间序列动量系统的维度补充。",[90,903,904],{},"这里有一个重要的区分：用价格代替基本面（创新药案例的逻辑，价格永远替代基本面，不是过渡）和\"价格系统化后转向基本面研究\"（实质是走向已经拒绝的主观投资路线）是两条不同的路。不要在心态上悄悄开后门。",[90,906,907],{},"最终收敛很清楚：研究价格而非行业。价格路线可以在时间序列（GARCH、协整）和横截面（相对强度）两个维度做深，始终不涉及需要主观基本面判断力的领域。这是风险收益比更优的深化路径，不是能力局限。",[94,909,911],{"id":910},"btc与流动性相关性没那么简单","BTC与流动性：相关性没那么简单",[90,913,914],{},"\"BTC 和流动性高度相关\"--机制方向合理：流动性宽松 -> 资金溢出到高 beta 资产。但\"高度相关\"的说法有问题：相关性随周期不稳定，因果方向常被倒因为果，短视频叙事是事后归因。要用于策略得自己做滚动窗口回测验证，不能直接采信定性描述。",[90,916,917],{},"币圈反应快不等于定价效率高。反应快是 24\u002F7 交易 + 高频算法 + 高杠杆踩踏造成的基础设施结果，不代表信息处理效率高。真正的效率要看有没有超调后的回吐纠偏--如果存在，说明第一反应含大量噪音。这类品种更适合\"事后确认 + 右侧进场\"，而不是追第一时间反应。",[94,919,920],{"id":920},"抖音网赌小作文",[90,922,923],{},"刷到抖音上一个网赌小作文：女生从基金到黄金到股票充值游戏、期货爆仓、最终网赌。叙事很流畅，但流畅度和真实性成反比--风险递增顺序过于工整、时间线被压缩、多案例拼凑嫌疑、有变现动机。",[90,925,926],{},"不过每一步单独看的心理机制是真实的。追损升级（escalation of commitment）有实证支持：现实版本不会是直线堕落，而是反复横跳、时间跨度以年计。真正压垮人的往往是为掩盖亏损产生的借贷和欺骗行为。",[90,928,929],{},"止损纪律本质上就是在结构上拦截追损心理。这也呼应了我自己量化系统的价值--系统替你做理性认同但情绪会动摇的决定。",{"title":266,"searchDepth":267,"depth":267,"links":931},[932,933,934,935,936,937,938],{"id":855,"depth":267,"text":856},{"id":865,"depth":267,"text":866},{"id":875,"depth":267,"text":876},{"id":888,"depth":267,"text":888},{"id":894,"depth":267,"text":895},{"id":910,"depth":267,"text":911},{"id":920,"depth":267,"text":920},"围绕统计套利、容量空间、景气度投资、横截面动量和赌博心理的讨论，最终收敛到以价格为核心的量化路线。",{},"\u002Fwriting\u002F2026-07-26-market-strategy-exploration-price-route","2026-07-26T23:57:58+08:00",{"title":850,"description":939},"market-strategy-exploration-price-route","writing\u002F2026-07-26-market-strategy-exploration-price-route",[276,947,948,949,394],"量化","策略","动量","yIF9k9yKby26JobCZKCuXjRT7JUAa9HK-7dFEovl0Nk",{"id":952,"title":953,"body":954,"category":3907,"date":277,"description":3908,"extension":279,"meta":3909,"navigation":18,"path":3910,"publishedAt":3911,"seo":3912,"slug":293,"stem":3913,"tags":3914,"updated":293,"__hash__":3919},"writing\u002Fwriting\u002F2026-07-26-quilibra-complete-technical-handbook.md","Quilibra 个人主页完整技术手册：从页面架构到内容发布与生产部署",{"type":87,"value":955,"toc":3840},[956,959,962,966,969,972,981,995,998,1002,1005,1025,1028,1031,1035,1038,1138,1141,1147,1153,1167,1171,1174,1180,1183,1217,1231,1235,1241,1275,1293,1304,1310,1346,1353,1357,1362,1388,1405,1412,1449,1462,1466,1472,1504,1522,1564,1567,1578,1582,1585,1608,1627,1646,1649,1653,1656,1684,1687,1691,1698,1755,1766,1769,1795,1798,1804,1810,1814,1825,1831,1838,1848,1867,1871,1881,1884,1904,1907,1947,1953,1957,1964,1967,1970,1984,2005,2011,2043,2054,2058,2069,2072,2099,2110,2113,2128,2132,2135,2151,2154,2160,2174,2181,2199,2203,2209,2216,2219,2233,2247,2254,2258,2269,2272,2280,2286,2293,2297,2300,2375,2378,2384,2404,2427,2436,2446,2450,2459,2462,2481,2484,2492,2495,2502,2509,2515,2518,2522,2529,2532,2555,2574,2577,2581,2588,2594,2603,2616,2620,2623,2630,2633,2639,2642,2648,2651,2657,2674,2678,2684,2690,2703,2720,2729,2732,2738,2742,2765,2830,2836,2843,2847,2897,2904,2910,2914,2921,2963,2974,2985,2989,2992,2996,3002,3028,3032,3038,3057,3061,3067,3102,3105,3108,3112,3115,3132,3135,3138,3178,3183,3187,3190,3197,3214,3217,3221,3225,3231,3234,3243,3246,3255,3258,3268,3271,3285,3288,3295,3298,3312,3315,3321,3325,3329,3356,3361,3365,3441,3446,3449,3508,3513,3516,3519,3547,3558,3562,3565,3574,3578,3589,3592,3600,3603,3609,3613,3623,3627,3636,3640,3643,3647,3650,3656,3659,3665,3676,3680,3683,3686,3689,3692,3695,3698,3702,3705,3753,3756,3773,3776,3778,3836],[90,957,958],{},"这是一份面向未来自己的项目说明书。它不再复述网站是怎样一轮轮改成现在这个样子的，而是以 2026 年 7 月 26 日的实际代码为准，从浏览器里看到的页面一直追到内容文件、构建产物、静态服务器和生产 release。以后忘了某段代码为什么存在、主页颜色为什么能保存、文章为什么保存后还没有上线，或者 3000、3100、3101 三个端口分别在做什么，可以从这里重新建立完整认识。",[90,960,961],{},"本文记录的是一个具体版本的实现，不是一套永远不变的规范。最可靠的事实来源始终是仓库中的代码；本文的作用，是把分散在 Vue、CSS、YAML、脚本和运维文件里的设计意图串起来。",[94,963,965],{"id":964},"一先用一句话理解整个网站","一、先用一句话理解整个网站",[90,967,968],{},"Quilibra 是一个由 Nuxt 生成的静态个人网站：页面结构写在 Vue 中，主页设置写在 YAML 中，文章写在 Markdown 中；发布时把这些源文件编译成普通 HTML、CSS、JavaScript 和图片，再由一个很小的 Node 静态服务器提供给浏览器。",[90,970,971],{},"它的核心链路是：",[973,974,979],"pre",{"className":975,"code":977,"language":978,"meta":266},[976],"language-text","Vue \u002F CSS \u002F YAML \u002F Markdown\n           |\n           | Nuxt generate\n           v\n     .output\u002Fpublic\n           |\n           | 复制到带时间戳的 release\n           v\n  releases\u002F\u003Crelease-id>\n           |\n           | 原子切换 current 符号链接\n           v\n      current -> 当前 release\n           |\n           | Node 静态服务器 :3000\n           v\n        浏览器 \u002F 反向代理\n","text",[55,980,977],{"__ignoreMap":266},[90,982,983,984],{},"这里最重要的边界是：",[112,985,986,987,990,991,994],{},"仓库中的源码是长期事实，",[55,988,989],{},".output\u002Fpublic"," 是可重新生成的临时产物，",[55,992,993],{},"current"," 指向的 release 才是生产网站当前真正提供的版本。",[90,996,997],{},"因此，修改 Markdown 或 YAML 只改变源码；只有重新生成并切换 release，线上页面才会改变。网站没有生产数据库，也没有在访问文章时临时渲染 Markdown。",[94,999,1001],{"id":1000},"二为什么选择静态优先","二、为什么选择静态优先",[90,1003,1004],{},"个人主页的读取远多于写入，而且文章、简介和服务入口都不需要按访客实时计算。静态生成正好适合这种负载：",[117,1006,1007,1010,1013,1016,1019,1022],{},[120,1008,1009],{},"访问时不查询数据库，也不运行 Vue 服务端渲染逻辑；",[120,1011,1012],{},"HTML 已经在发布阶段生成，首屏可以直接返回完整内容；",[120,1014,1015],{},"生产服务只需要读取文件，故障面比常驻 Nuxt 服务小；",[120,1017,1018],{},"每个 release 都是一份独立、完整、可回滚的目录；",[120,1020,1021],{},"Markdown 和 YAML 都在 Git 中，内容、配置和代码可以一起审查与恢复；",[120,1023,1024],{},"CMS 只是源码编辑器，不会成为网站运行时依赖。",[90,1026,1027],{},"代价也很明确：每次内容变化都要重新生成站点；文章越多，生成时间越长；需要登录、评论、实时状态或用户数据时，必须接入独立服务，而不能假装静态文件可以承担动态业务。",[90,1029,1030],{},"当前项目主动接受这个取舍，因为稳定、透明和容易备份比“保存后数据库立刻生效”更重要。",[94,1032,1034],{"id":1033},"三技术栈与各自职责","三、技术栈与各自职责",[90,1036,1037],{},"当前主要依赖如下：",[1039,1040,1041,1054],"table",{},[1042,1043,1044],"thead",{},[1045,1046,1047,1051],"tr",{},[1048,1049,1050],"th",{},"技术",[1048,1052,1053],{},"当前职责",[1055,1056,1057,1066,1074,1082,1090,1098,1106,1114,1122,1130],"tbody",{},[1045,1058,1059,1063],{},[1060,1061,1062],"td",{},"Nuxt 4",[1060,1064,1065],{},"应用框架、路由、预渲染、页面头信息和构建产物",[1045,1067,1068,1071],{},[1060,1069,1070],{},"Vue 3",[1060,1072,1073],{},"组件、响应式状态、生命周期和浏览器交互",[1045,1075,1076,1079],{},[1060,1077,1078],{},"TypeScript",[1060,1080,1081],{},"页面、组件、配置、内容脚本和测试的静态类型检查",[1045,1083,1084,1087],{},[1060,1085,1086],{},"Nuxt Content 3",[1060,1088,1089],{},"读取 YAML\u002FMarkdown、建立集合、查询文章并渲染正文",[1045,1091,1092,1095],{},[1060,1093,1094],{},"Zod",[1060,1096,1097],{},"约束站点设置与文章字段",[1045,1099,1100,1103],{},[1060,1101,1102],{},"Lucide Vue",[1060,1104,1105],{},"返回、搜索、服务、调色等界面图标",[1045,1107,1108,1111],{},[1060,1109,1110],{},"原生 CSS",[1060,1112,1113],{},"全部视觉、响应式布局、悬浮反馈和字标动画",[1045,1115,1116,1119],{},[1060,1117,1118],{},"Sveltia CMS",[1060,1120,1121],{},"在浏览器中编辑仓库里的 YAML、Markdown 和上传资源",[1045,1123,1124,1127],{},[1060,1125,1126],{},"Playwright",[1060,1128,1129],{},"真实浏览器中的交互、布局、响应式和回归测试",[1045,1131,1132,1135],{},[1060,1133,1134],{},"Node.js",[1060,1136,1137],{},"内容工具、release 脚本和生产静态服务器",[90,1139,1140],{},"没有引入 Tailwind、组件库、动画框架、运行时数据库或外部字体。页面使用系统无衬线字体和系统等宽字体回退，这减少了字体请求，也避免了字体加载完成时重新排版。",[90,1142,1143,1146],{},[55,1144,1145],{},"package.json"," 中最常用的入口是：",[973,1148,1151],{"className":1149,"code":1150,"language":978,"meta":266},[976],"npm run dev              开发服务，默认对外监听 0.0.0.0\nnpm run generate         生成静态站点\nnpm run typecheck        Nuxt\u002FVue TypeScript 检查\nnpm run content:validate 校验全部文章与站点设置\nnpm run test:content     内容校验器与受限 writer 的单元测试\nnpm run test:release     release 工具的单元测试\nnpm run test:e2e         Playwright 浏览器测试\nnpm run publish          发布未提交的受管内容\nnpm run deploy           部署已经提交且工作区干净的代码版本\nnpm run rollback         切换回指定历史 release\n",[55,1152,1150],{"__ignoreMap":266},[90,1154,1155,1158,1159,1162,1163,1166],{},[55,1156,1157],{},"build"," 与 ",[55,1160,1161],{},"preview"," 仍是 Nuxt 的常规命令，但当前生产链路以 ",[55,1164,1165],{},"generate"," 和自有静态服务器为准。",[94,1168,1170],{"id":1169},"四目录结构与所有权边界","四、目录结构与所有权边界",[90,1172,1173],{},"理解这个项目，先要知道“改什么就去哪里”。",[973,1175,1178],{"className":1176,"code":1177,"language":978,"meta":266},[976],"personal-site\u002F\n├── app\u002F\n│   ├── app.vue                         全站外壳、主题初始化、动态 favicon\n│   ├── assets\u002Fcss\u002Fmain.css             全站视觉与响应式规则\n│   ├── components\u002F\n│   │   ├── HandwrittenWordmark.vue     Quilibra 字标加载与重播控制\n│   │   ├── RgbAssembly.vue             RGB 滑杆、预设与重置\n│   │   ├── ServiceIcon.vue             服务图标名称到 Lucide 的映射\n│   │   └── ServiceStatusDot.vue        服务状态点\n│   ├── composables\u002F\n│   │   ├── useAccentTheme.ts           主题色状态、混色、对比色与持久化\n│   │   ├── useSiteSettings.ts          读取唯一一份站点设置\n│   │   └── useWordmarkAnimation.ts     跨组件字标重播信号\n│   ├── config\u002F                         文章分类、服务状态和图标枚举\n│   ├── pages\u002F                          首页、文章、服务、关于页面\n│   └── error.vue                       错误页面\n├── content\u002F\n│   ├── settings\u002Fsite.yml               主页与栏目内容的唯一数据源\n│   └── writing\u002F*.md                    正式文章\n├── public\u002F\n│   ├── admin\u002F                          Sveltia CMS 入口与字段配置\n│   ├── brand\u002F                          字标位图资源\n│   ├── uploads\u002F                        文章上传资源\n│   └── favicon.svg                     静态 favicon 回退\n├── scripts\u002F\n│   ├── content\u002Fvalidate.ts             内容结构校验\n│   ├── content\u002Fwrite.ts                受限文章写入、更新与删除\n│   ├── release.ts                      测试、生成、提交、发布和回滚\n│   └── static-server.mjs               生产静态文件服务器\n├── tests\u002F                              单元、发布和浏览器测试\n├── ops\u002F\n│   ├── openclaw\u002F...\u002FSKILL.md           OpenClaw 文章发布 Skill\n│   └── systemd\u002Fpersonal-site.service   用户级生产服务定义\n├── content.config.ts                   Nuxt Content 集合\n├── content.schema.ts                   站点设置 Schema\n├── nuxt.config.ts                      Nuxt 与静态预渲染配置\n└── playwright.config.ts                E2E 临时服务与浏览器配置\n",[55,1179,1177],{"__ignoreMap":266},[90,1181,1182],{},"可以把这些文件分成四层：",[1184,1185,1186,1192,1198,1207],"ol",{},[120,1187,1188,1191],{},[55,1189,1190],{},"content\u002F"," 是可频繁修改的数据层。",[120,1193,1194,1197],{},[55,1195,1196],{},"app\u002F"," 是页面表现和交互层。",[120,1199,1200,1158,1203,1206],{},[55,1201,1202],{},"scripts\u002F",[55,1204,1205],{},"ops\u002F"," 是发布和运行层。",[120,1208,1209,1212,1213,1216],{},[55,1210,1211],{},".output\u002F","、",[55,1214,1215],{},".nuxt*"," 是构建缓存或产物，不是手工维护的源码。",[90,1218,1219,1220,1212,1223,1226,1227,1230],{},"CMS 默认只管理 ",[55,1221,1222],{},"content\u002Fsettings\u002Fsite.yml",[55,1224,1225],{},"content\u002Fwriting\u002F"," 和 ",[55,1228,1229],{},"public\u002Fuploads\u002F","。Vue、CSS、CMS 配置、脚本或测试发生变化时，应当视为代码变更，走完整代码部署流程。",[94,1232,1234],{"id":1233},"五nuxt-配置与构建数据库","五、Nuxt 配置与构建数据库",[90,1236,1237,1240],{},[55,1238,1239],{},"nuxt.config.ts"," 做了几件关键的事：",[117,1242,1243,1250,1256,1259,1262,1269,1272],{},[120,1244,1245,1246,1249],{},"加载 ",[55,1247,1248],{},"@nuxt\u002Fcontent","；",[120,1251,1252,1253,1249],{},"全局引入 ",[55,1254,1255],{},"app\u002Fassets\u002Fcss\u002Fmain.css",[120,1257,1258],{},"关闭开发工具；",[120,1260,1261],{},"设置中文页面语言和移动端 viewport；",[120,1263,1264,1265,1268],{},"使用 ",[55,1266,1267],{},"out-in"," 页面切换过渡；",[120,1270,1271],{},"允许 Nitro 爬取内部链接并预渲染，遇到错误时直接让构建失败；",[120,1273,1274],{},"把 Nuxt Content 的本地数据库放到与构建目录对应的位置。",[90,1276,1277,1278,1226,1281,1284,1285,1288,1289,1292],{},"Nuxt Content 3 在构建过程中会建立 SQLite 内容索引。开发环境默认使用 ",[55,1279,1280],{},".nuxt",[55,1282,1283],{},".data\u002Fcontent\u002Fcontents.sqlite","；release 构建传入 ",[55,1286,1287],{},"NUXT_BUILD_DIR=.nuxt-release","，E2E 使用 ",[55,1290,1291],{},".nuxt-e2e","。把三种构建目录分开，是为了避免开发服务器、正式生成和 Playwright 同时读写同一个内容缓存。",[90,1294,1295,1296,1299,1300,1303],{},"这里的 SQLite 是",[112,1297,1298],{},"构建时索引","，不是生产文章数据库。它帮助 Nuxt Content 查询 Markdown；静态页面生成完成后，生产服务器只负责输出构建结果。遇到 ",[55,1301,1302],{},"no such table: _content_writing"," 时，通常是本地 Nuxt Content 缓存被并发构建或中断破坏，不代表文章源文件丢失。",[90,1305,1306,1309],{},[55,1307,1308],{},"content.config.ts"," 定义了两个集合：",[117,1311,1312,1325],{},[120,1313,1314,1317,1318,1321,1322,1249],{},[55,1315,1316],{},"site","：",[55,1319,1320],{},"data"," 类型，只读取 ",[55,1323,1324],{},"settings\u002Fsite.yml",[120,1326,1327,1317,1330,1333,1334,1337,1338,1341,1342,1345],{},[55,1328,1329],{},"writing",[55,1331,1332],{},"page"," 类型，读取 ",[55,1335,1336],{},"writing\u002F**\u002F*.md","，因此每篇文章会拥有可路由的 ",[55,1339,1340],{},"path"," 和可供 ",[55,1343,1344],{},"ContentRenderer"," 使用的正文。",[90,1347,1348,1349,1352],{},"E2E 测试通过 ",[55,1350,1351],{},"NUXT_CONTENT_CWD=tests\u002Ffixtures\u002Fcontent"," 把文章集合切换到固定 fixture，测试不会依赖真实文章的标题和数量，也不会改动生产内容。",[94,1354,1356],{"id":1355},"六站点设置一份-yaml-如何驱动多个页面","六、站点设置：一份 YAML 如何驱动多个页面",[90,1358,1359,1361],{},[55,1360,1222],{}," 是主页和栏目文本的中心配置。它包含：",[117,1363,1364,1367,1370,1373,1376,1379,1382,1385],{},[120,1365,1366],{},"站点名称、浏览器标题、描述、位置；",[120,1368,1369],{},"首页介绍、当前状态、关注主题；",[120,1371,1372],{},"首页标题前缀与强调字标文字；",[120,1374,1375],{},"默认主题色；",[120,1377,1378],{},"最新文章、服务矩阵、RGB 模块和底部入口的开关与文案；",[120,1380,1381],{},"服务名称、说明、URL、状态、图标和是否显示在主页；",[120,1383,1384],{},"文章、服务、关于三个页面的介绍与 SEO 文案；",[120,1386,1387],{},"ICP、公安备案和署名。",[90,1389,1390,1393,1394,1397,1398,1400,1401,1404],{},[55,1391,1392],{},"useSiteSettings()"," 使用固定的异步数据键 ",[55,1395,1396],{},"site-settings"," 查询 ",[55,1399,1316],{}," 集合的第一条记录。固定键让多个页面共享同一份 Nuxt 数据；如果设置缺失，它立即抛出 500，而不是让各组件在大量 ",[55,1402,1403],{},"undefined"," 判断中带病运行。",[90,1406,1407,1408,1411],{},"配置不是任意 YAML。",[55,1409,1410],{},"content.schema.ts"," 用严格 Schema 规定每个字段的类型和范围，例如：",[117,1413,1414,1420,1423,1426,1436,1439,1446],{},[120,1415,1416,1417,1249],{},"默认强调色必须是 ",[55,1418,1419],{},"#RRGGBB",[120,1421,1422],{},"最新文章数量只能是 1 到 3；",[120,1424,1425],{},"服务数量只能是 1 到 12；",[120,1427,1428,1429,1212,1431,1212,1434,1249],{},"服务状态只能是 ",[55,1430,70],{},[55,1432,1433],{},"private",[55,1435,54],{},[120,1437,1438],{},"图标只能使用代码中已有的枚举；",[120,1440,1441,1442,1445],{},"服务链接只能是 ",[55,1443,1444],{},"#"," 或完整的 HTTPS URL；",[120,1447,1448],{},"对象使用严格模式，拼错字段不会被静默忽略。",[90,1450,1451,1454,1455,1457,1458,1461],{},[55,1452,1453],{},"public\u002Fadmin\u002Fconfig.yml"," 的表单选项、",[55,1456,1410],{}," 的运行时约束、",[55,1459,1460],{},"app\u002Fconfig\u002Fsite.ts"," 的 TypeScript 枚举应该同步修改。只改 CMS 下拉框，不改 Schema，保存后会校验失败；只改 Schema，不改组件映射，界面可能没有正确图标。",[94,1463,1465],{"id":1464},"七全站外壳与水合边界","七、全站外壳与水合边界",[90,1467,1468,1471],{},[55,1469,1470],{},"app\u002Fapp.vue"," 是每个路由外面的共同外壳。它负责：",[117,1473,1474,1477,1480,1483,1489,1492,1498,1501],{},[120,1475,1476],{},"在页面加载时取得站点设置；",[120,1478,1479],{},"判断当前是否为主页；",[120,1481,1482],{},"初始化和恢复主题色；",[120,1484,1485,1486,1249],{},"把主题 CSS 变量挂到 ",[55,1487,1488],{},".site-shell",[120,1490,1491],{},"为非主页显示“返回”按钮与主题预设切换按钮；",[120,1493,1494,1495,1249],{},"设置标题模板、站点描述、Open Graph 信息和 ",[55,1496,1497],{},"theme-color",[120,1499,1500],{},"根据当前强调色实时生成 data URL favicon；",[120,1502,1503],{},"显示 Nuxt 页面加载进度条。",[90,1505,1506,1509,1510,1513,1514,1517,1518,1521],{},[55,1507,1508],{},"hydrated"," 初始为 ",[55,1511,1512],{},"false","，在 ",[55,1515,1516],{},"onMounted"," 完成主题恢复和本地监听注册后变成 ",[55,1519,1520],{},"true","，最终反映为：",[973,1523,1527],{"className":1524,"code":1525,"language":1526,"meta":266,"style":266},"language-html shiki shiki-themes github-light github-dark","\u003Cdiv class=\"site-shell\" data-hydrated=\"true\">\n","html",[55,1528,1529],{"__ignoreMap":266},[1530,1531,1534,1538,1542,1546,1549,1553,1556,1558,1561],"span",{"class":1532,"line":1533},"line",1,[1530,1535,1537],{"class":1536},"sVt8B","\u003C",[1530,1539,1541],{"class":1540},"s9eBZ","div",[1530,1543,1545],{"class":1544},"sScJk"," class",[1530,1547,1548],{"class":1536},"=",[1530,1550,1552],{"class":1551},"sZZnC","\"site-shell\"",[1530,1554,1555],{"class":1544}," data-hydrated",[1530,1557,1548],{"class":1536},[1530,1559,1560],{"class":1551},"\"true\"",[1530,1562,1563],{"class":1536},">\n",[90,1565,1566],{},"这个属性既是测试可观察的“客户端已经接管页面”标志，也是字标动画的播放闸门。CSS 动画先建立，但在页面完成水合前保持暂停，防止服务端 HTML 刚显示就消耗掉一段动画，等 JavaScript 接管时只剩最终帧。",[90,1568,1569,1570,1573,1574,1577],{},"非主页的全局返回入口固定回到 ",[55,1571,1572],{},"\u002F","，文本只有“返回”，图标和 ",[55,1575,1576],{},"aria-label"," 补充了方向与完整语义。它与文章正文中的“返回文章”属于不同层级：前者返回网站主页，后者返回文章列表。",[94,1579,1581],{"id":1580},"八主页是一张单屏工作台","八、主页是一张单屏工作台",[90,1583,1584],{},"主页不是按多个营销区块向下滚动，而是一张固定在一个视口高度内的工作台。核心区域包括：",[117,1586,1587,1590,1593,1596,1599,1602,1605],{},[120,1588,1589],{},"顶部站点标识、上海时区时钟、指针坐标和主题按钮；",[120,1591,1592],{},"左上介绍、普通标题前缀与 Quilibra 字标；",[120,1594,1595],{},"右上服务矩阵；",[120,1597,1598],{},"左下最近三篇文章；",[120,1600,1601],{},"右下 RGB 调色器；",[120,1603,1604],{},"底部中央文章、服务、关于三个入口；",[120,1606,1607],{},"两侧备案与署名。",[90,1609,1610,1611,1614,1615,1618,1619,1622,1623,1626],{},"首页在 ",[55,1612,1613],{},"setup"," 阶段并行取得站点设置和最近文章。文章查询按 ",[55,1616,1617],{},"date DESC"," 排序，再按 YAML 中的 ",[55,1620,1621],{},"limit"," 截取。服务矩阵先筛选 ",[55,1624,1625],{},"showOnHome: true","，按 YAML 顺序最多取四个；服务页仍然展示完整列表。",[90,1628,1629,1630,1633,1634,1637,1638,1641,1642,1645],{},"顶部时钟通过 ",[55,1631,1632],{},"Intl.DateTimeFormat"," 固定使用 ",[55,1635,1636],{},"Asia\u002FShanghai","，每 30 秒更新一次。指针坐标不是每次 ",[55,1639,1640],{},"pointermove"," 都直接改 DOM：事件只保存最新坐标，然后在下一帧 ",[55,1643,1644],{},"requestAnimationFrame"," 中统一计算。元素边界在挂载与窗口缩放时缓存，触摸指针被忽略。这样可以减少高频事件中的布局读取和响应式更新。",[90,1647,1648],{},"工作台没有为了装饰引入 canvas 或 WebGL。网格、面板、条纹、阴影和入场效果全部由 CSS 完成，浏览器可以直接合成绝大多数变换。",[94,1650,1652],{"id":1651},"九响应式布局为何不只是按比例缩小","九、响应式布局为何不只是“按比例缩小”",[90,1654,1655],{},"主页有大量绝对定位元素，因此响应式的目标不是把桌面页面机械缩成手机版，而是维护清晰的空间约束：",[117,1657,1658,1665,1668,1671,1674,1681],{},[120,1659,1660,1661,1664],{},"桌面端通过 ",[55,1662,1663],{},"clamp()","、视口高度和稳定的面板高度控制上下关系；",[120,1666,1667],{},"最近文章与 RGB 面板在宽桌面上对齐顶部和底部；",[120,1669,1670],{},"小屏笔记本缩小间距和模块尺寸，仍避免重叠；",[120,1672,1673],{},"768 像素附近的紧凑布局隐藏无法舒适操作的 RGB 面板；",[120,1675,1676,1677,1680],{},"手机端重新排列主页元素，并使用 ",[55,1678,1679],{},"overflow: clip"," 防止装饰或过渡产生横向滚动；",[120,1682,1683],{},"固定格式组件使用明确的 grid 列、最小宽度和高度，标题悬浮时不会重新计算可用宽度。",[90,1685,1686],{},"Playwright 会在 768×1024、1024×768、1440×900 和 3440×1440 上读取真实元素几何信息，验证介绍不压住服务矩阵、上方面板不压住底部导航、RGB 与最近文章对齐、页面没有横向溢出。这里测试的是关系，而不是容易因一个像素改动就失效的整页截图。",[94,1688,1690],{"id":1689},"十主题色从一个-rgb-值扩展成整套界面","十、主题色从一个 RGB 值扩展成整套界面",[90,1692,1693,1694,1697],{},"主题逻辑集中在 ",[55,1695,1696],{},"useAccentTheme.ts","。唯一的核心状态是：",[973,1699,1703],{"className":1700,"code":1701,"language":1702,"meta":266,"style":266},"language-ts shiki shiki-themes github-light github-dark","interface RgbColor {\n  r: number\n  g: number\n  b: number\n}\n","ts",[55,1704,1705,1717,1730,1739,1749],{"__ignoreMap":266},[1530,1706,1707,1711,1714],{"class":1532,"line":1533},[1530,1708,1710],{"class":1709},"szBVR","interface",[1530,1712,1713],{"class":1544}," RgbColor",[1530,1715,1716],{"class":1536}," {\n",[1530,1718,1719,1723,1726],{"class":1532,"line":267},[1530,1720,1722],{"class":1721},"s4XuR","  r",[1530,1724,1725],{"class":1709},":",[1530,1727,1729],{"class":1728},"sj4cs"," number\n",[1530,1731,1732,1735,1737],{"class":1532,"line":22},[1530,1733,1734],{"class":1721},"  g",[1530,1736,1725],{"class":1709},[1530,1738,1729],{"class":1728},[1530,1740,1742,1745,1747],{"class":1532,"line":1741},4,[1530,1743,1744],{"class":1721},"  b",[1530,1746,1725],{"class":1709},[1530,1748,1729],{"class":1728},[1530,1750,1752],{"class":1532,"line":1751},5,[1530,1753,1754],{"class":1536},"}\n",[90,1756,1757,1758,1761,1762,1765],{},"三个内置预设是红、绿、蓝。站点设置里的 ",[55,1759,1760],{},"theme.defaultAccent"," 可以是任意合法十六进制颜色，并不要求与预设一致。当前颜色存放在 Nuxt ",[55,1763,1764],{},"useState"," 中，因此同一客户端的页面切换不会创建互相冲突的主题实例。",[90,1767,1768],{},"主题计算分为几步：",[1184,1770,1771,1774,1783,1786,1792],{},[120,1772,1773],{},"把每个通道四舍五入并限制在 0 到 255。",[120,1775,1776,1777,1780,1781,115],{},"生成 CSS ",[55,1778,1779],{},"rgb(r g b)"," 与大写 ",[55,1782,1419],{},[120,1784,1785],{},"把强调色分别与白色、画布色和黑色混合，得到 soft、faint、canvas、grid、strong 等衍生色。",[120,1787,1788,1789,115],{},"计算 sRGB 相对亮度，对比黑白文字的对比度，自动选择更清晰的 ",[55,1790,1791],{},"--accent-ink",[120,1793,1794],{},"把结果以 CSS 变量挂到站点外壳，按钮、悬浮底色、网格、字标和 favicon 共同消费这些变量。",[90,1796,1797],{},"主题变量的意义大致如下：",[973,1799,1802],{"className":1800,"code":1801,"language":978,"meta":266},[976],"--accent          原始强调色\n--accent-ink      强调色背景上的黑或白文字\n--accent-soft     大面积悬浮反馈\n--accent-faint    更浅的面板背景\n--accent-canvas   轻微带主题倾向的页面画布\n--accent-grid     网格与线条色\n--accent-strong   向黑色混合后的强调色\n",[55,1803,1801],{"__ignoreMap":266},[90,1805,1806,1807,1809],{},"这样做比在 CSS 中到处硬编码“红色按钮、浅红背景、深红边框”更可靠。换成极亮或极暗的自定义颜色时，文字对比度仍会自动调整。E2E 会直接把颜色调到纯白和纯黑，验证 ",[55,1808,1791],{}," 分别变成深色和白色。",[94,1811,1813],{"id":1812},"十一主题持久化与旧黄色迁移","十一、主题持久化与旧黄色迁移",[90,1815,1816,1817,1820,1821,1824],{},"客户端挂载时，",[55,1818,1819],{},"restoreSavedAccent()"," 从 ",[55,1822,1823],{},"localStorage"," 读取：",[973,1826,1829],{"className":1827,"code":1828,"language":978,"meta":266},[976],"site-accent-rgb   完整 RGB 对象\nsite-accent       red \u002F green \u002F blue \u002F custom 等名称\n",[55,1830,1828],{"__ignoreMap":266},[90,1832,1833,1834,1837],{},"恢复后，深度监听 ",[55,1835,1836],{},"accentRgb","，后续每次变化都会重新保存。由于服务端无法读取浏览器存储，静态 HTML 首先使用 YAML 中的默认颜色；客户端挂载后再恢复访客上次的选择。",[90,1839,1840,1841,1158,1844,1847],{},"旧版本曾使用黄色默认主题。为了避免已经访问过网站的浏览器永远被旧缓存锁在黄色，恢复逻辑专门识别 ",[55,1842,1843],{},"{255,255,2}",[55,1845,1846],{},"yellow"," 的组合，删除这两个旧值并回到当前 YAML 默认色。这是一次小型数据迁移：不是清空所有人的自定义配色，只清除能够明确识别的旧默认值。",[90,1849,1850,1851,1854,1855,1858,1859,1862,1863,1866],{},"动态 favicon 也跟随主题。",[55,1852,1853],{},"app.vue"," 在内存中生成一个含背景色和 Q 图形的 SVG，再编码为 ",[55,1856,1857],{},"data:image\u002Fsvg+xml","。因此标签页图标和 ",[55,1860,1861],{},"meta[name=theme-color]"," 会与 RGB 面板同步；",[55,1864,1865],{},"public\u002Ffavicon.svg"," 只负责 JavaScript 接管前或不支持动态图标时的回退。",[94,1868,1870],{"id":1869},"十二rgb-调色器的交互细节","十二、RGB 调色器的交互细节",[90,1872,1873,1876,1877,1880],{},[55,1874,1875],{},"RgbAssembly.vue"," 不是独立维护另一份颜色，它调用同一个 ",[55,1878,1879],{},"useAccentTheme()","，因此滑杆、预设按钮、页面按钮和 favicon 始终共享状态。",[90,1882,1883],{},"三个 range input 分别控制 R、G、B：",[117,1885,1886,1892,1895,1898,1901],{},[120,1887,1888,1891],{},[55,1889,1890],{},"input"," 事件实时更新颜色，拖动时页面连续渐变；",[120,1893,1894],{},"每条轨道通过 CSS 变量计算已填充百分比；",[120,1896,1897],{},"输出区显示十六进制、十进制通道值，并采用自动对比文字；",[120,1899,1900],{},"点击 RED、GREEN、BLUE 立即加载预设；",[120,1902,1903],{},"重置按钮恢复 YAML 中的默认颜色，而不是写死某个预设。",[90,1905,1906],{},"字标动画不能在滑杆的每一个像素变化时重播，否则会不断重建动画并显得卡顿。组件因此区分“预览变化”和“提交变化”：",[117,1908,1909,1916,1922,1932,1939],{},[120,1910,1911,1912,1915],{},"指针按下后标记 ",[55,1913,1914],{},"pointerActive","，并捕获当前 pointer；",[120,1917,1918,1919,1921],{},"拖动中的 ",[55,1920,1890],{}," 只改变颜色；",[120,1923,1924,1927,1928,1931],{},[55,1925,1926],{},"pointerup"," 或 ",[55,1929,1930],{},"pointercancel"," 才请求重播一次字标；",[120,1933,1934,1935,1938],{},"键盘调整 range 时由 ",[55,1936,1937],{},"change"," 请求重播；",[120,1940,1941,1942,1226,1944,1946],{},"一个零延时抑制标志防止同一次鼠标提交同时触发 ",[55,1943,1926],{},[55,1945,1937],{},"，造成双播。",[90,1948,1949,1950],{},"预设与重置属于离散操作，所以点击时立即换色并重播。这个模型可以概括为：",[112,1951,1952],{},"连续操作实时预览、松手提交动画；离散操作立即提交。",[94,1954,1956],{"id":1955},"十三quilibra-字标并不是逐笔书写动画","十三、Quilibra 字标并不是逐笔书写动画",[90,1958,1959,1960,1963],{},"当前字标资源是 ",[55,1961,1962],{},"public\u002Fbrand\u002Fquilibra-handwritten.png","，尺寸比例为 1127:293，文件约 30 KB。页面不会直接显示这张 PNG，而是把它作为 CSS mask：图片只定义哪些像素可见，真正填充的颜色由 CSS 决定。因此同一份手写轮廓可以跟随任意主题色。",[90,1965,1966],{},"最终采用的是“RGB 套色从偏移到合拢”的动画，而不是模拟笔尖沿路径逐笔书写。原因是位图没有天然的笔画顺序；从位图自动推断真实书写路径成本高、结果也容易机械。套色动画更符合现有 RGB 工作台语言，同时实现稳定。",[90,1968,1969],{},"字标由四层相同 mask 组成：",[117,1971,1972,1975,1978,1981],{},[120,1973,1974],{},"红层从左下附近偏移进入；",[120,1976,1977],{},"绿层从上方偏移进入；",[120,1979,1980],{},"蓝层从右下附近偏移进入；",[120,1982,1983],{},"最终层使用当前主题色并带极轻的阴影。",[90,1985,1986,1987,1990,1991,1212,1994,1226,1997,2000,2001,2004],{},"前三层使用 ",[55,1988,1989],{},"mix-blend-mode: multiply","、动态模糊、透明度和不同位移。动画前段保留可见错版，中段快速靠近，后段降低彩色层透明度并让最终主题层聚焦。四层都只改变 ",[55,1992,1993],{},"opacity",[55,1995,1996],{},"transform",[55,1998,1999],{},"filter","，播放时临时声明 ",[55,2002,2003],{},"will-change","，结束后不长期占用合成资源。",[90,2006,2007,2010],{},[55,2008,2009],{},"HandwrittenWordmark.vue"," 的加载控制解决了“首次打开没有动画”的问题：",[1184,2012,2013,2020,2027,2037,2040],{},[120,2014,2015,2016,2019],{},"首页用 ",[55,2017,2018],{},"\u003Clink rel=\"preload\" as=\"image\">"," 提前请求 mask。",[120,2021,2022,2023,2026],{},"组件创建一次共享的 ",[55,2024,2025],{},"wordmarkReady"," Promise。",[120,2028,2029,2032,2033,2036],{},[55,2030,2031],{},"Image"," 加载后调用 ",[55,2034,2035],{},"decode()","，等待图片真正可用于绘制。",[120,2038,2039],{},"只有资源就绪、组件仍存活、页面可见且请求仍是最新时才开始播放。",[120,2041,2042],{},"图片失败时显示文字 fallback；开启减少动态效果时直接展示最终状态。",[90,2044,2045,2046,2049,2050,2053],{},"每次重播都会增加 ",[55,2047,2048],{},"animationRun","，并把它放进四层的 Vue ",[55,2051,2052],{},"key","。这会让浏览器得到新的动画元素，可靠地从第 0 帧开始，而不是依赖移除 class 后强制读取布局。",[94,2055,2057],{"id":2056},"十四字标在什么时候重播","十四、字标在什么时候重播",[90,2059,2060,2061,2064,2065,2068],{},"全局 ",[55,2062,2063],{},"useWordmarkAnimation()"," 只维护一个数字信号。任何组件调用 ",[55,2066,2067],{},"requestReplay()","，数字加一；字标组件 watch 到变化后重播。这个很小的事件通道避免 RGB 组件直接引用字标 DOM。",[90,2070,2071],{},"当前重播场景包括：",[117,2073,2074,2077,2080,2083,2086,2089,2092],{},[120,2075,2076],{},"首次进入主页并且 mask 解码完成；",[120,2078,2079],{},"点击主题预设或重置；",[120,2081,2082],{},"RGB 滑杆松手或键盘提交；",[120,2084,2085],{},"从文章、服务、关于页面返回主页，主页组件重新挂载；",[120,2087,2088],{},"浏览器标签页从隐藏变为可见；",[120,2090,2091],{},"窗口重新获得焦点；",[120,2093,2094,2095,2098],{},"浏览器的 ",[55,2096,2097],{},"pageshow","，包括可能来自往返缓存的恢复。",[90,2100,2101,1212,2104,1226,2107,2109],{},[55,2102,2103],{},"visibilitychange",[55,2105,2106],{},"focus",[55,2108,2097],{}," 可能在同一次切回中连续到达。组件使用一个 animation frame 合并激活请求，并设置 200ms 的最小间隔，防止一次切回连续播两三遍。页面变为隐藏时会取消待播放帧、使旧异步请求失效并结束当前播放。",[90,2111,2112],{},"这里还有两个无障碍与容错原则：",[117,2114,2115,2121],{},[120,2116,2117,2120],{},[55,2118,2119],{},"prefers-reduced-motion: reduce"," 时不播放套色，直接显示最终字标；",[120,2122,2123,2124,2127],{},"可读文字仍存在于 ",[55,2125,2126],{},"sr-only"," 中，视觉 mask 不承担标题语义。",[94,2129,2131],{"id":2130},"十五服务矩阵图标与状态点","十五、服务矩阵、图标与状态点",[90,2133,2134],{},"每个服务在 YAML 中有六个字段：名称、说明、链接、状态、图标、是否显示在主页。",[90,2136,2137,2140,2141,1158,2143,2146,2147,2150],{},[55,2138,2139],{},"ServiceIcon.vue"," 把业务名称映射到 Lucide 图标。NAS 使用独立的 ",[55,2142,65],{},[55,2144,2145],{},"HardDrive","，不会复用影音播放图标。未知值虽然有 ",[55,2148,2149],{},"Server"," 回退，但正常内容会在 Schema 阶段被拒绝，因此回退只是组件级防御。",[90,2152,2153],{},"状态共有三种：",[973,2155,2158],{"className":2156,"code":2157,"language":978,"meta":266},[976],"online   在线\nprivate  仅限本人\nsoon     准备中\n",[55,2159,2157],{"__ignoreMap":266},[90,2161,2162,2165,2166,2169,2170,2173],{},[55,2163,2164],{},"ServiceStatusDot.vue"," 把状态写入 ",[55,2167,2168],{},"data-state","，CSS 用属性选择器决定颜色，",[55,2171,2172],{},"title"," 提供文字说明。主页和服务页都复用这个组件，因此 CMS 修改 YAML 状态后，重新构建的两个页面会同步变化，不需要分别维护配色。",[90,2175,2176,2177,2180],{},"状态点表达的是",[112,2178,2179],{},"人工配置的展示状态","，不是实时健康检查。它不会主动请求 Code、Photos、NAS 或 Status，也不会自动从监控系统同步。如果未来需要实时状态，应由独立状态 API 提供可信结果，再决定是在客户端请求还是构建前抓取；不能仅把绿色小点误解为自动监控。",[90,2182,2183,2184,2186,2187,2190,2191,2194,2195,2198],{},"链接为 ",[55,2185,1444],{}," 时，主页服务节点转到 ",[55,2188,2189],{},"\u002Fservices","，服务页显示为不可点击行；完整 HTTPS 链接则在新标签页打开，并带 ",[55,2192,2193],{},"noopener noreferrer","。Schema 禁止 ",[55,2196,2197],{},"javascript:"," 和非 HTTPS 外部地址，避免 CMS 字段直接变成危险链接。",[94,2200,2202],{"id":2201},"十六文章列表筛选与搜索","十六、文章列表、筛选与搜索",[90,2204,2205,2208],{},[55,2206,2207],{},"\u002Fwriting"," 在构建阶段查询全部文章，并按日期倒序排列。浏览器端只对已经加载的数组做筛选，不需要为每个关键词请求服务器。",[90,2210,2211,2212,2215],{},"分类来自共享常量：随笔、学习、交易、观察。列表额外添加“全部”。搜索会把标题、摘要和标签拼成小写字符串，再做简单的 ",[55,2213,2214],{},"includes"," 匹配。这适合当前文章规模，特点是实现透明、中文可用、没有索引服务；但它不是分词搜索，也不会搜索正文。",[90,2217,2218],{},"文章行显示日期、标题、摘要、分类和箭头。悬浮一篇时：",[117,2220,2221,2224,2227,2230],{},[120,2222,2223],{},"只给当前行增加浅主题色背景；",[120,2225,2226],{},"日期与正文整体平移 8px；",[120,2228,2229],{},"箭头向右上轻移；",[120,2231,2232],{},"其他文章保持完全不变。",[90,2234,2235,2236,1212,2239,2242,2243,2246],{},"标题容器的 grid 列不会在 hover 时改变，所以长标题不会因为悬浮突然获得更小宽度而换行。主页“最近写下”的标题使用 ",[55,2237,2238],{},"minmax(0,1fr)",[55,2240,2241],{},"overflow:hidden","、省略号和 ",[55,2244,2245],{},"white-space:nowrap","，确保固定高度面板不被长标题撑开。",[90,2248,2249,2250,2253],{},"搜索结果区使用 ",[55,2251,2252],{},"aria-live=\"polite\"","，筛选后的篇数和空状态可以被辅助技术感知。",[94,2255,2257],{"id":2256},"十七文章详情与相邻导航","十七、文章详情与相邻导航",[90,2259,2260,2261,2264,2265,2268],{},"动态路由文件是 ",[55,2262,2263],{},"app\u002Fpages\u002Fwriting\u002F[...slug].vue","。它使用当前 ",[55,2266,2267],{},"route.path"," 查询对应文章；找不到时立即抛出带中文说明的 404。",[90,2270,2271],{},"详情页同时取得按日期倒序排列的全部文章，用当前文章的数组位置计算：",[117,2273,2274,2277],{},[120,2275,2276],{},"数组中下一项是时间上更旧的“上一篇”；",[120,2278,2279],{},"数组中上一项是时间上更新的“下一篇”。",[90,2281,2282,2283,2285],{},"页面展示分类、发布日期、可选的更新日期、标题、摘要、标签与正文。正文由 Nuxt Content 的 ",[55,2284,1344],{}," 生成。SEO 标题使用全站模板变成“文章标题 · Quilibra”，描述来自 frontmatter，Open Graph 类型设为 article。",[90,2287,2288,2289,2292],{},"正文样式集中在 ",[55,2290,2291],{},".article-prose","：限制阅读宽度、提高行高、分级处理标题、列表、引用、代码、链接和图片。文章页面可以自由使用 Markdown，不需要为每篇文章编写 Vue 模板。",[94,2294,2296],{"id":2295},"十八文章-frontmatter-合约","十八、文章 frontmatter 合约",[90,2298,2299],{},"一篇新文章最小结构如下：",[973,2301,2305],{"className":2302,"code":2303,"language":2304,"meta":266,"style":266},"language-yaml shiki shiki-themes github-light github-dark","---\ntitle: 清楚的文章标题\ndescription: 一句话说明文章实际记录了什么。\ndate: 2026-07-26\ncategory: 学习\ntags:\n  - Nuxt\n---\n","yaml",[55,2306,2307,2312,2322,2332,2342,2352,2361,2370],{"__ignoreMap":266},[1530,2308,2309],{"class":1532,"line":1533},[1530,2310,2311],{"class":1544},"---\n",[1530,2313,2314,2316,2319],{"class":1532,"line":267},[1530,2315,2172],{"class":1540},[1530,2317,2318],{"class":1536},": ",[1530,2320,2321],{"class":1551},"清楚的文章标题\n",[1530,2323,2324,2327,2329],{"class":1532,"line":22},[1530,2325,2326],{"class":1540},"description",[1530,2328,2318],{"class":1536},[1530,2330,2331],{"class":1551},"一句话说明文章实际记录了什么。\n",[1530,2333,2334,2337,2339],{"class":1532,"line":1741},[1530,2335,2336],{"class":1540},"date",[1530,2338,2318],{"class":1536},[1530,2340,2341],{"class":1728},"2026-07-26\n",[1530,2343,2344,2347,2349],{"class":1532,"line":1751},[1530,2345,2346],{"class":1540},"category",[1530,2348,2318],{"class":1536},[1530,2350,2351],{"class":1551},"学习\n",[1530,2353,2355,2358],{"class":1532,"line":2354},6,[1530,2356,2357],{"class":1540},"tags",[1530,2359,2360],{"class":1536},":\n",[1530,2362,2364,2367],{"class":1532,"line":2363},7,[1530,2365,2366],{"class":1536},"  - ",[1530,2368,2369],{"class":1551},"Nuxt\n",[1530,2371,2373],{"class":1532,"line":2372},8,[1530,2374,2311],{"class":1544},[90,2376,2377],{},"文件名必须是：",[973,2379,2382],{"className":2380,"code":2381,"language":978,"meta":266},[976],"YYYY-MM-DD-english-kebab.md\n",[55,2383,2381],{"__ignoreMap":266},[90,2385,2386,2387,1212,2389,1212,2391,1212,2393,1212,2396,1212,2399,1212,2401,2403],{},"允许字段只有 ",[55,2388,2172],{},[55,2390,2326],{},[55,2392,2336],{},[55,2394,2395],{},"updated",[55,2397,2398],{},"slug",[55,2400,2346],{},[55,2402,2357],{},"。发布新文章时：",[117,2405,2406,2411,2417,2422],{},[120,2407,2408,2410],{},[55,2409,2336],{}," 必须是中国时区当天；",[120,2412,2413,2414,2416],{},"文件名日期必须与 ",[55,2415,2336],{}," 一致；",[120,2418,2419,2420,1249],{},"不能包含 ",[55,2421,2395],{},[120,2423,2424,2426],{},[55,2425,2398],{}," 如果存在，必须与文件名后半段一致。",[90,2428,2429,2430,2432,2433,2435],{},"修订文章时保留原文件名和 ",[55,2431,2336],{},"，把 ",[55,2434,2395],{}," 设置为中国时区当天。正文结构是自由的，但不能为空。若使用二级标题“来源与延伸阅读”，该节必须至少有一个 HTTP 或 HTTPS 链接。",[90,2437,2438,2441,2442,2445],{},[55,2439,2440],{},"scripts\u002Fcontent\u002Fvalidate.ts"," 使用 ",[55,2443,2444],{},"gray-matter"," 和 YAML 解析 frontmatter，再用 Markdown AST 检查正文与来源节。使用结构化解析而不是正则扫描全文，可以区分标题、链接与普通文本，并给出确定的错误。",[94,2447,2449],{"id":2448},"十九sveltia-cms-到底是什么","十九、Sveltia CMS 到底是什么",[90,2451,2452,2455,2456,2458],{},[55,2453,2454],{},"\u002Fadmin\u002Findex.html"," 只加载 Sveltia CMS 的前端脚本，",[55,2457,1453],{}," 描述后台字段。它不是另一个网站后端，也不存文章副本。",[90,2460,2461],{},"后台能维护：",[117,2463,2464,2467,2470,2473,2476],{},[120,2465,2466],{},"站点、首页与栏目文案；",[120,2468,2469],{},"默认强调色和主页模块开关；",[120,2471,2472],{},"服务的增删、顺序、URL、状态、图标和主页显示；",[120,2474,2475],{},"文章的新建、搜索、筛选、修改和删除；",[120,2477,2478,2480],{},[55,2479,1229],{}," 中的文章资源。",[90,2482,2483],{},"CMS 有两种工作方式：",[1184,2485,2486,2489],{},[120,2487,2488],{},"本地仓库模式：Chromium 通过 File System Access API 直接编辑本机选择的仓库。",[120,2490,2491],{},"GitHub 模式：用户经 GitHub 登录后，CMS 根据配置向私有仓库提交内容。",[90,2493,2494],{},"无论哪种模式，“保存”都只意味着源文件或远程仓库出现改动。它不会神奇地更新正在运行的静态 release。要让网站变化，仍需要一台部署机取得新提交，运行校验与生成，再切换 release。",[90,2496,2497,2498,2501],{},"GitHub OAuth 控制“谁能通过 CMS 读写仓库”，GitHub Actions 控制“仓库收到提交后执行什么自动任务”。两者不是同一个东西。私人仓库存放网站源码、文章、公开图片和不含密钥的配置；OAuth secret、访问令牌、部署 SSH key、OpenClaw 会话和 ",[55,2499,2500],{},".env"," 不应进入仓库。",[90,2503,2504,2505,2508],{},"目前 CMS 配置指向 ",[55,2506,2507],{},"master"," 分支。若未来启用自动部署，一个典型链路是：",[973,2510,2513],{"className":2511,"code":2512,"language":978,"meta":266},[976],"浏览器登录 GitHub -> CMS 提交 Markdown\u002FYAML -> 私有仓库 master 更新\n       -> GitHub Actions 触发 -> 部署机拉取指定提交\n       -> npm ci \u002F 校验 \u002F npm run deploy -> 新 release 上线\n",[55,2514,2512],{"__ignoreMap":266},[90,2516,2517],{},"域名是否已经备案、网站是否已有公网 HTTPS，与“先把代码推到私人仓库”没有冲突。远程 CMS 登录通常需要 HTTPS 回调，但仓库和 Actions 可以先配置好。",[94,2519,2521],{"id":2520},"二十受限-writer-为什么存在","二十、受限 writer 为什么存在",[90,2523,2524,2525,2528],{},"普通编辑器可以修改仓库中的任何文件，但自动化发布工具不应该拥有同样宽的写入自由。",[55,2526,2527],{},"scripts\u002Fcontent\u002Fwrite.ts"," 把 OpenClaw 的写入范围压缩为三个明确操作：create、update、delete。",[90,2530,2531],{},"新建流程只接受草稿目录中的一个普通 Markdown 文件名和一个无日期 slug。writer 会检查：",[117,2533,2534,2537,2540,2543,2546,2549,2552],{},[120,2535,2536],{},"草稿名不能包含目录或路径穿越；",[120,2538,2539],{},"草稿必须是普通文件，不能是符号链接；",[120,2541,2542],{},"草稿不超过 1 MiB；",[120,2544,2545],{},"slug 必须是小写英文、数字和连字符；",[120,2547,2548],{},"frontmatter 与正文必须通过完整校验；",[120,2550,2551],{},"日期必须是中国时区当天；",[120,2553,2554],{},"目标文章不能已经存在。",[90,2556,2557,2558,2561,2562,2565,2566,2569,2570,2573],{},"写入时先以 ",[55,2559,2560],{},"wx"," 模式建立权限为 ",[55,2563,2564],{},"0640"," 的随机临时文件并 ",[55,2567,2568],{},"fsync","，再用硬链接创建最终文件，利用文件系统的 ",[55,2571,2572],{},"EEXIST"," 保证不会覆盖已有新文章。更新时先验证现有文件和发布日期，再用 rename 原子替换。删除只接受精确的完整 dated slug，并拒绝目录、符号链接和不存在的目标。",[90,2575,2576],{},"这不是为了让日常写作变复杂，而是为了让“从聊天自动发布”仍有可审计的硬边界。Skill 中的文字规则可能被模型误解，writer 的路径、日期和文件类型检查则由操作系统与代码强制执行。",[94,2578,2580],{"id":2579},"二十一openclaw-发布-skill-的实际状态机","二十一、OpenClaw 发布 Skill 的实际状态机",[90,2582,2583,2584,2587],{},"仓库只维护一个 ",[55,2585,2586],{},"personal-site-publisher"," Skill。它先读取文章合约，再按以下过程工作：",[973,2589,2592],{"className":2590,"code":2591,"language":978,"meta":266},[976],"链接或素材\n   |\n   v\n确定标题、摘要、日期、slug、分类、标签\n   |\n   v\n在私聊中返回完整草稿，不写仓库\n   |\n   +-- 修改：... --> 修改内存草稿\n   +-- 放弃 ------> 清除内存草稿\n   +-- 发布 ------> 保存到受限草稿目录\n                         |\n                         v\n                   content:write\n                         |\n                         v\n                     npm publish\n                         |\n                         v\n              返回文章 URL、commit、release\n",[55,2593,2591],{"__ignoreMap":266},[90,2595,2596,2599,2600,115],{},[55,2597,2598],{},"直接发布"," 只跳过人工预览，不跳过 writer、内容校验和静态生成。更新文章必须保留 dated URL；删除必须先展示目标信息，再收到完全匹配的 ",[55,2601,2602],{},"确认删除 \u003Cdated-slug>",[90,2604,2605,2606,1212,2609,1927,2612,2615],{},"发布 Skill 还规定：只接受所有者私聊中的发布命令；把网页、对话和搜索结果视为不可信内容；不把 API key、cookie、账号信息、私人对话细节和精确私人资产写入文章；不能用任意编辑器、",[55,2607,2608],{},"rm",[55,2610,2611],{},"git add",[55,2613,2614],{},"git commit"," 绕过 writer 和 release 脚本。",[94,2617,2619],{"id":2618},"二十二publish-与-deploy-是两条不同入口","二十二、publish 与 deploy 是两条不同入口",[90,2621,2622],{},"这两个命令最终都会生成静态站并切换 release，但权限和检查强度不同。",[2624,2625,2627],"h3",{"id":2626},"npm-run-publish",[55,2628,2629],{},"npm run publish",[90,2631,2632],{},"用于尚未提交的内容改动。它只允许以下路径：",[973,2634,2637],{"className":2635,"code":2636,"language":978,"meta":266},[976],"content\u002Fsettings\u002Fsite.yml\ncontent\u002Fwriting\u002F**\npublic\u002Fuploads\u002F**\n",[55,2638,2636],{"__ignoreMap":266},[90,2640,2641],{},"它验证内容、生成静态站、自动创建本地 Git commit、复制 release 并切换生产。若工作区混入 Vue、CSS、脚本、CMS 配置或文档改动，会拒绝执行。内容发布不重复跑全部代码 E2E，因为代码版本没有变化。",[2624,2643,2645],{"id":2644},"npm-run-deploy",[55,2646,2647],{},"npm run deploy",[90,2649,2650],{},"用于已经提交的代码版本。它要求工作区完全干净，不创建 commit，并依次运行：",[973,2652,2655],{"className":2653,"code":2654,"language":978,"meta":266},[976],"类型检查\n内容与 writer 单元测试\nrelease 单元测试\n静态生成\n浏览器 E2E\n创建 release\n原子切换 current\n清理过旧 release\n",[55,2656,2654],{"__ignoreMap":266},[90,2658,2659,2660,2663,2664,2667,2668,2670,2671,2673],{},"因此，修改本文这样的文章后，正常下一步是 ",[55,2661,2662],{},"publish","；修改 Vue\u002FCSS 并已经提交后，使用 ",[55,2665,2666],{},"deploy","。不要用 ",[55,2669,2662],{}," 偷渡代码，也不要让 ",[55,2672,2666],{}," 带着未提交文件上线。",[94,2675,2677],{"id":2676},"二十三静态-release-如何做到切换时不中断","二十三、静态 release 如何做到切换时不中断",[90,2679,2680,2683],{},[55,2681,2682],{},"scripts\u002Frelease.ts"," 用 UTC 时间生成 release 名称，例如：",[973,2685,2688],{"className":2686,"code":2687,"language":978,"meta":266},[976],"20260726T144914-134Z\n",[55,2689,2687],{"__ignoreMap":266},[90,2691,2692,2693,2695,2696,2699,2700,2702],{},"生成结束后，把 ",[55,2694,989],{}," 递归复制到 ",[55,2697,2698],{},"releases\u002F\u003Cid>","。激活时不是先删 ",[55,2701,993],{}," 再新建，而是：",[1184,2704,2705,2708,2711],{},[120,2706,2707],{},"创建一个带进程号的临时符号链接；",[120,2709,2710],{},"让临时链接指向新 release；",[120,2712,2713,2714,2717,2718,115],{},"用 ",[55,2715,2716],{},"rename"," 把临时链接原子替换成 ",[55,2719,993],{},[90,2721,2722,2723,2725,2726,2728],{},"对访问者来说，某个请求要么读取旧 release，要么读取新 release，不会遇到 ",[55,2724,993],{}," 暂时不存在的中间状态。生产 Node 进程也不需要重启，因为它每次请求都从 ",[55,2727,993],{}," 路径解析文件。",[90,2730,2731],{},"脚本默认保留最近五个 release，并额外保证当前激活版本不被删掉。由于当前版本有可能是手工回滚到的较旧目录，保留“当前版本”比单纯保留时间最新的五个更重要。",[90,2733,2734,2735,2737],{},"回滚只调用同一个原子激活函数，把 ",[55,2736,993],{}," 指回已存在的 release。它不修改 Git、不重新构建、不删除较新的版本，也不重启生产服务。",[94,2739,2741],{"id":2740},"二十四生产静态服务器做了哪些事","二十四、生产静态服务器做了哪些事",[90,2743,2744,2747,2748,1212,2751,1212,2754,1226,2757,2760,2761,2764],{},[55,2745,2746],{},"scripts\u002Fstatic-server.mjs"," 使用 Node 自带的 ",[55,2749,2750],{},"http",[55,2752,2753],{},"fs",[55,2755,2756],{},"stream",[55,2758,2759],{},"zlib","，默认监听 ",[55,2762,2763],{},"0.0.0.0:3000","。它没有框架中间件，职责非常窄：",[117,2766,2767,2770,2783,2789,2796,2799,2802,2805,2808,2811,2818,2824,2827],{},[120,2768,2769],{},"只接受 GET 和 HEAD，其他方法返回 405；",[120,2771,2772,2773,1158,2776,2779,2780,2782],{},"解码 URL 后用 ",[55,2774,2775],{},"resolve",[55,2777,2778],{},"relative"," 检查目标仍在 ",[55,2781,993],{}," 内，阻止目录穿越；",[120,2784,2785,2786,1249],{},"请求目录时返回该目录的 ",[55,2787,2788],{},"index.html",[120,2790,2791,2792,2795],{},"找不到文件时返回预生成的 ",[55,2793,2794],{},"404.html"," 和 404 状态；",[120,2797,2798],{},"根据扩展名发送正确的 Content-Type；",[120,2800,2801],{},"对大于等于 1 KiB 的文本资源协商 Brotli 或 gzip；",[120,2803,2804],{},"Brotli 使用质量 4，gzip 使用级别 6，在 CPU 与体积间取中间值；",[120,2806,2807],{},"使用读取流和 pipeline，不把大文件一次性读进内存；",[120,2809,2810],{},"根据文件大小和修改时间生成弱 ETag；",[120,2812,2813,2814,2817],{},"命中 ",[55,2815,2816],{},"If-None-Match"," 时返回 304；",[120,2819,2820,2823],{},[55,2821,2822],{},"_nuxt\u002F"," 哈希资源缓存一年并标记 immutable；",[120,2825,2826],{},"HTML、图片等非哈希路径使用 no-cache，确保 release 切换后会重新验证；",[120,2828,2829],{},"收到 SIGINT 或 SIGTERM 时停止接受新连接并正常退出。",[90,2831,2832,2833,2835],{},"如果 ",[55,2834,993],{}," 不可用，服务器返回 503，而不是把文件系统错误暴露给访问者。若响应流已经开始后出错，则销毁连接，避免发送一半文件后再拼接错误文本。",[90,2837,2838,2839,2842],{},"它不会处理 TLS、OAuth 或反向代理。公网 HTTPS 一般由 Nginx、Caddy、访问代理或隧道层终止，再转发到本机 3000。把服务监听改成 ",[55,2840,2841],{},"0.0.0.0"," 只代表网络接口可达，不会自动获得 HTTPS，也不会自动建立访问控制。",[94,2844,2846],{"id":2845},"二十五300031003101-分别是什么","二十五、3000、3100、3101 分别是什么",[1039,2848,2849,2862],{},[1042,2850,2851],{},[1045,2852,2853,2856,2859],{},[1048,2854,2855],{},"端口",[1048,2857,2858],{},"用途",[1048,2860,2861],{},"生命周期",[1055,2863,2864,2875,2886],{},[1045,2865,2866,2869,2872],{},[1060,2867,2868],{},"3000",[1060,2870,2871],{},"当前生产静态 release",[1060,2873,2874],{},"systemd 长期运行",[1045,2876,2877,2880,2883],{},[1060,2878,2879],{},"3100",[1060,2881,2882],{},"远程开发或稳定预览",[1060,2884,2885],{},"人工启动，需要时运行",[1045,2887,2888,2891,2894],{},[1060,2889,2890],{},"3101",[1060,2892,2893],{},"Playwright 隔离测试服务",[1060,2895,2896],{},"测试自动启动并结束",[90,2898,2899,2900,2903],{},"开发命令使用 ",[55,2901,2902],{},"--host 0.0.0.0"," 后，可以从远程电脑访问 VPS 的 3100，但还必须满足防火墙、Tailscale\u002F内网路由和浏览器安全策略。Sveltia 的本地仓库模式依赖 Chromium File System Access API；通过普通 HTTP 远程访问时，浏览器可能因为不是安全上下文而拒绝文件系统权限。解决方向是通过 HTTPS 访问后台，或在实际拥有仓库文件的电脑上用 localhost 打开，而不是继续扩大 3100 的公网暴露。",[90,2905,2906,2907,2909],{},"3101 使用独立内容 fixture 和 ",[55,2908,1291],{},"，不能拿它当日常预览端口。生产 3000、开发 3100 和测试 3101 可以同时存在，因为缓存目录和端口都隔离。",[94,2911,2913],{"id":2912},"二十六systemd-用户服务","二十六、systemd 用户服务",[90,2915,2916,2917,2920],{},"生产服务由 ",[55,2918,2919],{},"ops\u002Fsystemd\u002Fpersonal-site.service"," 描述。它的关键设置包括：",[117,2922,2923,2929,2935,2941,2947,2956],{},[120,2924,2925,2928],{},[55,2926,2927],{},"Type=simple","：Node 进程本身就是主进程；",[120,2930,2931,2934],{},[55,2932,2933],{},"After\u002FWants=network-online.target","：网络就绪后启动；",[120,2936,2937,2940],{},[55,2938,2939],{},"Restart=on-failure"," 与 5 秒延迟：异常退出后自动恢复；",[120,2942,2943,2946],{},[55,2944,2945],{},"KillSignal=SIGINT","：与静态服务器的优雅关闭逻辑对应；",[120,2948,2949,1212,2952,2955],{},[55,2950,2951],{},"NoNewPrivileges=true",[55,2953,2954],{},"PrivateTmp=true","：缩小运行时权限；",[120,2957,2958,2959,2962],{},"安装到用户级 ",[55,2960,2961],{},"default.target","，不要求整个服务以 root 运行。",[90,2964,2965,2966,2969,2970,2973],{},"unit 当前把 Node 可执行文件写成 NVM 下的明确路径。升级 Node 或切换 NVM 版本后，shell 中的 ",[55,2967,2968],{},"node"," 可能已经变化，但 systemd 仍引用旧路径，这是需要主动检查的运维陷阱。修改 unit 后必须 ",[55,2971,2972],{},"daemon-reload","，而普通文章或页面 release 不需要重启服务。",[90,2975,2976,2977,2980,2981,2984],{},"用户级服务要在 VPS 重启且用户未登录时自动启动，需要为运行网站的 Linux 用户启用 linger。管理它时应使用相同用户的 ",[55,2978,2979],{},"systemctl --user","，不应使用 ",[55,2982,2983],{},"sudo systemctl --user"," 去连接 root 的用户总线。",[94,2986,2988],{"id":2987},"二十七测试体系究竟覆盖什么","二十七、测试体系究竟覆盖什么",[90,2990,2991],{},"测试按风险边界分成三组。",[2624,2993,2995],{"id":2994},"内容和-writer-单元测试","内容和 writer 单元测试",[90,2997,2998,3001],{},[55,2999,3000],{},"test:content"," 检查：",[117,3003,3004,3007,3010,3013,3016,3019,3022,3025],{},[120,3005,3006],{},"合法文章和四种分类可以通过；",[120,3008,3009],{},"非法日期、分类、文件名、重复标签和空正文会失败；",[120,3011,3012],{},"来源节必须包含公共 HTTP(S) 链接；",[120,3014,3015],{},"CMS 可选 slug 必须与文件名一致；",[120,3017,3018],{},"站点 YAML 满足 Schema；",[120,3020,3021],{},"writer 拒绝覆盖、穿越、符号链接和错误修订日期；",[120,3023,3024],{},"更新保留发布日期；",[120,3026,3027],{},"删除只接受精确存在的 dated slug。",[2624,3029,3031],{"id":3030},"release-单元测试","release 单元测试",[90,3033,3034,3037],{},[55,3035,3036],{},"test:release"," 在临时目录中检查：",[117,3039,3040,3045,3048,3051,3054],{},[120,3041,3042,3044],{},[55,3043,993],{}," 能原子切换；",[120,3046,3047],{},"清理历史版本时保留激活 release；",[120,3049,3050],{},"release 名称不能路径穿越；",[120,3052,3053],{},"受管内容路径不会扩大到应用代码；",[120,3055,3056],{},"子命令失败时错误信息保留退出码。",[2624,3058,3060],{"id":3059},"playwright-浏览器测试","Playwright 浏览器测试",[90,3062,3063,3066],{},[55,3064,3065],{},"test:e2e"," 在 Chromium 中检查：",[117,3068,3069,3072,3075,3078,3081,3084,3087,3090,3093,3096,3099],{},[120,3070,3071],{},"首页成功水合且没有控制台错误；",[120,3073,3074],{},"动态 favicon、theme-color 和 RGB 输出同步；",[120,3076,3077],{},"自定义主题在纯黑纯白下仍可读；",[120,3079,3080],{},"旧黄色缓存会迁移；",[120,3082,3083],{},"mask 没加载完时字标不偷跑，加载后正常播放；",[120,3085,3086],{},"标签页激活、窗口 focus、换色、滑杆松手和返回主页会重播；",[120,3088,3089],{},"拖动期间不会反复播放；",[120,3091,3092],{},"服务状态、NAS 图标、最近文章、文章详情和更新日期正确；",[120,3094,3095],{},"文章悬浮只影响当前行，长标题宽度不跳变；",[120,3097,3098],{},"手机页面无横向溢出，RGB 在小屏隐藏；",[120,3100,3101],{},"多种桌面尺寸下关键模块互不重叠。",[90,3103,3104],{},"Playwright 配置允许一次重试，等待时间 10 秒，临时 Nuxt 服务启动最长等待 120 秒。响应式几何测试启用 reduced motion，避免入场动画中的瞬时位置影响布局判断。",[90,3106,3107],{},"测试不是越多越好。这里保留的是曾经真实出错、或者一旦回归就很难靠类型系统发现的行为；字体文件数量、每个 CSS 颜色和每一段正文不需要分别写测试。",[94,3109,3111],{"id":3110},"二十八当前性能画像与做过的优化","二十八、当前性能画像与做过的优化",[90,3113,3114],{},"在当前版本的一次本机测量中：",[117,3116,3117,3120,3123,3126,3129],{},[120,3118,3119],{},"主 CSS 约 31.1 KB，gzip 后约 6.9 KB；",[120,3121,3122],{},"外部或本地字体文件由 98 个减少到 0；",[120,3124,3125],{},"首页一次传输约 252 KB；",[120,3127,3128],{},"模拟 4G 和 4 倍 CPU 降速时，LCP 约 0.75 秒，完整 load 约 1.37 秒；",[120,3130,3131],{},"CLS 为 0。",[90,3133,3134],{},"这些数字是环境相关快照，不是永久承诺。浏览器缓存、网络、CPU、文章数量和依赖升级都会改变结果。",[90,3136,3137],{},"当前主要性能措施包括：",[117,3139,3140,3143,3146,3149,3155,3160,3163,3166,3169,3172,3175],{},[120,3141,3142],{},"静态预渲染，HTML 首次响应包含页面内容；",[120,3144,3145],{},"移除大批字体资源，改用系统字体；",[120,3147,3148],{},"只预加载首屏真正依赖的 30 KB 字标 mask；",[120,3150,3151,3152,3154],{},"字标等待 ",[55,3153,2035],{},"，避免资源未准备好时动画丢失；",[120,3156,3157,3159],{},[55,3158,1644],{}," 合并高频指针更新；",[120,3161,3162],{},"缓存元素边界，避免每次 pointermove 读取布局；",[120,3164,3165],{},"连续调色只改颜色，松手才重播动画；",[120,3167,3168],{},"用 transform\u002Fopacity 处理大多数动效；",[120,3170,3171],{},"生产服务器流式响应并支持 Brotli、gzip、ETag 和长期哈希缓存；",[120,3173,3174],{},"固定组件尺寸，避免动态文本造成布局偏移；",[120,3176,3177],{},"分离开发、release 和 E2E 的 Nuxt Content 数据库。",[90,3179,3180,3182],{},[55,3181,989],{}," 整体约 5.4 MB，其中包括 Nuxt Content 的客户端 SQLite\u002FWASM 相关资源；这不等于每个访客首屏都会下载整个目录。分析性能时应看浏览器实际请求和传输体积，不应把产物目录大小直接当作首页流量。",[94,3184,3186],{"id":3185},"二十九为什么首次交互偶尔会过一会儿才正常","二十九、为什么首次交互偶尔会“过一会儿才正常”",[90,3188,3189],{},"这个问题曾同时表现为字标不播放和 RGB 滑杆暂时失灵，根因方向不是滑杆 CSS 本身，而是客户端水合尚未完成或开发服务器仍在编译。静态 HTML 可以先显示，但 Vue 事件只有在 JavaScript 加载、执行并成功水合后才生效。",[90,3191,3192,3193,3196],{},"判断方法是观察 ",[55,3194,3195],{},".site-shell[data-hydrated=\"true\"]","。如果页面已经显示但该属性迟迟没有变成 true，应检查：",[117,3198,3199,3202,3205,3208,3211],{},[120,3200,3201],{},"浏览器控制台是否有 JavaScript 错误；",[120,3203,3204],{},"Nuxt 开发服务器是否还在首次编译；",[120,3206,3207],{},"内容 SQLite 缓存是否损坏；",[120,3209,3210],{},"大型依赖或资源是否阻塞客户端入口；",[120,3212,3213],{},"当前访问的是 3100 开发服务，还是已经生成的生产静态站。",[90,3215,3216],{},"目前通过移除字体、减轻入口资源、预加载 mask、分离内容数据库和明确动画水合闸门改善了这个过程。生产静态站通常比第一次启动的开发服务器稳定，因为它不需要边访问边编译。",[94,3218,3220],{"id":3219},"三十常见修改应该改哪里","三十、常见修改应该改哪里",[2624,3222,3224],{"id":3223},"修改个人介绍栏目文案或服务","修改个人介绍、栏目文案或服务",[90,3226,3227,3228,3230],{},"优先通过 CMS 或编辑 ",[55,3229,1222],{},"。若新增服务状态或图标类型，还要同步修改 Schema、配置枚举、CMS 选项、组件映射、CSS 和测试。",[2624,3232,3233],{"id":3233},"修改默认颜色",[90,3235,3236,3237,3239,3240,3242],{},"修改 ",[55,3238,1760],{},"。它可以是任意 ",[55,3241,1419],{},"。已有访客若保存过自定义颜色，会继续看到自己的选择；要做全体迁移，需要像旧黄色迁移一样明确识别并处理旧值，不能无条件清空 localStorage。",[2624,3244,3245],{"id":3245},"修改红绿蓝预设",[90,3247,3236,3248,3250,3251,3254],{},[55,3249,1696],{}," 的 ",[55,3252,3253],{},"accentPresets","。RGB 面板和非主页调色按钮都复用它。修改后应测试纯黑纯白对比、localStorage 恢复和字标重播。",[2624,3256,3257],{"id":3257},"修改字标图",[90,3259,3260,3261,3263,3264,3267],{},"替换 ",[55,3262,1962],{},"，尽量保留透明背景和接近 1127:293 的宽高比；若比例改变，同步修改 CSS ",[55,3265,3266],{},"aspect-ratio","。检查 preload 路径、CSS mask 路径和组件资源路径三者一致。",[2624,3269,3270],{"id":3270},"修改字标动画",[90,3272,3273,3274,3276,3277,3280,3281,3284],{},"播放条件在 ",[55,3275,2009],{},"，跨组件触发在 ",[55,3278,3279],{},"useWordmarkAnimation.ts","，视觉关键帧在 ",[55,3282,3283],{},"main.css","。不要把三者混成一个大组件：资源状态、事件状态和视觉时间线是不同责任。",[2624,3286,3287],{"id":3287},"修改文章分类",[90,3289,3290,3291,3294],{},"至少同步 ",[55,3292,3293],{},"app\u002Fconfig\u002Farticles.ts","、Nuxt Content Schema、CMS 选项、校验器测试与界面测试。文章中的旧分类是否迁移，需要单独决定。",[2624,3296,3297],{"id":3297},"修改文章样式",[90,3299,3300,3301,3304,3305,3307,3308,3311],{},"文章列表看 ",[55,3302,3303],{},".article-row","，正文看 ",[55,3306,2291],{},"，详情头部看 ",[55,3309,3310],{},".article-hero","。长标题、手机宽度、hover 前后几何和其他文章 opacity 是必须复查的回归点。",[2624,3313,3314],{"id":3314},"修改生产服务",[90,3316,3317,3318,3320],{},"静态响应逻辑改 ",[55,3319,2746],{},"；启动用户、Node 路径、重启策略改 systemd unit。只有这两类变化需要重启服务本身，普通 release 切换不需要。",[94,3322,3324],{"id":3323},"三十一日常发布配方","三十一、日常发布配方",[2624,3326,3328],{"id":3327},"只发布文章或-yaml-内容","只发布文章或 YAML 内容",[973,3330,3334],{"className":3331,"code":3332,"language":3333,"meta":266,"style":266},"language-bash shiki shiki-themes github-light github-dark","npm run content:validate\nnpm run publish\n","bash",[55,3335,3336,3347],{"__ignoreMap":266},[1530,3337,3338,3341,3344],{"class":1532,"line":1533},[1530,3339,3340],{"class":1544},"npm",[1530,3342,3343],{"class":1551}," run",[1530,3345,3346],{"class":1551}," content:validate\n",[1530,3348,3349,3351,3353],{"class":1532,"line":267},[1530,3350,3340],{"class":1544},[1530,3352,3343],{"class":1551},[1530,3354,3355],{"class":1551}," publish\n",[90,3357,3358,3360],{},[55,3359,2662],{}," 成功后会输出 commit、release 和 current 路径。它创建的是本地提交；是否推送 GitHub 是另一项操作。",[2624,3362,3364],{"id":3363},"发布-vuecss脚本或配置代码","发布 Vue、CSS、脚本或配置代码",[973,3366,3368],{"className":3331,"code":3367,"language":3333,"meta":266,"style":266},"npm run typecheck\nnpm run test:content\nnpm run test:release\nnpm run test:e2e\nnpm run generate\ngit diff --check\n# 明确检查并提交本次文件\nnpm run deploy\n",[55,3369,3370,3379,3388,3397,3406,3415,3426,3432],{"__ignoreMap":266},[1530,3371,3372,3374,3376],{"class":1532,"line":1533},[1530,3373,3340],{"class":1544},[1530,3375,3343],{"class":1551},[1530,3377,3378],{"class":1551}," typecheck\n",[1530,3380,3381,3383,3385],{"class":1532,"line":267},[1530,3382,3340],{"class":1544},[1530,3384,3343],{"class":1551},[1530,3386,3387],{"class":1551}," test:content\n",[1530,3389,3390,3392,3394],{"class":1532,"line":22},[1530,3391,3340],{"class":1544},[1530,3393,3343],{"class":1551},[1530,3395,3396],{"class":1551}," test:release\n",[1530,3398,3399,3401,3403],{"class":1532,"line":1741},[1530,3400,3340],{"class":1544},[1530,3402,3343],{"class":1551},[1530,3404,3405],{"class":1551}," test:e2e\n",[1530,3407,3408,3410,3412],{"class":1532,"line":1751},[1530,3409,3340],{"class":1544},[1530,3411,3343],{"class":1551},[1530,3413,3414],{"class":1551}," generate\n",[1530,3416,3417,3420,3423],{"class":1532,"line":2354},[1530,3418,3419],{"class":1544},"git",[1530,3421,3422],{"class":1551}," diff",[1530,3424,3425],{"class":1728}," --check\n",[1530,3427,3428],{"class":1532,"line":2363},[1530,3429,3431],{"class":3430},"sJ8bj","# 明确检查并提交本次文件\n",[1530,3433,3434,3436,3438],{"class":1532,"line":2372},[1530,3435,3340],{"class":1544},[1530,3437,3343],{"class":1551},[1530,3439,3440],{"class":1551}," deploy\n",[90,3442,3443,3445],{},[55,3444,2666],{}," 自身也会执行完整检查，前面的命令适合在提交前尽早发现问题。工作区不干净时它会拒绝上线。",[2624,3447,3448],{"id":3448},"查看当前生产状态",[973,3450,3452],{"className":3331,"code":3451,"language":3333,"meta":266,"style":266},"systemctl --user is-active personal-site.service\nreadlink -f \"$SITE_DATA\u002Fcurrent\"\ncurl -fsS -o \u002Fdev\u002Fnull -w '%{http_code} %{content_type}\\n' http:\u002F\u002F127.0.0.1:3000\u002F\n",[55,3453,3454,3468,3485],{"__ignoreMap":266},[1530,3455,3456,3459,3462,3465],{"class":1532,"line":1533},[1530,3457,3458],{"class":1544},"systemctl",[1530,3460,3461],{"class":1728}," --user",[1530,3463,3464],{"class":1551}," is-active",[1530,3466,3467],{"class":1551}," personal-site.service\n",[1530,3469,3470,3473,3476,3479,3482],{"class":1532,"line":267},[1530,3471,3472],{"class":1544},"readlink",[1530,3474,3475],{"class":1728}," -f",[1530,3477,3478],{"class":1551}," \"",[1530,3480,3481],{"class":1536},"$SITE_DATA",[1530,3483,3484],{"class":1551},"\u002Fcurrent\"\n",[1530,3486,3487,3490,3493,3496,3499,3502,3505],{"class":1532,"line":22},[1530,3488,3489],{"class":1544},"curl",[1530,3491,3492],{"class":1728}," -fsS",[1530,3494,3495],{"class":1728}," -o",[1530,3497,3498],{"class":1551}," \u002Fdev\u002Fnull",[1530,3500,3501],{"class":1728}," -w",[1530,3503,3504],{"class":1551}," '%{http_code} %{content_type}\\n'",[1530,3506,3507],{"class":1551}," http:\u002F\u002F127.0.0.1:3000\u002F\n",[90,3509,3510,3512],{},[55,3511,3481],{}," 应指向个人站点的 release 数据目录，不要把示例变量直接用于删除命令。",[2624,3514,3515],{"id":3515},"回滚",[90,3517,3518],{},"先列出确实存在的 release，再执行：",[973,3520,3522],{"className":3331,"code":3521,"language":3333,"meta":266,"style":266},"npm run rollback -- \u003Cexact-release-id>\n",[55,3523,3524],{"__ignoreMap":266},[1530,3525,3526,3528,3530,3533,3536,3539,3542,3545],{"class":1532,"line":1533},[1530,3527,3340],{"class":1544},[1530,3529,3343],{"class":1551},[1530,3531,3532],{"class":1551}," rollback",[1530,3534,3535],{"class":1728}," --",[1530,3537,3538],{"class":1709}," \u003C",[1530,3540,3541],{"class":1551},"exact-release-i",[1530,3543,3544],{"class":1536},"d",[1530,3546,1563],{"class":1709},[90,3548,3549,3550,3552,3553,3555,3556,115],{},"回滚后再次检查 ",[55,3551,993],{}," 和 3000 返回值。不要手动删除 ",[55,3554,993],{},"，也不要把它指向仓库的 ",[55,3557,989],{},[94,3559,3561],{"id":3560},"三十二故障排查顺序","三十二、故障排查顺序",[2624,3563,3564],{"id":3564},"文章已保存但网站看不到",[90,3566,3567,3568,3570,3571,3573],{},"依次确认：文章是否在 ",[55,3569,1225],{},"、校验是否通过、是否执行 publish\u002Fdeploy、",[55,3572,993],{}," 是否指向新 release、3000 返回的 HTML 是否包含新标题。CMS 保存和 Git push 本身都不等于部署完成。",[2624,3575,3577],{"id":3576},"rgb-不能拖按钮不能点动画不播放","RGB 不能拖、按钮不能点、动画不播放",[90,3579,3580,3581,3584,3585,3588],{},"先看 ",[55,3582,3583],{},"data-hydrated","，再看控制台错误和网络请求。若只发生在 Nuxt 第一次开发编译，等待编译完成后重载；若持续发生，停止开发服务，运行 ",[55,3586,3587],{},"npx nuxt cleanup","，再启动 3100。不要为此停止生产 3000。",[2624,3590,3591],{"id":3591},"切回标签页没有动画",[90,3593,3594,3595,1212,3597,3599],{},"检查浏览器是否启用 reduced motion、mask 图片是否加载失败，以及 ",[55,3596,2103],{},[55,3598,2106],{}," 是否触发。一次切回只播一次是正常防抖，不应去掉 200ms 合并后让三个事件连续触发。",[2624,3601,3602],{"id":3602},"换色先闪回旧颜色",[90,3604,3605,3606,3608],{},"检查静态默认色、Nuxt ",[55,3607,1764],{}," 初始值和 localStorage 恢复顺序。服务端 HTML无法知道客户端保存颜色，完全避免首帧差异需要在页面渲染前执行极小的内联主题恢复脚本；当前实现选择保持静态生成简单，在水合时恢复。",[2624,3610,3612],{"id":3611},"服务状态点不随-cms-变化","服务状态点不随 CMS 变化",[90,3614,3615,3616,3619,3620,3622],{},"确认 YAML 中 ",[55,3617,3618],{},"state"," 已保存、值属于三个枚举、已经重新生成 release，并检查 DOM 的 ",[55,3621,2168],{},"。如果属性已变而颜色没变，检查 CSS 状态选择器；如果属性没变，检查当前访问的 release 是否仍是旧版本。",[2624,3624,3626],{"id":3625},"_3000-无法访问","3000 无法访问",[90,3628,3629,3630,3632,3633,3635],{},"检查用户级 systemd 状态、日志、Node 固定路径、端口占用和 ",[55,3631,993],{}," 链接。服务器进程存在但 ",[55,3634,993],{}," 失效时会返回 503。不要在未确认进程归属前直接杀端口进程。",[2624,3637,3639],{"id":3638},"管理页面提示只允许-https","管理页面提示只允许 HTTPS",[90,3641,3642],{},"这通常来自浏览器安全上下文要求，而不是 Git remote 配错。Git remote 只决定仓库同步地址，不会给 HTTP 页面增加 HTTPS。使用 localhost、本机仓库模式，或为远程后台配置可信 HTTPS 和 Git OAuth；同时把后台放在 Tailscale或访问控制后面，因为后台路径本身不是权限系统。",[94,3644,3646],{"id":3645},"三十三安全与备份边界","三十三、安全与备份边界",[90,3648,3649],{},"至少要区分三类数据：",[973,3651,3654],{"className":3652,"code":3653,"language":978,"meta":266},[976],"Git 仓库       源码、文章、站点设置、公开静态资源\nOpenClaw 目录  Skill、草稿、会话和本地配置\nrelease 目录   当前及历史静态构建结果\n",[55,3655,3653],{"__ignoreMap":266},[90,3657,3658],{},"Git 提交是版本历史，不是异地备份。私人远程仓库可以备份源码与文章，但 OpenClaw 配置和 release 数据需要单独备份到受控存储。",[90,3660,3661,3662,3664],{},"永远不要提交或写入公开文章的内容包括：API key、OAuth secret、部署私钥、QQ token、cookie、扫码状态、",[55,3663,2500],{},"、私人服务密码、内部地址清单和不适合公开的资产信息。",[90,3666,3667,3668,3671,3672,3675],{},"CMS 的 ",[55,3669,3670],{},"\u002Fadmin\u002F"," 路径和 ",[55,3673,3674],{},"noindex"," 只能减少搜索引擎收录，不能阻止陌生人访问。真正的保护来自 Git 登录、HTTPS、网络访问范围和最小权限部署凭据。",[94,3677,3679],{"id":3678},"三十四维护这套代码时应坚持的原则","三十四、维护这套代码时应坚持的原则",[90,3681,3682],{},"第一，内容、表现和发布边界分开。能在 YAML 解决的文案不要硬编码进 Vue；能由共享组件表达的状态不要在两个页面复制；生产切换不要混进页面代码。",[90,3684,3685],{},"第二，把浏览器状态当成显式状态。主题色、资源是否解码、页面是否可见、指针是否仍按下、水合是否完成，都应有清楚的变量和生命周期，而不是靠延时猜测。",[90,3687,3688],{},"第三，动画必须有静态最终状态。资源失败、JavaScript 失败或用户减少动态效果时，标题仍要可读，布局仍要成立。",[90,3690,3691],{},"第四，自动化写入必须比人工编辑权限更窄。Skill 负责工作流，writer 负责硬边界，validator 负责内容合约，release 负责上线，四者不能互相冒充。",[90,3693,3694],{},"第五，生产部署应该是“生成一个完整新版本，然后切换”，而不是在访问者正在读取的目录里逐个覆盖文件。原子 release 是这个小网站最值得长期保留的工程设计之一。",[90,3696,3697],{},"第六，测试真实的关系和历史 bug。主题对比、滑杆松手、标签页重播、长标题 hover、服务状态同步和多视口不重叠，都来自实际使用中的问题，比为了提高数字而堆大量脆弱测试更有价值。",[94,3699,3701],{"id":3700},"三十五重新上手时的最短阅读路径","三十五、重新上手时的最短阅读路径",[90,3703,3704],{},"如果未来很久没有维护这个项目，按下面顺序读，可以最快恢复上下文：",[1184,3706,3707,3713,3721,3730,3736,3741,3750],{},[120,3708,3709,3710,3712],{},"看 ",[55,3711,1222],{},"，知道网站当前展示什么。",[120,3714,3709,3715,1226,3718,3720],{},[55,3716,3717],{},"app\u002Fpages\u002Findex.vue",[55,3719,3283],{}," 的主页部分，理解首屏结构。",[120,3722,3709,3723,1212,3725,1212,3727,3729],{},[55,3724,1696],{},[55,3726,1875],{},[55,3728,2009],{},"，理解最复杂的交互。",[120,3731,3732,3733,3735],{},"看两个 writing 页面和 ",[55,3734,1308],{},"，理解文章查询与渲染。",[120,3737,3709,3738,3740],{},[55,3739,1410],{},"、validator 和 writer，理解内容边界。",[120,3742,3709,3743,1212,3746,3749],{},[55,3744,3745],{},"release.ts",[55,3747,3748],{},"static-server.mjs"," 和 systemd unit，理解生产链路。",[120,3751,3752],{},"最后看测试，把“哪些行为不能再坏”快速过一遍。",[90,3754,3755],{},"只要能重新回答下面五个问题，就已经掌握了这个项目：",[117,3757,3758,3761,3764,3767,3770],{},[120,3759,3760],{},"当前页面内容的唯一来源在哪里？",[120,3762,3763],{},"浏览器中的主题色如何从 RGB 状态传到 CSS、字标和 favicon？",[120,3765,3766],{},"为什么 CMS 保存后线上不会立刻变化？",[120,3768,3769],{},"publish 和 deploy 的权限、检查与 Git 行为有什么不同？",[120,3771,3772],{},"一个新 release 如何在不重启 3000 的情况下接管生产请求？",[90,3774,3775],{},"这五条就是 Quilibra 当前技术架构的骨架。",[94,3777,818],{"id":818},[117,3779,3780,3787,3794,3801,3808,3815,3822,3829],{},[120,3781,3782],{},[638,3783,3786],{"href":3784,"rel":3785},"https:\u002F\u002Fnuxt.com\u002Fdocs",[642],"Nuxt 文档",[120,3788,3789],{},[638,3790,3793],{"href":3791,"rel":3792},"https:\u002F\u002Fcontent.nuxt.com\u002F",[642],"Nuxt Content 文档",[120,3795,3796],{},[638,3797,3800],{"href":3798,"rel":3799},"https:\u002F\u002Fvuejs.org\u002Fguide\u002Fextras\u002Fcomposition-api-faq.html",[642],"Vue Composition API",[120,3802,3803],{},[638,3804,3807],{"href":3805,"rel":3806},"https:\u002F\u002Fplaywright.dev\u002Fdocs\u002Fintro",[642],"Playwright 文档",[120,3809,3810],{},[638,3811,3814],{"href":3812,"rel":3813},"https:\u002F\u002Fgithub.com\u002Fsveltia\u002Fsveltia-cms",[642],"Sveltia CMS 文档",[120,3816,3817],{},[638,3818,3821],{"href":3819,"rel":3820},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FCSS\u002Fmask",[642],"MDN：CSS mask",[120,3823,3824],{},[638,3825,3828],{"href":3826,"rel":3827},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FPage_Visibility_API",[642],"MDN：Page Visibility API",[120,3830,3831],{},[638,3832,3835],{"href":3833,"rel":3834},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FCaching",[642],"MDN：HTTP 缓存",[3837,3838,3839],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":266,"searchDepth":267,"depth":267,"links":3841},[3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3867,3868,3869,3870,3871,3876,3877,3878,3888,3894,3903,3904,3905,3906],{"id":964,"depth":267,"text":965},{"id":1000,"depth":267,"text":1001},{"id":1033,"depth":267,"text":1034},{"id":1169,"depth":267,"text":1170},{"id":1233,"depth":267,"text":1234},{"id":1355,"depth":267,"text":1356},{"id":1464,"depth":267,"text":1465},{"id":1580,"depth":267,"text":1581},{"id":1651,"depth":267,"text":1652},{"id":1689,"depth":267,"text":1690},{"id":1812,"depth":267,"text":1813},{"id":1869,"depth":267,"text":1870},{"id":1955,"depth":267,"text":1956},{"id":2056,"depth":267,"text":2057},{"id":2130,"depth":267,"text":2131},{"id":2201,"depth":267,"text":2202},{"id":2256,"depth":267,"text":2257},{"id":2295,"depth":267,"text":2296},{"id":2448,"depth":267,"text":2449},{"id":2520,"depth":267,"text":2521},{"id":2579,"depth":267,"text":2580},{"id":2618,"depth":267,"text":2619,"children":3864},[3865,3866],{"id":2626,"depth":22,"text":2629},{"id":2644,"depth":22,"text":2647},{"id":2676,"depth":267,"text":2677},{"id":2740,"depth":267,"text":2741},{"id":2845,"depth":267,"text":2846},{"id":2912,"depth":267,"text":2913},{"id":2987,"depth":267,"text":2988,"children":3872},[3873,3874,3875],{"id":2994,"depth":22,"text":2995},{"id":3030,"depth":22,"text":3031},{"id":3059,"depth":22,"text":3060},{"id":3110,"depth":267,"text":3111},{"id":3185,"depth":267,"text":3186},{"id":3219,"depth":267,"text":3220,"children":3879},[3880,3881,3882,3883,3884,3885,3886,3887],{"id":3223,"depth":22,"text":3224},{"id":3233,"depth":22,"text":3233},{"id":3245,"depth":22,"text":3245},{"id":3257,"depth":22,"text":3257},{"id":3270,"depth":22,"text":3270},{"id":3287,"depth":22,"text":3287},{"id":3297,"depth":22,"text":3297},{"id":3314,"depth":22,"text":3314},{"id":3323,"depth":267,"text":3324,"children":3889},[3890,3891,3892,3893],{"id":3327,"depth":22,"text":3328},{"id":3363,"depth":22,"text":3364},{"id":3448,"depth":22,"text":3448},{"id":3515,"depth":22,"text":3515},{"id":3560,"depth":267,"text":3561,"children":3895},[3896,3897,3898,3899,3900,3901,3902],{"id":3564,"depth":22,"text":3564},{"id":3576,"depth":22,"text":3577},{"id":3591,"depth":22,"text":3591},{"id":3602,"depth":22,"text":3602},{"id":3611,"depth":22,"text":3612},{"id":3625,"depth":22,"text":3626},{"id":3638,"depth":22,"text":3639},{"id":3645,"depth":267,"text":3646},{"id":3678,"depth":267,"text":3679},{"id":3700,"depth":267,"text":3701},{"id":818,"depth":267,"text":818},"学习","完整记录 Quilibra 个人主页当前版本的技术选型、页面架构、内容系统、主题动画、测试体系、发布流程和日常维护方法。",{},"\u002Fwriting\u002F2026-07-26-quilibra-complete-technical-handbook","2026-07-26T23:46:23+08:00",{"title":953,"description":3908},"writing\u002F2026-07-26-quilibra-complete-technical-handbook",[3915,3916,1078,3917,1126,1118,3918],"Nuxt","Vue","Nuxt Content","静态部署","ZT33YZq1D8x6VIr-hI2qE15LFS3Qlkr_dV3lsgBWpcw",{"id":3921,"title":3922,"body":3923,"category":276,"date":277,"description":4082,"extension":279,"meta":4083,"navigation":18,"path":4084,"publishedAt":3911,"seo":4085,"slug":4086,"stem":4087,"tags":4088,"updated":277,"__hash__":4091},"writing\u002Fwriting\u002F2026-07-26-trading-cognition-and-compound-reality.md","交易是为了赚钱还是验证认知：从量化门槛到复利现实",{"type":87,"value":3924,"toc":4071},[3925,3928,3932,3935,3938,3942,3945,3948,3951,3954,3957,3960,3963,3967,3970,3990,3993,4013,4016,4019,4033,4036,4039,4042,4045,4048,4052,4055,4058,4062,4065,4068],[90,3926,3927],{},"刷到一个清华博士的视频，说想赚钱就去量化。但普通人的门槛是不是太高？就算跨过去了，市场容量真的够赚到钱吗？带着这些问题和 AI 聊了一圈，从量化门槛一路聊到\"你到底为什么做交易\"，把思路理了一遍。",[94,3929,3931],{"id":3930},"机构量化-vs-系统化交易","机构量化 vs 系统化交易",[90,3933,3934],{},"机构量化（幻方、九坤级别）的门槛确实很高：博士学历、海量 tick 数据、专用算力、上亿起步资金，而且赛道内卷、alpha 衰减快、容量有限。",[90,3936,3937],{},"但普通人能做的是\"系统化交易\"而非机构量化。20 日均线 + 严格止损 + 行业 ETF，这套逻辑本质就是量化思维。真正的问题不是门槛，是把博士生的参照系错误地套用在自己身上。这类建议对清北学生可操作，对大多数人是废话，因为它省略了关键前提：清北学生的起点已经过滤掉 90% 的竞争。",[94,3939,3941],{"id":3940},"只是为了赚钱可能是对自己的贬低","\"只是为了赚钱\"可能是对自己的贬低",[90,3943,3944],{},"我说做交易只是为了赚钱。但仔细想想，我对系统和机制本身一直有探究欲--止损逻辑、Hyperliquid 架构、自己项目的技术选型会追求优雅和性能。真正纯粹为钱的人不会纠结止损后策略逻辑对不对。",[90,3946,3947],{},"如果账户明天清零，还会不会继续研究这套系统？会的。因为做交易挣不挣钱是对我认知是否正确的检验，猜对了奖励，猜错了亏钱。我在市场里的目的是验证认知，想知道自己是怎样的人。",[90,3949,3950],{},"核心驱动不是钱，是\"认知闭环\"--市场是不会说谎的裁判，钱只是计分板。",[94,3952,3953],{"id":3953},"一个需要警惕的特质",[90,3955,3956],{},"对\"是否正确\"极度敏感的人，容易把坚持系统等同于坚持自我，把止损等同于承认\"我是错的\"。如果哪天开始扛单不是因为信号而是无法接受\"我看错了\"，这个特质就从优势变成风险。",[90,3958,3959],{},"关键区分：把\"验证认知\"和\"验证自我价值\"分开。市场说这笔交易错了，不等于整个判断体系错了。我相信市场大部分时间是对的，应该是我往市场靠去检验自己，而不是市场错的时候坚持自己。但空仓时说这话容易，真正重仓浮亏 5%、系统说止损但脑子里说\"只是短期波动\"的那一刻，这套认知还在不在才是真考验。",[90,3961,3962],{},"止损系统的价值不只是风控，更是强制执行那些理性认同但情绪会动摇的信念。",[94,3964,3966],{"id":3965},"_10-万到几百万数学可行执行淘汰大多数人","10 万到几百万：数学可行，执行淘汰大多数人",[90,3968,3969],{},"市场容量直接排除--A 股日均成交额 8000 亿到 1.2 万亿，几十万到几百万对市场影响约等于零。真实难度分三段：",[117,3971,3972,3978,3984],{},[120,3973,3974,3977],{},[112,3975,3976],{},"10 万到 100 万","：拼策略稳定性和纪律一致性",[120,3979,3980,3983],{},[112,3981,3982],{},"100 万到 500 万","：拼复利需要时间，以及账户变大后心态是否变化（100 万亏 10% 是 10 万，感受和 10 万亏 10% 完全不同）",[120,3985,3986,3989],{},[112,3987,3988],{},"500 万以上","：拼市场风格切换时系统能否不变形",[90,3991,3992],{},"参照现有系统严格执行，年化 15%-30% 的历史区间成立。三种情景的复利推算：",[117,3994,3995,4001,4007],{},[120,3996,3997,4000],{},[112,3998,3999],{},"保守 15%","：10 万到 100 万约 17 年，到 500 万约 39 年",[120,4002,4003,4006],{},[112,4004,4005],{},"中性 20%","：10 万到 100 万约 13 年，到 500 万约 21 年",[120,4008,4009,4012],{},[112,4010,4011],{},"乐观 25%","：10 万到 100 万约 11 年，到 500 万约 15 年",[90,4014,4015],{},"数学上可行，但\"10 年严格执行\"淘汰的人比策略本身多。年化均值背后有巨大的方差，最大风险不是策略本身，而是震荡市连续止损后大多数人会改变规则。",[94,4017,4018],{"id":4018},"人群中能走到哪",[117,4020,4021,4024,4027,4030],{},[120,4022,4023],{},"能长期跑赢通胀：前 20%",[120,4025,4026],{},"年化 15%+ 持续 5 年以上：前 5%",[120,4028,4029],{},"系统化策略 10 年不变形：前 2-3%",[120,4031,4032],{},"10 万做到 500 万：前 1-2%",[90,4034,4035],{},"这个门槛不是天才门槛，而是纪律和时间门槛。输给认知的少，输给自己的多。",[94,4037,4038],{"id":4038},"交易不是生活的全部",[90,4040,4041],{},"正常认真上班拿现金流，有足球羽毛球爱好，偶尔玩游戏，继续交易探索市场和世界。每个部分各司其职：工作管现金流，运动游戏管切换放松，交易是认知战场。",[90,4043,4044],{},"这个心态本身是优势。很多人把交易当生活全部，盯盘过度、情绪放大、决策变差。有工作提供现金流、有运动游戏切换状态，交易在这个结构里心理压力更小，压力小反而更容易执行系统。",[90,4046,4047],{},"但有一个前提：执行密度。想清楚和做到之间有 gap，关键不是今天想通了，而是明天还在做。",[94,4049,4051],{"id":4050},"一个佩服的-up-主","一个佩服的 UP 主",[90,4053,4054],{},"关注过一个 UP 主，清华毕业三十多岁，提过资产千万级。他的操作和认知确实让人佩服：航运信息差套利抓住了真正的机会，暴跌那天开中证 500 期权多单判断准确，科技股暴跌后判断主线仍是科技股也对。盘中分享的想法很准，6 月 8 号中证 500 那波多单是实打实的。他还分享打新可转债信息、股东福利等内容，后来发现可转债确实是一个很好的盈利来源。",[90,4056,4057],{},"他的宏观判断和产业理解思路值得学，具体操作和套利思路也有参考价值。没有实盘记录这点确实无法验证，但判断质量摆在那里，佩服是真诚的。",[94,4059,4061],{"id":4060},"a-股打新现状","A 股打新现状",[90,4063,4064],{},"查了一下 A 股打新的数据：2024 年新股首日平均涨幅 253%，单签平均收益约 2 万元；2025 年至 6 月，45 只新股无一破发。但主板网上中签率仅 0.03% 左右，参与人数超 1100 万户，普通人中签概率极低，更像是彩票。网下机构打新年化约 4.5%，但门槛是亿级资金账户。",[94,4066,4067],{"id":4067},"止损永远是最重要的",[90,4069,4070],{},"20 日均线太死板，套到很多个股上买点太高了。但不管用什么方式入场，止损永远是第一位的。买点可以慢慢校准，进场理由可以有很多种，但止损必须进场前定好，而且不能因为浮亏就移动它。止损一旦守不住，什么策略都白搭。",{"title":266,"searchDepth":267,"depth":267,"links":4072},[4073,4074,4075,4076,4077,4078,4079,4080,4081],{"id":3930,"depth":267,"text":3931},{"id":3940,"depth":267,"text":3941},{"id":3953,"depth":267,"text":3953},{"id":3965,"depth":267,"text":3966},{"id":4018,"depth":267,"text":4018},{"id":4038,"depth":267,"text":4038},{"id":4050,"depth":267,"text":4051},{"id":4060,"depth":267,"text":4061},{"id":4067,"depth":267,"text":4067},"从清华博士的量化建议出发，梳理普通人做系统化交易的现实路径、人群比例和自我认知驱动。",{},"\u002Fwriting\u002F2026-07-26-trading-cognition-and-compound-reality",{"title":3922,"description":4082},"trading-cognition-and-compound-reality","writing\u002F2026-07-26-trading-cognition-and-compound-reality",[276,947,394,4089,4090],"复利","系统化交易","f82123ri2o8FqCPfH3G_9GEp8qqGeTztyTnd_1TzBhA",{"id":4093,"title":4094,"body":4095,"category":3907,"date":277,"description":4260,"extension":279,"meta":4261,"navigation":18,"path":4262,"publishedAt":4263,"seo":4264,"slug":293,"stem":4265,"tags":4266,"updated":293,"__hash__":4270},"writing\u002Fwriting\u002F2026-07-26-why-vector-database.md","向量库到底有什么用",{"type":87,"value":4096,"toc":4253},[4097,4101,4104,4115,4118,4132,4136,4139,4153,4156,4160,4163,4166,4186,4193,4196,4199,4202,4220,4223,4226,4250],[94,4098,4100],{"id":4099},"sql-存个相同列-join-一下不就行了","SQL 存个相同列 join 一下不就行了？",[90,4102,4103],{},"这是我最初的问题。看起来很合理：embedding 不就是一串数字吗，存个字段，SQL join 一下就完事了。",[90,4105,4106,4107,4110,4111,4114],{},"但 SQL 擅长的是 ",[55,4108,4109],{},"WHERE A = B"," 这种精确匹配。Embedding 是高维浮点数组，代表语义特征。两句话语义相似，它们的向量数值却绝不相等。",[55,4112,4113],{},"WHERE Va = Vb"," 直接返回空。",[90,4116,4117],{},"所以向量库真正在做的事情有两层：",[1184,4119,4120,4126],{},[120,4121,4122,4125],{},[112,4123,4124],{},"数学计算","：用余弦相似度等算法算高维空间的\"距离\"，而不是判等。",[120,4127,4128,4131],{},[112,4129,4130],{},"专属索引（ANN 算法）","：传统 B-Tree 索引对高维数据失效，会退化成全表扫描。向量库用 HNSW 之类的索引在高维空间建\"地图\"，做到毫秒级近似最近邻检索。",[94,4133,4135],{"id":4134},"那-rag-到底是怎么跑的","那 RAG 到底是怎么跑的",[90,4137,4138],{},"搞清楚向量库的作用之后，整个 RAG 链路就顺了：",[1184,4140,4141,4144,4147,4150],{},[120,4142,4143],{},"用户提问 -> 经过 Embedding 模型 -> 转成向量",[120,4145,4146],{},"拿向量去向量库里找最近的文档片段",[120,4148,4149],{},"找到的相关资料 + 用户原问题一起拼成 Prompt 发给大模型",[120,4151,4152],{},"大模型结合资料回答，减少幻觉",[90,4154,4155],{},"核心就是：输入给大模型之前，先用向量检索把相关上下文捞回来，拼在一起再喂进去。",[94,4157,4159],{"id":4158},"全量召回还是选几条","全量召回还是选几条？",[90,4161,4162],{},"这是第二个直觉问题：如果数据库里相关的东西很多，比如 50 页文本都沾边，全部塞进大模型？还是挑几条最相关的？",[90,4164,4165],{},"答案是必须精选截断。原因有三个：",[117,4167,4168,4174,4180],{},[120,4169,4170,4173],{},[112,4171,4172],{},"上下文窗口有限","：大模型的 Context Window 有上限，塞不下就是塞不下。",[120,4175,4176,4179],{},[112,4177,4178],{},"中间迷失","：上下文太长时，大模型容易忽略中间的内容。",[120,4181,4182,4185],{},[112,4183,4184],{},"Token 费用","：输入越长越贵。",[90,4187,4188,4189,4192],{},"所以标准做法是设置 ",[55,4190,4191],{},"top_k","（比如 limit=5），只取相似度最高的前 N 个片段。入库之前也先把长文本切成小块（比如每段 500 字），精准匹配局部内容，避免带入无关段落。",[94,4194,4195],{"id":4195},"但我的数据量没那么大",[90,4197,4198],{},"说到这里我反应过来了--我的复盘日志根本没多少数据。几万字而已，全塞进去不就完了？",[90,4200,4201],{},"确实可以。小数据量下\"全上下文注入\"更简单有效：",[117,4203,4204,4210],{},[120,4205,4206,4209],{},[112,4207,4208],{},"逻辑完整","：保留完整的时间线和因果链，不会因为切片断章取义。",[120,4211,4212,4215,4216,4219],{},[112,4213,4214],{},"架构极简","：直接 SQL ",[55,4217,4218],{},"SELECT *","，全部喂给大模型，不需要向量索引和切片逻辑。",[94,4221,4222],{"id":4222},"那向量库还有没有意义",[90,4224,4225],{},"有。即便是小数据量，向量库（或 SQL 的向量插件）仍然有几个不可替代的能力：",[117,4227,4228,4238,4244],{},[120,4229,4230,4233,4234,4237],{},[112,4231,4232],{},"模糊语义匹配","：日志里写的是\"肝到两点\"或\"披星戴月\"，向量检索能匹配到\"加班\"的语义。传统 SQL ",[55,4235,4236],{},"LIKE"," 搜不到这种。",[120,4239,4240,4243],{},[112,4241,4242],{},"扩展性","：日志会越积越多，一两年后可能就塞不进上下文窗口了。向量检索的成本随数据量亚线性增长，全量注入则是线性上升。",[120,4245,4246,4249],{},[112,4247,4248],{},"聚类与挖掘","：基于向量距离可以做无标签的主题归类和情绪分析，这是全量注入给大模型做不到的。",[90,4251,4252],{},"所以比较务实的方案是：短周期（比如近一周）的分析直接 SQL 全量提取，喂给大模型；跨年度的特定问题搜索走向量匹配。两条路各管各的，不冲突。",{"title":266,"searchDepth":267,"depth":267,"links":4254},[4255,4256,4257,4258,4259],{"id":4099,"depth":267,"text":4100},{"id":4134,"depth":267,"text":4135},{"id":4158,"depth":267,"text":4159},{"id":4195,"depth":267,"text":4195},{"id":4222,"depth":267,"text":4222},"从\"SQL 加个列不就行了\"到理解向量检索和 RAG 的完整链路，以及小数据量场景下到底该怎么选。",{},"\u002Fwriting\u002F2026-07-26-why-vector-database","2026-07-26T00:09:14+08:00",{"title":4094,"description":4260},"writing\u002F2026-07-26-why-vector-database",[4267,4268,4269],"向量数据库","Embedding","RAG","9q4Dlkg3MPwjAbd68zr9nVdA_E9SlT8u4gPpEGXZKqQ",{"id":4272,"title":4273,"body":4274,"category":833,"date":4402,"description":4403,"extension":279,"meta":4404,"navigation":18,"path":4405,"publishedAt":4406,"seo":4407,"slug":293,"stem":4408,"tags":4409,"updated":4411,"__hash__":4412},"writing\u002Fwriting\u002F2026-07-24-quilibra-tech-stack-and-design-direction.md","这个网站是怎样在 Codex 中一步步构建出来的",{"type":87,"value":4275,"toc":4392},[4276,4280,4283,4286,4289,4292,4296,4299,4302,4306,4309,4312,4315,4318,4321,4325,4328,4331,4334,4337,4340,4343,4346,4349,4353,4356,4359,4362,4365,4368,4371,4374,4377,4380,4383,4386,4389],[94,4277,4279],{"id":4278},"买了域名然后呢","买了域名，然后呢",[90,4281,4282],{},"7 月 21 日，域名到手，备案在走。我想给自己弄个网站，需求听着特别朴素：浅色、好看、能写东西、能给自建服务挂个入口。就这样。",[90,4284,4285],{},"参考了 xiaommx.cn，觉得人家做得挺炫，但冷静想了想--不要小游戏，不要数据库，不要后端，不要那些听着就维护不动的东西。网站只需要四样：介绍自己、写文章、服务入口、关于。这个判断很省事，后面所有技术选型都是被它倒推的。Nuxt 4、Nuxt Content、原生 CSS，没有 Hono，没有 SQLite，不用纠结。",[90,4287,4288],{},"\"算了，全权交给你负责了！Kimi 用的人太多了，整个网页全部交给你了！\"",[90,4290,4291],{},"于是 Codex 上场。接下来三天，8 个会话，大约 230 条输入。这个网站就是这么搞出来的。",[94,4293,4295],{"id":4294},"第一版什么都有但就是没意思","第一版：什么都有，但就是没意思",[90,4297,4298],{},"浅绿色、大图 Hero、导航栏、文章列表、服务区、关于页。功能该有的全有，看着也像模像样。但怎么说呢--就像一个精心装修过的样板房，你能看出花了心思，但说不出这是谁的家。",[90,4300,4301],{},"然后改文案。原来的介绍写得跟产品着陆页似的，特别正经。\"把那些尴尬的文案改了好不好。\"删掉那些抽象表述，换上\"这是我自己部署的个人主页\"和\"正在上班当牛马\"。这一步让我明白一件事：网站的性格不靠功能堆出来的，靠语气。",[94,4303,4305],{"id":4304},"复刻-raunome从真香到翻车","复刻 rauno.me：从真香到翻车",[90,4307,4308],{},"\"你详细调研一下 rauno.me，我想完全复刻这个网站做我的主页。\"",[90,4310,4311],{},"rauno.me 那种横向画框的玩法确实好看。旧首页二话不说推翻，改成五张横向全屏画框：自我介绍、文章、服务、联系方式、宣言。顶部还加了刻度和滑动指示器，像那么回事。",[90,4313,4314],{},"然后就开始跟滑动手感死磕。太慢、惯性不够、触控板方向反的、自动吸附老打断节奏。最后让滚轮和触控板只管注入速度，动画循环自己算惯性，去掉自动吸附，第一张画框加个弹簧聚焦。Playwright 测试也是这时候开始写的--手动搓滑动根本测不出问题。",[90,4316,4317],{},"复刻到一比一了，新鲜劲也过了。\"现在网站基本是一比一复刻，我想做出差异化。要不改成竖着的？横着的太明显了。\"道理很简单：可以学人家的视觉语言，但不能变成中文版 rauno.me。于是横改竖，每幕换个进入动画，去掉编号。",[90,4319,4320],{},"改完一看--好家伙，这不就是个 PPT 吗。",[94,4322,4324],{"id":4323},"不做-ppt-了做工作台","不做 PPT 了，做工作台",[90,4326,4327],{},"\"要不只保留第一张，把其他内容集成在第一个页面，参考 2023.rauno.me，保留一些好玩的互动。\"",[90,4329,4330],{},"这是整个项目拐弯最大的一次。不做滚动，不做转场，不做一幕一幕的切换。让所有东西同时出现在一个屏幕里：介绍、最近文章、服务、时间、坐标、调色器、栏目入口，全塞进去。然后砍掉第二幕，服务摆成无边框 2×2 矩阵，底部入口只留三个。首页钉死在视口里，没有导航栏，不产生原生滚动。",[90,4332,4333],{},"从\"复刻一个网站\"到\"设计一个工作台\"，就这么转过来的。",[94,4335,4336],{"id":4336},"右下角这块空地怎么办",[90,4338,4339],{},"工作台成型了，右下角一直空着。试了一圈：互动坐标场、大型指针圆圈、可拖动组件、涂鸦板。指针圆圈太大，喧宾夺主；拖动组件没啥用；涂鸦板跟网站气质完全不搭。最后只留了顶部一个克制的坐标读数。",[90,4341,4342],{},"\"我想把它做成斜纹的、可拖动调色的条带，用红绿蓝三基色混合，最后出来的颜色是混合的。\"",[90,4344,4345],{},"三条斜纹轨道放进去，拖红绿蓝三个通道调色，配黄橙蓝三个预设。但让它真正变成网站灵魂的决定是：这个颜色不只管按钮，而是接管整个页面--背景、网格、文字对比色、悬浮反馈、文本选中状态全跟着变。后来又顺手把浏览器标签页的 theme-color 和 favicon 也同步了，favicon 做成几何化的 Q，刷新还能恢复上次选的颜色。",[90,4347,4348],{},"本来只是想填个空，结果填出来一个控制中枢。",[94,4350,4352],{"id":4351},"首页热闹内页安静","首页热闹，内页安静",[90,4354,4355],{},"\"点进文章界面之后，不要再出现其他地方的入口，只专注于展示文章。\"",[90,4357,4358],{},"分工很明确：首页负责有意思，内页负责能读进去。文章、服务、关于三个内页不要公共导航、不要页脚，只留左上角一个返回入口。文章页有分类、搜索、前后篇导航。其他内页黑白排版，安安静静的。",[90,4360,4361],{},"大结构定了，剩下的全是鸡毛蒜皮的微调。\"最近写下的宽度稍微窄一点。\"\"SYSTEMS 再左移一点点。\"\"手机端网格线不能覆盖整个页面。\"\"返回按钮字体颜色淡一点，加上符号标识。\"\"状态小点再浅一点，深的看不清。\"每条单独看都不值一提，但加在一起就是\"差点意思\"和\"对了\"之间的区别。字号、间距、颜色、断点，全靠浏览器截图反复比对。最后紧凑桌面、超宽屏、手机都能正常显示，不会因为某个标题长了一点就整个错位。",[94,4363,4364],{"id":4364},"连发文章都想重新发明一遍",[90,4366,4367],{},"\"这都 2026 年了，谁还手写文章。我把和其他 AI 的对话链接分享给 agent，然后它自动按照模板整理好文章并分类发布。\"",[90,4369,4370],{},"文章不临时编，来源就是真实对话。分类定了随笔、学习、交易、观察四类。发布前跑一整套：内容验证、类型检查、单元测试、静态生成、Playwright 测试。",[90,4372,4373],{},"发文章还撞上一个离谱的问题：构建静态站点居然要占 3000 端口，也就是说每次发文章都得把线上服务停了。\"为什么发布文章还要占用 3000 端口？为什么要停止开机服务才能自动发布？\"改完之后，生产服务读版本化 release 的 current 链接，构建完原子切换目录，3000 端口根本不用动。开发预览走 3100，测试走 3101。构建失败也影响不到线上。",[90,4375,4376],{},"内容管理也顺手迁了：个人资料和文案放 YAML，文章还是 Markdown，加了 Sveltia CMS 做可视化管理，Git 当唯一真实来源。",[94,4378,4379],{"id":4379},"越做越少",[90,4381,4382],{},"\"能不能简单点？这么多策略配置，我觉得只需要维护一个 skill。\"",[90,4384,4385],{},"OpenClaw 工作区里重复的角色说明和工具配置全删了，文章整理和发布逻辑收进一个 personal-site-publisher skill。到最后整个系统就四样东西：一个静态站点、一套内容规则、一个发布 skill、一条原子部署流程。",[90,4387,4388],{},"回头看，这个网站不是哪个版本的直接产物。传统首页做过，横向画框做过，纵向幻灯片做过，第二幕做过，自动吸附做过，指针圆圈做过，涂鸦板做过--然后全删了。留下来的东西有个共同点：反复用着觉得对。单屏工作台、服务矩阵、RGB 全局调色、安静的阅读页、对话驱动的内容发布，每一个都是推翻好几轮之后才定下来的。",[90,4390,4391],{},"文章和服务越来越多之后，单屏首页还能不能撑住，得接着看。远程管理和自动部署等接了正式私有仓库再验证。",{"title":266,"searchDepth":267,"depth":267,"links":4393},[4394,4395,4396,4397,4398,4399,4400,4401],{"id":4278,"depth":267,"text":4279},{"id":4294,"depth":267,"text":4295},{"id":4304,"depth":267,"text":4305},{"id":4323,"depth":267,"text":4324},{"id":4336,"depth":267,"text":4336},{"id":4351,"depth":267,"text":4352},{"id":4364,"depth":267,"text":4364},{"id":4379,"depth":267,"text":4379},"2026-07-24","三天，230 条输入，四版被推翻的首页，最终留下一个单屏工作台和一堆被删掉的代码。",{},"\u002Fwriting\u002F2026-07-24-quilibra-tech-stack-and-design-direction","2026-07-24T19:32:20+08:00",{"title":4273,"description":4403},"writing\u002F2026-07-24-quilibra-tech-stack-and-design-direction",[3915,3917,1126,1118,4410],"OpenClaw","2026-07-25","1xyfQ8pi9KvnsWB_BeENERo0y41vQZMY9KrT8sdbj_E",1785121515003]