Skip to content

Releases: caweis/SideBar

v0.3.3 · regression-window diagnostic + render-library workaround budget + MapLibre vector recipe

18 May 07:36

Choose a tag to compare

Three new skills earned in one stretch of work on the reference planning app — a visible map bug that took six commits to chase down, only to discover the cause was in a completely different file.

New skills

regression-window-diagnostic — when a user says "this was working a few builds ago," the first move is git log against the timeframe and a full cross-repo diff against the last-known-good point, not edits to the file where the symptom appears. The cause is often in a global rule or shared helper that's nowhere near the symptom.

dont-fight-the-render-library — set a workaround budget. Two CSS / JS attempts to override library internals; if neither lands cleanly, the cheaper move is swapping the library, not stacking more overrides. Pairs with the regression-window skill: workarounds against an environmental cause never converge. Includes a failure-attempt log discipline so the swap decision is survivable later.

maplibre-vector-when-leaflet-seams — the specific recipe. Leaflet + raster tiles + Safari + HDPI produces visible subpixel tile seams; MapLibre GL JS + CartoDB Voyager vector style renders the whole map to a WebGL canvas with no inter-tile seams structurally possible. Same look, different render path. Migration notes including the [lat,lng] → [lng,lat] boundary flip, style-load gate, marker DOM preservation, popup CSS mirror, and partial-migration option.

Refinement

phase-clearance-gates — added the convergence vs participation distinction. Some phases clear when a majority of distinct voters have weighed in (each picks their own per-axis answer · lodging picks, RSVPs); others clear when a majority has agreed on a SPECIFIC shared option (one trip date, one city combo). Conflating the two ships "cleared" phases where three voters all picked different options and nothing actually won. Both flavors documented with example PHASE_CHAIN table.

Origin story

A user reported visible vertical lines on a Leaflet-rendered map. Six commits' worth of CSS workarounds (box-sizing reset, width:257px !important, will-change: transform, tile provider swaps) made the seams either no different or actively worse. The user's tell — "they weren't there a few builds ago" — turned out to be load-bearing diagnostic data. A cross-repo diff against the last-known-good point surfaced html,body{overflow-x:clip} from an unrelated horizontal-scroll fix commit two days earlier. The clip rule established a clipping context that subpixel-snapped descendant Leaflet tiles. Reverting the one line fixed the map without touching the map code.

The lessons: check the timeframe diff before editing the symptom file (skill 1), set a workaround budget so you don't grind through six attempts (skill 2), and if the library's render path genuinely doesn't fit the constraint, swap libraries (skill 3, the specific recipe).

What's also in here

  • docs/METHOD.md · regression-window addendum under Maxim 2 (Audit Before You Write)
  • README updated · 18 skills total (was 14), skill index alphabetized with the new entries

Sidebar v0.3.2 — extend-the-seed skill + Verifying contract extensions

09 May 22:52

Choose a tag to compare

A patch release with two pieces, both earned in production on a single afternoon working in the reference field-companion app.

skills/extend-the-seed.md — new skill

Captures the pattern for letting users extend a curated seed catalog without shipping N add-paths for N entity types. Five primitives:

  • Schema · added_by + added_at columns on every seed-extendable table (NULL = seeded, non-NULL = user-added)
  • Ad-hoc table · escape hatch for things that don't fit any seed schema (a small plans / notes / actions table)
  • API · one /api/add-item endpoint with kind dispatch + per-kind required-fields map. Adding a ninth kind = three small list updates.
  • UI · one shared sheet with per-context + Add buttons. Each button passes { fixedKind, parentId, onSuccess } so the kind is locked, the parent is pre-filled, the section reloads on success.
  • Render hooks · convert per-section IIFEs to named functions exposed on window (window.reloadPacking, window.reloadJournal, window.reloadChapter(stopId)) for targeted refresh after a successful add.

