Skip to content

v0.6.54.0 feat(#320): per-Lifebook briefing sections fold + collapsible web rendering#335

Merged
jayzalowitz merged 2 commits into
mainfrom
jayzalowitz/320-briefing-fold
May 18, 2026
Merged

v0.6.54.0 feat(#320): per-Lifebook briefing sections fold + collapsible web rendering#335
jayzalowitz merged 2 commits into
mainfrom
jayzalowitz/320-briefing-fold

Conversation

@jayzalowitz

Copy link
Copy Markdown
Owner

Summary

Why

Backend per-Lifebook partitioning shipped in #258. Until now the dashboard only fetched the global briefing; per-Lifebook rows were only reachable via the per-Lifebook detail page. This adds the API fold + UI so the dashboard renders the full partitioned view in one round-trip.

Backward compatibility

  • briefing field unchanged
  • sections always an array (never undefined)
  • /lifebook/:domain/latest untouched

Test plan

  • pnpm build --concurrency=1 clean
  • pnpm --filter @skytwin/db test — 290 passed (5 new in briefing-repository-per-lifebook.test.ts)
  • pnpm --filter @skytwin/api test — 675 passed (6 new in twin-briefings-sections-fold.test.ts; pre-existing briefing-routes.test.ts mocks extended for the new repo calls)

🤖 Generated with Claude Code

…le web rendering

New repo method briefingRepository.getLatestPerLifebook(userId, cadence?)
uses DISTINCT ON (domain_name) for one round-trip regardless of
Lifebook count. Hard-filters domain_name IS NOT NULL so global
briefings can never accidentally fold into the sections list.

GET /api/twin-briefings/latest grew an additive sections[] field:
one entry per visible Lifebook that has a per-domain briefing,
ordered by Lifebook importance (core -> secondary -> emerging).
Lifebooks without a matching briefing are omitted (no empty slots).

Web rendering in twin-briefing.js: per-Lifebook sections render as
collapsible <details> elements between the global prose section and
the history sidebar. First card open by default; rest collapsed to
avoid a wall of text. Native browser collapsing, zero JS state.

Backend partitioning shipped earlier in #258; this PR is the API
fold + web rendering — the dashboard now has a single round-trip
to render the full partitioned view.

Backward-additive: existing briefing field unchanged; sections always
an array (never undefined). /lifebook/:domain/latest untouched.

Updated briefing-routes.test.ts to mock the new lifebookRepository
+ getLatestPerLifebook defaults so pre-#320 tests still pass.

5 new repo tests + 6 new route tests. 290 db / 675 api tests pass.

Closes #320 (no deferred scope — mobile rendering tracked under #179).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 18, 2026 06:19

Copilot AI 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.

Pull request overview

Adds per-Lifebook briefing sections to the latest twin briefing API response and renders them as collapsible cards in the web briefing page.

Changes:

  • Adds briefingRepository.getLatestPerLifebook(userId, cadence?).
  • Extends GET /api/twin-briefings/latest with additive sections[].
  • Renders per-Lifebook sections in twin-briefing.js and adds API/repository tests.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
VERSION Bumps release version to 0.6.54.0.
package.json Bumps package version to 0.6.54.0.
CHANGELOG.md Documents the new per-Lifebook briefing fold and rendering.
packages/db/src/repositories/briefing-repository.ts Adds latest per-domain briefing lookup.
packages/db/src/tests/briefing-repository-per-lifebook.test.ts Adds repository tests for the new lookup.
apps/api/src/routes/twin-briefings.ts Adds sections[] folding to /latest.
apps/api/src/tests/twin-briefings-sections-fold.test.ts Adds route tests for folded sections.
apps/api/src/tests/briefing-routes.test.ts Extends existing route mocks for the new dependencies.
apps/web/public/js/pages/twin-briefing.js Renders per-Lifebook briefing sections as collapsible cards.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +195 to +204
* #320: return the latest per-Lifebook briefing for EACH of a user's
* visible Lifebooks, in importance order (core → secondary →
* emerging). One row per Lifebook, NULL when no briefing for that
* domain exists yet (the worker hasn't emitted one). Used by
* `GET /api/twin-briefings/latest`'s `sections[]` fold to render the
* partitioned dashboard view alongside the global briefing.
*
* Single SQL query with `DISTINCT ON (domain_name)` so cost is one
* query no matter how many Lifebooks the user has. Equivalent to N+1
* `getLatestForUserDomain` calls but bounded.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in f40d57d — docstring now describes what the method actually does (DISTINCT ON over twin_briefings non-null-domain rows) and explicitly defers visibility / ordering / omission to the route's join against listVisible. No more overclaiming.

Comment thread apps/api/src/routes/twin-briefings.ts Outdated
Comment on lines +44 to +46
// Two parallel queries + a join in JS — cheaper than per-Lifebook
// round-trips, and the per-call cost is bounded by the user's
// visible-Lifebook count (typically < 10).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in f40d57d — comment now reads 'Three parallel queries' matching the actual Promise.all of getLatestForUser + getLatestPerLifebook + listVisible.

Comment thread CHANGELOG.md Outdated
### Tests

- 5 new repository tests in `briefing-repository-per-lifebook.test.ts` pinning: DISTINCT ON + cadence threading + global-briefing exclusion + empty-result case.
- 7 new route tests in `twin-briefings-sections-fold.test.ts` pinning: 400 on missing userId; empty-state shape; global-only path; importance-ordered sections with omit-when-no-briefing; hidden Lifebooks excluded (via listVisible contract); cadence query param threads to both queries.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in f40d57d — CHANGELOG now reads 6, matching the actual it() count in twin-briefings-sections-fold.test.ts. Off-by-one on my part.

… count

Three Copilot doc findings, all valid:

1. briefingRepository.getLatestPerLifebook docstring overstated scope —
   it claimed visibility filtering / importance ordering / null
   placeholders, but those happen later in the API route's join
   against listVisible. Rewrote docstring to describe what the
   method actually does (DISTINCT ON over twin_briefings rows with
   non-null domain_name) and explicitly note the route handles
   visibility / ordering / omission.

2. Route comment said 'Two parallel queries' but it's actually three
   (getLatestForUser, getLatestPerLifebook, listVisible). Corrected.

3. CHANGELOG claimed 7 new route tests; the file has 6. Off-by-one
   I miscounted. Fixed.

No functional changes.
@jayzalowitz jayzalowitz merged commit 6f5bc5b into main May 18, 2026
8 checks passed
jayzalowitz added a commit that referenced this pull request May 18, 2026
…ive-toolchain caches (#336)

Three changes to .github/workflows/{build,evals,release}.yml to cut CI wall-clock:

1. Turbo remote cache via dtinth/setup-github-actions-caching-for-turbo@v1 on every job that runs `pnpm build`. First job populates the GH Actions cache; downstream jobs (desktop-mac/linux, mobile-android/ios, evals, release matrix) get `pnpm build` as cache restores across the monorepo. Skipped on Windows desktop runners (action writes to /tmp).

2. Path-filtered desktop + mobile jobs on PRs via dorny/paths-filter@v3. PRs that don't touch apps/desktop/**, apps/mobile/**, packages/**, or lockfiles skip the 5 desktop+mobile packaging jobs. Push events to main and tag pushes always run everything; release artifact coverage unchanged.

3. Native-toolchain caches: electron-builder downloads (per-OS), Gradle (gradle/actions/setup-gradle@v4), CocoaPods (Pods/ + global cache).

Bumped 0.6.54.0 → 0.6.55.0 after rebase (#335 took the 0.6.54.0 slot).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

Emergent Lifebooks: per-Lifebook briefing partitions

2 participants