跳至主要内容

RFC 2026-10-10-audit-persistence-failure-isolation: 審計事件預設非同步 JDBC 持久化與失敗隔離

狀態:accepted;建立/提交:2026-10-10;接受決策:2026-10-11;決策者:Jason Lin;目標版本:appfuse-server@4.0.0-alpha.33。完整修訂稿已接受:可停用、非同步、允許遺失,預設沿用下游既有 DataSource,以 JDBC adapter 背景批次寫入,包含本文的接線、批次邊界、生命週期與故障處置設計。取代原先同步 REQUIRES_NEW 提案,不另衍生 ADR。實作工作樹已於2026-10-11通過四輪人審,已發布 alpha.33;FU-136 的真實 MySQL 健康路徑已另行驗證,alpha.32 及更早版本不具備本文的新契約;本人已補充裁決 BUSY 可遺失及開關操作紀錄同樣失敗隔離,見最新 Decision Log。

摘要​

第一階段以審計失敗不阻斷業務交易為優先。交易端僅檢查審計開關、擷取事件快照並嘗試非阻塞入列;背景工作者透過儲存 adapter 寫入,使用自己的交易,不加入或暫停呼叫端的業務交易。佇列滿、admission gate 競爭(BUSY,即使容量未滿)、工作者不可用或寫入失敗時可遺失事件,不回到交易執行緒同步寫入,也不承諾可靠遞送。

預設儲存方式是 JDBC adapter,沿用下游既有的預設 DataSource,降低接入與維運成本;背景採批次 INSERT,保留指定其他 DataSource 及擴充其他儲存 adapter 的能力。這是交易邊界與呼叫等待的隔離,不是共用 CPU、記憶體、連線池或資料庫資源的完全隔離。

本開關僅針對 Spring Boot AuditEvent 事件紀錄。安裝 audit feature 後預設啟用,支援啟動設定、程式介面與專用 Actuator 端點切換。關閉後略過新事件、清空尚未寫入的事件,讓已開始的資料庫批次完成或失敗後結束;不強制中斷其交易,不切換到 in-memory repository,既有歷史資料不因關閉而刪除。本案不改變 JPA Auditing 狀態欄位或 optional Entity history 的業務交易契約。

動機​

使用場景​

登入、帳號鎖定、設定變更及退款等操作會發布審計事件。業務操作應依自身條件完成,不因審計資料庫離線、批次失敗或審計工作者停止而被中止或標記 rollback-only。應用可在故障或維運期間關閉事件紀錄,並在執行中重新開啟。

下游最簡單的接入方式應沿用已配置的資料庫連線,無須為第一階段另建審計資料庫。需要更強資源隔離時,可明確指定獨立 DataSource;需要其他查詢或分析能力時,可另接儲存 adapter。

目前的限制與原提案​

  • 查核基準:消費端固定依賴 appfuse-server:4.0.0-alpha.27,已查核 JAR SHA-256:4715b6d6085e620b57c390a875c2658e808627a93de68d00d59185770cc98374;本機框架原始碼版本為 4.0.0-alpha.29。
  • 現有 API 與實作:PersistentAuditEventRepository<T> 使用應用擁有的 JPA repository 與 Entity factory,提供兩參數及明確指定 transaction manager 的三參數建構子。add(AuditEvent) 回傳 void;目前逐筆呼叫 repository.save(),並於交易提交前 flush。
  • 現行交易語意:無外層交易時建立可寫交易;唯讀外層採 REQUIRES_NEW,可寫外層採 REQUIRED;失敗記 WARN 並向外傳遞。審計可能與業務共同回滾,或因例外中止呼叫流程。
  • 原提案與延後原因:原稿在呼叫端同步執行 REQUIRES_NEW,於整個 execute 外捕捉 RuntimeException。首次審議發現 suspend/cleanup/resume 故障仍可能影響外層資源,且 rollback 故障的框架日誌安全尚未釐清;維護者正式決定 Deferred。詳細歷史保留於 Decision Log。
  • 本輪修訂:背景工作者不承接呼叫端 transaction context,取代在業務執行緒暫停/恢復外層交易的設計。JDBC 的輕量寫入與批次控制適合新增為主的事件,但「JDBC 必然比 JPA 快」不是本案保證;Hibernate 也可使用 JDBC batching。

建議設計​

寫入流程與責任​

  • 事件入口:Spring Boot 自動審計與應用自訂事件均經同一個受開關及佇列控制的 AuditEventRepository,包含直接呼叫 add() 的路徑。
  • 交易端:不取得審計資料庫連線,不等待寫入確認,不因佇列滿而等待空位,也不等待 admission gate。tryLock 競爭即以 BUSY 略過,容量未滿不代表每筆必定接受。禁止 CallerRunsPolicy 或其他回到呼叫端執行寫入的 fallback。
  • 事件快照:入列前固定事件時間、principal、type 與安全 payload;需脫離可變來源,不能只有淺拷貝外層 Map。不得交給背景工作者 lazy Entity、尚未提交的業務列或呼叫端的 thread-local transaction/SecurityContext/tenant context。必要的應用身份與租戶資訊由應用轉為允許保存的明確值。
  • 背景工作者:以有界批次與自己的短交易寫入。批次大小、最長等待時間、佇列容量及工作者數量受限;本稿在「工程設計」提供可配置的初始值。資料庫等待、timeout 及 rollback 處理均留在工作者。
  • 儲存 adapter:負責後端的寫入與批次策略;事件入口、開關、佇列及失敗隔離由框架共用。第一階段提供 JDBC adapter,其他後端只保留擴充點。

一般 Spring 交易 context 綁定執行緒,不會自動傳到新執行緒;本設計仍須以接線與測試確保審計工作者不攜帶呼叫端交易。參見 Spring Transactional 文件及工作者與拒絕策略。

API 設計與接線​

沿用 Spring Boot 的 AuditEventRepository 作事件入口,add(AuditEvent) 維持 void。它返回只表示本次入口處理完成,不能代表事件已持久化。以下為已接受的 adapter 介面形狀,尚非已發布 API;套件與完整建構子於實作時依本設計落定。

public interface AuditStorage {
void writeBatch(List<AuditEventSnapshot> events);
List<AuditEventSnapshot> find(String principal, Instant after, String type);
}

