Skip to content

Commit 70122c4

Browse files
committed
Add approval testing: verify artifacts against approved baselines
1 parent 08c8dee commit 70122c4

15 files changed

Lines changed: 447 additions & 1 deletion

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
## Table of Contents
1515

16+
- [What's new (2026-06-19) — Approval Testing (Golden-Master Baselines)](#whats-new-2026-06-19--approval-testing-golden-master-baselines)
1617
- [What's new (2026-06-19) — Network Egress Allowlist Guard](#whats-new-2026-06-19--network-egress-allowlist-guard)
1718
- [What's new (2026-06-19) — Just-In-Time Credential Leases](#whats-new-2026-06-19--just-in-time-credential-leases)
1819
- [What's new (2026-06-19) — Maker-Checker Approval Gate](#whats-new-2026-06-19--maker-checker-approval-gate)
@@ -87,6 +88,12 @@
8788

8889
---
8990

91+
## What's new (2026-06-19) — Approval Testing (Golden-Master Baselines)
92+
93+
Lock outputs against a human-approved baseline. Full reference: [`docs/source/Eng/doc/new_features/v35_features_doc.rst`](docs/source/Eng/doc/new_features/v35_features_doc.rst).
94+
95+
- **`verify_artifact` / `approve_artifact`** (`AC_verify_artifact` / `AC_approve_artifact` / `AC_pending_artifacts`, `ac_*`): golden-master / snapshot testing for *any* artifact (text, JSON, OCR output, screenshot bytes). `verify_artifact` compares produced content to `<name>.approved.<ext>`; a mismatch or missing baseline writes `<name>.received.<ext>` for review and fails, and `approve_artifact` promotes a reviewed received file to the baseline. Complements pixel diffing with a review-gated baseline you commit alongside the test; names are path-traversal-checked.
96+
9097
## What's new (2026-06-19) — Network Egress Allowlist Guard
9198

9299
Pin which hosts automation may reach. Full reference: [`docs/source/Eng/doc/new_features/v34_features_doc.rst`](docs/source/Eng/doc/new_features/v34_features_doc.rst).

README/README_zh-CN.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目录
1414

15+
- [本次更新 (2026-06-19) — 核准式测试(Golden-Master 基准)](#本次更新-2026-06-19--核准式测试golden-master-基准)
1516
- [本次更新 (2026-06-19) — 网络出口允许清单守卫](#本次更新-2026-06-19--网络出口允许清单守卫)
1617
- [本次更新 (2026-06-19) — 即时凭证租约](#本次更新-2026-06-19--即时凭证租约)
1718
- [本次更新 (2026-06-19) — Maker-Checker 审批闸门](#本次更新-2026-06-19--maker-checker-审批闸门)
@@ -86,6 +87,12 @@
8687

8788
---
8889

90+
## 本次更新 (2026-06-19) — 核准式测试(Golden-Master 基准)
91+
92+
将输出锁定到人工核准的基准。完整参考:[`docs/source/Zh/doc/new_features/v35_features_doc.rst`](../docs/source/Zh/doc/new_features/v35_features_doc.rst)
93+
94+
- **`verify_artifact` / `approve_artifact`**(`AC_verify_artifact` / `AC_approve_artifact` / `AC_pending_artifacts``ac_*`):对*任何*产物(文本、JSON、OCR 输出、屏幕截图字节)进行 golden-master / snapshot 测试。`verify_artifact` 将产出内容与 `<name>.approved.<ext>` 比对;不符或缺少基准会写入 `<name>.received.<ext>` 供审查并失败,`approve_artifact` 则将审查后的 received 文件晋升为基准。以与测试一起提交、受审查把关的基准补强逐像素比对;名称会经过路径穿越检查。
95+
8996
## 本次更新 (2026-06-19) — 网络出口允许清单守卫
9097

9198
钉选自动化可连线的主机。完整参考:[`docs/source/Zh/doc/new_features/v34_features_doc.rst`](../docs/source/Zh/doc/new_features/v34_features_doc.rst)

README/README_zh-TW.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
## 目錄
1414

15+
- [本次更新 (2026-06-19) — 核准式測試(Golden-Master 基準)](#本次更新-2026-06-19--核准式測試golden-master-基準)
1516
- [本次更新 (2026-06-19) — 網路出口允許清單守衛](#本次更新-2026-06-19--網路出口允許清單守衛)
1617
- [本次更新 (2026-06-19) — 即時憑證租約](#本次更新-2026-06-19--即時憑證租約)
1718
- [本次更新 (2026-06-19) — Maker-Checker 審批閘門](#本次更新-2026-06-19--maker-checker-審批閘門)
@@ -86,6 +87,12 @@
8687

8788
---
8889

90+
## 本次更新 (2026-06-19) — 核准式測試(Golden-Master 基準)
91+
92+
將輸出鎖定到人工核准的基準。完整參考:[`docs/source/Zh/doc/new_features/v35_features_doc.rst`](../docs/source/Zh/doc/new_features/v35_features_doc.rst)
93+
94+
- **`verify_artifact` / `approve_artifact`**(`AC_verify_artifact` / `AC_approve_artifact` / `AC_pending_artifacts``ac_*`):對*任何*產物(文字、JSON、OCR 輸出、螢幕截圖位元組)進行 golden-master / snapshot 測試。`verify_artifact` 將產出內容與 `<name>.approved.<ext>` 比對;不符或缺少基準會寫入 `<name>.received.<ext>` 供審查並失敗,`approve_artifact` 則將審查後的 received 檔晉升為基準。以與測試一起提交、受審查把關的基準補強逐像素比對;名稱會經過路徑穿越檢查。
95+
8996
## 本次更新 (2026-06-19) — 網路出口允許清單守衛
9097

9198
釘選自動化可連線的主機。完整參考:[`docs/source/Zh/doc/new_features/v34_features_doc.rst`](../docs/source/Zh/doc/new_features/v34_features_doc.rst)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
Approval Testing (Golden-Master Baselines)
2+
==========================================
3+
4+
Approval testing (a.k.a. golden-master / snapshot testing) reframes "is this
5+
output still correct?" as "does it still match the version a human approved?".
6+
:func:`verify_artifact` compares produced content to a stored
7+
``<name>.approved.<ext>`` baseline:
8+
9+
* **match** → the check passes;
10+
* **mismatch or missing baseline** → the produced bytes are written to
11+
``<name>.received.<ext>`` and the check fails, so a reviewer can diff the two
12+
and, if the change is intended, promote it with :func:`approve_artifact`.
13+
14+
It works for *any* artifact — rendered text, JSON, OCR output, screenshot bytes
15+
— so it complements pixel diffing with a review-gated baseline you commit
16+
alongside the test. Pure standard library; imports no ``PySide6``. Names are
17+
validated against path traversal.
18+
19+
Headless API
20+
------------
21+
22+
.. code-block:: python
23+
24+
from je_auto_control import verify_artifact, approve_artifact
25+
26+
result = verify_artifact("invoice_render", produced_text,
27+
approvals_dir="tests/.approvals")
28+
if not result.match:
29+
# first run is "new", a changed output is "mismatch"; review the
30+
# .received file, then bless it:
31+
approve_artifact("invoice_render", approvals_dir="tests/.approvals")
32+
33+
``content`` may be ``str`` or ``bytes`` (pass ``extension="png"`` for binary
34+
snapshots). A verified run clears any stale received file.
35+
``pending_artifacts(dir)`` lists names still awaiting approval. ``ApprovalResult``
36+
carries ``status`` (``verified`` / ``mismatch`` / ``new``), ``match``, and both
37+
file paths.
38+
39+
Executor commands
40+
-----------------
41+
42+
================================ ===================================================
43+
Command Effect
44+
================================ ===================================================
45+
``AC_verify_artifact`` Compare ``content`` to the approved baseline.
46+
``AC_approve_artifact`` Promote the received artifact to the baseline.
47+
``AC_pending_artifacts`` List artifacts awaiting approval.
48+
================================ ===================================================
49+
50+
The same operations are exposed as MCP tools (``ac_verify_artifact`` /
51+
``ac_approve_artifact`` / ``ac_pending_artifacts``) and as Script Builder
52+
commands under **Testing**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Comprehensive guides for all AutoControl features.
5757
doc/new_features/v32_features_doc
5858
doc/new_features/v33_features_doc
5959
doc/new_features/v34_features_doc
60+
doc/new_features/v35_features_doc
6061
doc/ocr_backends/ocr_backends_doc
6162
doc/observability/observability_doc
6263
doc/operations_layer/operations_layer_doc
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
核准式測試(Golden-Master 基準)
2+
================================
3+
4+
核准式測試(又稱 golden-master / snapshot 測試)把「這個輸出還正確嗎?」重新表述為
5+
「它是否仍與人工核准過的版本相符?」。:func:`verify_artifact` 將產出的內容與儲存的
6+
``<name>.approved.<ext>`` 基準比對:
7+
8+
* **相符** → 檢查通過;
9+
* **不符或缺少基準** → 產出的位元組會被寫入 ``<name>.received.<ext>`` 且檢查失敗,讓
10+
審查者可比對兩者,若變更為預期,即以 :func:`approve_artifact` 晉升。
11+
12+
它適用於*任何*產物 —— 渲染後的文字、JSON、OCR 輸出、螢幕截圖位元組 —— 因此以一個受
13+
審查把關、與測試一起提交的基準,補強逐像素比對。純標準函式庫,不匯入 ``PySide6``。
14+
名稱會經過路徑穿越驗證。
15+
16+
無頭 API
17+
--------
18+
19+
.. code-block:: python
20+
21+
from je_auto_control import verify_artifact, approve_artifact
22+
23+
result = verify_artifact("invoice_render", produced_text,
24+
approvals_dir="tests/.approvals")
25+
if not result.match:
26+
# 首次執行為 "new",輸出變更為 "mismatch";審查 .received 檔後再核可:
27+
approve_artifact("invoice_render", approvals_dir="tests/.approvals")
28+
29+
``content`` 可為 ``str`` 或 ``bytes``(二進位快照請傳 ``extension="png"``)。相符的執
30+
行會清除任何過期的 received 檔。``pending_artifacts(dir)`` 列出仍待核准的名稱。
31+
``ApprovalResult`` 帶有 ``status``(``verified`` / ``mismatch`` / ``new``)、
32+
``match`` 及兩個檔案路徑。
33+
34+
執行器指令
35+
----------
36+
37+
================================ ===================================================
38+
指令 效果
39+
================================ ===================================================
40+
``AC_verify_artifact`` 將 ``content`` 與已核准基準比對。
41+
``AC_approve_artifact`` 將 received 產物晉升為基準。
42+
``AC_pending_artifacts`` 列出待核准的產物。
43+
================================ ===================================================
44+
45+
相同操作亦提供為 MCP 工具(``ac_verify_artifact`` / ``ac_approve_artifact`` /
46+
``ac_pending_artifacts``),以及 Script Builder 中 **Testing** 分類下的指令。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ AutoControl 所有功能的完整使用指南。
5757
doc/new_features/v32_features_doc
5858
doc/new_features/v33_features_doc
5959
doc/new_features/v34_features_doc
60+
doc/new_features/v35_features_doc
6061
doc/ocr_backends/ocr_backends_doc
6162
doc/observability/observability_doc
6263
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@
212212
from je_auto_control.utils.egress import (
213213
EgressBlocked, EgressPolicy, get_egress_policy, set_egress_policy,
214214
)
215+
# Approval testing: verify artifacts against a human-approved baseline
216+
from je_auto_control.utils.approval import (
217+
ApprovalResult, approve_artifact, pending_artifacts, verify_artifact,
218+
)
215219
# Background popup/interrupt watchdog (unattended automation)
216220
from je_auto_control.utils.watchdog import (
217221
PopupWatchdog, WatchdogRule, default_popup_watchdog,
@@ -650,6 +654,8 @@ def start_autocontrol_gui(*args, **kwargs):
650654
"ApprovalGate", "CredentialBroker", "CredentialBrokerError",
651655
"default_broker", "set_secret_resolver",
652656
"EgressBlocked", "EgressPolicy", "get_egress_policy", "set_egress_policy",
657+
"ApprovalResult", "approve_artifact", "pending_artifacts",
658+
"verify_artifact",
653659
# MCP server
654660
"AuditLogger", "HttpMCPServer", "MCPContent", "MCPPrompt",
655661
"MCPPromptArgument", "MCPResource", "MCPServer", "MCPTool",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,35 @@ def _add_misc_specs(specs: List[CommandSpec]) -> None:
772772
fields=(),
773773
description="Clear the egress policy back to allow-all.",
774774
))
775+
specs.append(CommandSpec(
776+
"AC_verify_artifact", "Testing", "Approval: Verify Artifact",
777+
fields=(
778+
FieldSpec("name", FieldType.STRING, placeholder="login_screen"),
779+
FieldSpec("content", FieldType.STRING),
780+
FieldSpec("approvals_dir", FieldType.STRING, optional=True,
781+
default=".approvals"),
782+
FieldSpec("extension", FieldType.STRING, optional=True,
783+
default="txt"),
784+
),
785+
description="Compare content to its approved baseline (snapshot test).",
786+
))
787+
specs.append(CommandSpec(
788+
"AC_approve_artifact", "Testing", "Approval: Promote Received",
789+
fields=(
790+
FieldSpec("name", FieldType.STRING),
791+
FieldSpec("approvals_dir", FieldType.STRING, optional=True,
792+
default=".approvals"),
793+
FieldSpec("extension", FieldType.STRING, optional=True,
794+
default="txt"),
795+
),
796+
description="Promote a received artifact to the approved baseline.",
797+
))
798+
specs.append(CommandSpec(
799+
"AC_pending_artifacts", "Testing", "Approval: List Pending",
800+
fields=(FieldSpec("approvals_dir", FieldType.STRING, optional=True,
801+
default=".approvals"),),
802+
description="List artifacts awaiting approval.",
803+
))
775804
specs.append(CommandSpec(
776805
"AC_generate_sop", "Report", "Generate SOP Document",
777806
fields=(
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Approval testing: verify artifacts against an approved baseline."""
2+
from je_auto_control.utils.approval.approval_test import (
3+
ApprovalResult, approve_artifact, pending_artifacts, verify_artifact,
4+
)
5+
6+
__all__ = [
7+
"ApprovalResult", "approve_artifact", "pending_artifacts",
8+
"verify_artifact",
9+
]

0 commit comments

Comments
 (0)