Skip to content

feat: add effect_size and effect_type edge attributes (Biolink PR #1774) - #69

Merged
SkyeAv merged 3 commits into
mainfrom
tablassert-effect-size-type
Aug 7, 2026
Merged

feat: add effect_size and effect_type edge attributes (Biolink PR #1774)#69
SkyeAv merged 3 commits into
mainfrom
tablassert-effect-size-type

Conversation

@SkyeAv

@SkyeAv SkyeAv commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Adds support for the new Biolink effect size / effect type association slots (biolink/biolink-model#1774) across the clean pipeline and final edges, using the same rapidfuzz coercion tactics as p_value / supporting_study_size. The pinned biolink-model 4.4.3 predates the PR, so the enum is defined locally until a release ships it.

Column coercion (src/tablassert/coerce.py)

  • coerce_effect_size_columns: renames effect-size-like columns (effect size, ES, beta, log2FC, odds ratio, hazard ratio, correlation/rho-style statistics, and the old relationship_strength) to canonical effect_size, picking the single best rapidfuzz candidate — matching the coerce_study_size_columns pattern.
  • coerce_effect_type_columns: renames effect-type-like columns to effect_type, then coerces VALUES into the 25 permissible EffectTypeEnum values via a case/separator-insensitive 37-entry alias table + rapidfuzz fallback (>= 80); unmatched values become null (Biolink range is the enum).
  • Class rule: per #1774, effect type may only be populated when effect size is — effect_type is nulled where effect_size is missing or non-numeric, documented the way sig() documents its rule.

Vocabulary + final edges (src/tablassert/biolink.py, src/tablassert/lib.py)

  • EFFECT_TYPE_VALUES / EffectTypes: the 25 values from the #1774 diff verbatim (mappings intentionally omitted), built with _build_str_enum in the KnowledgeLevels pattern; a comment marks the switch to _biolink_enum_values(_bm.EffectTypeEnum) once biolink-model ships it.
  • Final edges: effect_size / effect_type join TABLASERT_EDGE_EXTRAS so they survive fold_unknown_to_supporting_text as top-level edge fields; superseded relationship_strength is removed from the extras and instead coerced to effect_size.
  • Wiring: both coercions run in _source_ops after coerce_study_size_columns and before clean_numeric; numeric_columns exact set is now {"effect_size", "supporting_study_size"} — the old names sample_size / relationship_strength are replaced everywhere they appeared in the final-edges path.

Docs + agent prompts

  • Final-edges examples: docs/configuration/advanced-example.md, docs/examples.md, docs/tutorial.md, docs/configuration/table.md, and examples/tutorial-table.yaml now use the new names (JSON examples use {:.4g}-accurate values).
  • Agent: src/tablassert/agent.py INSTRUCTIONS and examples/agent/optimized_instructions.yaml steer p_value / supporting_study_size / effect_size + effect_type.

Design

  • Local enum: #1774 is merged but unreleased; 4.4.3 has neither the slots nor the enum, so both are defined locally. When biolink ships them, _association_model_fields() picks the slots up automatically and the extras stay harmless duplicates.
  • Backward compatibility: legacy configs annotating relationship_strength / sample_size still work — coercion renames at build time before numeric cleaning (the ALAMV6 agent fixture deliberately keeps the old names as the end-to-end legacy case).
  • Accepted caveats: bare-token rho / correlation effect-size candidates mirror the documented p-value/study-size heuristic (they can catch an unrelated header only when it is the sole candidate); the shared duplicate-name-when-canonical-exists behavior of the existing coercions is preserved as-is. Deferred: further value aliases (R^2, bare Egger) — unmatched values null safely.

Testing

  • uv run ruff check . — All checks passed.
  • uv run ruff format --check . — 67 files already formatted.
  • uv run pyright — 0 errors.
  • uv run pytest -q717 passed, 34 skipped (identical skip set to main); +28 new tests (rename / best-fuzzy-pick / no-ops, alias + fuzzy + unmatched value coercion, class-rule nulling both branches, fold survival, tcode ordering, enum drift guards). Independent CODE_REVIEWER pass: no Blockers; all Should-fixes applied.

Questions for the reviewer

  • logFC alias. limma/edgeR logFC maps to log2_fold_change (base-2 by convention) — keep, or drop until a real ingest needs it?

Summary by CodeRabbit

  • New Features

    • Added standardized effect_size, effect_type, and supporting_study_size annotations.
    • Added recognized effect types, including Spearman’s rho and odds ratio.
    • Automatically maps annotation aliases and variations to canonical fields.
  • Documentation

    • Updated configuration examples, tutorials, and guidance with the new statistical annotation names.
  • Bug Fixes

    • Improved handling of fuzzy effect-type values, missing data, and legacy annotation names.

SkyeAv added 2 commits August 7, 2026 14:06
Mirror the p-value/study-size coercion architecture for the merged-but-unreleased
PR #1774 edge attributes (absent from pinned biolink-model 4.4.3, defined locally):

- coerce.py: effect_size_target / coerce_effect_size_columns rename effect-size-like
  columns (effect size, ES, beta, log2FC, odds/hazard/risk ratio, correlation/rho/r-style
  statistic names, and the OLD relationship_strength name) to canonical effect_size.
  effect_type_target / coerce_effect_type_columns rename effect-type-like columns, then
  coerce VALUES into the 25 permissible enum values via a case/separator-insensitive
  alias table + rapidfuzz fuzzy fallback; values matching nothing drop to null (biolink
  range is the enum). Biolink class rule applied post-coercion: effect_type is nulled
  wherever effect_size is null/absent.
- biolink.py: EFFECT_TYPE_VALUES (verbatim PR diff, close_mappings ignored) + EffectTypes
  str-enum via _build_str_enum with the KnowledgeLevels-style TYPE_CHECKING stub; add
  effect_size / effect_type to TABLASERT_EDGE_EXTRAS so they survive
  fold_unknown_to_supporting_text and reach final edges; drop the now-superseded
  relationship_strength from extras (consistent with sample_size fold behavior).
- lib.py: both coercions wired into _source_ops after coerce_study_size_columns and
  before clean_numeric; PHASE_OF "clean"; numeric_columns exact set gains effect_size
  and drops the superseded sample_size / relationship_strength (coercion renames them
  before clean_numeric/format_numeric run).
- docs + agent prompts: old annotation names moved to
  supporting_study_size / effect_size / effect_type in advanced-example.md, examples.md,
  tutorial.md, table.md, tutorial-table.yaml, agent.py INSTRUCTIONS, and
  optimized_instructions.yaml.
- tests: +28 covering rename/best-fuzzy-pick/no-op/value-coercion/class-rule/folding and
  alias drift guards; existing old-name final-edge assertions moved to the new names
  (never weakened). Fixture config TEXT keeps old annotation names (coercion renames at
  build time).

Verified: uv run ruff check . && uv run ruff format --check . && uv run pyright &&
uv run pytest -q — all green (717 passed, 34 skipped = main's skip set); coverage on
touched modules at parity or better (coerce.py/biolink.py 100%).
…C alias

- advanced-example.md edge JSON: use {:.4g}-accurate values ("9", "0.85")
- tcode ordering test also asserts study-size coercion precedes effect-size
- add limma/edgeR "logFC" alias for log2_fold_change value coercion
- clarify ALAMV6 fixture keeps old annotation names as legacy-compat case
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 28f57edb-121b-4004-9019-7c2c83cb1ccb

📥 Commits

Reviewing files that changed from the base of the PR and between 48407b0 and 22b6a29.

📒 Files selected for processing (4)
  • examples/agent/optimized_instructions.yaml
  • src/tablassert/agent.py
  • src/tablassert/coerce.py
  • tests/test_lib.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • examples/agent/optimized_instructions.yaml
  • src/tablassert/agent.py
  • tests/test_lib.py
  • src/tablassert/coerce.py

📝 Walkthrough

Walkthrough

The PR adds canonical statistical edge annotations, defines 25 Biolink effect types, coerces effect columns, integrates coercion into cleaning, updates tests, and migrates documentation and agent guidance from legacy annotation names.

Changes

Statistical edge annotations

Layer / File(s) Summary
Effect annotation contract
src/tablassert/biolink.py, tests/test_biolink.py
Defines and exports EffectTypes and EFFECT_TYPE_VALUES. Allows effect_size and effect_type edge fields and removes relationship_strength.
Effect column coercion
src/tablassert/coerce.py, tests/test_lib.py
Detects and canonicalizes effect columns. Maps aliases and fuzzy values to Biolink effect types. Nulls effect_type when no populated effect_size exists.
Cleaning pipeline integration
src/tablassert/lib.py, tests/test_lib.py
Applies effect coercion before numeric cleaning. Exposes the new helpers and validates ordering, formatting, and output behavior.
Annotation examples and guidance
docs/..., examples/agent/optimized_instructions.yaml, src/tablassert/agent.py, tests/test_agent_derive.py
Replaces legacy statistical annotation names with supporting_study_size, effect_size, and effect_type in examples and agent guidance.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SourcePipeline
  participant EffectCoercion
  participant NumericCleaning
  SourcePipeline->>EffectCoercion: coerce effect_size and effect_type
  EffectCoercion-->>SourcePipeline: return canonical effect columns
  SourcePipeline->>NumericCleaning: clean numeric columns
  NumericCleaning-->>SourcePipeline: return formatted output
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding Biolink effect_size and effect_type edge attributes.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tablassert-effect-size-type

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/agent/optimized_instructions.yaml`:
- Line 92: The effect_type guidance must encode both supported sources and its
dependency on a valid numeric effect_size. In
examples/agent/optimized_instructions.yaml at line 92, revise the prompt to
specify method: column for table-provided effect types and method: value for
fixed valid Biolink effect types, emitting effect_type only alongside a numeric
effect_size; in src/tablassert/agent.py at lines 1929-1930, update the
corresponding guidance so effect_type is not described only as a source column
and preserves the same contract.

In `@src/tablassert/coerce.py`:
- Around line 526-531: Update the column-selection logic in
src/tablassert/coerce.py#L526-L531 to return the existing effect_size column
without fuzzy ranking or renaming; only rank aliases when the canonical column
is absent. Apply the same change to effect_type at
src/tablassert/coerce.py#L669-L675. Add regression cases at
tests/test_lib.py#L1659-L1680 and tests/test_lib.py#L1747-L1752 covering both
canonical and spaced alias columns, verifying coercion succeeds and preserves
the canonical columns.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 94b532f6-52b5-4596-b614-eba71940c6f5

📥 Commits

Reviewing files that changed from the base of the PR and between f1bdea5 and 48407b0.

📒 Files selected for processing (13)
  • docs/configuration/advanced-example.md
  • docs/configuration/table.md
  • docs/examples.md
  • docs/examples/tutorial-table.yaml
  • docs/tutorial.md
  • examples/agent/optimized_instructions.yaml
  • src/tablassert/agent.py
  • src/tablassert/biolink.py
  • src/tablassert/coerce.py
  • src/tablassert/lib.py
  • tests/test_agent_derive.py
  • tests/test_biolink.py
  • tests/test_lib.py

Comment thread examples/agent/optimized_instructions.yaml Outdated
Comment thread src/tablassert/coerce.py
… contract

- all four column coercions keep an existing canonical column instead of
  fuzzy-picking a higher-scoring spaced alias onto it (polars DuplicateError)
- agent.py + optimized_instructions.yaml now encode the full effect_type
  contract: method: column OR method: value with a fixed valid Biolink
  effect type, emitted only alongside an effect_size annotation
- +4 regression tests (effect_size/effect size, effect_type/effect type,
  p_value/p value, supporting_study_size/supporting study size)
@SkyeAv
SkyeAv merged commit 6f8456d into main Aug 7, 2026
5 checks passed
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.

1 participant