Prefill world-class submission artifact hashes

This commit is contained in:
yaojingang
2026-06-16 03:58:05 +08:00
parent 7b21b9f633
commit fa4067771b
6 changed files with 152 additions and 10 deletions
+2
View File
@@ -154,6 +154,8 @@ python3 scripts/yao.py world-class-evidence .
SUBMISSIONS_DIR="${SUBMISSIONS_DIR:-evidence/world_class/submissions}"
python3 scripts/yao.py world-class-preflight . --submissions-dir "$SUBMISSIONS_DIR"
python3 scripts/yao.py world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR"
# Alternative: prefill artifact SHA-256 digests while keeping drafts template-only.
python3 scripts/yao.py world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR" --prefill-artifacts
python3 scripts/yao.py world-class-intake . --submissions-dir "$SUBMISSIONS_DIR"
python3 scripts/yao.py world-class-submission-review . --submissions-dir "$SUBMISSIONS_DIR"
python3 scripts/yao.py world-class-ledger . --submissions-dir "$SUBMISSIONS_DIR"
+3 -1
View File
@@ -10,6 +10,8 @@ Run:
SUBMISSIONS_DIR="${SUBMISSIONS_DIR:-evidence/world_class/submissions}"
python3 scripts/yao.py world-class-preflight . --submissions-dir "$SUBMISSIONS_DIR"
python3 scripts/yao.py world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR"
# Alternative: prefill artifact SHA-256 digests while keeping drafts template-only.
python3 scripts/yao.py world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR" --prefill-artifacts
python3 scripts/yao.py world-class-intake . --submissions-dir "$SUBMISSIONS_DIR"
python3 scripts/yao.py world-class-submission-review . --submissions-dir "$SUBMISSIONS_DIR"
python3 scripts/yao.py world-class-ledger . --submissions-dir "$SUBMISSIONS_DIR"
@@ -28,7 +30,7 @@ Run `world-class-preflight` before assigning external or human work. It checks l
The generated intake report also includes an `operator_checklist` for each pending evidence item. Use it to find the template path, target submission path, preparation command, validation command, required provenance, success checks, and privacy boundary before asking a reviewer or external operator to submit evidence.
The submission kit command creates editable JSON drafts plus a local README for an external operator or human reviewer. Those drafts keep `template_only: true` and do not count as evidence until the real run or review exists, the packet is edited truthfully, every artifact ref points to a local aggregate evidence file with a matching `sha256`, and `world-class-intake` validates it.
The submission kit command creates editable JSON drafts plus a local README for an external operator or human reviewer. Use `--prefill-artifacts` when you want the kit to insert SHA-256 digests for currently available local aggregate artifacts. Prefill is operator convenience only: those drafts still keep `template_only: true` and do not count as evidence until the real run or review exists, the packet is edited truthfully, every artifact ref points to a local aggregate evidence file with a matching `sha256`, and `world-class-intake` validates it.
The submission review command renders a read-only queue that compares valid packets with the source evidence checks and current ledger state. It is for reviewer triage only; it does not accept evidence or make the world-class claim true.
+109 -9
View File
@@ -3,7 +3,6 @@ import argparse
import hashlib
import json
import shlex
import shutil
from datetime import date
from pathlib import Path
from typing import Any
@@ -59,12 +58,60 @@ def template_result_by_key(intake: dict[str, Any]) -> dict[str, dict[str, Any]]:
return {str(item.get("evidence_key")): item for item in intake.get("templates", [])}
def artifact_rows_by_key_and_path(rows: list[dict[str, Any]]) -> dict[tuple[str, str], dict[str, Any]]:
ready: dict[tuple[str, str], dict[str, Any]] = {}
for row in rows:
key = str(row.get("evidence_key", ""))
path = str(row.get("path", ""))
if key and path and row.get("artifact_ref_ready"):
ready[(key, path)] = row
return ready
def load_template_payload(path: Path, errors: list[str]) -> dict[str, Any] | None:
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
errors.append("template file is not valid JSON")
return None
return payload if isinstance(payload, dict) else None
def prefill_artifact_refs(
payload: dict[str, Any],
evidence_key: str,
ready_rows: dict[tuple[str, str], dict[str, Any]],
) -> dict[str, int]:
refs = payload.get("artifact_refs", [])
stats = {
"prefilled_artifact_ref_count": 0,
"unfilled_artifact_ref_count": 0,
}
if not isinstance(refs, list):
return stats
for ref in refs:
if not isinstance(ref, dict):
stats["unfilled_artifact_ref_count"] += 1
continue
path = str(ref.get("path", "")).strip()
row = ready_rows.get((evidence_key, path))
if row and row.get("sha256"):
ref["sha256"] = row["sha256"]
ref["contains_raw_content"] = False
stats["prefilled_artifact_ref_count"] += 1
else:
stats["unfilled_artifact_ref_count"] += 1
return stats
def copy_template(
skill_dir: Path,
output_dir: Path,
item: dict[str, Any],
template_results: dict[str, dict[str, Any]],
ready_rows: dict[tuple[str, str], dict[str, Any]],
overwrite: bool,
prefill_artifacts: bool,
) -> dict[str, Any]:
key = str(item.get("evidence_key", ""))
template_result = template_results.get(key, {})
@@ -83,6 +130,8 @@ def copy_template(
"status": "skipped",
"template_path": rel_path(template_path, skill_dir),
"output_path": rel_path(output_path, skill_dir),
"prefilled_artifact_ref_count": 0,
"unfilled_artifact_ref_count": 0,
"errors": errors,
}
@@ -92,16 +141,36 @@ def copy_template(
"status": "exists",
"template_path": rel_path(template_path, skill_dir),
"output_path": rel_path(output_path, skill_dir),
"prefilled_artifact_ref_count": 0,
"unfilled_artifact_ref_count": 0,
"errors": [],
}
payload = load_template_payload(template_path, errors)
if errors or payload is None:
return {
"evidence_key": key,
"status": "skipped",
"template_path": rel_path(template_path, skill_dir),
"output_path": rel_path(output_path, skill_dir),
"prefilled_artifact_ref_count": 0,
"unfilled_artifact_ref_count": 0,
"errors": errors or ["template file is not a JSON object"],
}
prefill_stats = (
prefill_artifact_refs(payload, key, ready_rows)
if prefill_artifacts
else {"prefilled_artifact_ref_count": 0, "unfilled_artifact_ref_count": 0}
)
output_path.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(template_path, output_path)
write_json(output_path, payload)
return {
"evidence_key": key,
"status": "written",
"template_path": rel_path(template_path, skill_dir),
"output_path": rel_path(output_path, skill_dir),
**prefill_stats,
"errors": [],
}
@@ -210,6 +279,7 @@ def render_readme(report: dict[str, Any]) -> str:
"3. Set `template_only` to `false` only after real evidence exists.",
"4. Set attestation booleans truthfully; do not include credentials, raw prompts, raw outputs, transcripts, notes, or private user content.",
"5. Validate the packet before asking the ledger reviewer to accept it.",
"6. Optional artifact prefill only inserts SHA-256 digests for current local aggregate artifacts; it does not mark a draft as real evidence.",
"",
"## Commands",
"",
@@ -219,11 +289,13 @@ def render_readme(report: dict[str, Any]) -> str:
"",
"## Drafts",
"",
"| Evidence | Draft | Status |",
"| --- | --- | --- |",
"| Evidence | Draft | Status | Prefilled refs |",
"| --- | --- | --- | ---: |",
]
for item in report["files"]:
lines.append(f"| `{item['evidence_key']}` | `{item['output_path']}` | `{item['status']}` |")
lines.append(
f"| `{item['evidence_key']}` | `{item['output_path']}` | `{item['status']}` | `{item.get('prefilled_artifact_ref_count', 0)}` |"
)
lines.extend(["", "## Execution Runbook", ""])
for item in report.get("evidence_items", []):
must_collect = item.get("must_collect", {}) if isinstance(item.get("must_collect", {}), dict) else {}
@@ -304,6 +376,7 @@ def render_html_files(files: list[dict[str, Any]]) -> str:
<dl>
<dt>Template</dt><dd><code>{template}</code></dd>
<dt>Draft</dt><dd><code>{output}</code></dd>
<dt>Prefill</dt><dd>{prefill} artifact refs</dd>
</dl>
{errors}
</article>
@@ -312,6 +385,7 @@ def render_html_files(files: list[dict[str, Any]]) -> str:
key=html_text(item.get("evidence_key", "")),
template=html_text(item.get("template_path", "")),
output=html_text(item.get("output_path", "")),
prefill=html_text(item.get("prefilled_artifact_ref_count", 0)),
errors=(
"<ul class=\"errors\">"
+ render_html_list(item.get("errors", []), "No errors.")
@@ -428,6 +502,7 @@ def render_html(report: dict[str, Any]) -> str:
("Existing", summary["existing_count"]),
("Skipped", summary["skipped_count"]),
("Artifacts", f"{artifact_ready}/{artifact_total}"),
("Prefilled", summary.get("artifact_ref_prefill_count", 0)),
]
stat_html = "".join(f"<article><span>{html_text(label)}</span><strong>{html_text(value)}</strong></article>" for label, value in stats)
evidence_html = "".join(render_html_item(item) for item in report.get("evidence_items", []))
@@ -457,7 +532,7 @@ def render_html(report: dict[str, Any]) -> str:
h3 {{ margin:4px 0 10px; font-size:22px; }}
h4 {{ margin:0 0 8px; font-size:16px; }}
.lede {{ max-width:800px; color:var(--muted); font-size:20px; }}
.stats {{ display:grid; grid-template-columns:repeat(5, minmax(0,1fr)); gap:12px; margin:26px 0 0; }}
.stats {{ display:grid; grid-template-columns:repeat(6, minmax(0,1fr)); gap:12px; margin:26px 0 0; }}
.stats article, .panel, .draft-card, .evidence-card {{ border:1px solid var(--line); border-radius:8px; background:#fff; }}
.stats article {{ padding:16px; }}
.stats span, .draft-card span, .evidence-card span, .muted {{ color:var(--muted); }}
@@ -495,11 +570,11 @@ def render_html(report: dict[str, Any]) -> str:
<section class="hero">
<span class="eyebrow">Evidence Intake</span>
<h1>World-Class Evidence Submission Kit</h1>
<p class="lede">Use this cockpit to prepare human and external evidence packets. Drafts are not accepted evidence, and this page never changes the ledger result.</p>
<p class="lede">Use this cockpit to prepare human and external evidence packets. Drafts are not accepted evidence, artifact prefill only inserts local SHA-256 digests, and this page never changes the ledger result.</p>
<div class="stats">{stat_html}</div>
</section>
<section class="section two-col" id="workflow">
<article class="panel"><h2>Workflow</h2><ol><li>Run the real provider, human review, native permission, or native client telemetry work first.</li><li>Edit the matching JSON draft with aggregate artifact references and provenance metadata.</li><li>Set template_only to false only after real evidence exists.</li><li>Validate intake, refresh the ledger, then guard public claims.</li></ol></article>
<article class="panel"><h2>Workflow</h2><ol><li>Run the real provider, human review, native permission, or native client telemetry work first.</li><li>Edit the matching JSON draft with aggregate artifact references and provenance metadata.</li><li>Set template_only to false only after real evidence exists.</li><li>Use prefilled SHA-256 values as convenience data, not evidence acceptance.</li><li>Validate intake, refresh the ledger, then guard public claims.</li></ol></article>
<aside class="panel"><h2>Commands</h2><ul class="commands">{render_html_commands(report['commands'])}</ul></aside>
</section>
<section class="section" id="drafts"><h2>Drafts</h2><div class="draft-grid">{render_html_files(report['files'])}</div></section>
@@ -519,6 +594,7 @@ def build_submission_kit(
generated_at: str,
evidence_keys: list[str] | None = None,
overwrite: bool = False,
prefill_artifacts: bool = False,
output_html: Path | None = None,
) -> dict[str, Any]:
intake = build_intake(skill_dir, generated_at, submissions_dir=output_dir)
@@ -526,8 +602,20 @@ def build_submission_kit(
valid_keys = {str(item.get("evidence_key")) for item in intake.get("operator_checklist", [])}
unknown_keys = sorted(set(evidence_keys or []) - valid_keys)
template_results = template_result_by_key(intake)
files = [copy_template(skill_dir, output_dir, item, template_results, overwrite) for item in items]
artifact_checklist = build_artifact_checklist(skill_dir, items)
ready_rows = artifact_rows_by_key_and_path(artifact_checklist)
files = [
copy_template(
skill_dir,
output_dir,
item,
template_results,
ready_rows,
overwrite,
prefill_artifacts,
)
for item in items
]
source_checklist = build_source_checklist(items)
manifest_path = output_dir / "submission_manifest.json"
readme_path = output_dir / "README.md"
@@ -535,6 +623,8 @@ def build_submission_kit(
written_count = sum(1 for item in files if item["status"] == "written")
existing_count = sum(1 for item in files if item["status"] == "exists")
skipped_count = sum(1 for item in files if item["status"] == "skipped")
prefilled_artifact_ref_count = sum(item.get("prefilled_artifact_ref_count", 0) for item in files)
unfilled_artifact_ref_count = sum(item.get("unfilled_artifact_ref_count", 0) for item in files)
artifact_ready_count = sum(1 for item in artifact_checklist if item.get("artifact_ref_ready"))
artifact_missing_count = sum(1 for item in artifact_checklist if not item.get("artifact_ref_ready"))
artifact_glob_count = sum(1 for item in artifact_checklist if item.get("concrete_reference_required"))
@@ -557,6 +647,9 @@ def build_submission_kit(
"artifact_ready_count": artifact_ready_count,
"artifact_missing_count": artifact_missing_count,
"artifact_glob_expansion_count": artifact_glob_count,
"artifact_prefill_enabled": prefill_artifacts,
"artifact_ref_prefill_count": prefilled_artifact_ref_count,
"artifact_ref_unfilled_count": unfilled_artifact_ref_count,
**source_summary,
"drafts_count_as_evidence": False,
"ledger_counts_submission_as_completion": False,
@@ -574,6 +667,7 @@ def build_submission_kit(
},
"safety": {
"template_only_drafts": True,
"artifact_prefill_counts_as_evidence": False,
"real_evidence_required_before_template_only_false": True,
"raw_content_allowed": False,
"credentials_allowed": False,
@@ -599,6 +693,11 @@ def main() -> None:
parser.add_argument("--output-dir", default="evidence/world_class/submission-kit")
parser.add_argument("--evidence-key", action="append", default=[])
parser.add_argument("--overwrite", action="store_true")
parser.add_argument(
"--prefill-artifacts",
action="store_true",
help="Insert SHA-256 digests for currently available aggregate artifacts while keeping drafts template-only.",
)
parser.add_argument("--generated-at", default=date.today().isoformat())
parser.add_argument("--output-html")
args = parser.parse_args()
@@ -613,6 +712,7 @@ def main() -> None:
args.generated_at,
evidence_keys=args.evidence_key,
overwrite=args.overwrite,
prefill_artifacts=args.prefill_artifacts,
output_html=Path(args.output_html).resolve() if args.output_html else None,
)
print(json.dumps(report, ensure_ascii=False, indent=2))
+5
View File
@@ -237,6 +237,11 @@ def build_parser(command_handlers: dict[str, Callable[[argparse.Namespace], int]
world_class_submission_kit_cmd.add_argument("--output-dir")
world_class_submission_kit_cmd.add_argument("--evidence-key", action="append", default=[])
world_class_submission_kit_cmd.add_argument("--overwrite", action="store_true")
world_class_submission_kit_cmd.add_argument(
"--prefill-artifacts",
action="store_true",
help="Insert SHA-256 digests for currently available aggregate artifacts while keeping drafts template-only.",
)
world_class_submission_kit_cmd.add_argument("--generated-at")
world_class_submission_kit_cmd.add_argument("--output-html")
world_class_submission_kit_cmd.set_defaults(func=_handler(command_handlers, "command_world_class_submission_kit"))
+2
View File
@@ -196,6 +196,8 @@ def command_world_class_submission_kit(args: argparse.Namespace) -> int:
cmd.extend(["--evidence-key", key])
if args.overwrite:
cmd.append("--overwrite")
if args.prefill_artifacts:
cmd.append("--prefill-artifacts")
if args.generated_at:
cmd.extend(["--generated-at", args.generated_at])
if args.output_html:
@@ -499,6 +499,7 @@ def assert_documented_submission_commands() -> None:
'SUBMISSIONS_DIR="${SUBMISSIONS_DIR:-evidence/world_class/submissions}"',
'world-class-preflight . --submissions-dir "$SUBMISSIONS_DIR"',
'world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR"',
'world-class-submission-kit . --output-dir "$SUBMISSIONS_DIR" --prefill-artifacts',
'world-class-intake . --submissions-dir "$SUBMISSIONS_DIR"',
'world-class-submission-review . --submissions-dir "$SUBMISSIONS_DIR"',
'world-class-ledger . --submissions-dir "$SUBMISSIONS_DIR"',
@@ -614,8 +615,11 @@ def main() -> None:
kit_draft = json.loads((kit_dir / "provider-holdout.json").read_text(encoding="utf-8"))
assert kit_draft["template_only"] is True, kit_draft
assert kit_draft["attestation"]["real_external_or_human_evidence"] is False, kit_draft
assert "sha256" not in kit_draft["artifact_refs"][0], kit_draft
kit_manifest = json.loads((kit_dir / "submission_manifest.json").read_text(encoding="utf-8"))
assert kit_manifest["summary"]["ledger_counts_submission_as_completion"] is False, kit_manifest["summary"]
assert kit_manifest["summary"]["artifact_prefill_enabled"] is False, kit_manifest["summary"]
assert kit_manifest["summary"]["artifact_ref_prefill_count"] == 0, kit_manifest["summary"]
assert kit_manifest["artifact_checklist"] == kit_payload["artifact_checklist"], kit_manifest["artifact_checklist"]
assert kit_manifest["source_checklist"] == kit_payload["source_checklist"], kit_manifest["source_checklist"]
assert kit_manifest["artifacts"]["html"].endswith("tests/tmp_world_class_evidence_intake/submission_kit/index.html"), kit_manifest["artifacts"]
@@ -642,6 +646,33 @@ def main() -> None:
assert "output-exec --provider-runner openai" in kit_html, kit_html
assert "Do not include credentials, raw prompts, raw outputs, transcripts, notes, or private user content." in kit_html, kit_html
prefilled_kit_dir = TMP / "prefilled_submission_kit"
prefilled_proc = run_kit(
"--output-dir",
str(prefilled_kit_dir),
"--evidence-key",
"provider-holdout",
"--prefill-artifacts",
)
prefilled_payload = json.loads(prefilled_proc.stdout)
assert prefilled_payload["summary"]["artifact_prefill_enabled"] is True, prefilled_payload["summary"]
assert prefilled_payload["summary"]["artifact_ref_prefill_count"] == 1, prefilled_payload["summary"]
assert prefilled_payload["summary"]["artifact_ref_unfilled_count"] == 0, prefilled_payload["summary"]
assert prefilled_payload["summary"]["drafts_count_as_evidence"] is False, prefilled_payload["summary"]
assert prefilled_payload["safety"]["artifact_prefill_counts_as_evidence"] is False, prefilled_payload["safety"]
assert prefilled_payload["files"][0]["prefilled_artifact_ref_count"] == 1, prefilled_payload["files"]
prefilled_draft = json.loads((prefilled_kit_dir / "provider-holdout.json").read_text(encoding="utf-8"))
assert prefilled_draft["template_only"] is True, prefilled_draft
assert prefilled_draft["attestation"]["real_external_or_human_evidence"] is False, prefilled_draft
assert len(prefilled_draft["artifact_refs"][0]["sha256"]) == 64, prefilled_draft
assert prefilled_draft["artifact_refs"][0]["contains_raw_content"] is False, prefilled_draft
prefilled_readme = (prefilled_kit_dir / "README.md").read_text(encoding="utf-8")
assert "Optional artifact prefill only inserts SHA-256 digests" in prefilled_readme, prefilled_readme
assert "does not mark a draft as real evidence" in prefilled_readme, prefilled_readme
prefilled_html = (prefilled_kit_dir / "index.html").read_text(encoding="utf-8")
assert "artifact prefill only inserts local SHA-256 digests" in prefilled_html, prefilled_html
assert "<dt>Prefill</dt><dd>1 artifact refs</dd>" in prefilled_html, prefilled_html
native_kit_dir = TMP / "native_permission_kit"
native_kit_proc = run_kit("--output-dir", str(native_kit_dir), "--evidence-key", "native-permission-enforcement")
native_kit_payload = json.loads(native_kit_proc.stdout)