Phase 4: per-child sessions, scan both children, items separated
Fetch and parse Harry and Finn with a stored Compass session per child and store every item against the right children.id. - cmd/school/session.go + internal/store/session.go: read and write the per-child harness session state in the SQLite `session` table. `show` prints metadata only; the state is never printed. - scripts/compass-fetch-patchright.mjs: reuse the stored session, refresh it after login, resolve the child's userId from the parent page by name, and keep the shared calendar out of the per-child run (it would leak the eldest's timetable into the younger child). - scripts/scan-compass.sh + make scan: scan one child or both; restore the session, fetch, persist the session, then parse. A failing child is recorded in `scans` with ok = 0 and the script exits non-zero (FR-12). - cmd/school/scan.go: `school scan record` writes a fetch failure to the scans table. cmd/school/items.go: `school items purge` removes rows that a shared page stored against the wrong child. - internal/store/store_test.go: prove items and sessions are separated by child. docs/phase-4-both-children-notes.md; README + image tag 0.3.0-phase4. Live evidence: Harry 70 tasks / 1 message / 35 events (6 overdue); Finn 42 tasks / 1 message / 0 events (2 overdue). Finn's subjects are Year 7, Harry's are Year 11. Both sessions stored. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
93
docs/phase-4-both-children-notes.md
Normal file
93
docs/phase-4-both-children-notes.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Phase 4 — both children, per-child sessions
|
||||
|
||||
Status: **done.** The Compass scan now fetches and parses **Harry and Finn**
|
||||
with a stored session per child, and every item is stored against the right
|
||||
`children.id`. See AUD-108.
|
||||
|
||||
## What runs
|
||||
|
||||
```bash
|
||||
# Both children, with the stored session per child.
|
||||
make scan
|
||||
|
||||
# One child only (a scan can target one child).
|
||||
make scan SCAN_CHILD=Finn
|
||||
|
||||
# Same thing without make.
|
||||
scripts/scan-compass.sh
|
||||
scripts/scan-compass.sh --child Harry --child Finn --classify none
|
||||
```
|
||||
|
||||
`scripts/scan-compass.sh` runs the patchright fetcher on the host and the
|
||||
`school` subcommands in a one-off container. It never restarts the service.
|
||||
|
||||
## Per-child session (FR-2, §7 `session` table)
|
||||
|
||||
The Compass login is one parent account, but each child gets its own browser
|
||||
session state so a scan is independent and targetable.
|
||||
|
||||
| Step | Command | Notes |
|
||||
|---|---|---|
|
||||
| Restore | `school session get --child NAME --out FILE` | Reads `session.state`; writes a 0600 file. No row means "log in fresh". |
|
||||
| Fetch | `node scripts/compass-fetch-patchright.mjs --child NAME --state FILE` | Loads the state; logs in only when Compass rejects it; saves the refreshed state. |
|
||||
| Persist | `school session put --child NAME --file FILE` | Upserts `session.state` for that child. |
|
||||
| Inspect | `school session show [--child NAME] [--json]` | Prints bytes, cookie and origin counts, and `updated_at`. **Never the state.** |
|
||||
|
||||
The session state is a secret. It lives in the database volume only. No command
|
||||
prints it, and the handoff file exists only inside the run's scratch directory.
|
||||
|
||||
## What each run stores
|
||||
|
||||
One run directory per child under `var/raw/<child>/<runId>/` (git-ignored):
|
||||
|
||||
| Page | Source | Becomes |
|
||||
|---|---|---|
|
||||
| `home` | parent landing page | `message` rows (news feed) |
|
||||
| `learning-tasks-all` | `POST /Services/LearningTasks.svc/GetAllLearningTasksByUserId` | `task` rows (authoritative per-child list) |
|
||||
| `child-profile` | `/Records/User.aspx?userId=N` | no grid; used only when it carries the legacy grid |
|
||||
| `learning-tasks` | `/Records/UserNew.aspx?userId=N#learningTasks` | `task` rows (legacy grid fallback) |
|
||||
|
||||
The per-child Compass `userId` is discovered from the parent landing page by
|
||||
child name (`Harrison` → Harry, `Finnegan` → Finn) and recorded in the manifest.
|
||||
|
||||
## Why the calendar is not fetched per child
|
||||
|
||||
The parent calendar page renders only the calendars that the parent has enabled.
|
||||
In this account only Harry's calendar is enabled; Finn's is hidden. Fetching that
|
||||
page inside Finn's run therefore stored Harry's Year 11 timetable against Finn —
|
||||
a leak between children.
|
||||
|
||||
Until per-child calendar attribution exists, the shared calendar stays out of the
|
||||
per-child loop. Harry's events remain from Phase 3. A caller can still fetch it
|
||||
explicitly with the fetcher's `--pages` option. The `school items purge` command
|
||||
removes rows that a shared page stored against the wrong child.
|
||||
|
||||
## Fail loudly (FR-12)
|
||||
|
||||
- A fetch failure records `scans.ok = 0` with the message through
|
||||
`school scan record --child NAME --ok=false --message TEXT`.
|
||||
- A parse failure records its own failed scan inside `school parse`.
|
||||
- The scan script finishes every child, prints each failure by name, and exits
|
||||
non-zero. A failed child is never shown as an empty day.
|
||||
|
||||
## Evidence (2026-10-15, live)
|
||||
|
||||
```bash
|
||||
scripts/scan-compass.sh --classify auto
|
||||
```
|
||||
|
||||
| Child | tasks | messages | events | overdue (home-page recon.) |
|
||||
|---|---|---|---|---|
|
||||
| Harry | 70 | 1 | 35 | 6 |
|
||||
| Finn | 42 | 1 | 0 | 2 |
|
||||
|
||||
Rows are separated by `child_id`. A check for items with no matching child
|
||||
returns 0. Finn's task subjects are all Year 7 (`7MA`, `7DRA`, `7DES`); Harry's
|
||||
are all Year 11 (`11MGMA`, `11HLEG`, `11EENG`).
|
||||
|
||||
## Known gaps
|
||||
|
||||
- `children.compass_id` is not populated yet. The manifest holds the `userId` per
|
||||
run; a later phase can copy it into the `children` table.
|
||||
- Per-child calendar attribution is deferred (see above).
|
||||
- Teams (FR-15) is a separate source and is not scanned here.
|
||||
Reference in New Issue
Block a user