Skip to content

feat(blog): shadow ingestion-surface UI — tiered reader + blended /stream + pulse tiers#217

Draft
Jesssullivan wants to merge 12 commits into
mainfrom
feat/blog-tiered-reader-ui
Draft

feat(blog): shadow ingestion-surface UI — tiered reader + blended /stream + pulse tiers#217
Jesssullivan wants to merge 12 commits into
mainfrom
feat/blog-tiered-reader-ui

Conversation

@Jesssullivan

@Jesssullivan Jesssullivan commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Shadow ingestion-surface UI

This PR grew from the WS-2 tiered blog reader into the shadow ingestion-surface UI — the next increment of the "blog as a live-streamed ingestion surface of tinyland.dev" vision, built and validated only on the shadow (tss.tinyland.dev). Everything is additive and reversible; the prod apex stays frozen.

Per docs/blog-editorial-taxonomy-2026-07-03.md, tiers/salience are reader-weight / IA only — never an auth, privacy, or ActivityPub-delivery signal. An absent tier/salience means "not classified yet" and never implies private.


Ingestion-surface increment (blended /stream + pulse tiers + nav)

  • /stream — one blended timeline (the centerpiece). New prerendered route (noindex,nofollow while held) that merges published long-form posts (src/lib/posts) with public pulse items (src/lib/pulse/load) into a single reverse-chronological, tier-weighted timeline. A small unified StreamItem type (kind: 'post' | 'pulse', title/summary/date/tier/url) plus a pure, deterministic blendStream(): date-desc primary; within an equal date noteworthy floats first (mirrors the feat(blog): shadow ingestion-surface UI — tiered reader + blended /stream + pulse tiers #217 blog-index comparator); stable id tie-break so ordering never relies on sort stability. Each row shows a kind indicator (📝 / 💬 / 🐦) + TierBadge, reusing the pulse-card styling. Pulse snapshot load is best-effort — the stream still prerenders from posts alone if it's absent.
  • Pulse tier badges. PulseNoteCard / PulseBirdCard now render TierBadge when salience is present (the WS-4 PublicPulseItem.salience field) and nothing when absent — graceful display-when-present. The hashed static snapshot fixture (static/data/pulse/public-snapshot.v1.json) is untouched (content-hash gate preserved); real hub data populates salience later.
  • Nav. Added Stream and Pulse entries to +layout.svelte (desktop + mobile drawer); /pulse now highlights on its subroutes.

Validation (this increment)

  • vitest (touched paths): 21/21 green — new src/lib/stream/blend.test.ts (interleave by date, noteworthy-first within equal date, empty inputs, absent-tier, deterministic across input orderings, total-order tie-break) + pulse-card salience gating (TierBadge only when salience is set).
  • svelte-check: 0 errors / 0 warnings on the new + changed code.
  • vite build (SvelteKit build): the new /stream page and all app code build clean. The only local build failures are pre-existing Missing Mermaid prerender cache errors in five src/posts/*.md blog-content files — the known headless-Chromium prerender-cache sandbox limitation, unrelated to this change (no error references any new file). Relying on the CI shadow build for the full prerender.

WS-2 — Tiered reader UI on the blog spoke (already in this branch)

Consumes the editorial_tier field added to the Post type in #212 and surfaces it in the reader UI.

What's here

  • TierBadge.svelte — a small, accessible, aria-labeled badge: stronger primary tint for noteworthy (with a subtle star), muted outline for less-noteworthy, and it renders nothing when the tier is undefined.
  • BlogCard (listing) — badge in the metadata row; noteworthy cards get a gentle ring-1 accent (featured styling still wins). No layout shift when the tier is absent.
  • BlogArticle header — badge beside date/category, threaded through both the static and broker metadata paths.
  • /blog index — additive reader-weight ordering: the date-desc contract is preserved globally, and noteworthy posts only float up within an equal date (stable Array.sort, fully reversible). Untiered posts keep their existing relative order. Optional tier filter chips (default All, view-only, never drops a post; chips only appear when tiered posts exist).
  • Two posts tagged to demonstrate both tiers on the shadow — a reverse-engineering writeup → noteworthy, a recipe → less-noteworthy.

Deliberately not touched

  • No RSS/JSON feed shape change.
  • No live broker Worker path change.
  • No change to the prod default build.

⚠️ HELD from prod merge during the transscendsurvival.org freeze — validate on the shadow only.

This is a visible reader change plus a new surface, so it is hold-for-freeze. The PR is opened non-draft on purpose so the "Build and optionally deploy Cloudflare Pages shadow" CI job renders a shadow preview at tss.tinyland.dev. Do not merge to prod, do not change the prod default build, and do not touch the live broker Worker while the freeze is in effect — validate on the shadow only.

Surface the editorial taxonomy tier (added to the Post type in #212) in the
reader UI. Tiers are reader-weight / IA only, never an auth, privacy, or
ActivityPub-delivery signal; an absent tier means "not classified yet".

- TierBadge.svelte: accessible, aria-labelled badge — stronger accent for
  noteworthy, muted outline for less-noteworthy, renders nothing when the
  tier is undefined.
- BlogCard: badge in the metadata row; noteworthy cards get a gentle ring
  accent (featured styling still wins); no layout shift when tier is absent.
- BlogArticle header: badge threaded through the static and broker paths.
- /blog index: additive reader-weight ordering (date-desc preserved
  globally, noteworthy floats up only within an equal date via a stable
  sort); optional view-only tier filter chips that never drop posts.
- Tag two posts to demonstrate both tiers (RE writeup -> noteworthy,
  recipe -> less-noteworthy), per the taxonomy migration guidance.

No RSS/JSON feed shape change; no broker Worker path change.
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

📝 Blog Post Review

Found 2 blog post(s) in this PR:

Post Status Date Published Tags Linear
XRAM Injection: Bypassing USB Bridge Whitelists to Recover NVMe Drives ✏️ Modified 2026-03-04 ✅ Published nvme, asm2362, xram, scsi, usb-bridge, reverse-engineering, zig, low-level none
Gingersnap Cookies (from a milk-free, soy-free recipe card) ✏️ Modified 2026-05-29 ✅ Published recipe, baking, baking-science, cookies, gingersnap, allergen-friendly, ocr, apple-vision, swift, llvm, macos none

Schema Validation

✅ All posts pass schema validation.

Hyperlink Suggestions

  • NVMeNVMe (line 2)

Slash Commands

Command Description
/schedule 2026-03-15 Schedule auto-merge for a date
/publish Set all posts to published: true
/draft Set all posts back to draft
/retitle "New Title" Change a post's title
/review Re-run AI prose review
/suggest-links Find unlinked keywords

Jesssullivan added a commit that referenced this pull request Jul 5, 2026
Build the next increment of the "blog as live-streamed ingestion surface"
vision on the SHADOW UI only (tss.tinyland.dev). Everything additive and
reversible; prod apex stays FROZEN.

- /stream route (prerender, noindex+nofollow while held): one blended,
  reverse-chronological, tier-weighted timeline merging published long-form
  posts (src/lib/posts) with public pulse items (src/lib/pulse/load). Pure,
  deterministic blendStream(): date desc primary; noteworthy-first within an
  equal date (mirrors the #217 comparator); stable id tie-break so ordering
  never depends on sort stability. Each item shows a kind indicator + TierBadge.
- Pulse tier badges: render TierBadge on PulseNoteCard/PulseBirdCard when
  salience is present; renders nothing when absent (graceful). The hashed
  static snapshot fixture is untouched — display wires up when real hub data
  populates salience.
- Nav: add Stream + Pulse entries; /pulse highlights on its subroutes.
- Tests: vitest for blendStream (interleave by date, noteworthy-first within
  equal date, empty inputs, absent-tier, deterministic, total-order tie-break)
  and pulse-card salience gating (TierBadge only when salience is set).

Tiers/salience are reader-weight/IA only — never auth, privacy, or AP delivery
(docs/blog-editorial-taxonomy-2026-07-03.md). HELD-for-freeze: shadow-only.
@Jesssullivan Jesssullivan changed the title feat(blog): tiered reader UI consuming editorial_tier (WS-2) feat(blog): shadow ingestion-surface UI — tiered reader + blended /stream + pulse tiers Jul 5, 2026
Build the next increment of the "blog as live-streamed ingestion surface"
vision on the SHADOW UI only (tss.tinyland.dev). Everything additive and
reversible; prod apex stays FROZEN.

- /stream route (prerender, noindex+nofollow while held): one blended,
  reverse-chronological, tier-weighted timeline merging published long-form
  posts (src/lib/posts) with public pulse items (src/lib/pulse/load). Pure,
  deterministic blendStream(): date desc primary; noteworthy-first within an
  equal date (mirrors the #217 comparator); stable id tie-break so ordering
  never depends on sort stability. Each item shows a kind indicator + TierBadge.
- Pulse tier badges: render TierBadge on PulseNoteCard/PulseBirdCard when
  salience is present; renders nothing when absent (graceful). The hashed
  static snapshot fixture is untouched — display wires up when real hub data
  populates salience.
- Nav: add Stream + Pulse entries; /pulse highlights on its subroutes.
- Tests: vitest for blendStream (interleave by date, noteworthy-first within
  equal date, empty inputs, absent-tier, deterministic, total-order tie-break)
  and pulse-card salience gating (TierBadge only when salience is set).

Tiers/salience are reader-weight/IA only — never auth, privacy, or AP delivery
(docs/blog-editorial-taxonomy-2026-07-03.md). HELD-for-freeze: shadow-only.
Pushes to feat/blog-tiered-reader-ui now deploy the tss-shadow Pages
project (production -> tss.tinyland.dev) so the shadow host tracks the
branch. main -> transscendsurvival-org routing is byte-identical; PRs
remain build-only. Lives on the held shadow branch only.
With Stream+Pulse added the full desktop nav measures ~830px, which
overflows exactly at the md (768px) breakpoint (e2e prose-overflow
caught it: 3 slug pages). Nav now appears at lg:, drawer covers tablet.
Verified 9/9 (768/1024/375 x slug/stream/index) via vite preview.
Desktop nav moved md:->lg: (768px overflow fix); the spec's hardcoded
nav.hidden.md\:flex selector + >=768 desktop assumption follow. Tablet
now asserts the drawer trigger; desktop also asserts the new Stream
link. Local: 49/50 pass (dark-mode fail is local headless-shell only —
CI run 28854281525 passed it).
@Jesssullivan

Copy link
Copy Markdown
Owner Author

Program disposition — 2026-07-14: keep this shadow-only and do not promote yet. The ratified order is design + data first. Fresh live checks show the hub blog projection has 140 posts and zero editorialTier / editorial_tier / frontmatter tier values; the Pulse projection has 6 items and zero salience values. The current badges/tier-weighting therefore exercise fixtures and branch-authored examples, not production broker data.

Promotion prerequisites remain: TIN-2413 owns the reader-IA decision, TIN-2641 owns the shadow /stream experiment, and the hub must project real reviewed salience/tier data. Green CI alone is not a production-merge signal for this PR.

@Jesssullivan

Copy link
Copy Markdown
Owner Author

Status: GREEN and deliberately HELD (ratified 2026-07-14).

The post-#228 bazel-remote-gates rerun passed (22m32s, no OOM signature — the parallelism-flags fix holds), and every functional check is green; the lone red "Build source image" is a cancelled duplicate shadow-preview run from 10:40Z, not a failure.

This PR does not merge yet, by operator ruling ("design + data first"):

  1. TIN-2413 — the reader-IA design (carousel vs planetarium tier treatment) that should define this UI's end-state has not started; implementation preceded design.
  2. Live salience — hub projections emit zero salience fields today (verified live), so the tiered reader has no real data contract to render against; fed live data it renders untiered.

Promotion ruling happens only after both exist. The shadow deploy remains available for design iteration via gh workflow run cloudflare-pages-shadow.yml --ref feat/blog-tiered-reader-ui.

@Jesssullivan
Jesssullivan marked this pull request as draft July 15, 2026 00:49
@Jesssullivan

Copy link
Copy Markdown
Owner Author

Program-state correction (2026-07-14): TIN-2413 did run and selected Observatory Ledger for beta; all required checks on this head are now green. Neither fact authorizes promotion. Live hub data still has 140 posts with no reviewed editorial tier and 6 Pulse items with no salience, now owned by TIN-2891. This PR is restored to draft and remains shadow-only until TIN-2891 supplies real producer data, the UI is reconciled with the ratified design, and a separate promotion ruling is recorded.

@Jesssullivan

Copy link
Copy Markdown
Owner Author

Product/IA ruling — 2026-07-15

This PR remains draft and will not be promoted as written. Stream and Pulse are not separate top-level navigation items or product destinations. The canonical reader homepage owns the multi-surface composition: noteworthy, less-noteworthy, unclassified legacy content, and public Pulse as distinct strata. Observatory Ledger is the beta direction; the future constellation/Planetarium is a margin-respecting homepage element, not a route.

The tested primitives here remain useful and will be ported into a clean homepage lane: TierBadge, salience-aware Pulse cards, deterministic blend/schema logic, and focused tests. The /stream route, Stream/Pulse nav additions, and fixture-only promotion framing are superseded.

No production promotion occurs until the homepage lane is QA'd in its immutable PR environment against representative reviewed live tier/salience data and absent-data states, followed by explicit operator review.

@Jesssullivan

Copy link
Copy Markdown
Owner Author

Status (2026-07-15, per TIN-2413/TIN-2641 rulings): this PR is ratified as the primitives donor of record — TierBadge, stream/blend.ts, the salience-aware pulse cards, and their tests will be lifted AS-IS into the canonical / Observatory Ledger implementation (TIN-2903, design of record ratified 2026-07-15). The /stream route and Stream/Pulse nav are not promotion candidates. Per the donor-then-close ruling, this PR closes once the harvest lands under bazel/GF-RBE — it should not be merged. Known live issue on this branch's surface, tracked on TIN-2641: pulse snapshot carries 6 items but the render shows 3 (consumer drop, pre-rail triage required).

Jesssullivan added a commit that referenced this pull request Jul 15, 2026
…nts (TIN-2903)

NoteworthySpread (register 01) + LedgerRegister (register 02, capped 8 + archive
link) compose the harvested TierBadge; PulseRail composes the #217 PulseNoteCard/
PulseBirdCard donors and renders every snapshot item in producer order (no silent
cap); ConstellationSection exposes buildConstellationGroups as native details/summary
disclosures with an honest category/tag label.
Jesssullivan added a commit that referenced this pull request Jul 15, 2026
…thead control labels (TIN-2903)

BlogCard wiring lifted verbatim from feat/blog-tiered-reader-ui (the harvested TierBadge test exercises it); aria-labels added to the masthead toggle/pause buttons flagged by the build a11y pass.
Jesssullivan added a commit that referenced this pull request Jul 17, 2026
…d, pulse cards) — TIN-2903

Harvested byte-for-byte from origin/feat/blog-tiered-reader-ui:
- src/lib/components/TierBadge.svelte
- src/lib/components/TierBadge.test.ts
- src/lib/stream/blend.ts
- src/lib/stream/blend.test.ts
- src/lib/components/pulse/PulseNoteCard.svelte (adds TierBadge integration)
- src/lib/components/pulse/PulseBirdCard.svelte (adds TierBadge integration)
- src/lib/components/pulse/PulseCards.test.ts (co-located tier-badge tests)
Jesssullivan added a commit that referenced this pull request Jul 17, 2026
…nts (TIN-2903)

NoteworthySpread (register 01) + LedgerRegister (register 02, capped 8 + archive
link) compose the harvested TierBadge; PulseRail composes the #217 PulseNoteCard/
PulseBirdCard donors and renders every snapshot item in producer order (no silent
cap); ConstellationSection exposes buildConstellationGroups as native details/summary
disclosures with an honest category/tag label.
Jesssullivan added a commit that referenced this pull request Jul 17, 2026
…thead control labels (TIN-2903)

BlogCard wiring lifted verbatim from feat/blog-tiered-reader-ui (the harvested TierBadge test exercises it); aria-labels added to the masthead toggle/pause buttons flagged by the build a11y pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant