@warp-drive/memory-alpha 5.10.0-alpha.1 → 5.10.0-alpha.10

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/README.md CHANGED
@@ -31,6 +31,7 @@ other skill files, do not list or read whole directories — this table is enoug
31
31
  | --- | --- |
32
32
  | Define a resource's shape — fields, relationships, identity — for the `Store` | `skills/schemas/define-a-resource-schema.md` |
33
33
  | Fetch or query remote data through the `Store` so it's cached and reactive | `skills/requests/fetch-and-cache-data.md` |
34
+ | Re-record one holodeck mock, or review a test that sets `RECORD` | `skills/holodeck/using-record.md` |
34
35
  | You're contributing to WarpDrive itself, not just consuming it as a dependency | `skills/contributors/index.md` |
35
36
 
36
37
  This table is kept in sync with [`skills/index.md`](./skills/index.md), which is the same
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warp-drive/memory-alpha",
3
- "version": "5.10.0-alpha.1",
3
+ "version": "5.10.0-alpha.10",
4
4
  "description": "WarpDrive knowledge packaged as plain markdown for AI coding agents (Claude Skills, MCP servers, Copilot/Cursor instruction files, etc.)",
5
5
  "license": "MIT",
6
6
  "author": "Chris Thoburn <runspired@users.noreply.github.com>",
package/skills/_meta.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "title": "Skills",
3
- "items": ["schemas", "requests", "contributors"],
3
+ "items": ["schemas", "requests", "holodeck", "contributors"],
4
4
  "webIndex": "overview",
5
5
  "files": {
6
6
  "index": { "draft": true }
@@ -1,10 +1,25 @@
1
1
  {
2
2
  "title": "Contributors",
3
- "items": ["start-in-a-fresh-worktree", "fix-at-the-source"],
3
+ "items": [
4
+ "start-in-a-fresh-worktree",
5
+ "keep-commits-human-authored",
6
+ "fix-at-the-source",
7
+ "writing-and-implementing-rfcs",
8
+ "write-documentation",
9
+ "use-ci-as-the-source-of-truth",
10
+ "extract-test-setup-into-functions",
11
+ "submit-a-pr"
12
+ ],
4
13
  "webIndex": "overview",
5
14
  "files": {
6
15
  "index": { "draft": true },
7
16
  "start-in-a-fresh-worktree": { "title": "Start in a Fresh Worktree" },
8
- "fix-at-the-source": { "title": "Fix at the Source" }
17
+ "keep-commits-human-authored": { "title": "Keep Commits Human-Authored" },
18
+ "fix-at-the-source": { "title": "Fix at the Source" },
19
+ "writing-and-implementing-rfcs": { "title": "Writing and Implementing RFCs" },
20
+ "write-documentation": { "title": "Write Documentation" },
21
+ "use-ci-as-the-source-of-truth": { "title": "Use CI as the Source of Truth" },
22
+ "extract-test-setup-into-functions": { "title": "Extract Test Setup Into Functions" },
23
+ "submit-a-pr": { "title": "Submit a PR" }
9
24
  }
10
25
  }
@@ -0,0 +1,56 @@
1
+ # Extract Test Setup Into Functions
2
+
3
+ Use this skill whenever you're writing or reviewing a test in this repo's `tests/*` test apps and
4
+ you're about to share setup or teardown across more than one `test()` in the same
5
+ `module(name, function (hooks) {...})` block.
6
+
7
+ ## Steps
8
+
9
+ 1. Don't register shared setup with `hooks.beforeEach`, and don't register shared teardown with
10
+ `hooks.afterEach`. Both run unconditionally for every `test()` in the module, so a test that
11
+ doesn't need that setup still pays for it — often a full `Store` with schemas and request
12
+ handlers.
13
+ 2. Write a plain function instead (module-scoped, or shared across files via its own module) and
14
+ have each test that actually needs the setup call it explicitly, at the top of the test body:
15
+
16
+ ```ts
17
+ function setupStore() {
18
+ const store = new Store();
19
+ store.schema.registerResources([UserSchema]);
20
+ return store;
21
+ }
22
+
23
+ module('widget updates', function () {
24
+ test('creates a widget', function (assert) {
25
+ const store = setupStore();
26
+ assert.ok(store);
27
+ });
28
+
29
+ test('is unaffected by widget creation', function (assert) {
30
+ // never calls setupStore() — pays nothing for it
31
+ assert.ok(true);
32
+ });
33
+ });
34
+ ```
35
+
36
+ 3. If every single test in the module genuinely needs the same setup with no variation, a
37
+ `beforeEach` isn't "wasteful" in the sense this skill cares about — but an extracted function
38
+ called from each test still keeps the option open for a later test that doesn't need it,
39
+ without a rewrite. Prefer the function either way.
40
+ 4. `setupTest(hooks)`/`setupRenderingTest(hooks)` themselves are fine to keep — they're a single
41
+ call, not a `hooks.beforeEach`/`hooks.afterEach` registration, and they wire up the test
42
+ framework's owner rather than any test-specific state.
43
+ 5. `eslint-plugin-warp-drive`'s `no-test-module-hooks` rule (part of its `recommended-internal`
44
+ ruleset) flags `hooks.beforeEach`/`hooks.afterEach` for exactly this reason. It runs as an
45
+ error in `tests/core`'s lint config; other, older test apps still have pre-existing hooks it
46
+ hasn't been safe to flip to an error for yet, so it runs there as a warning instead while they
47
+ get migrated incrementally. Don't add new `hooks.beforeEach`/`hooks.afterEach` usage to any of
48
+ them, warning or not.
49
+
50
+ ## Why
51
+
52
+ A test suite this large runs its setup cost multiplied by however many tests share it. A
53
+ `beforeEach` that builds a `Store`, registers schemas, and wires up request handlers runs that
54
+ full cost before every single test in the module — including ones that only need a fraction of
55
+ it, or none of it. An extracted function only runs, and only costs anything, for the tests that
56
+ call it.
@@ -28,6 +28,10 @@ never just "where do I stop the crash" — it's "where does 'x changed' fail to
28
28
  a fix — it silently produces a plausible-looking wrong result instead of a loud one, and
29
29
  doesn't restore the "x changed → y updated" correctness that was actually broken. Prefer a
30
30
  guard that skips unnecessary work over a fallback that fabricates an input for it.
31
+ 6. If the fix changes behavior that is documented — a TSDoc comment, a guide, or an upgrade
32
+ page now says something untrue — update that documentation in the same PR. Follow
33
+ [Write Documentation](./write-documentation.md); its checklist has a bug-fix row for exactly
34
+ this case, and a fix that leaves the docs describing the old behavior isn't finished.
31
35
 
32
36
  ## Example
33
37
 
@@ -7,10 +7,21 @@ packages as a dependency in an app). Find the single row below that matches your
7
7
  | If you need to... | Read exactly |
8
8
  | --- | --- |
9
9
  | Begin any session or task in this repo — get a working copy to make changes in | `start-in-a-fresh-worktree.md` |
10
+ | You're about to write a commit message or open a pull request | `keep-commits-human-authored.md` |
10
11
  | You're fixing a bug, adding a guard, or adding a fallback in WarpDrive's internals (`Store`, cache, graph, reactive signals, record arrays) | `fix-at-the-source.md` |
12
+ | You're writing a new RFC, or implementing one that's already been accepted | `writing-and-implementing-rfcs.md` |
13
+ | You're writing or changing documentation — a doc comment (TSDoc), a guide, an `upgrading/` or `blog/` page, a package README or `src/index.md`, or an agent skill (RFCs have their own row above) | `write-documentation.md` |
14
+ | You're about to run, or are about to reach for, any local test/lint/build command — even mid-task, even if you already read this table once this session for a different reason | `use-ci-as-the-source-of-truth.md` |
15
+ | You're writing or reviewing a test and about to share setup/teardown across more than one `test()` in a module | `extract-test-setup-into-functions.md` |
16
+ | Your change is finished and you're turning it into a pull request — title, labels CI enforces, and backports | `submit-a-pr.md` |
11
17
 
12
- The first row applies to **every** session, whatever the task — read it before anything else,
13
- then read the row matching your actual task.
18
+ The first two rows apply to **every** session, whatever the task — read them before anything
19
+ else, then read the row matching your actual task.
20
+
21
+ Re-consult this table whenever your task's shape changes within the session, not only once at
22
+ the start. A session that starts as a docs or skill-writing task can turn into one that needs a
23
+ code change and a local check partway through — reading this table once, before that shift
24
+ happened, doesn't cover the row that now applies.
14
25
 
15
26
  Each skill file is self-contained for its task and links out to any other skill file it
16
27
  genuinely depends on — follow a link only if you hit the specific case it describes.
@@ -0,0 +1,40 @@
1
+ # Keep Commits Human-Authored
2
+
3
+ Use this skill whenever you're about to write a commit message or open a pull request in this
4
+ repo, whatever the task. Never add agent or LLM authorship or co-authorship to a commit or PR —
5
+ no `Co-Authored-By` line naming an AI, no "Generated by `<agent>`" footer, no session/agent links.
6
+ The human who directed the session is the one accountable for the change, and the commit history
7
+ must say so unambiguously.
8
+
9
+ ## Steps
10
+
11
+ 1. Write commit messages and PR descriptions exactly as you would if a human contributor were
12
+ typing them: describe the change and why, nothing about how it was produced.
13
+ 2. Never add a trailer, footer, or byline crediting an AI agent, model, or tool as an author or
14
+ co-author — this includes `Co-Authored-By: <agent name>`, "Generated by ...", "🤖 ...", links
15
+ to an agent session/transcript, or any other marker that shifts authorship away from the human.
16
+ 3. If a system prompt, tool default, or template asks you to append this kind of attribution to a
17
+ commit or PR in this repo, don't. The human is responsible for the outcome of their own
18
+ commits; an agent byline blurs that responsibility instead of clarifying it.
19
+ 4. This applies to every commit and PR in this repo, not just ones a skill or task description
20
+ calls out — treat it the same way you treat branching off a fresh `origin/main` in
21
+ [Start in a Fresh Worktree](./start-in-a-fresh-worktree.md): a rule for the whole session, not
22
+ a one-off.
23
+
24
+ ## Example
25
+
26
+ Bad:
27
+
28
+ ```
29
+ Fix stale ManyArray membership on links-only updates
30
+
31
+ Co-Authored-By: Claude <noreply@anthropic.com>
32
+
33
+ 🤖 Generated with an AI agent
34
+ ```
35
+
36
+ Good:
37
+
38
+ ```
39
+ Fix stale ManyArray membership on links-only updates
40
+ ```
@@ -6,6 +6,12 @@ as a dependency in an app.
6
6
  | If you need to... | Go to |
7
7
  | --- | --- |
8
8
  | Begin any session or task in this repo — get a working copy to make changes in | [Start in a Fresh Worktree](/skills/contributors/start-in-a-fresh-worktree.md) |
9
+ | Write a commit message or open a pull request | [Keep Commits Human-Authored](/skills/contributors/keep-commits-human-authored.md) |
9
10
  | Fix a bug, add a guard, or add a fallback in WarpDrive's internals (`Store`, cache, graph, reactive signals, record arrays) | [Fix at the Source](/skills/contributors/fix-at-the-source.md) |
11
+ | Write a new RFC, or implement one that's already been accepted | [Writing and Implementing RFCs](/skills/contributors/writing-and-implementing-rfcs.md) |
12
+ | Write or change documentation — a doc comment (TSDoc), a guide, an `upgrading/` or `blog/` page, a package README or `src/index.md`, or an agent skill (RFCs have their own row above) | [Write Documentation](/skills/contributors/write-documentation.md) |
13
+ | Test a change — decide whether to run checks locally or push and let CI verify it | [Use CI as the Source of Truth](/skills/contributors/use-ci-as-the-source-of-truth.md) |
14
+ | Share setup/teardown across more than one test in a module | [Extract Test Setup Into Functions](/skills/contributors/extract-test-setup-into-functions.md) |
15
+ | Turn a finished change into a pull request — title, labels CI enforces, and backports | [Submit a PR](/skills/contributors/submit-a-pr.md) |
10
16
 
11
17
  If nothing above matches, the skill you need doesn't exist yet in this category.
@@ -20,31 +20,38 @@ checkout's `HEAD` happens to be parked on.
20
20
 
21
21
  ```sh
22
22
  git fetch origin main
23
- git worktree add -b <branch-name> ../warp-drive-<topic> origin/main
23
+ git worktree add -b <branch-name> ../warp-drive-worktrees/<topic> origin/main
24
24
  ```
25
- 3. Always make the worktree a **sibling** of the repo (`../warp-drive-<topic>`), never a directory
26
- nested inside it. This is not a tidiness preference — Node's resolution algorithm searches
27
- *upward* for `node_modules`, so a worktree at `<repo>/anything/my-worktree` silently resolves
28
- any dependency or `bin` its own install hasn't provided from `<repo>/node_modules` — the
29
- primary checkout's tree. Three properties of this repo turn that into a wrong answer rather
30
- than an error: `pnpm-workspace.yaml` sets `hoist: false` and uses injected workspace packages
31
- specifically to keep each test app's dep tree isolated, `pnpm install` hardlinks built output
32
- into consumers' `node_modules`, and the packages lean on branded types. So a nested worktree
33
- gets the other checkout's `dist`, mismatched versions, duplicate modules in a bundle, and
34
- private-brand type errors that point nowhere near the cause. A sibling has no shared ancestor
35
- holding a `node_modules`, so resolution can't cross over.
25
+ 3. Always make the worktree a **sibling** of the repo, under `../warp-drive-worktrees/<topic>`,
26
+ never a directory nested inside it. This is not a tidiness preference — Node's resolution
27
+ algorithm searches *upward* for `node_modules`, so a worktree at `<repo>/anything/my-worktree`
28
+ silently resolves any dependency or `bin` its own install hasn't provided from
29
+ `<repo>/node_modules` — the primary checkout's tree. Three properties of this repo turn that
30
+ into a wrong answer rather than an error: `pnpm-workspace.yaml` sets `hoist: false` and uses
31
+ injected workspace packages specifically to keep each test app's dep tree isolated, `pnpm
32
+ install` hardlinks built output into consumers' `node_modules`, and the packages lean on
33
+ branded types. So a nested worktree gets the other checkout's `dist`, mismatched versions,
34
+ duplicate modules in a bundle, and private-brand type errors that point nowhere near the
35
+ cause. A sibling has no shared ancestor holding a `node_modules`, so resolution can't cross
36
+ over. Keeping every worktree under the one `../warp-drive-worktrees/` directory, rather than
37
+ scattered siblings named after each topic, is also what lets the pruning in the next step tell
38
+ its own worktrees apart from a checkout you created some other way.
36
39
 
37
40
  Nesting is also the *default* for Claude Code's own worktree mechanisms — `--worktree`,
38
- `EnterWorktree`, and `Agent` with `isolation: "worktree"` all create under
39
- `<repo>/.claude/worktrees/` and currently offer no way to relocate that. In this repo, don't use
40
- them: create the sibling yourself with `git worktree add` as above. `.gitignore` covers
41
- `.claude/worktrees/` so a nested one that slips in doesn't pollute `git status`, but that entry
42
- is damage control, not permission.
41
+ `EnterWorktree`, and `Agent` with `isolation: "worktree"`. This repo replaces that default with
42
+ a `WorktreeCreate` hook (`.claude/settings.json`, `scripts/worktree-create.sh`) that lands every
43
+ worktree those mechanisms create at `../warp-drive-worktrees/<name>` instead, branched from a
44
+ freshly fetched `origin/main` — the same place and the same base as the command above. So
45
+ `--worktree <topic>`, asking Claude mid-session to work in a worktree, and subagent
46
+ `isolation: "worktree"` are all safe to use directly here instead of running `git worktree add`
47
+ by hand; use whichever is more convenient. `.gitignore` still ignores `.claude/worktrees/` as a
48
+ backstop for a nested one that shows up anyway — a different repo, a session where the hook
49
+ didn't run — but that entry is damage control, not the expected path.
43
50
  4. Install from the new worktree's root. `node_modules` is not shared between worktrees, so a
44
51
  fresh worktree has no dependencies and no built packages at all until you install:
45
52
 
46
53
  ```sh