Plus a companion sub-pattern: catalog go/skip via the audit-log table (default = 'go', skip = a row with notes='skip', click 'go' from skip DELETEs the row — no soft-delete column needed). Mirrors the lounge-plan pattern from earlier substrate work.

Honest Reporting status disclosure at the top of the file: ONE production substrate as of writing, where eight kinds share one sheet. Schema and API primitives are general; UI specifics need adapting to your design system. Not a hypothesis about every coordination app — fits when you have a curated seed AND meaningful schemas already, doesn't fit for generic note-takers where everything is user-added.

docs/METHOD.md — Verifying contract extensions (new subsection under Maxim 19)

The discipline that catches a specific bug class earned twice on the same afternoon: when adding a new value to an existing list, the new value is what you test — not whether the old values still work. Two concrete examples:

  1. CSS [hidden] defeated by display: flex on a higher-specificity class. Existing uses worked; one new use silently failed. Curl tests would have passed.
  2. VALID_KINDS allowlist not extended for four new kinds. Endpoint correctly returned 400; client correctly reverted; feature looked like it worked for one frame, then undid itself.

Both bugs same shape: contract worked for old values, failed for new. Section codifies four habits that catch this — listing every place that needs to know about the new value, testing the new value (not the old ones), making rejections self-documenting, and visual end-to-end on every new entry-point.

docs/PATTERNS.md + README.md

Brief PATTERNS.md entry pointing at the new skill. README skill index bumped 13 → 14, "Latest release" callout updated to describe v0.3.2 with explicit honest framing.

Why a patch release, not minor

The skill is one-substrate work with explicit gating. The METHOD.md addition is a discipline subsection, not a new maxim. Neither piece changes the bundle's existing API, contracts, or expected usage. v0.4.0 stays reserved for something with multi-substrate validation or a meaningful new deliverable in the starter.

