← Files VeraARCHIVED FILE
modules/new-client/scripts/promote_client_file_preparation.py
18.4 KB · Oct 2, 2026 · 00:29 UTC
from __future__ import annotations
import argparse
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Mapping, Sequence
SCRIPT_DIR = Path(__file__).resolve().parent
PLUGIN_ROOT = SCRIPT_DIR.parent
if str(SCRIPT_DIR) not in sys.path:
sys.path.insert(0, str(SCRIPT_DIR))
for _vendor_root in (
PLUGIN_ROOT / "vendor" / "modules",
PLUGIN_ROOT.parent.parent / "vendor" / "modules",
PLUGIN_ROOT.parent / "_shared" / "vendor" / "modules",
):
if (_vendor_root / "vera_assurance").is_dir():
if str(_vendor_root) not in sys.path:
sys.path.insert(0, str(_vendor_root))
break
from initialize_case import build_template # noqa: E402
from new_client_core import ( # noqa: E402
SUPPORTED_JURISDICTIONS,
SUPPORTED_LANGUAGES,
ValidationError,
ensure_private_output_directory,
load_json,
sha256_file,
validate_new_client_input,
verify_client_file_preparation_binding,
write_private_json,
)
from vera_assurance import ( # noqa: E402
AssuranceContractError,
load_client_engagement_context_file,
validate_client_workflow_run,
)
__all__ = ["build_parser", "main", "promote_client_file_preparation"]
def _run_relative_path(path: Path, run_root: Path, *, label: str) -> str:
try:
relative = path.resolve(strict=True).relative_to(run_root.resolve(strict=True))
except (OSError, ValueError) as exc:
raise ValidationError(f"{label} is outside the current customer run.") from exc
if not relative.parts:
raise ValidationError(f"{label} must identify a file inside the customer run.")
return relative.as_posix()
def _manifest_output_paths(manifest_path: Path) -> list[Path]:
manifest = load_json(manifest_path)
outputs = manifest.get("outputs")
if not isinstance(outputs, list) or not outputs:
raise ValidationError("Phase-one final_artifacts.outputs must not be empty.")
resolved: list[Path] = []
for index, output in enumerate(outputs):
if not isinstance(output, Mapping):
raise ValidationError(f"Phase-one outputs[{index}] must be an object.")
raw_path = output.get("path")
if not isinstance(raw_path, str):
raise ValidationError(f"Phase-one outputs[{index}].path must be text.")
relative = Path(raw_path)
if (
relative.is_absolute()
or relative.as_posix() != raw_path
or any(part in {"", ".", ".."} for part in relative.parts)
):
raise ValidationError(
"Phase-one outputs must use canonical relative paths."
)
candidate = manifest_path.parent / relative
try:
if candidate.is_symlink():
raise ValidationError("Phase-one outputs must not be symbolic links.")
output_path = candidate.resolve(strict=True)
except OSError as exc:
raise ValidationError(
f"Phase-one output {raw_path!r} cannot be resolved: {exc}"
) from exc
if not output_path.is_file():
raise ValidationError(f"Phase-one output {raw_path!r} is not a file.")
resolved.append(output_path)
return resolved
def _require_client_file_preparation_lineage(
context: Mapping[str, Any],
selected_paths: Sequence[Path],
) -> str:
"""Require selected files to come from one exact phase-one artifact handoff."""
raw_bindings = context.get("input_bindings")
if not isinstance(raw_bindings, list):
raise ValidationError("The New Client run has no validated input bindings.")
bindings_by_path: dict[Path, Mapping[str, Any]] = {}
for raw_binding in raw_bindings:
if not isinstance(raw_binding, Mapping):
raise ValidationError("The New Client run has an invalid input binding.")
raw_path = raw_binding.get("path")
if not isinstance(raw_path, str):
raise ValidationError("The New Client run has an invalid input path.")
try:
binding_path = Path(raw_path).resolve(strict=True)
except OSError as exc:
raise ValidationError(
f"A selected New Client input is unavailable: {exc}"
) from exc
bindings_by_path[binding_path] = raw_binding
upstream_run_ids: set[str] = set()
for selected_path in selected_paths:
try:
resolved = selected_path.resolve(strict=True)
except OSError as exc:
raise ValidationError(f"A phase-one input is unavailable: {exc}") from exc
binding = bindings_by_path.get(resolved)
if binding is None:
raise ValidationError(
"Every phase-one file must be an exact input of the New Client run."
)
if (
binding.get("kind") != "upstream_artifact"
or binding.get("upstream_workflow_id") != "client-file-preparation"
):
raise ValidationError(
"Phase one must be a verified Client File Preparation "
"upstream-artifact handoff."
)
upstream_run_id = binding.get("upstream_run_id")
if not isinstance(upstream_run_id, str) or not upstream_run_id:
raise ValidationError("A phase-one artifact has no upstream run identity.")
upstream_run_ids.add(upstream_run_id)
if len(upstream_run_ids) != 1:
raise ValidationError(
"All phase-one files must come from one Client File Preparation run."
)
return next(iter(upstream_run_ids))
def _reviewed_fiscal_items(
review_payload: Mapping[str, Any], applied_decisions: Mapping[str, Any]
) -> list[dict[str, Any]]:
"""Return accepted/edited fiscal fields only; never promote raw proposals."""
items = {
item.get("id"): item
for item in review_payload.get("items", [])
if isinstance(item, dict)
and item.get("item_type") == "extracted_fiscal_field"
and isinstance(item.get("id"), str)
}
promoted: list[dict[str, Any]] = []
for effect in applied_decisions.get("effects", []):
if not isinstance(effect, dict) or effect.get("action") not in {
"accept",
"edit",
}:
continue
item = items.get(effect.get("item_id"))
if not isinstance(item, dict):
continue
data = item.get("data")
if not isinstance(data, dict):
continue
value = effect.get("edit_value") if effect.get("action") == "edit" else None
if not isinstance(value, str) or not value.strip():
value = data.get("normalized_value") or data.get("value")
if not isinstance(value, str) or not value.strip():
continue
field_code = data.get("field_code")
if not isinstance(field_code, str) or not field_code.strip():
continue
promoted.append(
{
"item_id": effect["item_id"],
"field_code": field_code.strip(),
"value": value.strip(),
"document_kind": str(data.get("document_kind") or "unknown"),
"confidence": str(data.get("confidence") or "unknown"),
"source_relative_path": str(
data.get("relative_path") or item.get("source_path") or ""
),
"review_action": effect["action"],
}
)
return promoted
def _promote_reviewed_facts(
intake: dict[str, Any],
*,
verified_outputs: Sequence[Mapping[str, Any]],
) -> list[str]:
outputs_by_path = {record["path"]: record for record in verified_outputs}
review_record = outputs_by_path.get("review_payload.json")
applied_record = outputs_by_path.get("applied_decisions.json")
if review_record is None or applied_record is None:
raise ValidationError(
"The final-ready phase-one package lacks reviewed promotion inputs."
)
review_payload = load_json(Path(str(review_record["resolved_path"])))
applied_decisions = load_json(Path(str(applied_record["resolved_path"])))
if review_payload.get("run_id") != applied_decisions.get("run_id"):
raise ValidationError(
"Phase-one review payload and applied decisions use different run IDs."
)
promoted = _reviewed_fiscal_items(review_payload, applied_decisions)
unambiguous_tax_code_values = {
record["value"]
for record in promoted
if record["field_code"].casefold().startswith("codice_fiscale_")
and "partita_iva" not in record["field_code"].casefold()
}
if len(unambiguous_tax_code_values) != 1:
return []
evidence_id = "phase1-reviewed-decisions"
applied_path = Path(str(applied_record["resolved_path"]))
intake["evidence_register"].append(
{
"evidence_id": evidence_id,
"evidence_type": "reviewed_client_file_preparation_decisions",
"status": "available",
"obtained_on": None,
"expires_on": None,
"sha256": applied_record["sha256"],
"local_path": applied_path.as_posix(),
}
)
intake["tax_facts"]["codice_fiscale"] = {
"value": next(iter(unambiguous_tax_code_values)),
"verification_status": "reported",
"evidence_ids": [evidence_id],
}
return [evidence_id]
def promote_client_file_preparation(
final_artifacts_path: Path,
case_dir: Path,
*,
client_reference: str,
client_type: str = "company",
engagement_kind: str = "ongoing",
assessment_date: str | None = None,
jurisdiction: str | None = None,
language: str | None = None,
overwrite: bool = False,
run_root: Path | None = None,
) -> Path:
"""Create a private phase-two starter from a byte-verified final-ready run."""
manifest_path = final_artifacts_path.expanduser().resolve(strict=True)
manifest = load_json(manifest_path)
integrity = manifest.get("integrity")
if not isinstance(integrity, dict):
raise ValidationError(
"Phase-one final_artifacts.json has no integrity envelope."
)
package_hash = integrity.get("package_hash")
if not isinstance(package_hash, str):
raise ValidationError(
"Phase-one final_artifacts.json has no integrity.package_hash."
)
date_value = assessment_date or datetime.now(timezone.utc).date().isoformat()
intake = build_template(
client_reference,
client_type=client_type,
engagement_kind=engagement_kind,
assessment_date=date_value,
jurisdiction="IT",
language="it",
)
intake["client_file_preparation_binding"] = {
"mode": "client_file_preparation_run",
"run_id": manifest.get("run_id"),
"final_artifacts_path": manifest_path.as_posix(),
"final_artifacts_sha256": sha256_file(manifest_path),
"upstream_package_hash": package_hash,
"promoted_evidence_ids": [],
}
validate_new_client_input(intake)
verification = verify_client_file_preparation_binding(
intake, base_dir=manifest_path.parent
)
if verification.get("final_ready") is not True:
raise ValidationError(
"Only a final-ready Client File Preparation run can be promoted."
)
outputs_by_path = {
record["path"]: record for record in verification["verified_outputs"]
}
upstream_run_record = outputs_by_path.get("run_intake.json")
if upstream_run_record is None:
raise ValidationError("The phase-one package does not contain run_intake.json.")
upstream_run = load_json(Path(str(upstream_run_record["resolved_path"])))
upstream_jurisdiction = upstream_run.get("jurisdiction")
if upstream_jurisdiction == "mixed":
raise ValidationError(
"A mixed-jurisdiction file-preparation run cannot be promoted until "
"the professional isolates an Italy-only run."
)
if upstream_jurisdiction != "italy":
raise ValidationError(
"No Vera professional-setup country pack is available for the sealed "
f"phase-one jurisdiction {upstream_jurisdiction!r}."
)
if jurisdiction is not None and jurisdiction != "IT":
raise ValidationError(
"The requested professional-setup jurisdiction does not match the "
"sealed Italy phase-one run."
)
upstream_language = upstream_run.get("language")
if upstream_language not in SUPPORTED_LANGUAGES:
raise ValidationError(
"The sealed phase-one run does not declare a supported language."
)
if language is not None and language != upstream_language:
raise ValidationError(
"The requested language must match the sealed phase-one run language."
)
intake = build_template(
client_reference,
client_type=client_type,
engagement_kind=engagement_kind,
assessment_date=date_value,
jurisdiction="IT",
language=str(upstream_language),
)
intake["client_file_preparation_binding"] = {
"mode": "client_file_preparation_run",
"run_id": manifest.get("run_id"),
"final_artifacts_path": manifest_path.as_posix(),
"final_artifacts_sha256": sha256_file(manifest_path),
"upstream_package_hash": package_hash,
"promoted_evidence_ids": [],
}
promoted_evidence_ids = _promote_reviewed_facts(
intake,
verified_outputs=verification["verified_outputs"],
)
intake["client_file_preparation_binding"][
"promoted_evidence_ids"
] = promoted_evidence_ids
validate_new_client_input(intake)
verification = verify_client_file_preparation_binding(
intake, base_dir=manifest_path.parent
)
if verification.get("package_hash") != package_hash.casefold():
raise ValidationError("Phase-one package changed during promotion.")
if run_root is not None:
normalized_run_root = run_root.expanduser().resolve(strict=True)
binding = intake["client_file_preparation_binding"]
binding["final_artifacts_path"] = _run_relative_path(
manifest_path,
normalized_run_root,
label="Phase-one final_artifacts.json",
)
binding["final_artifacts_path_reference"] = "run_root_relative"
for index, evidence in enumerate(intake["evidence_register"]):
raw_path = evidence.get("local_path")
if not isinstance(raw_path, str):
continue
evidence["local_path"] = _run_relative_path(
Path(raw_path),
normalized_run_root,
label=f"Promoted evidence_register[{index}].local_path",
)
evidence["local_path_reference"] = "run_root_relative"
validate_new_client_input(intake)
output_dir = ensure_private_output_directory(
case_dir,
allowed_existing=("new_client_input.json",) if overwrite else (),
)
target = output_dir / "new_client_input.json"
if target.exists() and not overwrite:
raise ValidationError(
f"{target} already exists; pass --overwrite to replace the starter."
)
return write_private_json(target, intake)
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description=(
"Promote a byte-verified final-ready Client File Preparation run into "
"a private Vera New Client starter."
)
)
parser.add_argument("--final-artifacts", required=True, type=Path)
parser.add_argument("--case-dir", required=True, type=Path)
parser.add_argument("--client-engagement", required=True, type=Path)
parser.add_argument("--client-reference", required=True)
parser.add_argument(
"--client-type",
choices=("individual", "sole_trader", "company", "entity"),
default="company",
)
parser.add_argument(
"--engagement-kind", choices=("ongoing", "one_off"), default="ongoing"
)
parser.add_argument("--assessment-date")
parser.add_argument("--jurisdiction", choices=SUPPORTED_JURISDICTIONS)
parser.add_argument("--language", choices=SUPPORTED_LANGUAGES)
parser.add_argument("--overwrite", action="store_true")
return parser
def main(argv: Sequence[str] | None = None) -> int:
args = build_parser().parse_args(argv)
try:
context = load_client_engagement_context_file(
args.client_engagement,
expected_workflow_id="new-client",
input_paths=[args.final_artifacts],
output_dir=args.case_dir,
)
manifest_path = args.final_artifacts.expanduser().resolve(strict=True)
upstream_run_id = _require_client_file_preparation_lineage(
context,
[manifest_path],
)
manifest = load_json(manifest_path)
if manifest.get("run_id") != upstream_run_id:
raise ValidationError(
"Phase-one final_artifacts.json does not match its upstream run."
)
upstream_outputs = _manifest_output_paths(manifest_path)
validate_client_workflow_run(
context,
expected_workflow_id="new-client",
input_paths=[manifest_path, *upstream_outputs],
output_dir=args.case_dir,
)
if (
_require_client_file_preparation_lineage(
context,
[manifest_path, *upstream_outputs],
)
!= upstream_run_id
):
raise ValidationError(
"Phase-one files do not share their manifest's upstream run."
)
path = promote_client_file_preparation(
args.final_artifacts,
args.case_dir,
client_reference=args.client_reference,
client_type=args.client_type,
engagement_kind=args.engagement_kind,
assessment_date=args.assessment_date,
jurisdiction=args.jurisdiction,
language=args.language,
overwrite=args.overwrite,
run_root=Path(str(context["run_root"])),
)
except (AssuranceContractError, OSError, ValidationError) as exc:
sys.stdout.write(json.dumps({"status": "error", "error": str(exc)}) + "\n")
return 2
sys.stdout.write(
json.dumps(
{
"status": "new_client_input_promoted",
"path": path.as_posix(),
"file_mode": "0600",
"directory_mode": "0700",
},
ensure_ascii=False,
)
+ "\n"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
SHA-256: 666082d5278bc5ed9cc849183589fe93e55ffe3cdfcbb00535b6bf4718e28402