Metadata-Version: 2.5
Name: nodeengine
Version: 0.1.1
Summary: Install the NodeEngine staleness-guard scaffold into the current repo
Project-URL: Homepage, https://github.com/Alexyodude/NodeEngine
License: MIT
License-File: LICENSE
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# NodeEngine

A Claude Code plugin. Makes staleness **fail a check** instead of relying on
someone remembering.

*The name is literal: what it builds is a graph of **nodes** — clauses, blocks,
generated files — each holding the hash of the source it was derived from. The
engine walks that graph and reports every edge whose source has moved.*

A fact stated twice is a fact that will disagree with itself — not might, will,
usually within hours, because the two copies are edited by different people at
different times for different reasons.

The usual response is to be careful. That fails, because carefulness does not
survive a deadline. What works is to make the second copy *derived*, and then
make derivation *checkable*.

## The idea, in one line

> **Store the hash of the source beside the derived thing. Compare on every run.**

```json
"6.2B": { "hash": "3e40ff04…", "summary": "The reservations preserve rights as partners only…" }
            ^^^^^^^^^^^^^^^^^ the source text when a human last confirmed
                              this summary was true of it
```

Change the source and its hash changes; the summary no longer matches its
anchor; the check says `summary-stale: 6.2B`. Nobody had to remember. The
staleness is not caught by cleverness — it is **structurally unable to hide**.

## Install

One line, in any repo:

```
uvx nodeengine
```

That copies `stale.py`, `checkall.py` and `viewer.html` into `./tools/` and
prints what to do next. Add `--into scripts` or `--dry-run` if you want them.
`pipx run nodeengine` is the same thing. Nothing is installed into your
project: the installer runs in a throwaway environment, and what lands in
`tools/` is three readable files you are meant to edit.

Without [uv](https://docs.astral.sh/uv/) or [pipx](https://pipx.pypa.io/), any
Python will do:

```
curl -fsSL https://raw.githubusercontent.com/Alexyodude/NodeEngine/main/install.py | python
```

*Both run code fetched over the network, which is worth being deliberate about.
To read it first:*

```
curl -fsSL https://raw.githubusercontent.com/Alexyodude/NodeEngine/main/install.py -o install.py
less install.py && python install.py
```

*(`-f` is not decoration: without it, curl pipes an HTTP error page into your
interpreter and you get a syntax error pointing at `<!DOCTYPE html>` instead of
a readable failure.)*

**As a Claude Code plugin**, if you also want the skill and the guided setup:

```
/plugin marketplace add Alexyodude/NodeEngine
/plugin install node-engine@node-engine
/node-engine:install
```

The plugin adds the method itself — an agent that knows the three shapes, the
defect taxonomy, and the rule that a new check is guilty until it has failed on
demand. The one-liner just gives you the files.

## What it covers

Three shapes, because different relationships need different guarantees:

| Shape | For | Guarantee |
|---|---|---|
| **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 |
| **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 |
| **Ordered** | files a human generates by running a command | catches the case the others cannot: nobody ran it |

Plus the cheapest win in most repos: **a number restated in prose should be
computed at check time and compared** — version, file count, step count, size.
No hash needed; the artefact is the source of truth.

## Two files carry the human side

**`tools/DUPLICATION.md`** is the survey: what this repo states twice, where
both copies live, which shape guards each, and what is knowingly left
unguarded. The wiring-up writes it first, because a survey that lives only in
a conversation is gone when the session is.

**`tools/viewer.html`** is the search UI. Open it in a browser — no server, no
dependencies — drop in the store JSONs your checks keep, and search every id,
hash and summary. Paste a piece of source text and it computes the same key
`stale.py` computes, then tells you whether anything still anchors that exact
text. Read-only on purpose: re-anchoring stays a deliberate act in code,
because the one action that must remain expensive is clearing a stale flag
without looking.

## It carries the discipline, not just the machinery

When a defect is found:

1. Fix the instance.
2. **Name the class.**
3. **Measure what else has that shape** — grep for the *claim*, not the sentence.
4. Fix the class.
5. **Add a check, and make it fail on purpose before believing it.**

Step 5 is where this is won or lost. **A new check that passes has told you
nothing.** It might be correct; it might be structurally incapable of failing,
and you cannot tell those apart by reading it.

## Why that last point is not paranoia

`reference/traps.md` documents ten checks that shipped, each reporting a clean
pass, each unable to fail. In **eight of ten the failure mode was a clean
result** — not a crash, not a wrong answer, a pass. Examples:

- `glob_newer_than("*.pdf", ".pdf", ".pdf")` — compared every file to itself and
  reported *"9 rendered and current"*
- a regex using `[^.]` to span `2.4 … 11.1`, where every id contains a period —
  returned zero across the whole corpus, three times, by someone who had already
  documented the bug twice
- `if not X: return {}` upstream of `if X:` downstream — an unparseable input
  silently switched off every check that depended on it, while the run printed `ok`
- `if not path.exists(): continue` in a checker — a moved file quietly left the
  watch list and the run still said `clean`

Remembering these does not prevent them. Breaking the check does.

## Contents

```
skills/node-engine/
  SKILL.md              the method, the rule, and when not to use it
  reference/
    patterns.md         the three shapes, with implementations
    traps.md            ten checks that could not fail — all real
    taxonomy.md         thirteen defect classes, ranked by how many each produced
  scaffold/
    stale.py            the store and comparators (~150 lines, meant to be read)
    checkall.py         the runner; `--prove` prints how to break each check
    viewer.html         search the stores in a browser; paste text, see what anchors it
```

The scaffold is deliberately **not** a library. Copy it in, delete what you do
not need, change what does not fit. A dependency you cannot read is one you will
trust when it is wrong — which is the exact failure this plugin exists to prevent.

## Origin

Extracted from a bilingual legal package: nine documents making claims about a
tenth, in two languages, with a generated digest in the middle. Thirteen defect
classes and about forty real defects informed it.

The examples throughout stay concrete on purpose. *"A check compared PDFs to
themselves and reported 9 rendered and current"* transfers. *"Ensure comparison
operands differ"* does not.

## Licence

MIT
