Repository navigation
GO-7383 Import real space exports: full converter, unresolved references, uninstalled types - #11
Merged
Merged
Conversation
Extract the CLI's authoring converter into a shared bundle/convert package with two entry points: Authoring keeps the strict authored subset, Bundle converts a complete exported space — installed definitions, stored property and option keys, templates, participants, views, widgets, space settings, remote file metadata and encryption keys — into native v1 archive entries and attachment path mappings for streaming. The CLI gains to-v1 -full for bundle directories, with directory or ZIP output that refuses to overwrite an existing destination.
A dangling index target has three causes and the store already tells them apart: a tombstone (the user deleted the object; a reference to it is ordinary state), a row this export did not write (archived, or outside a partial export), and no row at all (not yet synced, or never here — the one real loss). index.json now declares the first two as the subsets unresolved.deleted and unresolved.omitted of unresolved.targets, classified by the composer through the existence and deletion resolvers with one exported predicate, ClassifyUnresolvedTarget. bundle.Inspect returns the whole verdict as a graded Report; Validate keeps its wording and refuses only on errors. On the full surface a declared target is admitted — deleted as info, omitted or absent as a warning — while an undeclared one stays an error, and the authoring surface refuses every dangling target. The converter forwards the graded lines and returns the three classes on Result.Unresolved; the CLI prints them after ok bundle and gains -strict. Export no longer manufactures _missing_object for an absent id: the id is kept verbatim and warned, because the sentinel is the importer's answer and a backup taken during a sync gap must carry what a later sync could still make whole. A deleted space icon follows the document-level icon rule. The icon gains a cid variant for images with no file object behind them — a participant avatar, a 1-to-1 space icon — chosen by CID codec (dag-pb or raw against dag-cbor), never folded, declared or resolved, refused by the authoring subset, with the old overloaded file spelling read for compatibility. Spec: docs/superpowers/specs/2026-09-11-unresolved-references-design.md. On the 79-space corpus sweep, 70 spaces now import against 17 before; the 9 remaining failures are missing type documents.
Nine real space exports still failed to import after the unresolved- reference work. Read against the source stores, 64 of the 72 type identities their objects named were types the user had REMOVED from the space, three were a legacy `ot-type`, and five were types an old import created and never made. None was a deletion. A removed type now travels. Removing a type sets `isUninstalled`, the app mirrors that into `isDeleted`, and the exporter enumerated through a query that refuses deleted rows, so the definition vanished while its objects kept the key. It is exported as an ordinary type document carrying `uninstalled: true` on the envelope, the mirror of the member a removed property already has, and import writes the flag back so it restores hidden and reinstallable. In the vocabulary such a type owns its stored key, so `type-<key>` references resolve, and claims no display name, so a live type that took the freed name is not shadowed. A type document's own type is written as `objectType`, derivable from the kind, with a warning when the store disagrees. A type the source space never held is declared in `index.json` under `unresolved.types`. The full surface admits a declared one as a warning and refuses an undeclared one; the authoring surface refuses both, and so does a declaration naming a type the bundle actually carries. The converter imports such an object as a Page, and a template as one for Page, because kept verbatim it is unsearchable by type and renders with a guessed layout. A slot that merely references the type drops the entry instead, the way a list already expresses an absent reference by being shorter. Property identity repairs found on real data: a stated `internal_key` breaks a contested declaration spelling; a dictionary entry's own `property` spelling outranks a display name another entry carries; a bundled spelling a live custom property also answers to owes a legend entry. A stored `_missing_object` drops from a dictionary entry's target types, and an option key containing a slash gets an escaped archive id, escaping the escape character first so two keys cannot collapse onto one entry. The comparator learns the two type-document normalizations so neither reads as loss. Measured: all nine spaces validate and import, against 17 of 79 at the start. Design note in docs/superpowers/specs.
format/v2/README.md already lists SKILL.md, but the file itself was never tracked, so the link was broken in the published tree. The skill points an authoring agent at the three authoring schemas and the habit_tracker example rather than the full spec, tells it to model the user's domain instead of defaulting every object to Page, and requires it to run the validator on the generated bundle before delivery rather than recommending the command or validating the example instead.
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Makes real whole-space exports import. Measured on a retained 79-space
account: 79 of 79 active spaces now import, against 17 before this work.
What is here
A shared bundle converter.
bundle/convertturns a complete exportedbundle into a native v1 archive: installed definitions, stored property and
option keys, templates, participants, views, widgets, space settings, remote
file metadata and encryption keys.
Authoringkeeps the strict authoredsubset. The CLI gains
to-v1 -full.A policy for references a bundle cannot resolve. A dangling reference has
three causes and the store already tells them apart: a tombstone (the user
deleted the object, and Anytype deliberately does not rewrite everything that
mentions it), a row the export did not write, and no row at all.
index.jsondeclares the first two as subsets of
unresolved.targets; the fullvalidation surface admits a declared target at the severity its class earns
and still refuses an undeclared one; the authoring surface refuses all of
them.
bundle.Inspectreturns the graded report, andValidatekeeps itssignature and its wording.
Export also stops manufacturing
_missing_objectfor an id the space had norow for. It keeps the id and warns, because the importer already writes the
sentinel for anything it cannot resolve, so a backup taken during a sync gap
now carries what a later sync could still make whole.
Uninstalled types travel. Removing a type sets
isUninstalled, which theapp mirrors into
isDeleted, and the exporter enumerated through a querythat refuses deleted rows, so the definition vanished while its objects kept
the key. 64 of the 72 unresolved type identities in the sweep were exactly
that. Such a type is now exported as a type document carrying
uninstalled: trueand restores hidden; in the vocabulary it owns its storedkey and claims no display name.
A type the space never held imports as a Page. Five objects an old import
created with a type it never made. They are declared under
unresolved.types; identity slots become Page, and a slot that merelyreferences the type drops the entry.
Smaller repairs found on real data: a type document's own type is
normalized to
objectType; a statedinternal_keybreaks a contesteddeclaration spelling; a dictionary entry's own spelling outranks a display
name another entry carries; a bundled spelling a live custom property also
answers to owes a legend entry; a stored
_missing_objectdrops from adictionary entry's target types; an option key containing a slash gets an
escaped archive id. The icon gains a
cidvariant for images with no fileobject behind them, which is how a participant avatar and a 1-to-1 space
icon are stored.
Review
A five-lens review over the finished change set found four severe defects,
all fixed here with a test each: a declared missing type that validated and
then refused to convert, an over-declaring index that silently retyped live
objects, a composer that never censused the property dictionary and so could
ship a bundle its own validator rejects, and an option archive id that was
not injective and made output nondeterministic. The corpus exercises none of
those paths, so the sweep was green with all four present.
Known and deliberate
importer installs bundled definitions before the guard runs. Zero of the 68
removed type keys in the corpus are bundled. The agreed resolution, scoping
the guard by the importer's new-space flag, is written up in the design note
and deliberately not implemented here.
format/v2/SKILL.mdcarries absolute local paths and needs them maderepository-relative.
Design notes:
docs/superpowers/specs/2026-09-11-unresolved-references-design.mdand
docs/superpowers/specs/2026-09-11-uninstalled-types-design.md.