Skip to main content

Pack-Upgrade Mechanism (v0.41.22)

How gbrain-base@1.x → gbrain-base-v2@1.0.0 (and any future pack succession) wires through the onboard cathedral.

The contract

A schema pack manifest can declare a migration_from field:
When this declaration is present + a mapping_rules: block is populated, the pack registers itself as the successor to (parent_pack, version_range). Any brain whose active pack matches that tuple lights up the pack_upgrade_available onboard check.

End-to-end flow

Version-range semantics

migration_from.version accepts three shapes: * is accepted as an alias for x. Implementation: _versionRangeMatches(version, range) in src/core/schema-pack/load-active.ts. Pinned by test/schema-pack-find-pack-successors.test.ts.

findPackSuccessors discovery

Walks BUNDLED_PACK_NAMES (currently gbrain-base, modusbrain-recommended, modusbrain-creator, modusbrain-investor, modusbrain-engineer, modusbrain-everything, gbrain-base-v2). For each candidate ≠ the active pack name, loads the manifest via loadActivePack({ perCall: candidate }), checks migration_from.pack === activeName && _versionRangeMatches(activeVer, migration_from.version). Returns matching packs sorted by version descending. v0.41.22 covers bundled packs only. v0.43+ TODO: enumerate user-installed packs at ~/.modusbrain/schema-packs/*/pack.yaml (defer to v0.43 since the filesystem-scan cost needs the cache invalidation strategy from registry.ts).

The manual_only apply policy

The shipped onboard contract has 3 apply_policy values: pack_upgrade_available emits a RemediationStep with protected: true + job: 'unify-types'. toOnboardRecommendation in src/core/onboard/render.ts maps this to manual_only via the MANUAL_ONLY_PROTECTED_JOBS allowlist (which also contains extract-takes-from-pages per v0.41.18 A12+A24). Rationale: pack upgrades change the brain’s taxonomy. Taxonomy is a user judgment call — not autopilot’s call. Even with --auto-with- prompt, prompting the user to confirm a pack upgrade mid-tick is the wrong UX (the user came to fix orphans, not to be interrupted with “hey want to migrate your taxonomy?”). Explicit submission is the right boundary.

Authoring a successor pack

Minimal example for an academic-research brain that adds a researcher canonical:
Drop at ~/.modusbrain/schema-packs/modusbrain-academic-v1/pack.yaml. Discoverable via modusbrain schema list. Activatable via modusbrain schema use modusbrain-academic-v1. Once active, the pack_upgrade_available check fires for any brain on gbrain-base-v2@1.x and surfaces a unify-types RemediationStep targeting your pack.

Lock + concurrency

modusbrain-unify is a dedicated modusbrain_cycle_locks row name (60min TTL). The handler acquires it before any apply phase + releases in finally. Two simultaneous modusbrain jobs submit unify-types invocations: second one fails fast at lock acquisition with a clear error. Same pattern as modusbrain-sync (v0.22.13 PR #490).

Audit trail

Every unify run writes to ~/.modusbrain/audit/schema-unify-YYYY-Www.jsonl (ISO-week rotation, mirrors existing audit channels). Records: pack identities (before + after), per-phase counts (would_apply + applied), warnings, completion timestamp. Privacy: page slugs are NOT logged in bulk (only the per-rule sample_slugs[≤10]); for forensic debugging add MODUSBRAIN_AUDIT_FULL=1 (v0.43+ TODO; not yet wired).

What’s NOT yet supported

  • Subprocess sandbox for the publish-gate (v0.43+ TODO)
  • Per-source pack-upgrade (the handler accepts sourceId but findPackSuccessors doesn’t yet pass it through)
  • Cross-brain federated mounts that disagree on canonical packs
  • Automatic rollback (today: manual SQL or modusbrain pages restore)
  • LLM-assisted mapping_rules codegen from production data (modusbrain schema detect-mappings; deferred to v0.43+)

Reference

  • Pack file: src/core/schema-pack/base/gbrain-base-v2.yaml
  • Manifest extension: src/core/schema-pack/manifest-v1.ts
  • Successor walker: src/core/schema-pack/load-active.ts:findPackSuccessors
  • Onboard check: src/core/onboard/checks.ts:checkPackUpgradeAvailable
  • Render allowlist: src/core/onboard/render.ts:MANUAL_ONLY_PROTECTED_JOBS
  • Handler: src/core/schema-pack/unify-types-handler.ts
  • Migration: src/core/migrate.ts:105 (slug_aliases table)
  • Type taxonomy doc: docs/architecture/type-taxonomy.md
  • Skill: skills/schema-unify/SKILL.md