// payload 在入列前固定為 JSON 字串,不保留可變物件圖。
public record AuditEventSnapshot(
UUID id,
Instant timestamp,
String principal,
String type,
String dataJson) {}
  • 預設接線:使用下游既有、可唯一識別的預設 DataSource;若多個 DataSource 沒有明確預設,不任意選一個。允許明確提供專用 DataSource;JDBC 工作者直接向選定來源取得自己擁有的連線,不經會承接 thread-bound 連線的 transaction-aware proxy。
  • JDBC adapter:以自己擁有的 Connection 與 PreparedStatement 參數化 INSERT、addBatch/executeBatch 實作,明確控制 commit、rollback、狀態還原及安全歸還;不把普通 JdbcTemplate.batchUpdate 或 TransactionTemplate.execute 返回視為已證明連線安全。批次減少資料庫往返,但實際收益依 driver、批次、提交及索引成本而異,沒有固定倍數保證。參見 Spring JDBC 批次寫入與 Hibernate batching。
  • 框架邊界:框架不宣告具體 Entity、不自動建表、不假定 tenant 欄位。應用擁有 schema、欄位映射與 SQL 方言;參考實作的 audit_event 五欄映射可作 JDBC 接線預設,其他表名及欄位由應用明確提供,詳見工程設計。
  • 啟用開關:安裝 feature 後預設啟用,支援啟動設定、程式介面與專用 Actuator 端點,入口對所有事件共用。端點授權由應用既有 Actuator 政策擁有,讀取使用 actuator:read,異動使用 actuator:write;不新增 audit 專用 Authority。Boot 的 management.auditevents.enabled 只控制相關自動配置,不能獨自保證直接 add() 或 runtime 切換的完整契約;與 Boot listener 的接線見工程設計。
  • 查詢:由同一儲存 adapter 承接 find(principal, after, type),保留 null 條件不篩選、after 為排他界線及事件時間排序的既有語意;principal 篩選與寫入使用相同的超長值雜湊規則。查詢已持久化資料,不能為了立即讀到事件而等待清空佇列;查詢失敗回報給查詢呼叫端,不偽裝成空清單。隔離保證只適用於事件寫入 add();同步 find() 可沿用 JDBC 查詢及呼叫端的 thread-bound 連線,其等待或失敗仍可能影響查詢呼叫者與該交易。

工程設計:接線、預設與生命週期​

以下設計原由主 session 依既有 feature/provider 接線、audit_event schema 與 Actuator 集中授權提出,已隨完整修訂稿獲維護者接受,包含設定初值、API 形狀及 provider 破壞性遷移。這是待實作契約,不表示相關型別或功能已可使用。

接線形狀:框架提供 AsyncAuditEventRepository、AuditStorage、JdbcAuditStorage、AuditWriteSettings 與欄位映射型別,均為 capability,由 app feature 明確建立。audit feature 是唯一的 AuditEventRepository bean 作者,同時發布程式控制介面及 Actuator adapter;不在 jar 自動掃描應用 Entity。

// 下列為待實作的接線形狀,非目前已存在的建構子。
new AsyncAuditEventRepository(
new JdbcAuditStorage(dataSource, applicationAuditMapping),
auditWriteSettings);

Provider 收斂:沿用 audit feature 的單一 provider 結構,但儲存接點改為回傳 AuditStorage 的 AuditStorageProvider,由 feature 統一包成上述非同步 repository。不能讓 provider 自行提供任意 repository 而繞過共同開關/佇列。既有 AuditEventRepositoryProvider 與 AuditPersistenceConfig 必須遷移;JPA repository/Entity factory 不再是新版 feature 的寫入依賴。本設計保留原 JPA 公開型別供既有應用自行遷移,不將舊同步 repository 接入新版 feature,也不把新隔離保證套用於直接使用舊類別的接線;不新增舊模式配置 enum。發布說明須明列這個界線與新 provider 的破壞性變更。

資料映射:參考實作沿用 audit_event:id 是 canonical UUID 字串、principal 是操作者、event_type 是類型、event_data 是 JSON 字串、event_at 是事件時間。UUID 在建立快照時產生,沿用目前超長 principal 的安全雜湊規則;JSON/事件型別驗證失敗略過單筆。JDBC 寫入及查詢共用應用明確提供的欄位映射,值使用 PreparedStatement 參數,不把事件內容拼進 SQL。DDL/索引/歷史資料由應用擁有;對既有 schema 以 JDBC type、UTC 時間往返及 JSON 測試證明可沿用,不靠欄位名字推論相容。

開關與端點:啟動設定 app.audit.enabled=true,Actuator id 為 auditcontrol。預設路徑的 GET /actuator/auditcontrol 讀取 enabled、工作者狀態、queue/in-flight 與安全失敗計數;POST 同一路徑接受 { "enabled": false } 或 true,與程式介面共用同一控制物件。runtime 狀態不回寫設定檔,重啟沿用啟動值;端點實際路徑由 Boot 的 base path/path mapping 解析,exposure 隨 feature 配置,授權沿應用既有集中政策。

開關操作紀錄:實際 enabled 值改變時,以獨立有界操作 queue 交給既有單一工作者,背景輸出時間、操作者與前後狀態的 INFO 應用日誌,不寫入 audit_event。事件入口關閉仍嘗試記錄,不清空操作 queue;同值呼叫、FAILED/STOPPING/CLOSED 拒絕的切換不產生成功紀錄,啟動設定及停止不冒充人工切換。HTTP adapter 以 ActingContext.current().getActor() 取得真實操作者 principal;模擬時另記 getSubject() 有效身份,A 模擬 B 的操作記為 principal=A/subject=B,純代理不另記 subject。程式介面保留相容 default overload setEnabled(boolean, String),新增相容三參數 overload 提供可選模擬 subject(非模擬傳 null),原單參數使用 (unspecified);不讓背景工作者繼承 SecurityContext。

操作 queue 與事件 queue 各自使用 queue-capacity 上限,另可有一筆操作及一個事件批次處理中;每輪最多輸出 batch-size 筆操作,logger 在 gate 外執行。沿用控制變更的短 gate 協調,不增加記錄完成等待;資料庫/日誌 I/O 都在背景。工作者卡在資料庫或 appender 時兩個 queue 皆可能滿而遺失;沒有重試、同步 fallback 或可靠保存。停止/工作者終止丟棄待記操作,已開始的 logger 可能在 close 返回後結束。logger RuntimeException 增加 CONTROL_LOGGER_FAILED,停止操作 INFO 與診斷 WARN 兩條共用 logger 的路徑,避免遞迴故障 logger;開關仍正常生效,普通日誌失敗不向控制/業務呼叫端傳遞。

操作 principal 及可選 subject 各最多取前100字元,超長加 [truncated];控制字元、行分隔、引號及反斜線替換成 ?。這是有界診斷識別,截斷/替換可能碰撞,不是完整身分憑證;不帶 payload、token、SQL 值或原始例外。CONTROL_ACCEPTED/CONTROL_LOGGED/CONTROL_DROPPED 可查;LOGGED 僅代表 logger 呼叫返回,不保證 appender 保存,亦不偵測所有級別過濾或內部丟棄。操作日誌的存取、路由及保留期由應用擁有;停用期間沒有完整 acting 軌跡,可靠追責須另案設計。

本開關不能直接綁定 management.auditevents.enabled。即使 app.audit.enabled=false 啟動,事件入口及 Boot listener 的接線仍保留,以便 runtime 重新開啟;listener 與直接 add() 都交給共用 gate 略過事件。若下游另外關掉 Boot auto-audit,應明載其來源在 runtime 不會憑空重建,不能宣稱僅打開本開關就恢復所有自動事件。

可配置的初始值:以下用於第一階段的有界資源配置,不代表吞吐量/延遲保證;不新增下游壓測義務。

設定預設初始值用途
queue-capacity1,000 筆事件及操作 queue 各自的上限;滿時丟棄,不等待空位
batch-size100 筆每次資料庫交易的最大事件數
flush-interval1 秒低流量下形成批次的等待上限;不代表必定於一秒內落表
worker-count第一階段固定 1限制同時寫入與共用連線池競爭
max-payload-bytes64 KiB/筆JSON UTF-8 上限;編碼過程即限制輸出,超過則略過,不先建立無界字串
statement-timeout3 秒適用於支援 query timeout 的 JDBC statement,不代表取連線或 commit 也受此上限約束
shutdown-wait5 秒停止服務時等待已開始批次的上限,不是資料庫硬中止保證

設定值必須正值且批次不得大於佇列容量;工作者數量第一階段不開放增加。共用 DataSource 的取得連線/driver network timeout 沿用應用設定,adapter 不私自改動共享連線池,也不關閉由應用擁有的 DataSource。

切換生效:gate 以短臨界區/世代識別協調入列、開始批次及關閉;DB I/O、JSON 編碼、日誌與等待不在此鎖內執行。事件入口兩次以 tryLock 嘗試取得 gate,任一次競爭都可略過並增加 BUSY,不等待鎖;先取得 enabled 與世代,再於鎖外建立快照,入列時重新檢查世代及生命週期。工作者在同一 gate 內驗證世代、取出固定批次並標記 in-flight;標記 in-flight 是「批次已開始」的唯一生效點,釋鎖後才取得連線並寫入。即使尚未取得連線,此批次也可於關閉返回後完成。關閉使舊世代失效,丟棄所有尚未標記 in-flight 的事件;重新開啟不能復活舊世代快照或批次。

正常停止與擁有者:feature 建立的 repository 實作 SmartLifecycle,擁有單一私有 daemon 工作者;close() 與 Spring 停止共用冪等流程。進入 STOPPING 即使世代失效、清空待寫,拒絕新事件及重新啟用;至多等待 shutdown-wait 後轉為 CLOSED 並完成停止回呼。STOPPING/CLOSED 為終止狀態,start()/enable 不會重啟該實例。逾時殘留的 daemon 工作者只能完成既有批次及處置自己持有的連線,不再取新批次;狀態保留 in-flight 提示,不把停止回呼完成等同 driver 已終止。生命週期須在應用 DataSource 銷毀前開始停止;不關閉共用 DataSource,不承諾硬中止 driver 或逾時後資料必不落表。

故障與恢復:一般批次失敗且 rollback、statement 清理及連線狀態還原均確認正常時,丟棄該批並安全歸還連線,後續事件可用新取得的連線繼續;這不是重試失敗事件。commit 結果未知、rollback/清理/還原失敗等不能證明連線可安全重用的情況,進入 FAILED、停止接收並清空待寫,先淘汰或隔離連線,不能只停止工作者後照常歸還連線池。第一階段 FAILED 不自動重建,以應用重啟恢復;enable 不會把它偽裝成已恢復。Error 不納入恢復保證。

連線處置:JDBC adapter 使用與目標 DataSource 相符的連線處置能力,預設提供 HikariCP 支援;其他 pool 或包裝來源須明確提供可驗證的處置 adapter,無法辨識其擁有者時屬無效接線,啟動 fail-fast,驗證不需先連線。持有原始借出的 pool lease,只有確認正常清理才能走一般歸還;不安全 lease 使用其所屬 pool 的 eviction 能力。不能把任意 proxy 的 close()/abort() 或 eviction 方法正常返回當作已淘汰的通用證明。若處置失敗或結果無法確認,保留 lease 隔離、不執行可能歸還 pool 的 close;固定單一工作者使隔離 lease 至多一個,並回報 FAILED/quarantined 安全狀態,交由維運修正及重啟。這可能占住一個共享連線,不宣稱資源零影響;不得以關閉共享 DataSource 作補救。

這個界線來自已查核的 Spring 7.0.2 連線清理:狀態還原失敗可能被記錄後仍釋放連線;以及 HikariCP 7.0.2 eviction:處置與 lease、pool 狀態相關。實作須以實際支援版本證明壞連線不再被借出,不能只斷言呼叫了淘汰 API。

安全診斷與日誌:事件入口、快照與編碼失敗只更新固定安全分類的計數,不在業務執行緒呼叫 logger,也不保存原始例外/cause 供背景列印;由私有工作者背景彙整診斷。日誌的普通 RuntimeException 由背景邊界隔離並更新安全計數,不再呼叫同一故障 logger;自訂 appender 阻塞可能拖慢排空而導致丟棄,不能因此回到呼叫端記錄或寫入。日誌沒有逐事件可靠遞送保證,安全計數可由控制端點讀取。預設 JDBC 寫入直接擁有連線,不使用會把原始 callback throwable 印出的 TransactionTemplate 路徑;實作仍須列明 JDBC、pool、driver logger 及必要設定,捕捉 JSON、batch、commit、rollback、還原與淘汰故障的實際輸出。自訂 driver logging、SQL bind TRACE 或應用自行記錄原始事件的行為須明載限制;不承諾攔截任意第三方 logger、appender 或 JVM 致命錯誤。

行為與失敗契約​

