Skip to content

對局平衡重做 + 敵方 agent 移到 0G Compute,做出「整場都是同一位 agent」的證明 - #16

Merged
k66inthesky merged 2 commits into
mainfrom
claude/0g-tech-competition-deploy-lv08or
Sep 10, 2026
Merged

k66inthesky merged 2 commits into
mainfrom
claude/0g-tech-competition-deploy-lv08or

Conversation

@k66inthesky

Copy link
Copy Markdown
Contributor

兩件事,第二件是第一件查下去之後發現的連鎖問題。


一、對局平衡:玩家原本是「必輸」

用搜尋器把這局玩到底之後發現:對上會下棋的對手,玩家勝率是 0%。 不是操作問題,是兩個結構問題。

1. 火力性價比不對稱。 壓制傷害只看攻擊力總和,所以真正的貨幣是「每點算力換到多少攻擊力」:憶哨兵 1 費 2 攻,遺忘者的雜訊 1 費 3 攻。同樣的算力,它每條迴廊都比你高一截。

2. AI 是後手,而且看得到你這回合的部署。 原本是玩家部署完才把盤面送去問 agent —— 它拿到你的答案卷才作答。在「逐條迴廊比火力」的規則下後手幾乎必勝。

而原本的壓制是贏者全拿(多 1 點攻擊力就拿滿 2 點),使平衡變成離散跳躍:把哨兵調到 3 攻,結果直接從「必輸」跳成 100% 和局(雙方火力永遠打平,誰都不受傷)。

三件事必須一起改

改動 作用
壓制傷害 → min(2, ⌈差/2⌉) 讓平衡從離散變連續,數值才調得動。上限仍是 2 點,沒有任何迴廊變得更危險
憶哨兵 2 → 3 攻 補上算術劣勢
改成同時出牌 回合一開始就用「玩家部署前」的快照問 agent,按結束回合才 await

實測(每組 300 場,雙方都挑最好的一手、各 25% 失誤)

設定 勝 / 敗 / 和 核心差
原本 6% / 84% / 10% −7.4
只改同時出牌 8% / 86% / 6% −7.8
只改傷害公式 3% / 85% / 12% −8.3
傷害公式 + 同時出牌 5% / 89% / 6% −10.1
三個一起改 34% / 40% / 27% −0.7

單獨改任何一項都沒用 —— 遞增傷害不是解方,是讓數值可以被調整的前提。

參數敏感度:min(2,⌈差/2⌉) 43/35/21 ← 採用;min(3,⌈差/2⌉) 39/37/24;min(3,⌈差/1⌉) 33/37/30;min(3,⌈差/3⌉) 17/61/22。失誤率 10%→40% 勝率穩在 28–38%,不是刀鋒。

雙方都下得更好時(失誤 10%)同時出牌的價值才明顯:勝率 29% → 37%,和局 35% → 28%。

瀏覽器實跑: 笨打法(每回合 1 張哨兵)→ 12:0 慘敗;好打法(零重刃破平手+哨兵佔空迴廊)→ 5 回合勝,3:0 收尾。技術真的會影響結果了。


二、TEE:原本那個說法不成立

我們宣稱用了 TEE,但跟玩家對打的 agent 走 OpenAI,TEE 只掛在戰後旁白那一段,而且沒有驗 attestation。所以「TEE 驗證了對手身分」當時是空話。

要讓它成立,三件事缺一不可:

1. 敵方 agent 預設改跑 0G Compute(AI_PROVIDER 預設 openai → 0g)。

2. 每回合封存證據,串成鏈,封進記憶碎片:

欄位 綁住什麼
boardHash 它看到的盤面
responseHash 供應商回的原始文字 —— 刻意不是解析後的結果,解析後才算等於在證明我們自己的程式
signature / signer / measurement enclave 簽名與公鑰

鏈存進碎片的 teeChain,會被錨定上鏈的 SHA-256 蓋住 —— 第三方拿鏈上摘要就能重驗整場,不是只能相信我們的伺服器。

3. 驗證與分級(POST /api/og/same-agent):

等級 意思
attested 全簽 + 同一把公鑰 + 對得上 attestation 的 measurement(enclave 等級)
signed 全簽 + 同一把公鑰,但沒拿到 attestation
changed 有簽名但公鑰中途換過 —— 否定結果,正是「agent 被換掉」的樣子
consistent 沒有(或只有部分)簽名,只有供應商與模型一致 —— 我們伺服器的紀錄而已
none 沒有紀錄,或供應商/模型本身就換過

刻意不回傳單純的 true/false。 把「只是紀錄一致」講成「已驗證」是這個功能最容易犯、也最不該犯的錯 —— 那比沒有這個功能更糟。

前端

結果畫面新增「TEE 驗證 · 是同一位 agent 嗎」按鈕與面板:徽章按等級變色,逐回合一格燈(同一把公鑰=藍、換過=橘、沒簽名=空心),下面攤開簽名覆蓋率、模型、供應商、公鑰、measurement。只有 attested 拿得到藍燈。

瀏覽器實跑三條路徑:

沒有金鑰      → none      「沒有任何回合的紀錄」
七回合同一把  → attested   ok ok ok ok ok ok ok
第 5 回合換掉 → changed    ok ok ok ok changed ok ok

修掉一個訊息 bug:公鑰中途換過時原本落到 consistent,訊息寫「供應商沒有回傳可驗證的簽名(2/2 回合有簽名)」—— 自相矛盾,而且把最該警告的狀況講成中性。現在是獨立的 changed 等級。

⚠️ 這個 PR 唯一的不確定處

0G 把簽名與 attestation 放在哪個欄位、標頭叫什麼名字,我沒辦法在建置環境裡實際打一次確認(*.0g.ai 在那裡連不到)。所以抽取器不押寶在單一欄位名上:標頭與 JSON 樹都走訪一遍,看到像簽名/公鑰/measurement 的鍵就收。

抽不到就回報抽不到。 最壞情況是畫面顯示 consistent(未驗證,僅紀錄一致),不會出現假的綠燈。

上線後要確認實際等級,設好 OG_COMPUTE_API_KEY 打一場,然後看 /api/og/same-agent 回的 level。如果是 consistent 但你確定 0G 有簽名,把 /api/agent 回應裡的 evidence 貼給我,我照實際欄位名調整。

🤖 Generated with Claude Code

https://claude.ai/code/session_015NBxaWtzqEX3i8NvoZEeq3


Generated by Claude Code

用搜尋器把這局玩到底之後發現:對上會下棋的對手,玩家勝率是 0%。不是操作問題,
是兩個結構問題。

一、火力性價比不對稱
壓制傷害只看攻擊力總和,所以真正的貨幣是「每點算力換到多少攻擊力」。
憶哨兵 1 費 2 攻,遺忘者的雜訊 1 費 3 攻 —— 同樣的算力,它每條迴廊都比你高一截。

二、AI 是後手,而且看得到你這回合的部署
原本流程是玩家部署完才把盤面送去問 agent。在「逐條迴廊比火力」的規則下,
後手幾乎必勝:在你投重兵的那條放掉,另外兩條各補一點就淨賺。

而原本的壓制是贏者全拿(多 1 點攻擊力就拿滿 2 點),使得平衡是離散的:
把哨兵調到 3 攻,結果直接從「必輸」跳成 100% 和局(雙方火力永遠打平,誰都不受傷)。
這就是為什麼三件事得一起改 —— 遞增傷害不是解方,是讓數值可以被調整的前提。

改動:
· 壓制傷害 min(2, ceil(火力差 / 2))。上限仍是 2 點,沒有任何一條迴廊變得比以前
  更危險,但小優勢只換到小傷害,要拿滿得壓過 3 攻以上。
· 憶哨兵 2 → 3 攻(血量 3 維持,仍比雜訊的 2 血耐打)。
· 同時出牌:回合一開始就用「玩家部署前」的快照去問 agent,按下結束回合時才 await。
  附帶好處是它的思考時間跟玩家重疊,回合更順。它從舊盤面挑的手若已不合法,
  applyAgentPlays 本來就每一手都 validate,會自動略過 —— 這正是戰爭迷霧該有的樣子。
· agent 的 system prompt 同步更新:新的傷害公式,以及「你看不到對方這回合的部署」。
· 簡報文案與 README 規則同步。

實測(每組 300 場,雙方都挑最好的一手、各 25% 機率失誤):
  原本                6% / 84% / 10%   核心差 -7.4
  只改同時出牌         8% / 86% /  6%   核心差 -7.8
  只改傷害公式         3% / 85% / 12%   核心差 -8.3
  傷害公式 + 同時出牌   5% / 89% /  6%   核心差 -10.1
  三個一起改          34% / 40% / 27%   核心差 -0.7
單獨改任何一項都沒用。

