You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
collectionDescriptorLogStore (keys): the log-governed, sealable descriptor
store over ONE encrypted collection's governing history log -- the
collection's own meta/log sub-resource, whose verified head state is its encryption descriptor. It takes the collection handle, a controller
resolver, a chain-head pin store, and the same ResourceLogSigner the
roster's store takes; it derives its own pin slot from the handle, and carries
the collection-descriptor log class.
ResourceLogClass / controllerForLogClass (resourceLog): the log-class
dispatch a log-governed store applies to every controller view it resolves, so
read-side verification and write-side admission run under one rule. The
ceremony-tail license binds the user-key-roster class; a collection-descriptor log admits a ladder-signed append on assertionMethod
membership at the anchored version alone (decisions/0013, app-connect-spec decisions/0003).
COLLECTION_HISTORY_LOG_SUBRESOURCE (space), 'meta/log': where every
encrypted wallet collection's governing history log lives.
collectionStoreFor, required on ensureAccountGenesis
(({ did }) => (collectionId) => store) and on ensureCredentialAnchoredAccountGenesis / establishCredentialAnchoredAccount / mendCredentialAnchoredAccount
(({ did, log }) => (collectionId) => store). Breaking: every caller of those
four supplies it. The mend also takes an optional collectionStore
((collectionId) => store), the per-collection sibling of rosterStore that
its post-promotion roster-and-epochs arm lands epochs through; the arm runs
only when both are supplied.
controller on cascadeCollectionsToUserKey: the ceremony's post-edit
controller view, set as every sealable collection store's minimum controller
version before that collection's first append. Absent, each store's injected
resolver decides its own freshness.
Changed
isResourceLogRefusal (resourceLog) is now @interop/vh-resource-log's
(0.5.0), re-exported from resourceLog/errors.ts in place of the local copy.
The descriptors subpath shrinks to the log-governed descriptor source
(logGovernedDescriptorSource, collectionDescriptorLogPinId). The
acquisition and unknown-epoch refresh policy moved to @interop/was-client/edv (0.54.0) unchanged: acquireDescriptor / acquireDescriptors, wasDescriptorSource, the EncryptionDescriptorSource
/ EncryptionDescriptorCache seams, DescriptorRefreshPolicy, createRefreshingEdvDocCipher, and isKeyUnwrapError. Breaking: import them
from there; this subpath re-exports none of them. The truth table is
unchanged: integrity refusals and every continuity reason but rollback, with
the license class deliberately outside the set.
Followed @interop/was-client's ./sync port contract update: the server's ETag is opaque and can no longer be rebuilt from a bare revision number. SyncedRow gains an etag field persisted alongside version; SyncStore.markPushed / markDeletedPushed take the write's acked etag
(from its WriteAck) and record it; runPush builds every conditional
write's ifMatch from the stored etag string instead of formatting one from version. Pull ingestion and adoptLatest record etag (and metaEtag,
where a collection syncs metadata) from MasterState / WireDoc.
The log-governed descriptor store moved down a layer: @interop/was-client/edv now owns the generic logGovernedDescriptorStore
(verified read, signed replace / create, the conflict translation, seal()), the readGovernedEpochConfiguration helper, the WasEpochConfiguration state type constant, and toEpochConfigurationState.
The roster's logGovernedDescriptorStore (keys/rosterLogStore.ts) is now
that store wrapped with the post-edit minimum controller version, and keeps
its SealableEncryptionDescriptorStore shape; descriptors/logSource.ts
re-exports the two names it exported before. No behavior change. Requires @interop/was-client 0.52.0.
Every edv roster collection is now created bare and declared by its own
governing history log. provisionWalletSpace creates such a collection with encryption: 'governed', so its Description carries no client-written
descriptor, and the epoch[0] install is the guarded create
(If-None-Match: *) that both declares the collection governed and lands its
first epoch. The server derives the Description's encryption member from the
log head, so the wallet writes the log alone, and a Description already
carrying a client-written descriptor cannot be governed. Breaking for a caller
that relied on provisioning to declare the descriptor. An account whose
collections were provisioned with a client-written descriptor is refused by
every provisioning re-run rather than adopted (the declared descriptor is
immutable server-side, so no conversion exists); such an account is
re-provisioned from scratch.
The provision-time epoch install is store-shaped rather than handle-shaped,
the lookup shape the rotation cascade already took. ensureIndexedFirstEpoch
takes store, ensureWalletSpaceEpochs and walletSpaceProvisioner take storeFor: (collectionId) => EncryptionDescriptorStore, and ensureRosterDeliveredEpochs takes the same storeFor. Each store's own
wiring decides the authority its requests ride and, on a governed collection,
the signer its genesis append is proved by. Breaking. spaceId on ensureWalletSpaceEpochs is now optional and names the Space in the
per-collection failure messages alone.
logGovernedDescriptorStore (keys/rosterLogStore.ts) takes a required logClass, stated once at construction, and narrows every controller view it
resolves through controllerForLogClass. A store cannot be built without
saying which class of log it governs. Breaking.
collectionDescriptorLogPinId resolves to space/<spaceId>/<collectionId>/meta/log, over @interop/vh-resource-log's collectionLogPinId, following the log's move out of the key-map collection
and into the subtree of the collection it governs. The read capability a share
grantee or a connected app already holds covers the log.
logGovernedDescriptorSource takes a resolveController returning a WebvhResourceLogController (was ResourceLogController) and reads under the collection-descriptor class, so a reader no longer inherits the roster's
license and refuses a served log its own wallet wrote. Breaking for a caller
passing a bare controller view.
anchorRosterStoreAt returns the controller view it built. Both cascade entry
points (rotateRosterToDocumentAndCascade, retireRosterRecipientAndCascade)
thread that view into the collection fan-out, so each log-governed collection
store takes the same post-edit minimum controller version the roster store
takes. Breaking for a caller typed on the void return.
userKeyRosterLogSigner also signs the per-collection descriptor logs; the
name says which log it was built for first.
cascadeCollectionsToUserKey and ensureWalletSpaceEpochs carry a
verified-log refusal (isResourceLogRefusal) in failed verbatim, the
refusal itself as the entry's error rather than the wrapped per-collection
message, so a caller reading the report tells it by err.name. The fan-out
never throws for it: the ceremonies past their pivot keep their later stages
and their resumable-success contract, and the settled collections still reach walletSpaceProvisioner's onSettled.
ensureWalletSpaceEpochs and walletSpaceProvisioner refuse a missing storeFor with a synchronous TypeError before any write, the way the
geneses and the mend refuse a missing collectionStoreFor. A caller on the
former handle-shaped signature fails loudly instead of landing every
collection in failed on a resolving call.
controllerForLogClass is an exhaustive switch that throws a TypeError on a
class it does not name, so a caller outside the type system never gets the
membership-only rule on the user key roster log.
The mend's completion probe and roster-mint precondition decide epoch presence
from each collection's VERIFIED governing log (through collectionStore)
rather than from the Description's server-derived encryption member. The
Description read stays, as the readability check under the caller's authority.
A host omitting the derived member can no longer license a fresh roster
genesis over collections keyed under the real user key.
Requires @interop/vh-resource-log 0.5.0 (collectionLogPinId, isResourceLogRefusal) and @interop/was-client 0.54.0 (the 'governed'
provisioning value, the meta/log transport seam, and the moved descriptor
policy). was-client 0.54.0 is unpublished today.
Removed
formatEtag, re-exported from push.ts / the sync subpath barrel. A SyncStore implementation now persists the opaque etag string itself rather
than reconstructing a validator from version.
readGovernedEpochConfiguration and EPOCH_CONFIGURATION_STATE_TYPE from the descriptors barrel, and logGovernedDescriptorStore and EPOCH_CONFIGURATION_STATE_TYPE from the keys barrel. Every governed store
states its log class at construction, so the class-stating builders
(userKeyRosterDescriptorStore, collectionDescriptorLogStore, logGovernedDescriptorSource) are the public surface; a bare-controller
reader or a caller-chosen-class wrapper would read or write a collection log
under the roster's license. The functions themselves stay, module-internal.
was and capability on ensureWalletSpaceEpochs, collection on ensureIndexedFirstEpoch, capability on walletSpaceProvisioner, and was
and capability on ensureRosterDeliveredEpochs. Each collection's transport
and invocation authority now ride the store the caller builds. A caller
installing epoch[0] on a collection that is NOT log-governed (an App Connect
per-app collection declared with a client-written edv descriptor) passes @interop/was-client/edv's collectionDescriptorStore({ collection }) as the store.
Tests
test/node/fixtures/descriptorStores.ts: in-memory descriptor stores keyed by
collection id, with create-if-absent and compare-and-swap semantics, the storeFor lookup the epoch install and the collection fan-out now take. Every
write and every anchoring is recorded, so a test asserts the fan-out's
per-collection minimum controller version directly.
The provisioning fixtures follow @interop/was-client 0.52.0: the create no
longer threads current: null into configure, and the genesis fake fails
the Collection Description read only once the collection exists, so the
provisioning's own absent-collection read still reaches the epoch stage.