情境第一階段契約
審計關閉,新事件送入不入列,不寫資料庫或記憶體,不使用 in-memory fallback
執行中關閉清空尚未寫入的事件;已開始的資料庫批次完成或失敗後結束,不強制取消其交易
審計開啟,gate 可取得且佇列有容量擷取快照並嘗試非阻塞入列;仍需二次 gate/世代檢查,不保證接受,不等待背景 commit
admission gate 競爭(即使佇列未滿)略過事件並增加 BUSY;業務執行緒不等待 gate,不轉為同步寫入
實際開關狀態改變背景 INFO 嘗試記時間/操作者/前後狀態,事件關閉仍嘗試;操作 queue 滿、工作者不可用、停止或 logger 失敗可遺失,普通日誌失敗不影響切換或交易
單筆事件驗證、快照或 JSON 轉換失敗略過該事件並留下安全診斷,業務繼續;不將事件資料錯誤送回呼叫端
佇列滿或工作者不可用可丟棄事件,以安全分類/計數診斷;不阻斷業務,不轉為同步寫入
背景連線、轉換、batch INSERT 或 commit 失敗由工作者處理並記安全診斷;不將持久化例外送回原業務呼叫,不自動重試
批次 commit 結果未知記為未確認,不斷言全部未落表;不自動重試,以免重複寫入
背景 rollback/cleanup 失敗FAILED 停止接收;不安全連線淘汰,無法確認則保留 lease 隔離,不照常歸還 pool;依工程設計處置
業務自行失敗或原本 rollback-only維持業務原有失敗規則,不由審計改寫結果
業務回滾前已發布事件事件仍可能落表,記錄曾被觀察/發布,不代表業務已成功提交
程序異常終止記憶體中尚未持久化的事件可以遺失,不承諾重啟恢復

關閉與開始批次的生效邊界由同一 gate 的 in-flight 標記決定。尚未標記的事件同樣丟棄;已標記批次可以在關閉返回後才取得連線、完成寫入。不承諾「關閉返回後絕無新增歷史資料」。重新開啟不恢復已丟棄事件,切換前仍在建立快照的呼叫也不能於重新開啟後補入舊事件。

啟動接線無效時 fail-fast,例如多個 provider、DataSource 選擇不明或非法容量;必須修正配置後啟動。資料庫暫時離線、資料表不可寫及 runtime 事件資料錯誤則按允許遺失契約處理,不作啟動時必須可連線的前提。致命 Error 不納入安全繼續保證,不用 blanket catch 掩蓋 JVM 致命錯誤。

安全、事件語意與隔離界線​

背景警告僅含安全失敗分類與框架元件識別,不輸出 principal、payload、token、個資、原始 SQL 參數或 throwable message。開關操作 INFO 日誌只額外包含上述有界、安全處理的 principal、可選模擬 subject、時間與前後狀態,存取權限由應用擁有;不能據此允許將事件 payload 或 token 列印。驗證涵蓋實際生效的工作者、JDBC、pool 與 driver logging,包含 rollback/淘汰失敗及 appender 故障;依工程設計列明生效版本與設定。

應用擁有事件發布時機、結果分類與授權。若 SUCCESS 必須證明業務已提交,應用應在成功 commit 後發布;第一階段允許遺失,即使提交後發布也不保證事件必定保存。新增的審計開關不關閉授權檢查、不影響業務資料的原子性。

共用預設 DataSource 仍會競爭連線、資料庫 CPU、磁碟與記憶體。框架須限制工作者並行與批次、保留獨立 DataSource 的選擇;獨立連線池及獨立資料庫實例可逐步加強資源隔離。本案不宣稱效能零影響,不設定效能證據契約或要求下游提供壓測報告。

與既有行為的相容性​

行為變更:是。 現行同步 JPA 持久化改為非同步寫入,add() 返回不再代表此次持久化完成,立即 find() 可能尚未查到新事件。依賴同一業務交易 commit/rollback 或立即可查的消費端必須調整。

現有兩個 PersistentAuditEventRepository<T> 建構子要求 JPA repository/Entity factory,無法僅升級依賴就自然變成 JDBC 接線。工程設計保留舊 JPA 類別,但新版 feature 的 provider 改為儲存 adapter 接點,參考實作改接 JDBC 與共用非同步 repository;舊 JPA repository 不作新版 fallback。這是明確的接線遷移,不把目前草案寫成已可直接使用的 API。

實作工作樹依本文開發並已通過人審,真實 MySQL 健康路徑已另行驗證,已發布 alpha.33;其餘資料庫認證仍由 FU-136 追蹤。具體 schema 與歷史資料是否可沿用,須以既有欄位及新 JDBC 映射核對;不預先承諾無遷移。升級相容性不限制這次設計,但要提供可執行的消費端接線與行為遷移說明。

實作與驗證建議​

候選變更範圍​

  • appfuse-server audit capability:事件入口、runtime gate、有界佇列、背景批次工作者、儲存介面與 JDBC adapter;公開類別與舊 sink 依工程設計遷移。
  • 下游/參考實作的 audit 配置:唯一 repository bean、預設 DataSource 與應用擁有的 SQL 映射,以及新接線範例。
  • 框架功能測試、audit 指南與 CHANGELOG:發布時載明延遲可見、允許遺失、開關範圍與資源共用限制。

功能測試策略​

  • 開關:啟動關閉及 runtime 關閉時新事件均不入列、不寫資料庫或 in-memory;重新開啟能接受新事件,包含 Boot 自動事件與直接 add()。
  • 切換邊界:以受控訊號安排建立快照、in-flight 標記、取得連線與 disable/enable 的競態;特別驗證標記後尚未取得連線的批次可完成,未標記批次丟棄,舊世代事件不會重新入列。正常停止不清空歷史資料,也不關閉應用共用的 DataSource。
  • 控制端點:讀取與異動分別驗證 actuator:read/actuator:write,並測試非預設 Actuator base path;回應不含事件 payload、連線資訊或原始例外。狀態的 enabled 與 FAILED 分開,不宣稱開啟即已恢復。
  • 操作紀錄:驗證已認證真實操作者、模擬時有效 subject(不冒稱操作者)、實際新舊狀態、關閉時仍背景記錄及同值不記錄;有界容量、停止丟棄、識別安全處理及 context 不繼承。以真實 appender 拋 RuntimeException/受控阻塞證明控制呼叫返回與業務交易提交,不同步 fallback,不遞迴操作 logger。
  • 啟動分類:無效 provider/DataSource 選擇/容量 fail-fast;不額外要求啟動時審計資料庫可連線或可寫。事件資料錯誤只略過單筆並留下安全分類。
  • 交易隔離:在無交易、唯讀及可寫業務交易中送事件,驗證資料庫取得連線及寫入都在工作者。以可控制的同步訊號阻塞工作者,業務仍能提交;以真實寫入失敗驗證無審計造成的 rollback-only。
  • 拒絕與容量:受控持有 gate,驗證容量未滿也可 BUSY,持鎖者未釋放時事件呼叫端即返回;佇列滿或工作者停止時丟棄,不在呼叫端寫入。驗證固定容量與批次上限,不用耗時斷言替代呼叫路徑證據。
  • 批次與故障:批次 INSERT、獨立提交、資料轉換/begin/rollback/statement cleanup/狀態還原故障及 commit 結果未知均有可辨識處置。不安全連線進入 FAILED;以真實支援 pool 與受控故障驗證 eviction 後不再借出,處置失敗時 lease 保留隔離、未歸還、無新批次,沒有關閉共享 DataSource。不假定一個批次失敗等同全部事件未落表。
  • 快照與日誌:來源含可變巢狀 payload 時,修改來源不能改變待寫事件;驗證不依賴 lazy Entity 或呼叫端 context。故障時檢查所有納入承諾的 logger 實際輸出,不洩漏原始 payload/例外訊息。以拋 RuntimeException 或受控阻塞的 appender 驗證 add() 不呼叫 logger,業務可提交,背景不遞迴記錄同一故障。
  • 接線與查詢:預設及指定 DataSource 有相符的連線取得/處置能力;多來源不任意選擇,非支援 pool 必須明確接線處置 adapter。以確定的工作者完成訊號驗證持久資料查詢,不加入每次 find() 清空佇列的同步等待;查詢故障確實回報給查詢者,不宣稱其享有 add() 的隔離契約。
  • 生命週期:驗證 Spring 正常停止、重複 close、有限等待逾時與 stop/enable 競態;STOPPING/CLOSED 不接收、不重啟,殘留 daemon 工作者不領新批次,停止回呼不無限等待,DataSource 由應用銷毀。FAILED 只以應用重啟恢復;程序崩潰不承諾恢復未落表事件。

以上是本案驗證策略;實作與測試證據由當輪審閱成果提供,第四輪人審已通過,發布及 FU-136 其餘資料庫驗證仍未完成,不能把 RFC 的 accepted 當作測試或發布完成。無業務 UI 變更,Visual/Accessibility 不適用;新增控制端點的狀態回應、切換行為與授權由上述功能測試驗證。

替代方案​

原方案 A:在呼叫端同步修正 REQUIRES_NEW​

沿用舊建構子,接入變更較小;仍有資料庫等待及業務交易 suspend/resume 的生命週期風險。首次 Deferred 針對此版本,後續確認的非同步方向取代其同步寫入設計。

原方案 B:應用自行組合 TransactionTemplate​

可用現有 Spring primitive 隔開同步資料庫交易,但重複維護接線,且無法移除業務執行緒等待、恢復外層資源及 logger 安全等問題,不採為第一階段預設。

原方案 C:保留舊預設,增加交易政策模式​

可支援多種共同回滾/獨立交易模式;本輪沒有此需求。已確認的啟用開關是控制是否記錄事件,不是切換交易政策的模式 enum。

修訂方案 D:非同步、可停用、允許遺失(本輪確認方向)​

原 D 將非同步、重試與 outbox 放在一起而排除。此輪僅採非同步、best-effort 的部分,使用 JDBC 批次寫入與既有預設 DataSource;不因此引入重試、持久佇列或 outbox。代價是延遲可見、待寫事件可能遺失,以及需定義背景生命週期。

預設使用獨立審計資料庫或專用後端​

獨立資料庫實例可加強資源隔離,ClickHouse/OpenSearch 可滿足不同分析/搜尋需求;但要求下游額外配置與維運,不符合最簡單的預設。保留 adapter 與指定 DataSource 的擴充能力,第一階段不交付這些專用後端。

不屬於本提案的範圍​

  • 可靠遞送、持久佇列、重試、outbox、exactly-once:第一階段明確允許事件遺失。
  • 強制共同回滾或依事件類型選交易政策:所有經本入口的事件共用非同步寫入契約。
  • 執行中更換儲存後端:runtime 切換只針對審計開關;adapter/DataSource 於接線時選擇。
  • JPA Auditing 與 Entity changeset history:維持原契約,不隨本開關停用或改為非同步。
  • 租戶 schema、Authority、root/acting scope、分區、保存期限、CSV 與業務事件映射:由應用擁有。
  • 新通用搜尋/cursor API、ClickHouse/OpenSearch adapter 的實作:僅保留擴充點。
  • 效能保證、基準報告及下游壓測義務:不設定新的效能證據契約;不宣稱 JDBC 固定加速倍數或共享資料庫零影響。

已確認的實作前決策​

維護者已接受完整修訂稿,實作前決策如下;既有審議與 Deferred 紀錄保留於 Decision Log。

項目已接受的契約
第一階段優先順序寫入失敗不阻斷業務,允許遺失;事件資料錯誤略過,啟動接線無效 fail-fast
開關預設啟用;app.audit.enabled、程式介面及 auditcontrol Actuator 端點;沿用集中維運授權
非阻塞 admission即使佇列未滿,gate 競爭亦以 BUSY 略過;業務執行緒不等待
開關操作紀錄實際切換嘗試背景 INFO 記時間/操作者/前後狀態;獨立有界 queue 不隨事件關閉清空,失敗不影響交易,可遺失且不保證完整追責
待寫事件生命週期關閉清空未開始批次的事件;同一 gate 的 in-flight 標記定義批次開始;世代檢查避免復活舊事件;停止有限等待且不重啟該實例
寫入與資源預設 DataSource、JDBC 背景批次、可指定其他來源;容量與時間初值依工程設計;不安全連線淘汰或隔離,FAILED 以應用重啟恢復
公開 API/遷移storage provider、不可變 JSON snapshot、應用擁有的五欄映射與舊 JPA 邊界;接受 provider 破壞性遷移
日誌安全入口只更新固定安全計數,背景彙整日誌;納入支援 logger 與雙重故障驗證,明列第三方 logging/致命 Error 的限制
正式決策Accepted;目標 appfuse-server@4.0.0-alpha.33;保留既有 ADR-013/017 關聯,不另衍生 ADR