參數敏感度(三個一起改的前提下):
  min(2, ceil(差/2))  勝 43 / 敗 35 / 和 21   ← 採用
  min(3, ceil(差/2))  勝 39 / 敗 37 / 和 24
  min(3, ceil(差/1))  勝 33 / 敗 37 / 和 30
  min(3, ceil(差/3))  勝 17 / 敗 61 / 和 22
失誤率從 10% 到 40%,勝率穩在 28–38%、核心差約 -1,不是踩在刀鋒上。

雙方都下得更好時(失誤率 10%)同時出牌的價值才明顯:勝率 29% → 37%,
和局率 35% → 28%。

npm run sim(隨機出牌)也跟著變健康:勝 30–33% / 敗 46–54%,平均 4.3–4.4 回合
(原本是勝約兩成、敗 59–69%,平均 3.7–3.8)。

已知待改善:和局率 21–27%,雙方越接近最佳解越高。滿 7 回合核心相同時要判誰贏
是設計取捨,還沒動。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NBxaWtzqEX3i8NvoZEeq3
先講原本的問題:我們宣稱用了 TEE,但跟玩家對打的 agent 走 OpenAI,TEE 只掛在
戰後旁白那一段,而且沒有驗 attestation。也就是說「TEE 驗證了對手身分」這個說法
當時完全不成立。

要讓它成立,三件事缺一不可,這個 commit 三件都做了。

一、敵方 agent 預設改跑 0G Compute
AI_PROVIDER 預設從 openai 改成 0g(agent.js 自己那份 providerConfig 與 _shared.js
兩處都要改,這支 Function 原本是自給自足、沒有 import 的)。設成 openai 仍可切回,
但畫面上的驗證會照實降級。

二、每回合封存證據,串成鏈,並封進記憶碎片
functions/api/og/tee.js 新增。每回合存:
  boardHash     它看到的盤面(送出去的原始內容算的雜湊)
  responseHash  供應商回的原始文字算的雜湊 —— 刻意不是解析後的結果,
                解析後才算等於在證明我們自己的程式,沒有意義
  signature / signer / measurement   enclave 簽名與公鑰
鏈存進碎片的 teeChain,所以會被錨定上鏈的 SHA-256 蓋住:第三方拿鏈上摘要就能重驗
整場,而不是只能相信我們的伺服器。

三、驗證與分級
POST /api/og/same-agent 收下證據鏈與 attestation,回報能證明到哪一層:
  attested    全簽 + 同一把公鑰 + 對得上 attestation 的 measurement(enclave 等級)
  signed      全簽 + 同一把公鑰,但沒拿到 attestation
  changed     有簽名但公鑰中途換過 —— 這是否定結果,正是「agent 被換掉」的樣子
  consistent  沒有(或只有部分)簽名,只有供應商與模型一致 —— 我們伺服器的紀錄而已
  none        沒有紀錄,或供應商/模型本身就換過
GET /api/og/attest 取 attestation,端點吃 OG_COMPUTE_ATTESTATION_URL,沒設就照實
回報沒設。

刻意不回傳單純的 true/false。把「只是紀錄一致」講成「已驗證」是這個功能最容易犯、
也最不該犯的錯 —— 那比沒有這個功能更糟。

欄位名為什麼寫得這麼容忍:0G 把簽名與 attestation 放在哪個欄位、標頭叫什麼,
沒辦法在建置環境裡實際打一次確認(*.0g.ai 在那裡連不到)。所以標頭與 JSON 樹都
走訪一遍,看到像簽名/公鑰/measurement 的鍵就收。抽不到就回報抽不到。

前端
結果畫面新增「TEE 驗證 · 是同一位 agent 嗎」按鈕與面板:徽章按等級變色,
逐回合一格燈(同一把公鑰=藍、換過=橘、沒簽名=空心),下面攤開簽名覆蓋率、
模型、供應商、公鑰、measurement。只有 attested 拿得到藍燈。

測試
verifyChain 六種情境全過,包含修掉的一個訊息 bug:公鑰中途換過時原本會落到
consistent,訊息寫「供應商沒有回傳可驗證的簽名(2/2 回合有簽名)」—— 自相矛盾,
而且把最該警告的狀況講成中性。現在是獨立的 changed 等級。
抽取器對「標頭 + 巢狀 body」都撈得到,沒有材料時正確回報空的。
瀏覽器實跑三條路徑:
  沒有金鑰      → none / 「沒有任何回合的紀錄」
  七回合同一把  → attested / 逐回合 ok ok ok ok ok ok ok
  第 5 回合換掉 → changed / ok ok ok ok changed ok ok

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NBxaWtzqEX3i8NvoZEeq3
@k66inthesky
k66inthesky marked this pull request as ready for review September 10, 2026 08:29
Copilot AI lite review requested due to automatic review settings September 10, 2026 08:29
@k66inthesky
k66inthesky merged commit f01d7dc into main Sep 10, 2026
1 check passed
k66inthesky pushed a commit that referenced this pull request Sep 10, 2026
「把 AI_PROVIDER 改成 0g 就能整支切過去」在 #16 之後是反的 —— 0g 已經是預設。
改成說明兩者預設都指向 0G Compute,以及為什麼不能是 OpenAI(對打的 agent 不在
enclave 裡的話,「整場都是同一位」這個主張就不成立)。

行號連結有三個在 #16 之後指到不相干的地方(範圍還在檔案內,所以肉眼看不出來):
  functions/api/og/shard.js#L62-L84   → #L85-L107   (原本落在註解中段)
  functions/api/agent.js#L173-L256    → #L188-L291  (evidence 那段把它往後推)
  public/js/ai.js#L16-L65             → #L16-L68
另外 _shared.js 的供應商工廠拆成兩個連結,分別指 providerConfig 與 ogComputeConfig。

這種漂移一天內發生兩次了,所以加 scripts/check-links.mjs(npm run check:links)。
它不驗「行號是不是原本想指的東西」—— 那需要人判斷 —— 只驗一件機械可查的事:
起始行要是函式或註解區塊的開頭、結束行要是收尾。位移之後這兩個條件幾乎必然被破壞。
現在 15 個連結全過。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NBxaWtzqEX3i8NvoZEeq3

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new “same-agent” verification path can fail in normal use due to oversized attestation payload forwarding and currently contains misleading verification/matching logic that risks incorrect “attested/signed” messaging.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR rebalances core combat fairness by changing suppression (“壓制”) damage scaling and shifting the AI opponent to “simultaneous play” so it can’t see the player’s current-turn deployment. In parallel, it strengthens the “same agent for the whole match” claim by defaulting the enemy agent to 0G Compute, collecting per-turn TEE evidence into the shard, and adding an API + UI flow to verify and display the evidence chain.

Changes:

  • Reworked suppression damage to scale with lane attack difference (min(2, ceil(diff/2))) and buffed “憶哨兵” atk 2→3.
  • Changed turn flow so the enemy agent starts thinking at turn start (pre-player-deploy snapshot) and is awaited only at end-turn.
  • Added TEE evidence extraction/sealing, shard persistence, and a /api/og/same-agent + /api/og/attest verification UX.
File summaries
File Description
README.md Documents new balance rules, simultaneous play, and attestation endpoint usage.
public/js/story.js Updates briefing text to reflect new suppression rule + simultaneous play.
public/js/rules.js Implements new suppression damage function/constants and buffs “憶哨兵” atk.
public/js/main.js Starts AI request at turn start; accumulates teeChain; adds “same agent” verification panel flow.
public/js/ai.js Plumbs evidence from /api/agent into the front-end decision result.
public/index.html Adds UI button and panel for TEE “same agent” verification results.
public/css/style.css Styles the TEE verification badge, per-turn indicators, and metadata panel.
functions/api/og/tee.js New: evidence extraction, per-turn sealing, and chain-level verification logic.
functions/api/og/shard.js Persists teeChain into the shard (hashed + bounded fields).
functions/api/og/same-agent.js New: POST endpoint that normalizes inputs and returns a per-turn + overall verdict.
functions/api/og/attest.js New: fetches provider attestation (configurable endpoint) and extracts key/measurement.
functions/api/og/_shared.js Defaults enemy AI provider to 0G Compute (AI_PROVIDER default 0g).
functions/api/agent.js Switches default provider to 0G; seals per-turn evidence using raw provider response text.
.env.example Updates defaults/docs for AI provider and adds OG_COMPUTE_ATTESTATION_URL.
Review details

Suppressed comments (1)

functions/api/og/tee.js:154

  • verifyChain 的 reason 文案在「有 attestation 但公鑰不匹配」時仍會說「沒取得 attestation」,而且也容易讓人誤解為已驗簽(實作只做欄位一致性比對)。建議把 attested/signed 的說明改成不過度主張,並涵蓋 attestation 不可用或不匹配兩種降級原因。
    level === 'attested'
      ? '每回合都有簽名、同一把 enclave 公鑰,且對得上 attestation 的 measurement'
      : level === 'signed'
        ? `每回合都有簽名且出自同一把公鑰,但沒取得 attestation${noAttest},無法證明那把金鑰長在 enclave 裡`
        : level === 'changed'
  • Files reviewed: 14/14 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread functions/api/og/tee.js
Comment on lines +136 to +140
const attestedKey = attestation && (attestation.publicKey || attestation.signer) || null;
const keyMatches =
Boolean(attestedKey) && sameSigner && [...signers][0]
? String([...signers][0]).toLowerCase().includes(String(attestedKey).toLowerCase().slice(0, 16))
: false;
Comment thread public/js/main.js
Comment on lines +909 to +918
// attestation 拿不到不算失敗 —— 它只是決定最高能驗到哪一級
const attestation = await fetch('/api/og/attest', { headers: { accept: 'application/json' } })
.then((r) => (r.ok ? r.json() : null))
.catch(() => null);

const res = await fetch('/api/og/same-agent', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ chain: game.teeChain, attestation }),
});
Comment thread functions/api/og/tee.js
Comment on lines +10 to +13
* 於是「同一位」的證明就是:
* 1. 每回合的回應都有簽名,且
* 2. 所有簽名都能用同一把公鑰驗過,且
* 3. 那把公鑰綁定的 measurement 從頭到尾沒變。
k66inthesky added a commit that referenced this pull request Sep 10, 2026
給評審那張表寫著「把 AI_PROVIDER 改成 0g 就能整支切過去」—— 在 #16 之後這是反的,
0g 已經是預設。改成說明兩者預設都指向 0G Compute,以及為什麼不能是 OpenAI:
對打的 agent 不在 enclave 裡的話,「整場都是同一位」這個主張就不成立。

三個行號連結在 #16 之後指到不相干的地方(範圍還在檔案內,所以肉眼看不出來):
  functions/api/og/shard.js#L62-L84  → #L85-L107   原本落在註解中段
  functions/api/agent.js#L173-L256   → #L188-L291  evidence 那段把它往後推了
  public/js/ai.js#L16-L65            → #L16-L68    函式尾巴被截掉
另外把 _shared.js 的供應商工廠拆成兩個連結,分別指 providerConfig 與 ogComputeConfig。

這種漂移一天內發生兩次了(上一次「賽道二 indexer 唯讀查詢」點下去落在兩個無關的
小工具函式上),所以加 scripts/check-links.mjs(npm run check:links)。

它不驗「行號是不是原本想指的東西」—— 那需要人判斷 —— 只驗一件機械可查的事:
起始行要是函式或註解區塊的開頭、結束行要是收尾。行號位移之後這兩個條件幾乎必然
被破壞,所以抓得到。目前 15 個連結全過。
k66inthesky added a commit that referenced this pull request Sep 10, 2026
三條賽道線上全部實測通過,文件跟上。

README 有一列講反了 —— 最後那列還寫「敵方 AI agent(OpenAI,非 0G)… 對戰時每回合
都要叫一次,需要低延遲,所以另外走 OpenAI」。那正是 #16 / #18 改掉的東西。改成說明
敵方 agent 本體就跑在 enclave 裡,並點明這是 TEE 主張的關鍵前提。

第一列的判準也修正了:原本寫「金鑰在 pc.0g.ai 選 Private(TEE enclave)模式」,
但真正的判準是模型的 verifiability —— TeeML 才代表模型本身在 enclave 裡,
TeeTLS 只有傳輸層。金鑰模式決定不了這件事。

新增三列:同一位 agent 的證據鏈、分級驗證(為什麼刻意不回傳 true/false)、
模型可用性探測(它要解決的就是「有金鑰但模型不存在」那個假綠燈)。

接力圖重畫,把證據鏈那條線畫進去 —— 鏈上那個 SHA-256 不只蓋住戰報敘述,也蓋住
「這七回合是同一位 agent 打的」那份證據,第三方拿摘要就能重驗整場。

端點清單補上 same-agent,示範刻意用「第 2 回合換掉 provider」的鏈,實跑確認會回
level: "changed" —— 不是寫一個沒驗過的範例。

簡報第 5 頁的 0G Compute 卡片從「金鑰為 TEE enclave 模式 / deepseek-chat-v3-0324 /
敵方 agent 另走 OpenAI」改成「0gm-1.0-35b-a3b · TeeML · TDX / 敵方 agent 本體跑在
enclave 裡 / 整場七回合同一個 provider」。0G Storage 那張改成通過,結語補上「刻意不
回傳 true/false」,第 3 頁失效的行號一併更正。五頁重新渲染,都確認沒有溢出。

行號連結從 15 個增加到 19 個,npm run check:links 全過。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants