from pathlib import Path from app.core.common.identifiers import new_governance_uid from app.core.data_rules.contracts import validate_dataflow_spec API = Path("frontend/src/api/dataRules.js") AUTHORING = Path("frontend/src/components/DataRules/RuleAuthoringPanel.vue") CATALOG = Path("frontend/src/components/DataRules/RuleCatalogPicker.vue") EVIDENCE = Path("frontend/src/components/DataRules/CompilationEvidence.vue") ASSEMBLER = Path( "frontend/src/components/DataRules/ProductionLineAssembler.vue" ) STANDARD = Path( "frontend/src/views/dataGovernance/dataStandard/components/edit.vue" ) DATAFLOW = Path( "frontend/src/views/dataGovernance/dataProcess/components/edit.vue" ) FACTORY = Path( "frontend/src/views/dataFactory/productionLineDeployment/index.vue" ) FACTORY_INDEX = FACTORY def test_rule_api_client_exposes_versions_publish_and_server_side_release(): source = API.read_text(encoding="utf-8") assert "http.get('/rules/capabilities')" in source assert "http.post('/rules/interpret'" in source assert "http.post('/rules/validate'" in source assert "http.post('/rules/production-lines/resolve'" in source assert "http.post('/rules/rule-versions'" in source assert "http.post(`/rules/rule-versions/${versionId}/publish`)" in source assert "http.post(`/rules/rule-versions/${versionId}/validate`" in source assert "http.post(`/rules/rule-versions/${versionId}/test`" in source assert "http.get('/rules/catalog'" in source assert "/rules/catalog/assets/${assetType}/${versionId}/evidence" in source assert "http.post('/rules/standard-versions'" in source assert "http.post(`/rules/standard-versions/${versionId}/publish`)" in source assert "http.post(`/rules/production-lines/${dataflowUid}/release`" in source assert "listDataFlowDeployments" in source assert "/deploy-disabled" in source assert "/canary" in source assert "/activate" in source assert "/rollback" in source def test_reusable_authoring_panel_preserves_human_review_gate(): source = AUTHORING.read_text(encoding="utf-8") assert "authoringSurface" in source assert "interpretRule" in source assert "clarification_required" in source assert "$emit('candidate'" in source assert "createRuleVersion" in source assert "publishRuleVersion" in source assert "先生成并发布 RuleVersion" in source assert "rules:publish" in source assert "$emit('version'" in source assert "自动执行" not in source def test_authoring_panel_exposes_governed_ai_lifecycle_without_code_editor(): source = AUTHORING.read_text(encoding="utf-8") for token in [ "schemaContextReady", "generation_receipt", "assumptions", "ambiguities", "modelProvenance", "validateRuleVersion", "testRuleVersion", "CompilationEvidence", ]: assert token in source assert "candidatePreview" not in source assert "
{{ candidate" not in source
def test_catalog_picker_selects_fixed_published_asset_versions():
source = CATALOG.read_text(encoding="utf-8")
for token in [
"searchPublishedCatalog",
"assetType",
"published",
"schema_compatibility",
"latest_evidence",
"v-skeleton-loader",
"aria-label",
"keydown",
]:
assert token in source
assert "$emit('input', item.id)" in source
assert "item.name" in source
assert "rule_uid" in source
assert "standard_uid" in source
def test_compilation_evidence_shows_trusted_chain_without_sensitive_payloads():
source = EVIDENCE.read_text(encoding="utf-8")
for token in [
"generation",
"logical_compile",
"dry_run",
"publication",
"physical",
"getRuleVersionEvidence",
]:
assert token in source
for forbidden in ["raw_sample", "secret", "password", "token"]:
assert forbidden not in source.lower()
assert "'ready'" in source
def test_standard_links_published_rules_and_keeps_legacy_code_read_only():
standard = STANDARD.read_text(encoding="utf-8")
assert 'authoring-surface="data_standard"' in standard
assert '@version="handleRuleVersion"' in standard
assert "RuleCatalogPicker" in standard
assert "rule_version_id" in standard
assert "legacyMigration" in standard
assert "readonly" in standard
assert "迁移" in standard
assert "dataStandardCodeGenerate" not in standard
assert "handleCodeGenerate" not in standard
assert "rule_version_status" not in standard
def test_dataflow_assembler_uses_published_catalog_ids_without_inline_rules():
source = ASSEMBLER.read_text(encoding="utf-8")
dataflow = DATAFLOW.read_text(encoding="utf-8")
assert "RuleCatalogPicker" in source
assert "standard_version_id" in source
assert "rule_version_id" in source
assert "schema_compatibility" in source
assert "releaseReadiness" in source
assert "component_kind" in source
assert "rule_spec" not in source
assert "operation_code" not in source
assert "ProductionLineAssembler" in dataflow
assert "dataflow_spec" in dataflow
assert "migration_metadata" in dataflow
assert "rule_spec" not in dataflow
assert "v-model=\"changeObj.rule\"" not in dataflow
assert "handleRuleCandidate" not in dataflow
def test_assembler_emits_a_real_closed_dataflow_spec_for_every_station_kind():
standard_version_id = new_governance_uid()
apply_rule_version_id = new_governance_uid()
quality_rule_version_id = new_governance_uid()
normalized = validate_dataflow_spec(
{
"schema_version": "1.0",
"dataflow_uid": new_governance_uid(),
"name": "客户数据生产线",
"description": "固定受治理资产版本",
"input_schema_refs": ["bd:customer_raw:v1"],
"output_schema_ref": "bd:customer_clean:v1",
"components": [
{
"id": "station_1",
"type": "standard.enforce",
"standard_version_id": standard_version_id,
"stage": "quality_gate",
"order": 1,
},
{
"id": "station_2",
"type": "rule.apply",
"rule_version_id": apply_rule_version_id,
"stage": "transform",
"order": 2,
"idempotency": {
"strategy": "partition_replace",
"key": "run_partition",
},
},
{
"id": "station_3",
"type": "quality.check",
"rule_version_id": quality_rule_version_id,
"stage": "quality_gate",
"order": 3,
},
],
"parameters": {},
}
)
assert "idempotency" not in normalized["components"][0]
assert "idempotency" in normalized["components"][1]
assert "idempotency" not in normalized["components"][2]
source = ASSEMBLER.read_text(encoding="utf-8")
assert "station.component_kind === 'rule.apply'" in source
assert "component.idempotency" in source
assert "idempotency: {" not in source
def test_catalog_never_guesses_schema_compatibility_from_arbitrary_objects():
source = CATALOG.read_text(encoding="utf-8")
assembler = ASSEMBLER.read_text(encoding="utf-8")
assert "normalizeCompatibility" in source
assert "Object.keys(item.schema_compatibility).length" not in source
assert "unknown" in source
assert "schema_compatibility !== 'compatible'" in assembler
assert "服务端发布预检" in assembler
assert "requestSequence" in source
assert "requestId !== this.requestSequence" in source
assert "getPublishedCatalogAsset" in source
assert "inputSchemaRefs" in source
assert "outputSchemaRef" in source
def test_production_line_editor_renews_expiring_receipts_and_retries_only_safe_errors():
source = DATAFLOW.read_text(encoding="utf-8")
request = Path("frontend/src/utils/request.js").read_text(encoding="utf-8")
assert "governedDraftExpiresAt" in source
assert "data.expires_at" in source
assert "expiresAt - Date.now() <= 60000" in source
assert "ensureFreshDraftReservation" in source
assert "draft_reservation_refresh_required" in source
assert "governedDraftReplayRequired" in source
assert "if (this.governedDraftReplayRequired) return" in source
assert "await this.ensureDataflowUid(true)" in source
assert source.count("await api.addDataFlow(payload)") == 2
assert "error.response?.data" in request
def test_new_dataflow_gets_server_governed_uid_before_assembly():
api = API.read_text(encoding="utf-8")
dataflow = DATAFLOW.read_text(encoding="utf-8")
assert "createProductionLineDraftIdentity" in api
assert "/rules/production-lines/draft-identity" in api
assert "ensureDataflowUid" in dataflow
assert "if (!this.dataflowUid) await this.ensureDataflowUid()" in dataflow
assert "persistedUid" in dataflow
assert "dataflow_uid: null" not in dataflow
def test_standard_authoring_does_not_forge_validated_state_client_side():
source = AUTHORING.read_text(encoding="utf-8")
assert "candidate.candidate_type === 'standard'" not in source or (
"status: 'validated'" not in source
)
assert "先发布规则,再在标准条款中绑定" in source
def test_data_factory_exposes_governed_trial_activation_and_rollback():
page = FACTORY.read_text(encoding="utf-8")
index = FACTORY_INDEX.read_text(encoding="utf-8")
assert "数据生产线投产" in page
assert "getRuleCapabilities" in page
assert "data_factory_readiness" in page
assert "listDataFlowDeployments" in page
assert "listDataFlowDeploymentCandidates" in page
assert "createDataFlowDeployment" in page
assert "deployDataFlowDisabled" in page
assert "runDataFlowCanary" in page
assert "activateDataFlowDeployment" in page
assert "rollbackDataFlowDeployment" in page
assert "reconcileDataFlowDeploy" in page
assert "reconcileDataFlowActivate" in page
assert "reconcileDataFlowRollback" in page
assert "dataflows:deploy" in page
assert "dataflows:canary" in page
assert "rules:execute" in page
assert "dataflows:activate" in page
assert "dataflows:rollback" in page
assert "生产线包 Hash" in page
assert "试生产证据" in page
assert "状态履历" in page
assert "生产线入厂" in page
assert "window.localStorage.getItem(storageKey)" in page
assert "window.localStorage.setItem(storageKey, value)" in page
assert "error?.error?.code === 'terminal_conflict'" in page
assert "Number(error?.code) === 409" not in page
assert "unknown_operations" in page
assert "v-dialog" in page
assert "ProductionLineDeployment" in index