Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 57 additions & 10 deletions result_server/routes/results_detail_routes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import os
import re

from flask import abort, current_app, render_template, request, url_for
from werkzeug.exceptions import Forbidden, NotFound
Expand Down Expand Up @@ -27,7 +28,6 @@
get_file_confidential_tags,
load_public_result_json,
load_permitted_result_json,
padata_matches_public_result,
serve_permitted_result_file,
serve_public_padata_file,
)
Expand All @@ -39,6 +39,11 @@
from utils.trigger_display import load_trigger_run_lookup, summarize_execution_trigger


PADATA_ARTIFACT_BASENAME_RE = re.compile(
r"[A-Za-z0-9][A-Za-z0-9_.-]{0,127}\.(?:tgz|tar\.gz)"
)


def register_results_detail_routes(results_bp):
def public_surface():
return current_app.config.get("PUBLIC_PORTAL_MODE", False)
Expand Down Expand Up @@ -75,7 +80,7 @@ def result_detail(filename):
)
quality = summarize_result_quality(result)
padata_dir = current_app.config.get("RECEIVED_PADATA_DIR", current_app.config["RECEIVED_DIR"])
padata_filenames = _list_public_padata_filenames(padata_dir) if is_public_surface else [
padata_filenames = _list_result_padata_filenames(result, padata_dir) if is_public_surface else [
name for name in os.listdir(padata_dir) if name.endswith(".tgz")
]
detail_context = build_result_detail_context(
Expand Down Expand Up @@ -281,7 +286,7 @@ def show_result(filename):

def _build_public_reuse_manifest_for_route(result, filename):
padata_dir = current_app.config.get("RECEIVED_PADATA_DIR", current_app.config["RECEIVED_DIR"])
padata_filenames = _list_public_padata_filenames(padata_dir)
padata_filenames = _list_result_padata_filenames(result, padata_dir)
padata_urls = {
name: url_for("results.show_result", filename=name)
for name in padata_filenames
Expand All @@ -296,10 +301,52 @@ def _build_public_reuse_manifest_for_route(result, filename):
padata_url_by_filename=padata_urls,
)

def _list_public_padata_filenames(padata_dir):
return [
name
for name in os.listdir(padata_dir)
if name.endswith(".tgz")
and padata_matches_public_result(name, current_app.config["RECEIVED_DIR"])
]

def _list_result_padata_filenames(result, padata_dir):
result_uuid = _clean_result_value(result.get("_server_uuid"))
timestamp = _clean_result_value(result.get("_server_timestamp"))
if not result_uuid or not timestamp:
return []

filenames = []
seen = set()
for artifact_path in _iter_result_padata_artifact_paths(result):
artifact_slug = _padata_artifact_slug(artifact_path)
if not artifact_slug:
continue
filename = f"padata_{timestamp}_{result_uuid}_{artifact_slug}.tgz"
if filename in seen:
continue
seen.add(filename)
if os.path.isfile(os.path.join(padata_dir, filename)):
filenames.append(filename)
return filenames


def _iter_result_padata_artifact_paths(result):
breakdown = result.get("fom_breakdown")
if not isinstance(breakdown, dict):
return
for collection_name in ("sections", "overlaps"):
for item in breakdown.get(collection_name) or []:
if not isinstance(item, dict):
continue
for artifact in item.get("artifacts") or []:
if not isinstance(artifact, dict) or artifact.get("type") != "file_reference":
continue
path = _clean_result_value(artifact.get("path"))
if path:
yield path


def _padata_artifact_slug(artifact_path):
if not isinstance(artifact_path, str) or not artifact_path.startswith("results/"):
return ""
basename = os.path.basename(artifact_path)
if not PADATA_ARTIFACT_BASENAME_RE.fullmatch(basename):
return ""
return basename[:-7] if basename.endswith(".tar.gz") else basename[:-4]


def _clean_result_value(value):
return str(value or "").strip()
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ <h2 class="section-title">Evidence Snapshot</h2>
<span><strong>Evidence Snapshot:</strong> the roll-up and CSV export source for configured, executed, profiled, estimated, source, input, and build-cache evidence.</span>
<span><strong>Configured:</strong> yes = enabled and implemented; partial = enabled but script support incomplete; off = configured off; no = not listed.</span>
<span><strong>Result Quality:</strong> missing = no result; basic = core result only; ready = estimation bindings present; rich = source provenance and artifacts present.</span>
<span><strong>Input Status:</strong> None = no input_info; Declared = input_info only; Covered = input fixed by a recorded source commit; Verified = digest-backed input verification.</span>
<span><strong>Input Status:</strong> None = no input_info; Declared = input_info only; Covered = input fixed by source commit or self-contained runtime parameters; Verified = digest-backed input verification.</span>
<span><strong>Reuse Package:</strong> complete = public packet eligible with profile and estimate evidence; public packet eligible = source material is ready for a public Markdown reuse packet.</span>
<span><strong>Public Packet:</strong> current latest result status; Latest packet links to the newest eligible public reuse packet if available.</span>
<span><strong>Next Action:</strong> the first practical follow-up suggested by the current evidence state.</span>
Expand Down
2 changes: 1 addition & 1 deletion result_server/tests/test_portal_list_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ def test_usage_report_evidence_snapshot_consolidates_coverage_and_quality():
assert "Maturity Gaps" in html
assert "Input Status" in html
assert "None = no input_info" in html
assert "Covered = input fixed by a recorded source commit" in html
assert "Covered = input fixed by source commit or self-contained runtime parameters" in html
assert "no profile; no estimate; source incomplete; input not declared" in html


Expand Down
77 changes: 76 additions & 1 deletion result_server/tests/test_public_result_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,35 @@ def test_public_portal_detail_does_not_link_download_packets(tmp_path):
assert "reuse-manifest.json" not in text


def test_public_portal_detail_links_current_result_padata_without_archive_scan(tmp_path, monkeypatch):
app, received_dir = _build_public_app(tmp_path)
padata_dir = tmp_path / "padata"
padata_dir.mkdir()
app.config["RECEIVED_PADATA_DIR"] = str(padata_dir)
filename = "result_20260824_090000_11111111-2222-3333-4444-555555555555.json"
payload = _eligible_public_result_payload()
archive = "padata_20260824_090000_11111111-2222-3333-4444-555555555555_demo-profile.tgz"
_write_result(received_dir, filename, payload)
(padata_dir / archive).write_bytes(b"public profile archive placeholder")

original_listdir = os.listdir

def guarded_listdir(path):
if os.path.abspath(os.fspath(path)) == os.path.abspath(os.fspath(padata_dir)):
raise AssertionError("Result Detail should not scan every PA archive")
return original_listdir(path)

monkeypatch.setattr(os, "listdir", guarded_listdir)

with app.test_client() as client:
response = client.get(f"/results/detail/{filename}")

assert response.status_code == 200
text = response.get_data(as_text=True)
assert archive in text
assert f'href="/results/{archive}"' in text


def test_console_detail_links_download_packets(tmp_path):
app, received_dir = _build_console_app(tmp_path)
filename = "result_20260824_090000_11111111-2222-3333-4444-555555555555.json"
Expand All @@ -292,6 +321,8 @@ def test_console_detail_links_download_packets(tmp_path):
assert "Reuse Package" in text
assert "Public packet" in text
assert "Review public reuse packet" in text
assert "Profile evidence" in text
assert "recorded; 1 linked artifact" in text
assert "Download Evidence Packet" in text
assert "evidence-packet.md" in text
assert "Download Reuse Packet" in text
Expand All @@ -313,7 +344,7 @@ def test_public_portal_reuse_packet_routes_are_blocked_until_release_review(tmp_
assert manifest_response.status_code == 404


def test_console_reuse_packet_exports_only_public_projection(tmp_path):
def test_console_reuse_packet_exports_only_public_projection(tmp_path, monkeypatch):
app, received_dir = _build_console_app(tmp_path)
padata_dir = tmp_path / "padata"
padata_dir.mkdir()
Expand All @@ -324,6 +355,15 @@ def test_console_reuse_packet_exports_only_public_projection(tmp_path):
_write_result(received_dir, filename, payload)
(padata_dir / archive).write_bytes(b"public profile archive placeholder")

original_listdir = os.listdir

def guarded_listdir(path):
if os.path.abspath(os.fspath(path)) == os.path.abspath(os.fspath(padata_dir)):
raise AssertionError("Reuse Packet should not scan every PA archive")
return original_listdir(path)

monkeypatch.setattr(os, "listdir", guarded_listdir)

with app.test_client() as client:
response = client.get(f"/results/detail/{filename}/reuse-packet.md")

Expand Down Expand Up @@ -364,6 +404,7 @@ def test_console_reuse_manifest_exports_machine_readable_projection(tmp_path):
assert manifest["eligibility"]["status"] == "eligible"
assert manifest["result"]["experiment"] == "CASE1"
assert manifest["source"]["repository_url"] == "https://example.org/repo.git"
assert manifest["input"]["summary"] == "input_info declares input fixed by a public source commit."
assert manifest["input"]["items"][0]["public_url"] == "https://example.org/inputs.git"
assert manifest["build"]["cache_entry"]["digests"]["artifacts"] == "sha256:artifacts"
assert manifest["estimation"]["package_bindings"][0]["estimation_package"] == "demo-kernel-package"
Expand All @@ -372,6 +413,32 @@ def test_console_reuse_manifest_exports_machine_readable_projection(tmp_path):
assert "local-input-placeholder" not in json.dumps(manifest)


def test_console_reuse_packet_omits_placeholder_values(tmp_path):
app, received_dir = _build_console_app(tmp_path)
filename = "result_20260824_090000_11111111-2222-3333-4444-555555555555.json"
payload = _eligible_public_result_payload()
payload["FOM_version"] = "null"
payload["fom_breakdown"] = {"sections": [], "overlaps": []}
payload["build_cache"]["stored"] = True
_write_result(received_dir, filename, payload)

with app.test_client() as client:
packet_response = client.get(f"/results/detail/{filename}/reuse-packet.md")
manifest_response = client.get(f"/results/detail/{filename}/reuse-manifest.json")

assert packet_response.status_code == 200
packet_text = packet_response.get_data(as_text=True)
assert "FOM version" not in packet_text
assert "| Stored fresh entry | yes |" in packet_text
assert "| Stored fresh entry | True |" not in packet_text
assert "| Sections | 0 |" not in packet_text
assert "0/0 sections" not in packet_text

manifest = manifest_response.get_json()
assert "fom_version" not in manifest["result"]
assert manifest["estimation"] == {"status": "not recorded"}


def test_console_reuse_manifest_accepts_scoped_runtime_parameters(tmp_path):
app, received_dir = _build_console_app(tmp_path)
filename = "result_20260824_090000_11111111-2222-3333-4444-555555555555.json"
Expand Down Expand Up @@ -417,6 +484,11 @@ def test_console_reuse_manifest_accepts_scoped_runtime_parameters(tmp_path):
assert manifest_response.status_code == 200
manifest = manifest_response.get_json()
assert manifest["eligibility"]["status"] == "eligible"
assert manifest["input"]["summary"] == "input_info declares self-contained runtime parameters."
assert (
"Use the recorded source commit and runtime parameters as the starting point for reuse."
in manifest["reuse"]["notes"]
)
assert manifest["input"]["items"] == [
{
"dataset_id": "qws-case1-parameters",
Expand All @@ -435,6 +507,9 @@ def test_console_reuse_manifest_accepts_scoped_runtime_parameters(tmp_path):

packet_text = packet_response.get_data(as_text=True)
assert packet_response.status_code == 200
assert "input_info declares self-contained runtime parameters." in packet_text
assert "source commit and runtime parameters" in packet_text
assert "source and input commits" not in packet_text
assert "dataset_id: qws-case1-parameters" in packet_text
assert "dataset_id: qws-case0-parameters" not in packet_text

Expand Down
Loading
Loading