Skip to content

feat: layered database structure and AI guidance skills#150

Open
krisnye wants to merge 28 commits into
mainfrom
knye/ai-layered-structure
Open

feat: layered database structure and AI guidance skills#150
krisnye wants to merge 28 commits into
mainfrom
knye/ai-layered-structure

Conversation

@krisnye

@krisnye krisnye commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Formalizes a feature-oriented architecture for @adobe/data apps, encodes it as path-injected AI rules, and ships composable build skills that generate it — with four worked samples.

The feature structure

Each feature is a features/<name>/ folder in four layers (higher imports lower):

  • data/ — the pure spec: the whole feature as one immutable State with pure, fully-tested transforms. The source of truth; performance irrelevant.
  • services/ — async capability contracts (optional).
  • ecs/ — the efficient implementation: a layered Database.Plugin stack (core → index → transaction → computed → service → action → system), each layer its own namespace; the assembled top aliased once as FeatureDatabase so consumers never name the varying topmost layer.
  • ui/ — presentation (lazy wrapper / container / pure render / css).

data/ (spec) and ecs/ (impl) are tied by conformance: a test-only State↔store projection proves each transaction/system equal to the pure transform it stands for, so the ecs layer can be largely mechanical and agent-generated. Apps compose features — one base host + lazily-loaded peers whose schema the base imports without type/bundle coupling.

Matching AI rules — packages/data-ai/.claude/rules/

Distributable .md rules whose paths: globs mirror the folder tree one-to-one: editing ecs/transactions/foo.ts injects exactly that layer's rule plus the cross-cutting ones (namespace, data-modelling, type-casts, conformance, …). Guidance lives at the same path shape as the code it governs, present at authoring time.

Build skills — packages/data-ai/skills/

Composable build-* leaf skills (build-data, build-core-database, build-transactions, build-computed, build-systems, build-ui, …) piped bottom-up by build-feature, and by build-application / build-game. meta-build drives the loop and polishes the rules/skills against a concrete app prompt.

Samples + core support

Worked samples: data-lit-asteroids (real-time ECS — systems, spatial broad-phase, swept collision), and data-lit-todo / data-lit-tictactoe conformed to the pattern. Supporting @adobe/data: equalsUnordered, Database.toSystemDatabase (writable-store lens), DatabaseElement accessor/restriction fixes.

Test plan

  • Workspace pnpm typecheck + pnpm lint green
  • Sample suites green (asteroids 148, todo 79, tictactoe 34, p2p 7)
  • data-ai skills install/resolve

krisnye and others added 28 commits July 16, 2026 14:46
Move samples toward namespaced database layers and expand data-ai skills so agents can follow the same structure.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ture

# Conflicts:
#	packages/data-lit-todo/package.json
#	packages/data-p2p-tictactoe/src/state/negotiation-plugin.ts
…tore

Restructure both samples into the four-layer feature model and fix the
supporting core types at the source.

Core @adobe/data
- Remove the separate transaction-context type. `Store` now carries `userId`
  and its index handles (`IX`); `ToStore<P>` includes indexes + partition
  keys. Transaction functions operate on `Store` directly — a store *is* the
  transaction context. Deletes `TransactionContext` / `ToTransactionContext`.
- Fix `UIService.FromService` misclassifying a plain async fire-and-forget
  action (`() => Promise<void>`) as a transaction overload and wrongly
  requiring an argument; a genuine transaction has a synchronous commit
  signature (never a Promise), which is the correct discriminator.

Samples (tic-tac-toe, todo)
- `data/` is the specification: one immutable `State` with pure, unit-tested
  transforms/derivations. `ecs/` is the materialised view; computeds and
  transactions are verified against the `data/` precedent by conformance
  tests. Add `services/` (async ports) and `ui/`.
- Facet-named database layers, no feature/app names in the ladder:
  Core -> Index -> Transaction -> Computed -> Service -> Action.
- todo: async name-generator service, todo-analytics service, and an
  `actions/` layer where the UI dispatches actions that record analytics and
  call one transaction (async action brackets the slow call for timing).

Rules & tooling
- Path-mapped `structure/` rules mirroring the feature folders (adds
  data/state, ecs/actions); README + skill bundle updated.
- Require Node >=22 (engines + .nvmrc) so live-reactivity paths are testable.

Full-monorepo typecheck clean; test suite green on Node 22.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ests

Builds on the layered feature architecture with lazily-loaded features, a
many-to-many index demo, and a presentation-testing utility — plus fixes to
analytics, computed sharing, and flaky tests.

Multi-feature app (data-lit-todo)
- Restructure the sample into src/features/{main,assign}/. `main` imports each
  peer feature's *schema* plugin (Database.Plugin `imports`, not `extends`) so
  the shared store knows every schema without type-coupling or bundling the
  feature's behavior.
- Feature elements lazily extend the live database on first connect
  (DatabaseElement), so a feature's indexes/transactions/UI load only when used.
- New `assign` feature: a User archetype, a unique `usersByName` index and a
  multi-value `todosByAssignee` index — the todo<->user many-to-many navigable
  both ways; assignee dropdown + Users tab load lazily.

Services / actions
- todo-analytics is now named, strongly-typed methods (event vocabulary and
  formatting owned by the service), with a stateless opaque timing token from
  randomTodoRequested handed back to randomTodoAdded; named-object args.

Core @adobe/data
- Wrap db.derive computeds in Observe.withCache so N subscribers share one
  computation (red/green test).
- Convert flaky wall-clock perf assertions to non-fatal warnings; the suite is
  now deterministic and exits 0.

Presentation testing (@adobe/data-lit)
- Add Template — a DOM-free query over a Lit TemplateResult
  (text/values/children/has/find) for asserting what a pure render(props)
  declares. Pure and tree-shakeable.
- Make todo-row-presentation pure (move the drag hook into the element).
- Unit-test every Lit presentation in the repo (tictactoe, todo, p2p) via
  Template; jsdom only where module-load side effects require it.

Rules updated for multi-feature composition, indexes/m2m, and the presentation
testing pattern. Full-monorepo typecheck clean; test suite green on Node 22.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each vec/quat/mat4x4/line/plane function now lives in its own file with
only the imports it uses, collected by the folder's public.ts barrel.
Remove the <type>-functions.ts exemption from namespace.md; multi-export
is now allowed only by explicit per-file/per-file-type approval. Delete
the dead, unreferenced quat/constants/functions.ts duplicate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename each feature's core-database to persistent-database (the durable,
serializable data model) and add a session-database layer that extends it,
holding transient session state and the archetypes (a packing convenience,
not persisted). Session components/resources declare nonPersistent: true
explicitly. Add assertPersistencePartition to @adobe/data/ecs and a
feature-root persistence-partition test per feature to verify the split.
Fix a latent add-user guard that treated user entity id 0 as "not found".

Also bundles the prior branch's uncommitted sample import-path corrections
and layer-isolation rule-doc edits so the branch builds green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ared

Add a nonShared schema flag and built-in component to @adobe/data (declared
consistently with nonPersistent; no database behavior wired — smart-id work
deferred). Restructure each feature's ECS schema into scope layers by the two
orthogonal axes (shared/local × durable/ephemeral): document-database
(shared+durable), optional settings-database (local+durable, nonShared),
optional session-database (local+ephemeral, both flags); archetypes move to
their own archetype-database layer above the scopes. Rename core→document;
displayCompleted becomes a durable-local setting; dragPosition gains nonShared.
Generalize the feature-root check to assertSchemaScopes and update the rules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add Database.scope — document/settings/presence/session map transforms that
stamp each scope's flag pair (document is identity), applied once where a layer
is composed (e.g. components: Database.scope.session(components)) rather than
per component/resource file. Component/resource files become scope-agnostic
data re-exports; the layer states the scope. Unit-test the transforms; the
feature-root assertSchemaScopes test verifies each layer applied the right one.
Archetype layer composes across scopes unchanged. Update rules accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…scalCase

A Schema is a runtime type, so a higher-order schema function that returns a
new type-representing schema is a type constructor (like Readonly<T>) and takes
PascalCase — matching Tuple and the *ResultSchema factories (5 of 6 already
did). Revert the lone outlier nullable -> Nullable and codify the rule in
namespace.md: PascalCase iff calling it yields a new runtime type; camelCase
for annotators (withValidation), spec builders (from*), resolvers/transformers,
and namespace methods.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ope helpers

Replace the per-scope database layers (document/settings/session/archetype)
with a single core-database/ per feature — four single-export files
(core-database.ts + components.ts / resources.ts / archetypes.ts). Add
Database.components / Database.resources / Database.archetypes: components and
resources group declarations by schema scope (document/settings/presence/
session, all optional, documented for intellisense) and stamp the flags;
resources enforce a default at the call; archetypes validate keys against the
component map and preserve literal tuples. document passes schemas through by
identity so cross-feature shared columns dedupe. Remove Database.scope and
assertSchemaScopes. Promote shared name/assignees to data/. Collapse all
transactions to CoreDatabase.Store; index-database extends core. Rewrite the
ecs rules to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap Database.components / Database.resources (and stampScopes) return types in
Simplify<…> so the merged scope groups render as one flat object type instead of
an A & B & C & D intersection in hover/intellisense.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rules: fix example bugs (actions.md service-database import path;
services.md db type TictactoeDatabase -> ComputedDatabase; computed.md facet
wording) and tighten the features/ overview. Paths verified against the samples.

Skills: make `structure` a thin bottom-up orchestrator that defers to the
path-injected features/ rules (no restated layer detail); replace its README
with a pointer and drop its stale references/ example tree. Delete the stale
per-facet build skills (components, resources, archetypes, types, services,
namespace, archetype-to-type) — they described the pre-ecs layout and only
pointed at rules that now auto-load by path. Re-sync the installed .agents
bundle (10 skills).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… root

The cross-cutting rules the features/ bundle references (namespace,
data-modelling, type-casts, cohesion, archetypes, plugin-modelling, element,
lazy-element, presentation) now live in packages/data-ai/.claude/rules/ so the
distributed bundle is self-contained; the repo symlinks them into root
.claude/rules/ (as it already does features/). Add .claude to the package
files[] so the rules ship, and note them in the bundle README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bring back the per-phase feature-building skills as a flat set (Claude Code
only discovers skills one level deep / flat in a plugin; nesting would only
work in Cursor). One build-* skill per feature layer — build-data,
build-services, build-core-database, build-indexes, build-transactions,
build-computed, build-service-database, build-actions, build-ui — each thin:
it scaffolds the layer and defers the how to the path-injected features/ rule.
`structure` becomes the orchestrator that sequences them bottom-up. Re-sync the
.agents bundle (19 skills).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
structure now describes only the feature's layer shape and dependency
direction (the "what"); the build-* skills own the build order (the "how"),
each stating its own place in the sequence. Re-sync .agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
structure only restated the feature layering, which features/index.md (the
overview rule) already covers as a superset. The "what" now lives solely in
the features/ rules; the "how" in the build-* skills. Re-sync .agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
structure is back as a minimal invokable entry that points to the features/
rules (the "what") without restating the overview. Re-sync .agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the restated layering/examples — they live in features/index.md. structure
is now just a one-line signpost to the features/ rules. Re-sync .agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… / game)

Add build-feature (composes the per-layer build-* skills bottom-up),
build-application (composes build-feature for a base + lazy peer features, plus
the imports/lazy-element wiring), and build-game (specializes build-application
with the game-concept mapping). Higher-order skills reference the lower build-*
concisely rather than restating them. Re-sync .agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Give each per-layer build-* skill input/output: feature so they chain, and
express the higher-order skills as pipelines of them:
build-feature = /build-data |> … |> /build-ui (run via /x-execute, validated by
/x-validate). build-application and build-game compose /build-feature. Re-sync
.agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The peer-import / lazy-load / entry-point wiring is now its own build-app-entry
skill, so build-application is a clean pipe: /build-feature |> /build-feature |>
/build-app-entry. Re-sync .agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add `review` (read-only assessment of built output against the features rules,
tagging each issue code|skill|rule) and `meta-build`: given an app/game prompt
and a target build command, it runs each phase in its own clean /x-subagent,
reviews the output, and on issues edits the phase skill or a referenced rule
(concise + general, never app-specific), re-running the phase up to N times
(default 4) before moving on. Ends with a read-only whole-product review that
changes nothing and summarizes per-phase iterations and which skills/rules were
edited. Re-sync .agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ystemDatabase

@adobe/data:
- add equalsUnordered (deep equality ignoring array + object ordering)
- add Database.toSystemDatabase — cast-free writable-store lens (restrict's twin)

Conformance pattern (Store.create + raw transactions projection, cast-free):
- lit-asteroids, data-lit-todo, data-lit-tictactoe conformance suites
- per-transaction tests vs spec, shared data/state cases, ecs/conformance projection

Samples (meta-build): new lit-calculator and lit-asteroids packages.

data-lit: DatabaseElement.database accessor + pre-upgrade property fix (enforce
the UI restriction; expose the store to imperative-rendering subclasses).

AI guidance: build-systems skill + features/ecs/{systems,conformance} rules,
computed-key indexes, tag components, struct schemas, and related refinements.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…orm calculator

- rename packages to match the data-lit-* convention (git mv, history preserved)
- apply the spec↔impl conformance test pattern to data-lit-calculator
  (resource-only projection; per-transaction expectConforms tests)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…a-ai bundle notice

FeatureDatabase standard:
- alias the assembled feature database once (ecs/feature-database.ts) so
  consumers never name the varying topmost layer; cross-feature imports use
  <Feature>CoreDatabase / <Feature>Database. Applied across the four samples;
  rewired data-p2p-tictactoe. Guidance in features/ecs/index.md + element.md
  (incl. the extend-friendly element exception).

Asteroids collision:
- resolveBulletHits defers split children (no same-frame chain-annihilation)
- swept segment-vs-circle bullet detection (Collision.segmentCircleOverlap) so
  fast bullets can't tunnel through asteroids; ecs system + transaction match.

data-ai: write a do-not-edit CLAUDE.md into the installed bundle; bump script
now syncs plugin.json version (and corrected the existing drift).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ame tick-loop

- createStore builds from the schema-complete layer's plugin directly
  (Store.create(IndexDatabase.plugin) / CoreDatabase.plugin), not FeatureDatabase.
- new rule function-references.md: pass functions by reference, never wrap in an
  identity arrow (only the rare unbound-method case wraps). Swept the transaction
  conformance tests to bare spec/apply references, leaving genuine adapters.
- rename system-database/conformance.test.ts -> tick-loop.test.ts (it verifies
  the whole tick equals State.step); guidance reference updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The calculator (resource-only, no entities/systems) added little over todo —
dropping it; asteroids, todo, and tictactoe cover the pattern.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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