Date: 2026-07-24
Branch: codex/data-rule-execution-m3a-m5
Task 8 removes the user-facing parallel rule implementations from Data Standard and Data Flow authoring.
The governed path is now:
Generated source code is never editable in the new path. Legacy code and free-text flow rules remain visible only in explicit migration sections and are excluded from new execution semantics.
The control plane now exposes:
GET /api/rules/catalog
query, asset_type, limit, and offset parameters;GET /api/rules/catalog/assets/<rule|standard>/<version_id>/evidence
Compatibility aliases remain available at
/api/rules/catalog/rule-versions and
/api/rules/rule-versions/<version_id>/evidence. Global API policy keeps all
GET paths behind rules:read.
RuleAuthoringPanel now:
rules:edit and rules:publish UI gates;Data Standard editing now links a published RuleVersion through
RuleCatalogPicker. New saves contain the fixed rule_version_id and bounded
migration_metadata; they do not require or write an operation-code field.
Existing operation code is shown in a read-only migration area with clear
unmigrated / linked state and a path back to natural-language
re-authoring. It cannot become execution semantics merely by saving the
legacy record.
Data Flow no longer edits free-text rules or embeds rule definitions.
ProductionLineAssembler models the flow as ordered factory stations:
standard.enforce fixes a standard_version_id;rule.apply and quality.check fix a rule_version_id;The new saved script_requirement envelope contains only:
dataflow_spec;dataset_edges;migration_metadata.It contains no inline rule definition or generated source. Existing legacy requirements remain read-only and are not copied into that envelope.
The implementation reuses Vue 2, Vuetify, Material Design Icons, and the existing request client. No dependency or design system was added.
The interface uses a low-motion, medium/high-density governance-workbench style. Catalog loading, empty and error states are explicit. Catalog items support focus, arrow navigation, Enter/Space selection, listbox semantics, ARIA labels, and skeleton loading. Responsive layout collapses the Data Flow dataset grid on narrow screens.
Fail-first:
5 failed, 3 passed because the
three governed components and convergence behavior did not exist.Final:
64 passed;673 passed, 33 skipped, 59 subtests passed;git diff --check: passed;0 errors;no-console warnings plus existing CSS
ordering and bundle-size warnings;/api/system/health returned application code 200;/api/rules/catalog returned HTTP 401.Browser automation opened the rebuilt deployment and verified the local login surface. The documented local sample administrator password did not match the persisted administrator in this long-lived Docker volume, so authenticated Standard/Data Flow navigation was not forced by overwriting or resetting credentials. The build, component contracts, authenticated API tests, real PostgreSQL query, and container health checks provide the Task 8 acceptance evidence; an authenticated visual walkthrough can be repeated during the phase-level M4 acceptance with the environment owner’s current local credential.
The post-implementation review found eight convergence gaps. All eight are closed:
rule.apply; standard.enforce and
quality.check now match the closed DataFlow contract;unknown;POST /api/interface/data/standard/code is closed with HTTP 410 and
read-only-migration semantics;rule_version_id against the complete trusted publication evidence chain;validated state;
new Standard clauses must bind a server-published RuleVersion;ready is rendered as successful and async
station values are reloaded by the existing deep watcher.The cutover deliberately preserves legacy non-governed records and read-only migration displays, while preventing those fields from becoming new governed execution semantics.
The second review strengthened the boundary from server-issued identifiers to database-enforced, single-use draft reservations:
20260723_210 adds a unique DataFlow UID, actor foreign key,
unique nonce digest, expiration and consumption ledger;UPDATE ... RETURNING;script_type, script path, task, code or workflow fields;Data Standard natural-language authoring now deterministically produces a Rule candidate. The prompt states that rule explicitly, the authoring agent repairs a model-produced Standard candidate, and the API independently checks the post-validation candidate before recording or signing it. New legacy Standard records require an exactly attested published RuleVersion; only an existing legacy record may be updated without one for read-only migration.
Catalog compatibility is now evaluated server-side against the production
line's current input and output schema references. It returns
compatible, incompatible, or unknown with a reason and evidence.
The frontend supplies this context, blocks unknown/incompatible stations,
hydrates an already-fixed version through an exact-version endpoint even
when it is outside the first catalog page, and uses a monotonically
increasing request sequence so stale searches cannot overwrite newer
context.
Real PostgreSQL acceptance confirmed:
20260723_210 (head);The third review replaced the one-shot PostgreSQL-consume/Neo4j-create
boundary with a recoverable create Saga. Historical migration 210 remains
unchanged; forward-only migration 20260724_220 adds:
reserved, creating, completed, and failed states;begin_dataflow_create now uses one conditional UPDATE ... RETURNING to
claim a lease. The claim is committed before the graph side effect. Governed
DataFlow creation installs the idempotent DataFlow.uid unique constraint,
uses MERGE only on the server-reserved UID, and verifies the persisted name,
UID, script type and canonical governed requirement without overwriting an
existing node. Completion conditionally owns the lease and persists the exact
response. A retry after response loss returns that stored response; an expired
lease reclaims the same UID, observes the existing graph node and finalizes it.
Name/UID or immutable-property conflicts fail closed.
Catalog compatibility no longer trusts matching reference strings alone:
SchemaResolver;standard_rule_bindings entry and requires
the same trusted rule plan/evidence/hash chain for every clause;unknown; same-reference hash drift and any bound
Standard rule drift return incompatible;The Data Flow editor stores the reservation expiry, renews it when less than
60 seconds remain, and changes to a new server UID only when the server
returns the explicit draft_reservation_refresh_required signal. It retries
that safe pre-side-effect case once. Network errors and in-progress leases do
not cause a new UID; a completed response-loss retry is replayed by the server.
Additional acceptance evidence:
20260724_220 (head);dataflow_create_in_progress; completion replay returned the identical
result, expired drafts were rejected, and an expired create lease was
reclaimed as attempt 2;data_flow_uid unique constraint, two same-UID
merges produced one node, and immutable drift was rejected;2 passed;The fourth review closed the remaining transaction and recovery boundaries:
SchemaResolver as an explicit read-through
persistence boundary: successful context-aware GETs commit newly created
snapshots before returning their IDs, and every error path rolls back;20260724_230 adds the canonical create request,
server-owned create intent and SHA-256 request digest without modifying
migration 220;dataflow_create_request_conflict instead of
silently returning an older result;DataFlowCreateReconciler and
python -m app.commands.reconcile_dataflow_creates recover orphaned graph
nodes without accepting a nonce or inline business payload:
creating or retryable failed rows with
FOR UPDATE SKIP LOCKED and an expiring lease;MERGE either finds the orphan or creates the
missing node, verifies immutable properties, and then finalizes PostgreSQL;Fourth-review acceptance:
65 passed;4 passed;673 passed, 33 skipped, 59 subtests passed.The fifth review removed the remaining concurrency and poison-record failure modes from orphan reconciliation:
lease_recovery_required;create_intent_integrity_failed without aborting the next valid item;create_intent_validation_failed. Both terminal codes are excluded from
later list and claim queries, while infrastructure failures remain
retryable;UPDATE ... RETURNING; a stale worker that no
longer owns the lease cannot report a false successful failure transition;MERGE (DataFlow)-[:LABEL]->(DataLabel) path shared by normal creation and
reconciliation. Governed tag failures are strict: PostgreSQL is not
finalized, the Saga remains retryable, and a later retry completes without
duplicate relationships. Legacy tag handling retains its previous
best-effort behavior.Fifth-review acceptance:
40 passed;3 passed;681 passed, 33 skipped, 59 subtests passed;F, I, and B checks passed;20260724_230 (head), application
health reports database and Neo4j healthy with code 200, and frontend HTTP
returns 200.The sixth review closed the final governed-create time-of-check/time-of-use
window around DataFlow.name_zh:
data_flow_uid and data_flow_name_zh uniqueness constraints before its
preflight and UID-keyed MERGE;dataflow_uid_conflict;Sixth-review acceptance:
47 passed;2 passed: two concurrent
creates with different UUIDv7 values and the same name_zh produced exactly
one success and one dataflow_uid_conflict, left one node, and verified both
constraints;MERGE;682 passed, 34 skipped, 59 subtests passed;F, I, and B checks and whitespace validation passed;20260724_230 (head), application
health reports database and Neo4j healthy with code 200, and frontend HTTP
returns 200.