本文實作與功能驗證已完成,並納入不可變版本 alpha.33;RFC 決策維持 accepted。消費端須依審計指南遷移接線,剩餘資料庫驗證仍由 FU-136 追蹤。

實作審閱結論(2026-10-11)​

Dev Lin 在第四輪確認通過:12 條意見中 10 done、2 declined 均已接受,無 open。 R3-01 已修正真實操作者/模擬 subject 的身份來源並補兩個 JWT HTTP IT;R1-01 一併結清。 本案及必要回歸共163項通過、1項 MySQL IT 因無 Docker 跳過;新增 audit capability JaCoCo 行覆蓋率93.50%、指令92.51%、分支81.02%。這是工作樹實作的人審結論,未發布。

  • 架構與刻意不改:第一階段穩定及不影響交易優先;R1-02 保留 tryLock/BUSY、不等待入列, 依 Jason Lin 本人裁決接受。既有 JPA API 維持同步契約;不新增可靠遞送、重試或 outbox。 取捨落於本文契約、ADR-013 R5 與 audit/acting 指南。
  • 遷移與身份語意:兩個 server source 的 Feature Changelog 承接 storage provider/JDBC/控制端點遷移; actor/可選模擬 subject 各有界安全處理,普通紀錄失敗不影響切換或業務交易。
  • 安全預檢的範圍:R1-06 declined 接受。作者 session 未提供 security-review skill,未宣稱已執行; 審閱方第2輪補跑該 skill,未發現信心 ≥ 8 的漏洞,第3/4輪人工複核操作紀錄及身份修正。 不將作者人工預檢當成 skill 報告,也不擴張為全產品安全保證。
  • 保留欠帳:FU-136 承接發布前真實 MySQL/UTC/Hibernate 歷史互通及 pool 驗證、後續多 driver 核對; FU-137(⭐)承接 Epic 0 完整性/100% 指標,由產品/維護者裁決。兩者不擋本次人審通過, 不把 MySQL 跳過當作通過,也不宣稱產品完整審計要求已對齊。
  • 發布界線:發布目標調整為 appfuse-server@4.0.0-alpha.33,原 alpha.30 已被遠端報表功能占用; 已發布 alpha.29 及參考 app 原釘 alpha.22 不具備新接線。RFC 保持 accepted,未改為 implemented。

發布前驗證(2026-10-11)​

同步遠端主線後,既有發布版號已到 alpha.32;原決策要求發布前核對版號是否占用, 本次依不可變 alpha 通道改用未占用的 4.0.0-alpha.33,保留下方原決策紀錄。

FU-136 要求的發布前 MySQL 健康路徑已完成獨立驗證:官方 MySQL 8.4.0 Linux binary、 Connector/J 9.5.0、HikariCP 7.0.2、JDK 25.0.3,JVM 時區 Asia/Taipei。 使用本輪 production classes 與預設 client-prepared statements,通過兩筆批次、UUID、中文巢狀 JSON、 UTC DATETIME(6) 微秒、排序及排他 after 查詢,並直接核對資料庫 UTC 欄位值;共享 DataSource 未被關閉。 驗證程序及輸出保存於執行環境 /tmp/AuditMySqlPublicationCheck.java、 /tmp/audit-mysql-native-validation.log。這是原 MySQL IT 相同健康命題的獨立執行, 不是把因無 Docker 跳過的 JdbcAuditStorageMySqlIT 改算為通過。

同步遠端主線後,框架完整 ./gradlew test(含各隔離與記憶體任務)共1,690通過、58跳過、0失敗; 跳過包含無 Docker/外部服務環境,以及8項要求 JDK 25.0.1 的舊 PDF bytes golden(本機為25.0.3)。 兩個參考 server 以 -PuseLocalFramework=true 重跑 audit、Actuator 授權、身份切換及架構回歸, tenant 65項、tenantless 63項均通過。完整文檔 lint、Javadoc/Storybook、production build 與 WAR 打包均成功。 執行結果保存於 /tmp/audit-publish-full-tests.log、/tmp/audit-publish-framework-test-summary.json、 /tmp/audit-publish-app-tenant-server-tests.log、/tmp/audit-publish-app-tenantless-server-tests.log、 /tmp/audit-publish-docs-war-prebuild.log。

Nexus 上傳停於 Gradle 的 credentials.username 缺值檢查,尚未上傳 artifact; alpha.33 POM 核對仍為404。本機未有 ~/.gradle/gradle.properties 或對應環境變數, 須補齊 nexusUsername/nexusPassword 後重建版本 commit 並接續發布。 版本檔與線上文檔站保留已發布 alpha.32;RFC 仍為 accepted,未標為 implemented。

Hibernate 歷史互通、MySQL 故障注入與其他 driver 認證仍由 FU-136 追蹤; 不因健康路徑通過擴大資料庫支援或持久化保證,FU-137 的產品決策也仍保留。

Decision Log​

以下保留各輪當時的狀態與判斷;現行決策以最新 Accepted 條目及 frontmatter 為準。

2026-10-11 — 發布 alpha.33​

  • 發布結果:Maven releases 已發布 appfuse-server@4.0.0-alpha.33;遠端 JAR 與本機產物 SHA-256 一致,POM 版號與非同步審計類別核對通過。
  • 發布前回歸:框架合計 1,710 項成功、58 項跳過,包含先前已通過且未改動的 27 項隔離測試;主套件重跑為 1,683 項成功。審計生命週期測試僅在前置確認入列,只允許 BUSY 有限重送;使用者人審通過,原案例 10 次獨立 JVM 重跑成功,結論記於 45d79f7c。正式事件入口仍不等待,BUSY 可遺失。
  • 驗證界線:不擴張為可靠遞送、資源完全隔離或多 driver 認證;FU-136/FU-137 保留。

2026-10-11 — Accepted(人審契約補充裁決)​

  • decided_by/決策者:Jason Lin。
  • decided_at/決策日期:2026-10-11。
  • 第 1 項本人原文:「接受 BUSY 可遺失,業務不等待」。本人回答的命題明列業務執行緒不等待 admission gate,容量未滿時鎖競爭仍可略過並增加 BUSY,並引用已展示的完整草稿 r3-decision-draft-5659942c1d72 的第 1 項。
  • 第 2 項本人原文:「2. 紀錄開關操作採用同樣原則,不影響交易。」此指示取代先前草稿第 2 項「不記錄」的建議;不宣稱本人接受舊草稿整份或不記錄方案。
  • 理由與範圍:第一階段先求穩定、審計失敗不影響交易。保留 tryLock/BUSY 的非等待入口;實際切換採背景最佳努力操作日誌,也允許遺失。主 session 依此授權落實既有工作者、獨立有界操作 queue、已認證 principal/前後狀態、普通日誌失敗隔離,具體上限及安全處理見正文;這些工程選擇不冒稱由本人逐值另行確認。
  • 對應人審意見:R1-01 改為實作背景操作紀錄,R1-02 保留 declined 的不等待取捨;R2-01 的失敗表與日誌契約依本人兩項裁決同步到 RFC/ADR-013 R5/指南。作者處置不等於審閱者通過。
  • 實作與相關 ADR:目標仍為 appfuse-server@4.0.0-alpha.30,既有 ADR-013/017 關聯不變,不另衍生 ADR;工作樹仍待 peer review/發布,不改為 implemented。

2026-10-11 — Accepted​

  • 決策者:Jason Lin。
  • 確認依據:維護者明示確認已展示的完整修訂稿(來源 revision 6d30b12f7c05),接受整份工程設計、目標版本及不新增 ADR 的選擇;本次只更新決策狀態與紀錄,未改變已確認的技術契約。
  • 理由:審計寫入失敗不應阻斷業務,具有跨應用的代表性;共用事件入口與可替換儲存 adapter 符合框架 capability/應用接線分工。採修訂方案 D 的非同步 best-effort 子集,以可關閉、有界佇列與預設既有 DataSource 的 JDBC 批次寫入滿足第一階段需求,無須引入重試或 outbox。provider 破壞性遷移與延遲可見、允許遺失的行為代價已明列並接受。
  • 接受範圍:本文完整工程設計,包含設定初值、storage provider 遷移、批次生效邊界、終止生命週期、不安全連線淘汰/隔離、背景安全診斷及相應驗證策略。兩位獨立 Codex 審議者複核後均支持修訂 D 並建議 Accepted,主 session 附議;正式決策由維護者確認。
  • 實作:預計納入 appfuse-server@4.0.0-alpha.30;發布前核對版號未被占用。
  • 相關 ADR:不另衍生 ADR;保留既有 ADR-013/017 關聯。
  • 目前交付狀態:僅完成 RFC 決策記錄,尚未實作或發布。功能測試與遷移驗證於實作時執行,完成發布後才更新為 implemented。

2026-10-11 — Under Review(非同步修訂稿並行審議與複核)​

  • 審議範圍:修訂方案 D 的非同步 best-effort 子集、預設 JDBC/DataSource、開關、provider 遷移、生命週期及失敗契約;沿用維護者已授權的並行 AI 審議。兩位獨立 Codex agent 使用相同模型,不代表跨模型共識;不沿用舊同步稿的方案 A 投票。
維度審議者 1審議者 2
建議方案修訂 D修訂 D
首輪主要缺口停止工作者不等於壞連線已隔離;入口 logger 仍可影響業務批次開始缺少唯一生效點;停止與工作者擁有者未明訂
修訂後複核兩項 major 已解除,無新 blocking/major兩項 major 已解除,無新阻擋缺口
完整稿決策建議AcceptedAccepted
目標版本由維護者正式確認由維護者正式確認
  • 本輪投票:修訂 D 2:0;補齊後的完整稿建議 Accepted 2:0。這是 AI 建議,不是維護者的正式決策,也不表示功能已實作或驗證通過。
  • 主 session defense — 審議者 1:同意連線處置缺口。僅背景化與 FAILED 無法阻止壞連線回到共享 pool,因此採明確擁有 Connection、正常清理才歸還、不安全 lease 淘汰或隔離的契約,並驗證實際不再借出。同意診斷缺口:入口只更新固定安全計數,背景處理 logger RuntimeException,並限制任意第三方 logging/致命 Error 的保證範圍;find() 明列不在 add() 隔離承諾內。
  • 主 session defense — 審議者 2:同意批次與切換競態缺口。以同一 gate 的 in-flight 標記作唯一起點、快照前及入列時核對世代,避免重新啟用復活舊事件。同意生命週期缺口:由 repository 的 SmartLifecycle 擁有私有 daemon 工作者,停止/close 冪等且終止、不重啟,有限等待不等同 driver 已結束,也不關閉共享 DataSource。
  • 主 session 建議與共識:四項契約已補入正文及受控故障測試策略,支持以完整修訂稿進入 Accepted 決策;兩位審議者無剩餘分歧或新阻擋。不要求接受前先完成產品程式或效能基準。建議納入 appfuse-server@4.0.0-alpha.30,發布前核對版號未占用;保留 ADR-013/017 關聯,本案不另衍生 ADR。
  • 待維護者確認:完整工程草案及其破壞性 provider 遷移是否接受、目標版本、是否衍生 ADR。正式狀態仍為 Deferred,決策者沿用 Jason Lin;本輪僅修訂 RFC。

2026-10-11 — Under Review(實作前政策確認與工程草案)​

  • 政策確認者:Jason Lin。
  • 預設啟用:安裝 audit feature 後預設啟用,可由啟動設定或 runtime 控制關閉。
  • 關閉行為:清空尚未寫入事件;已開始的資料庫批次完成或失敗後結束,不強制中斷其交易。
  • 控制入口:程式介面及專用 Actuator 端點,沿用應用既有維運授權。
  • 事件錯誤:單筆驗證/快照/JSON 資料錯誤略過,留下安全診斷,業務繼續。
  • 啟動錯誤:多 provider、DataSource 選擇不明或非法容量等無效接線 fail-fast;審計資料庫暫時離線或表不可寫不列為此類啟動錯誤。
  • 工程草案:主 session 補上 storage provider、JDBC 五欄映射、查詢銜接、控制端點、容量與生命週期/日誌策略,供完整新稿審議。設定數值與具體型別不是上述政策問題的確認內容,不宣稱已逐項由維護者拍板。
  • 狀態:保留 Deferred,尚未對完整修訂稿作 Accepted、target_version 或是否衍生 ADR 的新決策;沒有產品程式碼變更。

2026-10-11 — Under Review(Deferred 後的設計修訂)​

  • 方向確認者:Jason Lin;依本 session 的開關選擇、非同步方向確認、預設資料庫要求及 JDBC 批次建議確認記錄。
  • 第一階段:可停用、非同步、允許遺失;關閉略過新 AuditEvent,不寫資料庫或記憶體,支援啟動設定與 runtime 切換。
  • 預設儲存:沿用下游既有預設 DataSource,由背景工作者透過 JDBC adapter 批次 INSERT;保留指定其他 DataSource 與其他儲存 adapter 的能力。
  • 取代範圍:原同步 REQUIRES_NEW 方案 A 改為原方案 D 的非同步 best-effort 子集;不採原 D 的重試/outbox。業務執行緒不暫停/恢復外層交易、不等待資料庫、不採 caller-runs fallback。
  • 舊審議的適用性:先前 A 2:0 與 Deferred 2:0 僅針對原同步稿,不作本次非同步設計的 AI 審議證據。交易恢復問題改以背景工作者資源與失敗生命週期契約處理;共用日誌安全條件仍適用。
  • 重新評估條件的修訂方向:補齊本稿「待補齊的設計決策」與對應故障測試策略,再審議完整新稿;不以背景化宣稱所有風險已消失。保留前次正式 Deferred,未作新的 Accepted/target_version/ADR 決策。
  • 影響檢視:已查核 ADR-013 R1、ADR-017、acting/Entity audit 指南、既有 sink/測試與 llms 索引。這些仍描述現行版本;本輪只修訂 RFC,不將尚未實作的設計寫入已生效指南或程式碼。頁面 ID/permalink 不變。

2026-10-11 — Deferred​

  • 決策者:Jason Lin。
  • 延後理由:方案 A 的框架歸屬及統一預設合理;現稿尚未明訂不可安全繼續的交易生命週期故障如何處置,也未覆蓋 rollback 故障下的共用日誌安全界線,因此暫不把完整 execute 外的捕捉等同於成功隔離。
  • 重新評估條件:補明可隔離持久化失敗與 suspend/cleanup/resume 故障的區別、正常返回的前提及恢復失敗處置;補列受控故障測試,驗證外層資源恢復與無法恢復時的行為;補列 rollback 故障時實際日誌的 payload/原始例外訊息檢查,再由維護者重新審議。須補齊契約與驗證策略,不要求在接受 RFC 前完成產品實作。
  • 審議結論:兩個獨立 Codex agent 均支持方案 A,但建議現稿 Deferred(A 方向 2:0、Deferred 建議 2:0);主 session 同意,維護者已確認本輪 Q1–Q5 判斷、Deferred 理由與重新評估條件。此為同模型的獨立審議。
  • 範圍:不新增模式選擇、可靠遞送或效能證據要求;不設定接受版本或另衍生 ADR,保留既有 ADR-013/017 關聯。條件達成後以 /rfc-intake decide 2026-10-10-audit-persistence-failure-isolation 重新審議。

2026-10-11 — Under Review​

  • 本輪狀態:已完成兩個 Codex agent 的獨立並行審議與主 session 核對;以下為待維護者確認的決策草稿,frontmatter 維持 proposed,尚未作接受、延後、實作或發布決策。
  • 審議結果:兩位審議者均支持方案 A 的框架預設修正方向,但建議現稿 Deferred;方向投票 A 2:0,現稿決策建議 Deferred 2:0。此為同模型的獨立審議,不代表跨模型共識。
  • 現況證據:本機 appfuse-server/gradle.properties 為 4.0.0-alpha.29;PersistentAuditEventRepository.add() 與 AuditTransactionTestSupport 仍採可寫外層 REQUIRED、共同回滾及失敗向外傳遞。此次只查核原始碼與既有測試定義,未實作或執行新契約測試。
  • 維護者審議建議:Q1 動機具代表性;Q2 既有 API 風格對齊,但失敗邊界需補清楚;Q3 屬行為破壞性變更,接受後須明載發布版本及事件語意;Q4 採 A,B 重複接線且仍有相同交易恢復問題,C 無已確認的模式需求,D 屬另案;Q5 屬框架 sink 的基礎設施範圍,具體 Entity、授權及發布時機仍由應用擁有。
  • 主 session 判斷:同意兩位審議者指出的交易恢復缺口。Spring Framework 7.0.2 的 cleanupAfterCompletion 先清理內層資源,再恢復外層;任一階段失敗都可能從整個 execute 邊界逸出,不能僅因捕捉 RuntimeException 就推論外層可安全續行。這是隔離保證的前提,不要求新增模式、可靠遞送或效能證據。
  • 日誌補充:同意審議者 1 的日誌疑慮。TransactionTemplate.rollbackOnException 在 rollback 失敗時可能記錄原始 callback throwable;只測框架 sink 的 WARN 不足以證成本文的共用日誌安全承諾,須界定涵蓋 logger 與生效設定,並驗證實際輸出。
  • Deferred 理由草稿:方案 A 的歸屬及統一預設合理;現稿尚未明訂不可安全繼續的交易生命週期故障如何處置,也未覆蓋 rollback 故障下的共用日誌安全界線,因此暫不把完整 execute 外的捕捉等同於成功隔離。
  • 重新評估條件草稿:補明可隔離持久化失敗與 suspend/cleanup/resume 故障的區別、正常返回的前提及恢復失敗處置;補列受控故障測試,驗證外層資源恢復與無法恢復時的行為;補列 rollback 故障時實際日誌的 payload/原始例外訊息檢查,再由維護者重新審議。此處要求補齊契約與驗證策略,不要求在接受 RFC 前完成產品實作。
  • 若改採 Accepted:建議目標 appfuse-server@4.0.0-alpha.30,發布前核對未被占用;保留既有 ADR-013/017 關聯,本案可由 RFC 記錄而不另衍生 ADR。目標版本及是否衍生 ADR 仍待維護者確認。
  • 既有文檔差異:ADR-013 原文為 Accepted,索引仍為 Proposed;不據索引推翻已查核的 sink 歸屬,也不把此漂移當成本案拒絕理由。正式決策的 decided_by 尚待維護者提供。

2026-10-10 — Under Review​

  • 入站至 appfuse-docs/docs-server/rfcs/。
  • 已完成格式、七維度提交門檻及二次脫敏檢查;確認版本已收入本機框架工作樹。
  • 等待框架維護者以 /rfc-intake decide 2026-10-10-audit-persistence-failure-isolation 執行審議;尚未接受、實作或發布。

2026-10-10 — Proposed​

  • 提案者:retail 應用團隊。
  • 來源:retail。
  • 提案範圍:修正既有審計元件的預設獨立交易與持久化失敗隔離;不新增模式選擇、不要求升級相容性設計,效能保證維持框架責任。
  • 狀態:proposed;未作接受或實作決策。

相關連結​

最後更新:2026-10-11。