From 559890c482f5973f06aafdfec9550fee5ba3c7f2 Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 09 十一月 2026 17:02:15 +0800
Subject: [PATCH] feat: CAN 模拟器 TCP 化 + 多设备并发调试 + 后台生命周期管理

---
 docs/System_Architecture_V3_Restructured.html |  578 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 578 insertions(+), 0 deletions(-)

diff --git a/docs/System_Architecture_V3_Restructured.html b/docs/System_Architecture_V3_Restructured.html
new file mode 100644
index 0000000..3242ce4
--- /dev/null
+++ b/docs/System_Architecture_V3_Restructured.html
@@ -0,0 +1,578 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>浠櫒娉ㄥ唽涓庝华鍣ㄨ皟璇� 绯荤粺鏋舵瀯璇存槑 路 V3.0 閲嶆⒊鐞嗙増</title>
+<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
+<style>
+    * { box-sizing: border-box; }
+    body {
+        font-family: -apple-system, "Segoe UI", "Microsoft YaHei", "PingFang SC", sans-serif;
+        max-width: 1240px; margin: 0 auto; padding: 32px 24px 80px;
+        background: #FAFAFA; color: #212121; line-height: 1.75;
+    }
+    h1 { font-size: 29px; color: #1565C0; border-bottom: 3px solid #1976D2; padding-bottom: 12px; }
+    h2 { font-size: 23px; color: #0D47A1; margin-top: 42px; padding-left: 12px; border-left: 4px solid #FF9800; }
+    h3 { font-size: 17px; color: #37474F; margin-top: 26px; }
+    h4 { font-size: 15px; color: #455A64; margin-top: 18px; }
+    .subtitle { color: #757575; font-size: 14px; margin-bottom: 24px; }
+    .card { background: white; border-radius: 8px; padding: 18px 22px; margin: 16px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
+    .highlight { background: #FFF8E1; border-left: 4px solid #FFC107; padding: 12px 16px; margin: 12px 0; border-radius: 4px; }
+    .info { background: #E3F2FD; border-left: 4px solid #2196F3; padding: 12px 16px; margin: 12px 0; border-radius: 4px; }
+    .success { background: #E8F5E9; border-left: 4px solid #4CAF50; padding: 12px 16px; margin: 12px 0; border-radius: 4px; }
+    .warn { background: #FBE9E7; border-left: 4px solid #FF5722; padding: 12px 16px; margin: 12px 0; border-radius: 4px; }
+    table { width: 100%; border-collapse: collapse; margin: 16px 0; background: white; border-radius: 6px; overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,0.06); font-size: 13.5px; }
+    th { background: #1976D2; color: white; padding: 9px 12px; text-align: left; font-weight: 600; }
+    td { padding: 8px 12px; border-bottom: 1px solid #EEEEEE; vertical-align: top; }
+    tr:nth-child(even) td { background: #FAFAFA; }
+    tr:hover td { background: #E3F2FD; }
+    code { font-family: "Consolas", "Monaco", monospace; background: #F5F5F5; color: #C62828; padding: 2px 6px; border-radius: 3px; font-size: 13px; }
+    pre { background: #263238; color: #ECEFF1; padding: 16px 20px; border-radius: 6px; overflow-x: auto; font-family: "Consolas", monospace; font-size: 13px; line-height: 1.55; }
+    pre code { background: transparent; color: inherit; padding: 0; font-size: 13px; }
+    .mermaid { background: white; padding: 20px; border-radius: 8px; margin: 20px 0; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,0.06); overflow-x: auto; }
+    ul { padding-left: 22px; } li { margin: 4px 0; }
+    .toc { background: #F5F5F5; padding: 16px 24px; border-radius: 6px; margin: 20px 0; column-count: 2; column-gap: 40px; }
+    .toc a { color: #1976D2; text-decoration: none; display: block; padding: 3px 0; break-inside: avoid; }
+    .toc a:hover { text-decoration: underline; }
+    .kwd { color: #FFCC80; } .str { color: #C5E1A5; } .cmt { color: #546E7A; } .fn { color: #82AAFF; } .num { color: #F78C6C; }
+    .good { color: #2E7D32; font-weight: 600; } .bad { color: #C62828; font-weight: 600; } .mid { color: #EF6C00; font-weight: 600; }
+    footer { margin-top: 60px; padding-top: 20px; border-top: 1px solid #E0E0E0; color: #757575; font-size: 12px; text-align: center; }
+    .path { font-family: Consolas, monospace; font-size: 12.5px; background: #ECEFF1; color: #37474F; padding: 1px 6px; border-radius: 3px; }
+    .iron { display:inline-block; background:#E8EAF6; color:#283593; border-radius:12px; padding:1px 10px; font-size:12px; font-weight:700; margin-right:6px; }
+</style>
+</head>
+<body>
+
+<h1>浠櫒娉ㄥ唽涓庝华鍣ㄨ皟璇� 路 绯荤粺鏋舵瀯璇存槑锛圴3.0 閲嶆⒊鐞嗙増锛�</h1>
+<div class="subtitle">鍩轰簬銆奓ocal + DeviceBroker 娣峰悎鏋舵瀯璇︾粏璁捐璇存槑涔� V3.0銆嬪鐜版湁绯荤粺鐨勪竴娆″畬鏁撮噸鏋勫彊杩� 鈥斺�� 鍚� TestStep 浠櫒浣跨敤瑙勮寖 路 2026-11-03</div>
+
+<div class="toc">
+    <a href="#s1">涓�銆佹�诲畾浣嶏細涓�鍙ヨ瘽璇绘柊鏋舵瀯</a>
+    <a href="#s2">浜屻�佷簲鍩熷垎灞傛ā鍨�</a>
+    <a href="#s3">涓夈�佷华鍣ㄦ敞鍐岋紙DeviceConfig锛夌殑瑙掕壊閲嶅</a>
+    <a href="#s4">鍥涖�佷华鍣ㄨ皟璇曪紙DeviceDebug锛夌殑瑙掕壊閲嶅</a>
+    <a href="#s5">浜斻�佽繘绋嬫嫇鎵戜笌璐d换杈圭晫</a>
+    <a href="#s6">鍏�佹帴鍙e绾︽紨鍖栨槧灏勶紙鐜版湁浠g爜 鈫� V3.0锛�</a>
+    <a href="#s7">涓冦�佷笁鏉℃牳蹇冩暟鎹祦</a>
+    <a href="#s8">鍏�佷繚鎸佷笉鍙樼殑閮ㄥ垎锛堟灦鏋勮繛缁�ц祫浜э級</a>
+    <a href="#s9">涔濄�乀estStep 浠櫒浣跨敤瑙勮寖</a>
+    <a href="#s10">鍗併�佺粨璁�</a>
+</div>
+
+<!-- ======================================================== -->
+<h2 id="s1">涓�銆佹�诲畾浣嶏細涓�鍙ヨ瘽璇绘柊鏋舵瀯</h2>
+
+<div class="highlight">
+<strong>閰嶇疆鍩熺敓浜�"涓嶅彲鍙樼湡鐞�"锛屼徊瑁佸煙瀹堟姢"璋佹湁鏉冪"锛屽涓诲煙鎵ц"璋佹潵鍔ㄦ墜"锛屼笟鍔″煙鍐冲畾"璇ヤ笉璇ュ垽 FAIL"锛屾暟鎹煙淇濊瘉"浜嬪悗鑳借娓�"銆�</strong>
+<br><br>
+浠櫒娉ㄥ唽涓嶅啀鍙槸"澧炲垹鏀规煡琛ㄥ崟"锛岃�屾槸閰嶇疆鍩熺殑<strong>鍙戝竷绠$嚎</strong>锛涗华鍣ㄨ皟璇曚笉鍐嶅彧鏄�"杩炰笂鍙戝懡浠�"锛岃�屾槸浠茶鍩熶腑涓�涓壒娈婄殑鍐欐潈闄愭寔鏈夎�咃紙<strong>Maintenance Lease</strong>锛夈��
+</div>
+
+<div class="card">
+<strong>涓庢棫鏋舵瀯鐨勬牴鏈尯鍒細</strong>鏃ф灦鏋勯噷 DeviceConfig 鈫� <code>data.db</code> 鈫� DeviceDebug 鏄�"涓や釜妯″潡鍏变韩涓�寮犺〃"鐨勯殣寮忓绾︼紱鏂版灦鏋勯噷<strong>娌℃湁浠讳綍妯″潡鐩存帴鎿嶄綔鍒汉鐨勫簱</strong>鈥斺�旀敞鍐屼骇鐗╂槸鍝堝笇閿佸畾鐨勫揩鐓э紝璋冭瘯/鐢熶骇娑堣垂鐨勬案杩滄槸蹇収 + 绉熺害鍙ユ焺锛岀墿鐞� I/O 姘歌繙鍙彂鐢熷湪鍞竴瀹夸富鍐呫��
+</div>
+
+<!-- ======================================================== -->
+<h2 id="s2">浜屻�佷簲鍩熷垎灞傛ā鍨�</h2>
+
+<div class="mermaid">
+graph TB
+    subgraph D1["鈶� 閰嶇疆鍩燂紙璁捐鏃讹級"]
+        CFG["DeviceConfig 娉ㄥ唽椤�<br/>Draft 鈫� Validated 鈫� Published<br/>鈫� Prepared 鈫� Effective 鈫� Retired"]
+        SNAP["config_snapshot锛堜笉鍙彉+SHA256锛�<br/>resource_definition 路 slot_binding<br/>broker_task_template 路 effective_config"]
+        CFG --> SNAP
+    end
+    subgraph D2["鈶� 浠茶鍩燂紙杩愯鏃讹級"]
+        LS["LeaseStore<br/>arb.db锛圠ocal 鍩燂級<br/>broker-bxx.db锛圔roker 鍩燂級"]
+        RS["resource_state锛坓eneration/phase/epoch锛�<br/>parent_permit 路 lease_history"]
+        ARB["LeaseArbiter<br/>浼樺厛绾х煩闃� 路 璁╂浮 路 鎶㈠崰鎷掔粷"]
+        LS --- RS
+    end
+    subgraph D3["鈶� 鎵ц瀹夸富鍩燂紙鐗╃悊 I/O锛�"]
+        WKR["Worker 脳6锛圵01鈥揥06锛�<br/>Local 璁惧鍞竴瀹夸富<br/>杩炴帴瀹堝崼 Mutex 涓撶敤绾跨▼"]
+        BRK["Broker 脳3锛圔01鈥揃03锛�+B00<br/>SessionActor 路 TaskScheduler<br/>Journal/Outbox 路 Watchdog"]
+        DF["DriverFactory 鍒嗗寲<br/>瀹夸富椹卞姩锛堣浇SDK锛� vs BrokerProxy锛堜笉杞絊DK锛�"]
+    end
+    subgraph D4["鈶� 涓氬姟鎵ц鍩�"]
+        TAP["OpenTAP TestPlan / Recipe<br/>120 脳 DUTContext锛堝紓姝ヨ鏃讹級<br/>閫昏緫鑳藉姏缁戝畾锛氱┖浣�+鑳藉姏<br/>涓嶉�� COM / IP / 杩涚▼"]
+        RUNS["RunService<br/>涓柇绐楀彛 路 缁窇/閲嶆祴鍐崇瓥"]
+    end
+    subgraph D5["鈶� 鏁版嵁鍩�"]
+        DB1[("aging_system.db<br/>閰嶇疆+瀹¤绱㈠紩")]
+        DB2[("arb.db / broker-bxx.db<br/>鍚勫畧鍗曞啓鑰�")]
+        DB3[("姣� Run aging_data.db<br/>閲囨牱鍒嗙墖褰掓。")]
+    end
+    SNAP -->|"鍐荤粨 RunSnapshot<br/>浜斿厓 Hash 瀵硅处"| TAP
+    TAP -->|"AcquireGroup"| ARB
+    ARB --> RS
+    TAP -->|"DeviceOperation<br/>Grants+IdemKey"| WKR & BRK
+    WKR & BRK --> DB2
+    TAP --> DB3
+    CFG --> DB1
+</div>
+
+<table>
+    <tr><th>鍩�</th><th>瑙e喅浠�涔�</th><th>鏍稿績浜х墿</th><th>涓嶅彉閲�</th></tr>
+    <tr><td>鈶� 閰嶇疆鍩�</td><td>鐗╃悊涓栫晫鐨勬暟瀛楀鐢� + 鐢熸晥浠紡</td><td>涓嶅彲鍙樺揩鐓� + Hash</td><td>INV-04 鍚姩鍚庡喕缁� Recipe/Config/Driver/DBC/UDS/鏄犲皠 Hash</td></tr>
+    <tr><td>鈶� 浠茶鍩�</td><td>璋佹湁鏉冨湪杩欏彴浠櫒涓婂彂鍛戒护</td><td>LeaseGrant锛堟瘡璧勬簮涓�浠o級</td><td>INV-02 棰勭害鎺堟潈涓庡懡浠や覆琛屽寲鍒嗗眰</td></tr>
+    <tr><td>鈶� 鎵ц瀹夸富鍩�</td><td>鐗╃悊鍙ユ焺鐙崰 + 鍘熷瓙鐗囨</td><td>SessionGate + Task Journal</td><td>INV-01 鍚屼竴 PhysicalSessionKey 鍙湁涓�涓� I/O 瀹夸富</td></tr>
+    <tr><td>鈶� 涓氬姟鎵ц鍩�</td><td>宸ヨ壓缂栨帓涓庡悎鏍煎垽瀹�</td><td>Verdict / DUTContext</td><td>INV-05 鍐欐搷浣滃湪瀹為檯瀹夸富鍏ュ彛鏍¢獙锛屽鎴风浠呮彁绀�</td></tr>
+    <tr><td>鈶� 鏁版嵁鍩�</td><td>浜嬪悗杩芥函涓庡閲忔不鐞�</td><td>鍥涘簱鍒嗙 + Outbox</td><td>INV-06 宸插彂鏈洖璁� Unknown锛岀姝㈠綋鏈墽琛�</td></tr>
+</table>
+
+<!-- ======================================================== -->
+<h2 id="s3">涓夈�佷华鍣ㄦ敞鍐岋紙DeviceConfig锛夌殑瑙掕壊閲嶅</h2>
+
+<h3>3.1 鏂版棫鑱岃矗瀵圭収</h3>
+<table>
+    <tr><th>缁村害</th><th>鏃фā鍨嬶紙鐜扮姸浠g爜锛�</th><th>V3.0 妯″瀷</th></tr>
+    <tr><td>鏈川</td><td>璁惧淇℃伅 CRUD 琛ㄥ崟</td><td><strong>閰嶇疆鍙戝竷绠$嚎</strong>锛圖raft鈫扸alidated鈫扨ublished鈫扨repared鈫扙ffective鈫扲etired锛�</td></tr>
+    <tr><td>瀛樺偍</td><td><code>DeviceDefinition</code> 鍙彉琛岋紝鏀逛簡绔嬪嵆鐢熸晥</td><td><code>config_snapshot</code> <strong>涓嶅彲鍙�</strong>锛�<code>(config_hash, resource_key)</code> 澶嶅悎涓婚敭锛屽洖婊氫篃鏂板缓鐗堟湰璁板綍</td></tr>
+    <tr><td>鐗堟湰绠$悊</td><td><code>SaveDraft/Publish/Apply</code> 鏀圭姸鎬佸垪</td><td>鍙戝竷浜х墿 = JSON 蹇収 + SHA256锛涜繍琛屾椂鍐荤粨 RunSnapshot锛圧ecipe/Driver/DBC/UDS/鏄犲皠 浜斾欢濂楋級</td></tr>
+    <tr><td>璁惧鏍囪瘑</td><td>Endpoint 瀛楃涓茬洿鍐欙紙<code>CAN_BUS_1:0</code>锛�</td><td><strong>EndpointRef</strong>锛堝嚟鎹�/鍦板潃寮曠敤鍒嗙锛�+ <strong>PhysicalIdentity</strong>锛圫N 鐗╃悊韬唤锛岄槻鎹㈡満鍚庤韩浠芥紓绉伙級</td></tr>
+    <tr><td>宸ヤ綅缁戝畾</td><td><code>SlotDeviceMapping</code> 涓�寮犳槧灏勮〃</td><td><code>slot_binding</code>锛堥殢蹇収鐗堟湰鍖栵級+ 120 鏉℃槧灏勭敱鍏紡鐢熸垚鍣ㄤ骇鍑哄苟绂荤嚎鏍¢獙</td></tr>
+    <tr><td>鍐茬獊妫�娴�</td><td><code>DetectConflicts()</code> 璺戜竴娆� SQL 鍒嗙粍</td><td>鍙戝竷闂ㄧ锛氳韩浠藉幓閲嶃�侀┍鍔ㄤ綅鏁般�佽兘鍔涜鐩栥�丄uthority 涓�鑷淬��<strong>鍚屼竴 PhysicalSessionKey 鍙厑璁镐竴涓� I/O 瀹夸富锛圛NV-01锛�</strong>锛屼笉杩囧绂佹鍙戝竷</td></tr>
+</table>
+
+<h3>3.2 璁惧娉ㄥ唽椤甸渶鏂板鐨勫瓧娈碉紙鏀归�犳竻鍗曪級</h3>
+<pre><code>executionMode       Local | Broker            <span class="cmt">// 鎸夌墿鐞嗘嫇鎵戝喅瀹氾紝绂佹杩愯鏃舵贩鐢�</span>
+authorityId         broker-b01 / local-ipc01  <span class="cmt">// 鎵�灞炰徊瑁佸煙</span>
+brokerId            + ownerProcessId          <span class="cmt">// Broker 鍩熷綊灞�</span>
+physicalSessionKey  psu01/main                <span class="cmt">// 鍚屼竴鐗╃悊杩炴帴鏍囪瘑锛圫essionGate 閿級</span>
+physicalIdentity    serial:TBD-PSU01          <span class="cmt">// SN 鐗╃悊韬唤锛汿BD 绂佹杩囧彂甯冮棬绂�</span>
+accessPolicy        Exclusive | ExclusiveChannelWithParentPermit
+                    | TimeShared | SharedRead <span class="cmt">// 鐙崰/鍒嗘椂鐨勭瓥鐣ュ0鏄庝綅缃�</span>
+safeStateProfile    PSU-SAFE-001              <span class="cmt">// 鎭㈠/浜ゆ帴鏃剁殑瀹夊叏鎬佹ā鏉�</span>
+leasePolicy         TTL / Renew / Handover    <span class="cmt">// 鍏ㄥ眬榛樿 + 鍩熺骇瑕嗙洊</span></code></pre>
+
+<h3>3.3 鍙戝竷娴佺▼锛堟浛浠g幇鍦ㄧ殑"搴旂敤"鎸夐挳锛�</h3>
+<div class="mermaid">
+flowchart LR
+    A[缂栬緫鑽夌<br/>Draft] --> B[绂荤嚎鏍¢獙<br/>韬唤鍐茬獊/鑳藉姏瑕嗙洊<br/>闄愬��/椹卞姩渚濊禆]
+    B --> C[Validated]
+    C --> D["缁存姢绐楀彛鎺㈡祴<br/>杩炴帴/閫氶亾瀵诲潃/璇诲洖"]
+    D --> E["Published<br/>涓嶅彲鍙樺揩鐓�+Hash"]
+    E --> F["鍒嗗彂 Prepare<br/>鍚勫涓诲洖鎵у悓 Hash"]
+    F --> G["鍋滄満绐楀彛 Apply<br/>鍋淩un鈫掓挙鍐欐潈鈫掑畨鍏ㄦ柇杩�<br/>鈫掑悇瀹夸富Apply+鑷"]
+    G --> H{鍏ㄩ儴鎴愬姛?}
+    H -->|鏄瘄 I["鏇存柊 Effective 鎸囬拡<br/>Run 鍒涘缓鏃跺鍒跺揩鐓�"]
+    H -->|閮ㄥ垎澶辫触| J["鏁寸粍 ApplyFailed<br/>闃绘 Run 鍚姩<br/>缁熶竴鍥炴棫鐗堟垨鏂扮増"]
+    J -.-> F
+</div>
+
+<div class="info"><strong>鍏抽敭璇箟鍙樺寲锛�</strong>"鐢熸晥"浠庝竴娆� UPDATE 鍙樻垚涓�鍦洪渶瑕�<strong>鎵�鏈夊涓诲洖鎵х‘璁�</strong>鐨勪袱闃舵浠紡銆傛棫绋� <code>ApplyVersion()</code> 閭g鍗曠偣鏀圭姸鎬佺殑閫昏緫涓嶅瀛樺湪锛涙棦鏈� Run 缁х画寮曠敤鏃� Hash锛屼笉鍏佽闈欓粯鍒囩増銆�</div>
+
+<!-- ======================================================== -->
+<h2 id="s4">鍥涖�佷华鍣ㄨ皟璇曪紙DeviceDebug锛夌殑瑙掕壊閲嶅</h2>
+
+<h3>4.1 鏈�閲嶈鐨勬媶鍒嗭細鐩戞帶 鈮� 鍐欐潈闄�</h3>
+<div class="mermaid">
+graph TB
+    OLD["鏃фā鍨嬶細閫夎澶� 鈫� OpenSession(ReadOnly)<br/>鈫� [RequestMaintenance 鈫� Activate] 鈫� 鍙戝懡浠�<br/>鈿狅笍 鐩戞帶鍜屽啓鏉冮檺娣峰湪鍚屼竴涓細璇濈姸鎬佹満閲�"]
+    OLD ==> NEW1["鏂版ā鍨� 路 鐩戞帶閫氳矾锛堝父椹伙紝鏃犵绾︼級<br/>瀹夸富鐘舵�佺紦瀛� / Telemetry Fanout 鈫� DeviceMonitorView<br/>鏁版嵁甯� 鏉ユ簮+璐ㄩ噺+搴忓垪鍙�+鏃堕棿锛汫ap 蹇呴』鏄惧紡鍛堢幇"]
+    OLD ==> NEW2["鏂版ā鍨� 路 鍐欐潈闄愰�氳矾锛堢淮鎶や細璇� = 鐢宠 Maintenance 绉熺害锛�<br/>蹇呴』缁忚繃浠茶鍩燂細鐪嬪崰鐢� 鈫� Draining 鈫� 鎺掔┖ 鈫� 瀹夊叏纭 鈫� Grant"]
+</div>
+
+<h3>4.2 缁存姢浼氳瘽鐘舵�佹満锛堝鐜版湁 DebugSessionState 鐨勬墿灞曪級</h3>
+<div class="mermaid">
+stateDiagram-v2
+    [*] --> ViewOnly: 鎵撳紑璁惧(浠呯洃鎺�)
+    ViewOnly --> Requested: 鐢宠缁存姢(濉悊鐢�)
+    Requested --> Draining: Run鍗忚皟瀹夊叏鏆傚仠璇ョ┖浣�
+    Draining --> MaintenanceActive: 鎺掔┖+瀹夊叏鍔ㄤ綔璇诲洖+鏃у彞鏌勫叧闂璡n+Mutex瀹堝崼绉讳氦+鑱旈攣鎵嬬画纭
+    Draining --> RecoveryRequired: 浜ゆ帴瓒呮椂(30s)
+    RecoveryRequired --> ViewOnly: 鎭㈠鏍稿瀹屾垚\n(涓嶈兘鍥�"绛変簡30绉�"鐩存帴缁欑淮鎶よ�呪�擨NV-03)
+    MaintenanceActive --> Exiting: 閫�鍑虹淮鎶�
+    Exiting --> Released: 璇诲洖澶嶆牳+鎭㈠閫氫俊閰嶇疆+鎶ヨ鍩虹嚎
+    Released --> [*]: RunService鏄惧紡鎭㈠鎴栨柊寤篟un
+</div>
+
+<table>
+    <tr><th>鐜版湁鐘舵��/鏂规硶</th><th>V3.0 鍘诲悜</th></tr>
+    <tr><td>ReadOnly / OpenSession</td><td>鎷嗕负 ViewOnly锛堢洃鎺э級+ Requested锛堝啓鏉冪敵璇凤級涓や釜姒傚康</td></tr>
+    <tr><td>RequestMaintenance锛堝唴瀛� Reserve锛�</td><td>杩涘叆浠茶鍩燂細鏄剧ず鍗犵敤鑰�/Run/DUT/鍓╀綑绉熺害/鐖跺瓙褰卞搷 鈫� Draining</td></tr>
+    <tr><td>ActivateMaintenance</td><td>浠呭湪"鎺掔┖ + 瀹夊叏鍔ㄤ綔璇诲洖 + 鏃у彞鏌�/瀹堝崼纭"鍚庣鍙戠淮鎶� Grant</td></tr>
+    <tr><td>CloseSession锛堥噴鏀惧唴瀛樺瓧鍏革級</td><td>鍗囩骇涓�"鎺掔┖ I/O + 鐗╃悊璇诲洖 + ReleaseAsync"涓夋锛屽け璐ヨ繘 RecoveryRequired 鑰岄潪鍋囪鎴愬姛</td></tr>
+    <tr><td>Faulted / RecoveryRequired</td><td>璇箟淇濈暀锛屼絾杩涘叆璺緞澧炲姞锛氫氦鎺ヨ秴鏃躲�佺画鏈熷け璐ャ�侀噴鏀惧け璐�</td></tr>
+</table>
+
+<h3>4.3 "寮哄埗閲婃斁"鎸夐挳鐨勬纭涔�</h3>
+<div class="warn">
+<strong>鏃х洿瑙夛細</strong>Admin 鐐逛竴涓� 鈫� UPDATE/DELETE 绉熺害琛� 鈫� 璁惧褰掓垜銆�<br>
+<strong>V3.0锛�</strong>Force release <strong>鍙兘瑙﹀彂"闅旂 + 鎭㈠娴佺▼"</strong>鈥斺�斿厛鍦ㄧ墿鐞嗗眰纭鏃� I/O 宸茬粓姝紙鏃ц繘绋嬪彞鏌勫叧闂�丯amed Mutex 鍙幏鍙栥�佽澶囪緭鍑鸿鍥烇級锛屽惁鍒欏畞鍙繚鎸� RecoveryRequired銆傚浜轰綔涓氥�佹嫈绾裤�佹帴绾跨殑璁稿彲<strong>涓嶇敱杞欢 token 鍗曠嫭鍒ゅ畾</strong>锛圛NV-07锛氳蒋浠剁绾︿笉鏇夸唬鏂數涓庣‖浠惰仈閿侊級銆�
+</div>
+
+<h3>4.4 瀹¤鍗囩骇</h3>
+<p><code>debug_operation</code> 淇濈暀锛屾柊澧炰袱鍒楋細<code>lease_generation</code>锛堝摢涓�浠f寔鏈夎�咃級銆�<code>idempotency_key</code>锛堥噸璇曞幓閲嶏紝UNIQUE 閮ㄥ垎绱㈠紩锛夈�備换浣曚竴鏉″巻鍙叉寚浠ゅ彲鍥炵瓟锛�<strong>璋侊紙OwnerId+Principal锛夈�佷互鍝鎺堟潈锛圙rant 蹇収锛夈�佸湪鍝釜閰嶇疆鐗堟湰锛圕onfigHash锛変笅銆佹槸鍚﹀彲鑳借閲嶅鎵ц杩�</strong>銆�</p>
+
+<!-- ======================================================== -->
+<h2 id="s5">浜斻�佽繘绋嬫嫇鎵戜笌璐d换杈圭晫</h2>
+
+<div class="mermaid">
+graph TB
+    HMI["HMI 杩涚▼锛堝伐绋嬪笀/鎿嶄綔鍛橈級<br/>DeviceConfigView 鈶� 路 DeviceDebugView 鈶�<br/>DeviceMonitorView 鈶� (鏂板缓)"]
+    W["Worker 脳6锛圵01鈥揥06锛屾瘡20绌轰綅锛�<br/>Local 璁惧 I/O 瀹夸富锛堣繛鎺ュ畧鍗� Mutex 涓撶敤绾跨▼锛�<br/>DUTExecution 鐘舵�佹満 / 姝ラ寮曟搸锛圤penTAP锛�<br/>鐙珛缁湡浠诲姟锛堜笉鍗燯I锛涘け璐ョ珛鍗抽樆鏂柊鎿嶄綔锛�"]
+    B["Broker 脳3锛圔01鈥揃03锛�+ 鍙�� B00锛堝叏灞�鍏变韩鍩燂級<br/>鍏变韩浼氳瘽璁惧鍞竴 I/O 瀹夸富<br/>SessionActor锛堟瘡鐪熻繛鎺ュ崟闃熷垪锛屼竴娆′竴娈靛師瀛� I/O锛�<br/>Task鎵ц 路 Journal/Outbox鍗曞啓鍣� 路 Recovery妫�鏌ョ偣"]
+    SUP["Supervisor<br/>鍗曞疄渚嬪畧鍗� 路 闄愰鎷夎捣 路 epoch 鎻愬崌"]
+    DEV["鐗╃悊璁惧<br/>宸ヤ綅涓撶敤鐢垫簮(Local) / 澶氶�氶亾PSU路CAN路娓╃路PLC(Broker)"]
+    HMI -->|"閰嶇疆鍙戝竷/缁存姢鐢宠(鐢宠鍙埌浠茶鍩�)"| W & B
+    W -->|"Local鐩磋繛"| DEV
+    B -->|"鍞竴鍙ユ焺"| DEV
+    SUP -.->|鐪嬫姢| W & B
+</div>
+
+<table>
+    <tr><th>杩涚▼</th><th>鑱岃矗</th><th>鏄庣‘涓嶅仛</th></tr>
+    <tr><td>HMI</td><td>閰嶇疆瑙嗗浘銆佺淮鎶ゅ啓鏉冪敵璇枫�佸彧璇荤洃鎺�</td><td>涓嶆寔鏈夌敓浜ц澶囩殑鐗╃悊杩炴帴</td></tr>
+    <tr><td>Worker</td><td>Local 璁惧瀹夸富 + 鏈┖浣嶇粍姝ラ寮曟搸 + 寮傛绛夊緟锛�120 绌轰綅 鈮� 120 绾跨▼锛�</td><td>涓嶅姞杞藉叡浜澶囩殑 SDK</td></tr>
+    <tr><td>Broker</td><td>鍏变韩浼氳瘽璁惧鍞竴 I/O 瀹夸富銆乀ask 鏈夌晫鎵ц銆佸懆鏈熶换鍔°�佽闃呴仴娴�</td><td><strong>涓嶅仛 DUT 鍚堟牸鍒ゅ畾銆佷笉瑁呮暣鏉� Recipe銆佷笉绠� MES 浜嬪姟</strong>锛堜笉鏄浜屽娴嬭瘯寮曟搸锛�</td></tr>
+    <tr><td>Supervisor</td><td>鎷夎捣銆侀檺棰戦槻蹇�熼噸鍚惊鐜�乪poch 绠$悊</td><td>涓嶆墽琛屼笟鍔″懡浠�</td></tr>
+</table>
+
+<div class="highlight"><strong>杈圭晫閾佸緥锛�</strong>
+<ul>
+<li>Recipe/姝ラ寮曟搸<strong>浠庝笉</strong>鐩存帴閫� COM 鍙�/IP/杩涚▼鈥斺�斿彧鍐�"绌轰綅 S024 + 鑳藉姏 Power"锛岀敱 SnapshotResolver + ResourceRouter 鎸夊喕缁撶増鏈В鏋愬嚭璧勬簮闆嗕笌瀹夸富锛�</li>
+<li>璺ㄥ煙澶氳祫婧愮粍鐢宠 = 鍗忚皟寮忛鐣欙紙Prepare鈫扐ctivate锛屼换涓�澶辫触 Abort锛夛紝<strong>涓嶆壙璇鸿法搴撳師瀛�</strong>锛涗弗鏍煎叏鏈夊叏鏃犵殑鍔ㄤ綔蹇呴』钀藉湪鍚屼竴 Broker 鍩熸垨鎵撳寘鎴愪竴涓� Task锛�</li>
+<li>SQLite 涓�寰嬫湰鏈虹鐩橈紝绂佹 SMB/NAS 澶氭満鍏卞啓锛涜繛鎺ユ樉寮� <code>foreign_keys/busy_timeout</code>锛涗簨鍔″唴绂佸仛 I/O銆�</li>
+</ul></div>
+
+<!-- ======================================================== -->
+<h2 id="s6">鍏�佹帴鍙e绾︽紨鍖栨槧灏勶紙鐜版湁浠g爜 鈫� V3.0锛�</h2>
+
+<table>
+    <tr><th>鐜版湁瀹炵幇锛堟湰浠撳簱锛�</th><th>V3.0 鍘诲悜</th><th>鍙樺寲鎬ц川</th></tr>
+    <tr>
+        <td><span class="path">Core/ResourceManager.cs</span>锛堝唴瀛� Reserve/Release/ValidateOwner锛�</td>
+        <td>鏃у崟璧勬簮鏂规硶淇濈暀涓鸿繃娓� Adapter锛涙柊澧� <code>IResourceCoordinator</code>锛圓cquireGroup / RenewGroup / RequestHandover锛�</td>
+        <td class="mid">鍏煎鎵╁睍</td>
+    </tr>
+    <tr>
+        <td><span class="path">Contracts/ResourceOwnerToken.cs</span>锛堝崟涓�鍙彉 Generation锛�</td>
+        <td>涓氬姟鍏冩暟鎹繚鐣欙紱I/O 鏀圭敤<strong>姣忚祫婧愮嫭绔� LeaseGrant</strong>锛圓uthorityId / Epoch / LeaseId / Generation / ExpiresUtcMs锛�</td>
+        <td class="bad">鐮村潖鎬э細涓� owner 澶氳祫婧愪笉鑳藉叡鐢� Generation</td>
+    </tr>
+    <tr>
+        <td><span class="path">Services/AutoDeviceFacade.cs</span> + IAutoDeviceLease锛堝悓姝� Dispose 闃诲閲婃斁锛�</td>
+        <td>闂ㄩ潰璇箟淇濈暀锛汱ease 娉ㄥ叆鐙珛缁湡浠诲姟 + <code>LeaseLost</code> 淇″彿 + <code>HandoverRequested</code>锛汥ispose 鏀规樉寮忓紓姝� Release锛堝け璐ュ彲鏌ヨ銆佽繘鎭㈠锛�</td>
+        <td class="mid">璇箟澧炲己</td>
+    </tr>
+    <tr>
+        <td><span class="path">Services/DeviceService.cs</span>锛坉eviceId+command+token 瑁稿懡浠わ級</td>
+        <td>鍗囩骇涓� <code>IDeviceExecutor</code>锛氱被鍨嬪寲 OpCode + Grants 闆� + IdempotencyKey + Deadline锛況aw command 浠呬繚鐣欏彈鎺х淮鎶ゅ叆鍙�</td>
+        <td class="bad">鐢熶骇璺緞閲嶆瀯</td>
+    </tr>
+    <tr>
+        <td><span class="path">Drivers/DriverFactory.cs</span>锛堥潤鎬� switch锛�</td>
+        <td>鍖哄垎<strong>瀹夸富椹卞姩</strong>锛圠ocal/Broker 鍐呭姞杞� SDK锛変笌 <strong>BrokerProxy</strong>锛堝鎴风锛屼笉鍔犺浇 SDK锛夛紱閰嶅悎 .opentap 鍖呭垎鍙戯紙瑙佸濡圭瘒锛�</td>
+        <td class="mid">鍒嗗彂瑙h��</td>
+    </tr>
+    <tr>
+        <td><span class="path">Plugin.DeviceDebug/Model/DebugSessionManager.cs</span></td>
+        <td>澧� Draining / RecoveryRequired锛涙仮澶嶆椂<strong>涓嶅彲閲嶉�� owner token</strong>锛屽繀椤讳娇鐢ㄦ寔涔呭寲 Grant锛涚洃鎺т笌鍐欐潈闄愬垎绂�</td>
+        <td class="mid">鐘舵�佹墿灞�</td>
+    </tr>
+    <tr>
+        <td><span class="path">Plugin.DeviceConfig/Model/DeviceConfigModel.cs</span>锛圖etectConflicts/SaveDevice锛�</td>
+        <td>鍐茬獊妫�娴嬬Щ鍏ュ彂甯冮棬绂侊紙绂荤嚎鏍¢獙 + 缁存姢绐楀彛鎺㈡祴锛夛紱鍙彉琛ㄥ崌绾т负涓嶅彲鍙樺揩鐓�</td>
+        <td class="mid">浣嶇疆鍓嶇Щ</td>
+    </tr>
+    <tr>
+        <td><span class="path">data.db</span>锛堜竴搴撲笁鐢級+ debug.db</td>
+        <td>鎷嗗洓搴擄細aging_system.db / arb.db / broker-bxx.db / 姣廟un aging_data.db</td>
+        <td class="bad">鏈�澶х殑涓�娆℃�у伐绋嬶細瀛樺偍杈圭晫閲嶇粍</td>
+    </tr>
+    <tr>
+        <td><span class="path">ConnectionUtil/PipeClient.cs</span></td>
+        <td>V3.0 搂13 璁ゅ畾鍏�"鍝嶅簲涓嶅彲杈�"锛圫endMessage 鍐欏悗鐩存帴 return锛岃鍙栦负姝讳唬鐮侊級銆乻erverName 鏈敓鏁堚�斺�斾慨澶嶅悗鏂瑰彲浣滀负 IPC 鍊欓�夊熀纭�</td>
+        <td class="bad">P0 鍓嶇疆淇椤�</td>
+    </tr>
+</table>
+
+<div class="info"><strong>寤鸿锛�</strong>濂戠害锛圛LeaseScope / LeaseGrant / DeviceOperation / IDeviceExecutor / BrokerTaskRequest 绛夛級鎶藉嚭涓虹嫭绔嬬被搴� <span class="path">Aging.ResourceContracts</span>锛岄伩鍏� Broker / Worker / HMI 涓夌浜掑甫 WPF 渚濊禆銆�</div>
+
+<!-- ======================================================== -->
+<h2 id="s7">涓冦�佷笁鏉℃牳蹇冩暟鎹祦</h2>
+
+<h3>7.1 鐢熶骇鍐欏懡浠わ紙浠庢楠ゅ埌鐗╃悊 I/O 鐨勫畬鏁翠竴璺抽摼锛�</h3>
+<div class="mermaid">
+sequenceDiagram
+    autonumber
+    participant STEP as TestStep<br/>(鈶d笟鍔″煙)
+    participant CO as IResourceCoordinator<br/>(鈶′徊瑁佸煙)
+    participant EX as IDeviceExecutor<br/>(鈶㈠涓诲煙)
+    participant SG as SessionGate/Actor<br/>(鈶㈠涓诲煙)
+    participant DRV as 瀹夸富椹卞姩
+    participant DB as 杩愯搴�(Journal/Outbox)
+
+    STEP->>CO: AcquireGroup(璧勬簮闆�, OwnerKind=Production, ConfigHash)
+    CO->>DB: BEGIN IMMEDIATE 浜嬪姟CAS(閫愯祫婧� Free鈫扐ctive, generation+1)<br/>+ parent_permit 妫�鏌� + lease_history
+    DB-->>CO: 鎻愪氦鎴愬姛
+    CO-->>STEP: ILeaseScope锛圙rants + 缁湡浠诲姟 + LeaseLost锛�
+    STEP->>EX: DeviceOperation(OpCode, Params, IdemKey, Grants, Deadline)
+    EX->>EX: 鍏ラ槦鏍¢獙: grant闆�/epoch/ConfigHash/deadline/杩炴帴韬唤
+    EX->>SG: 鍑洪槦鎸侀棬: [閫夐�氶亾鈫掑啓鈫掕鍝嶅簲] 鍘熷瓙鐗囨
+    SG->>DB: MarkRunning 鍏堟寔涔呭寲锛圛/O 涔嬪墠锛�
+    SG->>DRV: 鐗╃悊鎵ц
+    DRV-->>SG: 璇诲洖鍊�
+    SG->>DB: 鍚屼簨鍔℃彁浜� Task缁堟��+浜嬩欢+Outbox
+    SG-->>STEP: OperationResult(Readback, Quality)
+    Note over STEP: 鍒ゅ畾 PASS/FAIL 鍦ㄦ楠�/寮曟搸锛圛NV-05/T-3锛�
+    STEP->>CO: ReleaseAsync锛堟帓绌衡啋璇诲洖/浜ゆ帴鈫掗噴鏀撅級
+</div>
+
+<h3>7.2 缁存姢浜ゆ帴锛堟憳瑕侊紝瀵瑰簲鏂囨。 14.2 鍏锛�</h3>
+<div class="card">
+鍗犵敤鍙鍖栵紙Run/DUT/鍓╀綑绉熺害/鐖跺瓙褰卞搷锛夆啋 Run 鍗忚皟瀹夊叏鏆傚仠锛岃祫婧愯浆 <code>Draining</code>锛屾嫆鏂板啓銆佸仠鍛ㄦ湡 鈫� 绛夊湪閫旂墖娈电粨鏉� + 鎵ц SafeStateProfile 骞惰鍥烇紙瓒呮椂 鈫� <code>RecoveryRequired</code>锛�<strong>涓嶇瓑浜�</strong>鑷姩缁欑淮鎶よ�咃級鈫� 鏃� owner 鎺掔┖閲婃斁 + 鏃у彞鏌勫叧闂� + Mutex 瀹堝崼鍙幏鍙� 鈫� 鐙珛鑱旈攣/鏂數鎵嬬画纭 鈫� 绛惧彂缁存姢 Grant锛屽姩浣滃叏閲忓璁★紱閫�鍑虹淮鎶ゅ弽鍚戝鏍稿悗鎵嶄氦杩樼敓浜с��
+</div>
+
+<h3>7.3 Broker 閲嶅惎鎭㈠</h3>
+<div class="card">
+鍙栧崟瀹炰緥瀹堝崼 鈫� <strong>epoch+1 钀界洏</strong>锛堟棫 Grant/鎺掗槦浠诲姟鍏ㄩ儴澶辨晥锛夆啋 闃绘柇鏅�氬啓 鈫� 璁惧韬唤楠岃瘉 鈫� 璇诲洖杈撳嚭/閫氶亾/鍗忚鐘舵�� 鈫� 鎸夎澶囧畨鍏ㄦā鏉挎仮澶嶏紙<strong>瀹夊叏鎬� 鈮� 缁熶竴"杈撳嚭鍏ㄥ叧"</strong>锛氭俯绠便�佸喎鍗淬�佽娴嬩欢鍚勬湁瑕佹眰锛夆啋 鎭㈠妫�鏌ョ偣涓庤瘉鎹寔涔呭寲锛堥渶浜哄伐瀹℃壒鍒欑瓑寰咃級鈫� Free/Ready 鈫� RunService 璁板綍涓柇绐楀彛涓庢暟鎹� Gap锛屽喅瀹氱画璺�/閲嶆祴銆�
+</div>
+
+<!-- ======================================================== -->
+<h2 id="s8">鍏�佷繚鎸佷笉鍙樼殑閮ㄥ垎锛堟灦鏋勮繛缁�ц祫浜э級</h2>
+
+<div class="success">
+<ol>
+<li><strong>鎻掍欢鍖� UI 楠ㄦ灦</strong>锛歋impleMaskControl / PluginLoader / MVVM 鍏ㄩ儴淇濈暀锛屼笁涓鍥句粛鏄儹鎻掓嫈鎻掍欢锛堟敞鎰忕幇鐘跺懡鍚嶅榻愶細瀹為檯涓� <code>Plugin.DeviceConfig.DeviceConfig</code> 绛夛紝涓� <code>DeviceMonitorView</code> 闇�鏂板缓锛夛紱</li>
+<li><strong>SQLite 鎶�鏈�夊瀷</strong>锛堟湰鏈虹洏 + WAL + 鐭簨鍔� + busy_timeout锛夛紝浣嗘暟鎹簱杈圭晫閲嶅垝锛�</li>
+<li><strong>璋冭瘯浼氳瘽"鐘舵�佹満 + 瀹¤"璁捐鎬濇兂</strong>鈥斺�擵3.0 鏄姞鐘舵�侊紝涓嶆槸鎺ㄧ炕锛�</li>
+<li><strong>Draft/Published/Effective 鐗堟湰鐞嗗康</strong>鈥斺�斿崌绾т负涓嶅彲鍙樺揩鐓� + 鍝堝笇瀵硅处锛�</li>
+<li><strong>鍏ㄨ嚜鍔ㄩ棬闈� B+C 妯″紡</strong>锛堜綔鐢ㄥ煙绉熺害 + 绫诲瀷鍖栨湇鍔★紝鏈」鐩凡瀹炵幇锛夆�斺�旀鏄� V3.0 <code>ILeaseScope + DeviceOperation</code> 鐨勯洀褰€��</li>
+</ol>
+</table>
+</div>
+
+<!-- ======================================================== -->
+<h2 id="s9">涔濄�乀estStep 浠櫒浣跨敤瑙勮寖锛堜笟鍔℃墽琛屽煙浣跨敤瑙嗗浘锛�</h2>
+
+<p>鍓嶅叓绔犲畾涔夆�滅郴缁熶笌鑱岃矗鈥濓紝鏈珷瀹氫箟鈥滀娇鐢ㄨ�呮�庝箞鍐欌�濃�斺�擱ecipe/TestStep 闈㈠悜娴嬭瘯寮�鍙戜汉鍛樼殑<strong>浣跨敤濂戠害</strong>銆�</p>
+
+<h3>9.1 涓夋潯閾佸緥锛堝厛绔嬭鐭╋級</h3>
+<table>
+    <tr><th>#</th><th>閾佸緥</th><th>鍘熷洜</th></tr>
+    <tr><td><span class="iron">T-1</span></td>
+        <td>TestStep <strong>姘镐笉</strong>鐩存帴 new 椹卞姩銆佸~ COM 鍙c�両P 鍦板潃銆佽繘绋嬪悕</td>
+        <td>鐗╃悊璺敱灞炰簬閰嶇疆鍩燂紙鍐荤粨蹇収锛夛紱鍐欐鍦ㄦ楠ら噷 = 鎹㈠彴鏋跺叏閲忔敼搴忓垪锛屼笖鐮村潖 INV-01/04</td></tr>
+    <tr><td><span class="iron">T-2</span></td>
+        <td>TestStep <strong>姘镐笉</strong>鑷繁璋� ResourceManager.Reserve / 鎷� LeaseGrant</td>
+        <td>绉熺害鐢熷懡鍛ㄦ湡褰掓鏋讹紙Scope + 鐙珛缁湡浠诲姟锛夛紝姝ラ鑷繁鎷跨绾﹀繀鐒跺繕缁湡/蹇橀噴鏀�</td></tr>
+    <tr><td><span class="iron">T-3</span></td>
+        <td>TestStep <strong>姘镐笉</strong>鎶� Broker 璇诲洖鍊肩洿鎺ュ綋鍚堟牸鍒ゅ畾</td>
+        <td>鈥滄暟鎹粠鍝潵銆佹柊涓嶆柊椴溾�濇槸瀹夸富璐d换锛涒�滄槸鍚﹁揪鍒板伐鑹烘潯浠垛�濇槸姝ラ/寮曟搸鍒ゅ畾锛埪�20.6 鍒嗘潈锛�</td></tr>
+</table>
+
+<h3>9.2 瑙f瀽閾撅細姝ラ澹版槑閫昏緫鑳藉姏锛屾鏋惰В鏋愮墿鐞嗚祫婧�</h3>
+<div class="mermaid">
+flowchart LR
+    A["TestStep 澹版槑<br/>SlotId=S024, Capability=Power"] --> B["SnapshotResolver<br/>锛圧un鍚姩鏃跺凡鍐荤粨 RunSnapshot锛�"]
+    B --> C["slot_binding<br/>S024+Power 鈫� psu/psu03/ch/5<br/>+ 鐖� Permit psu/psu03"]
+    C --> D["ResourceRouter<br/>resource_definition:<br/>executionMode=Broker, authority=B01"]
+    D --> E1["LocalExecutor锛圵0x锛�"]
+    D --> E2["BrokerClient锛圔01锛�"]
+    style A fill:#E8F5E9
+    style E1 fill:#FFF8E1
+    style E2 fill:#FFF8E1
+</div>
+<p>姝ラ浣滆�呴潰瀵圭殑鍙湁涓や釜姒傚康锛�<strong>绌轰綅鍙� + 鑳藉姏鍚�</strong>銆侱UTContext 姣忕┖浣嶇嫭绔嬩繚瀛� SN/姝ラ/璁℃椂/缁撴灉锛�<strong>120 涓┖浣� 鈮� 120 鏉$嚎绋�</strong>锛堢瓑寰呯敤寮傛璁℃椂锛夈��</p>
+
+<h3>9.3 涓夌浣跨敤妯″紡</h3>
+
+<h4>妯″紡 B锛堥閫夛級锛氫綔鐢ㄥ煙绉熺害 鈥斺�� 涓�涓楠ゅ娆℃搷浣滃悓涓�璧勬簮</h4>
+<pre><code><span class="cmt">// net472 鏃� await using锛屾樉寮� ReleaseAsync + try/finally</span>
+<span class="kwd">public override async void</span> Run()
+{
+    <span class="kwd">var</span> req = <span class="kwd">new</span> AcquireRequest {
+        OwnerId           = RunContext.StationId,          <span class="cmt">// 濡� "W02.Run-20261103-A"</span>
+        OwnerKind         = OwnerKind.Production,
+        ProcessInstanceId = RunContext.ProcessInstanceId,  <span class="cmt">// boot_id+pid锛岄槻涓插彴</span>
+        ConfigHash        = RunContext.RunSnapshot.ConfigHash,
+        ResourceKeys      = <span class="kwd">new</span>[] { <span class="str">"psu/psu03/ch/5"</span>, <span class="str">"can/can01/ch/2"</span> }, <span class="cmt">// 妗嗘灦鎸夊簭灞曞紑缁勭敵璇�</span>
+        WaitTimeoutMs     = <span class="num">60_000</span>
+    };
+
+    ILeaseScope scope = <span class="kwd">null</span>;
+    <span class="kwd">try</span>
+    {
+        scope = <span class="kwd">await</span> coordinator.<span class="fn">AcquireGroupAsync</span>(req, ct);   <span class="cmt">// 鍚屽煙锛氫簨鍔″叏鏈夊叏鏃狅紱璺ㄥ煙锛氬崗璋冨紡棰勭暀</span>
+        <span class="cmt">// LeaseLost 淇″彿锛氱画鏈熷け璐�/琚殧绂� 鈫� 绔嬪嵆鍋滄涓嬪彂</span>
+        <span class="kwd">var</span> ioCts = CancellationTokenSource.<span class="fn">CreateLinkedTokenSource</span>(ct, scope.LeaseLost);
+
+        <span class="kwd">var</span> psu = executorFactory.<span class="fn">For</span>(scope, <span class="str">"psu/psu03/ch/5"</span>); <span class="cmt">// Local/Broker 璺敱瀵规楠ら�忔槑</span>
+        <span class="kwd">await</span> psu.<span class="fn">SetVoltageAsync</span>(<span class="num">12.0</span>, ctx.<span class="fn">NextIdempotencyKey</span>(), ioCts.Token);
+        <span class="kwd">await</span> psu.<span class="fn">OutputOn</span>(ioCts.Token);
+        <span class="kwd">var</span> v = <span class="kwd">await</span> psu.<span class="fn">ReadVoltage</span>(ioCts.Token);
+
+        Upwards.<span class="fn">Find</span>(<span class="num">12.0</span>, v.Readback).Verdict =               <span class="cmt">// 鈫� 鍒ゅ畾鍦ㄥ紩鎿庝晶锛圱-3锛�</span>
+            Math.<span class="fn">Abs</span>(v.Readback - <span class="num">12.0</span>) &lt;= <span class="num">0.5</span> ? Verdict.Pass : Verdict.Fail;
+    }
+    <span class="kwd">finally</span>
+    {
+        <span class="cmt">// 鏄惧紡寮傛閲婃斁锛氭帓绌� I/O 鈫� 璇诲洖/瀹夊叏浜ゆ帴 鈫� 閲婃斁锛�</span>
+        <span class="cmt">// 澶辫触杩涙仮澶嶏紝缁濅笉鍋囪鎴愬姛锛涚粓鎬佷繚瀛樼敤鐙珛鏈夌晫 token锛屼笉鍙楄皟鐢ㄦ柟鍙栨秷褰卞搷</span>
+        <span class="kwd">if</span> (scope != <span class="kwd">null</span>)
+            <span class="kwd">await</span> scope.<span class="fn">ReleaseAsync</span>(CancellationToken.None);
+    }
+}</code></pre>
+
+<h4>妯″紡 C锛堝父鐢ㄥ皝瑁咃級锛氱被鍨嬪寲鏈嶅姟 + 鍙岀鍚�</h4>
+<pre><code><span class="cmt">// 鐙珛璋冪敤锛堟鏋跺唴閮ㄨ蛋瀹� 鐢宠鈫掓墽琛屸啋閲婃斁锛夆�斺�旈�傚悎鍗曞懡浠ゆ楠�</span>
+<span class="kwd">await</span> canBus.<span class="fn">SendFrameAsync</span>(<span class="str">"CAN-001"</span>, <span class="num">0x100</span>, data, ct);
+
+<span class="cmt">// 鍊熺敤浣滅敤鍩燂紙鎺ㄨ崘锛氫笌妯″紡B缁勫悎锛屽鐢ㄥ凡鎸佹湁绉熺害锛�</span>
+<span class="kwd">await</span> canBus.<span class="fn">SendFrameAsync</span>(scope.<span class="fn">LeaseOf</span>(<span class="str">"can/can01/ch/2"</span>), <span class="num">0x100</span>, data, ct);</code></pre>
+
+<h4>妯″紡閫夋嫨閫熸煡</h4>
+<table>
+    <tr><th>鍦烘櫙</th><th>妯″紡</th></tr>
+    <tr><td>鍗曟潯鏌ヨ绫绘楠わ紙濡傛壂涓�鏉� UDS DID锛�</td><td>A 涓�娆℃��</td></tr>
+    <tr><td>澶氬懡浠ゅ師瀛愬伐鑹烘锛堜笂鐢碘啋璁惧帇鈫掕鏁扳啋鍏宠緭鍑猴級</td><td class="good">B 浣滅敤鍩燂紙+C 灏佽锛�</td></tr>
+    <tr><td>璺ㄨ祫婧愯仈鍔紙鍚屼竴 DUT 鐢垫簮 + CAN锛�</td><td class="good">B 缁勭敵璇凤紙鍚屽煙鎵嶆壙璇哄叏鏈夊叏鏃狅級</td></tr>
+    <tr><td>鍛ㄦ湡鎬ф縺鍔� / 闀挎椂鐩戞帶</td><td>B + 搂9.6 鍚庡彴浠诲姟妯℃澘锛�<strong>涓嶆槸寰幆 A</strong></td></tr>
+</table>
+
+<h3>9.4 骞傜瓑閿笌瓒呮椂閲嶈瘯瑙勮寖</h3>
+<pre><code><span class="cmt">// 閿殑鐢熸垚瑙勫垯锛氬叏灞�鍞竴銆佸彲閲嶆斁瀹氫綅銆侀噸璇曚笉鎹㈠唴瀹瑰彧澧� attempt 搴忓彿</span>
+<span class="kwd">string</span> idemKey = $<span class="str">"{RunId}/{DutExecId}/{StepExecId}/attempt-{attempt}"</span>;</code></pre>
+<table>
+    <tr><th>鍔ㄤ綔绫诲瀷</th><th>瓒呮椂鍚庡彲鑷姩閲嶅彂锛�</th><th>渚濇嵁</th></tr>
+    <tr><td>璁剧疆鍨嬶紙SetVoltage=12.0锛�</td><td class="good">鉁� 鍏� Query 瀵硅处鍐嶉噸鍙�</td><td>骞傜瓑锛岄噸澶嶆墽琛岀粨鏋滃悓</td></tr>
+    <tr><td>瑙﹀彂/澶嶄綅/鐑у啓/璁℃暟鍨�</td><td class="bad">鉂� 鍙兘鎸� Unknown 璧拌鍥炴牳瀵�</td><td>鏂囨。 搂11.2锛氳法鎵ц涓庢彁浜や箣闂存棤纭欢浜嬪姟锛屼笉鎵胯 exactly-once</td></tr>
+    <tr><td>浠绘剰鍔ㄤ綔锛岀粨鏋滄湭鏀跺埌</td><td class="mid">鍏堝悓閿� Query/閲嶆彁锛孞ournal 鏈夌粓鎬佽繑鍥炲師缁撴灉</td><td>搂20.4锛氱粷涓嶇敓鎴愭柊閿啀瑙﹀彂涓�娆�</td></tr>
+</table>
+<p>瀹㈡埛绔噸杩炲繀椤�<strong>淇濈暀鍘� ClientInstanceId 鏌ヨ</strong>锛屼笉鐢熸垚鏂伴敭閲嶅彂銆�</p>
+
+<h3>9.5 浜ゆ帴銆佺画鏈熶笌 LeaseLost锛氭楠や綔鑰呯殑涔夊姟</h3>
+<table>
+    <tr><th>妗嗘灦鑱岃矗</th><th>姝ラ鑱岃矗</th></tr>
+    <tr><td>鍚庡彴鐙珛绾跨▼缁湡锛圱TL/3锛�</td><td>鐩戝惉 <code>scope.LeaseLost</code>锛岃仈杩涙墍鏈変笅鍙戠殑 CTS</td></tr>
+    <tr><td>Draining 閫氱煡锛堢淮鎶よ�呯敵璇疯繘鍏ワ級</td><td>鍙湪銆愭楠よ竟鐣屻�戣娓★紝缁濅笉鍦ㄥ崐鏉″懡浠ら棿鏀炬墜</td></tr>
+    <tr><td>缁湡杩炵画澶辫触 2 娆� 鈫� LeaseLost</td><td>绔嬪嵆鍋滄涓嬪彂鏂版搷浣�</td></tr>
+    <tr><td>Release 澶辫触</td><td>濡傚疄涓婃姤锛岀瓑寰呮仮澶嶏紝涓嶁�滆鏃ュ織鍚庣户缁��</td></tr>
+</table>
+<pre><code><span class="cmt">// 姝ラ鏀跺熬鐐规鏌ワ紙妗嗘灦鍦� HandoverRequested 鏃剁疆浣嶏級</span>
+<span class="kwd">if</span> (scope.HandoverRequested) <span class="kwd">return</span>;  <span class="cmt">// 鏈楠ゆ甯哥粨鏉燂紝浣滅敤鍩熼��鍑烘椂瀹夊叏璁╂浮</span>
+<span class="cmt">// 娉ㄦ剰锛氶暱 Delay 搴旀媶鎴愬彲涓柇鐨勫紓姝ョ瓑寰呯墖娈碉紝淇濊瘉 30s handover 绐楀彛鍐呰兘鍒拌揪杈圭晫</span></code></pre>
+<div class="info"><strong>鍙栨秷鐨勪笁绉嶈涔�</strong>锛堟鏋跺凡澶勭悊锛屼綔鑰呭彧闇�鐭ラ亾锛夛細鎺掗槦涓彇娑� = 纭畾鏈墽琛岋紱鎵ц涓彇娑� = 闇�椹卞姩瀹夊叏鍋滄纭锛涘搷搴旂瓑寰呭彇娑� = 鍙槸涓嶇瓑浜嗭紝<strong>涓嶈兘鍙嶆帹璁惧娌″姩</strong>鈥斺�旂粨鏋滀粛璧� Unknown/璇诲洖閫氶亾銆�</div>
+
+<h3>9.6 闀垮懆鏈熶换鍔★細浜ょ粰 Broker锛屾楠や笉鍏荤嚎绋�</h3>
+<table>
+    <tr><th>闇�姹�</th><th>鉂� 閿欒鍋氭硶</th><th>鉁� 姝g‘鍋氭硶锛圱ask 绫诲瀷锛�</th></tr>
+    <tr><td>CAN 鍛ㄦ湡鍙戦�� 0x100@100ms</td><td>TestStep 鍐� while+Sleep</td><td><strong>PeriodicTx</strong> 妯℃澘椹荤暀 Broker锛岄殢 owner 绉熺害瀛樼画/鍒版湡/澶辨晥锛涚姝㈤噸杩炲悗琛ュ彂鏃у抚</td></tr>
+    <tr><td>鑰佸寲鏈熼棿鐩戞帶鎬荤嚎淇″彿</td><td>120 绌轰綅杞绾跨▼</td><td><strong>Acquisition</strong> 璁㈤槄 + 浜嬩欢娓告爣澧為噺鎷夊彇锛涙暟鎹� Gap 甯﹁川閲忔爣璁� Stale/Disconnected</td></tr>
+    <tr><td>UDS 浼氳瘽淇濇椿</td><td>姝ラ瀹氭椂鍣ㄥ彂 TesterPresent</td><td><strong>ProtocolSession</strong>锛氫細璇濆綊涓�璋冨害锛孴esterPresent 涓庝笟鍔″姩浣滃悓闃�</td></tr>
+    <tr><td>绛� 30 鍒嗛挓</td><td>Thread.Sleep 鍗犵嚎绋�</td><td>寮傛璁℃椂鐣欏湪鎵ц寮曟搸锛圧ecipe 鐨勯暱 Delay <strong>涓嶈繘 Broker</strong>鈥斺�擝roker 鍙仛鏈夌晫璁惧鍔ㄤ綔锛�</td></tr>
+</table>
+<pre><code><span class="cmt">// 姝ラ渚ц闃呭舰鎬侊細鎻愪氦-鏌ヨ-ACK锛屼笉椹荤暀</span>
+<span class="kwd">var</span> sub = <span class="kwd">await</span> broker.<span class="fn">SubscribeAsync</span>(<span class="kwd">new</span> { resource = <span class="str">"can/can01/ch/2"</span>,
+    signal = <span class="str">"Motor.Temp"</span>, templateId = <span class="str">"can.acq.motor-temp"</span> }, ct);
+
+<span class="cmt">// 绛夊緟淇″彿杈炬爣锛堝垽瀹氫粛鍦ㄥ紩鎿庯級</span>
+<span class="kwd">var</span> sample = <span class="kwd">await</span> sub.<span class="fn">WaitMatchingAsync</span>(s =&gt; s.Value &gt; <span class="num">85.0</span>, TimeSpan.<span class="fn">FromMinutes</span>(<span class="num">30</span>), ct);
+<span class="kwd">if</span> (sample == <span class="kwd">null</span>) Upwards.<span class="fn">Find</span>().<span class="fn">Fail</span>(<span class="str">$"瓒呮椂鏈揪85鈩冿紝Gap={sub.GapCount}"</span>);
+
+<span class="kwd">await</span> sub.<span class="fn">UnsubscribeAsync</span>(ct);   <span class="cmt">// 鍙栨秷骞剁‘璁ゅ仠閲�/瑙g粦</span></code></pre>
+<p>缁撴灉娑堣垂閬靛惊 Outbox锛�<strong>ACK 鍙湪缁撴灉钀界洏鎴愬姛鍚庡彂閫�</strong>锛屾楠ゅ穿婧冮噸鍚敤鍚� IdempotencyKey 鎵惧洖鏈� ACK 缁撴灉锛屼笉閲嶈窇璁惧鍔ㄤ綔銆�</p>
+
+<h3>9.7 瀹屾暣绀轰緥锛氬宸ヤ綅 CAN 鑰佸寲姝ラ锛圔 + C + 璁㈤槄 鎷兼垚鐪熷疄宸ヨ壓锛�</h3>
+<pre><code>[Display(<span class="str">"CAN 閫氫俊鑰佸寲"</span>, Group = <span class="str">"Aging"</span>)]
+<span class="kwd">public class</span> CanCommAgingStep : TestStep
+{
+    [ResourceProperty(<span class="str">"CAN"</span>)] <span class="kwd">public string</span> SlotId { <span class="kwd">get</span>; <span class="kwd">set</span>; } = <span class="str">"S001"</span>;
+    <span class="kwd">public int</span> Cycles { <span class="kwd">get</span>; <span class="kwd">set</span>; } = <span class="num">100</span>;
+
+    <span class="kwd">public override async void</span> Run()
+    {
+        <span class="kwd">var</span> ctx  = RunContext.Current;                     <span class="cmt">// Run/DUT/Step 鍏宠仈ID</span>
+        <span class="kwd">var</span> auto = AgingRuntime.Coordinator;               <span class="cmt">// IResourceCoordinator</span>
+        <span class="kwd">var</span> cans = AgingRuntime.CanBus;                    <span class="cmt">// ICanBusService(绫诲瀷鍖�)</span>
+
+        <span class="kwd">var</span> req  = ctx.<span class="fn">BuildAcquire</span>(<span class="kwd">new</span>[] { <span class="str">"can/"</span> + ctx.<span class="fn">SlotOf</span>(SlotId) + <span class="str">"/ch/2"</span> });
+        <span class="kwd">using var</span> cts = Utils.<span class="fn">LinkedWithVerdictCancel</span>(Upwards);
+
+        ILeaseScope scope = <span class="kwd">await</span> auto.<span class="fn">AcquireGroupAsync</span>(req, cts.Token);
+        <span class="kwd">try</span>
+        {
+            <span class="kwd">var</span> lease = scope.<span class="fn">LeaseOf</span>(ctx.<span class="fn">ResourceOf</span>(SlotId));
+
+            <span class="cmt">// 鈶� 璧峰懆鏈熸縺鍔憋紙椹荤暀 Broker锛岄殢绉熺害澶辨晥鑷姩鍋滐級</span>
+            <span class="kwd">var</span> periodic = <span class="kwd">await</span> lease.<span class="fn">StartTemplateAsync</span>(<span class="str">"can.periodic.keepalive"</span>,
+                <span class="kwd">new</span> { frameId = <span class="num">0x3E0</span>, periodMs = <span class="num">500</span> }, cts.Token);
+
+            <span class="cmt">// 鈶� 璁㈤槄鍝嶅簲淇″彿</span>
+            <span class="kwd">var</span> sub = <span class="kwd">await</span> lease.<span class="fn">SubscribeAsync</span>(<span class="str">"can.acq.response-0x3E1"</span>, cts.Token);
+
+            <span class="kwd">for</span> (<span class="kwd">int</span> i = <span class="num">0</span>; i &lt; Cycles &amp;&amp; !scope.HandoverRequested; i++)
+            {
+                <span class="kwd">await</span> cans.<span class="fn">SendFrameAsync</span>(lease, <span class="num">0x100</span> + (uint)i, ctx.<span class="fn">Payload</span>(i),
+                    ctx.<span class="fn">NextIdempotencyKey</span>(), cts.Token);
+
+                <span class="kwd">var</span> echo = <span class="kwd">await</span> sub.<span class="fn">WaitMatchingAsync</span>(f =&gt; f.<span class="fn">MatchRequest</span>(<span class="num">0x100</span> + i),
+                    TimeSpan.<span class="fn">FromSeconds</span>(<span class="num">2</span>), cts.Token);
+
+                <span class="kwd">if</span> (echo == <span class="kwd">null</span>) { Verdict = Verdict.Fail; <span class="kwd">break</span>; }  <span class="cmt">// 鍒ゅ畾鍦ㄥ紩鎿�</span>
+                Report.<span class="fn">Sample</span>(i, echo);                                <span class="cmt">// 閲囨牱璧扮粨鏋滈�氳矾</span>
+            }
+
+            <span class="kwd">await</span> periodic.<span class="fn">StopAsync</span>(cts.Token);   <span class="cmt">// 鍛ㄦ湡浠诲姟鏄惧紡鍋滄骞垛�滅‘璁ゅ仠姝⑩��</span>
+            <span class="kwd">await</span> sub.<span class="fn">UnsubscribeAsync</span>(cts.Token);
+        }
+        <span class="kwd">finally</span>
+        {
+            <span class="kwd">await</span> scope.<span class="fn">ReleaseAsync</span>(CancellationToken.None);  <span class="cmt">// 寮傛銆佸彲澶辫触杩涙仮澶�</span>
+        }
+    }
+}</code></pre>
+
+<h3>9.8 姝ラ鐢熷懡鍛ㄦ湡鏃跺簭</h3>
+<pre><code>OnPlanLoad    瑙f瀽 Slot+Capability 鈫� 棰勬閰嶇疆瀛樺湪鎬э紙涓嶅崰璧勬簮锛�
+Run() 鍏ュ彛     DUTContext 鐘舵�佹鏌� 鈫� AcquireGroup锛堟帓闃熺瓑寰�=寮傛锛屼笉闃诲浠栦綅锛�
+鎸佺闃舵      绫诲瀷鍖栨搷浣�/璁㈤槄 鈫� 姣忓懡浠ゅ甫 Grant+IdemKey+Deadline 鈫� 璇诲洖璐ㄩ噺鏍稿
+閫�鍑鸿竟鐣�      HandoverRequested? 鈫� 璁╂浮鎴栫画璺�
+finally       鍋滃悗鍙颁换鍔�(纭) 鈫� ReleaseAsync 鈫� 缁撴灉 Outbox ACK 鍚庣粓鎬佷繚瀛�
+寮傚父璺緞      LeaseLost / Unknown 鈫� 鍋滄涓嬪彂 鈫� 涓婃姤 鈫� 浜ょ粰鎭㈠/RunService 鍐崇瓥锛堜笉鑷姩鍒ゅ悎鍚︼級</code></pre>
+
+<h3>9.9 鍙嶆ā寮忔竻鍗曪紙TestStep 渚ф眹鎬伙級</h3>
+<table>
+    <tr><th>鍙嶆ā寮�</th><th>鍚庢灉</th><th>姝hВ</th></tr>
+    <tr><td class="bad">姝ラ閲� new CanDriverAdapter(...)</td><td>缁曡繃浠茶涓庡揩鐓э紝鍙屽涓诲啿绐侊紙INV-01锛�</td><td>鍙粡 Scope/Executor 璺敱</td></tr>
+    <tr><td class="bad">瓒呮椂鍚庢崲鏂� IdempotencyKey 閲嶅彂</td><td>瑙﹀彂鍨嬪姩浣滄墽琛屼袱娆�</td><td>鍚岄敭 Query 瀵硅处锛埪�20.4锛�</td></tr>
+    <tr><td class="bad">鍦� await 璺ㄧ嚎绋嬪閲婃斁瀹堝崼 Mutex</td><td>AbandonedMutex / 闈炴硶閲婃斁</td><td>瀹堝崼褰掑涓讳笓鐢ㄧ嚎绋嬶紝姝ラ鍙搷浣滅绾�</td></tr>
+    <tr><td class="bad">scope.Dispose() 鍚屾闃诲 UI/绾跨▼姹�</td><td>鎺掔┖绛夊緟鍗℃璋冨害</td><td>鏄惧紡 ReleaseAsync</td></tr>
+    <tr><td class="bad">鐢� Thread.Sleep 绛夎�佸寲鏃堕暱</td><td>120 绌轰綅 = 120 绾跨▼</td><td>寮傛璁℃椂 + Broker Periodic/Acquisition</td></tr>
+    <tr><td class="bad">鎶� Broker 璇诲洖鐩存帴褰� PASS</td><td>鎺╃洊閫氫俊鏁呴殰锛堟暟鎹川閲忊墵宸ヨ壓鍒ゅ畾锛�</td><td>鍒ゅ畾鍦ㄦ楠�/寮曟搸锛孏ap 蹇呴』璁″叆</td></tr>
+    <tr><td class="bad">鎹曡幏 LeaseLost 鍚庣户缁彂鍛戒护</td><td>鍍靛案鍐欏叆锛堟爡鏍忓彧鎸″潖缁撴灉锛屾尅涓嶄綇浣犳病鏌ワ級</td><td>LeaseLost 鑱旇繘鎵�鏈変笅鍙戠殑 CTS</td></tr>
+</table>
+
+<!-- ======================================================== -->
+<h2 id="s10">鍗併�佺粨璁�</h2>
+
+<div class="success">
+<p><strong>鏂版灦鏋勫浘鐨勪竴鍙ヨ瘽璇绘硶锛�</strong>浠櫒娉ㄥ唽鐢熶骇<strong>甯﹀搱甯岀殑閰嶇疆鐪熺悊</strong>锛屼华鍣ㄨ皟璇曠敵璇�<strong>甯︽爡鏍忕殑涓存椂鍐欐潈</strong>锛學orker/Broker 鎵ц<strong>甯﹀師瀛愮墖娈电殑鐗╃悊 I/O</strong>锛孯ecipe 鍙仛<strong>绌轰綅鈫掕兘鍔涒啋鍒ゅ畾</strong>锛屽洓鏈暟鎹簱鍚勫畧鍚勭殑鍗曞啓鑰呪�斺�斾换浣曚竴娆♀�滅璁惧鈥濋兘瑕佸悓鏃跺洖绛旓細<strong>鎺堟潈鏄皝锛圙rant锛夈�侀厤缃槸鍝増锛圚ash锛夈�佺墿鐞嗙姸鎬佷俊涓嶄俊寰楄繃锛堣鍥烇級</strong>銆�</p>
+<p>钀藉湴椤哄簭閬靛惊 P0锝濸4 瑁佸壀锛圥ipeClient 淇涓庣‖浠舵嫇鎵戝喕缁� 鈫� 鍗� Authority 绉熺害鍐呮牳 鈫� Broker MVP 鈫� 鎭㈠缂栨帓 鈫� 閰嶇疆鍙戝竷浣撶郴锛夛紝璇﹁銆婂杩涚▼浠櫒璧勬簮鏂规璇勪及銆嬨�傛湰鏂囦笌浠ヤ笅鏂囨。閰嶅闃呰锛�</p>
+<ul>
+    <li><a href="./Local + DeviceBroker 娣峰悎鏋舵瀯璇︾粏璁捐璇存槑涔� V3.0.html">Local + DeviceBroker 娣峰悎鏋舵瀯璇︾粏璁捐璇存槑涔� V3.0</a>锛堟潈濞佽璁℃簮锛�</li>
+    <li><a href="./MultiProcess_Instrument_Resource_Solution.html">澶氳繘绋�/澶氱嚎绋嬩华鍣ㄨ祫婧愮嫭鍗犱笌鍏变韩鏂规</a>锛堝凡琚� V3.0 淇锛氬埌鏈熶笉鑷姩鎺ョ绛夛級</li>
+    <li><a href="./OpenTAP_Instrument_Package_Analysis.html">OpenTAP Instrument + 鎻掍欢鍖呮満鍒跺垎鏋�</a>锛堥┍鍔ㄥ垎鍙戝舰鎬侊級</li>
+    <li><a href="./DeviceConfig_DeviceDebug_Architecture.html">浠櫒娉ㄥ唽涓庣‖浠惰皟璇曡皟鐢ㄥ叧绯�</a>锛堢幇鐘跺疄鐜板揩鐓э級</li>
+</ul>
+</div>
+
+<footer>
+    浠櫒娉ㄥ唽涓庝华鍣ㄨ皟璇� 路 绯荤粺鏋舵瀯璇存槑 V3.0 閲嶆⒊鐞嗙増锛堝惈 TestStep 浣跨敤瑙勮寖锛壜� 2026-11-03<br>
+    鍩哄噯锛氥�奓ocal + DeviceBroker 娣峰悎鏋舵瀯璇︾粏璁捐璇存槑涔� V3.0銆嬄� 鏈枃鐜扮姸鎻忚堪閮ㄥ垎宸插鐓х湡瀹炰唬鐮佹牳瀹�
+</footer>
+
+<script>
+    mermaid.initialize({ 
+        startOnLoad: true, theme: 'default', securityLevel: 'loose',
+        fontFamily: 'Segoe UI, Microsoft YaHei, sans-serif',
+        flowchart: { curve: 'basis', padding: 16 },
+        sequence: { showSequenceNumbers: false, actorMargin: 50 }
+    });
+</script>
+
+</body>
+</html>

--
Gitblit v1.9.1