"""Regression coverage for extensible, still-grounded model generation.""" from __future__ import annotations import pytest from app.intelligence.contracts import ( IntelligenceContractError, IntelligenceOutput, validate_intelligence_output, ) from app.intelligence.generation import GenerationPolicy, policy_for, register_generation_policy from app.intelligence.settings import ( DEFAULT_CLOUD_CACHE_DAYS, DEFAULT_CLOUD_COOLDOWN_MINUTES, SETTING_CLOUD_CACHE_DAYS, SETTING_CLOUD_COOLDOWN_MINUTES, ) def _valid_payload() -> dict[str, object]: return { "summary_zh": "共 2 项。", "summary_en": "2 items in total.", "summary_fact_refs": ["/facts/total"], "conclusions": [], "risks": [], "opportunities": [], "forecasts": [], "recommendations": [], "data_gaps": [], } def test_existing_subject_policies_keep_their_production_windows(): cloud = policy_for("cloud_scope") assert (cloud.default_cache_days, cloud.default_cooldown_minutes) == ( DEFAULT_CLOUD_CACHE_DAYS, DEFAULT_CLOUD_COOLDOWN_MINUTES, ) assert cloud.cache_days_setting == SETTING_CLOUD_CACHE_DAYS assert cloud.cooldown_setting == SETTING_CLOUD_COOLDOWN_MINUTES assert cloud.system_prompt is not None assert "Do not write any numeral" in cloud.system_prompt for subject in ("platform", "domain", "unknown_subject"): policy = policy_for(subject) assert (policy.default_cache_days, policy.default_cooldown_minutes) == (1, 1) assert policy.cache_days_setting is None assert policy.cooldown_setting is None def test_subject_registration_is_explicit_and_reversible(): custom = GenerationPolicy(default_cache_days=3, default_cooldown_minutes=5) register_generation_policy("test_subject", custom) try: assert policy_for("test_subject") is custom finally: from app.intelligence.generation import _POLICIES _POLICIES.pop("test_subject", None) assert policy_for("test_subject").default_cache_days == 1 def test_generation_policy_refuses_an_unprotected_output_contract(): with pytest.raises(ValueError, match="must inherit"): register_generation_policy( "unsafe_subject", GenerationPolicy(output_model=object), # type: ignore[arg-type] ) @pytest.mark.parametrize( ("subject_type", "policy"), [ (" ", GenerationPolicy()), ("invalid_cache", GenerationPolicy(default_cache_days=0)), ("invalid_cooldown", GenerationPolicy(default_cooldown_minutes=1441)), ], ) def test_generation_policy_refuses_invalid_registration(subject_type, policy): with pytest.raises(ValueError): register_generation_policy(subject_type, policy) class NarrowOutput(IntelligenceOutput): """A subject can narrow its model contract without bypassing the guards.""" def test_custom_contract_retains_grounding_and_privacy_guards(): facts = {"facts": {"total": 2}} output = validate_intelligence_output( _valid_payload(), facts=facts, allowed_evidence_refs=set(), confidence_score=90, output_model=NarrowOutput, ) assert isinstance(output, NarrowOutput) invalid_number = _valid_payload() invalid_number["summary_zh"] = "共 99 项。" invalid_number["summary_en"] = "99 items in total." with pytest.raises(IntelligenceContractError): validate_intelligence_output( invalid_number, facts=facts, allowed_evidence_refs=set(), confidence_score=90, output_model=NarrowOutput, ) invalid_ref = _valid_payload() invalid_ref["summary_zh"] = "srv_99" invalid_ref["summary_en"] = "srv_99" with pytest.raises(IntelligenceContractError): validate_intelligence_output( invalid_ref, facts=facts, allowed_evidence_refs={"srv_01"}, confidence_score=90, output_model=NarrowOutput, ) with pytest.raises(IntelligenceContractError, match="data gap"): validate_intelligence_output( _valid_payload(), facts=facts, allowed_evidence_refs=set(), confidence_score=40, output_model=NarrowOutput, ) # ── naming your own reporting period is not an invented number ──────── def _payload(zh: str, en: str, refs: list[str]) -> dict: return { "summary_zh": zh, "summary_en": en, "summary_fact_refs": refs, "conclusions": [], "risks": [], "opportunities": [], "forecasts": [], "recommendations": [], "data_gaps": [], } _PERIOD_FACTS = {"facts": { "period_start": "2026-07-01", "period_end": "2026-07-31", "controls_total": 11, "controls_passing": 9, }} def test_a_summary_may_name_the_month_it_covers(): """Every AI subject in the platform was failing on this. The grounding check collected every number in the narrative and refused any the model had not cited — so "In July 2026, 11 controls, 9 passing" was rejected over the tokens 2026 and 7, which are the period the model was HANDED rather than a claim it made. Nothing had ever reached ``ready`` in production as a result: naming your own reporting period is the most natural sentence a summary can open with. """ validate_intelligence_output( _payload( "2026 年 7 月共 11 项控制项,9 项通过。", "In July 2026, 11 controls, 9 passing.", ["/facts/controls_total", "/facts/controls_passing"], ), facts=_PERIOD_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) def test_an_invented_magnitude_is_still_refused(): """The load-bearing half. Allowing period digits must not become 'any number goes' — that would make the guard decorative.""" with pytest.raises(IntelligenceContractError, match="uncited numbers"): validate_intelligence_output( _payload( "2026 年 7 月共 47 项控制项。", "In July 2026, 47 controls.", ["/facts/controls_total"], ), facts=_PERIOD_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) def test_only_date_shaped_values_contribute_their_digits(): """A plain string that merely contains digits is not a date, so its numbers stay uncited — otherwise any free-text fact would smuggle magnitudes into the allowed set.""" facts = {"facts": {"note": "ticket 4711 was closed", "controls_total": 11}} with pytest.raises(IntelligenceContractError, match="uncited numbers"): validate_intelligence_output( _payload("共 4711 项。", "4711 items.", ["/facts/controls_total"]), facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) def test_the_posture_subject_forbids_computing_numbers(): """Bounded instruction instead of guessing the model's phrasing. The grounding check is a literal token comparison with no arithmetic, so a model handed a ratio and writing the obvious percentage is refused for a number it derived correctly. Three rounds of publishing another pre-computed form each bought one deploy before the model found a fourth phrasing. Telling it to copy rather than compute is finite; enumerating phrasings is not. """ policy = policy_for("compliance_posture") assert policy.system_prompt, "posture must not fall back to the base prompt" lowered = policy.system_prompt.lower() assert "never compute" in lowered assert "ratio into a percentage" in lowered # Still inherits the shared grounding rules rather than replacing them. assert "only source of truth" in lowered def test_subject_prompts_keep_the_shared_guard_rules(): """A subject prompt extends the base prompt; it must not drop the anonymity and citation rules that make narration permissible. ``platform`` used to be asserted as "still the module default". It now carries its own prompt — it was the only subject never told to stop computing figures, and the only subject that never published — so the check is what it always meant: whatever a subject adds, the shared rules survive underneath. """ for subject in ("platform", "compliance_posture", "cloud_scope"): prompt = policy_for(subject).system_prompt assert prompt, f"{subject} must not fall back to the base prompt" for rule in ("cite scalar facts", "never invent an object", "data_gaps"): assert rule in prompt, f"{subject} prompt dropped: {rule}" def test_a_figure_present_in_the_facts_is_accepted_whichever_ref_is_cited(): """The invariant is 'the number came from Helix', not 'the model picked the tidiest pointer'. Four production deploys showed a model writing a CORRECT figure while citing a neighbouring pointer, and the whole narrative being refused for it — which is why not one analysis across four subjects had ever reached ``ready``. """ facts = {"facts": { "control_pass_percent": 45.45, "controls_total": 11, "period_start": "2026-07-01", }} validate_intelligence_output( _payload("通过率 45.45%。", "Pass rate 45.45%.", ["/facts/controls_total"]), # deliberately the "wrong" ref facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) def test_a_number_nowhere_in_the_facts_is_still_refused(): """The load-bearing half — widening must not mean 'anything goes'.""" facts = {"facts": {"control_pass_percent": 45.45, "controls_total": 11}} with pytest.raises( IntelligenceContractError, match="uncited numbers", ): validate_intelligence_output( _payload("通过率 99.9%。", "Pass rate 99.9%.", ["/facts/control_pass_percent"]), facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) def test_a_citation_pointing_nowhere_is_still_a_breach(): """Widening the NUMBER check must not stop validating the refs.""" facts = {"facts": {"controls_total": 11}} with pytest.raises(IntelligenceContractError, match="Unknown fact reference"): validate_intelligence_output( _payload("共 11 项。", "11 items.", ["/facts/does_not_exist"]), facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) # The fact package production actually froze for 2026-07, read back out of # ``intelligence_snapshots``. Tests about what the guard admits are worth # nothing against invented facts. _PROD_JULY_FACTS = {"facts": { "period_start": "2026-07-01", "period_end": "2026-07-31", "controls_total": 11, "controls_passing": 5, "controls_failing": 4, "controls_not_evaluated": 0, "controls_status_not_configured": 2, "control_pass_percent": 45.45, "control_fail_percent": 36.36, "control_pass_ratio": 0.4545, "overall_score": 45, "confidence_score": 90, "evidence_queries_precompiled": 9, "open_drift_findings": 0, "findings_awaiting_decision": 1045, "grade": "D", }} @pytest.mark.parametrize( ("figure", "sentence_zh", "sentence_en"), [ # 100 - 36.36. Refused in production at 12:28 on 2026-08-17. ("63.64", "11 项控制项中 4 项未通过,63.64% 未失败。", "Of 11 controls 4 failed, so 63.64% did not."), # 100 - 45.45. Refused at 11:33. ("54.55", "通过率 45.45%,即 54.55% 尚未通过。", "A 45.45% pass rate leaves 54.55% not passing."), # 11 - 5. Refused at 11:33 alongside 54.55. ("6", "11 项中 5 项通过,其余 6 项未通过。", "5 of 11 passed; the remaining 6 did not."), ], ) def test_arithmetic_on_the_facts_is_grounded(figure, sentence_zh, sentence_en): """The exact figures production refused, with the exact facts it had. Each is a complement or a difference of Helix's own numbers — the arithmetic any sentence describing a ratio performs. Refusing these is why ``intelligence_analyses`` never once reached ``ready``. """ validate_intelligence_output( _payload(sentence_zh, sentence_en, ["/facts/controls_total", "/facts/controls_failing"]), facts=_PROD_JULY_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) assert figure in sentence_en def test_a_remainder_is_grounded(): """Verifies the difference rule specifically. ``6`` and ``9.09`` from the production failures turn out to be reachable as rounded ratios too, so neither of them actually exercises this rule — removing it left those cases green. ``1041`` is ``1045 - 4``, and a probe over the July package confirmed nothing else derives it, so this is the case that holds the rule up. """ validate_intelligence_output( _payload( "1045 项待决策,其中 4 项与未通过控制项相关,其余 1041 项无关。", "1045 await decision; 4 relate to failing controls, 1041 do not.", ["/facts/findings_awaiting_decision", "/facts/controls_failing"], ), facts=_PROD_JULY_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) def test_rounding_a_published_figure_is_grounded(): """Verifies the rounding rule, on a package that can isolate it. Found while checking whether each rule earned its place: a narrator abbreviating one of Helix's own numbers was still being refused, which is the same class of failure as the complement and the remainder. The July package cannot hold this rule up on its own — ``45.5`` also falls out of the percentage rule there, since ``5 / 11`` is ``45.4545``. So this uses a single-fact package where rounding is the only route: no pair exists to divide or subtract, and the complement of ``72.31`` is ``27.69``. """ facts = {"facts": {"weighted_score": 72.31}} validate_intelligence_output( _payload("加权得分约 72.3。", "A weighted score of about 72.3.", ["/facts/weighted_score"]), facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) def test_a_share_over_another_denominator_is_grounded(): """Verifies the percentage rule. Helix publishes the pass share over ALL controls (45.45%). A narrative may legitimately reckon it over the 9 that were actually evaluated — 55.56% — and which denominator is the right caliber is a judgement the summary is allowed to make. No other rule derives this figure. """ validate_intelligence_output( _payload("9 项已评估中 5 项通过,占 55.56%。", "5 of the 9 evaluated passed, or 55.56%.", ["/facts/controls_passing", "/facts/evidence_queries_precompiled"]), facts=_PROD_JULY_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) def test_a_bare_proportion_of_two_counts_is_not_grounded(): """Proportions were deliberately left out: ``11 / 2 = 5.5`` was the only thing justifying them, and the remainder rule derives that ``6`` honestly as ``11 - 5``. Prose writes percentages, not ``0.45``.""" with pytest.raises(IntelligenceContractError, match="uncited numbers"): validate_intelligence_output( _payload("比值为 0.36。", "A ratio of 0.36.", ["/facts/controls_failing", "/facts/controls_total"]), facts=_PROD_JULY_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) def test_adding_two_unrelated_counts_is_not_grounded(): """Sums were deliberately left out. ``1045 + 5`` is not a sentence any summary writes, and admitting it widened the allowed set by 116 values for no production reason.""" with pytest.raises(IntelligenceContractError, match="uncited numbers"): validate_intelligence_output( _payload("合计 1050 项。", "1050 in total.", ["/facts/findings_awaiting_decision"]), facts=_PROD_JULY_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) def test_a_magnitude_with_no_basis_in_the_facts_is_still_refused(): """The load-bearing half: knowing the arithmetic must not become 'any number goes'. 4200000 is no ratio, sum, difference or complement of anything in the July package.""" with pytest.raises(IntelligenceContractError, match="uncited numbers"): validate_intelligence_output( _payload("风险敞口 4200000 元。", "Exposure of 4200000.", ["/facts/controls_total"]), facts=_PROD_JULY_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) def test_a_plausible_but_ungrounded_count_is_still_refused(): """A fabrication does not have to be absurd to be a fabrication. 312 orphaned accounts is the shape of a real finding, and nothing in the package derives it.""" with pytest.raises(IntelligenceContractError, match="uncited numbers"): validate_intelligence_output( _payload("发现 312 个孤儿账号。", "Found 312 orphaned accounts.", ["/facts/controls_total"]), facts=_PROD_JULY_FACTS, allowed_evidence_refs=set(), confidence_score=90, ) def test_derivation_is_skipped_rather_than_stalling_on_a_huge_package(): """The pairwise pass is O(n^2). A package past the cap must fall back to the CHEAP rules instead of spending minutes — and must still admit a figure that IS a plain fact. Updated 2026-09-01. This asserted ``_derived_number_tokens(...) == set()``, which is stronger than the anti-stall property it exists for, and that extra strength was a real production defect: rules 1 and 2 (rounding a published figure, the complement of a share) are O(n) and were being skipped with the quadratic ones. The cross-domain brief's package holds 161 distinct numeric facts, over the cap, so it could not write ``72`` for the published ``72.14`` — three of six live runs died on exactly that. What must stay skipped is the PAIRWISE family, and that is now what this asserts. """ from decimal import Decimal from app.intelligence.contracts import ( _MAX_PAIRWISE_FACTS, _derived_number_tokens, _grounded_number_tokens, ) oversized = {Decimal(i) for i in range(_MAX_PAIRWISE_FACTS + 40)} derived = _derived_number_tokens(oversized) # Cheap rules still run: the complement of the published 40 is 60. assert Decimal(60) in derived # Quadratic rules do not: 7 * 100 / 40 = 17.5 is a rule-4 share of two # published facts, and nothing else in this base produces it. assert Decimal("17.5") not in derived # And the fallback stays bounded — not the 51,862-value set the pairwise # pass derives from a package this size. assert len(derived) < len(oversized) * 4 wide = {"facts": {f"n_{i}": i for i in range(_MAX_PAIRWISE_FACTS + 40)}} grounded = _grounded_number_tokens(wide) assert Decimal(7) in grounded def test_assigning_an_owner_is_an_allowed_action_and_is_gated(): """Production refused a whole daily brief over this one word. The narrator wanted to recommend assigning an owner — a first-class Helix flow (auto-Owner backfill, cloud-scope Owner, server owner) — and the action vocabulary did not carry it, so the entire narrative was thrown away for a legitimate recommendation. Widening a vocabulary that gates writes is only safe if the gate comes with it: handing a resource a new owner moves accountability, the same kind of change as ``transfer``, so it must require approval. """ from app.intelligence.recommendations import build_recommendation_handoff payload = _payload("共 11 项。", "11 items.", ["/facts/controls_total"]) payload["recommendations"] = [{ "title_zh": "为无主资源指定 Owner", "title_en": "Assign an owner", "detail_zh": "11 项中有资源无 Owner。", "detail_en": "Of 11, some lack an owner.", "fact_refs": ["/facts/controls_total"], "evidence_refs": [], "confidence": "medium", "priority": "p1", "action_kind": "assign", }] output = validate_intelligence_output( payload, facts={"facts": {"controls_total": 11}}, allowed_evidence_refs=set(), confidence_score=90, ) assert output.recommendations[0].action_kind == "assign" handoff = build_recommendation_handoff( action_kind="assign", fact_refs=["/facts/controls_total"], ) assert handoff["requires_approval"] is True, ( "assign moves accountability and must not slip past the approval gate" ) assert "approval_boundary" in handoff["handling_steps"] def test_a_summary_may_cite_every_fact_it_was_given(): """A citation cap below the fact package forbids citing what you were handed. The cross-domain brief publishes 8 aggregate facts plus 8 dimensions — about 24 citable scalars — and production refused it for listing 22 against a cap of 20. The cap must clear the largest real package. """ facts = {"facts": {f"dimension_{i}": i for i in range(24)}} payload = _payload( "共 24 个维度。", "24 dimensions in total.", [f"/facts/dimension_{i}" for i in range(24)], ) output = validate_intelligence_output( payload, facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) assert len(output.summary_fact_refs) == 24 def test_the_citation_cap_still_exists(): """Raising the cap must not mean removing it — an unbounded citation list is an unbounded output.""" facts = {"facts": {f"dimension_{i}": i for i in range(60)}} payload = _payload( "共 1 项。", "1 item.", [f"/facts/dimension_{i}" for i in range(60)], ) with pytest.raises(IntelligenceContractError, match="at most 40"): validate_intelligence_output( payload, facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) # ── the model is handed one flat level of citable scalars ────────────── def test_a_nested_fact_package_is_flattened_for_citation(): """The exact production failure, reproduced and fixed. The cloud subscription package nests 7 groups and 12 lists, and the model cited ``/facts/costs/data_quality/sources/2/available_count`` — concatenating two paths, because ``data_quality`` is a TOP-LEVEL group and not under ``costs``. The whole narrative was refused for it. A flat level cannot be mis-navigated: there is nothing to navigate. """ from app.intelligence.generation import _flatten_for_citation nested = { "costs": {"top_resources": [{"amount": 5}, {"amount": 3}]}, "data_quality": {"sources": [ {"available_count": 1}, {"available_count": 2}, {"available_count": 3}, {"available_count": 4}, ]}, } flat = _flatten_for_citation(nested) assert flat["data_quality.sources.2.available_count"] == 3 assert all( not isinstance(value, (dict, list)) for value in flat.values() ), "every citable value must be a scalar" def test_flattening_loses_no_value_and_publishes_list_lengths(): """Flat must not mean lossy: every leaf survives, and each list also publishes the count, which is usually the fact a narrative wants.""" from app.intelligence.generation import _flatten_for_citation nested = {"access": {"expiring_refs": ["a_01", "a_02"]}, "sync": {"lag_days": 4}} flat = _flatten_for_citation(nested) assert flat["access.expiring_refs.count"] == 2 assert flat["access.expiring_refs.0"] == "a_01" assert flat["access.expiring_refs.1"] == "a_02" assert flat["sync.lag_days"] == 4 def test_an_already_flat_package_keeps_its_pointers_unchanged(): """Regression guard for the one analysis that WORKS in production. These are the facts the compliance posture summary actually froze for 2026-07, read out of ``intelligence_snapshots``. It succeeded citing ``/facts/overall_score`` and friends, so flattening must leave every one of those pointers exactly where it was. """ from app.intelligence.generation import _flatten_for_citation flat = _flatten_for_citation(_PROD_JULY_FACTS["facts"]) assert flat == _PROD_JULY_FACTS["facts"], ( "an already-flat package must be untouched, or the working " "production summary breaks" ) def test_a_dotted_source_key_fails_loudly_instead_of_merging_facts(): """Two different facts must never share one citable key: the model would quote a number filed under someone else's name.""" from app.intelligence.generation import _flatten_for_citation with pytest.raises(ValueError, match="collision"): _flatten_for_citation({"a": {"b": 1}, "a.b": 2}) def test_a_flat_key_spelled_without_the_pointer_prefix_still_resolves(): """Production, third iteration on this one subject. Flattening removed the mis-navigation failure and revealed the next one: the model wrote ``costs.current_month_business_cost`` — the flat key with no ``/facts/`` prefix — because after flattening the keys look like complete paths. A whole narrative was discarded over a missing slash. Grounding is unchanged: the fact must still exist under exactly that name. Only the spelling is tolerated. """ facts = {"facts": {"costs.current_month_business_cost": 1200}} validate_intelligence_output( _payload("本月成本 1200。", "Current-month cost is 1200.", ["costs.current_month_business_cost"]), facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) def test_a_bare_name_that_is_not_a_fact_is_still_a_breach(): """Tolerating a spelling must not tolerate an invented address. The message is now the single "Unknown fact reference" for every spelling: once resolution judges the address rather than the path, "you wrote it the wrong way" and "there is no such fact" stopped being different diagnoses — the only question left is whether the payload publishes that name. """ facts = {"facts": {"costs.current_month_business_cost": 1200}} with pytest.raises(IntelligenceContractError, match="Unknown fact reference"): validate_intelligence_output( _payload("本月成本 1200。", "Current-month cost is 1200.", ["costs.nonexistent_key"]), facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) def test_a_bare_name_pointing_at_a_nested_member_is_still_a_breach(): """A citation must name a scalar however it is spelled. Enforced by the single scalar check in ``_validate_text_numbers``, not by the resolver: a duplicate type check inside the resolver was written first, then removed once a mutation showed it could never be the guard that fired. """ facts = {"facts": {"group": {"inner": 1}}, "dimensions": [{"score": 5}]} with pytest.raises(IntelligenceContractError): validate_intelligence_output( _payload("共 1 项。", "1 item.", ["dimensions"]), facts=facts, allowed_evidence_refs=set(), confidence_score=90, ) def test_low_confidence_facts_clamp_a_high_claim_instead_of_discarding_it(): """Production, after the reference problems were fixed. The cloud subscription narrative was then refused for claiming "high" confidence on low-confidence facts — an otherwise grounded document thrown away over one field. Clamping can only ever LOWER a claim, so the invariant holds exactly as before and now holds deterministically rather than depending on the model obeying an instruction. """ facts = {"facts": {"controls_total": 11}} payload = _payload("共 11 项。", "11 items.", ["/facts/controls_total"]) payload["data_gaps"] = [{ "title_zh": "缺少清单", "title_en": "Inventory missing", "detail_zh": "共 11 项未覆盖。", "detail_en": "11 items uncovered.", "fact_refs": ["/facts/controls_total"], "evidence_refs": [], "confidence": "low", }] payload["risks"] = [{ "title_zh": "风险", "title_en": "A risk", "detail_zh": "共 11 项。", "detail_en": "11 items.", "fact_refs": ["/facts/controls_total"], "evidence_refs": [], "confidence": "high", "severity": "high", }] output = validate_intelligence_output( payload, facts=facts, allowed_evidence_refs=set(), confidence_score=40, ) assert output.risks[0].confidence == "medium", ( "a high claim on low-confidence facts must be lowered, not refused" ) def test_low_confidence_with_no_data_gap_is_still_refused(): """The other half stays a refusal: a missing explanation cannot be manufactured, only the model can supply one.""" facts = {"facts": {"controls_total": 11}} with pytest.raises(IntelligenceContractError, match="data gap"): validate_intelligence_output( _payload("共 11 项。", "11 items.", ["/facts/controls_total"]), facts=facts, allowed_evidence_refs=set(), confidence_score=40, )