feat: une cible annoncee mais pas encore ecrite a desormais sa categorie

This commit is contained in:
Sylvain Duchesne
2026-09-16 15:33:14 +02:00
parent 1a4857cb75
commit dd874bb9c4
7 changed files with 249 additions and 32 deletions
@@ -35,18 +35,23 @@ When a divergence is genuinely unavoidable it must be **deliberate, documented a
## Every symbol says where it comes from
Answering *does the target do this?* once, in conversation, does not survive the week. So each symbol carries its own provenance, beside the code rather than in a document that drifts: the **level** that answers (1 the engine, 2 the binding, 3 the ORM), the upstream `path:symbol` it aligns on, and one of five kinds.
Answering *does the target do this?* once, in conversation, does not survive the week. So each symbol carries its own provenance, beside the code rather than in a document that drifts: the **level** that answers (1 the engine, 2 the binding, 3 the ORM), the `path:symbol` it cites — a symbol in `nextgraph-rs`, or, for the one kind that has nothing upstream to cite, the record in this working copy — and one kind from a closed set.
| kind | meaning |
|---|---|
| `passthrough` | upstream's own symbol, same name and shape |
| `aligned` | our name or ergonomics, upstream's semantics and model |
| `declared-not-wired` | upstream **defines** the shape; nothing constructs it yet; we implement it |
| `announced-not-written` | upstream's developers have **stated** this is the direction; nothing in the tree carries it — not a definition, not even a name |
| `reserved-name` | upstream has declared a NAME with no shape behind it — it binds nothing, so building on it is a bet |
| `invention` | nothing at any level answers — a deliberate, documented bet |
| `divergent` | upstream does this, and we do it differently |
A test requires the annotation on every published symbol; it cannot check that the citation is *true*, and that is fine — a citation is refutable by a reader in seconds, prose is not. The classification also applies to unpublished code that **claims to resemble the target**: the mistake this section exists for was made on an internal function, and being unexported protected nobody.
A test requires the annotation on every published symbol; it cannot check that the citation is *true*, and that is fine — a citation is refutable by a reader in seconds, prose is not. It does check that the citation still **resolves**, which a reader cannot: into `nextgraph-rs` when that sibling checkout is present — absent, it asks nothing rather than going red for a reason that would only teach people to skip the suite — and into this working copy always, for the one kind whose record lives here. The classification also applies to unpublished code that **claims to resemble the target**: the mistake this section exists for was made on an internal function, and being unexported protected nobody.
**An announced target has no file to cite, and that is not a reason to call it ours.** `announced-not-written` covers the case the other kinds leave out: the developers have said what the direction is, and the tree carries nothing yet — no definition, not even a name. It is the **strongest** justification available there, because deviating *toward* what the target has announced is alignment, and it is the rest of the surface that will have to catch up. The two moves it replaces are both bad: citing an approximate symbol, which is the `readUnion` failure — a true citation attached to a false claim — or declaring `invention`, which understates the alignment and tells a later reader the shape is ours to change when it is not.
Being the strongest, it is the **hardest to assert**. It names **who** stated it and **when** (`announced-by=<who>@<YYYY-MM-DD>`), and its `ref` is not a symbol upstream — there is none — but the **document in this working copy where the statement is on record**, plus the announced name it is on record for. That record is prose and may never be one of our own source files: our code standing as the evidence for its own shape is a circle, and the circle would wear the strongest label in the set. An announcement nobody wrote down is hearsay, and hearsay is exactly how *"every document has a native inbox"* became an implementation before anyone checked it. The date is there to be weighed: a direction announced long ago and still unwritten is worth less than one stated last week, and without a date nobody can tell the two apart.
**A reserved name is not a declared shape, and the gap between them is the whole point.** `declared-not-wired` is strong *because the shape constrains us*: implementing it is realising something the target wrote down. A name with nothing behind it constrains nothing, so what we build under it is our own invention wearing the target's vocabulary — the most dangerous kind, because the borrowed name makes it read as alignment.
@@ -22,13 +22,19 @@ This is the surface-level sibling of [[no-divergence-from-nextgraph]], which ask
**The legitimate deviation, so nobody concludes every difference is a fault.** `watchShape` returns a `ShapeQuery` shaped like TanStack Query's `useQuery` — `{ data, isPending, isSuccess, isError, error }` — where the SDK's `useShape` returns a bare `DeepSignalSet`. That is a real difference from what the SDK ships today, and it is **justified**: NextGraph's direction, as reported by its developers, is a `useShapeQuery` returning exactly that shape. Deviating *toward* the announced target is alignment, not divergence — it is the rest of the surface that will have to catch up.
**The gap that same example exposes — a known weakness of the annotation format.** A target **stated by its developers but not yet written** has no `file:symbol` to cite: `useShapeQuery` has zero occurrences in the tree. The taxonomy in [[no-divergence-from-nextgraph]] has no kind for it either — `declared-not-wired` needs a declaration, `reserved-name` needs a name present in the tree. So an author holding the strongest possible justification has only two bad moves left: cite an approximate symbol, which is precisely the `readUnion` failure, or declare `invention`, which understates the alignment and tells a later reader the shape is ours to change. Recorded here as a weakness to fix, deliberately not fixed here.
**The gap that same example exposed — closed by `announced-not-written`.** A target **stated by its developers but not yet written** has no `file:symbol` to cite: `useShapeQuery` has zero occurrences in the tree. The taxonomy in [[no-divergence-from-nextgraph]] had no kind for it either — `declared-not-wired` needs a declaration, `reserved-name` needs a name present in the tree — so an author holding the strongest possible justification had only two bad moves left: cite an approximate symbol, which is precisely the `readUnion` failure, or declare `invention`, which understates the alignment and tells a later reader the shape is ours to change. The kind `announced-not-written` is the third move: in place of a symbol upstream it cites the **record of the statement**, and it names who made it and when.
```
// @provenance useShapeQuery kind=announced-not-written level=3 ref=.project/rules/nextgraph/surface-mirrors-the-sdk.md:useShapeQuery announced-by=nextgraph-developers@2026-09-16 — the SDK ships `useShape` returning a bare `DeepSignalSet`; the announced direction is a `useShapeQuery` returning a TanStack-shaped snapshot
```
**This section is that record**, and the annotation above points back at it. The statement it holds: NextGraph's direction is a `useShapeQuery` returning `{ data, isPending, isSuccess, isError, error }`, reported from its developers and written down here on 2026-09-16 — the date the annotation carries, so a later reader can weigh how long the direction has been announced and still unwritten. An announcement nobody wrote down is hearsay: `packages/polyfill/test/provenance.test.ts` refuses an annotation of this kind whose record is missing, is a source file rather than prose, or no longer names the symbol.
**How to apply.**
- **Before naming a published symbol**, find the target's own name and use it. If the target has not named it, check the verb is *free* at the target: one it already spends elsewhere is taken, and borrowing it says something false.
- **Prefer passing the target's type through to translating it.** When a parameter cannot be passed through, stop and ask what will have to be built beneath it — that is the real decision, and it is being made by the parameter.
- **Return what the SDK returns**, unless the difference is the target's announced direction — then say whose statement it is.
- **Return what the SDK returns**, unless the difference is the target's announced direction — then say whose statement it is, in the annotation's `announced-by` field and against a record the reader can open. "Whose statement" is a field the test checks, not a remark.
- **"Duly justified" has a fixed cost**: one annotation line, beside the code, naming what the target does, what was chosen instead, and why. The test is refutability — a reader must be able to check it by opening one file.
- **Check every citation against the CLAIM, not just against the tree.** Same granularity on both sides: a function may cite a function; a composition, a pipeline or a policy cites nothing at level 2 and must say so. "The reference resolves" is not "the annotation is true".
- **Applies to what is published.** An internal helper that claims to resemble the target falls under [[no-divergence-from-nextgraph]]; this rule is about the symbols an application types.