-
-
Notifications
You must be signed in to change notification settings - Fork 3
fix(effort-viz): make primitive and lifecycle legible at a glance #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5556d50
223f64c
e071219
757c2db
a4f466b
f4bd85b
e900cd1
eda6222
20e8f0b
b0e51cb
a95f447
d2eeba1
78a2f09
4386ad7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| --- | ||
| id: dec-keep-effort-graph-as-the-product-name--r5wr2vdjwjs9bs13 | ||
| effort: eff-flatbread-product-branding--zt7b35sa05kyvhdz | ||
| title: Keep Effort Graph as the product name | ||
| state: accepted | ||
| created_at: '2026-07-26T03:27:20.788Z' | ||
| derives_from: | ||
| - fnd-crumb-rebrand-refuted-in-review-effort-graph-is--n8kb269z7vz8jhyk | ||
| supersedes: | ||
| - dec-brand-the-agent-memory-surface-as-crumb-trail--tngncepdbwjkh9jc | ||
| --- | ||
|
|
||
| Supersedes Crumb Trail (and, transitively, Crumb Graph). The rebrand line is refuted: **Effort Graph** is the product name for Flatbread's longform agent memory, and crumb naming is dropped entirely rather than retained as a datamodel explainer. | ||
|
|
||
| ## Context | ||
|
|
||
| Two prior Decisions moved the brand from Effort Graph to Crumb Graph and then to Crumb Trail, each time deferring the package, CLI, path, and skill renames. Review of the accumulated naming stack found the crumb metaphor works against the product: crumbs connote leftovers in a system whose pitch is durable, trustworthy reasoning, and _crumb trail_ is already taken by breadcrumb navigation in UI vocabulary. Meanwhile every identifier a user touches — `@flatbread/effort-graph`, `flatbread effort`, `.flatbread-efforts/`, the `effort-graph` skill — still said Effort. | ||
|
|
||
| ## Decision | ||
|
|
||
| Adopt **Effort Graph** as the product name, not merely an allowed technical descriptor. Retire **Crumb Graph** and **Crumb Trail**; neither is a product name, a datamodel explainer, nor a documented alias. | ||
|
|
||
| Describe the datamodel in plain terms — Effort-scoped relational records with typed edges and bounded digests — instead of coining a second branded layer for it. | ||
|
|
||
| No rename work is required or deferred: code, packages, CLI, paths, and skills already match the product name, and that alignment is now the point rather than a coincidence. | ||
|
|
||
| ## Alternatives considered | ||
|
|
||
| - **Keep Crumb Trail as the brand and finally execute the renames.** Rejected: it pays a full breaking-rename cost to buy a metaphor that review judged actively misleading. | ||
| - **Keep Crumb Trail for marketing, Effort Graph in code.** Rejected: this is the status quo the prior Decisions created, and it is the failure mode — a permanent gap between what the docs call the product and what every command and import path calls it. | ||
| - **Keep Crumb Graph as a datamodel explainer only.** Rejected: a second branded vocabulary for the same graph adds a translation step without adding precision over saying Effort-scoped records and edges. | ||
| - **Pick a third unleavened, Proof-peer name.** Rejected for now: naming churn has already cost two Decisions and two stale Issues, and no candidate beats the name that the API already teaches. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - Docs, skills copy, and product messaging use Effort Graph with no crumb aliases; existing crumb references are wording bugs to fix, not variants to preserve. | ||
| - The rename Issues under this Effort close as wontfix — the work is cancelled, not postponed. | ||
| - Brand and implementation vocabulary are unified, so future naming pressure has to argue for renaming real identifiers rather than only marketing copy. | ||
| - Flatbread gives up a bread-metaphor peer to Proof for this surface. That is accepted: primitive fidelity beats metaphor symmetry here. | ||
|
|
||
| ## Reversal criteria | ||
|
|
||
| Revisit only if Effort Graph measurably fails external comprehension — for example if users read Effort as project-management effort tracking or story points rather than a thread of work — and a candidate name wins while committing to rename the packages, CLI, and paths in the same Decision rather than deferring them again. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| --- | ||
| id: fnd-crumb-rebrand-refuted-in-review-effort-graph-is--n8kb269z7vz8jhyk | ||
| effort: eff-flatbread-product-branding--zt7b35sa05kyvhdz | ||
| title: Crumb rebrand refuted in review; Effort Graph is the retained name | ||
| kind: dead-end | ||
| created_at: '2026-07-26T03:26:52.792Z' | ||
| derives_from: | ||
| - fnd-postable-brand-names-favor-trail-over-graph--zzpgaw0kvqtaqmxt | ||
| - fnd-workshop-shortlist-favors-crumb-graph-over-yeast--tv3ydt3wfb3n4y0g | ||
| --- | ||
|
|
||
| ## What happened | ||
|
|
||
| The Crumb Graph → Crumb Trail branding line was grilled in review and refuted. The owner call is to keep **Effort Graph** as the product name for Flatbread's longform agent memory, not as a fallback technical alias. | ||
|
|
||
| ## Why the rebrand did not hold | ||
|
|
||
| - **Crumb reads as leftovers, not memory.** In a product about durable reasoning, the metaphor undercuts the value claim: crumbs are what falls off the loaf, not the record you are meant to trust. | ||
| - **Crumb collides with breadcrumbs.** In UI vocabulary a crumb trail is a navigation path widget. Users landing on the docs pattern-match to breadcrumb navigation before they reach agent memory. | ||
| - **Effort Graph already names the load-bearing primitive.** Every record belongs to exactly one Effort. A brand that hides the Effort primitive forces a second vocabulary on top of the one the API, CLI, and skills already teach. | ||
| - **The rebrand's own reversal criteria fired.** Both prior Decisions listed external-comprehension failure and crumb ≈ breadcrumbs/scraps confusion as revisit triggers. Review found exactly those failures, so the Decisions closed themselves out on their stated terms. | ||
| - **Deferring implementation hid the cost.** Both Decisions deferred the package/CLI/path/skill renames, which kept the accepted brand permanently out of sync with every identifier a user actually touches. | ||
|
|
||
| ## Standing evidence | ||
|
|
||
| The two workshop Findings remain accurate as records of what those exercises produced — the shortlist did favor crumb over yeast metaphors, and trail did test as more postable than graph. Neither is invalidated. What is refuted is treating brandability as decisive over primitive fidelity and collision risk. | ||
|
|
||
| ## Consequence | ||
|
|
||
| The rename work tracked by both implementation Issues is a dead end and should close as wontfix rather than stay open as latent debt. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| --- | ||
| id: fnd-supersession-transitions-decision-state-on-the-r--2m807tcfjz2jz9gt | ||
| effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 | ||
| title: >- | ||
| Supersession transitions Decision state on the retro-link path but not on | ||
| create | ||
| kind: survey | ||
| created_at: '2026-07-26T05:06:57.371Z' | ||
| --- | ||
|
|
||
| ## Observation | ||
|
|
||
| `packages/effort-graph/src/planner.ts` has two code paths that create a `supersedes` edge, and they disagree about whether the superseded Decision changes state. | ||
|
|
||
| - **Retro-link (`Supersede` mutation), planner.ts ~195-215.** When the target is a Decision it composes `supersedeDecisionLifecycle(snapshot, b.id).nextFrontmatter`, which sets `state: 'superseded'`, then appends the `superseded_by` back-pointer. | ||
| - **Inline on create (`WriteDecision` with `supersedes: [...]`), planner.ts ~127-160.** The generic forward-edge loop only appends the `superseded_by` reverse projection. It never consults `supersedeDecisionLifecycle` and never touches `state`. | ||
|
|
||
| ## Evidence | ||
|
|
||
| Two records in this repo's own graph show the create-path outcome — both carry `superseded_by` while still reporting `state: accepted`: | ||
|
|
||
| - `dec-brand-the-agent-memory-surface-as-crumb-graph--fvskcvagx3a7sybe` | ||
| - `dec-brand-the-agent-memory-surface-as-crumb-trail--tngncepdbwjkh9jc` | ||
|
|
||
| `DecisionFrontmatterSchema` in `schemas.ts` already admits `'superseded'`, and `decision-lifecycle.ts` exists to produce it, so this is an inconsistency between the two paths rather than a deliberate modelling choice. | ||
|
|
||
| The blind spot is a test gap: the planner suite covers the create path with `supersedes` only for Findings, which have no state field, so the Decision case is unexercised. | ||
|
|
||
| ## Why it matters beyond cosmetics | ||
|
|
||
| - `planner.ts` gates `MitigateRisk` on `state !== 'accepted'`, so a superseded Decision can currently mitigate a Risk. | ||
| - `flatbread effort records --state accepted` returns retired Decisions. | ||
| - Consumers reading `state` directly label retired reasoning as committed. `examples/effort-viz` now carries a dedicated module (`lib/lifecycle.ts`) that derives effective lifecycle from edges specifically to work around this. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,16 +3,20 @@ id: iss-implement-crumb-trail-rename-across-packages-cli--316rdzpt80sdxkw1 | |
| effort: eff-flatbread-product-branding--zt7b35sa05kyvhdz | ||
| title: 'Implement Crumb Trail rename across packages, CLI, paths, and skills' | ||
| kind: gap | ||
| status: open | ||
| status: wontfix | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HIGH ( Minimal fix: Append a short resolution note that the rename is cancelled and Effort Graph is the product name. (Same issue on the Crumb Graph twin Issue.) |
||
| created_at: '2026-07-19T03:54:27.962Z' | ||
| derives_from: | ||
| - dec-brand-the-agent-memory-surface-as-crumb-trail--tngncepdbwjkh9jc | ||
| supersedes: | ||
| - iss-implement-crumb-graph-rename-across-packages-cli--dp6jvt2kafab7m4t | ||
| resolved_by: | ||
| - dec-keep-effort-graph-as-the-product-name--r5wr2vdjwjs9bs13 | ||
| --- | ||
|
|
||
| Supersedes the Crumb Graph rename Issue. Branding now targets Crumb Trail as the product name (Crumb Graph = datamodel explainer; Effort Graph = technical descriptor). | ||
|
|
||
| Implementation remains pending. Likely touchpoints (non-exhaustive): `@flatbread/effort-graph`, `effortGraphContent`, `flatbread effort` CLI, `.flatbread-efforts/`, `.flatbread/effort-graph/`, agent skill name/paths, docs/README copy, error codes (`EFFORT_GRAPH_*`), and dogfood references. | ||
|
|
||
| Do not start the mechanical rename until an implementation plan chooses which identifiers move vs stay for compatibility, and how Crumb Trail / Crumb Graph / Effort Graph map onto public vs internal names. | ||
|
|
||
| Resolution: cancelled as `wontfix`; product name is Effort Graph; resolved by `dec-keep-effort-graph-as-the-product-name--r5wr2vdjwjs9bs13`; do not reopen rename work. | ||
|
Comment on lines
+21
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HIGH ( Minimal fix: Rewrite the body lead to past-tense cancellation (Effort Graph retained per |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| --- | ||
| id: iss-writedecision-with-supersedes-leaves-the-superse--by624gyf21ex42sv | ||
| effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 | ||
| title: WriteDecision with supersedes leaves the superseded Decision in state accepted | ||
| kind: defect | ||
| status: open | ||
| created_at: '2026-07-26T05:07:15.240Z' | ||
| derives_from: | ||
| - fnd-supersession-transitions-decision-state-on-the-r--2m807tcfjz2jz9gt | ||
| --- | ||
|
|
||
| ## Problem | ||
|
|
||
| Creating a Decision with an inline `supersedes` edge appends the `superseded_by` reverse projection to the target but leaves its `state` untouched, so a replaced Decision keeps reporting `state: accepted`. The `Supersede` retro-link mutation on the same target does set `state: superseded`. Same semantic act, two different outcomes depending on which mutation got there first. | ||
|
|
||
| ## Fix sketch | ||
|
|
||
| In the create-path forward-edge loop in `packages/effort-graph/src/planner.ts`, when `edge === 'supersedes'` and the target is a Decision, compose `supersedeDecisionLifecycle(snapshot, target.id).nextFrontmatter` before appending the back-pointer — the same composition the `Supersede` branch already performs. Add a planner test mirroring the existing retro-link supersession test but driven through `WriteDecision`, since the current create-path test only covers Findings and so cannot catch this. | ||
|
|
||
| ## Repair | ||
|
|
||
| Two records in this repo already carry the bad shape (`dec-brand-the-agent-memory-surface-as-crumb-graph--fvskcvagx3a7sybe`, `dec-brand-the-agent-memory-surface-as-crumb-trail--tngncepdbwjkh9jc`). Repair them through the reindexer rather than by hand-editing frontmatter. | ||
|
|
||
| ## Scope note | ||
|
|
||
| Consumers should keep deriving supersession from edges regardless of the fix: forward edges are the authoritative representation, and edge-derived state also covers legacy and hand-edited records. `examples/effort-viz/lib/lifecycle.ts` does this and should not be reverted once the writer is corrected. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,19 +36,69 @@ Flatbread serves GraphQL at **`http://localhost:5057/graphql`**. The app | |
| subscribes to **`http://localhost:5057/events`** (SSE) for schema generation | ||
| updates. | ||
|
|
||
| ## What you get | ||
| ## What you can read off it | ||
|
|
||
| Within a few seconds of opening the page you should be able to answer: | ||
|
|
||
| - **What kinds of records are here?** Every primitive has its own hue *and* its | ||
| own silhouette — Issues are amber diamonds, Findings blue circles, Decisions | ||
| violet squares, Constraints green/teal slabs (flat bars), Risks red triangles, | ||
| and each Effort is a ring whose core carries that cluster's tint. | ||
| - **What is still live, and what got overturned?** Rejected, superseded, | ||
| invalidated, won't-fix, deprecated, and abandoned records fade to a | ||
| desaturated ghost with a struck-through label. Supersession is derived from | ||
| the graph's edges rather than from frontmatter, because forward edges are the | ||
| authoritative representation and `state` can lag behind them — a Decision | ||
| replaced through an inline `supersedes` still records `state: accepted`, so | ||
| reading the field alone would label retired reasoning as committed. | ||
| - **What is blocking?** Open Issues with `kind: blocker` wear an amber warning | ||
| outline. | ||
| - **How much work is tracked?** The header counts primitives and lifecycle | ||
| (`5 Efforts · 4 open Issues · 3 proposed Decisions`) rather than nodes and | ||
| edges — roughly half the "edges" are synthesised membership spokes, so a raw | ||
| edge count flatters the graph without informing anyone. | ||
|
|
||
| ## Encoding notes | ||
|
|
||
| Hue belongs to the **primitive**, not the Effort. Effort membership is already | ||
| carried by three other channels — the force layout pulls same-Effort records to | ||
| a shared centroid, each cluster has a large labelled hub, and membership spokes | ||
| take the cluster's tint — so spending the strongest nominal channel on it left | ||
| record kind with nothing. Shape repeats hue as a colour-vision backstop, since | ||
| amber/red and blue/violet partially merge under deuteranopia. Silhouettes are | ||
| area-normalized (`lib/glyphs.ts`) so a triangle and a square read at the same | ||
| visual weight; otherwise size would imply an importance ranking nobody | ||
| intended. | ||
|
|
||
| The legend derives its swatches from the same outlines and palette the canvas | ||
| builds geometry from (`lib/glyphs.ts`, `lib/primitives.ts`), so it cannot drift | ||
| from the render, and it only lists the relations the current generation actually | ||
| contains. | ||
|
|
||
| ## Other features | ||
|
|
||
| - **Live graph** — `useEffortGraphLive` opens an `EventSource` on `/events`. | ||
| On `ready` and each `generation` event it refetches the Effort Graph query and | ||
| updates the canvas. The status pill shows connecting / live / disconnected and | ||
| the current generation. | ||
| updates the canvas. The status pill shows connecting / live / partial / | ||
| disconnected / error and the current generation. **Partial** means records | ||
| loaded but relationship fields could not be confirmed yet — retirement links | ||
| may be missing until the next successful schema probe. | ||
|
Comment on lines
+82
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MED ( Minimal fix (this round): One sentence that sticky cached schema keeps Live; only a successful re-probe picks up new relation fields. Do not require a Partial code flip unless product wants it. |
||
| - **Watch mode** — `flatbread start --watch` reloads content and config changes | ||
| under `.flatbread-efforts`. Edit an effort, issue, or finding file and the | ||
| under `.flatbread-efforts`. Edit an Effort, Issue, or Finding file and the | ||
| graph animates in/out without restarting Next. | ||
| - **R3F canvas** — orthographic 2D scene with pan/zoom, node labels, edge | ||
| “veins”, spawn/retract physics, and a detail drawer on node click. | ||
| - **Theme** — sun/moon toggle in the top bar; preference persists in | ||
| `localStorage` (`effort-viz-theme`) with a boot script to avoid FOUC. | ||
| - **R3F canvas** — orthographic 2D scene with pan/zoom, cluster labels, edge | ||
| “veins”, spawn/retract physics, and a detail drawer on record click. | ||
| - **Keyboard** — Tab to the canvas, then arrow keys to walk records in a stable | ||
| Effort-then-primitive order, Enter to open the drawer, Escape to close. The | ||
| camera follows focus and each move is announced to screen readers. The canvas | ||
| itself is still a WebGL surface, so this is a focus proxy rather than a full | ||
| DOM mirror of the graph. | ||
| - **Reduced motion** — `prefers-reduced-motion` settles the layout and finishes | ||
| every growth animation before the first paint, and the camera snaps instead | ||
| of easing. | ||
| - **Theme** — sun/moon toggle in the top bar. The app follows | ||
| `prefers-color-scheme` until you pick a mode, after which the choice persists | ||
| in `localStorage` (`effort-viz-theme`) with a boot script to avoid FOUC. | ||
|
|
||
| ## Scripts | ||
|
|
||
|
|
@@ -58,7 +108,7 @@ updates. | |
| | `pnpm play:efforts` | Same as `dev`, from the monorepo root. | | ||
| | `pnpm --filter effort-viz build` | `flatbread start` wrapping `next build` (Flatbread must be up during the build). | | ||
| | `pnpm --filter effort-viz start` | Production Next only (`next start`); run Flatbread separately if needed. | | ||
| | `pnpm --filter effort-viz test` | Physics/simulation unit tests under `lib/physics/`. | | ||
| | `pnpm --filter effort-viz test` | Unit tests: physics/simulation, normalizer, lifecycle derivation, glyph invariants. | | ||
| | `pnpm --filter effort-viz exec tsc --noEmit` | Typecheck without running dev servers. | | ||
|
|
||
| ## Configuration | ||
|
|
@@ -74,7 +124,13 @@ updates. | |
| - `app/` — layout, theme tokens, R3F canvas and UI chrome | ||
| - `app/hooks/useTheme.tsx` — light/dark context + FOUC boot script | ||
| - `app/components/` — `EffortGraphApp`, `GraphCanvas`, `TopBar`, `Legend`, | ||
| `DetailDrawer` | ||
| `DetailDrawer`, `RelationLegend` (shared relation + badge metadata) | ||
| - `lib/primitives.ts` — per-primitive label, hue, and glyph: the encoding's | ||
| single source of truth | ||
| - `lib/glyphs.ts` — area-normalized glyph outlines shared by the canvas and the | ||
| legend | ||
| - `lib/lifecycle.ts` — effective lifecycle derived from edges, plus the header | ||
| summary | ||
| - `lib/physics/` — force simulation, growth, and layout helpers | ||
| - `lib/query.ts` — Effort Graph GraphQL query | ||
| - `flatbread.config.js` — Effort Graph content preset | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HIGH (
docs-and-positioning) — This PR addssuperseded_bybut leavesstate: acceptedand a body that still commits to Crumb Trail as the product name. Frontmatter, edges, and prose disagree.Minimal fix: Repair via reindexer (
state: superseded) periss-writedecision-with-supersedes-…, or add a top-of-body supersession banner pointing atdec-keep-effort-graph…until repaired.