Repository navigation
Conversation
Bring the server up to @haverstack/core 0.43 (adapter-local 0.42,
commons 0.38, wire-types 0.42, conformance-fixtures 0.37).
One rule per concern rather than per-route exceptions:
- Every aspect of a record has one write endpoint: PATCH .../content,
PUT .../parent, PUT .../unlisted, and POST (edit) / PUT (replace) on
.../associations and .../permissions. The change-set PATCH and the
/delete sub-paths are gone; PATCH /entity is PATCH /entity/content.
- Every write reads and checks If-Match, including the no-bump ones.
- Every endpoint core specifies is parsed by core's parser for it;
knownParams()/readJson keys remain only for server-defined routes.
The server's own booleanParam, isOwnerActingAlone and the POST /types
and migrate hand checks are removed.
- Versions and the journal page by one rule (readHistoryPage): a
500-row server ceiling announced through an exact cursor. The query
limit clamp is gone, since Stack resolves and caps query defaults.
- POST /records/:id/migrate is ScopedStack's to gate, so an installed
app can commit migrations within its own families.
- GET /records/:id hides tombstones unless ?includeDeleted=true.
New: POST /installs (advertised in discovery) and an owner-only review
surface at /installs/requests. Pending requests live in a new sibling
store, <DB_PATH>.installs — additive, no migration of existing data.
Also: LocalAdapter.open({ create }), includeUnlisted read from the
change filter, the full commons set seeded (image, post, site), and
the conformance gate dispatching every 0.37 fixture.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XRRrTNcLcf2TtfuL9wB8Z8
Review findings on the install surface: - GET /installs/requests/:id returns an ETag naming the plan it shows, a hash of its canonical JSON. Approve reads If-Match and answers 412 (precondition_failed) when the plan has changed, so what lands is what was reviewed — the same If-Match rule every other write follows. - Requests are removed by the id that names them, never by key, so a manifest re-sent mid-approval is no longer deleted in its place. - requireActingAlone() refuses a delegated session before its body is read, in the same order as requireAuth() and requireOwner(). - Manifests compare as canonical JSON, so reordered keys keep an id. - ifMatchVersion()/ifMatchTag() live in src/lib/ifMatch.ts, and serializePlan spreads every plan field rather than listing them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XRRrTNcLcf2TtfuL9wB8Z8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the server up to the latest published core releases:
@haverstack/core0.43,adapter-local0.42,commons0.38,wire-types0.42 andconformance-fixtures0.37. Where the old code had a per-route exception, this applies one shared rule:PATCH /records/:id/content,PUT .../parent,PUT .../unlisted, plusPOST(edit list) andPUT(replace) on.../associationsand.../permissions. The change-setPATCH /records/:idand the/deletesub-paths are removed.PATCH /entityis nowPATCH /entity/content.If-Match, including writes that don't bump the version.booleanParam,isOwnerActingAlone, and the hand-written checks onPOST /typesand migrate.knownParams()and thereadJsonkey list remain only for routes the server defines itself.{ versions, cursor }envelope) and the journal sharereadHistoryPage: a 500-row page cap, with a cursor that is null exactly when nothing follows. The querylimitclamp is removed, becauseStacknow sets and caps query defaults itself.ScopedStack, so an installed app can commit migrations within its own type families.GET /records/:idhides tombstones unless called with?includeDeleted=true.POST /installs(advertised in discovery), plus an owner-only review surface at/installs/requestsfor listing, reviewing the current plan, approving and declining.LocalAdapter.open({ create }),includeUnlistedread from the change filter, all ten commons types seeded (adds image, post and site), andgrantTypecalls take a type family.Stored data: pending install requests live in a new sibling file,
<DB_PATH>.installs. It is additive, and nothing existing needs migrating.Docs
docs/api.md: Discovery, Records (per-aspect writes, history/restore/migrate, optimistic concurrency), query defaults, tombstones, Unlisted, change-feedkinds, Types, the new Installs section, Entity, Permissions and the grant surface (baseId).docs/deployment.md: the.noncesand.installssibling stores, and how install requests are bounded..env.example: the full commons type list.The wire contract itself is core's. This PR implements core 0.43 and does not change the contract.
Verification
pnpm run format:check && pnpm run lint && pnpm typecheck && pnpm testall pass, with 652 tests across 32 files.pnpm run buildalso succeeds.The conformance gate dispatches every 0.37 fixture. The only skips are the same two as before, each of which pins a client obligation rather than a server one.
New tests:
tests/routes/installs.test.tsandtests/lib/installRequestStore.test.ts: the install surfaces and the request store.tests/lib/historyPage.test.ts: the paging rule.Notes for reviewers
If-Matchon a write that doesn't bump the version now answering412.delete-record-softfixture's body keeps content that the spec's tombstone projection empties. The test pins the spec. Filed as delete-record-soft fixture shows content the tombstone projection empties core#475.mainhas three unreleased changesets (theownerEntityIdrename, portable copy, reshare-needs-read). A smaller follow-up will adopt them once they're published.Generated by Claude Code