Server side of haverstack/core#68, and the server's clearest instance of the review's layering principle (adapters are storage engines; Stack is the invariant layer).
Problem
POST /types writes directly to the adapter (src/routes/types.ts:53):
await adapter.saveType(type);
saveType is INSERT OR REPLACE — so the wire inherits exactly the silent-replace hole core #68 describes: re-POST com.example/note@1 with a different shape and every existing record of that type is silently mislabeled. The route validates the submitted hash matches the submitted schema (types.ts:38-40, from #15), which proves internal consistency of the request but compares against nothing stored — the one comparison schemaHash exists for.
The route also constructs the StackType by hand (id/baseId/version/name/createdAt), duplicating in the HTTP layer what defineType() owns, and accepts a client-supplied createdAt — which core #68's flow makes moot (no-op and additive paths preserve the stored createdAt).
Decided direction (upstream)
Core #68 item 5 says it directly: "Server-side POST /types runs the same check… saveType() stays a dumb REPLACE — legality is decided in the invariant layer."
Work items
Refs haverstack/core#68, haverstack/core#47 (additive policy), haverstack/core#53, #32, #33.
Server side of haverstack/core#68, and the server's clearest instance of the review's layering principle (adapters are storage engines;
Stackis the invariant layer).Problem
POST /typeswrites directly to the adapter (src/routes/types.ts:53):saveTypeisINSERT OR REPLACE— so the wire inherits exactly the silent-replace hole core #68 describes: re-POSTcom.example/note@1with a different shape and every existing record of that type is silently mislabeled. The route validates the submitted hash matches the submitted schema (types.ts:38-40, from #15), which proves internal consistency of the request but compares against nothing stored — the one comparisonschemaHashexists for.The route also constructs the
StackTypeby hand (id/baseId/version/name/createdAt), duplicating in the HTTP layer whatdefineType()owns, and accepts a client-suppliedcreatedAt— which core #68's flow makes moot (no-op and additive paths preserve the storedcreatedAt).Decided direction (upstream)
Core #68 item 5 says it directly: "Server-side
POST /typesruns the same check…saveType()stays a dumb REPLACE — legality is decided in the invariant layer."createdAtpreservedschema_driftcode (Core sync: wire error contract — typedcodevocabulary, structured bodies, 400/422 discipline (core #53) #33)Work items
Stack.defineType()once the drift-guard flow lands (blocked on core #68); delete the hand-rolledStackTypeconstructiondefineTypederivingbaseId/versionfrom the id, the client-suppliedschemaHash/baseId/version/createdAtfields become either redundant or 400-checked consistency inputs — decide with the spec updaterequireOwner(type registration is owner surface today; grants don't cover it)createdAtchurn), additive → accepted, illegal → 409schema_driftRefs haverstack/core#68, haverstack/core#47 (additive policy), haverstack/core#53, #32, #33.