Releases: caweis/SideBar
v0.3.3 · regression-window diagnostic + render-library workaround budget + MapLibre vector recipe
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
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_atcolumns 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/actionstable) - API · one
/api/add-itemendpoint withkinddispatch + per-kind required-fields map. Adding a ninth kind = three small list updates. - UI · one shared sheet with per-context
+ Addbuttons. 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:
- CSS
[hidden]defeated bydisplay: flexon a higher-specificity class. Existing uses worked; one new use silently failed. Curl tests would have passed. VALID_KINDSallowlist 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 inextend-the-seedis "name the players" applied per item rather than per axis. - The
Verifying contract extensionsdiscipline cross-referencesextend-the-seedbecause that pattern is most likely to introduce the bug class the discipline catches.
Sidebar v0.3.1 — Honest Reporting + flight-search engine starter
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-testedactually claim - Honest substitutions — six overclaim phrases mapped to honest equivalents (
proven to generalize→articulated 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
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
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 check —
bootstrap.shnow querieswrangler pages project listandwrangler d1 listand 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
ybefore 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 deployoverwrite 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
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 install→wrangler login→wrangler d1 create→wrangler d1 migrations apply→wrangler 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
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.