Pairs with prior releases

  • v0.3.1 shipped the Honest Reporting discipline — this release applies it (the skill's status disclosure, the careful one-substrate framing).
  • v0.3.0 shipped gameify-the-convergence — the catalog go/skip companion sub-pattern in extend-the-seed is "name the players" applied per item rather than per axis.
  • The Verifying contract extensions discipline cross-references extend-the-seed because that pattern is most likely to introduce the bug class the discipline catches.

Sidebar v0.3.1 — Honest Reporting + flight-search engine starter

08 May 23:19

Choose a tag to compare

Two changes in one patch release.

Maxim 12 sharpened · Honest Reporting discipline

Earned in production. An agent closed a session with prose that ratified the work using language ahead of the evidence — "the framing has now formally graduated to a transferable engineering pattern · proving the lens generalizes." The work was real; the sentence was not. A council of independent advisors caught the overclaim; the discipline is now in docs/METHOD.md so the same trap doesn't reset every session.

What's new in METHOD.md:

  • Maxim 12 text now explicitly extends the truthfulness obligation to the prose around the stoplight chart, not just the colored emoji rows
  • New Honest Reporting section after the Maxims with:
    • Two-event test for transfer claims (author articulation + non-author use; until both occur, the verb is "articulated" not "transferred")
    • Validation-language table — what proven / transferable / generalizes / validated / battle-tested actually claim
    • Honest substitutions — six overclaim phrases mapped to honest equivalents (proven to generalizearticulated in a form that could generalize, etc.)
    • One-substrate / multi-substrate gate for skills files
    • Three-words-for-a-bug-class diagnostic test for filing patterns
    • Closing-summary checklist to run before any session-end summary ships

The closer that backstops everything: "length over false confidence · trade for one more sentence of caveat every time."

Flight-search engine starter

New file starter/planning/site/flight-engines.js — canonical buildFlightUrl(engine, params) plus an ENGINES catalog. Ten engines pre-wired with deep-link URL templates earned in production:

  • Award · seats.aero · point.me · AwardFares · PointsYeah
  • Cash · Google Flights · ITA Matrix · Skyscanner · Kayak · Going · Hopper

Six accept pre-fill, four land on a form (ITA / Going / Hopper / Skyscanner-multi-city corner). Visual dimming + tooltip explanation in the starter cluster for the landing-only engines.

Wired into the planning starter as a "Search award seats & cash" section · single form drives all ten anchors via refreshFlightSearchHrefs(). Adding a new engine takes two lines: one switch case + one ENGINES entry.

bootstrap.sh deploy output now enumerates the engines alongside the gamification mechanics.

Honest framing

The flight-engines URL shapes are facts (extracted from real post-search dumps), not novel patterns. They will break when an engine ships a routing change. The file's opening comment says this explicitly. Test manually when something looks off.

Pairs with v0.3.0

The Honest Reporting discipline is the natural backstop to last release's gameify-the-convergence skill — extracting a lens into OSS is the articulation event, not the transfer event. v0.3.0 was the articulation; transfer would be measured by third-party use, which has not yet occurred. v0.3.1 is the discipline to keep stating that honestly.

Sidebar v0.3.0 — gameify the convergence

06 May 23:32

Choose a tag to compare

The thing nobody tells you about multi-household coordination apps: the failure mode isn't disagreement, it's silence. Everyone has an opinion. Nobody clicks. The app turns into an opinion poll where the loudest household decides because they were the only one who recorded a vote.

The fix isn't more reminders. It's making the state of each decision legible enough that the group closes it themselves.

What's new

  • skills/gameify-the-convergence.md — the full lens. Five mechanics that work in adult coordination contexts (visible score · named players · phase gates as level unlocks · personal recognition · actionable items only) and four anti-patterns to avoid (no streaks · no leaderboards · no badges · no game-y vocabulary).
  • starter/planning/site/index.html — all five mechanics wired into the date-vote section as the canonical example. Phase chip strip across the top, per-axis context block (▰▱ score bar + voted + pending + unlock target), ✓ personal indicator on the user's chosen card. Tiny canonical helpers (PHASE_CHAIN, phaseCleared, pendingHouseholds, scoreBar, renderPhaseChips, renderAxisContext) so the data flow is visible before you extend it to your own axes.
  • starter/bootstrap.sh — deploy output enumerates the five mechanics so new operators see what they got out of the box without grepping the source.
  • docs/PATTERNS.md — new entry pointing at the skill, summarizing the lens in two paragraphs.
  • README.md — skill index 11 → 12, new entry sorted in.

Pairs with

The skill cross-references the existing phase-clearance-gates, canonical-data-audit, and mode-of-tuples-voting skills · the gamification surfaces are how those infrastructure patterns become visible to the user.

Earned in production

The mechanics + the anti-patterns came out of the Alpenelf digest rebuild this week. The original email had a buried "(2 of 5)" parenthetical, raw usernames in the VOTED line, no chain context, and no personal achievement signal. After applying the lens: visible ▰▰▱▱▱ bar, household labels canonical with the SPA, chain chip strip up top, ✓ dates / · cities personal row. Same data, half the noise, materially more "go vote" pull.

Sidebar v0.2.1 — bootstrap safety guards

03 May 14:54

Choose a tag to compare

A defensive patch on top of v0.2.0. Same starters, safer bootstrap.

wrangler pages deploy --project-name X silently overwrites an existing Pages project named X — that's a footgun if your CF account already has unrelated production deployments and you typo'd a base name. v0.2.1 adds three guardrails so bootstrap can't blow away anything.

What's new

  • Pre-flight collision checkbootstrap.sh now queries wrangler pages project list and wrangler d1 list and aborts with a clear error if any of the planned names already exist on your account. Word-boundary match, deliberately conservative.
  • Explicit confirmation prompt — after the name is chosen, the script prints exactly what's about to be created (Pages projects + D1 databases) and waits for y before any wrangler create/deploy step runs.
  • Random-suffix default name — the project-name prompt now suggests sidebar-demo-${4-hex-chars} as the default. Accept the default and accidental collisions are nearly impossible.
  • README updated — new "Why the safety guards matter" section explaining the pages deploy overwrite behavior so people understand what they're consenting to.

Behaviour change

Bootstrap.sh now refuses to deploy on top of any existing Pages project or D1 database with a matching name. Re-deploys of the same project name must be done manually (delete the existing resources first, or run wrangler pages deploy ./planning/site --project-name X directly and skip the bootstrap). Considered "make bootstrap idempotent on re-run" — decided against, because correctly distinguishing "same project, redeploy" from "different project, name collision" requires checking specifics that wrangler doesn't easily expose. Refuse-and-explain is the safer default.

Heads up

  • Same license as before: PolyForm Noncommercial 1.0.0.
  • v0.2.0 stays tagged at the unsafe-bootstrap state for anyone who wants to fork from there. Do not recommend.
  • The collision-check parsing is grep-based; if your wrangler output format diverges from the standard table, the check might false-positive (refuse to deploy) or rare false-negative. Errs on the side of refusing, which is the right way to fail.

Sidebar v0.2.0 — runnable starter scaffold

03 May 14:48

Choose a tag to compare

You can now actually deploy Sidebar.

./starter/bootstrap.sh is an interactive one-shot — pick planning, field, or both, give it a project name, and it creates the D1 databases, runs migrations, and deploys to your Cloudflare account. The only thing left is configuring Cloudflare Access on the deployed URLs (it'll print the dashboard steps).

What's new

  • starter/planning/ — multi-household voting + coordination, ~700 lines of HTML/JS. Single-axis votes, multi-field votes with mode-of-tuples aggregation, activity log, canonical-data shared module. Real working demo, not a stub.
  • starter/field/ — offline-first execution notebook with per-user E2E-encrypted journal, ~900 lines. Trip metadata, seeded place catalog, completion toggles, encrypted journal entries (PBKDF2 200k → AES-GCM 256, server stores opaque ciphertext, key-check pattern), service worker.
  • starter/bootstrap.sh — interactive deploy: npm installwrangler loginwrangler d1 createwrangler d1 migrations applywrangler pages deploy. Idempotent on rerun.
  • docs/DATA-MODEL.md — expanded with the field-companion schema (catalog tables, completions tracker, per-user encryption) and a coupling-handoff section explaining what flows from the planning DB to the field DB at trip-start time.
  • README — note about Claude Code as the coding agent + deployment method that built this.

Heads up

  • v0.1.0 is still tagged at the original docs-only release for forking from that point.
  • Both starters are minimum-viable on purpose — multi-category voting, RSVPs, photo galleries, weather caches all live in the reference apps but not here. The Sidebar method (see docs/METHOD.md) is the discipline that keeps that growth tractable as you extend.
  • The bootstrap script can't configure Cloudflare Access for you — it prints the dashboard steps when it's done.

Same license: PolyForm Noncommercial 1.0.0. Free for personal, hobby, research, charitable, educational use. Commercial needs a separate license; ping me.

Sidebar v0.1.0 — initial public release

03 May 13:46

Choose a tag to compare

Sidebar is what fell out when I tried to write down what actually made two small Cloudflare-edge coordination apps work — not the version I'd say at a conference, but the version I'd hand my past self to save the Sundays I lost to specific bugs. Two apps in production for my own family seeded everything in here.

What's inside: 22 maxims (load-bearing rules, not aspirations); a Cloudflare Pages + D1 + Functions architecture that survives real users with no build step and no React; a coupling pattern that explains why the planning app and the field-companion app are two apps and not one; a small skill library, where each entry is a specific scar from a specific bug; a starter scaffold; and an agent persona for Claude Code — the Sidebar engineer — that carries the protocol in one file.

Licensed under PolyForm Noncommercial 1.0.0. Free for personal, hobby, research, charitable, and educational use. Commercial use needs a separate license; ping me and we'll figure it out.

This is v0.1 — first time it's been outside my house. Things will get rewritten. If something's broken or unclear, open an issue or fork it and tell me.