fix(report): make density facts readable and printable
Independent Staging Quality Gate / validate (push) Failing after 11m4s
Independent Staging Quality Gate / publish (push) Skipped

Unify reader cleanup rules, lock writer table guards, and register the exact fictional timestamp collision. Preserve existing ordinary-report safety contracts and source-data gaps.

Validation: report Node 165/165, final safety 29/29, Python 101/101, Chrome 28/28; both PDFs retain all 130 rows. Full Node 3704 tests with the same 91 baseline failures. Privacy test: 62 passed, 1 failed due to 17 protected-file READ_ERRORs; not a green gate. Build, DB, manual checklist and controlled-login gaps remain documented. User explicitly authorized staging push with these gaps disclosed.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
jesse-ux
2026-09-23 15:26:25 +08:00
co-authored by Claude Code
parent 0d37bec15a
commit a12f2c0d26
27 changed files with 1220 additions and 210 deletions
@@ -0,0 +1,52 @@
"""Shared vocabulary regressions; no generated engine facts in these unit inputs."""
from pathlib import Path
import pytest
from scripts.reader_appendix_language import clean_reader_appendix_markdown
from scripts import skill_release_package
ROOT = Path(__file__).resolve().parents[1]
RULE_PATH = "scripts/reader_appendix_language.rules.json"
@pytest.mark.parametrize("source,expected", [
("PL9 第 42 页", "外部参照资料"),
("PL9第42页", "外部参照资料"),
("PL9.pdf 第 42 页", "外部参照资料"),
("PL9.pdf第42页后文", "外部参照资料后文"),
("参见PL9第43–44页中的字段", "参见外部参照资料中的字段"),
("PL9 第 40 / 48 页", "外部参照资料"),
("PL9 pages 99-100", "外部参照资料"),
])
def test_chinese_page_boundary(source, expected):
assert clean_reader_appendix_markdown(source) == expected
@pytest.mark.parametrize("edition", ["basic_git", "premium_cloud_drive"])
def test_shared_rules_are_included_by_skill_package_selection(monkeypatch, edition):
# Simulate the tracked file inventory without mutating this worktree's index.
# Exercise the real release selector: scripts assets must not become .py-only.
inventory = ["scripts/reader_appendix_language.py", RULE_PATH]
# Release manifest references are relative to the repository, not the caller.
monkeypatch.chdir(ROOT)
monkeypatch.setattr(skill_release_package, "_git_files", lambda: inventory)
selected = skill_release_package._edition_files(edition)
assert all(path in selected for path in inventory)
assert (ROOT / RULE_PATH).is_file()
@pytest.mark.parametrize("dockerfile", ["railway-api.Dockerfile", "railway-web.Dockerfile"])
def test_shared_rules_live_inside_existing_image_copy_boundary(dockerfile):
source = (ROOT / "deploy" / dockerfile).read_text(encoding="utf-8")
assert any(line.startswith("COPY scripts ") for line in source.splitlines())
def test_crlf_chart_fence_is_byte_preserved():
fence = ' ```jyotish-chart\r\n{"title":"PL9第42页 parameter_sensitive","id":"D1"}\r\n ```\r\n'
source = "PL9第42页\r\n" + fence + "| parameter_sensitive |\r\n"
assert clean_reader_appendix_markdown(source).encode("utf-8") == (
"外部参照资料\r\n" + fence + "| 参数敏感 |\r\n"
).encode("utf-8")
+74 -1
View File
@@ -192,12 +192,49 @@ def _collision_spans(path: str, source: str, rules: tuple[Rule, ...]) -> list[tu
return []
service_path = "tests/test_rectification_v5_services.py"
replay_path = "references/oracle/pyjhora_multi_case_panchanga_gulika_replay_2026_07_23.json"
if path not in {service_path, replay_path}:
report_path = "frontend/tests/fixtures/report-density-fictional-reader.json"
if path not in {service_path, replay_path, report_path}:
return []
try:
tree = ast.parse(source)
except SyntaxError:
return []
if path == report_path:
# BUG-1010: engine timestamp from fictional input, independently replayed
# during acceptance (TASK-report-density-fix-20260923, P1-B; BUG-1008).
# Pin provenance, JSON node, source line and complete computed row; allow
# only the colliding timestamp span, not the large markdown string.
try:
data = json.loads(source)
if data["fixtureProvenance"] != {
"fictional": True,
"generator": "cmd_full_reading -> build_professional_report_reference_packet",
"input": {
"year": 2000, "month": 1, "day": 1, "hour": 12,
"minute": 0, "second": 0, "lat": 0.0, "lon": 0.0,
"tz": 0, "ayanamsa": "lahiri", "node_mode": "mean",
"house_system": "whole_sign", "today": "2026-09-22",
"target_year": 2026,
},
} or data["fixtureProvenance"]["fictional"] is not True:
return []
nodes = [v for k, v in zip(tree.body[0].value.keys, tree.body[0].value.values)
if isinstance(k, ast.Constant) and k.value == "markdown"]
if len(nodes) != 1 or not isinstance(nodes[0], ast.Constant) or nodes[0].lineno != 22:
return []
row = (f"| 5 | 4 | 5 | 2028-01-24 {marker}:39 (unresolved_external_tuple_boundary) "
"| 0.019276268255984996 | pyjhora_behavior_only / not_multiengine_parity |")
if data["markdown"].splitlines().count(row) != 1:
return []
start, end = _node_span(source, nodes[0])
literal = source[start:end]
encoded_row = r"\n" + json.dumps(row, ensure_ascii=False)[1:-1] + r"\n"
if literal.count(encoded_row) != 1:
return []
offset = start + literal.index(encoded_row) + encoded_row.index(marker)
return [(offset, offset + len(marker))]
except (ValueError, KeyError, IndexError, AttributeError, TypeError):
return []
if path == service_path:
name = "test_hour_window_keeps_all_seventeen_signature_clusters_including_late_tail"
functions = [n for n in ast.walk(tree) if isinstance(n, ast.FunctionDef) and n.name == name]
@@ -559,6 +596,42 @@ def test_reviewed_numerical_collisions_are_exact_nodes_only(path: str, count: in
assert len(scan_text(path, source.replace(marker + ":18", marker + ":19"), rules)[0]) == count
def test_report_fixture_collision_is_one_reviewed_timestamp_only() -> None:
__tracebackhide__ = True
path = "frontend/tests/fixtures/report-density-fictional-reader.json"
rules = build_rules((ROOT / GOLDEN_PATH).read_text(encoding="utf8"))
source = (ROOT / path).read_text(encoding="utf8")
marker = next(r.value for r in rules if r.code == "R003")
findings, permitted = scan_text(path, source, rules)
assert len(findings) == 0 and permitted == 1
for dirty_path, dirty in [
("new/" + path, source),
(path, "\n" + source),
(path, source.replace('"fictional": true', '"fictional": false', 1)),
(path, source.replace('"year": 2000', '"year": 2001', 1)),
(path, source.replace('"generator": "cmd_full_reading', '"generator": "unreviewed', 1)),
(path, source.replace('"markdown":', '"other":', 1)),
(path, source.replace(marker + ":39", marker + ":40", 1)),
(path, source.replace("| 5 | 4 | 5 | 2028-01-24", "| 6 | 4 | 5 | 2028-01-24", 1)),
]:
findings, permitted = scan_text(dirty_path, dirty, rules)
assert len(findings) == 1 and permitted == 0
# Extra markers in the same markdown node or another field remain findings.
for dirty in [
source.replace('"markdown": "', '"markdown": "' + marker + r"\n", 1),
source.replace('"markdown":', f'"extra": {json.dumps(marker)}, "markdown":', 1),
]:
findings, permitted = scan_text(path, dirty, rules)
assert len(findings) == 1 and permitted == 1
row = next(line for line in json.loads(source)["markdown"].splitlines() if marker in line)
encoded_row = json.dumps(row, ensure_ascii=False)[1:-1]
dirty = source.replace(encoded_row, encoded_row + r"\n" + encoded_row, 1)
findings, permitted = scan_text(path, dirty, rules)
assert len(findings) == 2 and permitted == 0
findings, permitted = scan_text(path, source, rules + (Rule("LOCAL_001", marker),))
assert [finding.rule for finding in findings] == ["LOCAL_001"] and permitted == 1
def test_local_rule_is_not_exempted_by_golden_declaration() -> None:
source = 'FORBIDDEN_PRIVACY_MARKERS = ("synthetic",)'
rules = build_rules(source, "synthetic")
+33
View File
@@ -87,3 +87,36 @@ def test_optional_table_validator_fails_closed_on_bad_shape():
errors.clear()
validate_fact_tables([], lambda *error: errors.append(error))
assert not errors
def test_fact_subtable_contract_uses_golden_periods_and_keeps_legacy_snapshots():
import jsonschema
packet = json.loads((ROOT / "frontend/tests/fixtures/report-density-fictional-engine.json").read_text(encoding="utf8"))
source = "worksheets.timing_and_predictive_systems.dasha"
timeline = packet["worksheets"]["timing_and_predictive_systems"]["dasha"]["timeline"]
rows = [{"sourcePath": f"{source}.timeline[{index}]", "cells": [period["lord_cn"], period["start"], period["end"], f'{period["full_years"]:.2f}', "是" if period["is_current"] else "否"]} for index, period in enumerate(timeline)]
table = {"id": "vimshottari", "title": "Vimshottari 主运", "claimStatus": "parameter_sensitive", "sourcePath": source, "note": "原始计算供核对。", "columns": ["主运", "起", "止", "年数", "当前"], "rows": rows}
current_index, current = next((index, period) for index, period in enumerate(timeline) if period["is_current"])
child_source = f"{source}.timeline[{current_index}]"
child = {"id": "antardasha", "title": "当前主运下分运", "sourcePath": child_source, "note": "原始计算供核对。", "columns": ["分运", "起", "止", "当前"], "rows": [{"sourcePath": f"{child_source}.antardasha_timeline[{index}]", "cells": [period["lord_cn"], period["start"], period["end"], "是" if period["is_current"] else "否"]} for index, period in enumerate(current["antardasha_timeline"])]}
schema = json.loads((ROOT / "contracts/personal-report/report-document.v2.schema.json").read_text(encoding="utf8"))
contract = {"$ref": "#/definitions/factTable", "definitions": schema["definitions"]}
for candidate in [table, {**table, "subtables": [child]}]:
errors = []
validate_fact_tables([candidate], lambda *error: errors.append(error))
assert not errors
jsonschema.validate(candidate, contract)
for mutation in ("row_width", "origin", "duplicate", "unknown_key"):
invalid = copy.deepcopy({**table, "subtables": [child]})
if mutation == "row_width":
invalid["subtables"][0]["rows"][0]["cells"].pop()
elif mutation == "origin":
invalid["subtables"][0]["sourcePath"] = "worksheets.other"
elif mutation == "duplicate":
invalid["subtables"].append(copy.deepcopy(child))
else:
invalid["subtables"][0]["raw"] = True
errors = []
validate_fact_tables([invalid], lambda *error: errors.append(error))
assert errors, mutation