Research Labs

2026-09-17 20:37 UTCopen field data · live

pages/wellness.php

Snapshot 2026.09.17-a2894de (current) · 94 lines · 12,407 bytes · tree · plain text

SHA-256 dc992921b27b6019b364fa856614dbc273d0f3a84ba8526616fc5a22de977f3e
Functions: wl_feed L8-L94
1<?php
2/* Districthive Research Labs: the wellness circuit programme. The outline of
3 every programme and the anonymous results, read from the AI operations
4 platform's public feed. Installed to research/pages/wellness.php by the AI
5 platform's deploy hook; source deploy/research/wellness.php in districthive/ai. */
6require_once is_file(__DIR__.'/layout.php') ? __DIR__.'/layout.php' : __DIR__.'/../inc/layout.php';
7
8function wl_feed(): array
9{
10 $cache = sys_get_temp_dir().'/dh-research-wellness.json';
11 if (is_file($cache) && filemtime($cache) > time() - 300) { $j = json_decode((string) file_get_contents($cache), true); if (is_array($j) && isset($j['programmes'])) { return $j; } }
12 $ctx = stream_context_create(['http' => ['timeout' => 5, 'header' => "User-Agent: DistricthiveResearchLabs/1.0\r\n"]]);
13 $raw = @file_get_contents('https://districthive.com/ai_discover/api/wellness.php', false, $ctx);
14 $j = $raw !== false ? json_decode($raw, true) : null;
15 if (is_array($j) && isset($j['programmes'])) { @file_put_contents($cache, $raw); return $j; }
16 if (is_file($cache)) { $j = json_decode((string) file_get_contents($cache), true); if (is_array($j)) { return $j; } }
17 return ['programmes' => [], 'summary' => [], 'per_programme' => [], 'per_circuit' => [], 'log' => [], 'change' => [], 'unavailable' => true];
18}
19$d = wl_feed();
20$kinds = ['sauna' => 'Heat', 'steam' => 'Steam', 'cold' => 'Cold air', 'breath' => 'Breath', 'meditation' => 'Stillness', 'light' => 'Light', 'sound' => 'Sound', 'movement' => 'Movement', 'rest' => 'Rest', 'nature' => 'Outside', 'salt' => 'Salt water', 'jacuzzi' => 'Warm water', 'aroma' => 'Aroma', 'tea' => 'Tea', 'silence' => 'Silence', 'sky' => 'Sky'];
21$s = $d['summary'] ?? [];
22
23page_header('Wellness programme', 'wellness');
24echo '<h1>The wellness circuit programme</h1>';
25echo '<p class="lede">The Outpost\'s stations as logged doses: heat, steam, cold air, salt water, light, aroma, breath, stillness, movement, silence and the sky, arranged into routes for a day. Guests follow a route in the retreat app step by step. Research consent is chosen in the app before the programme begins, defaults to none, and can be changed at any time; the stay is the same whatever is chosen. Below the questionnaires tier the app asks no questions and keeps the steps without any identifier. Everything below is anonymous: sessions are kept under codes, never names, and averages are published only for groups of at least '.(int) ($d['rules']['min_group'] ?? 5).' sessions. This is the primary strand of the doctoral programme; the routes shown here are definition '.h((string) ($d['definition_version'] ?? '')).' and every change to a step, duration or limit is a versioned research-design change.</p>';
26if (!empty($d['unavailable'])) { echo '<div class="alert">The programme feed could not be read just now; the last known state is shown.</div>'; }
27
28/* results */
29$tiers = $s['by_consent_tier'] ?? [];
30echo '<h2>Results so far</h2><div class="spstats">';
31echo '<div class="spstat"><b>'.(int) ($s['sessions'] ?? 0).'</b><span>sessions in the research</span></div><div class="spstat"><b>'.(int) ($s['participants'] ?? 0).'</b><span>coded participants</span></div>';
32echo '<div class="spstat"><b>'.(isset($s['share_done']) && $s['share_done'] !== null ? h((string) $s['share_done']).'%' : '·').'</b><span>of offered steps done</span></div>';
33echo '<div class="spstat"><b>'.(isset($s['prompt_mindful']) && $s['prompt_mindful'] !== null ? h((string) $s['prompt_mindful']).' · '.h((string) $s['prompt_restored']).' · '.h((string) $s['prompt_connected']) : '·').'</b><span>daily prompt: present · rested · connected, 0 to 10</span></div>';
34echo '<div class="spstat"><b>'.(isset($s['day_rating']) && $s['day_rating'] !== null ? h((string) $s['day_rating']) : '·').'</b><span>how the day felt, 0 to 10</span></div>';
35echo '<div class="spstat"><b>'.(isset($s['would_repeat_share']) && $s['would_repeat_share'] !== null ? h((string) $s['would_repeat_share']).'%' : '·').'</b><span>would repeat the route</span></div></div>';
36echo '<p class="note">Consent tiers chosen, by session: none '.(int) ($tiers['none'] ?? 0).' (never enters the research), telemetry '.(int) ($tiers['telemetry'] ?? 0).' (aggregates only), questionnaires '.(int) ($tiers['questionnaires'] ?? 0).', wearables and interviews '.(int) ($tiers['wearables'] ?? 0).'. A dot means the group is still below the minimum size.</p>';
37if (($s['sessions'] ?? 0) === 0) { echo '<p class="note">No sessions in the research yet: the programme opens with the retreat. The outline below is live now.</p>'; }
38
39/* arrival, departure, four weeks on (guarded: a cached feed may predate the 'change' block) */
40$ch = is_array($d['change'] ?? null) ? $d['change'] : [];
41$chItems = is_array($ch['items'] ?? null) ? $ch['items'] : [];
42$pr = is_array($ch['paired'] ?? null) ? $ch['paired'] : [];
43$fu = is_array($ch['followup'] ?? null) ? $ch['followup'] : [];
44$ft = is_array($ch['followup12'] ?? null) ? $ch['followup12'] : [];
45$dot = static fn ($v): string => $v === null || $v === '' ? '·' : h((string) $v);
46$signed = static fn ($v): string => $v === null || $v === '' ? '·' : h(((float) $v > 0 ? '+' : '').(string) $v);
47if ($chItems !== []) {
48 echo '<div class="card"><h3>Arrival, departure, four and twelve weeks on</h3><p class="kv">The same nine feeling scales, 0 to 10, answered in the app on arrival and on departure, and four and twelve weeks after the stay through private links sent by e-mail. Change is departure minus arrival; on the stress scale the lower figure is the calmer one. n is arrival · departure · four weeks · twelve weeks. A dot means the group is still below the minimum size.</p>';
49 echo '<table class="data"><thead><tr><th>item</th><th>arrival</th><th>departure</th><th>change</th><th>four weeks on</th><th>twelve weeks on</th><th>n</th></tr></thead><tbody>';
50 foreach ($chItems as $r) {
51 if (!is_array($r)) { continue; }
52 echo '<tr><td>'.h((string) ($r['question'] ?? $r['key'] ?? '')).(!empty($r['reverse']) ? ' <span class="kv">(lower is calmer)</span>' : '').'</td><td>'.$dot($r['arrival'] ?? null).'</td><td>'.$dot($r['departure'] ?? null).'</td><td>'.$signed($r['change'] ?? null).'</td><td>'.$dot($r['followup'] ?? null).'</td><td>'.$dot($r['followup12'] ?? null).'</td><td class="mono">'.(int) ($r['n_arrival'] ?? 0).' · '.(int) ($r['n_departure'] ?? 0).' · '.(int) ($r['n_followup'] ?? 0).' · '.(int) ($r['n_followup12'] ?? 0).'</td></tr>';
53 }
54 echo '</tbody></table>';
55 echo '<p class="note">Paired stays, both arrival and departure answered: '.(int) ($pr['n'] ?? 0).' · mean change across the nine items per stay, stress reversed: '.$signed($pr['mean_change'] ?? null).'</p>';
56 $labels = ['days' => 'a day or two', 'week' => 'about a week', 'weeks' => 'a few weeks', 'still' => 'it is still with me'];
57 if (is_array($fu['lasted_options'] ?? null) && $fu['lasted_options'] !== []) { $labels = $fu['lasted_options']; }
58 foreach ([['Four weeks after', $fu], ['Twelve weeks after', $ft]] as [$wl, $fw]) {
59 $lastedTxt = '·';
60 if (is_array($fw['lasted'] ?? null)) { $parts = []; foreach ($labels as $k => $label) { $parts[] = h((string) $label).' '.(int) ($fw['lasted'][$k] ?? 0); } $lastedTxt = implode(' · ', $parts); }
61 echo '<p class="note">'.h($wl).': follow-ups '.(int) ($fw['scheduled'] ?? $fw['due'] ?? 0).' scheduled · '.(int) ($fw['sent'] ?? 0).' sent · '.(int) ($fw['answered'] ?? 0).' answered · the stay in mind today '.$dot($fw['memorable'] ?? null).' of 10 (n '.(int) ($fw['n_memorable'] ?? 0).') · would come back '.(isset($fw['would_return_share']) ? h((string) $fw['would_return_share']).'%' : '·').' (n '.(int) ($fw['n_return'] ?? 0).') · how long the feeling lasted: '.$lastedTxt.'</p>';
62 }
63 echo '</div>';
64}
65
66/* per programme */
67if (!empty($d['per_programme']) && ($s['sessions'] ?? 0) > 0) {
68 echo '<div class="card"><h3>By route</h3><table class="data"><thead><tr><th>route</th><th>sessions</th><th>completed</th><th>steps done</th><th>the day, 0 to 10</th><th>would repeat</th></tr></thead><tbody>';
69 foreach ($d['per_programme'] as $r) { echo '<tr><td>'.h($r['programme']).'</td><td>'.(int) $r['sessions'].'</td><td>'.(int) $r['completed'].'</td><td>'.($r['share_done'] !== null ? h((string) $r['share_done']).'%' : '').'</td><td>'.h((string) ($r['day_rating'] ?? '·')).'</td><td>'.(isset($r['would_repeat_share']) && $r['would_repeat_share'] !== null ? h((string) $r['would_repeat_share']).'%' : '·').'</td></tr>'; }
70 echo '</tbody></table></div>';
71 echo '<div class="card"><h3>By step: done as a share of the times it was reached, and how it felt (0 to 10)</h3><table class="data"><thead><tr><th>route</th><th>step</th><th>station</th><th>reached</th><th>done</th><th>skipped</th><th>share</th><th>felt</th><th>minutes</th></tr></thead><tbody>';
72 foreach ($d['per_circuit'] as $r) { echo '<tr><td>'.h($r['programme']).'</td><td>'.h($r['title']).'</td><td>'.h(($r['station'] ?? '').' '.($kinds[$r['kind']] ?? $r['kind'])).'</td><td>'.(int) $r['reached'].'</td><td>'.(int) $r['done'].'</td><td>'.(int) $r['skipped'].'</td><td>'.($r['share_done'] !== null ? h((string) $r['share_done']).'%' : '').'</td><td>'.h((string) ($r['feeling'] ?? '·')).'</td><td>'.h((string) ($r['minutes'] ?? '')).'</td></tr>'; }
73 echo '</tbody></table></div>';
74}
75
76/* outline */
77echo '<h2>The programmes</h2><div class="grid cols2">';
78foreach ($d['programmes'] as $p) {
79 echo '<div class="card"><h3>'.h($p['title']).' <span class="kv">'.(int) $p['minutes_total'].' min</span></h3><p class="kv"><b>'.h($p['purpose']).'</b> · '.h($p['tagline']).'</p><p>'.h($p['description']).'</p><ol class="spfacts">';
80 foreach ($p['circuits'] as $c) { echo '<li><b>'.h($c['title']).'</b> <span class="kv">'.h($kinds[$c['kind']] ?? $c['kind']).' · '.(int) $c['minutes'].' min'.(!empty($c['optional']) ? ' · optional' : '').'</span><br><span class="kv">'.h($c['intent']).' '.h((string) $c['dose']).'</span></li>'; }
81 echo '</ol></div>';
82}
83echo '</div>';
84
85/* the log */
86if (!empty($d['log'])) {
87 echo '<h2>Session log</h2><p class="lede">Every session at the questionnaires tier and above as a coded row: participant code, route, day, the daily prompt, steps done of those offered, how the day felt, whether the guest would repeat the route. Open data for the research; nothing here identifies a person.</p>';
88 echo '<details class="card"><summary>'.count($d['log']).' sessions</summary><table class="data"><thead><tr><th>session</th><th>participant</th><th>route</th><th>day</th><th>definition</th><th>status</th><th>present</th><th>rested</th><th>connected</th><th>done</th><th>offered</th><th>skipped</th><th>the day</th><th>repeat</th><th>minutes</th></tr></thead><tbody>';
89 foreach ($d['log'] as $r) { echo '<tr><td>'.(int) $r['session'].'</td><td class="mono">'.h($r['participant']).'</td><td>'.h($r['programme']).'</td><td>'.h($r['day']).'</td><td>'.h((string) ($r['definition'] ?? '')).'</td><td>'.h($r['status']).'</td><td>'.h((string) ($r['mindful'] ?? '')).'</td><td>'.h((string) ($r['restored'] ?? '')).'</td><td>'.h((string) ($r['connected'] ?? '')).'</td><td>'.(int) $r['done'].'</td><td>'.(int) $r['offered'].'</td><td>'.(int) $r['skipped'].'</td><td>'.h((string) ($r['day_rating'] ?? '')).'</td><td>'.(isset($r['would_repeat']) ? ($r['would_repeat'] ? 'yes' : 'no') : '').'</td><td>'.(int) $r['minutes'].'</td></tr>'; }
90 echo '</tbody></table></details>';
91}
92echo '<p class="note">Method: a guest signs in to the retreat app from their booking; the app then keeps only a salted code for the person and the stay, and below the questionnaires tier not even that. Measures follow the research plan: the same nine feeling scales (0 to 10, with three words) answered on arrival, on departure, and four and twelve weeks after the stay by e-mail, the daily prompt (three items, 0 to 10) on the mornings between, per-step feedback (0 to 10), the closing feedback (the day 0 to 10, three words, would repeat) and a measurement moment on the first and last mornings (five minutes seated, one cuff reading, entered by hand until a device is connected). Words are never published. Wearable readings will join the same log at the wearables tier. Guests may skip, pause or abandon at any time, and every session counts, complete or not.</p>';
93page_footer();
94

Lines can be cited as pages/wellness.php L120-L140, platform code 2026.09.17-a2894de; add #L120-L140 to this page's address to highlight them. Source shown for scrutiny of the research platform. All rights reserved. Not offered as installable software.