From 8a18c894dd5d49bbc96be27e08b0ea1dc5fd6940 Mon Sep 17 00:00:00 2001 From: Experiments DB Dev Date: Wed, 22 Jul 2026 15:45:19 -0400 Subject: [PATCH] feat(matlab): add Satterthwaite DF + honest random-slope test to LME reports Every fitlme-based report (lme_*, paper_*, phase_*, and the variations' analyze.m) now shows, per effect: residual-DF p, Satterthwaite-DF p, and -- for the interaction -- an HONEST test from a per-animal random-SLOPE model (day|rat), whose Satterthwaite DF collapses toward the animal count. New: tdcs_random_slope_interaction.m (shared helper). Wired into tdcs_lme, tdcs_paper_lme, tdcs_phase_lme, variation_analyze; SUMMARY.csv gains interaction_p_satt / interaction_p_rs. Regenerated all results/, variations/, matched-effort outputs. Key point this surfaces: Satterthwaite ~= residual on the random-INTERCEPT model (the slope's error is at session level), so it does NOT fix pseudoreplication; the random-slope model does. Effect: full-range mergeA2 interaction 0.009 -> 0.75 (collapses); unmerge_d0_5 0.015 -> 0.13 (n.s.); the pooled-control early windows survive honestly (naive_a2_d0_5 0.001 -> 0.028; naive_boxa_d0_5 0.003 -> 0.036). Suite 42/42. Co-Authored-By: Claude Opus 4.8 --- BACKUP.md | 75 ++++ N8N_WORKFLOWS.md | 293 +++++++++++++++ analysis/matlab/make_variations.m | 7 +- analysis/matlab/results/lme_mergeA2_d0_10.txt | 16 +- analysis/matlab/results/lme_mergeA2_d0_13.txt | 16 +- analysis/matlab/results/lme_mergeA2_full.txt | 16 +- analysis/matlab/results/lme_mergeB2_d0_10.txt | 16 +- analysis/matlab/results/lme_mergeB2_d0_13.txt | 16 +- analysis/matlab/results/lme_mergeB2_full.txt | 16 +- .../matlab/results/lme_unmerged_d0_10.txt | 16 +- .../matlab/results/lme_unmerged_d0_13.txt | 16 +- analysis/matlab/results/lme_unmerged_full.txt | 16 +- analysis/matlab/results/paper_mergeA2.txt | 15 +- analysis/matlab/results/paper_mergeB2.txt | 22 +- analysis/matlab/results/paper_mergeNaive.txt | 22 +- .../matlab/results/paper_mergeNaive_d0_10.txt | 15 +- .../matlab/results/paper_mergeNaive_d0_13.txt | 15 +- analysis/matlab/results/paper_unmerged.txt | 24 +- analysis/matlab/results/phase_mergeA2.txt | 18 +- analysis/matlab/results/phase_mergeB2.txt | 18 +- analysis/matlab/results/phase_mergeNaive.txt | 18 +- analysis/matlab/results/phase_unmerged.txt | 18 +- analysis/matlab/tdcs_lme.m | 20 +- analysis/matlab/tdcs_lme_report.m | 24 +- analysis/matlab/tdcs_paper_lme.m | 38 +- analysis/matlab/tdcs_phase_lme.m | 22 +- .../matlab/tdcs_random_slope_interaction.m | 33 ++ analysis/matlab/tests/tLme.m | 21 ++ analysis/matlab/variation_analyze.m | 30 +- analysis/matlab/variations/SUMMARY.csv | 42 +-- .../variations/matched_current_d0_3/analyze.m | 30 +- .../matched_current_d0_3/result.txt | 13 +- .../variations/naive_a2_d0_10/analyze.m | 30 +- .../variations/naive_a2_d0_10/result.txt | 13 +- .../variations/naive_a2_d0_13/analyze.m | 30 +- .../variations/naive_a2_d0_13/result.txt | 13 +- .../matlab/variations/naive_a2_d0_5/analyze.m | 32 +- .../variations/naive_a2_d0_5/result.txt | 38 +- .../variations/naive_a2_d6_10/analyze.m | 30 +- .../variations/naive_a2_d6_10/result.txt | 13 +- .../variations/naive_a2_d6_13/analyze.m | 30 +- .../variations/naive_a2_d6_13/result.txt | 13 +- .../variations/naive_boxa_d0_10/analyze.m | 30 +- .../variations/naive_boxa_d0_10/result.txt | 13 +- .../variations/naive_boxa_d0_13/analyze.m | 30 +- .../variations/naive_boxa_d0_13/result.txt | 13 +- .../variations/naive_boxa_d0_5/analyze.m | 30 +- .../variations/naive_boxa_d0_5/result.txt | 13 +- .../variations/naive_boxa_d6_10/analyze.m | 30 +- .../variations/naive_boxa_d6_10/result.txt | 13 +- .../variations/naive_boxa_d6_13/analyze.m | 30 +- .../variations/naive_boxa_d6_13/result.txt | 13 +- .../matlab/variations/prev_f_full/analyze.m | 30 +- .../matlab/variations/prev_f_full/result.txt | 13 +- .../variations/right_only_d0_10/analyze.m | 30 +- .../variations/right_only_d0_10/result.txt | 13 +- .../variations/right_only_d0_13/analyze.m | 30 +- .../variations/right_only_d0_13/result.txt | 13 +- .../variations/right_only_d0_5/analyze.m | 30 +- .../variations/right_only_d0_5/result.txt | 13 +- .../variations/right_only_d6_10/analyze.m | 30 +- .../variations/right_only_d6_10/result.txt | 13 +- .../variations/right_only_d6_13/analyze.m | 30 +- .../variations/right_only_d6_13/result.txt | 13 +- .../matlab/variations/unmerge_d0_10/analyze.m | 30 +- .../variations/unmerge_d0_10/result.txt | 13 +- .../matlab/variations/unmerge_d0_13/analyze.m | 30 +- .../variations/unmerge_d0_13/result.txt | 13 +- .../matlab/variations/unmerge_d0_5/analyze.m | 30 +- .../matlab/variations/unmerge_d0_5/result.txt | 13 +- .../matlab/variations/unmerge_d6_10/analyze.m | 30 +- .../variations/unmerge_d6_10/result.txt | 13 +- .../matlab/variations/unmerge_d6_13/analyze.m | 30 +- .../variations/unmerge_d6_13/result.txt | 13 +- n8n_create_workflows.py | 345 ++++++++++++++++++ scripts/backup.sh | 130 +++++++ scripts/setup_cron.sh | 29 ++ 77 files changed, 2066 insertions(+), 345 deletions(-) create mode 100644 BACKUP.md create mode 100644 N8N_WORKFLOWS.md create mode 100644 analysis/matlab/tdcs_random_slope_interaction.m create mode 100644 n8n_create_workflows.py create mode 100755 scripts/backup.sh create mode 100755 scripts/setup_cron.sh diff --git a/BACKUP.md b/BACKUP.md new file mode 100644 index 0000000..57076a4 --- /dev/null +++ b/BACKUP.md @@ -0,0 +1,75 @@ +# Experiments Database — Backup + +## Location +``` +/home/sam/synology/Backups/Experiments-DB-Backup/ +├── daily/ ← up to 5 change-triggered daily backups +├── weekly/ ← up to 2 unconditional weekly backups +├── .last_backup_state ← DB fingerprint from last backup run +└── backup.log ← all run output +``` + +## Scripts +``` +scripts/ +├── backup.sh ← main backup script +└── setup_cron.sh ← installs / updates cron entries (idempotent) +``` + +## Schedule +| Cron | Mode | Behaviour | +|------|------|-----------| +| `0 2 * * *` (daily 02:00) | `daily` | Compares DB fingerprint; skips if nothing changed | +| `0 3 * * 0` (Sunday 03:00) | `weekly` | Always dumps; ignores fingerprint | + +To re-install cron entries after a path change: +```bash +./scripts/setup_cron.sh +``` + +## Backup Format +Files are `pg_dump --format=custom --compress=9` (`.pgdump`). + +**Restore a backup:** +```bash +# Restore into a running container +docker exec -i experiments_postgres pg_restore \ + -U expuser -d experiments_db --clean \ + < /home/sam/synology/Backups/Experiments-DB-Backup/daily/.pgdump + +# Or restore to a fresh database +docker exec -i experiments_postgres createdb -U expuser experiments_db_restore +docker exec -i experiments_postgres pg_restore \ + -U expuser -d experiments_db_restore \ + < /path/to/file.pgdump +``` + +## Change Detection +The daily run fingerprints the database as: +``` +,,, +,, +``` +Any insert, update, or delete on any table shifts this string and triggers a backup. + +## Retention Policy +| Type | Keep | +|------|------| +| Daily | 5 most recent | +| Weekly | 2 most recent | + +Older files are automatically deleted after each successful dump. + +## Manual Run +```bash +# Force a backup right now (ignores change detection) +./scripts/backup.sh weekly + +# Run change-detect check manually +./scripts/backup.sh daily +``` + +## Verify Cron Is Installed +```bash +crontab -l | grep ExpDB +``` diff --git a/N8N_WORKFLOWS.md b/N8N_WORKFLOWS.md new file mode 100644 index 0000000..e192824 --- /dev/null +++ b/N8N_WORKFLOWS.md @@ -0,0 +1,293 @@ +# Experiments Database — n8n Workflows + +n8n is running at **http://localhost:5678** + +The Postgres credential **"Experiments DB (PostgreSQL)"** (id: `9iJuyA9iR5KUzmj5`) connects to `experiments_postgres:5432 / experiments_db` via the shared `llm-net` Docker network. + +--- + +## Workflow Index + +| ID | Workflow | Entity | +|----|----------|--------| +| `jjmtecjuHJPKZ4T7` | ExpDB · Experiments | `experiments` table | +| `HYnlIscuKwMW7blG` | ExpDB · Animals | `animals` table | +| `9emayzMpnhIZQxqd` | ExpDB · Daily Statuses | `daily_statuses` table | +| `hso5z2W1uO44bTP6` | ExpDB · Daily Analyses | `daily_analyses` table | +| `2s02OX1yibfqp6jK` | ExpDB · Session Files | `session_files` table | +| `T76NAYiFcCxHDKQB` | ExpDB · Audit Logs | `audit_logs` table | +| `lq3R3YqeHgxixrbZ` | ExpDB · Reports | cross-table queries | + +--- + +## How to Call a Workflow + +All workflows use an **Execute Workflow Trigger** — call them with an **Execute Workflow** node from any parent workflow. Pass a JSON object with `action` + the required fields. + +``` +Execute Workflow node + → Workflow: