@adobe/data-ai 0.10.21 → 0.10.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/README.md +26 -31
- package/.claude/rules/app.md +46 -0
- package/.claude/rules/archetypes.md +5 -3
- package/.claude/rules/data-modelling.md +8 -7
- package/.claude/rules/ecs.md +11 -7
- package/.claude/rules/element.md +6 -5
- package/.claude/rules/features/data/components.md +51 -0
- package/.claude/rules/features/data/entities.md +37 -0
- package/.claude/rules/features/data/index.md +18 -70
- package/.claude/rules/features/data/resources.md +34 -0
- package/.claude/rules/features/data/values.md +36 -0
- package/.claude/rules/features/ecs/actions.md +31 -0
- package/.claude/rules/features/ecs/computed.md +31 -0
- package/.claude/rules/features/ecs/conformance.md +85 -0
- package/.claude/rules/features/ecs/core.md +43 -0
- package/.claude/rules/features/ecs/index.md +72 -0
- package/.claude/rules/features/{services/main-service → ecs}/indexes.md +6 -7
- package/.claude/rules/features/ecs/services.md +36 -0
- package/.claude/rules/features/{services/main-service → ecs}/systems.md +61 -47
- package/.claude/rules/features/ecs/transactions.md +32 -0
- package/.claude/rules/features/index.md +104 -150
- package/.claude/rules/features/services/index.md +52 -84
- package/.claude/rules/features/spec/index.md +161 -0
- package/.claude/rules/features/ui/binding-element.md +5 -5
- package/.claude/rules/features/ui/index.md +8 -3
- package/.claude/rules/features/ui/lazy-wrapper.md +2 -2
- package/.claude/rules/features/ui/presentation-test.md +1 -0
- package/.claude/rules/features/ui/presentation.md +1 -0
- package/.claude/rules/global/function-references.md +2 -2
- package/.claude/rules/global/namespace.md +3 -3
- package/.claude/rules/global/react.md +4 -4
- package/.claude/rules/lit.md +2 -2
- package/.claude/rules/plugin-modelling.md +2 -0
- package/.claude/rules/service.md +2 -0
- package/.claude/rules/versioning.md +8 -6
- package/.claude-plugin/plugin.json +1 -1
- package/package.json +3 -3
- package/skills/build-actions/SKILL.md +7 -8
- package/skills/build-app-entry/SKILL.md +12 -8
- package/skills/build-computed/SKILL.md +8 -7
- package/skills/build-core-database/SKILL.md +18 -15
- package/skills/build-data/SKILL.md +14 -13
- package/skills/build-feature/SKILL.md +2 -1
- package/skills/build-game/SKILL.md +6 -4
- package/skills/build-indexes/SKILL.md +6 -7
- package/skills/build-service-database/SKILL.md +8 -8
- package/skills/build-services/SKILL.md +9 -7
- package/skills/build-spec/SKILL.md +23 -0
- package/skills/build-systems/SKILL.md +12 -18
- package/skills/build-transactions/SKILL.md +8 -8
- package/skills/build-ui/SKILL.md +5 -4
- package/skills/review/SKILL.md +3 -3
- package/.claude/rules/features/data/state.md +0 -209
- package/.claude/rules/features/services/main-service/actions.md +0 -70
- package/.claude/rules/features/services/main-service/archetypes.md +0 -49
- package/.claude/rules/features/services/main-service/components.md +0 -41
- package/.claude/rules/features/services/main-service/computed.md +0 -82
- package/.claude/rules/features/services/main-service/conformance.md +0 -95
- package/.claude/rules/features/services/main-service/core-database.md +0 -48
- package/.claude/rules/features/services/main-service/index.md +0 -187
- package/.claude/rules/features/services/main-service/resources.md +0 -28
- package/.claude/rules/features/services/main-service/services.md +0 -25
- package/.claude/rules/features/services/main-service/transactions.md +0 -59
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
paths:
|
|
3
3
|
- '**/features/*/ui/**/*.ts'
|
|
4
|
+
- '**/features/*/ui/**/*.tsx'
|
|
4
5
|
---
|
|
5
6
|
|
|
6
7
|
# ui/ — user interface
|
|
7
8
|
|
|
8
|
-
The top layer: UI that binds the `
|
|
9
|
-
owns no business logic — it subscribes to state, hands it to
|
|
10
|
-
presentation, and wires
|
|
9
|
+
The top layer: UI that binds the feature's `MainService` database (`ecs/main-service.ts`)
|
|
10
|
+
to what the user sees. It owns no business logic — it subscribes to state, hands it to
|
|
11
|
+
a pure presentation, and wires user input to `service.actions.*`.
|
|
12
|
+
|
|
13
|
+
Each feature has one base element (Lit: `ui/<feature>-element.ts`, a
|
|
14
|
+
`DatabaseElement` typed on its `MainService.plugin`; React: a `use-main-service.ts`
|
|
15
|
+
hook) that every element of the feature builds on.
|
|
11
16
|
|
|
12
17
|
The folder name is framework-neutral; its contents are framework-specific
|
|
13
18
|
(Lit elements, React components, …). Each UI unit is its own folder, named
|
|
@@ -11,12 +11,12 @@ When a value is already a function with the signature the callee wants, pass it
|
|
|
11
11
|
|
|
12
12
|
```ts
|
|
13
13
|
// ❌ identity wrappers — the arrow adds nothing
|
|
14
|
-
|
|
14
|
+
cached((db) => Observe.withFilter(db.observe.resources.board, (b) => BoardState.deriveStatus(b)));
|
|
15
15
|
onClick={() => save()}
|
|
16
16
|
todos.map((t) => render(t))
|
|
17
17
|
|
|
18
18
|
// ✅ pass the function itself
|
|
19
|
-
|
|
19
|
+
cached((db) => Observe.withFilter(db.observe.resources.board, BoardState.deriveStatus));
|
|
20
20
|
onClick={save}
|
|
21
21
|
todos.map(render)
|
|
22
22
|
```
|
|
@@ -6,7 +6,8 @@ paths:
|
|
|
6
6
|
# Type namespace pattern
|
|
7
7
|
|
|
8
8
|
Single import surface per type: `<type-name>/<type-name>.ts`. Schema in `-schema.ts`, namespace re-export from `public.js`. Types live in
|
|
9
|
-
the `types/` layer.
|
|
9
|
+
the `types/` layer. **In a feature**, Data types live in `features/<name>/data/values/<type>/` with the schema in `schema.ts`
|
|
10
|
+
(`features/data/values.md`).
|
|
10
11
|
|
|
11
12
|
## Authority
|
|
12
13
|
|
|
@@ -161,5 +162,4 @@ Example — a type merged with one value export and any number of type-only memb
|
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
The canonical use is a feature's `core-database.ts` / layered `*-database.ts` (a
|
|
164
|
-
`plugin` value plus `Store` / `Index`
|
|
165
|
-
`features/services/main-service/core-database.md`.
|
|
165
|
+
`plugin` value plus `Store` / `Index` types) — see `features/ecs/core.md`.
|
|
@@ -5,7 +5,7 @@ paths:
|
|
|
5
5
|
|
|
6
6
|
# React component authoring
|
|
7
7
|
|
|
8
|
-
React components live in the `
|
|
8
|
+
React components live in the `ui/` layer (`features/ui/`). Consume Observe and void actions from plugins. Use `@adobe/data-react` for `useDatabase`,
|
|
9
9
|
`useObservableValues`, and `DatabaseProvider`.
|
|
10
10
|
|
|
11
11
|
---
|
|
@@ -61,7 +61,7 @@ function Counter() {
|
|
|
61
61
|
count: db.observe.resources.count,
|
|
62
62
|
}));
|
|
63
63
|
if (!values) return null;
|
|
64
|
-
return presentation.render({ ...values, increment: db.
|
|
64
|
+
return presentation.render({ ...values, increment: db.actions.increment });
|
|
65
65
|
}
|
|
66
66
|
```
|
|
67
67
|
|
|
@@ -81,8 +81,8 @@ Use **verb** or **verbNoun** names — never `on*` prefix. See `features/ui/pres
|
|
|
81
81
|
**Pass function references directly** when the signature matches; wrap in an arrow function only to supply arguments:
|
|
82
82
|
|
|
83
83
|
```tsx
|
|
84
|
-
increment: db.
|
|
85
|
-
toggleSprite: () => db.
|
|
84
|
+
increment: db.actions.increment; // reference — no wrapper needed
|
|
85
|
+
toggleSprite: () => db.actions.toggleSpriteActive({ entity }); // args required — wrap
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
---
|
package/.claude/rules/lit.md
CHANGED
|
@@ -7,7 +7,7 @@ paths:
|
|
|
7
7
|
|
|
8
8
|
# Lit element authoring
|
|
9
9
|
|
|
10
|
-
Lit elements live in the `
|
|
10
|
+
Lit elements live in the `ui/` layer (`features/ui/`). Consume Observe and void actions from plugins per the service rule.
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -58,7 +58,7 @@ render() {
|
|
|
58
58
|
userProfile: this.service.services.authentication.userProfile,
|
|
59
59
|
}));
|
|
60
60
|
if (!values) return;
|
|
61
|
-
return presentation.render({ ...values, toggleView: () => this.service.
|
|
61
|
+
return presentation.render({ ...values, toggleView: () => this.service.actions.setViewVisible({ name, visible: true }) });
|
|
62
62
|
}
|
|
63
63
|
```
|
|
64
64
|
|
|
@@ -31,6 +31,8 @@ authoring abstraction.
|
|
|
31
31
|
|
|
32
32
|
## File naming
|
|
33
33
|
|
|
34
|
+
Outside `features/`. Inside a feature, the `features/ecs/` naming applies (`<layer>-database.ts`).
|
|
35
|
+
|
|
34
36
|
Each file whose primary export is a `Database.Plugin` (created or
|
|
35
37
|
combined) ends in `-plugin.ts` — e.g. `node-plugin.ts`, `model-plugin.ts`,
|
|
36
38
|
`pbr-core-plugin.ts`. The suffix is for discovery: cursor rules,
|
package/.claude/rules/service.md
CHANGED
|
@@ -6,6 +6,8 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Service authoring
|
|
8
8
|
|
|
9
|
+
> Inside a feature, `features/services/index.md` governs the folder layout: a small service keeps `create.ts` and `create-fake.ts` flat beside the interface (the single-file exception below); one with helpers moves its implementation into a sub-folder. Database-bound factories in `ecs/services/` follow `features/ecs/services.md`.
|
|
10
|
+
|
|
9
11
|
Asynchronous data services. Live in the `services/` layer. Adhere to the namespace rule for type and function organization.
|
|
10
12
|
|
|
11
13
|
**Data** = readonly JSON values, `ReadonlySet`, `ReadonlyMap`, or Blobs.
|
|
@@ -12,6 +12,9 @@ persisted document can be upgraded to the current schema on load. You (human or
|
|
|
12
12
|
agent) should almost never have to reason about this by hand: **change the schema,
|
|
13
13
|
run the tests, and the failing test prints the exact fix to apply.**
|
|
14
14
|
|
|
15
|
+
The history lives in the app root, `src/app/versioning/` (`app.md`), because the
|
|
16
|
+
persisted data covers every feature's schema in the database.
|
|
17
|
+
|
|
15
18
|
## The pieces (all from `@adobe/data/ecs`)
|
|
16
19
|
|
|
17
20
|
- **`versions.ts`** — `export const versions: readonly VersionEntry[]`. `entries[i]`
|
|
@@ -59,7 +62,7 @@ run the tests, and the failing test prints the exact fix to apply.**
|
|
|
59
62
|
writes to SEVERAL components (a cross-component move, deriving a new component from
|
|
60
63
|
others, splitting one into many) must be hand-written to your upgrade algorithm:
|
|
61
64
|
query the input components, compute, and write the outputs directly on the store.
|
|
62
|
-
Add a test case either way (
|
|
65
|
+
Add a test case either way (the guard test below).
|
|
63
66
|
5. **Removing a component drops its data.** If the data still matters, migrate it in a
|
|
64
67
|
handler BEFORE the removal entry.
|
|
65
68
|
6. **Versioned schemas must be REAL** — declare a `type` (or `enum`/`const`), and the
|
|
@@ -83,7 +86,7 @@ history. Its message is a literal recipe. To fix it:
|
|
|
83
86
|
and the `changes` block the error printed verbatim. `db.version` follows the history
|
|
84
87
|
automatically (`= versions.length - 1`) — there is no resource default to update.
|
|
85
88
|
2. If the error marks a change **BREAKING — needs a handler**, add a `handler` to that
|
|
86
|
-
entry AND add a matching test case under `testUpgradeHandlers` (
|
|
89
|
+
entry AND add a matching test case under `testUpgradeHandlers` (the guard test below). The error
|
|
87
90
|
may point at `Store.remapComponent(...)` for an isolated single-component change, but
|
|
88
91
|
that is only a suggestion — write whatever upgrade code the change actually needs.
|
|
89
92
|
|
|
@@ -97,17 +100,17 @@ schema (schema coverage) AND every entry with a `handler` has a passing test cas
|
|
|
97
100
|
|
|
98
101
|
```ts
|
|
99
102
|
import { Database, assertVersioning, createVersionUpgrader } from "@adobe/data/ecs";
|
|
100
|
-
import {
|
|
103
|
+
import { AppSchema } from "../schema.js";
|
|
101
104
|
import { versions } from "./versions.js";
|
|
102
105
|
|
|
103
106
|
describe("database schema versions", () => {
|
|
104
107
|
it("the version history is consistent (schema folds + every handler tested)", () =>
|
|
105
108
|
assertVersioning({
|
|
106
109
|
// the version-configured db, so db.version = the history's current version
|
|
107
|
-
database: Database.create(
|
|
110
|
+
database: Database.create(AppSchema.plugin, { versioning: createVersionUpgrader(versions) }),
|
|
108
111
|
entries: versions,
|
|
109
112
|
handlers: {
|
|
110
|
-
// Append a case per version that adds a `handler` (
|
|
113
|
+
// Append a case per version that adds a `handler` (the guard test below):
|
|
111
114
|
// <version>: { setup: (store) => <populate the version-(v-1) store, return entities>,
|
|
112
115
|
// expect: (store, setup) => <assert the version-v result> },
|
|
113
116
|
},
|
|
@@ -116,7 +119,6 @@ describe("database schema versions", () => {
|
|
|
116
119
|
```
|
|
117
120
|
|
|
118
121
|
(`assertVersionsMatchSchema` and `testUpgradeHandlers` remain exported for bespoke use.)
|
|
119
|
-
```
|
|
120
122
|
|
|
121
123
|
## Example: a breaking change (number → object) at version 1
|
|
122
124
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/data-ai",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.22",
|
|
4
4
|
"description": "Cross-agent architecture skills for @adobe/data — installable as a Claude Code plugin or copied into any Agent-Skills-compatible agent (Cursor, Codex).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
"skills"
|
|
30
30
|
],
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@adobe/data": "0.10.
|
|
32
|
+
"@adobe/data": "0.10.22"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"typescript": "^5.8.3",
|
|
36
36
|
"vitest": "^1.6.0",
|
|
37
|
-
"@adobe/data": "0.10.
|
|
37
|
+
"@adobe/data": "0.10.22"
|
|
38
38
|
},
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"scripts": {
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-actions
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's ecs/actions layer — the operations the app performs.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Create `ecs/actions/`: `action-database.ts` (extends the previous layer, adds `actions`
|
|
9
|
+
from `./index.js`), one action per file, and a barrel. Every spec action has a
|
|
10
|
+
same-named action. It awaits services and commits through at most one transaction
|
|
11
|
+
(add any transaction `build-transactions` missed). Point `ecs/main-service.ts` at the top layer.
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
from `./actions/index.js`) plus an `actions/` folder — one async orchestrator per file. An action
|
|
12
|
-
takes `db: ServiceDatabase`, awaits `services/` ports, then commits **exactly one** transaction.
|
|
13
|
+
Gate: `checkFeature` passes for each op as it is added.
|
|
13
14
|
|
|
14
|
-
The
|
|
15
|
-
|
|
16
|
-
The how is in the auto-loading `features/services/main-service/actions.md` rule.
|
|
15
|
+
The how is in the auto-loading `features/ecs/actions.md` rule.
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-app-entry
|
|
3
|
-
description:
|
|
3
|
+
description: Build an application's src/app/ composition root.
|
|
4
4
|
input: app
|
|
5
5
|
output: app
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
plugin, so all schemas coexist, persist, and sync while the base type stays decoupled.
|
|
10
|
-
- The base reaches a peer only through a lazy element wrapper (dynamic import), so peers
|
|
11
|
-
load on demand.
|
|
12
|
-
- The entry point creates the live database from `MainService.plugin` (the base
|
|
13
|
-
feature's assembled database — see `features/services/main-service/index.md`) and mounts the root UI.
|
|
8
|
+
Create `src/app/`:
|
|
14
9
|
|
|
15
|
-
|
|
10
|
+
- `schema.ts` — the composed plugin: the base feature's `MainService.plugin`, `imports`
|
|
11
|
+
of the core schema of each feature that loads lazily (single-feature apps skip this).
|
|
12
|
+
- `versioning/` — `versions.ts` + `versions.test.ts` over the composed schema, when
|
|
13
|
+
the app persists.
|
|
14
|
+
- `persistence.test.ts` — a save/load round-trip, when the app persists.
|
|
15
|
+
- `main.ts` — creates the database, injects every service whose `create` throws, and
|
|
16
|
+
mounts the root UI. Point `index.html` at it.
|
|
17
|
+
|
|
18
|
+
The how is in the auto-loading `app.md` and `versioning.md` rules, and
|
|
19
|
+
`features/index.md` (one app, many features).
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-computed
|
|
3
|
-
description: Build a feature's computed
|
|
3
|
+
description: Build a feature's ecs/computed layer. Optional.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Skip if
|
|
8
|
+
Skip if the spec has no derivations and the UI needs no derived values.
|
|
9
9
|
|
|
10
|
-
Create `
|
|
11
|
-
`computed` from `./
|
|
12
|
-
|
|
10
|
+
Create `ecs/computed/`: `computed-database.ts` (extends the previous layer, adds
|
|
11
|
+
`computed` from `./index.js`), one `cached` derived value per file, and a barrel. Wire
|
|
12
|
+
`data/values/` helpers to the minimal observables. Name each entity-id-list computed in
|
|
13
|
+
the implementation's `hydrate`, and pass `computedPlugin: ComputedDatabase.plugin`.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
Gate: each derivation's computed conforms.
|
|
15
16
|
|
|
16
|
-
The how is in the auto-loading `features/
|
|
17
|
+
The how is in the auto-loading `features/ecs/computed.md` rule.
|
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-core-database
|
|
3
|
-
description: Build a feature's schema
|
|
3
|
+
description: Build a feature's ECS schema (ecs/core) and its conformance wiring. The first ecs layer.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Create
|
|
9
|
-
the feature actually uses (`components`, `resources`, `archetypes` are each optional on
|
|
10
|
-
`Database.Plugin.create`). Create only the facet files you need; omit the rest rather than
|
|
11
|
-
shipping empty `Database.components({})` boilerplate. A feature with **no entities** (a
|
|
12
|
-
singleton whose whole state is resources) is just `resources.ts` + `core-database.ts`.
|
|
8
|
+
Create:
|
|
13
9
|
|
|
14
|
-
- `
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- `core-database.ts`
|
|
10
|
+
- `ecs/core/archetypes.ts` — `Database.archetypes(components, { … })`, spreading each
|
|
11
|
+
`data/entities` tuple and adding implementation-only columns (never a
|
|
12
|
+
`nonPersistent` column without a real default).
|
|
13
|
+
- `ecs/core/core-database.ts` — `Database.Plugin.create({ extends?, components?,
|
|
14
|
+
resources?, archetypes? })` from the `data/` barrels, exporting the `CoreDatabase`
|
|
15
|
+
namespace. A feature built on another extends that feature's core.
|
|
16
|
+
- `ecs/main-service.ts` — `export { CoreDatabase as MainService }`, moved up as layers
|
|
17
|
+
are added.
|
|
18
|
+
- `ecs/conformance/` — `projection.ts`, `implementation.ts`
|
|
19
|
+
(`Conformance.implementation(spec, …)`) and `conformance.test.ts`
|
|
20
|
+
(`Conformance.checkFeature`).
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
Gate: the samples round-trip through the projection. Until the later layers exist,
|
|
23
|
+
`checkFeature` lists each spec op without an implementation by name; that list is
|
|
24
|
+
the work remaining.
|
|
22
25
|
|
|
23
|
-
The how is in the auto-loading `features/
|
|
24
|
-
|
|
26
|
+
The how is in the auto-loading `features/ecs/index.md`, `core.md` and `conformance.md`
|
|
27
|
+
rules.
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-data
|
|
3
|
-
description: Build a feature's data/ layer —
|
|
3
|
+
description: Build a feature's data/ layer — values, components, resources, entities. The first, foundational phase.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Create the feature's `data/` layer
|
|
9
|
-
and
|
|
8
|
+
Create the feature's `data/` layer: pure Data declarations, depending only on
|
|
9
|
+
`@adobe/data` and the `data/` of features this one builds on.
|
|
10
10
|
|
|
11
|
-
- one namespace
|
|
12
|
-
|
|
11
|
+
- `values/<type>/` — one namespace per Data type: a hand-written type, a schema pinned
|
|
12
|
+
to it (`type _Pin = Assert<Equal<Schema.ToType<typeof schema>, <Type>>>`) when
|
|
13
|
+
something needs one, and pure helpers, each with a test.
|
|
14
|
+
- `components/<name>.ts` — one schema per file, scope spread from `Scope`, plus an
|
|
15
|
+
`index.ts` barrel. Include implementation-only columns (tags, drag offsets).
|
|
16
|
+
- `resources/<name>.ts` — one schema per file, `satisfies ResourceSchema`, plus a barrel.
|
|
17
|
+
- `entities/<entity>.ts` — the spec-visible entity as a component-name tuple, with its
|
|
18
|
+
type derived by `Database.EntityType`, plus a barrel.
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
incomplete: the transaction must wrap a pure transform, not invent the logic. In rare circumstances, there may be no real state in a feature in which case the state type = {}
|
|
20
|
+
Create only the folders the feature needs. Gate: it compiles and the helper tests
|
|
21
|
+
pass.
|
|
17
22
|
|
|
18
|
-
The
|
|
19
|
-
Helpers are pure and unit-tested. Run this first — every other layer imports `data/`.
|
|
20
|
-
|
|
21
|
-
The how is in the auto-loading rules: `features/data/index.md`, `features/data/state.md`, and
|
|
22
|
-
`global/namespace.md`.
|
|
23
|
+
The how is in the auto-loading `features/data/` rules and `global/namespace.md`.
|
|
@@ -8,11 +8,12 @@ output: feature
|
|
|
8
8
|
/graph-execute
|
|
9
9
|
/build-data
|
|
10
10
|
/build-services
|
|
11
|
+
/build-spec
|
|
11
12
|
/build-core-database
|
|
12
13
|
/build-indexes
|
|
13
14
|
/build-transactions
|
|
14
|
-
/build-computed
|
|
15
15
|
/build-service-database
|
|
16
|
+
/build-computed
|
|
16
17
|
/build-actions
|
|
17
18
|
/build-systems
|
|
18
19
|
/build-ui
|
|
@@ -7,15 +7,17 @@ output: game
|
|
|
7
7
|
|
|
8
8
|
/build-application — a game is an application.
|
|
9
9
|
|
|
10
|
-
Map game concepts to feature layers: data/ =
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Map game concepts to feature layers: data/ = value types, rules math, components,
|
|
11
|
+
resources (the board, the player, the score) and entities (the pieces); spec/ = the
|
|
12
|
+
game state + moves (+ one pure function per system); indexes = spatial/lookup queries;
|
|
13
|
+
transactions + actions = moves/spawns; computed = score/status/winner; ui = view + input.
|
|
13
14
|
|
|
14
15
|
- **Turn-based** uses the reactive transaction → computed → ui loop, no systems
|
|
15
16
|
(see data-lit-tictactoe).
|
|
16
17
|
- **Real-time** adds the `build-systems` phase: a per-frame tick loop (movement,
|
|
17
18
|
collision, lifetime) driven by the scheduler, over many entities in distinct
|
|
18
19
|
archetypes. Systems must stay O(1) per touched entity — never project the whole
|
|
19
|
-
`State` into/out of the store each frame
|
|
20
|
+
`State` into/out of the store each frame, and never turn per-row work into per-entity
|
|
21
|
+
transactions. Each system conforms alone and as a frame (see `features/ecs/systems.md`).
|
|
20
22
|
This is where components, archetypes, indexes, and systems all carry real
|
|
21
23
|
weight.
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-indexes
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's ecs/indexes layer. Optional.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Skip if
|
|
8
|
+
Skip if the feature needs no indexed lookups.
|
|
9
9
|
|
|
10
|
-
Create `
|
|
11
|
-
|
|
12
|
-
barrel.
|
|
10
|
+
Create `ecs/indexes/`: `index-database.ts` (extends `CoreDatabase`, adds `indexes` from
|
|
11
|
+
`./index.js`), one index per file, and an `index.ts` barrel.
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
Gate: conformance unchanged, plus index tests where an index has logic.
|
|
15
14
|
|
|
16
|
-
The how is in the auto-loading `features/
|
|
15
|
+
The how is in the auto-loading `features/ecs/indexes.md` rule.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-service-database
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's ecs/services layer — registering services on the database. Optional.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
`services` facet). Two forms:
|
|
8
|
+
Skip if the feature has no services.
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Create `ecs/services/service-database.ts` (extends the previous layer), registering
|
|
11
|
+
each `services/` service's `create` under its `Services` key, plus any database-bound
|
|
12
|
+
factories (one per file + barrel) for services that read observables or call
|
|
13
|
+
transactions. Pin with `Assert<Equal<ServiceDatabase["services"], Services>>`. Give
|
|
14
|
+
the implementation base fakes for services whose `create` throws.
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
The how is in the auto-loading `features/services/main-service/services.md` rule.
|
|
16
|
+
The how is in the auto-loading `features/ecs/services.md` rule.
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-services
|
|
3
|
-
description: Build a feature's services/ layer — async
|
|
3
|
+
description: Build a feature's services/ layer — async data services (interface, create, createFake). Optional.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Skip if
|
|
8
|
+
Skip if the feature talks to nothing outside itself.
|
|
9
9
|
|
|
10
|
-
Create
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Create one `services/<name>-service/` namespace per service: the interface (an async
|
|
11
|
+
data service, validated with `AsyncDataService.IsValid`), `create` (the
|
|
12
|
+
implementation, or a factory that throws when the app must inject it),
|
|
13
|
+
`createFake`, and `public.ts`. Add `services/services.ts` with the `Services` map when
|
|
14
|
+
spec actions inject services.
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
Depends only on `data/`. Gate: per-service unit tests.
|
|
15
17
|
|
|
16
|
-
The how is in the auto-loading `features/services/index.md` rule
|
|
18
|
+
The how is in the auto-loading `features/services/index.md` rule.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-spec
|
|
3
|
+
description: Build a feature's spec/ — the State, its actions and derivations, and their cases. Test tier.
|
|
4
|
+
input: feature
|
|
5
|
+
output: feature
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Create the feature's `spec/` folder, the specification the ECS will be conformed to:
|
|
9
|
+
|
|
10
|
+
- `state.ts` — `State` built from `data/` types (singletons named for resources,
|
|
11
|
+
`ReadonlyMap` entity collections), pinned with `Conformance.StateMatches`; `create.ts`,
|
|
12
|
+
`samples.ts`, `public.ts`.
|
|
13
|
+
- One file per **action** (each operation the app performs) and per **derivation**
|
|
14
|
+
(each derived value it shows), each with its inert `*.cases.ts`. A real-time feature
|
|
15
|
+
adds `systems.ts`: one pure function per ECS system it will have, named the same,
|
|
16
|
+
each with cases, plus `noOp` states every system leaves unchanged.
|
|
17
|
+
- `transforms.ts` (the barrel of every action and derivation), `spec.ts`
|
|
18
|
+
(`Conformance.spec`) and `spec.test.ts` (`Conformance.checkSpec`).
|
|
19
|
+
|
|
20
|
+
Build one action or derivation plus its cases at a time. Logic the ECS will share goes
|
|
21
|
+
into `data/values/` helpers, never here. Gate: `checkSpec` passes.
|
|
22
|
+
|
|
23
|
+
The how is in the auto-loading `features/spec/index.md` rule.
|
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-systems
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a real-time feature's ecs/systems layer — the per-frame tick loop. Optional.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Skip
|
|
9
|
-
Most games that use a canvas will use systems but most applications will not.
|
|
8
|
+
Skip unless the feature is real-time (games, simulations).
|
|
10
9
|
|
|
11
|
-
Create `
|
|
12
|
-
Database.Plugin.combine(<currentTop>.plugin, scheduler), systems
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
map is declared **inline** (see `features/services/main-service/systems.md` — inline is required for `db` to be
|
|
17
|
-
typed and for system-name inference; a `systems/` folder is optional, only for extracted
|
|
18
|
-
per-frame body helpers).
|
|
10
|
+
Create `ecs/systems/system-database.ts`: `Database.Plugin.create({ extends:
|
|
11
|
+
Database.Plugin.combine(<currentTop>.plugin, scheduler), systems: { … } })`, with the
|
|
12
|
+
`systems` map declared **inline** so `db` and the system names are inferred. Hot
|
|
13
|
+
per-row work writes columns in place; discrete events dispatch transactions. Order
|
|
14
|
+
systems under `schedule`; it is the only statement of order.
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
combining `scheduler` (rAF), gated by the `schedulerState` resource.
|
|
16
|
+
Add `frame: { args, unmodelled?, cases? }` to the implementation: a writer per frame
|
|
17
|
+
arg, each system the spec can't model (wasm, init-only) with its reason, and
|
|
18
|
+
whole-frame cases in `ecs/conformance/frame.cases.ts`. Gate: every
|
|
19
|
+
system's own cases and the frame cases pass.
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
Comes after `build-computed`. The how is in the auto-loading `features/services/main-service/systems.md` rule.
|
|
21
|
+
The how is in the auto-loading `features/ecs/systems.md` rule.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-transactions
|
|
3
|
-
description: Build a feature's
|
|
3
|
+
description: Build a feature's ecs/transactions layer.
|
|
4
4
|
input: feature
|
|
5
5
|
output: feature
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Create `
|
|
9
|
-
|
|
10
|
-
`
|
|
11
|
-
|
|
12
|
-
`IndexDatabase.Store` (reads an index).
|
|
8
|
+
Create `ecs/transactions/`: `transaction-database.ts` (extends the previous layer, adds
|
|
9
|
+
`transactions` from `./index.js`), one mutation per file, and a barrel. Type the store
|
|
10
|
+
`CoreDatabase.Store`, or `IndexDatabase.Store` once it reads an index. Guard by entity
|
|
11
|
+
kind, and apply `data/values/` helpers; never import `spec/`.
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
Build the transactions the spec actions will need. They are conformed through the
|
|
14
|
+
actions that call them, so their gate is `build-actions`; add any missing one there.
|
|
15
15
|
|
|
16
|
-
The how is in the auto-loading `features/
|
|
16
|
+
The how is in the auto-loading `features/ecs/transactions.md` rule.
|