Files

1001 lines
35 KiB
Python
Executable File

#!/usr/bin/env python3
"""Validate every full Schema leaf against Cobra Help and smoke runtime wiring.
The script loads ``dws schema --all --format json`` exactly once and uses those
full leaf payloads directly. Every leaf receives a bidirectional Schema/Help
flag contract check that excludes root execution controls and reviewed generic
payload escape hatches, but retains effective product/group flags. Runtime
execution is opt-in: only a leaf that publishes a valid ``dry_run`` object is
invoked with ``--dry-run``. Merely inheriting the global flag is never treated
as capability evidence, and ``--yes`` is never injected.
The subprocess result is only a final-binary exit-health check. It deliberately
does not infer preview evidence from human-readable text. The Go Agent-example
gate is the sole proof of preview kind, absence of real ToolCaller invocations,
and non-interactive safety.
Run the fast, binary-free self-tests with::
python3 -m unittest scripts/dev/schema_command_smoke_test.py
"""
from __future__ import annotations
import argparse
import concurrent.futures
import itertools
import json
import re
import shlex
import subprocess
import tempfile
import time
from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
GLOBAL_EXECUTION_CONTROL_FLAGS = frozenset(
{
"client-id",
"client-secret",
"debug",
"dry-run",
"fields",
"format",
"jq",
"mock",
"output",
"profile",
"timeout",
"token",
"verbose",
"yes",
}
)
COBRA_FRAMEWORK_FLAGS = frozenset({"help"})
DRY_RUN_PREVIEW_KINDS = frozenset({"invocation", "request", "plan", "diff"})
GENERIC_PAYLOAD_FLAG_USAGES = {
"json": "Base JSON object payload for this tool invocation",
"params": "Additional JSON object payload merged after --json",
}
HELP_FLAG_PATTERN = re.compile(
r"^\s*(?:-[a-zA-Z0-9],\s*)?--([a-zA-Z0-9][a-zA-Z0-9_.-]*)(?:[ =]|$)"
)
@dataclass
class SmokeResult:
canonical_path: str
case_name: str
cli_path: str
command: list[str]
status: str
exit_code: int
stdout: str
stderr: str
error: str = ""
def should_retry_json_failure(output: str) -> bool:
return any(
token in output
for token in [
"TOKEN_VERIFIED_FAILED",
"tools/list failed",
"returned HTTP 400",
]
)
def run_json(argv: list[str], cwd: Path, timeout: int, attempts: int = 3) -> Any:
last_output = ""
last_code = 1
for attempt in range(attempts):
proc = subprocess.run(
argv,
cwd=cwd,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=timeout,
)
if proc.returncode == 0:
return json.loads(proc.stdout)
last_code = proc.returncode
last_output = (proc.stderr or proc.stdout).strip()
if attempt + 1 < attempts and should_retry_json_failure(last_output):
time.sleep(1 + attempt)
continue
break
raise RuntimeError(f"{shlex.join(argv)} exited {last_code}: {last_output}")
def kebab_to_words(value: str) -> str:
return re.sub(r"[-_]+", " ", value.lower())
def scalar_value(flag: str, param: dict[str, Any], canonical_path: str) -> str:
if param.get("example") not in (None, ""):
return str(param["example"])
enum = param.get("enum") or []
if enum:
return str(enum[0])
value_format = str(param.get("format", "")).lower()
is_end = flag == "end" or flag.startswith("end-") or flag.endswith("-end")
if value_format in {"numeric-id", "positive-integer"}:
return "1"
if value_format == "a1-range":
return "A1:B2"
if value_format == "file-path":
return str(Path(tempfile.gettempdir()) / "dws-schema-smoke-fixture.txt")
if value_format == "date-time":
return "2027-01-15T11:00:00+08:00" if is_end else "2027-01-15T10:00:00+08:00"
if value_format == "date":
return "2027-01-16" if is_end else "2027-01-15"
if "default" in param and param["default"] not in (None, ""):
return str(param["default"])
haystack = " ".join(
[
kebab_to_words(flag),
kebab_to_words(str(param.get("property", ""))),
str(param.get("description", "")).lower(),
]
)
if flag in {"start", "end", "start-time", "end-time"}:
return "2027-01-15T11:00:00+08:00" if is_end else "2027-01-15T10:00:00+08:00"
if flag == "fields":
return '[{"fieldName":"Name","type":"text"}]'
if flag in {"records", "record"}:
return '[{"cells":{"fld1":"value"}}]'
if flag == "json":
samples = {
"aitable.view_update_aggregate": '{"fld1":"COUNT"}',
"aitable.view_update_card": '{"displayFieldName":true}',
"aitable.view_update_field_widths": '{"fld1":160}',
"aitable.view_update_timebar": '{"startField":"fld_start"}',
}
if canonical_path in samples:
return samples[canonical_path]
if canonical_path == "attendance.generateTurnSchedule" and flag == "scheduleVOS":
return '[{"userId":"user-smoke","workDate":"2026-07-09 09:00:00","classId":1,"isRest":"N"}]'
if canonical_path == "attendance.create_group_setting" and flag == "type":
return "NONE"
if canonical_path == "attendance.query_at_approve_template" and flag == "type":
return "leave"
if canonical_path == "attendance.save_self_setting" and flag == "setting-scene":
return "checkResultNotify"
if canonical_path == "attendance.get_attendance_summary" and flag == "date":
return "2026-07-09 10:00:00"
if "json" in haystack:
if "array" in haystack or "数组" in haystack:
return "[]"
return "{}"
if flag == "config" or flag == "layout" or flag.endswith("-config"):
return "{}"
if flag == "scope":
return "all"
if flag == "format":
return "excel"
if "enabled" in haystack or "allow back" in haystack:
return "true"
if flag in {"to", "cc", "bcc", "from"}:
return "user@example.com"
if "url" in haystack or "callback" in haystack or "homepage" in haystack:
return "https://example.com"
if "email" in haystack or "mail" in haystack:
return "user@example.com"
if "mobile" in haystack or "phone" in haystack:
return "13800138000"
if "date" in haystack and "time" not in haystack:
return "2026-07-09"
if "time" in haystack or "deadline" in haystack:
return "2026-07-09T10:00:00+08:00"
if "file" in haystack or "path" in haystack or "attachment" in haystack or flag == "output":
return str(Path(tempfile.gettempdir()) / "dws-schema-smoke-fixture.txt")
if "confirm name" in haystack:
return "SchemaSmoke"
if flag in {"redirect-urls", "sso-urls"}:
return "https://example.com"
if flag == "ip-whitelist" or "ip" in haystack:
return "192.0.2.10"
if "secret" in haystack:
return "test-secret"
if "robot code" in haystack:
return "robot-code-smoke"
if flag == "mode" and any(item in haystack for item in ["https", "stream", "aiskill"]):
return "STREAM"
if flag == "share-type":
return "PUBLIC"
if flag in {"id", "parent-id", "dept-id"} or "dept id" in haystack:
return "1"
if "version" in haystack:
return "1.0.0"
if "content" in haystack or "message" in haystack or "desc" in haystack:
return "schema smoke"
if "name" in haystack or "title" in haystack or "subject" in haystack:
return "SchemaSmoke"
if "type" in haystack:
return "app"
return f"{flag}-smoke"
def value_for(flag: str, param: dict[str, Any], canonical_path: str) -> str | None:
# Reviewed examples and declared enums are contract data. They must win
# before type/name heuristics (notably integer enums such as mute-time).
if param.get("example") not in (None, ""):
return str(param["example"])
enum = param.get("enum") or []
if enum:
return str(enum[0])
if canonical_path == "sheet.range_batch_set_style" and flag == "batch":
return str(Path(tempfile.gettempdir()) / "dws-schema-smoke-style.json")
if canonical_path == "report.create_report" and flag == "contents-file":
return "tmp/dws-schema-smoke-report.json"
typ = str(param.get("type", "string")).lower()
prop = str(param.get("property", ""))
haystack = " ".join([kebab_to_words(flag), kebab_to_words(prop)])
if typ == "boolean":
return None
if typ in {"integer", "number"}:
return "1"
if typ == "object":
return "{}"
if typ == "array":
if "url" in haystack:
return "https://example.com"
if "ip" in haystack:
return "192.0.2.10"
if any(token in haystack for token in [" id", " ids", "user", "users", "field", "fields"]):
return "value1,value2"
if any(token in haystack for token in ["record", "records"]):
return '[{"cells":{"fld1":"value"}}]'
if any(token in haystack for token in ["sort"]):
return "[]"
if any(token in haystack for token in ["field", "fields"]):
return "field1,field2"
return "value1,value2"
return scalar_value(flag, param, canonical_path)
def smoke_extra_flags(canonical_path: str) -> set[str]:
# Avoid environment-dependent auto-detection in dry-run smoke. The command
# accepts --email as optional, but without it the CLI probes the bound mailbox.
return {
"mail.search_mail_users": {"email"},
}.get(canonical_path, set())
def constraint_groups(leaf: dict[str, Any], name: str) -> list[list[str]]:
constraints = leaf.get("constraints") or {}
groups = constraints.get(name) or []
return [[str(item) for item in group] for group in groups if group]
def available_one_of_groups(leaf: dict[str, Any]) -> list[list[str]]:
params = leaf.get("parameters") or {}
positional_names = {
str(item.get("name"))
for item in (leaf.get("positionals") or [])
if item.get("name")
}
available = set(params) | positional_names
return [
[name for name in group if name in available]
for group in constraint_groups(leaf, "require_one_of")
if any(name in available for name in group)
]
def one_of_cases(leaf: dict[str, Any]) -> list[tuple[str, ...]]:
groups = available_one_of_groups(leaf)
if not groups:
return [()]
cases: list[tuple[str, ...]] = []
seen: set[tuple[str, ...]] = set()
mutually_exclusive = constraint_groups(leaf, "mutually_exclusive")
for choices in itertools.product(*groups):
selected = set(choices)
if any(sum(name in selected for name in group) > 1 for group in mutually_exclusive):
continue
if choices not in seen:
seen.add(choices)
cases.append(choices)
return cases or [()]
def required_when_matches(
expression: str,
params: dict[str, Any],
selected_params: set[str],
canonical_path: str,
) -> bool:
expression = expression.strip()
value_match = re.fullmatch(r"([a-zA-Z0-9_.-]+) is (.+)", expression)
if value_match:
controller, expected_raw = value_match.groups()
controller_param = params.get(controller) or {}
if controller in selected_params:
actual = value_for(controller, controller_param, canonical_path)
actual_value = "true" if actual is None else str(actual)
elif controller_param.get("default") not in (None, ""):
actual_value = str(controller_param["default"])
elif str(controller_param.get("type", "")).lower() == "boolean":
actual_value = "false"
else:
return False
expected = [item.strip() for item in re.split(r"\s+or\s+", expected_raw)]
return actual_value in expected
any_flag_match = re.fullmatch(
r"any ([a-zA-Z0-9_.-]+)\* flag is provided", expression
)
if any_flag_match:
prefix = any_flag_match.group(1)
return any(name.startswith(prefix) for name in selected_params)
return False
def selected_inputs(
leaf: dict[str, Any],
include_optional: bool,
one_of_choices: tuple[str, ...] = (),
) -> tuple[set[str], set[str]]:
params = leaf.get("parameters") or {}
canonical_path = str(leaf.get("canonical_path", ""))
positionals = {
str(item.get("name")): item
for item in (leaf.get("positionals") or [])
if item.get("name")
}
selected_params = {
name for name, param in params.items()
if include_optional or bool((param or {}).get("required"))
}
selected_positionals = {
name for name, positional in positionals.items()
if bool((positional or {}).get("required"))
}
def is_selected(name: str) -> bool:
return name in selected_params or name in selected_positionals
def select(name: str) -> bool:
if name in params:
selected_params.add(name)
return True
if name in positionals:
selected_positionals.add(name)
return True
return False
one_of_groups = available_one_of_groups(leaf)
choices = one_of_choices or tuple(group[0] for group in one_of_groups)
preferred = set(choices)
for group, choice in zip(one_of_groups, choices):
for name in group:
selected_params.discard(name)
selected_positionals.discard(name)
select(choice)
changed = True
while changed:
changed = False
for group in constraint_groups(leaf, "require_together"):
if not any(is_selected(name) for name in group):
continue
for name in group:
if not is_selected(name) and select(name):
changed = True
for name, param in params.items():
if name in selected_params:
continue
required_when = str((param or {}).get("required_when", ""))
if required_when_matches(
required_when, params, selected_params, canonical_path
):
selected_params.add(name)
changed = True
for group in constraint_groups(leaf, "mutually_exclusive"):
selected = [name for name in group if is_selected(name)]
keep = next((name for name in selected if name in preferred), selected[0] if selected else "")
for name in selected:
if name == keep:
continue
selected_params.discard(name)
selected_positionals.discard(name)
return selected_params, selected_positionals
def build_command(
binary: str,
leaf: dict[str, Any],
include_optional: bool,
one_of_choices: tuple[str, ...] = (),
) -> list[str]:
if not declared_dry_run(leaf):
raise ValueError("runtime smoke requires an explicit leaf dry_run capability")
cli_path = str(leaf["cli_path"])
canonical_path = str(leaf.get("canonical_path", ""))
extra_flags = smoke_extra_flags(canonical_path)
argv = [binary, *shlex.split(cli_path)]
params = leaf.get("parameters") or {}
selected_params, selected_positionals = selected_inputs(
leaf, include_optional, one_of_choices
)
positionals = sorted(
(leaf.get("positionals") or []),
key=lambda item: int(item.get("index", 0)),
)
for positional in positionals:
name = str(positional.get("name", ""))
if name not in selected_positionals:
continue
value = value_for(name, positional, canonical_path)
argv.append("" if value is None else value)
for flag in sorted(params):
param = params[flag] or {}
if flag == "yes":
# A preview must prove that confirmation cannot be bypassed.
continue
if flag not in selected_params and flag not in extra_flags:
continue
if str(param.get("type", "")).lower() == "boolean":
argv.append(f"--{flag}")
continue
value = value_for(flag, param, canonical_path)
argv.extend([f"--{flag}", "" if value is None else value])
# A positive leaf dry_run declaration is the only caller-side admission
# condition. Confirmation must never be bypassed by injecting --yes, and
# no output flag is appended because commands may own a same-named flag.
argv.append("--dry-run")
return argv
def effective_schema_flags_from_help(output: str) -> set[str]:
"""Return executable non-root flags from Cobra's rendered Help.
Cobra renders a leaf's own flags under ``Flags`` and all persistent
ancestors under ``Global Flags``. Schema intentionally excludes only the
root execution controls; product/group persistent flags remain part of the
leaf contract. Keeping section origin prevents a local business ``--format``
flag from being confused with the root output-format control.
"""
local_flags: set[str] = set()
inherited_flags: set[str] = set()
section = ""
saw_flags_section = False
for line in output.splitlines():
heading = line.strip()
if heading in {"Flags:", "Local Flags:"}:
section = "local"
saw_flags_section = True
continue
if heading in {"Global Flags:", "Inherited Flags:"}:
section = "inherited"
saw_flags_section = True
continue
if re.fullmatch(r"[A-Za-z][A-Za-z ]*:", heading):
section = ""
continue
if not section:
continue
match = HELP_FLAG_PATTERN.match(line)
if not match:
continue
name = match.group(1)
generic_usage = GENERIC_PAYLOAD_FLAG_USAGES.get(name)
if generic_usage and generic_usage in line:
# These two generic transport escape hatches are intentionally not
# projected as typed Schema parameters. Match their reviewed usage
# text rather than excluding every business flag named json/params.
continue
if section == "local":
local_flags.add(name)
else:
inherited_flags.add(name)
if not saw_flags_section:
raise RuntimeError("command help has no recognizable Flags section")
return (
local_flags
| (inherited_flags - GLOBAL_EXECUTION_CONTROL_FLAGS)
) - COBRA_FRAMEWORK_FLAGS
def help_schema_flags(binary: str, cwd: Path, cli_path: str, timeout: int) -> set[str]:
proc = subprocess.run(
[binary, *shlex.split(cli_path), "--help"],
cwd=cwd,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=timeout,
)
if proc.returncode != 0:
raise RuntimeError(
f"{binary} {cli_path} --help exited {proc.returncode}: "
f"{(proc.stderr or proc.stdout).strip()}"
)
return effective_schema_flags_from_help(proc.stdout)
def run_smoke_case(
binary: str,
cwd: Path,
path: str,
leaf: dict[str, Any],
timeout: int,
include_optional: bool,
choices: tuple[str, ...],
) -> SmokeResult:
case_name = (
"dry_run/default"
if not choices
else "dry_run/one_of:" + "+".join(choices)
)
try:
command = build_command(binary, leaf, include_optional, choices)
proc = subprocess.run(
command,
cwd=cwd,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=timeout,
)
# Exit zero proves only that the built command accepted and completed
# the reviewed dry-run invocation. Preview/safety evidence belongs to
# the fail-closed Go Agent-example gate, not text scraping here.
status = (
"runtime_exit_pass"
if proc.returncode == 0
else "runtime_exit_fail"
)
return SmokeResult(
canonical_path=path,
case_name=case_name,
cli_path=str(leaf.get("cli_path", "")),
command=command,
status=status,
exit_code=proc.returncode,
stdout=proc.stdout,
stderr=proc.stderr,
)
except subprocess.TimeoutExpired as exc:
return SmokeResult(
canonical_path=path,
case_name=case_name,
cli_path="",
command=exc.cmd if isinstance(exc.cmd, list) else [str(exc.cmd)],
status="timeout",
exit_code=124,
stdout=exc.stdout or "",
stderr=exc.stderr or "",
error=str(exc),
)
except Exception as exc: # noqa: BLE001 - record all smoke failures.
return SmokeResult(
canonical_path=path,
case_name=case_name,
cli_path="",
command=[],
status="error",
exit_code=1,
stdout="",
stderr="",
error=str(exc),
)
def dry_run_capability_error(leaf: dict[str, Any]) -> str:
"""Return a closed-shape error for a leaf-local dry_run declaration."""
if "dry_run" not in leaf:
return ""
capability = leaf["dry_run"]
if not isinstance(capability, dict):
return "dry_run must be an object"
unknown_fields = sorted(set(capability) - {"preview_kind", "remote_reads"})
if unknown_fields:
return "dry_run has unsupported fields: " + ", ".join(unknown_fields)
preview_kind = capability.get("preview_kind")
if not isinstance(preview_kind, str) or preview_kind not in DRY_RUN_PREVIEW_KINDS:
allowed = ", ".join(sorted(DRY_RUN_PREVIEW_KINDS))
return f"dry_run.preview_kind must be one of: {allowed}"
if "remote_reads" in capability and not isinstance(capability["remote_reads"], bool):
return "dry_run.remote_reads must be a boolean"
return ""
def declared_dry_run(leaf: dict[str, Any]) -> bool:
"""Return true only for a valid, positive leaf-local declaration."""
problem = dry_run_capability_error(leaf)
if problem:
raise ValueError(problem)
return "dry_run" in leaf
def run_one(
binary: str,
cwd: Path,
leaf: dict[str, Any],
timeout: int,
include_optional: bool,
) -> list[SmokeResult]:
path = str(leaf.get("canonical_path", ""))
cli_path = str(leaf.get("cli_path", ""))
help_command = [binary, *shlex.split(cli_path), "--help"]
try:
if not path or not cli_path:
raise ValueError("full Schema leaf requires canonical_path and cli_path")
parameters = leaf.get("parameters")
if not isinstance(parameters, dict):
raise ValueError("full Schema leaf parameters must be an object")
declared = set(parameters)
executable = help_schema_flags(binary, cwd, cli_path, timeout)
schema_only = sorted(declared - executable)
help_only = sorted(executable - declared)
if schema_only or help_only:
problems = []
if schema_only:
problems.append(
"Schema-only/non-effective flags: " + ", ".join(schema_only)
)
if help_only:
problems.append(
"effective non-global Help flags missing from Schema: "
+ ", ".join(help_only)
)
return [
SmokeResult(
canonical_path=path,
case_name="contract",
cli_path=cli_path,
command=help_command,
status="schema_flag_mismatch",
exit_code=3,
stdout="",
stderr="",
error="; ".join(problems),
)
]
contract = SmokeResult(
canonical_path=path,
case_name="contract",
cli_path=cli_path,
command=help_command,
status="contract_pass",
exit_code=0,
stdout="",
stderr="",
)
capability_problem = dry_run_capability_error(leaf)
if capability_problem:
contract.status = "invalid_dry_run_capability"
contract.exit_code = 3
contract.error = capability_problem
return [contract]
if not declared_dry_run(leaf):
return [contract]
return [
contract,
*[
run_smoke_case(
binary,
cwd,
path,
leaf,
timeout,
include_optional,
choices,
)
for choices in one_of_cases(leaf)
],
]
except subprocess.TimeoutExpired as exc:
return [
SmokeResult(
canonical_path=path,
case_name="contract",
cli_path=cli_path,
command=exc.cmd if isinstance(exc.cmd, list) else [str(exc.cmd)],
status="timeout",
exit_code=124,
stdout=exc.stdout or "",
stderr=exc.stderr or "",
error=str(exc),
)
]
except Exception as exc: # noqa: BLE001 - record all smoke failures.
return [
SmokeResult(
canonical_path=path,
case_name="contract",
cli_path=cli_path,
command=help_command,
status="error",
exit_code=1,
stdout="",
stderr="",
error=str(exc),
)
]
def result_to_dict(result: SmokeResult) -> dict[str, Any]:
return {
"canonical_path": result.canonical_path,
"case": result.case_name,
"phase": (
"contract"
if result.case_name == "contract"
else "runtime_exit_health"
),
"cli_path": result.cli_path,
"command": result.command,
"status": result.status,
"exit_code": result.exit_code,
"stdout": result.stdout[-4000:],
"stderr": result.stderr[-4000:],
"error": result.error,
}
def load_schema_leaves(
binary: str,
cwd: Path,
timeout: int,
requested_paths: list[str] | None = None,
) -> list[dict[str, Any]]:
"""Load the full inventory once and optionally select canonical paths."""
listing = run_json(
[binary, "schema", "--all", "--format", "json"],
cwd,
timeout,
attempts=1,
)
if not isinstance(listing, dict):
raise RuntimeError("schema --all payload must be an object")
products = listing.get("products")
if not isinstance(products, list):
raise RuntimeError("schema --all products must be an array")
by_path: dict[str, dict[str, Any]] = {}
for product_index, product in enumerate(products):
if not isinstance(product, dict):
raise RuntimeError(
f"schema --all product {product_index} must be an object"
)
tools = product.get("tools")
if not isinstance(tools, list):
raise RuntimeError(
f"schema --all product {product_index} tools must be an array"
)
for raw_leaf in tools:
if not isinstance(raw_leaf, dict):
raise RuntimeError("schema --all returned a non-object tool")
raw_path = raw_leaf.get("canonical_path")
if not isinstance(raw_path, str) or not raw_path.strip():
raise RuntimeError("schema --all returned a tool without canonical_path")
path = raw_path.strip()
if path in by_path:
raise RuntimeError(f"schema --all returned duplicate tool {path}")
cli_path = raw_leaf.get("cli_path")
if not isinstance(cli_path, str) or not cli_path.strip():
raise RuntimeError(
f"schema --all tool {path} has no non-empty cli_path"
)
if "parameters" not in raw_leaf:
raise RuntimeError(
f"schema --all tool {path} is a summary, not a full leaf"
)
if not isinstance(raw_leaf["parameters"], dict):
raise RuntimeError(
f"schema --all full tool {path} parameters must be an object"
)
for parameter_name, parameter in raw_leaf["parameters"].items():
if not isinstance(parameter, dict):
raise RuntimeError(
"schema --all full tool "
f"{path} parameter {parameter_name!r} must be an object"
)
capability_problem = dry_run_capability_error(raw_leaf)
if capability_problem:
raise RuntimeError(
f"schema --all tool {path} has invalid dry_run: "
f"{capability_problem}"
)
by_path[path] = raw_leaf
if not by_path:
raise RuntimeError("schema --all returned no full tools")
if not requested_paths:
return [by_path[path] for path in sorted(by_path)]
selected_paths = list(dict.fromkeys(requested_paths))
missing = sorted(set(selected_paths) - set(by_path))
if missing:
raise RuntimeError(
"requested canonical path missing from schema --all: " + ", ".join(missing)
)
return [by_path[path] for path in selected_paths]
def write_markdown(
results: list[SmokeResult],
output: Path,
tool_count: int,
runtime_tool_count: int,
) -> None:
counts: dict[str, int] = {}
for result in results:
counts[result.status] = counts.get(result.status, 0) + 1
lines = [
"# Schema Command Smoke Results",
"",
f"- Generated: {datetime.now(timezone.utc).isoformat()}",
f"- Tools: {tool_count}",
f"- Contract checks: {sum(r.case_name == 'contract' for r in results)}",
f"- Runtime exit-health tools: {runtime_tool_count}",
f"- Runtime exit-health cases: {sum(r.case_name.startswith('dry_run/') for r in results)}",
f"- Result rows: {len(results)}",
"- Safety proof: Go Agent-example dry-run gate (not inferred here)",
]
for status in sorted(counts):
lines.append(f"- {status}: {counts[status]}")
lines.extend(["", "## Non-passing cases", ""])
failures = [
r
for r in results
if r.status not in {"contract_pass", "runtime_exit_pass"}
]
if not failures:
lines.append("No failures.")
else:
lines.append("| canonical_path | case | cli_path | status | exit | issue |")
lines.append("| --- | --- | --- | --- | --- | --- |")
for result in failures:
issue = result.error or result.stderr.strip() or result.stdout.strip()
issue = issue.replace("\n", "<br>")
if len(issue) > 500:
issue = issue[:500] + "..."
lines.append(
"| "
+ " | ".join(
[
f"`{result.canonical_path}`",
f"`{result.case_name}`",
f"`{result.cli_path}`",
result.status,
str(result.exit_code),
issue or "-",
]
)
+ " |"
)
output.write_text("\n".join(lines) + "\n", encoding="utf-8")
def main() -> int:
parser = argparse.ArgumentParser(
description=(
"Load full schema --all once, check every selected leaf against "
"Cobra Help, and exit-health-check only explicit dry_run capabilities."
)
)
parser.add_argument("--binary", default="./dws", help="dws binary to inspect")
parser.add_argument("--output-jsonl", default="tmp/schema-command-smoke.jsonl")
parser.add_argument("--output-md", default="tmp/schema-command-smoke.md")
parser.add_argument(
"--jobs", type=int, default=8, help="parallel Help/runtime-health workers"
)
parser.add_argument("--timeout", type=int, default=20, help="seconds per subprocess")
parser.add_argument(
"--include-optional",
action="store_true",
help="include optional parameters in explicit runtime exit-health cases",
)
parser.add_argument(
"--path",
action="append",
help=(
"canonical path selected from the single schema --all payload; "
"repeatable"
),
)
args = parser.parse_args()
cwd = Path.cwd()
leaves = load_schema_leaves(
args.binary, cwd, args.timeout, requested_paths=args.path
)
runtime_tool_count = sum(declared_dry_run(leaf) for leaf in leaves)
if runtime_tool_count:
fixture = Path(tempfile.gettempdir()) / "dws-schema-smoke-fixture.txt"
fixture.write_text("schema smoke fixture\n", encoding="utf-8")
style_fixture = Path(tempfile.gettempdir()) / "dws-schema-smoke-style.json"
style_fixture.write_text(
'[{"sheetId":"sheet-smoke","range":"A1","fontSize":12}]\n',
encoding="utf-8",
)
report_fixture = cwd / "tmp" / "dws-schema-smoke-report.json"
report_fixture.parent.mkdir(parents=True, exist_ok=True)
report_fixture.write_text(
'[{"content":"schema smoke","sort":"0","key":"work",'
'"contentType":"markdown","type":"1"}]\n',
encoding="utf-8",
)
with concurrent.futures.ThreadPoolExecutor(max_workers=args.jobs) as executor:
result_groups = list(
executor.map(
lambda leaf: run_one(
args.binary, cwd, leaf, args.timeout, args.include_optional
),
leaves,
)
)
results = [result for group in result_groups for result in group]
results.sort(key=lambda item: (item.canonical_path, item.case_name))
jsonl_path = Path(args.output_jsonl)
jsonl_path.parent.mkdir(parents=True, exist_ok=True)
with jsonl_path.open("w", encoding="utf-8") as fh:
for result in results:
fh.write(json.dumps(result_to_dict(result), ensure_ascii=False) + "\n")
md_path = Path(args.output_md)
md_path.parent.mkdir(parents=True, exist_ok=True)
write_markdown(results, md_path, len(leaves), runtime_tool_count)
accepted = {"contract_pass", "runtime_exit_pass"}
failures = [result for result in results if result.status not in accepted]
contract_results = [result for result in results if result.case_name == "contract"]
runtime_results = [
result for result in results if result.case_name.startswith("dry_run/")
]
print(f"tools={len(leaves)}")
print(
"contract_pass="
f"{sum(result.status == 'contract_pass' for result in contract_results)}"
)
print(
"contract_failures="
f"{sum(result.status != 'contract_pass' for result in contract_results)}"
)
print(f"runtime_exit_tools={runtime_tool_count}")
print(f"runtime_exit_cases={len(runtime_results)}")
print(
"runtime_exit_failures="
f"{sum(result.status != 'runtime_exit_pass' for result in runtime_results)}"
)
print(f"total={len(results)}")
print(f"failures={len(failures)}")
print(f"jsonl={jsonl_path}")
print(f"markdown={md_path}")
return 1 if failures else 0
if __name__ == "__main__":
raise SystemExit(main())