feat: make Core reports commercially production-ready
This commit is contained in:
@@ -30,6 +30,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
from contextlib import contextmanager
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import queue
|
||||
@@ -160,6 +161,9 @@ def _render_init(result):
|
||||
("Clients", _client_names(result["clients"])),
|
||||
("Files", "%d created or updated" % len(result["created"])),
|
||||
("Harness", result["harness_version"]),
|
||||
("Core readiness", result["readiness"]["dimensions"]["core"]["status"].replace("_", " ")),
|
||||
("Domain Pipeline", result["readiness"]["dimensions"]["domain_pipeline"]["status"].replace("_", " ")),
|
||||
("Provider Telemetry", result["readiness"]["dimensions"]["provider_telemetry"]["status"].replace("_", " ")),
|
||||
])
|
||||
print()
|
||||
print(_color("1", "Integrations"))
|
||||
@@ -178,9 +182,13 @@ def _render_init(result):
|
||||
_mark(ok), "VS Code extension", extension.get("status")))
|
||||
print()
|
||||
print(_color("1", "Next steps"))
|
||||
print(" 1. Run `casan doctor`")
|
||||
if "codex" in result["clients"]:
|
||||
print(" 2. In a local Codex client, open `/hooks` and trust this project's hook.")
|
||||
actions = result["readiness"].get("next_actions") or []
|
||||
steps = [action["message"] for action in actions]
|
||||
steps.append("Run `casan doctor` for the deep integrity and client smoke check.")
|
||||
steps.append(
|
||||
"After a governed prompt, run `casan view` to inspect its H1–H7 evidence.")
|
||||
for index, step in enumerate(steps, 1):
|
||||
print(" %d. %s" % (index, step))
|
||||
|
||||
|
||||
def _render_verify(result):
|
||||
@@ -1221,6 +1229,7 @@ def cmd_init(args):
|
||||
cfg = {
|
||||
"schema_version": "21.3",
|
||||
"project_id": project,
|
||||
"project_name": project,
|
||||
"created_at": now_iso(),
|
||||
"enforcement_mode": args.mode,
|
||||
"integration_mode": args.integration_mode,
|
||||
@@ -1413,6 +1422,40 @@ def cmd_init(args):
|
||||
newly_owned_files.update(domain_files)
|
||||
level_extras.append("apps/%s/domain (%d files)" % (project, n))
|
||||
|
||||
# ── Commercial readiness contract.
|
||||
# Core acceptance never invents or modifies application-domain inputs.
|
||||
# Domain Pipeline and Provider Telemetry have independent readiness states.
|
||||
readiness_module_path = os.path.join(
|
||||
active_harness, "scripts", "python", "readiness.py")
|
||||
if not os.path.isfile(readiness_module_path):
|
||||
sys.stderr.write(
|
||||
"casan init: resolved Core is missing the readiness contract\n")
|
||||
return 1
|
||||
readiness_state_paths = (
|
||||
os.path.join(target, ".casan", "discovery.json"),
|
||||
os.path.join(target, ".casan", "readiness.json"),
|
||||
)
|
||||
for state_path in readiness_state_paths:
|
||||
mark_owned_if_absent(state_path)
|
||||
try:
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"casan_runtime_readiness", readiness_module_path)
|
||||
readiness_module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(readiness_module)
|
||||
client_state = {}
|
||||
if "codex" in clients:
|
||||
client_state["codex"] = _codex_project_hook_trust(
|
||||
target, timeout=3)
|
||||
readiness = readiness_module.assess(
|
||||
target, persist=True, client_state=client_state)
|
||||
except (AttributeError, OSError, TypeError, ValueError) as error:
|
||||
sys.stderr.write(
|
||||
"casan init: cannot generate commercial readiness state: %s\n" %
|
||||
error)
|
||||
return 1
|
||||
for state_path in readiness_state_paths:
|
||||
created_add(state_path)
|
||||
|
||||
# ── manifest (so uninstall/verify know what init created) ──
|
||||
owned_file_hashes = {
|
||||
path: digest
|
||||
@@ -1460,6 +1503,7 @@ def cmd_init(args):
|
||||
"level_extras": level_extras,
|
||||
"level_removed": level_removed,
|
||||
"level_retained": level_retained,
|
||||
"readiness": readiness,
|
||||
"note": (
|
||||
"managed runtime is referenced by version/hash lock"
|
||||
if runtime_mode == "managed" else
|
||||
@@ -1910,6 +1954,18 @@ def cmd_doctor(args):
|
||||
ready = ready and client_ready
|
||||
checks["client_checks"][client] = item
|
||||
|
||||
for client, item in checks["client_checks"].items():
|
||||
if item.get("ready") or client == "codex":
|
||||
continue
|
||||
checks["required_actions"].append({
|
||||
"code": "%s_activation" % client.replace("-", "_"),
|
||||
"message": (
|
||||
item.get("install_action")
|
||||
or "Repair the selected %s client route, then run `casan doctor`."
|
||||
% CLIENT_LABELS.get(client, client)
|
||||
),
|
||||
})
|
||||
|
||||
if "codex" in clients:
|
||||
codex_check = checks["client_checks"].get("codex", {})
|
||||
trust = codex_check.get("trust", {})
|
||||
@@ -1964,6 +2020,31 @@ def cmd_doctor(args):
|
||||
else "user_action_required" if checks["required_actions"]
|
||||
else "ready"
|
||||
)
|
||||
if harness:
|
||||
readiness_module_path = os.path.join(
|
||||
harness, "scripts", "python", "readiness.py")
|
||||
try:
|
||||
if not os.path.isfile(readiness_module_path):
|
||||
raise FileNotFoundError
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"casan_doctor_readiness", readiness_module_path)
|
||||
readiness_module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(readiness_module)
|
||||
readiness_clients = {
|
||||
client: {
|
||||
**(item.get("trust", {}) if client == "codex" else {}),
|
||||
"operational": bool(item.get("ready")),
|
||||
}
|
||||
for client, item in checks["client_checks"].items()
|
||||
}
|
||||
checks["readiness"] = readiness_module.assess(
|
||||
target, persist=True, client_state=readiness_clients)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except (AttributeError, OSError, TypeError, ValueError) as error:
|
||||
checks["warnings"].append(
|
||||
"Commercial readiness state could not be refreshed: %s." %
|
||||
error)
|
||||
_emit_json_or_human(args, checks, _render_doctor)
|
||||
return 0 if ready else 2
|
||||
|
||||
@@ -2150,6 +2231,9 @@ def cmd_uninstall(args):
|
||||
".casan/version.lock",
|
||||
".casan/agentic.env",
|
||||
".casan/casan-hook.py",
|
||||
".casan/domain.json",
|
||||
".casan/discovery.json",
|
||||
".casan/readiness.json",
|
||||
".casan/init-manifest.json"):
|
||||
_remove_owned_file(
|
||||
os.path.join(target, *relative.split("/")), removed, target)
|
||||
|
||||
@@ -80,6 +80,7 @@ for required in (
|
||||
"packages/casan-harness/scripts/python/local_report.py",
|
||||
"packages/casan-harness/scripts/python/local_viewer.py",
|
||||
"packages/casan-harness/scripts/python/report_cli.py",
|
||||
"packages/casan-harness/scripts/python/readiness.py",
|
||||
):
|
||||
assert (root / required).is_file(), required
|
||||
registry = json.loads(
|
||||
@@ -148,6 +149,7 @@ for required in (
|
||||
"packages/casan-harness/config/tool-registry.yaml",
|
||||
"packages/casan-harness/scripts/bash/casan-harness.sh",
|
||||
"packages/casan-harness/scripts/python/local_viewer.py",
|
||||
"packages/casan-harness/scripts/python/readiness.py",
|
||||
"packaging/runtime-layout.json",
|
||||
"scripts/copy-runtime.py",
|
||||
"install.sh",
|
||||
@@ -159,9 +161,31 @@ echo "===== ② casan init (config only, no harness copy) ====="
|
||||
PROJ="$WORK/proj/my-app"; mkdir -p "$PROJ"; echo '{"name":"x"}' > "$PROJ/package.json"
|
||||
( cd "$PROJ" && "$CASAN" init --project my-app --mode enforce >/dev/null 2>&1 ) \
|
||||
&& pass "casan init completes" || fail "casan init failed"
|
||||
for f in .casan/config.json .casan/version.lock .casan/agentic.env .casan/casan-hook.py .claude/settings.json .codex/hooks.json .vscode/extensions.json .specify/.gitignore; do
|
||||
for f in .casan/config.json .casan/version.lock .casan/agentic.env .casan/casan-hook.py .casan/discovery.json .casan/readiness.json .claude/settings.json .codex/hooks.json .vscode/extensions.json .specify/.gitignore; do
|
||||
[[ -f "$PROJ/$f" ]] && pass "init wrote $f" || fail "init missing $f"
|
||||
done
|
||||
python3 - "$PROJ/.casan/readiness.json" <<'PY' \
|
||||
&& pass "Core readiness is independent from optional Domain/Provider states" \
|
||||
|| fail "commercial readiness contract is invalid"
|
||||
import json
|
||||
import sys
|
||||
|
||||
d = json.load(open(sys.argv[1], encoding="utf-8"))
|
||||
assert d["dimensions"]["core"]["status"] in {"ready", "ready_with_attention"}
|
||||
assert d["dimensions"]["domain_pipeline"]["status"] == "not_configured"
|
||||
assert d["dimensions"]["provider_telemetry"]["status"] == "optional_unavailable"
|
||||
PY
|
||||
CASAN_APP_ROOT="$PROJ" "$CASAN" pipeline --help 2>&1 \
|
||||
| grep -q "optional Domain Pack" \
|
||||
&& pass "pipeline help describes the optional capability without executing it" \
|
||||
|| fail "pipeline help executed or hid the Core/Domain boundary"
|
||||
set +e
|
||||
PIPELINE_MISSING="$(CASAN_APP_ROOT="$PROJ" "$CASAN" pipeline 2>&1)"
|
||||
PIPELINE_RC=$?
|
||||
set -e
|
||||
[[ "$PIPELINE_RC" -eq 2 && "$PIPELINE_MISSING" == *"CASAN_PIPELINE_NOT_CONFIGURED"* ]] \
|
||||
&& pass "missing Domain Pipeline is explicit and does not impersonate a Core failure" \
|
||||
|| fail "missing Domain Pipeline capability was not reported truthfully"
|
||||
python3 - "$PROJ/.casan/config.json" <<'PY' \
|
||||
&& pass "config declares supported and excluded client surfaces" \
|
||||
|| fail "config client surface contract is incomplete"
|
||||
|
||||
Reference in New Issue
Block a user