Files
ng-eventually/.project/concepts/app-contract/knowledge_what-an-app-deletes-at-migration.md
T
Sylvain Duchesne 30f6263db5 docs(concept): le contrat entre le polyfill et l'application qui l'utilise
Amorce le système `concept` dans ce dépôt et ouvre `app-contract` — la frontière
entre cette bibliothèque et les applications qui la consomment.

C'est un contrat **inter-dépôts** et ce dépôt en est le FOURNISSEUR : les applications
vivent ailleurs et tireront `sdk-surface` d'ici. D'où le type `contract_`, ses cinq
sections obligatoires, et l'inscription dans `.project/contracts.yaml` — c'est
l'inscription qui publie.

Trois feuilles :

- **`contract_sdk-surface`** — l'engagement, écrit du point de vue de l'appelant.
  Ce qu'il peut tenir pour acquis : permissif en entrée et précis en sortie ; toute
  référence rendue est NUE, aucun appel ne rend jamais de clé ; lire est la possession,
  écrire est la propriété ; donner à lire est un seul acte et le destinataire n'appelle
  rien ; un dépôt s'adresse à une inbox, jamais à un document ; `ensureIdentity()` est
  toute la connexion ; et `configure` est le seul appel qu'il supprimera.
  Ce qu'il ne doit PAS tenir pour acquis, dit aussi crûment : aucune confidentialité,
  rien de « par lecteur » sur un document public, aucune révocation, aucune écriture
  déléguée, et les références ne voyagent que dans un déploiement.

- **`rule_would-the-caller-unlearn-it`** — le test qui décide de tout : est-ce que
  ceci ferait apprendre à l'appelant quelque chose qu'il devra DÉSAPPRENDRE ? Avec les
  deux tells que la revue de ces jours-ci a rendus concrets : une exception nommée
  cesse d'en être une dès qu'on la publie, et un symbole gardé parce qu'il était là
  n'est pas une décision.

- **`knowledge_what-an-app-deletes-at-migration`** — les deux destins d'un symbole
  publié, le cas intermédiaire d'`ensureIdentity` (substance jetée, site d'appel
  conservé), et le fait que la liste de suppression n'est plus portée par un chemin
  d'import depuis la fusion des entrées : une garantie mécanique remplacée par une
  garantie documentaire, dont seule la moitié est tenue par un test.

Le vocabulaire du concept fixe trois termes que ce projet a déjà payé cher :
`reference` (jamais « lien »), `ReadCap`, `polyfill-era`. `lint` est conformant.

Reste à décider : ce dépôt n'a pas de `CLAUDE.md` racine, donc l'`AGENTS.md` généré
n'est chargé nulle part.
2026-08-10 09:25:01 +02:00

3.2 KiB

type, summary
type summary
knowledge The two fates a published symbol can have, and why the deletion list is now carried by a block and a test rather than by an import path

What an application deletes at migration, and what it keeps

Every published symbol has exactly one of two fates, and knowing which is the whole point of this boundary.

Replaced in place. The build alias resolving @ng-eventually/sdk is removed, the import resolves to the real SDK, and the application's code is unchanged. This is almost everything: ng, useShape, watchShape, init, initNg, readUnion, subscribeDoc(s), docs.*, inbox.*, storeRegistry.*, and the types.

Deleted. The symbol has no counterpart at any level of the target, exists only because one shared wallet hosts every user, and goes with its call site. Today that is configure and its config type.

ensureIdentity sits between the two and is worth stating precisely: its substance is scaffolding — a barrier that hands out a shared wallet file and takes an identifier, a step that exists only because users share a wallet — while its call site survives, because an application still awaits a session before it renders. Its signature was designed for that: it takes no identifier, so the line does not change the day the wallet supplies the identity and the barrier stops appearing.

Why the deletion list is not an import path any more

There were two entry points until 2026-08-07, . and ./polyfill, and the second one carried a signal worth naming: what you import from that path is exactly what you will delete. That was a mechanical guarantee — the compiler produced the list.

Merging them lost it. Nothing at an import line now distinguishes configure, which goes away, from docs, which is replaced. Three things carry it instead, and it is worth knowing that only the last two are enforced:

  • the POLYFILL-ERA block in the package's entry module, which is the deletion list, kept short by construction;
  • docs/api-contract.md, which rules on every symbol with an epistemic label (PASSTHROUGH / LEVEL-1 SHAPE / ASSUMPTION / NO COUNTERPART) and whose export inventory is pinned by a test — so it cannot go stale quietly, which a hand-kept list would;
  • the names themselves, each built from the target's own vocabulary or carrying a marker saying why it exists only here, pinned by the same test.

The trade was deliberate and it is a real reduction in enforcement: a documentary signal where a mechanical one used to be. To verify the pinning is doing its job, look for the vocabulary test beside the package's other tests — it compares the contract's inventory against the entry's real exports, in both directions, and it caught five drifted sections the day it was extended to the rulings.

The direction of travel

The polyfill-era list only shrinks. It has gone from four published calls to one, and each removal was a symbol an application should never have had: naming its own identity, awaiting the connection, wiring a second bootstrap, reaching a machinery accessor. A symbol added to that block is a promise to delete it later — so the question at every addition is whether the application genuinely needs it, or whether the library is passing on a problem of its own.