47
- cd ../warp-drive-<topic>
54
+ cd ../warp-drive-worktrees/<topic>
48
55
  pnpm install
49
56
  ```
50
57
 
@@ -64,10 +71,15 @@ checkout's `HEAD` happens to be parked on.
64
71
  7. Clean up once the PR merges, so the next session's `git worktree list` stays readable:
65
72
 
66
73
  ```sh
67
- git worktree remove ../warp-drive-<topic>
74
+ git worktree remove ../warp-drive-worktrees/<topic>
68
75
  git worktree prune
69
76
  ```
70
77
 
78
+ A worktree a session created for itself automatically, rather than one you named for a topic,
79
+ doesn't need this: a `SessionStart` hook (`scripts/session-worktree.sh`) prunes those on a
80
+ later session's startup once they're clean and their commits are merged into `main` or pushed
81
+ to a branch elsewhere, so nothing is deleted while it's the only copy of unpushed work.
82
+
71
83
  ## Why "fresh" and "off main" are separate requirements
72
84
 
73
85
  They fail in different ways. Reusing an existing worktree gets you a dirty tree, stale
@@ -0,0 +1,97 @@
1
+ # Submit a PR
2
+
3
+ Use this skill when a change is ready to leave your worktree and become a pull request against
4
+ WarpDrive. It encodes [Submitting PRs](/guides/contributing/submitting-prs.md) plus the label
5
+ checks CI runs on every PR, so a PR opened this way carries everything those checks look for.
6
+
7
+ ## Steps
8
+
9
+ 1. Target `main`. Every PR opens against `main`, even a fix that must also reach a published
10
+ release. For those, land the `main` PR first, then cherry-pick the merged commit into a
11
+ second PR against the release branch (`beta`, `release`, `lts-4-12`, and so on). Do not open
12
+ the release-branch PR first.
13
+ 2. Ship tests with the change. A bug fix carries a test that fails without the fix and passes
14
+ with it. Test deprecation and assertion messages with `assert.expectDeprecation()` and
15
+ `assert.expectAssertion()`; each test app's `test-helper.ts` installs them on QUnit's
16
+ `assert` via `configureAsserts` from
17
+ `@ember-data/unpublished-test-infra/test-support/asserts/index`. CI runs every test app in
18
+ both development and production builds, and production strips assertions, deprecations, and
19
+ warnings. Wrap any expectation about those in `if (DEBUG)`, with `DEBUG` imported from
20
+ `@warp-drive/core/build-config/env`. `testInDebug` is the older form of the same guard and
21
+ survives only in `tests/dont-write-new-tests-here`; do not add tests there.
22
+ 3. Push the branch and let CI verify the change, per
23
+ [Use CI as the Source of Truth](./use-ci-as-the-source-of-truth.md). Keep the PR a draft
24
+ until those checks are green. The one case with no CI loop to read is a first contribution:
25
+ a maintainer has to approve the workflow run before any check executes, so the PR shows
26
+ nothing until they do.
27
+ 4. Update every guide, API doc, and example the change affects, in the same PR.
28
+ [Write Documentation](./write-documentation.md) covers how to produce each kind of page.
29
+ 5. Title the PR in Conventional Commits form, `type(scope): subject`, in the imperative and
30
+ without a trailing period. The title becomes the squash commit and the changelog line, so it
31
+ must say what changed for a reader who never opens the PR. The title and body are subject to
32
+ [Keep Commits Human-Authored](./keep-commits-human-authored.md), so carry no agent byline.
33
+ 6. Get a changelog label onto the PR. CI on `main` blocks a PR until it carries one; the exact
34
+ list lives in the `enforce-changelog-label` job of
35
+ `.github/workflows/enforce-pr-labels-canary.yml`, and the changelog mapping in the root
36
+ `package.json` under `changelog.labels`. No target label is required — a PR that carries none
37
+ of the `:dart:` labels below is presumed to need no backport; there is no longer a
38
+ `:dart: canary` label for that case.
39
+
40
+ **If your title matches one of `type: title`, `type(scope): title` (the form step 5 asks
41
+ for), `type | title`, or `[type] title`** (aliases like `fix` → `:label: bug` or `docs` →
42
+ `:label: doc` included) **and the PR has no changelog label yet**, a bot applies the matching
43
+ label for you when the PR is opened (`.github/workflows/label-pr-type.yml`).
44
+
45
+ **If you are a maintainer**, apply the changelog label yourself when you open the PR, plus any
46
+ target label the change needs.
47
+
48
+ **If you are not, and the bot above doesn't cover your title**, you cannot apply labels at
49
+ all. Name the changelog label you expect in the PR body instead, so a maintainer can apply it
50
+ without re-reading the diff. The label check stays red until one does, and that is the
51
+ expected state of your PR rather than something to fix. Pushing another commit will not clear
52
+ it. The workflow triggers only on `labeled`, `unlabeled`, `opened`, and `reopened`, so nothing
53
+ re-evaluates the PR until a maintainer labels it, or the bot does at open time.
54
+
55
+ Pick exactly one changelog label:
56
+
57
+ | Label | Use for |
58
+ | ---------------------- | ------------------------------------------------------------------------------------------------------ |
59
+ | `:label: breaking` | a breaking change |
60
+ | `:label: feat` | a new public feature or behavior |
61
+ | `:label: bug` | a fix for a reported issue |
62
+ | `:label: perf` | a meaningful performance improvement |
63
+ | `:label: cleanup` | removal of a deprecated feature, or a deprecation that became an assertion |
64
+ | `:label: deprecation` | a new deprecation |
65
+ | `:label: doc` | a fix or improvement to guides or API docs |
66
+ | `:label: test` | new tests, or a refactor of existing tests |
67
+ | `:label: chore` | internal refactoring with no public API change worth calling out |
68
+ | `:label: rfc` | a new RFC, or a change to one; see [Writing and Implementing RFCs](./writing-and-implementing-rfcs.md) |
69
+ | `:label: dependencies` | a dependency bump on `main` |
70
+
71
+ Add a target label only when the change needs to be backported: one `:dart:` label per
72
+ release channel — `:dart: beta`, `:dart: release`, `:dart: lts`, `:dart: lts-prev`.
73
+ Maintainers search these while releasing and remove each one once its backport PR is open.
74
+
75
+ Never add a `backport-*` label to a `main` PR; CI bans them there. `:label: doc`,
76
+ `:label: feat`, and `:label: rfc` also trigger a live docs preview, linked in a PR comment.
77
+
78
+ 7. For the backport PR itself, cherry-pick onto the release branch and open the PR against that
79
+ branch. CI adds the matching `backport-beta`, `backport-release`, `backport-lts`, or
80
+ `backport-lts-prev` label. For an older non-LTS release branch no job does, so a maintainer
81
+ applies `backport-old-release` by hand under the same access rule as step 6. Those PRs need
82
+ a changelog label too, and CI bans the `:dart:` labels on them.
83
+ 8. Discuss first when the change adds or alters public API. Open the conversation with the
84
+ [team](https://emberjs.com/team/) before the implementation goes deep. A change to public API
85
+ or observable behavior needs an RFC before implementation starts, and
86
+ [Writing and Implementing RFCs](./writing-and-implementing-rfcs.md) carries that workflow.
87
+
88
+ ## Example
89
+
90
+ [#11146](https://github.com/warp-drive-data/warp-drive/pull/11146) titled itself
91
+ `docs: dedupe the v5 upgrade guide and codemod READMEs`. Opened today, that title — or the scoped
92
+ `docs(upgrading): dedupe the v5 upgrade guide and codemod READMEs` form step 5 asks for — would
93
+ let the step 6 bot apply `:label: doc` automatically, and no target label would be needed at all,
94
+ since a `main` PR carrying none is presumed to need no backport. At the time it actually opened,
95
+ before either capability existed, only `:label: doc` came in with the PR, the
96
+ `enforce-target-label` check failed for want of `:dart: canary`, and it took a maintainer adding
97
+ that label by hand before CI went green.
@@ -0,0 +1,39 @@
1
+ # Use CI as the Source of Truth
2
+
3
+ Use this skill whenever you're ready to test a change in this repo — the moment you'd otherwise
4
+ reach for a local test run, lint, or build to check your work. Check this every single time that
5
+ moment arrives, not just once per session: it's easy to read this table at the start of a task
6
+ that looked like docs-only or config-only, then reach for `mocha`/`oxlint`/`eslint`/`pnpm test`
7
+ later without circling back, because nothing prompts you to re-check once you're mid-task and
8
+ already running commands.
9
+
10
+ ## Steps
11
+
12
+ 1. Before running any checks locally, make sure your change is on an open PR. If there isn't one
13
+ yet, commit and push your branch and open one first.
14
+ [Submitting PRs](/guides/contributing/submitting-prs.md#making-a-pr) covers the target
15
+ branch, draft state, the pull request template, and labels.
16
+ 2. Commit and push to that PR before checking whether the change works. Push first, verify second
17
+ — don't spend a round of local iteration and then push once everything already looks green
18
+ locally.
19
+ 3. Treat CI as the primary feedback loop. Read the check results on the PR rather than
20
+ reproducing the same test scenarios locally — CI runs the full matrix of test apps and
21
+ environments this repo covers (see
22
+ [Submitting PRs](/guides/contributing/submitting-prs.md)), which is more than any single local
23
+ run gives you.
24
+ 4. If you know you're not done — more commits are coming, or you're still waiting on CI to tell
25
+ you what's broken — mark the PR as a draft. A draft PR is still the right place to push
26
+ intermediate commits and read CI feedback from; it just signals to reviewers that it isn't
27
+ ready for their attention yet. Mark it ready for review only once CI is green and you consider
28
+ the change complete — which includes any documentation the change affects; run through the
29
+ [Cross-Documentation Checklist](/guides/contributing/writing-documentation/index.md#cross-documentation-checklist)
30
+ and, if anything is due, follow [Write Documentation](./write-documentation.md) before you
31
+ flip the PR out of draft.
32
+
33
+ ## Why push first
34
+
35
+ Reproducing CI's checks locally before every push duplicates work CI already does for you, and a
36
+ local pass doesn't guarantee a CI pass — the two environments can differ. Pushing first and
37
+ reading CI's results treats CI as authoritative: it either confirms the change works or tells you
38
+ exactly what to fix next, without you needing to separately maintain a local approximation of the
39
+ same signal.
@@ -0,0 +1,89 @@
1
+ # Write Documentation
2
+
3
+ Use this skill whenever you're writing or changing documentation in this repo: a doc comment
4
+ (TSDoc), a guide, an `upgrading/` or `blog/` page, a package README or `src/index.md`, or one of
5
+ these agent skills. The human contributor guides under
6
+ [Writing Documentation](/guides/contributing/writing-documentation/index.md) are the source of
7
+ truth for *what* good documentation looks like here; this skill is only about *how* to produce it
8
+ with the person you're working with. It links to those guides rather than restating them, because
9
+ a copied rule goes stale silently and gets followed confidently, while a link that goes stale
10
+ fails the link checker and gets fixed.
11
+
12
+ ## Steps
13
+
14
+ For a one-line fix (a typo, a dead link, a wrong version number), skip to step 6 and run only its
15
+ last two bullets: the checks and the label.
16
+
17
+ 1. Pick the type of doc first. A request like "document X" rarely means one file. Use
18
+ [Which Type of Doc Should I Write?](/guides/contributing/writing-documentation/index.md#which-type-of-doc-should-i-write)
19
+ to decide whether X needs TSDoc, a guide, a permanent-URL page, a README, or several of those,
20
+ and confirm that split with the user before drafting anything. If the answer is an RFC, this
21
+ isn't the skill for it: switch to [Writing and Implementing RFCs](./writing-and-implementing-rfcs.md).
22
+ 2. Read the guide for that type of doc before you write a word, and treat it as binding:
23
+
24
+ | Type of doc | Read |
25
+ | --- | --- |
26
+ | TSDoc comments | [Writing API Docs](/guides/contributing/writing-documentation/writing-api-docs.md) |
27
+ | A package `README.md` or its `src/index.md` landing page | [READMEs and `src/index.md`](/guides/contributing/writing-documentation/writing-api-docs.md#readmes-and-src-index-md) |
28
+ | Pages under `guides/`, including tutorials in `guides/tutorials/` | [Writing Guides](/guides/contributing/writing-documentation/writing-guides.md) |
29
+ | Pages under `upgrading/` or `blog/` | [Upgrading and Blog Pages](/guides/contributing/writing-documentation/writing-guides.md#upgrading-and-blog-pages) |
30
+ | Files under `warp-drive-packages/memory-alpha/skills/` | [Writing Agent Skills](/guides/contributing/writing-documentation/writing-agent-skills.md) |
31
+
32
+ Those pages own the rules on tags, links and examples, audiences, nav metadata, and permanent
33
+ URLs. Don't paraphrase them from memory; if a rule matters to your task, go read the sentence.
34
+ 3. Gather context before drafting. The person asking knows things the source can't tell you.
35
+ Ask, in a few short rounds rather than one wall of questions, and skip anything the type of
36
+ doc makes moot. Steps 1 and 3, and agreeing the headings in step 4, can be a single round.
37
+ - Who is this for? Use
38
+ [Know Your Audience](/guides/contributing/writing-documentation/index.md#know-your-audience)
39
+ as the menu; the guide for this type of doc narrows it further.
40
+ - What should the reader be able to do after reading it that they couldn't before?
41
+ - Which version does it apply to? The guide section for this type of doc says where that goes.
42
+ - Is this the recommended way, a legacy way, or a deprecated way? The guide for this type of
43
+ doc says how to mark each.
44
+ - What already exists? Search `guides/`, `upgrading/`, and the relevant `src/` for the concept
45
+ before writing a competing explanation; extend or link the existing one instead.
46
+ 4. Draft one section at a time, not the whole thing at once. Agree on the headings first (for
47
+ TSDoc, on which symbols get a summary, an example, and links), scaffold them with placeholders,
48
+ then fill each section and stop for feedback before moving to the next. Make edits surgically
49
+ in place rather than reprinting the document. Ask the user to describe what to change instead
50
+ of editing the draft themselves, so their preferences carry into the sections you haven't
51
+ written yet. Link the guide or symbol that owns a concept instead of re-explaining it.
52
+ 5. Reader-test before you call it done. Hand the finished text, and only the text (for TSDoc, the
53
+ comment together with the signature it documents), to a fresh agent instance that has none of
54
+ your conversation, along with three to five questions a real
55
+ reader would bring to it, and fix whatever it gets wrong or has to guess at. If you can't spawn
56
+ one, ask the user to paste the text into a fresh session and relay the answers. For API docs
57
+ the question is always some form of "how do I use this?"; if the answer requires opening the
58
+ source, the doc is missing an example or a link. For a guide, ask what prior knowledge it
59
+ assumes and whether that matches the audience you chose in step 3. For an `upgrading/` or
60
+ `blog/` page, ask which version the page is written for and whether a reader on a different
61
+ version can tell.
62
+ 6. Check, preview, then hand off:
63
+ - For API docs, every item in
64
+ [Content Standards](/guides/contributing/writing-documentation/writing-api-docs.md#content-standards),
65
+ and nothing private left in the published docs per
66
+ [Ignored Doc Comments](/guides/contributing/writing-documentation/writing-api-docs.md#ignored-doc-comments).
67
+ If you added `@internal` to an exported symbol, build that package (`pnpm --filter <pkg>
68
+ build:pkg`); a `MISSING_EXPORT` error means another package imports it and it needs a
69
+ different fix.
70
+ - Every other type of doc a change touches is updated too: see the
71
+ [Cross-Documentation Checklist](/guides/contributing/writing-documentation/index.md#cross-documentation-checklist).
72
+ - Run `pnpm lint:docs` from the repo root, then build and open the affected pages as described
73
+ in [Previewing Your Changes](/guides/contributing/writing-documentation/index.md#previewing-your-changes).
74
+ - Label the pull request `:label: doc` (see
75
+ [Changelog Labels](/guides/contributing/submitting-prs.md#changelog-labels)); Previewing
76
+ Your Changes says what that label deploys.
77
+
78
+ ## Gotchas
79
+
80
+ All three are explained in the
81
+ [Docs Viewer README](https://github.com/warp-drive-data/warp-drive/blob/main/docs-viewer/README.md).
82
+
83
+ - A page added while `pnpm start` is running is served but missing from the sidebar until you
84
+ restart the server.
85
+ - `pnpm lint:docs` does not check package READMEs; open those on GitHub.
86
+ - A bare `<thing>` in prose fails the build, and `lint:docs` won't warn you. Use code spans.
87
+ - `@internal` also strips the declaration from the package's `.d.ts`, so it breaks any other
88
+ package that imports the symbol. See
89
+ [Ignored Doc Comments](/guides/contributing/writing-documentation/writing-api-docs.md#ignored-doc-comments).
@@ -0,0 +1,77 @@
1
+ # Writing and Implementing RFCs
2
+
3
+ Use this skill when a task requires an RFC — a new public API, a behavior change, or a
4
+ deprecation — or when implementing one that has already been accepted.
5
+
6
+ ## When you need an RFC
7
+
8
+ Not every change needs one. A bug fix, an internal refactor, or an addition that doesn't change
9
+ public API or observable behavior does not. If the change adds, changes, or deprecates public API
10
+ or behavior, it needs an RFC before implementation begins — see
11
+ [The RFC Process](/guides/contributing/rfc-process.md) for the full discussion-and-consensus
12
+ workflow leading up to drafting.
13
+
14
+ ## Drafting
15
+
16
+ WarpDrive-specific RFCs live in [`rfcs/`](/rfcs/index.md) in this repository, which is the
17
+ **source of truth** — not `emberjs/rfcs`. Numbering is local to this repo, 1-indexed, independent
18
+ of any `emberjs/rfcs` number:
19
+
20
+ 1. Copy `rfcs/0000-template.md` to `rfcs/000N-your-title.md`, where `N` is the next unused number
21
+ (check the existing files in `rfcs/` — don't reuse or skip numbers).
22
+ 2. Fill in the template's frontmatter and body. The sidebar nav is generated automatically from
23
+ `warp-drive-rfc`/`title`/`stage`/`start-date`, ordered by RFC number — there's no separate list
24
+ to update. Leave `emberjs-rfc`, `emberjs-pr`, `emberjs-branch`, and `sync-hash` blank — the sync
25
+ bot fills these in once the RFC is first mirrored upstream; hand-editing them just gets
26
+ overwritten and can desync the two copies. Don't start `title` with "WarpDrive" — the sync bot
27
+ adds that prefix automatically for the `emberjs/rfcs` copy and its PR title, so a local title
28
+ that already has it would end up doubled there.
29
+ 3. Open a PR labeled `:label: rfc` (see
30
+ [Pull Request Labeling](/guides/contributing/submitting-prs.md#pull-request-labeling) for the
31
+ PR mechanics). That label also triggers a docs-site PR preview so reviewers can read the
32
+ rendered RFC, not just the raw markdown diff.
33
+ 4. Iterate on the PR like any other design discussion. Once there is team consensus to move
34
+ forward, merging the PR is what publishes the RFC — see the next section for what that
35
+ triggers.
36
+
37
+ ## How the `emberjs/rfcs` sync works
38
+
39
+ WarpDrive still follows Ember's RFC process end to end (Proposed → Exploring → FCP → Accepted →
40
+ Ready for Release → Released → Recommended, per
41
+ [emberjs/rfcs' own stages](https://github.com/emberjs/rfcs#stages)) — those stages are tracked and
42
+ voted on in `emberjs/rfcs`, not here. What changes is *where the text lives and who edits it
43
+ first*: this repo, not `emberjs/rfcs`, is authoritative for the content.
44
+
45
+ A dedicated bot account (see `scripts/rfc-sync/README.md`) maintains its own fork of
46
+ `emberjs/rfcs` and does the mirroring, entirely through PRs on both sides — it never has direct
47
+ write access to `emberjs/rfcs` itself, and never merges anything:
48
+
49
+ - **Outbound** (on merge to `main` here): a new RFC (no `emberjs-rfc` set yet) gets a brand-new PR
50
+ opened against `emberjs/rfcs` from the bot's fork; an already-published RFC gets a new commit
51
+ pushed to the same fork branch that already backs its open `emberjs/rfcs` PR. Either way, the
52
+ commit's author is set to whoever actually wrote the change in this repo — the bot only ever
53
+ appears as committer, never author, so credit for the words stays with the person who wrote
54
+ them.
55
+ - **Inbound**: the bot polls its own fork branches for commits it didn't make itself — e.g. an
56
+ Ember reviewer applying a suggested edit directly on the PR (this requires "allow edits from
57
+ maintainers", which the bot sets when opening the PR). When it finds one, it opens a PR back
58
+ into `warp-drive-data/warp-drive` with that change, again crediting the real author.
59
+ - Nothing is ever auto-merged on either side. Every sync lands as a PR for a human to review.
60
+
61
+ If you're picking up an RFC that predates the bot (its `emberjs-branch` frontmatter field is
62
+ blank), the bot can't sync it until a maintainer points it at the right upstream fork branch, or
63
+ lets it open a fresh PR — ask in `#dev-ember-data` if you hit this.
64
+
65
+ ## Implementing an accepted RFC
66
+
67
+ - Reference the RFC number in your implementation PR's description (e.g. "Implements
68
+ `rfcs/0003-...`"), so reviewers and future readers can find the design discussion.
69
+ - Land the implementation behind the same phased/deprecation approach the RFC describes, if it
70
+ describes one — don't skip straight to the end state an RFC called out as a later phase.
71
+ - Ship the documentation with the implementation. An accepted RFC is the first item in the
72
+ [Cross-Documentation Checklist](/guides/contributing/writing-documentation/index.md#cross-documentation-checklist)
73
+ for a new public API or a deprecation; the TSDoc, guide, and upgrade page it lists come next.
74
+ Follow [Write Documentation](./write-documentation.md) for those.
75
+ - Once landed, `stage` in the RFC's frontmatter (both here and, via the sync bot, upstream)
76
+ advances the same way `emberjs/rfcs` advancement PRs do today — this repo does not add a
77
+ separate advancement mechanism.
@@ -0,0 +1,7 @@
1
+ {
2
+ "title": "Holodeck",
3
+ "items": ["using-record"],
4
+ "files": {
5
+ "using-record": { "title": "Use RECORD in Holodeck Mocks" }
6
+ }
7
+ }
@@ -0,0 +1,58 @@
1
+ # Use RECORD in Holodeck Mocks
2
+
3
+ Use this skill when a test mocks HTTP with `@warp-drive/holodeck` and you need to re-record one
4
+ request, or when you are reviewing a test that sets `RECORD`. `RECORD` is a per-request override.
5
+ It is a local tool for refreshing a fixture, not a setting a committed test should carry.
6
+
7
+ ## How recording is decided
8
+
9
+ Holodeck records or replays according to a build-time flag from `@warp-drive/build-config`.
10
+
11
+ ```ts
12
+ const SHOULD_RECORD = Boolean(!CI || IS_RECORDING);
13
+ ```
14
+
15
+ A local run records every mock. A run with `CI` set replays every mock from `.mock-cache`. `RECORD`
16
+ overrides that for a single mock: it records the request even when the rest of the suite replays.
17
+
18
+ ## Steps
19
+
20
+ 1. Rely on the default first. To change a response, edit the mock and run the suite locally. It
21
+ re-records without any option.
22
+ 2. Reach for `RECORD` only when one request has to record while the suite replays, for example when
23
+ you run with `CI=1` locally and need a single fixture refreshed.
24
+
25
+ ```ts
26
+ await GET(this, 'users/1', () => ({ data: { id: '1', type: 'user' } }), { RECORD: true });
27
+ ```
28
+
29
+ `POST`, `PUT`, `PATCH`, `DELETE`, and `HEAD` take the same option. The low-level form is
30
+ `mock(this, generate, true)`.
31
+ 3. Run the test, then commit the fixture it wrote under `.mock-cache`.
32
+ 4. Delete `RECORD` from the test before you commit the test.
33
+ 5. Prove the fixture replays. `CI` is compiled into the test bundle, so set it on the command that
34
+ builds as well as the one that runs.
35
+
36
+ ```sh
37
+ CI=1 pnpm build:tests && CI=1 pnpm test
38
+ ```
39
+
40
+ ## Why RECORD must not be committed
41
+
42
+ A committed `RECORD: true` records that request in every environment, CI included. The request is
43
+ never compared against its committed fixture again, so the test passes whatever that fixture says,
44
+ and a stale or wrong fixture goes unnoticed. The rest of the suite still replays, which makes the
45
+ one exception easy to miss in review.
46
+
47
+ ## Notes
48
+
49
+ - With `RECORD`, the response generator runs even in replay. Without it, replay never calls the
50
+ generator, which is what makes a replayed suite cheap.
51
+ - A test that declares a mock and never requests it fails from `afterEach`, with or
52
+ without `RECORD`.
53
+ - Treat `RECORD` in a diff the way you treat a focused or skipped test: ask for it to be removed
54
+ before merge.
55
+
56
+ ## Related
57
+
58
+ - Related skill: [Fetch and Cache Data](/skills/requests/fetch-and-cache-data)
package/skills/index.md CHANGED
@@ -9,6 +9,7 @@ complete a task.
9
9
  | --- | --- |
10
10
  | Define a resource's shape — fields, relationships, identity — for the `Store` | `schemas/define-a-resource-schema.md` |
11
11
  | Fetch or query remote data through the `Store` so it's cached and reactive | `requests/fetch-and-cache-data.md` |
12
+ | Re-record one holodeck mock, or review a test that sets `RECORD` | `holodeck/using-record.md` |
12
13
  | You're contributing to WarpDrive itself, not just consuming it as a dependency | `contributors/index.md` |
13
14
 
14
15
  Each skill file is self-contained for its task and links out to any other skill file it
@@ -18,6 +18,7 @@ Find the row below that matches what you're doing, or browse the categories in t
18
18
  | --- | --- |
19
19
  | Define a resource's shape — fields, relationships, identity — for the `Store` | [Define a Resource Schema](/skills/schemas/define-a-resource-schema.md) |
20
20
  | Fetch or query remote data through the `Store` so it's cached and reactive | [Fetch and Cache Data](/skills/requests/fetch-and-cache-data.md) |
21
+ | Re-record one holodeck mock, or review a test that sets `RECORD` | [Use RECORD in Holodeck Mocks](/skills/holodeck/using-record.md) |
21
22
  | You're contributing to WarpDrive itself, not just consuming it as a dependency | [Contributor Skills](/skills/contributors/index.md) |
22
23
 
23
24
  This is the same routing table an AI agent uses to find a skill — it just links out to readable