From 768f61ee47360823d2b166d8c614e7f18d05a549 Mon Sep 17 00:00:00 2001 From: yaojingang Date: Tue, 16 Jun 2026 22:46:33 +0800 Subject: [PATCH] Validate ledger review timestamp order --- reports/architecture_maintainability.json | 4 +-- reports/architecture_maintainability.md | 4 +-- reports/context_budget.json | 12 +++---- reports/context_budget.md | 2 +- reports/context_budget_summary.json | 6 ++-- reports/security_trust_report.json | 2 +- reports/security_trust_report.md | 2 +- scripts/world_class_evidence_contract.py | 17 +++++++++ tests/verify_world_class_evidence_ledger.py | 40 +++++++++++++++++++++ 9 files changed, 73 insertions(+), 16 deletions(-) diff --git a/reports/architecture_maintainability.json b/reports/architecture_maintainability.json index 99ee9f3..a20776f 100644 --- a/reports/architecture_maintainability.json +++ b/reports/architecture_maintainability.json @@ -15,7 +15,7 @@ "warn_line_threshold": 900, "watch_line_threshold": 720, "block_line_threshold": 1500, - "largest_file_lines": 700, + "largest_file_lines": 717, "watchlist_count": 0, "hotspot_count": 0, "blocker_count": 0, @@ -24,7 +24,7 @@ "largest_files": [ { "path": "scripts/world_class_evidence_contract.py", - "lines": 700, + "lines": 717, "kind": "internal-module", "severity": "pass", "recommendation": "Watch this file before adding new responsibilities; extract a helper module when one concern dominates." diff --git a/reports/architecture_maintainability.md b/reports/architecture_maintainability.md index 615aa6f..841b089 100644 --- a/reports/architecture_maintainability.md +++ b/reports/architecture_maintainability.md @@ -13,7 +13,7 @@ Generated at: `2026-06-16` - Yao CLI command handlers: `68` - entrypoint command handlers: `18` - command modules: `6` -- largest file lines: `700` +- largest file lines: `717` - watch threshold lines: `720` - watchlist: `0` - hotspots: `0` @@ -33,7 +33,7 @@ No near-threshold files found. | File | Lines | Kind | Severity | | --- | ---: | --- | --- | -| `scripts/world_class_evidence_contract.py` | `700` | `internal-module` | `pass` | +| `scripts/world_class_evidence_contract.py` | `717` | `internal-module` | `pass` | | `tests/verify_yao_cli.py` | `696` | `test` | `pass` | | `scripts/render_review_viewer.py` | `685` | `cli-script` | `pass` | | `tests/verify_world_class_evidence_intake.py` | `669` | `test` | `pass` | diff --git a/reports/context_budget.json b/reports/context_budget.json index 85a94fd..a124eb7 100644 --- a/reports/context_budget.json +++ b/reports/context_budget.json @@ -6,15 +6,15 @@ "context_budget_tier": "production", "context_budget_limit": 1000, "skill_body_tokens": 797, - "other_text_tokens": 1057945, + "other_text_tokens": 1058565, "estimated_initial_load_tokens": 990, - "estimated_total_text_tokens": 1058742, - "deferred_resource_tokens": 489964, + "estimated_total_text_tokens": 1059362, + "deferred_resource_tokens": 490155, "deferred_resource_warn_threshold": 120000, "deferred_resource_dirs": [ { "path": "scripts", - "estimated_tokens": 429866, + "estimated_tokens": 430057, "file_count": 135 }, { @@ -36,7 +36,7 @@ "large_deferred_resource_dirs": [ { "path": "scripts", - "estimated_tokens": 429866, + "estimated_tokens": 430057, "file_count": 135 } ], @@ -59,7 +59,7 @@ ], "missing": [], "path": "scripts", - "estimated_tokens": 429866, + "estimated_tokens": 430057, "file_count": 135, "rationale": "Script resources are deterministic deferred tools, not initial-load prompt context." } diff --git a/reports/context_budget.md b/reports/context_budget.md index 8258c37..d7b8995 100644 --- a/reports/context_budget.md +++ b/reports/context_budget.md @@ -2,7 +2,7 @@ | Target | Path | Tier | Limit | Initial | SKILL | Deferred | Resource Governance | Large Deferred Dirs | Quality Density | Unused Dirs | Status | | --- | --- | --- | ---: | ---: | ---: | ---: | --- | --- | ---: | --- | --- | -| root | `.` | `production` | 1000 | 990 | 797 | 489964 | `governed` | scripts:429866 | 131.3 | - | ok | +| root | `.` | `production` | 1000 | 990 | 797 | 490155 | `governed` | scripts:430057 | 131.3 | - | ok | | complex-release-orchestrator | `examples/complex-release-orchestrator/generated-skill` | `production` | 1000 | 790 | 718 | 1657 | `not-required` | - | 164.6 | - | ok | | governed-incident-command | `examples/governed-incident-command/generated-skill` | `production` | 1000 | 760 | 658 | 1030 | `not-required` | - | 171.1 | - | ok | diff --git a/reports/context_budget_summary.json b/reports/context_budget_summary.json index 162ed46..93224ce 100644 --- a/reports/context_budget_summary.json +++ b/reports/context_budget_summary.json @@ -8,11 +8,11 @@ "budget_limit": 1000, "initial_tokens": 990, "skill_body_tokens": 797, - "deferred_resource_tokens": 489964, + "deferred_resource_tokens": 490155, "large_deferred_resource_dirs": [ { "path": "scripts", - "estimated_tokens": 429866, + "estimated_tokens": 430057, "file_count": 135 } ], @@ -35,7 +35,7 @@ ], "missing": [], "path": "scripts", - "estimated_tokens": 429866, + "estimated_tokens": 430057, "file_count": 135, "rationale": "Script resources are deterministic deferred tools, not initial-load prompt context." } diff --git a/reports/security_trust_report.json b/reports/security_trust_report.json index c86bd5d..13d2453 100644 --- a/reports/security_trust_report.json +++ b/reports/security_trust_report.json @@ -23,7 +23,7 @@ "interactive_script_count": 0, "package_hash_scope": "source-contract-without-generated-reports", "package_hash_file_count": 226, - "package_sha256": "a19c34849f99fe3f9166f7ba13c54d9ca709e1cec205ad3a1e82e8f1eb30d895" + "package_sha256": "6149b95fa5fb9a93108ed5099f3f53e629fa6ac673e03206371d5837a31bae97" }, "failures": [], "warnings": [], diff --git a/reports/security_trust_report.md b/reports/security_trust_report.md index 9cd24f6..7f5c83e 100644 --- a/reports/security_trust_report.md +++ b/reports/security_trust_report.md @@ -16,7 +16,7 @@ - Interactive scripts: `0` - Package hash scope: `source-contract-without-generated-reports` - Package hash files: `226` -- Package SHA256: `a19c34849f99fe3f9166f7ba13c54d9ca709e1cec205ad3a1e82e8f1eb30d895` +- Package SHA256: `6149b95fa5fb9a93108ed5099f3f53e629fa6ac673e03206371d5837a31bae97` ## Failures diff --git a/scripts/world_class_evidence_contract.py b/scripts/world_class_evidence_contract.py index 1f271d9..f8e8c35 100644 --- a/scripts/world_class_evidence_contract.py +++ b/scripts/world_class_evidence_contract.py @@ -2,6 +2,7 @@ import hashlib import json import re +from datetime import datetime, timezone from pathlib import Path from typing import Any @@ -159,6 +160,15 @@ def require_real_text(errors: list[str], value: Any, field: str) -> None: add_error(errors, not has_placeholder_text(text), f"{field} must not use template placeholder text") +def parse_audit_timestamp(value: Any) -> datetime | None: + text = str(value or "").strip() + if not SUBMITTED_AT_RE.match(text): + return None + if "T" in text: + return datetime.fromisoformat(text.replace("Z", "+00:00")).astimezone(timezone.utc) + return datetime.fromisoformat(text).replace(tzinfo=timezone.utc) + + def forbidden_submission_field_paths(value: Any, prefix: str = "$") -> list[str]: found: list[str] = [] if isinstance(value, dict): @@ -689,6 +699,13 @@ def validate_payload( bool(ledger_reviewer and submitted_by and ledger_reviewer.casefold() != submitted_by.casefold()), "attestation.ledger_reviewer must be different from submitted_by", ) + submitted_at = parse_audit_timestamp(payload.get("submitted_at")) + ledger_reviewed_at = parse_audit_timestamp(attestation.get("ledger_reviewed_at")) + add_error( + errors, + bool(submitted_at and ledger_reviewed_at and ledger_reviewed_at >= submitted_at), + "attestation.ledger_reviewed_at must be at or after submitted_at", + ) validate_real_artifact_payloads(payload, errors, root, template_expected) return { "path": rel_path(path, root), diff --git a/tests/verify_world_class_evidence_ledger.py b/tests/verify_world_class_evidence_ledger.py index 2392cd6..b15c487 100644 --- a/tests/verify_world_class_evidence_ledger.py +++ b/tests/verify_world_class_evidence_ledger.py @@ -464,6 +464,46 @@ def main() -> None: for error in self_approved_provider["submission_state"]["errors"] ), self_approved_provider + early_review_submissions = TMP / "early_review_submissions" + early_review_submissions.mkdir() + early_review_submission = provider_submission(accepted_source_skill) + early_review_submission["submitted_at"] = "2026-06-13" + early_review_submission["attestation"]["ledger_reviewed_at"] = "2026-06-12" + (early_review_submissions / "provider-holdout.json").write_text( + json.dumps(early_review_submission, ensure_ascii=False, indent=2) + "\n", + encoding="utf-8", + ) + early_review_proc = subprocess.run( + [ + sys.executable, + str(SCRIPT), + str(accepted_source_skill), + "--output-json", + str(TMP / "early_review_provider_ledger.json"), + "--output-md", + str(TMP / "early_review_provider_ledger.md"), + "--submissions-dir", + str(early_review_submissions), + "--generated-at", + "2026-06-13", + ], + cwd=ROOT, + capture_output=True, + text=True, + check=True, + ) + early_review_payload = json.loads(early_review_proc.stdout) + early_review_provider = { + entry["key"]: entry for entry in early_review_payload["entries"] + }["provider-holdout"] + assert early_review_provider["source_accepted"] is True, early_review_provider + assert early_review_provider["status"] == "pending", early_review_provider + assert early_review_provider["submission_state"]["status"] == "invalid-contract", early_review_provider + assert any( + "attestation.ledger_reviewed_at must be at or after submitted_at" in error + for error in early_review_provider["submission_state"]["errors"] + ), early_review_provider + accepted_submissions = TMP / "accepted_submissions" accepted_submissions.mkdir() (accepted_submissions / "provider-holdout.json").write_text(