@@ -7,6 +7,93 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
77
88## [Unreleased]
99
10+ ### BREAKING — the default provider composition registered vocabulary no other port has
11+
12+ `forgeTypesProvider` leaves `defaultLoadMemoryProviders` and `meta types`. Metadata carrying
13+ `@forgeConfidence` — or a `decision` / `principle` / `convention` / `glossary` / `failure`
14+ node — now fails to load unless the project opts the provider in.
15+
16+ That vocabulary was registered in **TypeScript and nowhere else**: no C#, Python, Java or
17+ Kotlin registry declares a line of it, and `expected-registry.json` — the manifest all five
18+ ports byte-match — carries none of it, so the cross-port gate never had jurisdiction over
19+ any of it. One document therefore had **two verdicts depending on which toolchain read it**,
20+ which is precisely the defect the `0.25.0` breaking slot was spent on, and 1.0 would have
21+ frozen it into a permanent public surface. Found by an adopter estate running the RC, in a
22+ project carrying nine such nodes. **`metamodelVersion` does not move** — none of this was
23+ ever in the manifest, so the covered contract is unchanged; what changed is which door
24+ agrees with it.
25+
26+ The provider is still exported and unchanged: `loadMemory(root, { providers:
27+ [forgeTypesProvider] })` is the chartered ADR-0023 opt-in, and a project taking it knows it
28+ has a surface the other four ports do not. `meta upgrade --apply` strips the attributes.
29+ Migration: [`0.x-to-1.0.md` §12](docs/features/migrations/0.x-to-1.0.md).
30+
31+ **The gate closes the door, not the instance.** `metadata`'s registry-conformance test pins
32+ the canonical against `coreProviders` — but the door adopters actually use composed
33+ something else, so the gate was asserting about a provider list that was not the one in
34+ force. A new sdk test asks the DEFAULT composition the same question, and is proved
35+ non-vacuous with the provider that escaped it. The repo's own fixture was part of how this
36+ stayed invisible: `trainer-website-meta` carried a `decision.global` node and eight
37+ `@forge*` attrs, so the CLI suite exercised TS-only vocabulary on the default path.
38+
39+ Also removed from `@metaobjectsdev/sdk`: the forge memory record schemas (`RecordCore`,
40+ `DecisionRecord`, …) and their file storage layer (`readRecord` / `writeRecord` /
41+ `listRecords` / `promoteRecord` / `supersede` / …). Nothing in the library imported either,
42+ and a sweep of all seven adopter estates found no use of any of the fifteen names.
43+
44+ ### Fixed — a hand-edited `<Entity>Names` read as "in sync with the metadata"
45+
46+ Hand-edit a generated `Subscriber.names.ts` so a column reads `first_name_BROKEN` and
47+ `meta verify --codegen` exited **0**, saying *"generated output is in sync with the
48+ metadata"* — over a file contradicting the model, in the one artifact whose entire purpose
49+ is that a physical name is spelled once per run and referenced everywhere else. Found by an
50+ adopter estate doing what its brief said: breaking the gate to see whether it convicts.
51+
52+ **RULED: a names artifact must match a fresh regen exactly.** If you want a constant of your
53+ own, put it in a file of your own. The `0.24.3` hand-edit exemption is otherwise untouched
54+ and remains right — it exists because `meta gen` MERGES an edit and reports `merged`, so
55+ convicting it printed a remedy that could not work. A names artifact is not that shape:
56+ every value is a string, so no compiler sees a wrong one, nothing reads it in a test, and an
57+ edit inside it silently renames a column for every consumer.
58+
59+ Two smaller claims in the same area were false and are corrected: the success line now says
60+ what it CHECKED (*"every file's generated contribution is current"*) rather than the stronger
61+ property it had not verified, and `--codegen`'s `--help` no longer describes the pre-`0.24.3`
62+ gate it replaced. `.names.ts` is now one exported constant the emitter, the ejectable
63+ reference template and the gate all spell from — three literals would have been three
64+ chances for the gate to stop finding the artifact it protects, silently. An adopter who owns
65+ the generator and renames the artifact opts out; that is stated in the reference template
66+ rather than hidden.
67+
68+ ### Fixed — the one `@expr` spelling a human writes was the one that drifted
69+
70+ `pg_get_expr` re-emits every operator SPACED and appends casts, so an index authored as
71+ `(request_context->>'device_id')` reads back as `((request_context ->> 'device_id'::text))`.
72+ The comparator already canonicalized the casts and the redundant parens — measured across
73+ five spellings against a live engine, three reconciling and two not — so the ONE surviving
74+ difference was the whitespace around the operator, and it was the one difference a person
75+ actually produces. `verify --db` reported drift and `migrate` proposed **DROP + CREATE
76+ against an index the database already held**, declared exactly as it stood. Found by an
77+ adopter estate running the RC: its own README said to retire a hand-written index adjunct
78+ "the moment #342 ships", and following that instruction proposed a DROP against a live
79+ production index.
80+
81+ Whitespace around a symbolic operator run now collapses, outside single-quoted literals, in
82+ the pass that already did that for commas. Safe on the stronger ground the comparator now
83+ needs: it is not semantic in ANY valid SQL — where two spellings differ only there, at most
84+ one parses, because Postgres lexes a maximal run of operator characters as a single token.
85+ Only SYMBOLIC operators, so `AND` / `OR` / `IN` / `IS NULL` keep their separators. Derived
86+ from Postgres' operator CHARACTER SET rather than a list of operators, so `->>`, `!~*`,
87+ `@>`, `?|` and anything user-defined normalize by one rule.
88+
89+ The file's header claimed the canonicalizer was safe because "every check expression we emit
90+ is machine-derived … there is no arbitrary author SQL to mis-normalize" — which stopped
91+ being true when `index.lookup`'s `@expr` and `@where` began using it. It now justifies each
92+ rewrite on the ground it actually needs. Gated against a real engine, per this package's
93+ doctrine: the test asserts that PG really does re-emit the expression spaced and cast (so a
94+ future PG rendering it differently fails there rather than making the suite vacuous), diffs
95+ all five spellings to empty, and proves the gate can still convict a genuinely different key.
96+
1097### Fixed — `verify --docs` skipped a page and said nothing about it
1198
1299`--docs` tests BOTH halves against `.gitignore` — the pages a fresh `meta docs` emits, and the
0 commit comments