nodeengine 0.1.0__tar.gz
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.
- nodeengine-0.1.0/.claude-plugin/marketplace.json +31 -0
- nodeengine-0.1.0/.claude-plugin/plugin.json +22 -0
- nodeengine-0.1.0/.gitignore +6 -0
- nodeengine-0.1.0/CLAUDE.md +151 -0
- nodeengine-0.1.0/LICENSE +21 -0
- nodeengine-0.1.0/PKG-INFO +173 -0
- nodeengine-0.1.0/README.md +163 -0
- nodeengine-0.1.0/commands/install.md +92 -0
- nodeengine-0.1.0/docs/SYNCING.md +98 -0
- nodeengine-0.1.0/install.py +152 -0
- nodeengine-0.1.0/pyproject.toml +37 -0
- nodeengine-0.1.0/skills/node-engine/SKILL.md +155 -0
- nodeengine-0.1.0/skills/node-engine/reference/patterns.md +166 -0
- nodeengine-0.1.0/skills/node-engine/reference/taxonomy.md +59 -0
- nodeengine-0.1.0/skills/node-engine/reference/traps.md +256 -0
- nodeengine-0.1.0/skills/node-engine/scaffold/checkall.py +78 -0
- nodeengine-0.1.0/skills/node-engine/scaffold/stale.py +150 -0
- nodeengine-0.1.0/skills/node-engine/scaffold/viewer.html +178 -0
- nodeengine-0.1.0/tools/check_claude_md.py +183 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
|
3
|
+
"name": "node-engine",
|
|
4
|
+
"description": "Hash-and-compare guards so derived things report stale instead of silently lying",
|
|
5
|
+
"owner": {
|
|
6
|
+
"name": "Alexyodude",
|
|
7
|
+
"email": "jihoonhotmail.com@gmail.com"
|
|
8
|
+
},
|
|
9
|
+
"plugins": [
|
|
10
|
+
{
|
|
11
|
+
"name": "node-engine",
|
|
12
|
+
"description": "Make staleness fail a check instead of relying on someone remembering. Sets up hash-and-compare guards for summaries, translations, generated files and any fact restated in prose. Carries the discipline too: fix the class not the instance, and a new check is guilty until it has failed on demand.",
|
|
13
|
+
"version": "0.1.0",
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "Alexyodude",
|
|
16
|
+
"email": "jihoonhotmail.com@gmail.com"
|
|
17
|
+
},
|
|
18
|
+
"source": "./",
|
|
19
|
+
"category": "quality",
|
|
20
|
+
"homepage": "https://github.com/Alexyodude/NodeEngine",
|
|
21
|
+
"tags": [
|
|
22
|
+
"drift",
|
|
23
|
+
"consistency",
|
|
24
|
+
"documentation",
|
|
25
|
+
"checks",
|
|
26
|
+
"content-addressing"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"version": "0.1.0"
|
|
31
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "node-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Make staleness fail a check instead of relying on someone remembering. Hash-and-compare guards for derived facts, generated artefacts and translations.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Alexyodude",
|
|
7
|
+
"email": "jihoonhotmail.com@gmail.com"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/Alexyodude/NodeEngine",
|
|
10
|
+
"homepage": "https://github.com/Alexyodude/NodeEngine",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"claude-code",
|
|
14
|
+
"plugin",
|
|
15
|
+
"documentation",
|
|
16
|
+
"drift",
|
|
17
|
+
"consistency",
|
|
18
|
+
"checks",
|
|
19
|
+
"provenance"
|
|
20
|
+
],
|
|
21
|
+
"skills": "./skills/"
|
|
22
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# NodeEngine
|
|
2
|
+
|
|
3
|
+
A Claude Code **plugin** that makes staleness fail a check instead of relying on
|
|
4
|
+
someone remembering. It ships one skill and a copyable scaffold.
|
|
5
|
+
|
|
6
|
+
**This repo is mostly prose, and the prose is the product.** The scaffold is
|
|
7
|
+
~150 lines of Python plus a self-contained HTML viewer; the value is in
|
|
8
|
+
`SKILL.md` and `reference/`. Edits that make the guidance vaguer make the
|
|
9
|
+
plugin worse, even when they make it shorter.
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
| Command | Description |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `python skills/node-engine/scaffold/stale.py` | No CLI — it is a module. Import it to smoke-test. |
|
|
16
|
+
| `python -c "import sys; sys.path.insert(0,'skills/node-engine/scaffold'); import stale"` | Confirm the scaffold imports |
|
|
17
|
+
| `python skills/node-engine/scaffold/checkall.py --prove` | Print how to break each check in the runner |
|
|
18
|
+
| `python tools/check_claude_md.py` | Is this file still true? Paths exist, versions agree, sections vs the template |
|
|
19
|
+
| `python install.py --dry-run` | Show what installing into the current repo would write |
|
|
20
|
+
| `python install.py --into <dir>` | Copy the scaffold elsewhere; finds the git root, refuses to overwrite |
|
|
21
|
+
| `uvx --from <this repo> nodeengine --dry-run` | The same installer via its packaged entry point — exercises `pyproject.toml` |
|
|
22
|
+
|
|
23
|
+
There is no build and no test suite. The scaffold is copied into other projects,
|
|
24
|
+
not executed here — `install.py` is the copier, and `commands/install.md` is the
|
|
25
|
+
`/node-engine:install` command that runs it and then walks the wiring-up.
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
NodeEngine/
|
|
31
|
+
install.py copies the scaffold into another repo
|
|
32
|
+
pyproject.toml packages install.py ONLY, so `uvx nodeengine` works
|
|
33
|
+
commands/
|
|
34
|
+
install.md /node-engine:install — copy, then wire it up
|
|
35
|
+
tools/
|
|
36
|
+
check_claude_md.py is CLAUDE.md still true? (see docs/SYNCING.md)
|
|
37
|
+
docs/
|
|
38
|
+
SYNCING.md why the template is checked, not synced
|
|
39
|
+
.claude-plugin/
|
|
40
|
+
plugin.json the manifest; `skills` points at ./skills/
|
|
41
|
+
marketplace.json makes the repo installable as its own marketplace
|
|
42
|
+
skills/node-engine/
|
|
43
|
+
SKILL.md the method, the rule, when NOT to use it
|
|
44
|
+
reference/
|
|
45
|
+
patterns.md the three shapes, with implementations
|
|
46
|
+
traps.md ten checks that could not fail — all real
|
|
47
|
+
taxonomy.md thirteen defect classes
|
|
48
|
+
scaffold/
|
|
49
|
+
stale.py store + comparators, meant to be read and edited
|
|
50
|
+
checkall.py the runner
|
|
51
|
+
viewer.html browser search over the stores; keyOf must match key_of
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**The version appears in four places** — `plugin.json`, twice in
|
|
55
|
+
`marketplace.json` (the plugin entry and the top-level field), and
|
|
56
|
+
`pyproject.toml`. They must agree. This is precisely the class of defect the
|
|
57
|
+
plugin exists to catch; `tools/check_claude_md.py` fails if they disagree,
|
|
58
|
+
including the TOML one — its JSON glob never sees `pyproject.toml`, so that
|
|
59
|
+
copy needed its own read, proven by breaking it (`0.9.9` → exit 1).
|
|
60
|
+
|
|
61
|
+
## Key files
|
|
62
|
+
|
|
63
|
+
- `skills/node-engine/SKILL.md` — what an agent loads. Frontmatter `description`
|
|
64
|
+
is what makes it fire, so it must name the symptoms someone would actually
|
|
65
|
+
type ("stop this drifting", "why did that go stale"), not just the concept.
|
|
66
|
+
- `skills/node-engine/reference/traps.md` — the highest-value file. Ten worked
|
|
67
|
+
examples of checks that shipped unable to fail.
|
|
68
|
+
- `skills/node-engine/scaffold/stale.py` — deliberately not a library.
|
|
69
|
+
|
|
70
|
+
## Editing conventions
|
|
71
|
+
|
|
72
|
+
**Keep the examples concrete and real.** Every example in `reference/` is from a
|
|
73
|
+
project that actually shipped the defect. `"A check compared PDFs to themselves
|
|
74
|
+
and reported 9 rendered and current"` transfers; `"ensure comparison operands
|
|
75
|
+
differ"` does not. Do not generalise an example to make it tidier.
|
|
76
|
+
|
|
77
|
+
**The scaffold is copied, not imported.** Its docstrings say so. Do not add
|
|
78
|
+
dependencies or packaging *to the scaffold* — a dependency you cannot read is
|
|
79
|
+
one you will trust when it is wrong, which is the failure the plugin exists to
|
|
80
|
+
prevent. The root `pyproject.toml` is not an exception: it packages the
|
|
81
|
+
*installer* as the `nodeengine` entry point, and what that entry point does is
|
|
82
|
+
still copy readable files into `tools/`. If a change would make the scaffold
|
|
83
|
+
itself installable or importable, it is wrong.
|
|
84
|
+
|
|
85
|
+
**Do not strip the dense docstrings.** They record the measured defect each
|
|
86
|
+
guard was built to catch. That is institutional knowledge, not slop.
|
|
87
|
+
|
|
88
|
+
## Gotchas
|
|
89
|
+
|
|
90
|
+
- **`.omc/` reappears constantly.** OMC writes state into whatever directory a
|
|
91
|
+
command runs from, including this one and `skills/node-engine/scaffold/`. It is
|
|
92
|
+
gitignored; check `git status` before committing anyway.
|
|
93
|
+
- **`__pycache__/` appears in `scaffold/`** the moment anything imports `stale.py`
|
|
94
|
+
from there. Also gitignored.
|
|
95
|
+
- **Git reports LF→CRLF warnings on every commit** on Windows. Harmless.
|
|
96
|
+
- **Installing from a local path is not the same as from GitHub.** Test with
|
|
97
|
+
`/plugin marketplace add <path>` before pushing, then again from the remote —
|
|
98
|
+
the manifest is only exercised properly on a real install.
|
|
99
|
+
|
|
100
|
+
## Publishing
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
git push -u origin main
|
|
104
|
+
/plugin marketplace add Alexyodude/NodeEngine
|
|
105
|
+
/plugin install node-engine@node-engine
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Bump the version in **all four places** together — `plugin.json`, twice in
|
|
109
|
+
`marketplace.json`, `pyproject.toml` — or the install will resolve to something
|
|
110
|
+
that does not exist. `check_claude_md.py` catches a missed one.
|
|
111
|
+
|
|
112
|
+
## Known gaps
|
|
113
|
+
|
|
114
|
+
- ~~The one-line installer 404s until the repo is public.~~ **Closed 2026-08-31**
|
|
115
|
+
— the repo is public and the happy path is verified: both
|
|
116
|
+
`curl -fsSL .../install.py | python` and `uv run <github raw URL>` installed
|
|
117
|
+
`stale.py` + `checkall.py` into a fresh repo's `tools/`, exit 0. Before the
|
|
118
|
+
push, a 404 body was piped straight into the interpreter (`<!DOCTYPE html>`
|
|
119
|
+
SyntaxError) — `curl` needs `-f`, and `uv run` does not check HTTP status.
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
Stated plainly because this plugin is about not letting claims drift:
|
|
123
|
+
|
|
124
|
+
- ~~The version is restated in three places and nothing checks it.~~ **Closed**
|
|
125
|
+
— `tools/check_claude_md.py` fails if the manifests disagree. Proven by
|
|
126
|
+
setting `plugin.json` to `0.2.0` and watching it fire.
|
|
127
|
+
- **`nodeengine` is not on PyPI**, so the bare `uvx nodeengine` / `pipx run
|
|
128
|
+
nodeengine` does not resolve. What works without a publish is
|
|
129
|
+
`uvx --from git+https://github.com/Alexyodude/NodeEngine nodeengine`. The
|
|
130
|
+
name was free on PyPI as of 2026-08-31 — publishing would claim it and make
|
|
131
|
+
the two-word form real.
|
|
132
|
+
- **The scaffold has no tests.** Its correctness is asserted by the reference
|
|
133
|
+
docs, not demonstrated. `checkall.py --prove` prints how to break the checks
|
|
134
|
+
it describes, but nothing runs them here.
|
|
135
|
+
- The skill has never been invoked cold in an unfamiliar repo. Until it has, the
|
|
136
|
+
claim that it "sets up guards in any repo" is untested.
|
|
137
|
+
|
|
138
|
+
## Upstream template
|
|
139
|
+
|
|
140
|
+
`CLAUDE.md` here follows the template in the `claude-md-management` plugin
|
|
141
|
+
(`skills/claude-md-improver/references/templates.md`). To re-check this file
|
|
142
|
+
against the current upstream guidance:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
/plugin marketplace update claude-plugins-official
|
|
146
|
+
/revise-claude-md
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The template is *guidance*, not a file to copy — there is no automatic sync, and
|
|
150
|
+
`/revise-claude-md` reads the session for learnings rather than diffing against
|
|
151
|
+
the template. See `docs/SYNCING.md` for what can and cannot be automated.
|
nodeengine-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexyodude
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: nodeengine
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Install the NodeEngine staleness-guard scaffold into the current repo
|
|
5
|
+
Project-URL: Homepage, https://github.com/Alexyodude/NodeEngine
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# NodeEngine
|
|
12
|
+
|
|
13
|
+
A Claude Code plugin. Makes staleness **fail a check** instead of relying on
|
|
14
|
+
someone remembering.
|
|
15
|
+
|
|
16
|
+
*The name is literal: what it builds is a graph of **nodes** — clauses, blocks,
|
|
17
|
+
generated files — each holding the hash of the source it was derived from. The
|
|
18
|
+
engine walks that graph and reports every edge whose source has moved.*
|
|
19
|
+
|
|
20
|
+
A fact stated twice is a fact that will disagree with itself — not might, will,
|
|
21
|
+
usually within hours, because the two copies are edited by different people at
|
|
22
|
+
different times for different reasons.
|
|
23
|
+
|
|
24
|
+
The usual response is to be careful. That fails, because carefulness does not
|
|
25
|
+
survive a deadline. What works is to make the second copy *derived*, and then
|
|
26
|
+
make derivation *checkable*.
|
|
27
|
+
|
|
28
|
+
## The idea, in one line
|
|
29
|
+
|
|
30
|
+
> **Store the hash of the source beside the derived thing. Compare on every run.**
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
"6.2B": { "hash": "3e40ff04…", "summary": "The reservations preserve rights as partners only…" }
|
|
34
|
+
^^^^^^^^^^^^^^^^^ the source text when a human last confirmed
|
|
35
|
+
this summary was true of it
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Change the source and its hash changes; the summary no longer matches its
|
|
39
|
+
anchor; the check says `summary-stale: 6.2B`. Nobody had to remember. The
|
|
40
|
+
staleness is not caught by cleverness — it is **structurally unable to hide**.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
One line, in any repo:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
curl -sL https://raw.githubusercontent.com/Alexyodude/NodeEngine/main/install.py | python -
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That copies `stale.py`, `checkall.py` and `viewer.html` into `./tools/` and
|
|
51
|
+
prints what to do next. No clone, no plugin, no dependencies. Add
|
|
52
|
+
`--into scripts` or `--dry-run` after `python -` if you want them.
|
|
53
|
+
|
|
54
|
+
If you have [uv](https://docs.astral.sh/uv/), the same installer runs as a
|
|
55
|
+
packaged tool — same files land, same refusal to overwrite:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
uvx --from git+https://github.com/Alexyodude/NodeEngine nodeengine
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
*It runs code fetched over the network, which is worth being deliberate about.
|
|
62
|
+
To read it first:*
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
curl -sL https://raw.githubusercontent.com/Alexyodude/NodeEngine/main/install.py -o install.py
|
|
66
|
+
less install.py && python install.py
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**As a Claude Code plugin**, if you also want the skill and the guided setup:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
/plugin marketplace add Alexyodude/NodeEngine
|
|
73
|
+
/plugin install node-engine@node-engine
|
|
74
|
+
/node-engine:install
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The plugin adds the method itself — an agent that knows the three shapes, the
|
|
78
|
+
defect taxonomy, and the rule that a new check is guilty until it has failed on
|
|
79
|
+
demand. The one-liner just gives you the files.
|
|
80
|
+
|
|
81
|
+
## What it covers
|
|
82
|
+
|
|
83
|
+
Three shapes, because different relationships need different guarantees:
|
|
84
|
+
|
|
85
|
+
| Shape | For | Guarantee |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| **Anchored** | a human judgement about a source — summaries, descriptions, a sentence citing a spec | re-anchoring is an explicit act; you cannot clear a stale flag by accident |
|
|
88
|
+
| **Content-addressed** | anything that must track an original exactly — translations, mirrors | the hash *is* the key, so a changed source has no entry rather than the wrong one |
|
|
89
|
+
| **Ordered** | files a human generates by running a command | catches the case the others cannot: nobody ran it |
|
|
90
|
+
|
|
91
|
+
Plus the cheapest win in most repos: **a number restated in prose should be
|
|
92
|
+
computed at check time and compared** — version, file count, step count, size.
|
|
93
|
+
No hash needed; the artefact is the source of truth.
|
|
94
|
+
|
|
95
|
+
## Two files carry the human side
|
|
96
|
+
|
|
97
|
+
**`tools/DUPLICATION.md`** is the survey: what this repo states twice, where
|
|
98
|
+
both copies live, which shape guards each, and what is knowingly left
|
|
99
|
+
unguarded. The wiring-up writes it first, because a survey that lives only in
|
|
100
|
+
a conversation is gone when the session is.
|
|
101
|
+
|
|
102
|
+
**`tools/viewer.html`** is the search UI. Open it in a browser — no server, no
|
|
103
|
+
dependencies — drop in the store JSONs your checks keep, and search every id,
|
|
104
|
+
hash and summary. Paste a piece of source text and it computes the same key
|
|
105
|
+
`stale.py` computes, then tells you whether anything still anchors that exact
|
|
106
|
+
text. Read-only on purpose: re-anchoring stays a deliberate act in code,
|
|
107
|
+
because the one action that must remain expensive is clearing a stale flag
|
|
108
|
+
without looking.
|
|
109
|
+
|
|
110
|
+
## It carries the discipline, not just the machinery
|
|
111
|
+
|
|
112
|
+
When a defect is found:
|
|
113
|
+
|
|
114
|
+
1. Fix the instance.
|
|
115
|
+
2. **Name the class.**
|
|
116
|
+
3. **Measure what else has that shape** — grep for the *claim*, not the sentence.
|
|
117
|
+
4. Fix the class.
|
|
118
|
+
5. **Add a check, and make it fail on purpose before believing it.**
|
|
119
|
+
|
|
120
|
+
Step 5 is where this is won or lost. **A new check that passes has told you
|
|
121
|
+
nothing.** It might be correct; it might be structurally incapable of failing,
|
|
122
|
+
and you cannot tell those apart by reading it.
|
|
123
|
+
|
|
124
|
+
## Why that last point is not paranoia
|
|
125
|
+
|
|
126
|
+
`reference/traps.md` documents ten checks that shipped, each reporting a clean
|
|
127
|
+
pass, each unable to fail. In **eight of ten the failure mode was a clean
|
|
128
|
+
result** — not a crash, not a wrong answer, a pass. Examples:
|
|
129
|
+
|
|
130
|
+
- `glob_newer_than("*.pdf", ".pdf", ".pdf")` — compared every file to itself and
|
|
131
|
+
reported *"9 rendered and current"*
|
|
132
|
+
- a regex using `[^.]` to span `2.4 … 11.1`, where every id contains a period —
|
|
133
|
+
returned zero across the whole corpus, three times, by someone who had already
|
|
134
|
+
documented the bug twice
|
|
135
|
+
- `if not X: return {}` upstream of `if X:` downstream — an unparseable input
|
|
136
|
+
silently switched off every check that depended on it, while the run printed `ok`
|
|
137
|
+
- `if not path.exists(): continue` in a checker — a moved file quietly left the
|
|
138
|
+
watch list and the run still said `clean`
|
|
139
|
+
|
|
140
|
+
Remembering these does not prevent them. Breaking the check does.
|
|
141
|
+
|
|
142
|
+
## Contents
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
skills/node-engine/
|
|
146
|
+
SKILL.md the method, the rule, and when not to use it
|
|
147
|
+
reference/
|
|
148
|
+
patterns.md the three shapes, with implementations
|
|
149
|
+
traps.md ten checks that could not fail — all real
|
|
150
|
+
taxonomy.md thirteen defect classes, ranked by how many each produced
|
|
151
|
+
scaffold/
|
|
152
|
+
stale.py the store and comparators (~150 lines, meant to be read)
|
|
153
|
+
checkall.py the runner; `--prove` prints how to break each check
|
|
154
|
+
viewer.html search the stores in a browser; paste text, see what anchors it
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The scaffold is deliberately **not** a library. Copy it in, delete what you do
|
|
158
|
+
not need, change what does not fit. A dependency you cannot read is one you will
|
|
159
|
+
trust when it is wrong — which is the exact failure this plugin exists to prevent.
|
|
160
|
+
|
|
161
|
+
## Origin
|
|
162
|
+
|
|
163
|
+
Extracted from a bilingual legal package: nine documents making claims about a
|
|
164
|
+
tenth, in two languages, with a generated digest in the middle. Thirteen defect
|
|
165
|
+
classes and about forty real defects informed it.
|
|
166
|
+
|
|
167
|
+
The examples throughout stay concrete on purpose. *"A check compared PDFs to
|
|
168
|
+
themselves and reported 9 rendered and current"* transfers. *"Ensure comparison
|
|
169
|
+
operands differ"* does not.
|
|
170
|
+
|
|
171
|
+
## Licence
|
|
172
|
+
|
|
173
|
+
MIT
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# NodeEngine
|
|
2
|
+
|
|
3
|
+
A Claude Code plugin. Makes staleness **fail a check** instead of relying on
|
|
4
|
+
someone remembering.
|
|
5
|
+
|
|
6
|
+
*The name is literal: what it builds is a graph of **nodes** — clauses, blocks,
|
|
7
|
+
generated files — each holding the hash of the source it was derived from. The
|
|
8
|
+
engine walks that graph and reports every edge whose source has moved.*
|
|
9
|
+
|
|
10
|
+
A fact stated twice is a fact that will disagree with itself — not might, will,
|
|
11
|
+
usually within hours, because the two copies are edited by different people at
|
|
12
|
+
different times for different reasons.
|
|
13
|
+
|
|
14
|
+
The usual response is to be careful. That fails, because carefulness does not
|
|
15
|
+
survive a deadline. What works is to make the second copy *derived*, and then
|
|
16
|
+
make derivation *checkable*.
|
|
17
|
+
|
|
18
|
+
## The idea, in one line
|
|
19
|
+
|
|
20
|
+
> **Store the hash of the source beside the derived thing. Compare on every run.**
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
"6.2B": { "hash": "3e40ff04…", "summary": "The reservations preserve rights as partners only…" }
|
|
24
|
+
^^^^^^^^^^^^^^^^^ the source text when a human last confirmed
|
|
25
|
+
this summary was true of it
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Change the source and its hash changes; the summary no longer matches its
|
|
29
|
+
anchor; the check says `summary-stale: 6.2B`. Nobody had to remember. The
|
|
30
|
+
staleness is not caught by cleverness — it is **structurally unable to hide**.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
One line, in any repo:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
curl -sL https://raw.githubusercontent.com/Alexyodude/NodeEngine/main/install.py | python -
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
That copies `stale.py`, `checkall.py` and `viewer.html` into `./tools/` and
|
|
41
|
+
prints what to do next. No clone, no plugin, no dependencies. Add
|
|
42
|
+
`--into scripts` or `--dry-run` after `python -` if you want them.
|
|
43
|
+
|
|
44
|
+
If you have [uv](https://docs.astral.sh/uv/), the same installer runs as a
|
|
45
|
+
packaged tool — same files land, same refusal to overwrite:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
uvx --from git+https://github.com/Alexyodude/NodeEngine nodeengine
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
*It runs code fetched over the network, which is worth being deliberate about.
|
|
52
|
+
To read it first:*
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
curl -sL https://raw.githubusercontent.com/Alexyodude/NodeEngine/main/install.py -o install.py
|
|
56
|
+
less install.py && python install.py
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**As a Claude Code plugin**, if you also want the skill and the guided setup:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
/plugin marketplace add Alexyodude/NodeEngine
|
|
63
|
+
/plugin install node-engine@node-engine
|
|
64
|
+
/node-engine:install
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The plugin adds the method itself — an agent that knows the three shapes, the
|
|
68
|
+
defect taxonomy, and the rule that a new check is guilty until it has failed on
|
|
69
|
+
demand. The one-liner just gives you the files.
|
|
70
|
+
|
|
71
|
+
## What it covers
|
|
72
|
+
|
|
73
|
+
Three shapes, because different relationships need different guarantees:
|
|
74
|
+
|
|
75
|
+
| Shape | For | Guarantee |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| **Anchored** | a human judgement about a source — summaries, descriptions, a sentence citing a spec | re-anchoring is an explicit act; you cannot clear a stale flag by accident |
|
|
78
|
+
| **Content-addressed** | anything that must track an original exactly — translations, mirrors | the hash *is* the key, so a changed source has no entry rather than the wrong one |
|
|
79
|
+
| **Ordered** | files a human generates by running a command | catches the case the others cannot: nobody ran it |
|
|
80
|
+
|
|
81
|
+
Plus the cheapest win in most repos: **a number restated in prose should be
|
|
82
|
+
computed at check time and compared** — version, file count, step count, size.
|
|
83
|
+
No hash needed; the artefact is the source of truth.
|
|
84
|
+
|
|
85
|
+
## Two files carry the human side
|
|
86
|
+
|
|
87
|
+
**`tools/DUPLICATION.md`** is the survey: what this repo states twice, where
|
|
88
|
+
both copies live, which shape guards each, and what is knowingly left
|
|
89
|
+
unguarded. The wiring-up writes it first, because a survey that lives only in
|
|
90
|
+
a conversation is gone when the session is.
|
|
91
|
+
|
|
92
|
+
**`tools/viewer.html`** is the search UI. Open it in a browser — no server, no
|
|
93
|
+
dependencies — drop in the store JSONs your checks keep, and search every id,
|
|
94
|
+
hash and summary. Paste a piece of source text and it computes the same key
|
|
95
|
+
`stale.py` computes, then tells you whether anything still anchors that exact
|
|
96
|
+
text. Read-only on purpose: re-anchoring stays a deliberate act in code,
|
|
97
|
+
because the one action that must remain expensive is clearing a stale flag
|
|
98
|
+
without looking.
|
|
99
|
+
|
|
100
|
+
## It carries the discipline, not just the machinery
|
|
101
|
+
|
|
102
|
+
When a defect is found:
|
|
103
|
+
|
|
104
|
+
1. Fix the instance.
|
|
105
|
+
2. **Name the class.**
|
|
106
|
+
3. **Measure what else has that shape** — grep for the *claim*, not the sentence.
|
|
107
|
+
4. Fix the class.
|
|
108
|
+
5. **Add a check, and make it fail on purpose before believing it.**
|
|
109
|
+
|
|
110
|
+
Step 5 is where this is won or lost. **A new check that passes has told you
|
|
111
|
+
nothing.** It might be correct; it might be structurally incapable of failing,
|
|
112
|
+
and you cannot tell those apart by reading it.
|
|
113
|
+
|
|
114
|
+
## Why that last point is not paranoia
|
|
115
|
+
|
|
116
|
+
`reference/traps.md` documents ten checks that shipped, each reporting a clean
|
|
117
|
+
pass, each unable to fail. In **eight of ten the failure mode was a clean
|
|
118
|
+
result** — not a crash, not a wrong answer, a pass. Examples:
|
|
119
|
+
|
|
120
|
+
- `glob_newer_than("*.pdf", ".pdf", ".pdf")` — compared every file to itself and
|
|
121
|
+
reported *"9 rendered and current"*
|
|
122
|
+
- a regex using `[^.]` to span `2.4 … 11.1`, where every id contains a period —
|
|
123
|
+
returned zero across the whole corpus, three times, by someone who had already
|
|
124
|
+
documented the bug twice
|
|
125
|
+
- `if not X: return {}` upstream of `if X:` downstream — an unparseable input
|
|
126
|
+
silently switched off every check that depended on it, while the run printed `ok`
|
|
127
|
+
- `if not path.exists(): continue` in a checker — a moved file quietly left the
|
|
128
|
+
watch list and the run still said `clean`
|
|
129
|
+
|
|
130
|
+
Remembering these does not prevent them. Breaking the check does.
|
|
131
|
+
|
|
132
|
+
## Contents
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
skills/node-engine/
|
|
136
|
+
SKILL.md the method, the rule, and when not to use it
|
|
137
|
+
reference/
|
|
138
|
+
patterns.md the three shapes, with implementations
|
|
139
|
+
traps.md ten checks that could not fail — all real
|
|
140
|
+
taxonomy.md thirteen defect classes, ranked by how many each produced
|
|
141
|
+
scaffold/
|
|
142
|
+
stale.py the store and comparators (~150 lines, meant to be read)
|
|
143
|
+
checkall.py the runner; `--prove` prints how to break each check
|
|
144
|
+
viewer.html search the stores in a browser; paste text, see what anchors it
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The scaffold is deliberately **not** a library. Copy it in, delete what you do
|
|
148
|
+
not need, change what does not fit. A dependency you cannot read is one you will
|
|
149
|
+
trust when it is wrong — which is the exact failure this plugin exists to prevent.
|
|
150
|
+
|
|
151
|
+
## Origin
|
|
152
|
+
|
|
153
|
+
Extracted from a bilingual legal package: nine documents making claims about a
|
|
154
|
+
tenth, in two languages, with a generated digest in the middle. Thirteen defect
|
|
155
|
+
classes and about forty real defects informed it.
|
|
156
|
+
|
|
157
|
+
The examples throughout stay concrete on purpose. *"A check compared PDFs to
|
|
158
|
+
themselves and reported 9 rendered and current"* transfers. *"Ensure comparison
|
|
159
|
+
operands differ"* does not.
|
|
160
|
+
|
|
161
|
+
## Licence
|
|
162
|
+
|
|
163
|
+
MIT
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Install NodeEngine's staleness guards into the current repository
|
|
3
|
+
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Install the NodeEngine scaffold here, then wire it to what this repository
|
|
7
|
+
actually duplicates. Copying files is the trivial part; step 2 is the work.
|
|
8
|
+
|
|
9
|
+
## Step 1 — Copy the scaffold
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python "${CLAUDE_PLUGIN_ROOT}/install.py"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Add `--into <dir>` if this project does not use `tools/`. It refuses to
|
|
16
|
+
overwrite existing files, so it is safe to re-run.
|
|
17
|
+
|
|
18
|
+
## Step 2 — Find what is stated twice
|
|
19
|
+
|
|
20
|
+
This is the whole job, and it cannot be done from a template. Survey the repo
|
|
21
|
+
and build a real list. Look for:
|
|
22
|
+
|
|
23
|
+
- **Numbers in prose** — versions, counts, sizes, "three steps", "nine files".
|
|
24
|
+
These are the most common and the cheapest to guard: compute them at check
|
|
25
|
+
time and compare.
|
|
26
|
+
- **The same version in several manifests** — `package.json`, a lockfile, a
|
|
27
|
+
`__version__`, a badge in the README.
|
|
28
|
+
- **Docs describing structure** — a README or CLAUDE.md with a directory tree,
|
|
29
|
+
a list of commands, a table of modules. Paths rot silently.
|
|
30
|
+
- **Generated files** a human regenerates by running something.
|
|
31
|
+
- **Anything translated or mirrored** — i18n, a second-language README.
|
|
32
|
+
- **Summaries of code** — docstrings or docs that describe behaviour someone
|
|
33
|
+
can change without touching the description.
|
|
34
|
+
|
|
35
|
+
Write the list to `tools/DUPLICATION.md` — each item, where both copies live,
|
|
36
|
+
and (once decided) which shape guards it or why it is left unguarded. This file
|
|
37
|
+
is the survey's permanent home; a list that lives only in the conversation is
|
|
38
|
+
gone when the session is. Then report it to the user. Ask which matter; do not
|
|
39
|
+
guard everything, and say plainly which ones you think are not worth it.
|
|
40
|
+
|
|
41
|
+
## Step 3 — Pick a shape for each
|
|
42
|
+
|
|
43
|
+
Read `${CLAUDE_PLUGIN_ROOT}/skills/node-engine/reference/patterns.md`.
|
|
44
|
+
|
|
45
|
+
| The derived thing is… | Shape |
|
|
46
|
+
|---|---|
|
|
47
|
+
| a human judgement about a source | **anchored** — hash stored beside it, `--confirm` to re-anchor |
|
|
48
|
+
| a mechanical transform that must match exactly | **content-addressed** — the hash is the key |
|
|
49
|
+
| produced by a command someone runs | **ordered**, or have the generator self-check |
|
|
50
|
+
| a count, size or inventory | **derive it live** — no hash needed, the artefact is the truth |
|
|
51
|
+
|
|
52
|
+
That last row usually covers most of what you found.
|
|
53
|
+
|
|
54
|
+
## Step 4 — Write the table, not the checks
|
|
55
|
+
|
|
56
|
+
Edit `tools/checkall.py` so its `CHECKS` table names the real checks. Each row
|
|
57
|
+
carries a fourth column: **how to make this one fail**. That column is not
|
|
58
|
+
documentation — it is the verification instruction, and if you cannot fill it
|
|
59
|
+
in, you do not yet know whether the check can fail.
|
|
60
|
+
|
|
61
|
+
Adding a watched thing must mean adding a row. If it means writing a function,
|
|
62
|
+
the design has drifted: that is how you get one guard per instance and a gap
|
|
63
|
+
wherever nobody has been bitten yet.
|
|
64
|
+
|
|
65
|
+
## Step 5 — Break every one
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python tools/checkall.py --prove # prints how to break each
|
|
69
|
+
python tools/checkall.py # should be green first
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then actually do it, one at a time: make the change, confirm the check fails,
|
|
73
|
+
revert, confirm it passes. **Report the evidence** — the failing output, not
|
|
74
|
+
"verified".
|
|
75
|
+
|
|
76
|
+
Read `${CLAUDE_PLUGIN_ROOT}/skills/node-engine/reference/traps.md` before this
|
|
77
|
+
step. Ten checks documented there shipped unable to fail, and in eight of ten
|
|
78
|
+
the failure mode was a clean pass. The most common causes:
|
|
79
|
+
|
|
80
|
+
- comparing a thing to itself
|
|
81
|
+
- a pattern that cannot match the shape the text is in
|
|
82
|
+
- a sweep returning zero, which reads as "clean"
|
|
83
|
+
- an empty or missing input treated as "nothing to check" rather than as a finding
|
|
84
|
+
- `if not path.exists(): continue` inside a checker
|
|
85
|
+
|
|
86
|
+
## Step 6 — Record it
|
|
87
|
+
|
|
88
|
+
Add a short section to `CLAUDE.md` (or the README) saying what is guarded, what
|
|
89
|
+
is not, and how to run the checks. State the gaps plainly — a checking system
|
|
90
|
+
that overstates its own coverage is the first thing to mislead someone.
|
|
91
|
+
|
|
92
|
+
Then commit, with the evidence from step 5 in the message.
|