Skip to content

Commit 1ecbe9f

Browse files
authored
Merge pull request #303 from Integration-Automation/feat/config-schema-batch
Add typed configuration schema validation
2 parents b39a604 + f68abc9 commit 1ecbe9f

15 files changed

Lines changed: 334 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-22) — Typed Configuration Schema](#whats-new-2026-06-22--typed-configuration-schema)
1617
- [What's new (2026-06-22) — OTLP/JSON Span Export](#whats-new-2026-06-22--otlpjson-span-export)
1718
- [What's new (2026-06-22) — Canonical Log Lines & Structured Logging](#whats-new-2026-06-22--canonical-log-lines--structured-logging)
1819
- [What's new (2026-06-22) — Conditional HTTP Requests & Cache Validators](#whats-new-2026-06-22--conditional-http-requests--cache-validators)
@@ -147,6 +148,12 @@
147148

148149
---
149150

151+
## What's new (2026-06-22) — Typed Configuration Schema
152+
153+
Validate config into a typed object. Full reference: [`docs/source/Eng/doc/new_features/v95_features_doc.rst`](docs/source/Eng/doc/new_features/v95_features_doc.rst).
154+
155+
- **`ConfigSchema` / `ConfigField` / `validate_config` / `coerce`** (`AC_validate_config`): `assets._coerce` coerces one value and `json_schema` validates structure, but nothing bound a resolved config dict into a typed object with required-field enforcement and choice constraints. This coerces types (`str`/`int`/`float`/`bool`), applies defaults, enforces required/choices, and returns `{ok, config, errors}` — a stdlib pydantic-settings analog. Pure-stdlib, deterministic.
156+
150157
## What's new (2026-06-22) — OTLP/JSON Span Export
151158

152159
Export spans the way a collector ingests them. Full reference: [`docs/source/Eng/doc/new_features/v94_features_doc.rst`](docs/source/Eng/doc/new_features/v94_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-22) — 具类型的配置结构](#本次更新-2026-06-22--具类型的配置结构)
1516
- [本次更新 (2026-06-22) — OTLP/JSON Span 导出](#本次更新-2026-06-22--otlpjson-span-导出)
1617
- [本次更新 (2026-06-22) — 标准日志行与结构化日志](#本次更新-2026-06-22--标准日志行与结构化日志)
1718
- [本次更新 (2026-06-22) — 条件式 HTTP 请求与缓存验证子](#本次更新-2026-06-22--条件式-http-请求与缓存验证子)
@@ -146,6 +147,12 @@
146147

147148
---
148149

150+
## 本次更新 (2026-06-22) — 具类型的配置结构
151+
152+
把配置验证成具类型的对象。完整参考:[`docs/source/Zh/doc/new_features/v95_features_doc.rst`](../docs/source/Zh/doc/new_features/v95_features_doc.rst)
153+
154+
- **`ConfigSchema` / `ConfigField` / `validate_config` / `coerce`**(`AC_validate_config`):`assets._coerce` 只转换单一值,`json_schema` 只验证结构,但没有东西把已解析配置 dict 绑定成具类型对象并做必填强制与选项约束。本功能转换类型(`str`/`int`/`float`/`bool`)、应用默认、强制必填/选项,返回 `{ok, config, errors}` —— 标准库版 pydantic-settings。纯标准库、确定。
155+
149156
## 本次更新 (2026-06-22) — OTLP/JSON Span 导出
150157

151158
以 collector 摄取的格式导出 span。完整参考:[`docs/source/Zh/doc/new_features/v94_features_doc.rst`](../docs/source/Zh/doc/new_features/v94_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-22) — 具型別的設定結構](#本次更新-2026-06-22--具型別的設定結構)
1516
- [本次更新 (2026-06-22) — OTLP/JSON Span 匯出](#本次更新-2026-06-22--otlpjson-span-匯出)
1617
- [本次更新 (2026-06-22) — 標準日誌行與結構化日誌](#本次更新-2026-06-22--標準日誌行與結構化日誌)
1718
- [本次更新 (2026-06-22) — 條件式 HTTP 請求與快取驗證子](#本次更新-2026-06-22--條件式-http-請求與快取驗證子)
@@ -146,6 +147,12 @@
146147

147148
---
148149

150+
## 本次更新 (2026-06-22) — 具型別的設定結構
151+
152+
把設定驗證成具型別的物件。完整參考:[`docs/source/Zh/doc/new_features/v95_features_doc.rst`](../docs/source/Zh/doc/new_features/v95_features_doc.rst)
153+
154+
- **`ConfigSchema` / `ConfigField` / `validate_config` / `coerce`**(`AC_validate_config`):`assets._coerce` 只轉換單一值,`json_schema` 只驗證結構,但沒有東西把已解析設定 dict 綁定成具型別物件並做必填強制與選項約束。本功能轉換型別(`str`/`int`/`float`/`bool`)、套用預設、強制必填/選項,回傳 `{ok, config, errors}` —— 標準函式庫版 pydantic-settings。純標準函式庫、具決定性。
155+
149156
## 本次更新 (2026-06-22) — OTLP/JSON Span 匯出
150157

151158
以 collector 攝取的格式匯出 span。完整參考:[`docs/source/Zh/doc/new_features/v94_features_doc.rst`](../docs/source/Zh/doc/new_features/v94_features_doc.rst)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
Typed Configuration Schema
2+
==========================
3+
4+
``assets._coerce`` coerces a single value and ``json_schema`` validates JSON
5+
structure, but nothing bound a resolved config dict into a typed object with
6+
required-field enforcement and choice constraints. This validates a mapping
7+
against declared fields, coercing types and reporting actionable errors — a
8+
stdlib analog of pydantic-settings.
9+
10+
Pure standard library (``dataclasses``); imports no ``PySide6``. Validation is a
11+
pure function (mapping in, report out), so it is fully deterministic in CI.
12+
13+
Headless API
14+
------------
15+
16+
.. code-block:: python
17+
18+
from je_auto_control import ConfigSchema, ConfigField, validate_config
19+
20+
schema = ConfigSchema({
21+
"port": ConfigField("int", required=True),
22+
"env": ConfigField("str", default="dev", choices=["dev", "prod"]),
23+
"debug": ConfigField("bool", default=False),
24+
})
25+
report = schema.validate({"port": "8080", "debug": "yes"})
26+
# {"ok": True, "config": {"port": 8080, "env": "dev", "debug": True}, "errors": []}
27+
28+
``ConfigField`` declares a ``type`` (``str`` / ``int`` / ``float`` / ``bool``),
29+
optional ``default``, ``required`` flag, ``choices``, and an ``env`` hint.
30+
``ConfigSchema.validate`` coerces each present value, applies defaults, enforces
31+
required fields and choices, and returns ``{ok, config, errors}`` (errors as
32+
``{field, error}``). ``ConfigSchema.from_dict`` builds a schema from a plain
33+
spec, ``validate_config`` does spec-plus-mapping in one call, and ``coerce``
34+
exposes the value coercion (booleans accept ``true``/``yes``/``on`` etc.).
35+
36+
Executor command
37+
----------------
38+
39+
``AC_validate_config`` validates a ``config`` mapping against a ``schema`` spec
40+
and returns ``{ok, config, errors}``. It is exposed as the MCP tool
41+
``ac_validate_config`` and as a Script Builder command under **Data**.

docs/source/Eng/eng_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ Comprehensive guides for all AutoControl features.
117117
doc/new_features/v92_features_doc
118118
doc/new_features/v93_features_doc
119119
doc/new_features/v94_features_doc
120+
doc/new_features/v95_features_doc
120121
doc/ocr_backends/ocr_backends_doc
121122
doc/observability/observability_doc
122123
doc/operations_layer/operations_layer_doc
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
具型別的設定結構
2+
==============
3+
4+
``assets._coerce`` 只轉換單一值,``json_schema`` 只驗證 JSON 結構,但沒有任何東西能把已解析的設定 dict
5+
綁定成具型別的物件,並做必填欄位強制與選項約束。本功能依宣告的欄位驗證一個 mapping,轉換型別並回報可
6+
據以行動的錯誤 —— 標準函式庫版的 pydantic-settings。
7+
8+
純標準函式庫(``dataclasses``);不匯入 ``PySide6``。驗證為純函式(輸入 mapping、輸出報告),因此在 CI
9+
中完全具決定性。
10+
11+
無頭 API
12+
--------
13+
14+
.. code-block:: python
15+
16+
from je_auto_control import ConfigSchema, ConfigField, validate_config
17+
18+
schema = ConfigSchema({
19+
"port": ConfigField("int", required=True),
20+
"env": ConfigField("str", default="dev", choices=["dev", "prod"]),
21+
"debug": ConfigField("bool", default=False),
22+
})
23+
report = schema.validate({"port": "8080", "debug": "yes"})
24+
# {"ok": True, "config": {"port": 8080, "env": "dev", "debug": True}, "errors": []}
25+
26+
``ConfigField`` 宣告 ``type``(``str`` / ``int`` / ``float`` / ``bool``)、選用的 ``default``、``required``
27+
旗標、``choices`` 與 ``env`` 提示。``ConfigSchema.validate`` 轉換每個存在的值、套用預設、強制必填與選項,
28+
回傳 ``{ok, config, errors}``(錯誤為 ``{field, error}``)。``ConfigSchema.from_dict`` 從純 spec 建立結構,
29+
``validate_config`` 一次完成 spec 加 mapping,``coerce`` 公開值轉換(布林接受 ``true``/``yes``/``on`` 等)。
30+
31+
執行器命令
32+
----------
33+
34+
``AC_validate_config`` 依 ``schema`` spec 驗證 ``config`` mapping,回傳 ``{ok, config, errors}``。它以 MCP
35+
工具 ``ac_validate_config`` 以及 Script Builder 中 **Data** 分類下的命令提供。

docs/source/Zh/zh_index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ AutoControl 所有功能的完整使用指南。
117117
doc/new_features/v92_features_doc
118118
doc/new_features/v93_features_doc
119119
doc/new_features/v94_features_doc
120+
doc/new_features/v95_features_doc
120121
doc/ocr_backends/ocr_backends_doc
121122
doc/observability/observability_doc
122123
doc/operations_layer/operations_layer_doc

je_auto_control/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@
290290
from je_auto_control.utils.layered_config import (
291291
LayeredConfig, SourceTrace, deep_merge,
292292
)
293+
# Typed config schema validation (coerce + required + choices)
294+
from je_auto_control.utils.config_schema import (
295+
ConfigField, ConfigSchema, coerce, validate_config,
296+
)
293297
# URI-scheme secret/value reference resolver (env:// / file:// / secret://)
294298
from je_auto_control.utils.secret_ref import (
295299
RefResolver, SecretRefError, is_ref, resolve_ref, resolve_refs_in,
@@ -921,6 +925,7 @@ def start_autocontrol_gui(*args, **kwargs):
921925
"Asset", "AssetStore", "AssetValue", "active_environment",
922926
"dotenv_values", "dump_dotenv", "load_dotenv", "parse_dotenv",
923927
"LayeredConfig", "SourceTrace", "deep_merge",
928+
"ConfigField", "ConfigSchema", "coerce", "validate_config",
924929
"RefResolver", "SecretRefError", "is_ref", "resolve_ref", "resolve_refs_in",
925930
"redact_config", "redact_secret_text",
926931
"EventEmitter", "post_cloudevent", "to_cloudevent",

je_auto_control/gui/script_builder/command_schema.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,16 @@ def _add_resilience_specs(specs: List[CommandSpec]) -> None:
16761676
),
16771677
description="Recursively resolve references inside a JSON structure.",
16781678
))
1679+
specs.append(CommandSpec(
1680+
"AC_validate_config", "Data", "Config Schema: Validate",
1681+
fields=(
1682+
FieldSpec("schema", FieldType.STRING,
1683+
placeholder='{"port": {"type": "int", "required": true}}'),
1684+
FieldSpec("config", FieldType.STRING,
1685+
placeholder='{"port": "8080"}'),
1686+
),
1687+
description="Validate a config mapping against a typed schema spec.",
1688+
))
16791689
specs.append(CommandSpec(
16801690
"AC_redact_config", "Security", "Redaction: Redact Config",
16811691
fields=(
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Typed configuration schema validation for AutoControl."""
2+
from je_auto_control.utils.config_schema.config_schema import (
3+
ConfigField, ConfigSchema, coerce, validate_config,
4+
)
5+
6+
__all__ = ["ConfigField", "ConfigSchema", "coerce", "validate_config"]

0 commit comments

Comments
 (0)