last hop

規格的邊界:不可編譯的剩餘意圖與合法的不知道

導言

一個醫院掛號系統的需求寫著:「急症患者應優先處理。」團隊把它細化成生命徵象欄位、嚴重度分數、狀態轉移與驗收案例。所有測試通過後,系統遇到原規格沒有同時考慮的情境:一名高風險孕婦、一名呼吸困難兒童與大量傷患事件同時到達。此時「優先」不只是排序問題,而是臨床政策、資源配置與公平原則之間的衝突。

規格並沒有因此變得無用。它仍可精確處理大量常態情境,也能保存已經作出的政策選擇。錯誤在於把「能執行的規則集合」誤認為「目的本身已被完全消化」。需求工程中,verification 問產物是否按照規格被正確建造;validation 則問規格與產物是否滿足預期用途。NASA SWE-055 把需求 validation 定義為確保軟體能在客戶環境中依預期運作,並要求在生命週期中使用客觀證據與利害關係人參與(NASA/SWE-055 Requirements Validation)。

本報告把規格沒有承載、尚未承載,或不應被預先封死的部分稱為剩餘意圖(Residual Intent) 。它包括未知情境、價值衝突、例外裁量、分布改變,以及只有現場責任者能取得的資訊。成熟系統的目標不是假裝剩餘為零,而是讓它可見、可升級、可留下理由,也能在重複出現後重新制度化。

[!IMPORTANT] 剩餘意圖 (Residual Intent): 指規格未能承載、尚未承載或不應預先封死的決策空間,包含未知情境、價值衝突與現場例外裁量。

分析

一、規格是情境空間上的偏函數

令所有可能營運情境構成集合 \Omega ,允許動作構成集合 A 。理想政策可被想像成全函數(Total Function) :

[!IMPORTANT] 全函數 (Total Function): 在其定義域的所有可能輸入上皆有明確定義與輸出之函數。

f:\Omega\rightarrow A.

但實際規格只對已辨識且已決定的情境子集 D\subseteq\Omega 給出動作:

s:D\rightarrow A.

剩餘情境至少包含 R=\Omega\setminus D 。此外,即使 x\in D ,仍可能同時觸發兩條互不相容的政策。若適用規則集合為 P(x) ,衝突集合可寫成:

C=\{x\in D\mid \exists p_i,p_j\in P(x),\ p_i(x)\neq p_j(x)\}.

因此需要升級的並不只是「沒有規則」的 R ,還包括「規則彼此不能共同滿足」的 C 。把未涵蓋情境交給模型猜測,等同在沒有授權的情況下任意延伸 s 的定義域;把衝突情境交給固定優先序,則是在沒有價值判斷的地方偷偷寫入價值判斷。

二、從目的到程式是多次有損投影

每一次工程轉譯都會保留某些資訊、丟失另一些資訊。這不是自然語言獨有的缺陷;形式規格同樣必須先決定要形式化哪些變數與關係。

圖中虛線不是待消滅的技術債(Technical Debt) 。當情境分布會改變、錯誤代價高、或多個價值無法被單一指標代表時,保留受控裁量比捏造永久規則更精確。真正的技術債 是沒有升級路徑,迫使執行者把「系統不知道」偽裝成一個確定答案。

[!IMPORTANT] 技術債 (Technical Debt): 程式碼中為求快速交付而妥協、待重構與修復的設計或品質缺陷。

三、把急症排序走一遍

以下表格把輸入、規則判定、狀態轉移與最終處置放在同一條線上。它顯示自動化的邊界應由可判定性與政策衝突共同決定,而不只由模型信心決定。

邊界輸入可取得觀察關鍵判定狀態轉移最終處置
嚴重度 9,無政策衝突生命徵象完整命中穩定門檻RECEIVED → PRIORITY自動優先
嚴重度 5,資料缺漏無法確認關鍵生命徵象可觀測性(Observability) 不足RECEIVED → NEEDS_ASSESSMENT由臨床人員補評估
嚴重度 9,同時命中兩條優先政策規則各自成立動作衝突RECEIVED → POLICY_CONFLICT升級至政策 owner
大量傷患事件資源與到達率異常營運模式已改變NORMAL → INCIDENT_MODE交由當班指揮體系
同類衝突一月出現 40 次有完整決策紀錄已非罕見例外EXCEPTION → POLICY_REVIEW修訂政策與測試

[!IMPORTANT] 可觀測性 (Observability): 軟體系統或程式邏輯的運作狀態被外部工具或監控機制感知、偵測與度量的難易程度。

「升級」不是把所有困難交給一個人。每一個升級狀態都要有觸發條件、可決策角色、回應時限、保守預設與留痕要求。否則它只會把規格黑洞換成人工佇列。

四、讓不知道成為合法狀態

下列程式把未知、資料不足與政策衝突做成不同結果。它不計算臨床倫理,只驗證系統不會把這三種情況靜默壓成一般排序。

from dataclasses import dataclass
from enum import Enum, auto

class Route(Enum):
    PRIORITY = auto()
    QUEUE = auto()
    NEEDS_ASSESSMENT = auto()
    POLICY_CONFLICT = auto()
    INCIDENT_COMMAND = auto()

@dataclass(frozen=True)
class TriageInput:
    severity: int | None
    policy_actions: frozenset[str] = frozenset()
    mass_casualty: bool = False

def route(case: TriageInput) -> Route:
    if case.mass_casualty:
        return Route.INCIDENT_COMMAND
    if case.severity is None:
        return Route.NEEDS_ASSESSMENT
    if len(case.policy_actions) > 1:
        return Route.POLICY_CONFLICT
    return Route.PRIORITY if case.severity >= 8 else Route.QUEUE

