Skip to content

fix: a tree playground page, and the two bugs building it exposed - #3

Merged
yaotzin1 merged 1 commit into
mainfrom
fix/examples-and-source-swap
Sep 10, 2026
Merged

fix: a tree playground page, and the two bugs building it exposed#3
yaotzin1 merged 1 commit into
mainfrom
fix/examples-and-source-swap

Conversation

@yaotzin1

Copy link
Copy Markdown
Owner

What and why

Standing instruction: always update the examples. 0.3.0 shipped tree data, a bubble menu and inline
editing with tests, docs and a spec, and no way to click any of it.

Building the page found two defects that 269 tests had missed, because a test constructs a
component once and an application changes props.

The page

examples/playground/tree.html, over three shapes: nested children, flat rows with two parents,
and lazy children. Bubble menu, inline editing on three columns with different rules, a language
switcher, a "refuse every edit" toggle for watching rollback, and live nested set counters that
make the model legible. Eight nodes for six distinct rows is what "one row, two placements" looks
like.

examples/react-remote/App.tsx gains a tree section, so the tree API is type-checked with the rest.

The bugs

A changed dataSource prop never reached the engine. The guard compared the new prop against a
helper that reads the current props, so it compared the prop against itself, which is always equal,
and setDataSource was never called. Present since 0.1.0.

Changing the tree's input shape left every row a root. The controller chose between nested
children and parent references when it was built. It now asks on every normalise, which is better
than the rebuild I tried first: that cascaded, because plugins are fixed at engine creation, so the
engine kept a reference to a controller that had just been destroyed.

Expanding a node with children present fetched an empty list and replaced them. Fallout of the
fix above, since loadChildren became always-supplied. Loading now runs only for a node that
declared children and has none.

Regression tests for all three.

Semver classification

  • patch — no change to the public surface
  • minor
  • major

TreeControllerOptions gained an optional mode, which is additive.

Verification

Test Files  15 passed (15)
     Tests  271 passed (271)

Test Files   1 passed (1)      [smoke, against dist/]
     Tests  12 passed (12)

typecheck      exit 0
lint           exit 0
check-exports  the published package resolves cleanly.

Driven in a browser: switching to "Flat, with two parents" shows Shared.pdf under both folders,
expanding one leaves the other shut, and the bubble menu hides "Add child" on a file.

Self-review

  1. Boundary and layering — no layer moved. The controller now answers a question per call instead of at construction, which removed a rebuild and the destroyed-reference cascade behind it.
  2. The local/remote seam — the dataSource swap fix is exactly this seam working as documented for the first time.
  3. Public surface and semver — patch, one additive optional option.
  4. Accessibility and i18n — unchanged; the new page exercises the existing keyboard routes and the language switcher.
  5. Supply chain and packaging — no dependency. examples/ stays out of the tarball.
  6. Honest output — the page shows the nested set counters rather than describing them, and the "refuse every edit" toggle makes rollback visible instead of claimed.
  7. Verification — the gates above, plus CI now boots the new page.

Documentation

  • CHANGELOG.md under Unreleased, naming both bugs and that the examples found them
  • examples/playground/README.md gains the page and four things to try
  • specs/tree-data/tasks.md gains an Examples section
  • .agents/rules/agent_execution_standards.md makes it a rule, so it is planned at stage 4
    rather than remembered
  • workflow.ai.yml not affected; the sync scripts still pass with --check

Standing instruction from the user: always update the examples. 0.3.0 shipped
tree data, a bubble menu and inline editing with tests, docs and a spec, and no
way to click any of it.

## The page

examples/playground/tree.html, over three shapes: nested children, flat rows
with two parents, and lazy children. It has the bubble menu, inline editing on
three columns with different rules, a language switcher, a "refuse every edit"
toggle for watching rollback, and live nested set counters that make the model
legible: eight nodes for six distinct rows is what "one row, two placements"
looks like.

examples/react-remote/App.tsx gains a tree section, so the tree API is
type-checked with the rest and cannot drift.

## The two bugs it found

Neither was caught by 269 tests, because tests construct a component once and an
application changes props.

- A changed `dataSource` prop never reached the engine. The guard compared the
  new prop against a helper that reads the current props, so it compared the
  prop against itself, which is always equal, and setDataSource was never
  called. Present since 0.1.0.

- Changing the tree's input shape left every row a root. The controller chose
  between nested children and parent references when it was built. It now asks
  on every normalise, which is also better than the rebuild I tried first: that
  cascaded, because plugins are fixed at engine creation, so the engine kept a
  reference to a controller that had just been destroyed.

A third came out of the fix: always supplying loadChildren made every expand
fetch an empty list and replace real children with it. Loading now runs only for
a node that declared children and has none.

Regression tests for all three, plus the CI example job now boots the new page.

The rule is written into .agents/rules/agent_execution_standards.md and the tree
spec's task list, so it is planned at stage 4 rather than remembered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ndm72nQiMLvEqekHNJuAV
@yaotzin1
yaotzin1 merged commit 4a90576 into main Sep 10, 2026
6 checks passed
@yaotzin1
yaotzin1 deleted the fix/examples-and-source-swap branch September 10, 2026 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant