mirror of
https://github.com/THU-MAIC/OpenMAIC.git
synced 2026-10-17 05:29:46 +08:00
* refactor(dsl): restate the asset seam as allocated, non-disclosing refs The asset seam's docstrings described a ref as a handle whose scheme was the backend's business, and recommended content-addressed hashing so identical bytes de-duplicate. Both are now wrong in the same place: a content-addressed ref *is* a statement about the bytes, so returning one from `put` tells the caller whether those bytes were already stored — an existence oracle over data the caller never wrote. State the contract the global asset pool needs instead: `put` allocates, every call returns a new ref, and nothing the caller receives reveals whether the bytes pre-existed. A provider may still de-duplicate internally; that is a property of its storage layer, not of the ref. Also spell out that the ref domain is unconstrained, so an unrecognized ref is a miss rather than an error. Comments only — no interface signature changes. * feat(storage): add the asset registry — allocated ids over the blob layer Part 1 of the global asset pool (#1007): the browser registry core. `BrowserAssetStore` is now the package's asset backend. It maps an allocated `AssetId` to a registry entry (`contentHash`, `mime`, `meta`), and the registry maps that hash to bytes, giving three properties at once: - an id survives the bytes behind it being regenerated or replaced, and one set of bytes can back several ids with different metadata; - identical bytes occupy one row however many ids name them; - the content hash never leaves the package, so "whoever knows the hash can reach the bytes" — the threat pure content-addressing has to defend against — structurally does not arise, and the blob layer beneath can stay global and metadata-free without being an isolation hole. `put` always allocates a new id and always writes the blob unconditionally, so the first-store and de-duplication-hit paths run the same statements, issue the same requests, and return the same shape. The caller cannot infer that someone else's bytes are already present. Both stores live in one IndexedDB database, so reference counting on `remove` happens inside the transaction that deletes the entry, over an index on `contentHash`. IndexedDB serializes readwrite transactions over the same stores, so a last-reference removal can never reclaim bytes a concurrent `put` has just adopted. Images, audio and video share one id space; the medium is a `mime` column, not a partition. There is no `principal` column: a principal is derived server-side from an authenticated session, and a value the client supplies about itself authorizes nothing — the column arrives with the server backend. The id domain is opaque and unvalidated, taking the KV key domain's conclusion as its starting point. `toAssetId` brands without checking; an id this store never issued is a miss, never an error. `BrowserAssetProvider` is demoted to an internal blob backend and dropped from the public exports (0.x, and it had no consumers): its content-addressed ref is precisely the de-duplication signal an outward API must not emit. Tests split along the same seam. `runAssetStoreContract` pins the outward semantics — allocation, an existence-disclosure matrix compared facet by facet rather than asserted in prose, reference-counted release, and a table of foreign ids that must all miss without throwing — while `runBlobStoreContract` keeps the content-addressed semantics for the layer underneath. Facts the outward API must not disclose (one blob row per byte string, reclamation at the last reference, the put/remove race) are asserted against the rows. * chore(packages): bump @openmaic/dsl to 0.5.1 and @openmaic/storage to 0.2.0 `storage` takes a minor bump rather than a patch: `BrowserAssetProvider` is no longer exported from the package entry point, which is breaking under 0.x convention even though nothing consumed it. * fix(storage): address asset registry review findings * fix(storage): complete asset registry lifecycle * fix(storage): harden asset cache coherence and lifecycle * fix(storage): close pending asset mint edges * refactor(storage): adopt immutable asset URL snapshots * fix(storage): close asset snapshot lifecycle gaps * test(storage): pin asset lifecycle contracts * docs(storage): document 0.1.x asset upgrade * fix(storage): reject incompatible asset database schemas * fix(storage): enforce asset allocation independence * fix(storage): instrument production asset allocation * test(storage): cover allocation ordinals across histories * refactor(storage): remove standalone blob backend seam