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 a canonical device asset catalog with stable platform UIDs, immutable versions, source-system code mappings, source timestamps, search, and end-to-end traceability for devices, components, measurement points, alarms, and maintenance records.
Architecture: PostgreSQL remains authoritative for canonical device assets, source mappings, and immutable versions. A normalized import service accepts bounded records from the existing ingestion boundary, never reads credentials, and never merges two source identities automatically; later WP-06 matching may explicitly link identities after review. The Vue 2 catalog is a read and trace interface, while write access is exposed through a dedicated permission-controlled API for adapters and data engineers.
Tech Stack: Flask, SQLAlchemy, PostgreSQL JSONB, Alembic, Vue 2, Vuetify, pytest.
device, component, measurement_point, alarm, and maintenance_record.(source_uid, source_entity, asset_type, source_code).device-assets:edit.codex/dataops-phase1-equipment-governance; no push or remote deployment is authorized.Files:
app/core/data_research/device_assets.pyapp/core/data_research/errors.pytests/data_research/test_device_assets.pyInterfaces:
repository.source_is_active(source_uid), repository.find_mapping(...), repository.create_asset(...), repository.update_asset(...), and repository.touch_mapping(...).Produces: DeviceAssetService.import_records(payload, actor_uid), DeviceAssetRecord, DeviceAssetMappingRecord, DeviceAssetVersionRecord, and DeviceAssetImportResult.
[x] Step 1: Write failing domain tests
Cover stable UID reuse, unchanged reimport without a new version, changed record with exactly one new version, five allowed asset types, inactive source rejection, duplicate source code rejection inside one request, bounded batch size, required source entity/code/name, attributes size, secret-key rejection, and no caller-supplied asset UID.
Run:
PYTHONPATH=. .venv/bin/pytest -q tests/data_research/test_device_assets.py
Expected: failure because the device asset service does not exist.
Normalize fields, compute a deterministic SHA-256 content hash, create a UUIDv7 only for a new source identity, preserve the existing UID on reimport, and classify every input as created, updated, or unchanged.
Run the Task 1 test command and expect all tests to pass.
Files:
app/core/data_research/device_asset_repository.pyapp/models/data_research.pymigrations/versions/20260729_290_device_asset_catalog.pytests/test_database_migrations.pytests/integration/test_device_asset_postgres.pyInterfaces:
Produces: SqlAlchemyDeviceAssetRepository, tables device_assets, device_asset_source_mappings, and device_asset_versions.
[x] Step 1: Write failing persistence tests
Add a migration contract test and a real PostgreSQL integration test covering source validation, one canonical asset, one unique mapping, immutable sequential versions, source timestamp refresh, search by source code/name/location/responsible person, type/status/source filters, and detail traceability.
Run:
PYTHONPATH=. .venv/bin/pytest -q \
tests/test_database_migrations.py::test_device_asset_catalog_migration_is_versioned_and_traceable \
tests/integration/test_device_asset_postgres.py
Expected: failure because the migration, models, and SQL repository do not exist.
Use unique constraints for source identity and asset version, row locking for updates, indexed search fields, source and actor timestamps, JSONB snapshots, and data-preserving downgrade behavior.
Run:
docker exec dataops-test-backend-1 alembic upgrade head
PYTHONPATH=. .venv/bin/pytest -q \
tests/test_database_migrations.py::test_device_asset_catalog_migration_is_versioned_and_traceable \
tests/integration/test_device_asset_postgres.py
Expected: migration head 20260729_290; tests pass.
Files:
app/api/data_development/routes.pyapp/core/system/permissions.pytests/data_research/test_development_api.pytests/test_permission_matrix.pyInterfaces:
Produces: POST /api/development/v1/device-assets/import, GET /api/development/v1/device-assets, GET /api/development/v1/device-assets/{asset_uid}, and GET /api/development/v1/device-assets/{asset_uid}/versions.
[x] Step 1: Write failing API and permission tests
Cover viewer read, viewer import denial, editor import, secret-free responses, search/filter pagination, detail mappings, version history, malformed pagination, and not-found errors.
Run:
PYTHONPATH=. .venv/bin/pytest -q \
tests/data_research/test_development_api.py \
tests/test_permission_matrix.py::test_data_development_paths_have_specific_write_policies
Expected: failure because the routes and permission do not exist.
Add device-assets:edit to editor/admin, keep reads on governance:read, bound page to at least 1 and page size to 1–100, serialize source mappings and versions without secret material, and return domain errors through the existing data-research error envelope.
Run the Task 3 test command and expect all tests to pass.
Files:
frontend/src/api/dataDevelopment.jsfrontend/src/router/routes.jsfrontend/src/views/dataGovernance/development/index.vuefrontend/src/views/dataGovernance/development/deviceAssets.vuedocs/architecture/OPENAPI.yamldocs/architecture/DATA_MODEL.mddocs/FUNCTION_MODULE_CENSUS_20260726.mddocs/DATAOPS_PHASE1_3_MONTH_WORK_PLAN_20260729.mddeployment/app/ only for the WP-04 backend subset.Interfaces:
Produces: /data-governance/development/device-assets with keyword/type/status filters, stable UID display, source-code chips, source timestamps, responsibility fields, detail traceability, and immutable version history.
[x] Step 1: Implement the catalog UI
Add API functions, hidden child route, research-center entry, responsive table, detail dialog, empty/error/loading states, source mappings, and version timeline. Do not add a generic analysis-development or raw-SQL interface.
Run:
.venv/bin/python scripts/generate_openapi.py
Record engineering completion separately from enterprise data acceptance and keep WP-06 automatic matching outside WP-04.
Run only:
PYTHONPATH=. .venv/bin/pytest -q \
tests/data_research/test_device_assets.py \
tests/integration/test_device_asset_postgres.py \
tests/data_research/test_development_api.py \
tests/test_permission_matrix.py::test_data_development_paths_have_specific_write_policies \
tests/test_database_migrations.py::test_device_asset_catalog_migration_is_versioned_and_traceable \
tests/test_architecture_artifacts.py
npx eslint src/api/dataDevelopment.js src/router/routes.js \
src/views/dataGovernance/development/index.vue \
src/views/dataGovernance/development/deviceAssets.vue
Then rebuild only the affected local backend/frontend services and exercise import, search, detail, source mapping, and version history in the browser. Run git diff --check.
Create one independently reversible WP-04 engineering commit. Do not push.
20260729_290 is the local head; the real PostgreSQL integration test covers source identity, search, filters, detail, and version history.governance:read for reads and device-assets:edit for import. OpenAPI now inventories 151 operations.EQ-WP04-DEMO: source-code search returned one stable asset at V2, detail showed source mapping plus V1/V2 locations and correct China timestamps, with zero browser console errors.