assert route(TriageInput(9)) is Route.PRIORITY
assert route(TriageInput(None)) is Route.NEEDS_ASSESSMENT
assert route(TriageInput(9, frozenset({"maternal", "pediatric"}))) \
       is Route.POLICY_CONFLICT
assert route(TriageInput(5, mass_casualty=True)) \
       is Route.INCIDENT_COMMAND

程式中的列舉型別具有認識論意義:NEEDS_ASSESSMENT 表示觀察不足,POLICY_CONFLICT 表示價值或規則衝突,INCIDENT_COMMAND 表示原本規格的營運前提失效。若三者都叫 manual_review,組織就無法知道應補資料、修政策,還是切換指揮模式。

五、剩餘意圖必須受治理,而不是無限自由裁量

以下診斷矩陣用可觀測性 與價值衝突兩軸決定合理處理方式。

可觀測性價值衝突底層病灶脆弱做法嚴格防線
高低規則穩定且可判定每次都人工處理自動規則、測試與監測
高高資料足夠但政策相撞用模型分數偷偷排序價值具名政策 owner、版本與申訴
低低缺少關鍵觀察用預設值補洞補資料、保守降級、標記不確定
低高既看不清又涉及價值讓生成器合理補完停止自動決策並升級

矩陣也限制了「剩餘意圖 」的使用。團隊不能因為某問題困難,就永久宣稱它只能靠直覺。若同類裁量反覆發生、理由逐漸穩定,而且輸入可被觀測,就應把它回寫成政策、資料需求與驗收案例。反之,罕見且高衝突的情境可能應永久保留人類指揮,而不是追求百分之百自動化。

六、完整性不是列舉更多案例,而是封閉決策責任

規格完整性常被理解成「再多寫一些 edge cases」。這只能處理已想像到的缺口。更成熟的完整性至少包含四層:

  • 行為完整性(Behavioral Completeness) :已定義的情境都有可判定結果。
  • 觀察完整性(Observational Completeness) :作出判定所需的資料真的可取得,缺漏有顯式狀態。
  • 衝突完整性(Conflict Completeness) :多規則同時成立時,有衝突偵測與授權角色。
  • 生命週期完整性(Lifecycle Completeness) :例外決定會留下理由,並有條件地回寫成新政策。

[!IMPORTANT] 行為完整性 (Behavioral Completeness): 指系統在已定義的情境集合內皆具備可判定且明確的執行結果。 觀察完整性 (Observational Completeness): 指作出工程判定所需的觀測資料具備客觀可取得性,且資料缺漏時具有顯式狀態。 衝突完整性 (Conflict Completeness): 指多項業務或安全規則同時命中且衝突時,具備機械化的衝突偵測與具名授權裁決機制。 生命週期完整性 (Lifecycle Completeness): 指例外裁決與升級處理必須保留結構化理由,並具備回寫為未來新政策的閉環流程。

這四層不保證系統永遠正確,但會封閉「下一步由誰處理」。未知世界仍然存在,責任不再消失。

反思

最強反方是,「剩餘意圖 」會成為拒絕精確化的藉口。只要團隊把模糊處都標成需要判斷,就能逃避設計與測試。這個風險很真實,所以剩餘意圖 不能只是一段散文。它必須落成可觀察的觸發器、有限的決策角色、保守預設、回應期限、理由紀錄與重新制度化門檻。沒有這些欄位的「人工判斷」不是邊界,而是責任真空。

另一個反方是,自然語言本身可以很嚴謹,形式模型也可能錯得很精確。完全正確。問題不在媒介,而在真值來源、可追溯性與拒絕條件。自然語言需求可以連結到利害關係人、使用場景與驗收資料;形式規格若把錯誤前提寫成公理,則只會更可靠地推出錯誤結論。

第三個邊界是封閉微世界。封包解析、編碼格式或小型狀態協定若具有有限且可列舉的狀態空間,形式規格應盡量吞掉剩餘意圖 ,模型檢查也能提供很強保證。不能因開放社會技術系統(Sociotechnical System) 存在價值衝突,就把所有軟體都描述成不可規格化。

[!IMPORTANT] 社會技術系統 (Sociotechnical System): 由技術元件與組織安排共同構成、必須整體運作才產生價值的系統。

最後,「人類判斷」不必永遠由同一個職稱完成。臨床例外、法遵衝突、營運事故與產品取捨需要不同權威。把它們全送給「human reviewer」,仍然是在用一個空泛角色隱藏剩餘意圖 的種類。

結論

規格的成熟,不是宣稱自己已代表全部意圖,而是同時精確描述可自動處理的區域與不可自動處理的邊界。把規格視為偏函數(Partial Function) ,可以清楚區分三種情況:定義域內的穩定規則、觀察不足的未知情境,以及規則彼此衝突的價值判斷。

[!IMPORTANT] 偏函數 (Partial Function): 僅在輸入定義域的某個真子集上有定義的函數;當面對未定義的輸入時將產生未定義行為或靜默錯誤。

可攜帶的原則是:

  • 允許系統回傳「不知道」,但必須說明是哪一種不知道。
  • 為未知、資料不足、政策衝突與營運模式改變設置不同狀態。
  • 反覆出現且逐漸穩定的裁量,應回寫成政策與測試。
  • 罕見、高代價且高衝突的情境,應保留具名升級而非由模型補完。

真正危險的模糊不是文件尚未寫完,而是系統把未被代表的意圖靜默轉換成了一個看似確定的答案。