Skip to content

an association scan that mostly refuses to say anything - #50

Merged
abdulsaheel merged 2 commits into
mainfrom
feat/correlation-engine
Aug 20, 2026
Merged

an association scan that mostly refuses to say anything#50
abdulsaheel merged 2 commits into
mainfrom
feat/correlation-engine

Conversation

@abdulsaheel

@abdulsaheel abdulsaheel commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Re-raise of #48 against main — it was merged into its stacked base branch by mistake, so main never got it. Same commits, already reviewed and resolved there.

Engine + tests only, no UI. The number that decided the design: on 200 synthetic histories of pure AR(1) noise, a day-wise shuffle publishes at least one false finding in 69% of histories at φ=0.6 and 98% at φ=0.8; 14-day moving blocks hold it at ~12% across the range. Both rows are in the suite as a live contrast.

Also: BH over the whole grid, lag declared per variable rather than scanned, weekday-median adjustment with the raw rho kept for disclosure, tautologies refused structurally, redundancy clustered at |rho| >= 0.7, and a discreteness guard that says so when no test could have published at any effect size.

Power is low and that is the honest answer, not a tuning failure — at 84 days only ~72 questions can reach significance at all, so the UI has to treat "nothing to say" as the normal state.

Summary by CodeRabbit

  • New Features
    • Added personal health association analysis across daily variables such as sleep, strain, steps, alcohol, and recovery.
    • Reports lagged relationships, effect strength, significance, coverage, confidence indicators, and explanatory caveats.
    • Supports safeguards for sparse, constant, conflicting, redundant, or insufficient data.
    • Added standardized health metric catalog access and JSON-exportable scan results.
  • Tests
    • Added comprehensive coverage for statistical accuracy, data validation, determinism, filtering, and result serialization.

correlates day-level series against each other on device. the whole thing is
built around not inventing findings:

- moving-block permutation for the null. days are autocorrelated and a plain
  shuffle destroys exactly the structure that caused the spurious correlation,
  so it calls it significant. measured on pure noise at phi 0.6, day-wise
  shuffling published something in 69% of histories, 14-day blocks in 11%.
  at phi 0.8 it's 98% vs 12%. that's the whole reason for the block length.
- benjamini-hochberg over the entire grid, and nothing is screened on effect
  size before the correction runs.
- lag is derived per pair from when each variable actually happened, so
  today's strain lands on tonight's sleep and nothing runs backwards. same-day
  pairs are simultaneous, not directional, so they're refused.
- weekday is removed from both series before testing. "late meals hurt my
  recovery" is usually saturday.
- readiness is never explained by hrv/rhr/resp/temp. it IS them. a variable
  declares what it's made of and those pairs are refused.
- sleep duration, longest sleep and efficiency collapse to one finding instead
  of three.
- under 12 weeks it says how many nights it needs. if the grid is wider than
  the history could ever answer, it says that too rather than returning an
  empty list and looking like nothing's happening.
- imported days are erased, not blended.

~15 ms for 6 variables over 90 days, 80 ms for 14 over a year.

the journal path (journalCorrelations / journalNumericCorrelations) is
untouched, this doesn't duplicate it.
review on #48, and it's right that the comments and the reason strings are
callable surface rather than decoration. several of them described an earlier
version of this.

- blockLen doc said 7, ships 14. the table on associationMinPairedDays is
  where the 14 came from, so point at it.
- associationLag can't return null and never could, so backwards_in_time was
  dead and simultaneous/not_an_input/misaligned_series were documented but
  never emitted. dropped the nullable return and the dead guard, and wrote out
  the reason list as exactly what comes out. the same-night refusal is real,
  it just lives in the +1 alignment rather than in a reason string — said so
  where the +1 happens.
- two variables with the same key shared one grid slot and the loser's label
  could get published against the winner's series. same for two rows on one
  calendar day. abstain, like a misaligned series does.
- coverage was checked after the count, which needs a 168-day window before it
  can bind, so every rarely-logged field came back need_pairs. "log this more
  often" and "wait 74 nights" are different instructions and only one of them
  is true for a field logged one day in twelve. rate first.
- short_history used a literal 84 next to a constant that is 84.
- tests for no_contrast, the variable-level constant refusal, and
  redundant_with in the json, which is the shape the edge will actually read.
@abdulsaheel
abdulsaheel merged commit 458af60 into main Aug 20, 2026
5 checks passed
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 515c0831-df08-42a0-ae05-74b2aa5fbc7c

📥 Commits

Reviewing files that changed from the base of the PR and between 652f7a4 and 795c429.

📒 Files selected for processing (3)
  • lib/src/onehz/human/associations.dart
  • lib/src/onehz/human/human.dart
  • test/onehz/associations_test.dart

📝 Walkthrough

Walkthrough

Changes

Association scan

Layer / File(s) Summary
Public contracts and variable catalog
lib/src/onehz/human/associations.dart, lib/src/onehz/human/human.dart
Adds association models, scan constants, catalog metadata, standard variable lookup, JSON serialization, and barrel export wiring.
Scan execution and statistical processing
lib/src/onehz/human/associations.dart
Adds calendar alignment, timing-based lagging, weekday adjustment, Spearman correlation, block permutation testing, contrast evaluation, FDR filtering, refusal handling, and redundancy collapse.
Behavior and contract validation
test/onehz/associations_test.dart
Adds deterministic tests for statistical behavior, lag direction, caveats, refusals, catalog handling, serialization, determinism, and malformed inputs.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant scanAssociations
  participant StatisticalHelpers
  participant AssociationScan
  Caller->>scanAssociations: provide dates and daily variables
  scanAssociations->>StatisticalHelpers: adjust, rank, lag, and test paired series
  StatisticalHelpers-->>scanAssociations: correlations, p-values, and contrasts
  scanAssociations->>AssociationScan: apply FDR and redundancy rules
  AssociationScan-->>Caller: return findings, tested pairs, and refusals
Loading

Possibly related PRs


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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