語法結構

Markdown+ 文件由 一份 H1 標題 + 一段引言 + 多個 bullet-list block 組成。每個 block 的開頭固定格式:

- **#<kebab-case-id>** `type:<value>` `<key>:<value>` ...
  <block body, 縮排 2 spaces, 任意合法 Markdown>

  - **#<child-id>** `type:<value>` ...
    <子 block, 縮排 4 spaces>

組成元素

元件規則純 Markdown 渲染Markdown+ viewer 渲染
Bullet- 圓點section 邊界
Block ID**#kebab-id**粗體 hashtaganchor + id=""
Metadatainline code `key:value`monospace badge解析為 attribute
父子nested bullet list 縮排自然縮排<section> 巢狀

受控 metadata 字彙表

type: (block 主類型,closed list)

需要擴充必須用 x- 前綴。

type用途
state描述當前事實 / 現況
history已不適用的歷史(預設摺疊)
decision決策紀錄
record事件紀錄 (會議、incident)
issue待解問題 / blocker
note補充說明
spec規格 / 技術說明
task待辦 / action item
reference外部連結彙整
figure / table / chart / diagram視覺資料
kpi / gauge / targets / dashboard / card儀表板元件
dialogue / turn對話容器與輪次
step教學 / runbook 步驟

status: (closed list)

draft active proposed accepted rejected superseded deprecated archive healthy degraded down on-track behind exceeded done blocked open closed

其他常用 metadata

  • updated:YYYY-MM-DD — ISO 日期
  • visibility:collapsed — viewer 預設摺疊
  • priority:high|normal|low|critical
  • tags:[domain:auth,team:platform] — 用 namespace
  • superseded-by:<id> — 指向替代者
  • related:[id1,id2]
  • variant-group:install + variant:mac — 同 group 的 sibling 會被 viewer 聚合成 tab
  • KPI: value: target: delta: unit:
  • Gauge: value: min: max: target: zones:[99:red,99.9:amber,99.95:green]
  • keywords:a,b,c — block 關鍵詞清單。手動宣告永遠優先;未宣告時 viewer 會自動抽出(虛線 chip)。詳見 自動關鍵詞抽取

必須遵守的約束關係

  • status:deprecated ⇒ 必有 superseded-by:<id>
  • type:history ⇒ visibility:collapsed
  • type:kpi ⇒ value:,且與 prose 段數字一致
  • type:gauge ⇒ value: min: max: target: zones: 全要
  • 同層共用 variant-group: 的 sibling 必須各有不同 variant:
  • 每個 figure / chart / table / kpi / gauge / video / audio 必須有 prose companion 段
  • 表格 > 30 列必須用 data-source:./data/<name>.csv

禁止清單 (lint error)

