'synthetic-qa', 'rule_code' => 'IVA-GERAL-BASE-LIQUIDA', 'rule_version' => 1, 'component' => 'IVA', 'status' => 'published', 'scope_key' => 'mz.internal-general-net.mzn', 'valid_from' => '2023-01-01', 'valid_until' => null, 'source_version_no' => 1, 'source_sha256' => str_repeat('a', 64), 'rule_definition' => ['language' => 'investmoz.tax.v1'], 'parameters' => ['IVA_GENERAL_RATE' => ['value' => '16', 'unit' => 'percent', 'conditions' => ['operation' => 'internal_general_net', 'currency' => 'MZN']]], 'source' => ['validation_status' => 'validated', 'version_no' => 1, 'valid_from' => '2023-01-01', 'valid_until' => null, 'title' => 'Synthetic source', 'diploma' => 'QA only', 'article' => 'Fixture', 'url' => 'https://example.invalid/official']]; } public function test_reported_annual_query_contract_reproduces_the_generic_failure_and_identifies_both_missing_links(): void { $version = $this->version(); $context = ['fiscal_operation' => 'domestic']; $original = $context; $before = (new SimulationTaxParameterResolver)->resolveAvailableParameters([$version], 'IVA', '2026-01-01', '2026-12-31', $context); self::assertSame('indeterminate_context', $before[0]['status']); $details = (new SimulationIvaDiagnostics)->explain([$version], '2026-01-01', '2026-12-31', $context); self::assertSame(['system_configuration', 'missing_field'], array_column($details[0]['issues'], 'category')); self::assertSame('domestic', $details[0]['issues'][0]['received']); self::assertSame('MZN', $details[0]['issues'][1]['expected']); self::assertSame($original, $context); self::assertArrayNotHasKey('rule_definition', $details[0]); self::assertArrayNotHasKey('rule_code', $details[0]); } public function test_all_failed_conditions_are_separate_and_currency_is_not_assumed(): void { foreach (['' => 'missing_field', 'usd' => 'invalid_value', 'USD' => 'out_of_scope'] as $value => $category) { $details = (new SimulationIvaDiagnostics)->explain([$this->version()], '2026-01-01', '2026-12-31', ['operation' => 'import', 'currency' => $value]); self::assertCount(2, $details[0]['issues']); self::assertSame('out_of_scope', $details[0]['issues'][0]['category']); self::assertSame($category, $details[0]['issues'][1]['category']); } } public function test_period_and_broken_source_are_not_reported_as_incorrect_answers(): void { $version = $this->version(); $version['source_version_no'] = 2; $details = (new SimulationIvaDiagnostics)->explain([$version], '2022-01-01', '2022-12-31', ['operation' => 'internal_general_net', 'currency' => 'MZN']); self::assertSame(['period_unavailable', 'system_configuration'], array_column($details[0]['issues'], 'category')); self::assertSame('2022-01-01 a 2022-12-31', $details[0]['issues'][0]['received']); self::assertSame(1, $details[0]['rule_version']); self::assertSame('Synthetic source', $details[0]['source']['title']); } public function test_matching_context_has_no_diagnostic_and_does_not_evaluate_an_expression(): void { self::assertSame([], (new SimulationIvaDiagnostics)->explain([$this->version()], '2026-01-01', '2026-12-31', ['operation' => 'internal_general_net', 'currency' => 'MZN'])); } public function test_an_explicitly_excluded_generic_operation_is_reported_without_inferring_a_domestic_scope(): void { $details = (new SimulationIvaDiagnostics)->explain([$this->version()], '2026-01-01', '2026-12-31', ['fiscal_operation' => 'import', 'currency' => 'MZN']); self::assertCount(1, $details[0]['issues']); self::assertSame('out_of_scope', $details[0]['issues'][0]['category']); self::assertSame('import', $details[0]['issues'][0]['received']); } }