@graftsync/skill 0.1.1 → 0.2.0

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.
Files changed (2) hide show
  1. package/SKILL.md +57 -40
  2. package/package.json +1 -1
package/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: graft-sync
3
- description: Keep local modifications ("grafts") to upstream npm packages working when upstream releases a new version. Use when a repo has a `.grafts/` directory and an upstream dependency was bumped, `graft sync` reported `needs-agent`, a graft's anchors miss or its oracle fails, or you are asked to sync, repair, add, or retire a graft.
3
+ description: Keep local modifications ("grafts") to upstream npm packages working when upstream releases a new version. Use when a repo has a `.grafts/` directory and an upstream dependency was bumped, `graft sync` reported `needs-agent`, a graft's anchors miss or its tests fail after an upgrade, or you are asked to sync, repair, add, or retire a graft.
4
4
  ---
5
5
 
6
6
  # Graft sync
@@ -17,19 +17,19 @@ https://github.com/brandonroberts/graft/blob/main/docs/spec.md
17
17
 
18
18
  `graft.md` frontmatter:
19
19
 
20
- - `rootstock.package` / `rootstock.verified` — upstream package and the last version the
21
- oracle passed against.
20
+ - `rootstock.package` / `rootstock.verified` — upstream package and the last version the graft
21
+ was verified against.
22
22
  - `mechanism` — how it is applied (e.g. `patch`: a pnpm `patchedDependencies` patch file).
23
23
  - `variants` — one implementation per upstream version range (`range` + `module` path).
24
24
  Ranges are disjoint; exactly one variant applies to any version.
25
- - `oracle` — the command that proves the invariants hold, run once per `mode`
26
- (with `GRAFT_MODE` and `GRAFT_UPSTREAM_VERSION` set).
27
25
  - `status` — `applied` | `conflicted` | `upstreamed` | `obsolete`.
28
26
 
29
27
  Body sections, all required — read them before touching anything:
30
28
 
31
29
  - **Why** — what the modification enables and why upstream doesn't do it.
32
- - **Invariants** — observable behaviors that must hold. **This is the contract.**
30
+ - **Invariants** — observable behaviors that must hold, and which of the project's tests cover
31
+ them. **This is the contract, and verifying it is your job:** Graft only checks that a graft
32
+ still *fits* (anchors, apply, install). It runs no tests.
33
33
  - **Where to look** — the upstream area, described by behavior so you can re-find it after
34
34
  a refactor. Trust this over file paths.
35
35
  - **Anchors** — what each variant matches on and why it was chosen.
@@ -51,7 +51,7 @@ the project root. Exit codes: `0` ok, `1` something needs attention, `2` tooling
51
51
  | Apply a variant to pristine upstream, for inspection | `graft preview <id> [--version X] [--out dir]` |
52
52
  | Register a new variant | `graft variant add <id> --range R --module ./variants/… --verify-version X --note "…"` |
53
53
  | Wire the package manager to the selected variants + reinstall | `graft apply` |
54
- | Prove it | `graft verify <id>` |
54
+ | Prove the Invariants | the project's own tests (see *Invariants*) |
55
55
  | Status, verified version, History | `graft mark <id> [--status S] [--verified X] [--history "…"]` |
56
56
  | Where a variant fits across published versions | `graft replay <id> [--range R]` |
57
57
 
@@ -65,7 +65,7 @@ Reports from `sync` land in `.grafts/.report/` (`sync.md`, `sync.json`, and per
65
65
  `verified` and wrote History. Only grafts marked `needs-agent` are yours.
66
66
  2. **Gather context for each `needs-agent` graft**, in this order:
67
67
  `graft show <id>` → the reasons in the sync report → `graft check <id> --version <target>` →
68
- `graft diff <id>` (from `verified` to the target) → the failing oracle output, if the oracle ran.
68
+ `graft diff <id>` (from `verified` to the target).
69
69
  3. **Locate the new equivalent code by behavior.** Use *Where to look* and *Anchors*, then
70
70
  the scoped diff. If a target file was removed or renamed, search the new version's
71
71
  published files for the behavior (the pristine copy is under `.grafts/.cache/upstream/`). Upstream
@@ -81,32 +81,45 @@ Reports from `sync` land in `.grafts/.report/` (`sync.md`, `sync.json`, and per
81
81
  refuses (and rolls back) if the anchors don't match at the target. Older open-ended ranges
82
82
  are narrowed automatically; existing variant files are never touched. Then
83
83
  `graft check <id> --version <target>` should be clean.
84
- 7. **Prove it:** re-run `graft sync --version <target> --install`. With anchors now matching,
85
- it wires the package manager to the new variant, installs the target, and runs the oracle
86
- in every mode; on green it sets `verified` and status `applied`. (Or install yourself, run
87
- `graft verify <id>`, then `graft mark <id> --status applied --verified <target>`.)
88
- 8. **Finish:** open a PR (see below).
84
+ 7. **Check it fits:** re-run `graft sync --version <target> --install`. With anchors now
85
+ matching, it wires the package manager to the new variant, installs the target, and on green
86
+ sets `verified` and status `applied`.
87
+ 8. **Prove the Invariants** at the target with the project's tests: run the ones *Invariants*
88
+ names (and the suite), and add a test for any Invariant nothing covers. Show it fails
89
+ without the graft. If a test fails, the graft isn't done, whatever sync said: fix the
90
+ variant, or stop (see *When to stop*).
91
+ 9. **Finish:** open a PR (see below), saying how you verified each Invariant.
89
92
 
90
93
  ## Adding a new graft
91
94
 
92
95
  When asked to capture a modification as a graft (new, or migrating an existing patch):
93
96
 
94
97
  1. **Scaffold:** `graft init --agent` (once; it also installs this skill), then `graft add <id> --package <pkg> --target <file>`.
95
- This creates `graft.md`, an empty variant stub (which fails loudly until written), and an
96
- oracle stub that exits 1.
98
+ This creates `graft.md` and an empty variant stub (which fails loudly until written).
97
99
  2. **Write the intent first,** with the person who owns the modification if you can: *Why*,
98
100
  the *Invariants* (observable behaviors, one per bullet), *Where to look* (by behavior), and
99
101
  *Anchors* (what the variant matches on and why).
100
- 3. **Write the variant.** For `patch`: run `pnpm patch <pkg>@<installed>`, make the change in the
101
- printed directory, then run `pnpm patch-commit <dir> --patches-dir <tmp>`. Move the generated
102
- file onto the scaffolded `variants/v<major>.patch`. `pnpm patch-commit` may also write a
103
- version-pinned entry to `package.json`; the next step replaces it.
102
+ 3. **Write the variant.** For `patch`, make the change in the installed package
103
+ (`node_modules/<pkg>`), then run `graft capture <id>`: it writes the difference from the
104
+ published package as the variant (replacing the scaffold stub), and refuses binary changes.
105
+ **With pnpm**, don't edit `node_modules` in place (its files are hard links into the shared
106
+ store): run `pnpm patch <pkg>@<installed>`, edit the printed directory, `pnpm patch-commit
107
+ <dir> --patches-dir <tmp>`, and move the generated file onto `variants/v<major>.patch`
108
+ (`pnpm patch-commit` may also write a `package.json` entry; the next step replaces it).
104
109
  4. **Apply it:** `graft apply`. This points the package manager at the
105
110
  variant, reinstalls, and re-checks anchors.
106
- 5. **Write the oracle** so it fails before the modification and passes after. Check that it
107
- fails without the graft. An oracle that can't fail proves nothing. Test the Invariants,
108
- plus at least one pre-existing behavior the graft must not break.
109
- 6. **Prove it:** `graft verify <id>`, then `graft sync` (green).
111
+ 5. **Cover the Invariants with the project's tests.** Find the tests that exercise each
112
+ Invariant, or add them to the project's suite, and name them under *Invariants*. Show each
113
+ fails without the modification and passes with it: a test that can't fail proves nothing.
114
+ Also keep one pre-existing behavior the graft must not break covered.
115
+ - **Test what the graft changes, not the whole stack.** For a patch that stops a dependency
116
+ loading Node polyfills, assert it doesn't load them (e.g. via `require.cache`); you don't
117
+ need a browser or a build.
118
+ - **Browser tests** (Playwright etc.), when you need one, fail on uncaught page errors,
119
+ **`console.error`** messages and failed (5xx) requests: Angular's `ErrorHandler`, React
120
+ error boundaries and Vue's `errorHandler` catch errors and only log them. Assert something
121
+ visible that depends on the graft, and stop any server you start on every exit.
122
+ 6. **Check it:** `graft sync` (green), and the project's tests pass.
110
123
  7. **Find the variant's real range:** `graft replay <id>` checks every published version.
111
124
  Record what you learn in *History*.
112
125
 
@@ -114,12 +127,13 @@ When asked to capture a modification as a graft (new, or migrating an existing p
114
127
 
115
128
  - **Never edit an existing variant.** Older version ranges keep their variants and tests.
116
129
  Write a new file for the new range. `graft variant add` refuses to re-register a file.
117
- - **The Invariants are the contract and the oracle is the only proof.** Anchors matching or a
118
- clean apply is not success; a passing oracle is.
119
- - **Never weaken the oracle** to get green: don't skip, loosen, or delete checks, and don't
120
- change Invariants to match what you built. If an invariant is genuinely obsolete, say so
121
- and ask a human.
122
- - **Never set `verified`** to a version the oracle has not passed against.
130
+ - **The Invariants are the contract, and you verify them.** A green sync means the change still
131
+ fits and installs, not that it still works. Prove the Invariants with the project's tests.
132
+ - **Never weaken a test** to get green: don't skip, loosen, or delete checks, and don't change
133
+ Invariants to match what you built. If an invariant is genuinely obsolete, say so and ask a
134
+ human.
135
+ - **Never set `verified`** (or register a variant) for a version you haven't verified the
136
+ Invariants at.
123
137
  - **Fail loudly.** A graft that silently applies nothing is the worst outcome. Anchors must
124
138
  match exactly once; don't add fuzz, catch-alls, or "skip if not found" logic.
125
139
  - **Anchor by behavior.** Prefer stable exported names, public API lists, and user-facing
@@ -163,8 +177,8 @@ When asked to capture a modification as a graft (new, or migrating an existing p
163
177
  - If the graft's variants are generated, give it a `generator: { command }` in its
164
178
  frontmatter (`{version}` and `{out}` are substituted; e.g.
165
179
  `node tools/cjs-to-esm/make-variant.mjs semver {version} {out}`). `graft sync` then
166
- regenerates and registers a variant itself when the old one misses, and keeps it only if
167
- the oracle passes. If sync still hands the graft to you, its reasons say what the generator
180
+ regenerates and registers a variant itself when the old one misses, and keeps it only if it
181
+ fits and installs. If sync still hands the graft to you, its reasons say what the generator
168
182
  did; the rejected output is under `.grafts/.report/<id>/regenerated/`. Fix the generator
169
183
  or review that output rather than hand-patching the old variant.
170
184
 
@@ -188,13 +202,14 @@ When asked to capture a modification as a graft (new, or migrating an existing p
188
202
  `{ "ref": "graft/<id>-<target>", "base": "<target>" }`. Register it with
189
203
  `graft variant add <id> --range '>=<target>' --module ./variants/v<target>.json
190
204
  --verify-version <target>`.
191
- 4. Prove it with `graft sync --version <target> --install`.
205
+ 4. Check it with `graft sync --version <target> --install`, then prove the Invariants with the
206
+ project's tests.
192
207
  - **Repo mode** (`fork.install: none`): the fork is the product (e.g. a translated docs site),
193
- nothing is installed, and the oracle runs in the rebased checkout. The diff in
208
+ nothing is installed, and a green sync materializes the rebased checkout. The diff in
194
209
  `.grafts/.report/<id>/diff.patch` is what upstream changed since the fork's base in the files
195
210
  the fork touches. A clean rebase is not enough: upstream text that lands next to the change
196
- (e.g. a new English paragraph in a translated page) only fails the oracle, so read its
197
- output. Same fix steps as above, with `graft sync --version <target>` (no `--install`). A
211
+ (e.g. a new English paragraph in a translated page) merges without a conflict, so run the
212
+ project's checks (the graft's *Invariants* say which) on the result. Same fix steps as above, with `graft sync --version <target>` (no `--install`). A
198
213
  green sync leaves the result as branch `graft/<id>/<target>` in `.grafts/.cache/fork/<id>`;
199
214
  fetch it from there. Never push it unless the user asks.
200
215
  - A target can be an upstream commit between releases: `--version 22.3.0-next.3+<sha>` (the
@@ -205,7 +220,7 @@ When asked to capture a modification as a graft (new, or migrating an existing p
205
220
  variant. A green sync puts the new `verified` only in the result branch; adopt it with
206
221
  `git fetch <repo> <ref> && git read-tree -u --reset FETCH_HEAD`. On the `-agent` branch,
207
222
  graft.md already says the target version (`status: conflicted`): resolve, then
208
- `graft sync --version <target>` verifies the working tree as it is.
223
+ `graft sync --version <target>` checks the working tree as it is; then run the project's checks.
209
224
  - **Start from the prepared branch.** On `needs-agent`, the report's "Start from" line names
210
225
  `graft/<id>/<target>-agent` in the cache clone: git's merge of the fork's change onto the
211
226
  target, with conflict markers left only in the files it lists. Fetch it into the fork, resolve
@@ -219,7 +234,7 @@ Stop and mark the graft `conflicted` (`graft mark <id> --status conflicted --his
219
234
 
220
235
  - the behavior the graft modifies no longer exists upstream, or upstream changed it in a way
221
236
  that makes an invariant impossible or contradictory;
222
- - you cannot make the oracle pass in every mode without weakening it;
237
+ - you cannot make the project's tests pass for an Invariant without weakening them;
223
238
  - upstream now does what the graft did — say so; a human decides whether to mark it
224
239
  `upstreamed`. Graft detects the common case for you: when the variant no longer applies
225
240
  but upstream already contains its change (for patches, the reverse patch applies cleanly),
@@ -240,7 +255,9 @@ at everything else: `GRAFT_SKILL_PATH` (this file), `GRAFT_COMMAND` (how to run
240
255
  `GRAFT_TARGET_VERSION`, and `GRAFT_BRANCH` (already checked out).
241
256
 
242
257
  - Do **not** commit, push, or open a pull request. The action re-runs `graft sync` on your
243
- work and opens the PR itself: a normal PR only if the oracle passes, otherwise a draft.
258
+ work and opens the PR itself: a normal PR when every graft fits, otherwise a draft. It can't
259
+ check behavior: prove the Invariants with the project's tests before you finish, and say how
260
+ in the PR description.
244
261
  - Write the PR description (format below) to `GRAFT_PR_BODY_FILE`.
245
262
 
246
263
  ## PR description
@@ -256,8 +273,8 @@ at everything else: `GRAFT_SKILL_PATH` (this file), `GRAFT_COMMAND` (how to run
256
273
  **What changed upstream:** <the behavior-level change, citing the scoped diff>
257
274
  **Anchors that moved:** <anchor names, and where they went>
258
275
  **New variant:** `variants/<file>` for `<range>` — <how it differs from the previous variant>
259
- **Proof:** oracle passed in <modes> against <package>@<target>
276
+ **Verified:** <which tests, covering which Invariants, passed against <package>@<target>>
260
277
  ```
261
278
 
262
- For a conflicted graft, replace *New variant* and *Proof* with **Failing invariant**,
279
+ For a conflicted graft, replace *New variant* and *Verified* with **Failing invariant**,
263
280
  **What was tried**, and **What a human needs to decide**.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graftsync/skill",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Agent skill (SKILL.md) teaching coding agents the graft sync loop.",
5
5
  "license": "MIT",
6
6
  "repository": {