禁止項替代
:::block fenced divbullet list block
Raw HTML 容器 (div / span / section ...)由 viewer 從 metadata 生成
<script> / <style>留給 viewer
class="" / style=""留給 viewer
Inline data:image/...;base64,...外部相對路徑
Raw <svg> 直接寫在段落或 HTML 容器內包進 ```svg fence(<= 16 KB)或外部檔 ![alt](./path.svg)
```svg fence 內容 > 16 KB拆成 ./diagrams/*.svg 外部檔
巨型 inline chart spec (>80 行)拆到 ./charts/*.json
巨型 inline 表格 (>30 列)拆到 ./data/*.csv
寫死 caption 編號 (Figure 1:)*Figure: ...*,viewer 自動編號
自由 type: 值受控字彙表或 x- 前綴

視覺化 fence:```svg 與 ```mermaid

圖表 / 流程圖 / 簡單示意圖可以用兩種 標準 code fence 內聯, 在 GitHub / Obsidian 仍是合法的 code block(graceful degradation), 在 Markdown+ viewer 才長出 graph / code 切換 toolbar。

```svg — 內聯向量圖

- **#sla-trend** `type:figure` `media:svg`

  *Figure: API SLA 月度趨勢*

  ```svg
  <svg viewBox="0 0 320 120" xmlns="http://www.w3.org/2000/svg">
    <polyline points="50,40 130,56 210,70 290,72" fill="none" stroke="#0ea5e9" stroke-width="2"/>
    ...
  </svg>
  ```

  4 月 SLA 跌至 99.92%,低於目標。

viewer 行為

SVG 大小viewer 動作說明
≤ 16 KB渲染圖 + graph / code 雙視圖 toolbartoolbar 顯示 svg · X.Y KB
> 16 KB強制只顯示 code + warning callout提示拆成 ./diagrams/*.svg

注入前 sanitize

  • <script> tag 整段移除
  • on*= event handler attribute 全部去掉(onclick / onload / onerror …)
  • 結構標記(<defs> <style> <marker> <filter>)保留

```mermaid — Mermaid 圖表

- **#refresh-flow** `type:diagram` `diagram-type:mermaid`

  *Figure: Token refresh 流程*

  ```mermaid
  sequenceDiagram
      participant C as Client
      participant G as Gateway
      C->>G: request with expired token
      G-->>C: new access token
  ```

  refresh 流程從 client 看是透明的。

viewer 動態 import Mermaid 10 (CDN) 渲染為 SVG; toolbar 與 SVG fence 共用元件,「graph」視圖顯示渲染後的圖、 「code」視圖顯示原始 mermaid source。

自動抓取的結構關鍵詞

含 ```mermaid 的 block 自動帶 mermaid + 圖表類型(從 fence 第一個非空行偵測):

fence 第一行抽出的關鍵詞
sequenceDiagrammermaid, sequenceDiagram
flowchart TDmermaid, flowchart
classDiagrammermaid, classDiagram
ganttmermaid, gantt
graph LRmermaid, graph
stateDiagram / erDiagram / pie / ...同上規則,取 fence 第一個 identifier

含 ```svg 的 block 則永遠帶 svg 作第一個關鍵詞。

自動關鍵詞抽取(無辭典)

每個 block 沒宣告 keywords: 時, viewer 會用 純統計、無辭典依賴的演算法即時抽出 top-N 關鍵詞,在 block header 下方以虛線 chip 顯示。 手動宣告永遠優先;沒宣告才填 auto chip。

演算法 — N-gram + PMI + 左右熵

完全照「無詞典新詞發現」標準演算法實作,瀏覽器端純 JS 跑,毫秒級完成:

  1. 文本清理:剝除 code fence、inline code、image / link markdown、heading 標記、block header 行,僅保留 prose。
  2. N-gram 枚舉:
    • CJK 連續字串 2 ~ 8 字(min_len=2, max_len=8)
    • ASCII token [A-Za-z][A-Za-z0-9+\-]* 並行抓取 (適用 Markdown+ / block-based / SDK 等混合語術語)
  3. 內部凝固度(PMI cohesion): 對候選詞 w 嘗試所有二分切分, 算 PMI(x, y) = log(P(xy) / P(x)P(y))), 取 最小值作 cohesion(代表最弱的內部連結強度,反映「整體是否確實一起出現」)。 門檻 min_pmi ≥ 1.0。
  4. 左右自由度(Shannon entropy): 收集候選詞左、右鄰字分佈,各計算 Shannon 熵。 兩端皆需 ≥ 0.4。 熵高表示鄰字多樣 = 該詞能獨立出現(像「人工智慧」左右搭配很多), 熵低表示鄰字固定 = 是更長詞的一部分(像「式人工智」永遠夾在「生成式人工智慧」裡會被濾掉)。
  5. 詞頻過濾:出現次數 ≥ 2。
  6. 綜合排序: score = freq × min-PMI × min(left, right)-entropy, 降冪取 top-K(預設 80 個全域候選 → 每 block 取 top-5)。
  7. 子字串抑制:已 kept 的長詞會擠掉它的子字串 (若 freq 接近 ≥ 60%)——比如「人工智慧」入選後就會擠掉 只是它子字串的「人工」「智慧」。
  8. 每 block 投影:對該 block body 計算每個全域候選的命中次數, block_score = global_score × log(occ + 1), 排序取 top-5。

結構標籤前置

以下兩類訊號 n-gram 抓不到(fence 內容被清理階段剝除),所以由獨立 helper 注入並 排在自動抽取詞之前:

  • 含 ```svg fence → 永遠先放 svg
  • 含 ```mermaid fence → 先放 mermaid + 圖表類型(見上)

預設參數一覽

參數預設值說明
min_len2CJK n-gram 最小長度
max_len8CJK n-gram 最大長度(中文詞通常 ≤ 6,留 buffer 抓「概念組合詞」)
min_freq2單檔場景的下限(大語料建議 ≥ 5)
min_pmi1.0單檔較寬鬆;大語料 PDF 建議 3
min_entropy0.4左右兩端 Shannon 熵下限
min_ascii_len3ASCII token 最短長度(避開 `is`, `of` 等)
topK80 / 5全域 80,每 block 5

手動覆寫

把 keywords:a,b,c 放進 block header,viewer 就改顯示實線 chip,不再跑自動抽取。playground sub-header 的「寫入 keywords」按鈕會把 viewer 計算出的 auto 詞用 inline-code 形式寫進 source(``keywords:`a,b,c```),套用前 confirm dialog 列前 8 個 block 的建議供預覽。

複雜度

固定 L (最大候選長度)下,演算法是 O(N × L) 線性掃描 + O(V log V) 排序。文件變 10 倍大、時間約 10 倍,不是平方。 記憶體主要是候選 Map,經 min_freq 過濾後規模有限。

設計理念對照

面向傳統 MarkdownHTMLMarkdown+
對 AI友善但難結構化tag 噪音、token 暴漲block-addressable + 受控 metadata
對人類陽春漂亮但 source 不可讀viewer 渲染漂亮 + source 仍可讀
新 dialect無(N/A)無 — 仍是合法 CommonMark
圖片路徑或 base64常用 base64 inline強制路徑,禁 base64
互動 UI無需手寫 JS + CSS由 viewer 從 metadata 自動推導