market-research-reports: fix ledger validator crash on publication_date=not-stated

The sentinel "not-stated" is exactly 10 characters, so it satisfied the
len(publication) == 10 ISO-date guard and reached
date.fromisoformat("not-stated"), raising an uncaught ValueError instead of
the documented warning. SKILL.md instructs recording "not-stated" when the
publication date is unavailable, so this crashed on valid ledgers.

Check the sentinel before the retrieval/publication comparison, and add
regression tests for both the not-stated warning and the still-enforced
retrieval-precedes-publication error.

Fixes #219
This commit is contained in:
Timothy Kassis
2026-07-31 10:57:18 -07:00
parent 390c8b8b49
commit 95d3adda6d
3 changed files with 27 additions and 6 deletions

View File

@@ -4,7 +4,7 @@ description: Build evidence-traceable market research reports and assumption-dri
license: MIT
compatibility: Python 3.11+ standard library for optional offline CLIs. The optional LaTeX template uses XeLaTeX or LuaLaTeX. Online research requires user-approved network access and source-specific terms; bundled scripts make no network, LLM, or image calls.
metadata:
version: "1.1"
version: "1.2"
skill-author: "K-Dense Inc."
---

View File

@@ -177,14 +177,14 @@ def validate_records(records: list[dict[str, Any]]) -> dict[str, Any]:
retrieval = parse_iso_date(
record["retrieval_date"], f"{context}.retrieval_date"
)
if len(publication) == 10 and date.fromisoformat(retrieval) < date.fromisoformat(
publication
):
if publication == "not-stated":
warnings.append(f"{source_id}: publication date is not stated")
elif len(publication) == 10 and date.fromisoformat(
retrieval
) < date.fromisoformat(publication):
raise ValidationError(
f"{context}.retrieval_date precedes publication_date"
)
if publication == "not-stated":
warnings.append(f"{source_id}: publication date is not stated")
require_text(record["geography"], f"{context}.geography")
currency = parse_currency(

View File

@@ -59,6 +59,27 @@ class EvidenceLedgerTests(unittest.TestCase):
self.assertFalse(report["valid"])
self.assertTrue(any("duplicate" in error for error in report["errors"]))
def test_not_stated_publication_date_warns_without_crashing(self) -> None:
records = _load_records(ASSETS / "source_ledger_template.csv")
records[0]["publication_date"] = "not-stated"
report = validate_records(records)
self.assertTrue(report["valid"], report["errors"])
self.assertTrue(
any("publication date is not stated" in warning
for warning in report["warnings"])
)
def test_retrieval_before_publication_fails(self) -> None:
records = _load_records(ASSETS / "source_ledger_template.csv")
records[0]["publication_date"] = "2026-07-30"
records[0]["retrieval_date"] = "2026-07-01"
report = validate_records(records)
self.assertFalse(report["valid"])
self.assertTrue(
any("retrieval_date precedes publication_date" in error
for error in report["errors"])
)
class MarketSizingTests(unittest.TestCase):
def test_synthetic_sizing_reconciles_and_returns_scenarios(self) -> None: