Skip to content

Initial beta build for OMOP Waveform Extension ETL - #65

Open
briangow wants to merge 27 commits into
devfrom
bg_waveform_extension_1
Open

Initial beta build for OMOP Waveform Extension ETL#65
briangow wants to merge 27 commits into
devfrom
bg_waveform_extension_1

Conversation

@briangow

Copy link
Copy Markdown
Collaborator

Overview
This PR introduces an initial (beta) build path for OMOP Waveform Extension ETL tables using pre-extracted waveform metadata inputs.

Context
The Python waveform metadata extraction process is currently maintained in a separate repository. Once that process is finalized, it may be incorporated into this repository.

Source metadata inputs
The ETL expects two source tables populated by the extraction script:

waveform_files_all
subject_id, person_id, hadm_id, visit_occurrence_id, visit_detail_id, location, waveform_folders, record_id, group_id, mimic_start, mimic_end, session_start, session_end, file_start, file_end, src_file, trg_file

waveform_channels_all
person_id, visit_occurrence_id, visit_detail_id, group_id, session_start, session_end, file_start, file_end, src_file, trg_file, channel_name, sample_units, sample_rate, sample_rate_units, gain, gain_units, segment_length

What this PR includes:

  • Adds initial SQL ETL build logic for OMOP Waveform Extension targets.
  • Uses waveform_files_all and waveform_channels_all as source metadata interfaces.
  • Applies waveform-specific concept mappings as part of the build. Some waveform-specific vocabulary content is currently supplied via the Tufts CVB repository, and additional terms/mappings will be added over time.

Scope and maturity
This PR establishes the initial/beta end-to-end waveform ETL framework and will be expanded and refined in subsequent updates.

Out of scope
This PR does not build the WAVEFORM_FEATURE table.

@odikia

odikia commented Jun 12, 2026

Copy link
Copy Markdown

@briangow , thanks for the work! will plan to review soon. Any firm deadlines I should be aware of? Should be well before next WG meeting, but just grounding in known milestones

(cherry picked from commit 448f8b386796d8e83b046aaf506c9eb608211563)
@odikia

odikia commented Jun 17, 2026

Copy link
Copy Markdown

Smoke test: runs end-to-end on BigQuery ✅

Stood up a synthetic smoke test of this branch on BigQuery to confirm it executes and emits sane rows.

Setup:

  • Branches
    • dev +
    • this branch +
    • @briangow 's synthetic CSVs:
      • waveform_files_all
      • waveform_channels_all
  • empty vocabulary stubs:
    • voc_concept
    • voc_concept_relationship
    • voc_concept_synonym
    • Note: the COALESCE(LEFT JOIN, 0) lookups resolve to 0
  • obfuscation UDFs installed via workflow_setup then workflow_waveforms

All three ETL scripts ran clean in ~20s. No changes to the PR's SQL.

Output (synthetic data):

Table Rows
cdm_waveform_occurrence 22 (one per distinct group_id)
cdm_waveform_registry 70 (one per file row)
cdm_waveform_channel_metadata 384 (96 channels × 4 metadata types)

PK uniqueness: 0 duplicates on all three tables. metadata_source_value split evenly across AMPLITUDE / SAMPLERATE / RESOLUTION / SEGMENTLENGTH (96 each).

Follow-up Questions/Concerns

A couple of things worth noting from the run:

  • cdm_waveform_channel_metadata.sql:62 (link) aliases the second column value_as_number a second time where it should read value_as_concept_id. It's harmless today because UNION ALL binds by position (verified: all 96 SEGMENTLENGTH rows have value_as_number populated and value_as_concept_id NULL, as intended), but it's a latent bug if the columns are ever reordered. This could be cheap to fix for clarity.
  • The registry numerics (*n.hea / *n.csv) returned 0 rows because the synthetic data has no MIMIC numerics-suffixed files; every file took the base branch. Expected, not a defect. Just flagging that those branches weren't exercised by this dataset, so should be evaluated in the future

One thing to confirm before scale-up:

  • the PKs use obf_id(..., 32), so the keys live in a 2³² space. No collisions at this scale, but the NOT NULL waveform ids could hit "birthday-bound" collisions on a full-set run. Worth either bumping those to bits = 64 or confirming expected cardinalities stay well under ~50k.

Reproducing this from start (for anyone not steeped in the repo layout)

This PR's head branch is bg_waveform_extension_1, and the synthetic source data lives on a separate branch, bg_syn_waveform_metadata (two files under data/). The smoke run assembles a tree of dev + this PR + those CSVs, so the branch-hopping is the non-obvious part. From a fresh throwaway branch:

git fetch origin

# 1. Start from dev (the PR's intended base), not main
git reset --hard origin/dev

# 2. Layer PR #65 on top — it's purely additive, merges clean
git merge --no-edit origin/bg_waveform_extension_1

# 3. Pull ONLY the two synthetic CSVs off Brian's data branch
#    (checkout <branch> -- <paths> grabs just those files, not the whole branch)
git checkout origin/bg_syn_waveform_metadata -- \
  data/waveform_files_all.csv \
  data/waveform_channels_all.csv

Happy to hand over the full runbook + driver script (one bash file, edit your GCP project at the top) if it's useful. It captures the whole sequence above plus the validation queries.

@briangow

Copy link
Copy Markdown
Collaborator Author

@odikia thank you for testing this and for your review!

cdm_waveform_channel_metadata.sql:62 (link) aliases the second column value_as_number a second time where it should read value_as_concept_id. It's harmless today because UNION ALL binds by position (verified: all 96 SEGMENTLENGTH rows have value_as_number populated and value_as_concept_id NULL, as intended), but it's a latent bug if the columns are ever reordered. This could be cheap to fix for clarity.

Good catch, I've changed value_as_number to value_as_concept_id on this line, as intended.

the PKs use obf_id(..., 32), so the keys live in a 2³² space. No collisions at this scale, but the NOT NULL waveform ids could hit "birthday-bound" collisions on a full-set run. Worth either bumping those to bits = 64 or confirming expected cardinalities stay well under ~50k.

Good point, this ID is at high risk for collisions since there are numerous entries in the Waveform Channel Metadata table for every recording. I've updated this to use 64 bit space.

@p-talapova p-talapova left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@briangow, thank you so much for implementing the initial Waveform Extension ETL workflow. The overall population sequence is correct. The table structures are also broadly aligned with the current Waveform Extension specification, and it is reasonable for WAVEFORM_FEATURE population to remain outside the scope of this beta PR.

However, I recommend requesting changes before merge.

Major issues

  1. WAVEFORM_OCCURRENCE uses ANY_VALUE() for person, visit, and timestamp fields, which can hide inconsistent source data and produce nondeterministic results.
  2. preceding_waveform_occurrence_id uses 0 instead of NULL.
  3. num_of_files is calculated from staging rows rather than from the generated registry records.
  4. The numerics logic appears to create two WAVEFORM_REGISTRY records for one transformed CSV target.
  5. Some source and target URIs are reconstructed rather than taken from the authoritative staging values.
  6. Registry person and visit fields are independently copied from staging instead of inherited from WAVEFORM_OCCURRENCE.
  7. WAVEFORM_CHANNEL_METADATA independently regenerates the registry foreign key instead of joining to the populated registry.
  8. Channel metadata identifiers do not include a channel index and may collide for duplicate channel labels.
  9. Required channel and metadata concepts silently default to concept ID 0.
  10. Channel mapping relies on broad name and synonym matching and resolves ambiguity by selecting the lowest concept ID.
  11. Unit mappings are not restricted to valid standard Unit-domain concepts.
  12. No blocking QA is included for duplicate IDs, orphan foreign keys, inconsistent timestamps, or unresolved mandatory mappings (added test/qa/qa_wf_extension.sql as a draft)

Minor issues

  1. The README contains incorrect file paths, and an incomplete staging-data contract.
  2. DDL definitions are duplicated in both the central DDL file and individual ETL scripts.
  3. Several vocabulary joins do not filter non-standard concepts or invalid relationships.
  4. Some metadata records are created even when no metadata value or unit is available.
  5. Workflow formatting is a bit inconsistent

Comment thread README.md Outdated
* set the project root (location of this file) as the current directory

#### Waveforms
- Generate your source data in the format of the `data/waveform_files_all.csv` and `data/waveform_channels_all.csv` or use those files them when performing a dummy build. Upload to BigQuery as waveform_files_all and waveform_channels_all tables, respectively.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

• 'use those files them' is a typo
• The expected grain and uniqueness rules for both staging tables are not documented.
• It is not stated whether timestamps are UTC or local.
• It is not stated whether group_id is globally unique.
• It is not stated whether trg_file uniquely identifies one registry file.
• It is not stated whether one staging row may generate more than one registry record.

If possible, please document the staging contract, including at least:
• natural key and row grain of waveform_files_all;
• natural key and row grain of waveform_channels_all;
• uniqueness expectations for group_id, src_file, and trg_file;
• timestamp timezone and precision;
• nullable and required fields;
• meaning of session_start, session_end, file_start, and file_end;
• whether channel order or channel index is available.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I corrected the README waveform section and added a staging-data contract for waveform_files and waveform_channels, including identifier/uniqueness expectations, required and optional fields, timestamp interpretation (MIMIC date-shifted local clinical time, not UTC), and availability of channel_index.

Comment thread README.md Outdated

#### Waveforms
- Generate your source data in the format of the `data/waveform_files_all.csv` and `data/waveform_channels_all.csv` or use those files them when performing a dummy build. Upload to BigQuery as waveform_files_all and waveform_channels_all tables, respectively.
- Run `etl/cdm_waveform_occurrence.sql`, `cdm_waveform_registry.sql`, `cdm_waveform_channel_metadata.sql` with `python scripts/run_workflow.py -e conf/<env>.etlconf -c conf/workflow_waveforms.conf`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual paths:
etl/etl/cdm_waveform_occurrence.sql
etl/etl/cdm_waveform_registry.sql
etl/etl/cdm_waveform_channel_metadata.sql

Because the scripts are executed through workflow_waveforms.conf, listing each SQL path here may be unnecessary. The README could simply instruct users to execute the workflow configuration.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README now points users to the waveform workflow config(s) rather than listing individual SQL script paths.

Comment thread README.md Outdated
- Generate your source data in the format of the `data/waveform_files_all.csv` and `data/waveform_channels_all.csv` or use those files them when performing a dummy build. Upload to BigQuery as waveform_files_all and waveform_channels_all tables, respectively.
- Run `etl/cdm_waveform_occurrence.sql`, `cdm_waveform_registry.sql`, `cdm_waveform_channel_metadata.sql` with `python scripts/run_workflow.py -e conf/<env>.etlconf -c conf/workflow_waveforms.conf`

NOTE: the standard process for combining Athena and custom vocab (_delta talbes) going forward

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

• _delta talbes → _delta tables
• BQ VIEW → preferably BigQuery view

the ETL relies on custom Waveform vocabulary concepts, but the README does not identify:
• the required CVB vocabulary package (link can be added)
• the expected vocabulary version from Athena (Feb 2026)
• the required custom concept IDs (those which are hardcoded)
• a preflight check confirming that those concepts exist and are valid.
Please add a reproducible vocabulary dependency statement and validation query for all hard-coded custom concepts used by this PR.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README now documents the expected waveform vocabulary inputs, lists the hardcoded waveform concept dependencies used by the ETL, and notes that those dependencies are validated by waveform QA.

Comment thread conf/workflow_ddl.conf
{"script": "etl/ddl/ddl_voc_5_4_2.sql", "comment": ""},
{"script": "etl/ddl/ddl_cdm_5_4_2.sql", "comment": ""}
{"script": "etl/ddl/ddl_voc_5_4_2.sql", "comment": ""},
{"script": "etl/ddl/ddl_cdm_5_4_2.sql", "comment": ""},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding ddl_cdm_waveform_extension.sql to the DDL workflow is appropriate. However, because the individual ETL scripts recreate the same tables, the schema currently has two separate definitions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The waveform extension tables are now defined only in the central DDL workflow, and the waveform ETL scripts populate those existing tables via full-refresh loads.

Comment thread conf/workflow_waveforms.conf Outdated
[
{"script": "etl/etl/cdm_waveform_occurrence.sql", "comment": ""},
{"script": "etl/etl/cdm_waveform_registry.sql", "comment": ""},
{"script": "etl/etl/cdm_waveform_channel_metadata.sql", "comment": ""}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a waveform-specific validation script or workflow step.
At minimum, it should test:
• primary-key uniqueness
• orphan registry records
• orphan channel metadata records
• person and visit consistency
• timestamp validity
• registry timestamps outside occurrence timestamps
• unresolved mandatory concepts
• duplicate target file URIs
• file-count consistency
• duplicate channel metadata at the intended natural grain.

Also, there is minor formatting issue - indent the script entries consistently with the rest of the JSON configuration.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a dedicated workflow_waveforms_qa.conf for blocking waveform validation, cleaned up the workflow formatting/indentation, and updated waveform workflows to run as complete BigQuery scripts (type: "sql_script") so the new DECLARE / ASSERT / temp-table QA logic executes correctly.

FROM @etl_project.@etl_dataset.voc_concept
WHERE vocabulary_id IN ('WAVEFORM', 'MIMIC4')
AND domain_id IN ('Waveform Metadata', 'Measurement', 'Observation')
QUALIFY ROW_NUMBER() OVER (PARTITION BY concept_code ORDER BY concept_id) = 1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The numerically lowest concept ID has no semantic priority. This can silently select an incorrect target when multiple candidate concepts share a code, name, or synonym. Please:
• require a unique valid mapping
• report ambiguous matches
• resolve them through an explicit curated mapping rule

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@p-talapova , I'm a bit stuck regarding how to resolve this issue. I agree this is not a good production rule. Selecting the numerically lowest concept_id is arbitrary and I don’t want to hard-code that behavior here. This seems to overlap with a broader upstream vocabulary-governance issue that is already being discussed in TuftsCTSI/CVB#27. My main question is what the intended production policy should be when multiple eligible concepts are present across the custom waveform/MIMIC vocabularies and Athena. For example, should the ETL prefer exact custom concept_code matches only, fail on multiple candidates, or follow some other reviewed precedence rule? Once that policy is clarified, I can align the ETL logic to it.

-- Extracts abbreviation from synonyms like "ABP - Arterial blood pressure" by matching before the " - "
LEFT JOIN
(SELECT DISTINCT
UPPER(TRIM(SPLIT(syn.concept_synonym_name, ' - ')[OFFSET(0)])) AS parsed_value,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current logic extracts the text before " - " from every synonym and treats it as a channel abbreviation.
This assumes that every synonym formatted as" BBREVIATION - description" defines a globally safe abbreviation. That is not guaranteed and may create collisions across unrelated concepts.
Please remove this heuristic from automatic production mapping or constrain it to a reviewed allow-list.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the parsed synonym-prefix heuristic from automatic production channel mapping.

WHERE vocabulary_id IN ('WAVEFORM', 'MIMIC4', 'UCUM', 'SNOMED')
QUALIFY ROW_NUMBER() OVER (PARTITION BY UPPER(concept_code) ORDER BY concept_id) = 1
) vc_unit_code
ON vc_unit_code.concept_code = UPPER(meta.unit_source_value)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restrict normal unit mapping to standard Unit-domain concepts

WHERE domain_id = 'Unit'
AND standard_concept = 'S'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also consider preserving the unmodified source value in unit_source_value

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unit mapping is now restricted to valid standard Unit-domain concepts, preserves the original source value in unit_source_value, and keeps unit-code matching case-sensitive to avoid false collisions such as mV versus MV.

(SELECT DISTINCT concept_id, UPPER(concept_code) AS concept_code
FROM @etl_project.@etl_dataset.voc_concept
WHERE vocabulary_id IN ('WAVEFORM', 'MIMIC4', 'UCUM', 'SNOMED')
QUALIFY ROW_NUMBER() OVER (PARTITION BY UPPER(concept_code) ORDER BY concept_id) = 1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If multiple valid unit concepts match one normalized source value, the mapping should be treated as ambiguous and escalated rather than resolved by concept ID order.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ambiguous unit matches now fail the build instead of being resolved by concept_id ordering.

)
;

INSERT INTO @etl_project.@etl_dataset.cdm_waveform_channel_metadata

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unpivoted metadata retains person_id and visit_occurrence_id, but these values are not used in the final query. After joining to the registry, validate that metadata staging person_id = registry person_id
and metadata staging visit_occurrence_id = registry visit_occurrence_id

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unpivot retains person/visit only for QA. Added a preflight that validates meta.person_id and meta.visit_occurrence_id equal the occurrence values reached via registry. Any mismatch fails the build.

@briangow

briangow commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

Thank you for the detailed review. I addressed the waveform comments across a series of focused commits and will reply inline where relevant. Two higher-level notes that are not tied to a single line:

  1. I updated the waveform workflow to run complete BigQuery scripts (type: "sql_script") so the waveform ETL/QA can use DECLARE, ASSERT, and temp-table scripting safely rather than splitting files into individual statements.
  2. The remaining blockers are vocabulary gaps rather than ETL code failures. I verified that the waveform build succeeds once unresolved required concept dependencies are temporarily bypassed for smoke testing, and the outstanding mapping work is tracked in #26 (metadata concepts), CVB #31 (channel concepts), and CVB #32 (unit concepts).

Here is a summary of updates related to the major and minor points raised:

Major

  1. WAVEFORM_OCCURRENCE uses ANY_VALUE() for person, visit, and timestamp fields, which can hide inconsistent source data and produce nondeterministic results.

Updated in commits 0c0ddb4 and b7dcba8. I replaced ANY_VALUE() in cdm_waveform_occurrence with deterministic aggregation (MIN/MAX) after adding blocking preflight validation that each group_id resolves to a single person, visit, visit detail, and session interval. I also added blocking validation/QA for invalid occurrence intervals.

  1. preceding_waveform_occurrence_id uses 0 instead of NULL.

Updated in commit 0c0ddb4. I changed preceding_waveform_occurrence_id to CAST(NULL AS INT64) so missing predecessor information no longer creates an invalid foreign-key-like reference.

  1. num_of_files is calculated from staging rows rather than from the generated registry records.

Updated in commits e1cf63a and b7dcba8. num_of_files is now derived from the populated cdm_waveform_registry output rather than from raw staging rows, and a blocking QA check now verifies that waveform_occurrence.num_of_files matches the linked registry-file count.

  1. The numerics logic appears to create two WAVEFORM_REGISTRY records for one transformed CSV target.

Updated in commits e1cf63a and b7dcba8. I removed the prior numerics-specific duplicate-row behavior and now create one registry row per canonical target file. I also added blocking QA for duplicate waveform_registry_id values, duplicate waveform_target_file_uri values, and occurrence/registry file-count consistency.

  1. Some source and target URIs are reconstructed rather than taken from the authoritative staging values.

Updated in commit e1cf63a. cdm_waveform_registry now uses the authoritative staging src_file / trg_file values directly rather than reconstructing URIs from path assumptions, and waveform_registry_id is derived from the canonical target URI represented by the row.

  1. Registry person and visit fields are independently copied from staging instead of inherited from WAVEFORM_OCCURRENCE.

Updated in commits 609e657 and b7dcba8. cdm_waveform_registry now inherits person_id, visit_occurrence_id, and visit_detail_id from the linked cdm_waveform_occurrence row rather than copying them independently from staging. I also added blocking validation/QA requiring registry rows to resolve to a parent occurrence and to remain temporally compatible with that parent occurrence.

  1. WAVEFORM_CHANNEL_METADATA independently regenerates the registry foreign key instead of joining to the populated registry.

Updated in commits 609e657 and b7dcba8. cdm_waveform_channel_metadata now resolves waveform_registry_id by joining the populated registry on waveform_target_file_uri = trg_file instead of regenerating the foreign key independently. Blocking validation/QA now checks for missing/duplicate registry resolution and orphan channel metadata rows.

  1. Channel metadata identifiers do not include a channel index and may collide for duplicate channel labels.

Updated in commits 33ca3a2 and b7dcba8. I added channel_index to the staging/ETL contract and now build waveform_channel_metadata_id from waveform_registry_id + channel_index + metadata_type using an unambiguous hashed structure. Blocking validation/QA now checks both metadata-ID uniqueness and duplicate channel metadata at the intended natural grain.

  1. Required channel and metadata concepts silently default to concept ID 0.

Updated in commits c92579d, b7dcba8, and 30748b4. I removed the silent production fallback to concept ID 0 for required channel_concept_id / metadata_concept_id assignment. In the intended production logic, unresolved channel or metadata mappings should fail the load. The remaining vocabulary gaps are tracked separately in CVB #26, #31 and #32.

  1. Channel mapping relies on broad name and synonym matching and resolves ambiguity by selecting the lowest concept ID.

Updated in commit 5f58004. Channel mapping no longer selects the lowest concept_id. It now generates exact code/name/full-synonym candidates, applies explicit WAVEFORM → MIMIC4 → Athena precedence, removes the parsed synonym-prefix heuristic, and blocks ambiguous selected-tier mappings rather than silently resolving them.

  1. Unit mappings are not restricted to valid standard Unit-domain concepts.

Updated in commits c3ec93c and 70d90e2. Unit mapping is now restricted to valid standard Unit-domain concepts (domain_id = 'Unit', standard_concept = 'S', invalid_reason IS NULL), preserves the source unit string in unit_source_value, treats ambiguous unit matches as blocking failures, and keeps unit-code matching case-sensitive to avoid false collisions such as mV versus MV.

  1. No blocking QA is included for duplicate IDs, orphan foreign keys, inconsistent timestamps, or unresolved mandatory mappings (added test/qa/qa_wf_extension.sql as a draft)

Updated in commits b7dcba8, fca5992, and 99502e5. Converted the waveform QA draft into a blocking ASSERT-based BigQuery script covering PK uniqueness, orphan foreign keys, timestamp validity, registry/occurrence consistency, duplicate target file URIs, file-count consistency, invalid unit concepts, and duplicate channel metadata at the intended natural grain. I also added a dedicated waveform QA workflow config and a separate waveform_feature QA script for the requested feature PK/FK checks. Checks tied to currently unresolved required channel/metadata concept dependencies remain temporarily disabled pending CVB #31 and CVB #26.

Minor

  1. The README contains incorrect file paths, and an incomplete staging-data contract.

Updated in commit 81d03a2. I corrected the README waveform paths and expanded the waveform staging/source-schema documentation, including expected identifiers, required/optional fields, timestamp interpretation (MIMIC date-shifted local clinical time, not UTC), vocabulary dependencies, hardcoded concept dependencies, and availability of channel_index.

  1. DDL definitions are duplicated in both the central DDL file and individual ETL scripts.

Updated in commits 81d03a2 and c9f7871. I centralized waveform table definitions in etl/ddl/ddl_cdm_waveform_extension.sql, removed duplicate table definitions from the occurrence/registry/channel ETL scripts, converted those ETL scripts to a full-refresh TRUNCATE TABLE + INSERT INTO pattern, and cleaned up the remaining minor file-formatting issue.

  1. Several vocabulary joins do not filter non-standard concepts or invalid relationships.

Updated in commits e1cf63a, 5f58004, and c3ec93c. I tightened the registry/channel/unit vocabulary joins so extension relationships exclude invalid mappings, channel candidates require valid standard concepts, and unit candidates require valid standard Unit-domain concepts.

  1. Some metadata records are created even when no metadata value or unit is available.

Updated in commit c92579d. I added branch-specific filters so channel metadata rows are only created when the relevant source metadata is present (sample_units, sample_rate, gain, or segment_length as applicable).

  1. Workflow formatting is a bit inconsistent

Updated in commits c9f7871, fca5992, and f5a1a25. I cleaned up workflow formatting/indentation, added the dedicated waveform QA workflow, updated waveform workflow execution to support sql_script BigQuery scripting, and removed the old waveform workflow path that was no longer needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants