Repository navigation
feat(aggregator): honesty + freshness — no silent zeros, primed health, per-source chips (#1139, #1267, #1138) - #1318
Conversation
…h, per-source chips (#1139, #1267, #1138) #1139 — the orchestration section is diagnosed on every read (diagnoseOrchestrationSection: live/stale>90m/absent/invalid with the failing check named) and Source.diagnostics() carries it to the surfaces. /attention banners an absent/invalid/stale tier source at the point of display, renders tier counts as 'unknown' (never a confident 0) when the source is missing, stamps tier headings with the section run id + age when present, and suppresses the false-reassurance empty copy. /today's derived banner names the section's true state (invalid names the failed checks); a stale section behind the served view warns. This banner is #1148's aggregator-side dead-man's switch. #1267 — /api/health primes every provenance facet (60s-cached, failure-tolerant) before answering, so its report no longer depends on request order; the response also carries the structured sections diagnosis. Regression test boots a live-source server and asserts on the FIRST response it ever serves. The live items() facet also reports pool-backed truthfully on an empty-refs prime call. #1138 — per-source freshness chips (source · state · age; counts always with their noun) on the pages that use each source, from Source.provenanceDetail(); the footer provenance line moves into a collapsed 'source detail' disclosure. The registry facet now counts the MERGED store total (the number /sessions renders) instead of the per-read incoming batch, ending the 221-vs-61 disagreement. Role-based wording (Drew, 2026-10-27): all user-visible 'Needs Drew' copy becomes 'Needs user' (headings, chips, session badge, /today alert, page blurb, program editorial, README) — the NEEDS USER queue is an intake the orchestrator works first; only items it cannot resolve escalate to the user. Internal field names, JSON keys, and the orchestration contract (needsDrew etc.) are unchanged — contract naming is #1290's decision. Tests: 181 pass (baseline 167), tsc clean, biome 2.3.2 + prettier.
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 4 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc571cff35
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (path === "/attention") { | ||
| const { view, coverage } = await attentionContext(); | ||
| return html(renderAttention(view, coverage, prov(), await commentsStore.counts())); | ||
| return html(renderAttention(view, coverage, prov(), await commentsStore.counts(), provDetail())); |
There was a problem hiding this comment.
Prime displayed facets before rendering freshness chips
On a fresh live-source process, /attention renders a registry freshness chip without calling source.registry(): attentionContext() only reads attention, orchestration, and coverage. With a valid registry in the feed, I reproduced registry · fixtures on the first /attention request, changing to registry · live · 1 session records · fresh after visiting /sessions. The board's orchestration chip and projects page's items chip have the same unprimed-facet problem. Exercise the displayed facets or maintain their metadata when their underlying data is read, so these new indicators do not depend on which unrelated pages were visited first.
Useful? React with 👍 / 👎.
| : ""); | ||
| } else if (projectorServed) { | ||
| provenance.items = "live (projector)"; | ||
| } else if (pool.length > 0 && feed) { |
There was a problem hiding this comment.
Limit pool-only provenance to empty-reference priming
When the feed contains a nonempty project pool but none of the requested refs match it, and the projector is disabled or unavailable, items() returns fixture items through fix.items(remaining). This new branch nevertheless labels the result live (project pool…), so the freshness chip presents hand-written fixture issue/PR states as live data. The branch also matches nonempty unresolved requests, not just the empty-reference priming case described in its comment. Restrict that special case to empty refs and report fixture provenance when all requested items came from the fallback.
Useful? React with 👍 / 👎.
Honesty + freshness slice (epic #1184)
One PR closing the three honesty issues from the PM-stack coherence review, plus the aggregator half of #1148's dead-man's switch.
#1139 — no silent zeros
diagnoseOrchestrationSection()insrc/feed.tsclassifies the raw section value as live / stale (>90 min, the design's threshold) / absent / invalid (invalid names the first failing validation check).Source.diagnostics()carries it from both sources; the live source recomputes it on everyorchestration()read.Tier source missing — showing session-derived items only; the orchestrator's published queues are NOT reflected in the counts below.; invalid names the failed checks (Tier source invalid — … failed validation (provenance); …); stale names the run and its age. When the source is absent/invalid the tier headings and chips read "Needs user (unknown)" — never a confident 0 — and the "nothing needs you" empty copy is suppressed (it was the false-reassurance failure mode). When present, tier headings carry a section stamp (· section <runId> · <age>).tiers.needsDrew)…" instead of the old blanket "has not published yet"; a stale-but-served section gets a stale warning with run + age.#1267 — /api/health must not lie by request order
Provenance facets populate lazily, one per method call, so health used to report fixture defaults for facets nobody had exercised yet.
/api/healthnow primes every facet first (60 s-cached, failure-tolerant — a failed facet keeps its honest fallback string) and returns the structuredsectionsdiagnosis beside the provenance strings. Regression test (test/health-priming.test.ts) boots a live-source server against a controlled feed and asserts on the first response the process ever serves: quota/orchestration/registry facets report live, registry counts1 session records,sections.orchestration.state === "live". The liveitems()facet also reports pool-backed truthfully on an empty-refs prime call.#1138 — per-source freshness chips
Source.provenanceDetail()returns structured per-facet detail (text,state,ageMs,count,countLabel); state derives from the facet's own maintained string plus the orchestration diagnosis and feed age (a "live" string over a >15 min-old feed renders stale, impl(fleet): staleness watchdog - surface dead/stale stack inputs as NEEDS ORCHESTRATOR instead of silent decay #1148's threshold).<details>"source detail" disclosure; the tailnet link stays visible.live (221 session records · 61 from the latest feed · …)— the same number the /sessions header renders, ending the unexplained 221-vs-61 split.Role-based wording (Drew's direction, 2026-10-27)
All user-visible "Needs Drew" copy becomes "Needs user" across the aggregator — /attention headings, chips and intro, the session tier badge, the /today alert, the page-manifest blurb, the /program editorial record, project-config prose, and the README. This is Drew's explicit direction, extending the fleet-wide 2026-10-25 rename of Drew-named labels to role-based ones: the NEEDS USER queue is an intake the orchestrator works first — it resolves what it can and escalates only what genuinely requires the user (user/escalated) — so the copy no longer implies every queued item is waiting on the user personally. Internal field names, JSON keys, and the orchestration contract (
needsDrew,drewReason, …) are unchanged; contract naming is #1290's open decision.Verification
bun test: 181 pass / 0 fail (baseline 167; +14 new: diagnosis states, attention banner states, today invalid banner, chips incl. per-page selection, live-source diagnostics/detail, health priming).bunx tsc --noEmit: clean. Formatted with schema-pinned biome 2.3.2 + prettier.Closes #1139, closes #1267, closes #1138. Refs #1148 (aggregator half), #1184.
Need help on this PR? Tag
@codesmith-botwith what you need.