For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Build the governed path from natural-language data standards and rules, through immutable DataFlow production-line assembly, to Data Factory deployment on Kestra and the DataOps Runner.
Architecture: Data standards, reusable rules, DataFlow versions, and Data Factory deployments remain separate versioned aggregates while sharing one RuleSpec compiler and artifact model. AI produces schema-constrained candidates; deterministic validators, tests, policy, and immutable hashes decide what can be published. A released DataFlowVersion resolves StandardVersion and RuleVersion references into a ProductionLinePackage and WorkflowSpec; only Data Factory may deploy and activate it.
Tech Stack: Flask 2.3, SQLAlchemy 2, Alembic/PostgreSQL JSONB, OpenAI-compatible LLM client, existing WorkflowSpec/Kestra compiler, DataOps Runner, Vue 2/Vuetify, pytest, Docker Compose.
This iteration delivers a deployable governed foundation:
20260723_110;The following M3/M5 runtime activation work is deliberately not represented as available capability yet:
/api/rules/capabilities now returns
production_line_release=true and data_factory_activation=false. The Vue
deployment page exposes this distinction: a production line may be released,
but cannot be activated until the M3 runtime adapter and M5 canary/rollback
evidence are complete.
| Milestone | Tasks | Deployable outcome |
|---|---|---|
| M1 — governed contracts | 1–3 | Rule/Standard/DataFlow schemas, immutable persistence, AI candidate validation |
| M2 — production-line control plane | 4–5 | Standards and rules resolve into a released ProductionLinePackage and API |
| M3 — deterministic execution | 6 | rule.apply/quality.check compile to Kestra and fail closed in Runner |
| M4 — product experience | 7 | Data Standard, Data Flow, and Data Factory pages expose their separate duties |
| M5 — acceptance and rollout | 8 | Migration, API, canary, rollback, and Docker evidence |
app/core/data_rules/contracts.py: closed schemas, normalization, canonical hashing.app/core/data_rules/authoring.py: schema-constrained AI candidate generation and bounded repair.app/core/data_rules/repository.py: immutable PostgreSQL versions and catalog reads.app/core/data_rules/production_line.py: standard expansion, conflict checks, package resolution.app/api/data_rules/routes.py: rule/standard validation, authoring, publishing, and resolve APIs.app/core/orchestration/spec.py: registered rule.apply and quality.check workflow nodes.app/runner/rules.py: published-plan lookup and deterministic rule execution adapter.migrations/versions/20260723_110_ai_data_rules.py: rule, standard, DataFlow version, artifact, deployment, and run tables.frontend/src/views/dataGovernance/dataStandard/: natural-language standard authoring and read-only executable artifacts.frontend/src/views/dataGovernance/dataProcess/: StandardVersion/RuleVersion production-line assembly.frontend/src/views/dataFactory/workflow/: released-line deployment, canary, activate, and rollback.tests/core/data_rules/: domain contract, authoring, repository, and resolver tests.tests/integration/test_data_rule_production_line.py: PostgreSQL-backed end-to-end control-plane acceptance.Files:
app/core/data_rules/__init__.pyapp/core/data_rules/contracts.pyCreate: tests/core/data_rules/test_contracts.py
[ ] Step 1: Write failing tests for valid RuleSpec normalization and stable hashing
def test_rule_spec_is_closed_normalized_and_hash_stable():
normalized = validate_rule_spec(valid_rule_spec())
assert normalized["steps"][0]["op"] == "normalize_text"
assert rule_spec_hash(valid_rule_spec()) == rule_spec_hash(reordered_rule_spec())
Run: PYTHONPATH=. .venv/bin/pytest -q tests/core/data_rules/test_contracts.py
Expected: FAIL because app.core.data_rules.contracts does not exist.
RULE_OPS = {
"cast", "normalize_text", "regex_replace", "fill_null", "filter",
"derive", "map_values", "assert", "deduplicate", "aggregate",
"lookup_join", "mask",
}
def rule_spec_hash(value):
normalized = validate_rule_spec(value)
canonical = json.dumps(
normalized, sort_keys=True, separators=(",", ":"), ensure_ascii=False
)
return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
The validators must close unknown fields, require UUIDv7 identifiers, reject secret material and arbitrary source code, bound arrays and strings, enforce unique step/component IDs, and reject unsupported component types.
Run: PYTHONPATH=. .venv/bin/pytest -q tests/core/data_rules/test_contracts.py
Expected: all contract tests pass.
Files:
app/core/data_rules/authoring.pyCreate: tests/core/data_rules/test_authoring.py
[ ] Step 1: Write failing tests for standard and flow authoring
def test_authoring_validates_model_output_before_returning_candidate():
model = FakeModel({"candidate_type": "rule", "rule_spec": valid_rule_spec()})
candidate = RuleAuthoringAgent(model=model).interpret(
source_text="手机号去空格后必须为11位数字",
authoring_surface="data_standard",
context={"input_schema_ref": "bd:customer:v1"},
)
assert candidate["source_text"].startswith("手机号")
assert candidate["candidate_hash"]
Run: PYTHONPATH=. .venv/bin/pytest -q tests/core/data_rules/test_authoring.py
Expected: FAIL on missing RuleAuthoringAgent.
class RuleAuthoringAgent:
def interpret(self, *, source_text, authoring_surface, context):
raw = self.model.generate(
messages=build_rule_messages(source_text, authoring_surface, context),
response_schema=RULE_CANDIDATE_SCHEMA,
timeout_seconds=self.timeout_seconds,
)
candidate = validate_rule_candidate(json.loads(raw))
return attach_generation_evidence(candidate, source_text, self.model, context)
The model receives only bounded, redacted context. The returned candidate records provider, model, prompt version, context hash, candidate hash, assumptions, ambiguities, and confidence. Invalid output fails closed; no SQL, Python, publication, or production tool is invoked by the model.
Run: PYTHONPATH=. .venv/bin/pytest -q tests/core/data_rules/test_authoring.py
Expected: valid candidates pass; malformed/ambiguous output is rejected or marked clarification_required.
Files:
migrations/versions/20260723_110_ai_data_rules.pytests/test_database_migrations.pyCreate: tests/test_data_rule_schema.py
[ ] Step 1: Write failing migration contract tests
EXPECTED_RULE_TABLES = {
"data_rules", "data_rule_versions", "rule_generation_runs",
"data_standards", "data_standard_versions", "standard_rule_bindings",
"dataflow_versions", "dataflow_component_bindings",
"rule_execution_plans", "rule_artifacts", "dataflow_deployments",
"rule_runs", "rule_violation_samples",
}
Run: PYTHONPATH=. .venv/bin/pytest -q tests/test_data_rule_schema.py
Expected: FAIL because revision 20260723_110 is absent.
The migration must use PostgreSQL UUID/JSONB/TIMESTAMPTZ, immutable version status checks, unique version numbers, fixed StandardVersion→RuleVersion and DataFlowVersion→component foreign keys, artifact hashes, AI audit hashes, deployment environment/status checks, and run/violation evidence. Downgrade preserves business data and performs no destructive drop.
Run: PYTHONPATH=. .venv/bin/pytest -q tests/test_data_rule_schema.py tests/test_database_migrations.py
Expected: all non-integration migration tests pass.
Files:
app/core/data_rules/production_line.pytests/core/data_rules/test_production_line.pyapp/core/orchestration/spec.pyModify: tests/core/orchestration/test_spec.py
[ ] Step 1: Write failing tests for StandardVersion expansion
package = resolve_production_line(
dataflow_spec=valid_dataflow_spec(),
standard_versions={standard_id: published_standard(rule_id)},
rule_versions={rule_id: published_rule(valid_rule_spec())},
)
assert package["standard_version_ids"] == [standard_id]
assert package["rule_version_ids"] == [rule_id]
assert package["workflow_spec"]["nodes"][0]["type"] == "quality.check"
Run: PYTHONPATH=. .venv/bin/pytest -q tests/core/data_rules/test_production_line.py tests/core/orchestration/test_spec.py
Expected: FAIL because the resolver and rule nodes are not registered.
The resolver must require published referenced versions, expand standard.enforce, deduplicate identical rule versions, preserve standard clause provenance, reject conflicting writes to the same target, generate acyclic nodes/edges, and produce sorted StandardVersion/RuleVersion lists plus a canonical package hash.
rule.apply and quality.check must require component_binding_id, rule_version_id, and execution_plan_hash. rule.apply writes require an idempotency strategy. Neither node accepts inline RuleSpec, SQL, Python source, credentials, URLs, or artifact bodies.
Run: PYTHONPATH=. .venv/bin/pytest -q tests/core/data_rules/test_production_line.py tests/core/orchestration/test_spec.py
Expected: all tests pass.
Files:
app/core/data_rules/repository.pyapp/api/data_rules/__init__.pyapp/api/data_rules/routes.pyapp/__init__.pyapp/core/system/permissions.pytests/core/data_rules/test_repository.pyCreate: tests/test_data_rule_api.py
[ ] Step 1: Write failing API tests
response = client.post(
"/api/rules/production-lines/resolve",
json={"dataflow_spec": valid_dataflow_spec()},
headers=editor_token_headers,
)
assert response.status_code == 200
assert response.get_json()["data"]["package_hash"]
Run: PYTHONPATH=. .venv/bin/pytest -q tests/test_data_rule_api.py
Expected: FAIL with 404.
Repository operations create stable identities and draft versions, publish only validated versions, load all referenced StandardVersion/RuleVersion rows in bounded queries, and create released DataFlowVersion/component rows transactionally. Published and released rows are never updated in place.
/api/rules control-plane routes and RBACAdd capabilities, interpret, validate, create-version, publish, resolve, and release routes. Use existing response envelopes and rules:read/edit/publish, standards:*, dataflows:* permissions. API errors are bounded and do not echo model output, secrets, generated code, or raw data.
Run: PYTHONPATH=. .venv/bin/pytest -q tests/core/data_rules/test_repository.py tests/test_data_rule_api.py tests/test_permission_matrix.py
Expected: all tests pass with 401/403/409 cases covered.
Files:
app/runner/rules.pyapp/runner/bootstrap.pytests/runner/test_nodes.pytests/runner/test_rules.pyModify: tests/core/orchestration/test_kestra_compiler.py
[ ] Step 1: Write failing tests for signed plan lookup
result = RulePlanExecutor(repository, adapters={"quality_check": adapter}).execute(
governed_node(), {}, write_authorized=False
)
assert result["status"] == "pass"
assert repository.requested == [(binding_id, plan_hash)]
Run: PYTHONPATH=. .venv/bin/pytest -q tests/runner/test_rules.py
Expected: FAIL on missing executor.
Runner loads only a published plan by component binding and exact hash, verifies artifact digest/status, dispatches only a registered backend adapter, and refuses inline plans. Initial adapters support deterministic quality checks and precompiled SQL/Polars handler names; generated Python remains disabled until signed-artifact sandbox tests exist.
Run: PYTHONPATH=. .venv/bin/pytest -q tests/runner/test_rules.py tests/core/orchestration/test_kestra_compiler.py
Expected: tests pass and compiled YAML contains version/hash references but no rule text, source code, credentials, or data.
Files:
frontend/src/views/dataGovernance/dataStandard/components/edit.vuefrontend/src/views/dataGovernance/dataStandard/index.vuefrontend/src/views/dataGovernance/dataProcess/components/edit.vuefrontend/src/views/dataFactory/workflow/WorkflowList.vuefrontend/src/api/dataGovernance.jsfrontend/src/api/dataFactory.jsCreate: tests/test_data_rule_frontend_contract.py
[ ] Step 1: Write failing frontend contract tests
The test asserts that Data Standard uses natural-language authoring and read-only executable artifacts, Data Process includes StandardVersion and RuleVersion components plus release, and Data Factory lists released DataFlowVersion deployments plus canary/activate/rollback. It also asserts the legacy direct dataStandardCodeGenerate save path is absent.
Run: PYTHONPATH=. .venv/bin/pytest -q tests/test_data_rule_frontend_contract.py
Expected: FAIL on missing API calls and component labels.
Use existing Vuetify patterns. Keep AI interpretation, assumptions, ambiguities, sample results, immutable versions, and impact visible. Do not render credentials, raw sensitive rows, editable generated source, or Data Factory rule-edit controls.
Run: PYTHONPATH=. .venv/bin/pytest -q tests/test_data_rule_frontend_contract.py
Run: npm --prefix frontend run build
Expected: tests and production build pass.
Files:
tests/integration/test_data_rule_production_line.pytests/test_local_docker_contract.pyModify: deploy/docker/README.md
[ ] Step 1: Write opt-in integration acceptance
The test creates a rule and standard, publishes immutable versions, resolves/releases a DataFlowVersion, creates a test DataFlowDeployment, verifies all hashes and foreign keys, and proves a new StandardVersion does not mutate the released production line.
Run:
PYTHONPATH=. .venv/bin/pytest -q \
tests/core/data_rules \
tests/core/orchestration \
tests/runner \
tests/test_data_rule_schema.py \
tests/test_data_rule_api.py \
tests/test_database_migrations.py \
tests/test_local_docker_contract.py
Expected: all tests pass; PostgreSQL integration may skip unless explicitly enabled.
Run: docker compose -f deploy/docker/docker-compose.yml up -d --build postgres neo4j minio minio-init kestra runner backend frontend
Expected: all requested services reach healthy/completed state.
Run: docker compose -f deploy/docker/docker-compose.yml exec backend alembic -c alembic.ini upgrade head
Run the authenticated live API smoke test for rule validation, production-line resolve, backend health, and runner health.
Expected: migration head is 20260723_110; API returns immutable package hashes; health endpoints are successful.
Run: docker compose -f deploy/docker/docker-compose.yml ps
Run: git diff --check
Expected: containers are healthy, tests/build are green, and diff check reports no whitespace errors.