The founder wants to publish something every week. The two states Dawnscan is proudest of are the wrong material for that: on 2026-09-04 production held 1 Still Building project and 2 Under the Radar, because both are strict by design and both are meant to be rare. What production is rich in is shipping — 1,566 ship events from 793 published projects in seven days, 1,391 verified builders, 780 projects reading SHIPPING.
So /this-week is built on shipping, and the two rare states appear at the end
as small blocks that say plainly when they are empty and why.
1. What the page is
| Piece | Where |
|---|---|
| Page | apps/web/src/app/(site)/this-week/page.tsx — server-rendered, force-dynamic, no provider call in the request path |
| JSON | GET /api/this-week (apps/web/src/app/api/this-week/route.ts), cached five minutes, rate-limited (api.this-week, 60/min) |
| Query | weeklyRollup in packages/domain/src/queries/weekly.ts |
| JSON shape | buildThisWeekPayload in apps/web/src/lib/this-week-view.ts (pure), cached by apps/web/src/lib/this-week.ts |
| Linked from | The footer ("This Week"), the /ships header ("This week →"), the sitemap |
One primary CTA: Browse every ship → /ships. Every section links onward
to the surface that holds the rest of it. Mobile-first; e2e/this-week.spec.ts
asserts no sideways scroll at 375 px, top and bottom.
2. The window
The last seven days, ending when the page rendered, computed server-side
and printed on the page as 7 days to 4 Sep 2026. In SQL the window is
[since, until): since is inclusive, until is exclusive, so a row is
counted in exactly one window.
There is no calendar-week boundary and no timezone rule to remember: the page
states its own period, and the JSON carries window.since, window.until,
window.days and the same label. formatWeeklyDay writes the date itself
rather than through Intl, so the page, the JSON and a newsletter never
disagree about whether September is "Sep" or "Sept".
3. The sections
What shipped
Every approved ship event of a published project inside the window, grouped
by project, the project with the newest ship first. Each card is the ordinary
Card V7 project card with that project's newest ship inside it
(docs/PROJECT_CARD_V7.md §6a), so the contract, market-cap reading, launch
origin, official X account and the ship's source link are exactly what /ships
shows for the same ship.
- The headline count is ship events; the section total is projects. Both come from window functions over the same grouped set, so the sentence and the cards cannot disagree.
- A project's "3 ships in this window" is counted over the whole window, not over the sample: the grouping happens in SQL before the limit.
- Sample: 12 projects. The rest is one link away on
/ships. - Same visibility as every browse surface (
VISIBLE_PROJECT): approved, published (QUALIFIED/VERIFIED_BUILDER), and — outsideDATA_MODE=demo— not a demo fixture. Ship events must beAPPROVEDtoo.
New builders
Projects whose projects.verified_builder_at falls inside the window and whose
catalogue status is VERIFIED_BUILDER.
This is when Dawnscan finished checking the public evidence, not when the team started building. Dawnscan verifies in catalogue passes, so a large number here can mean Dawnscan caught up on its own backlog rather than that many teams appeared. The page says exactly that under the heading — it is the only honest way to show the number, because on 2026-09-04 all 1,391 verified builders were stamped in a single pass (1,398 on 4 Sep, 1 on 3 Sep).
Back to shipping
Projects whose activity reading moved from QUIET / DORMANT to
SHIPPING / ACTIVE / RESUMED during the window, read from project_scores
history: the project's first and last score row inside the window.
Why inside the window rather than across its edge: project_scores in
production only reaches back to 2026-09-01, so for almost every project there
is no reading from before the window to compare against. A comparison against
that missing reading returns zero rows — not because nothing moved, but because
Dawnscan could not look. Comparing the two ends of the window is a claim Dawnscan can
actually support, and the page says which comparison it made.
A project Dawnscan read only once in the window cannot move. Those projects are
counted in comparable, which the empty state prints: "Dawnscan compared its own
readings for 2,528 projects it read more than once here" — so "none moved" can
never be mistaken for "nothing was looked at".
Still Building · Under the Radar
The two strict states, as counts plus the names, side by side, with a link to
/methodology#gap. Both read the same stored eligibility as /radar —
project_score_current.still_building and .under_the_radar, gated on
VERIFIED_BUILDER — so the page and the Radar tab can never disagree.
They are usually empty. That is the design, not a defect, and the block says which condition is unmet rather than showing nothing. The section states plainly: neither is a buy signal.
4. What to do when a section is empty
Nothing. An empty section is a reading, and the copy already says what was measured:
| Section | Empty means | Check before treating it as a bug |
|---|---|---|
| What shipped | No approved ship event in seven days | select count(*) from ship_events where published_at >= now() - interval '7 days' — if events exist but are PENDING, moderation is the backlog, not ingestion |
| New builders | Nobody cleared the evidence bar this week | Expected most weeks; the promotion pass runs on its own schedule |
| Back to shipping | No reading moved from quiet to shipping | If comparable is also 0, scoring did not run twice in the window — that is a worker question (/status), not a page question |
| Still Building | No tracked drawdown with building after it | Expected; see /methodology#gap |
| Under the Radar | Nothing clears the momentum floor on the published cohort | Expected; a product decision, documented in docs/LISTING_CONTROLS.md §5 |
The page is written so that all five can be empty at once and still read honestly.
5. Copy discipline
No "alpha", "gem", "100x", "moon", "undervalued". No price talk beyond the
card's own market-cap context, and no sentence anywhere that connects building
to price. Counts are counts, each printed beside the window it was counted
over. e2e/this-week.spec.ts asserts the banned words never appear in Dawnscan's
own copy on the page, and weekly.test.ts asserts the same of the summary
line.
The JSON carries the same discipline plus a disclaimer field, because the
numbers travel further than the page: "Counts of public, source-backed
activity Dawnscan recorded in the stated window. Not a prediction, not a ranking by
price, and not investment advice."
6. Cost
Six aggregates and three card queries, all bounded, none scanning
token_candidates. Measured on production data (EXPLAIN (ANALYZE),
2026-09-05):
| Query | Plan | Time |
|---|---|---|
| Ship groups | Bitmap index scan on ship_events_published_at_idx, 1,587 rows |
69 ms |
| New builders | Bitmap index scan on projects_published_browse_idx |
61 ms |
| Status moves | Seq scan on project_scores (29.5k rows — the seven-day window is currently the whole table), hash join to the published catalogue |
700 ms |
No index was added. The status-move seq scan is the planner choosing
correctly: today the window covers ~100% of project_scores, so an index scan
would be slower. project_scores_calculated_at_idx already exists and takes
over as history grows past the window. If that query becomes the page's cost
centre later, the fix is to narrow the cohort (join project_score_current
first), not a new index.
GET /api/this-week is cached for five minutes, so a script polling it costs
one pass per five minutes.
7. Tests
- Unit:
packages/domain/src/queries/weekly.test.ts(window, date formatting, the row→section shaping, the summary line and its plurals),apps/web/src/lib/this-week.test.ts(JSON shape, links, what must not be in it). - Integration:
packages/domain/src/queries/weekly.integration.test.ts— window edges, grouping and per-project counts, ordering, sample bounds independent of totals, demo/hidden/unmoderated rows excluded,comparable. - Playwright:
apps/web/e2e/this-week.spec.ts— the sections render, the empty blocks read honestly, 375 px has no sideways scroll, the JSON route's shape and cache header, and the links from/shipsand the footer.
8. Production numbers on the day it was built (2026-09-04/05, read-only)
| Section | Would show |
|---|---|
| What shipped | 1,566 ship events from 793 projects |
| New builders | 1,391 (one catalogue pass on 4 Sep) |
| Back to shipping | 106, out of 2,528 projects read more than once |
| Still Building | 1 |
| Under the Radar | 2 |