Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

[1/8] refactor: split Application + ApplicationVersion (ADR-002 foundation)#58

Merged
rubenvdlinde merged 4 commits into
developmentfrom
feature/openbuilt-versioning-model
May 16, 2026
Merged

[1/8] refactor: split Application + ApplicationVersion (ADR-002 foundation)#58
rubenvdlinde merged 4 commits into
developmentfrom
feature/openbuilt-versioning-model

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Summary

Foundation spec of the ADR-002 versioned-app-deployment chain. Splits the flat Application row into a logical Application (slug, name, permissions, productionVersion relation) + N ApplicationVersion rows (manifest, register, semver, status, application + promotesTo relations).

Architectural anchors

What changes

  • New: `ApplicationVersion` schema in lib/Settings/openbuilt_register.json
  • New: `ApplicationVersionService` (semver auto-bump on manifest-hash diff, cycle prevention)
  • New: `ApplicationVersionsController` (CRUD + delete-with-strategy)
  • New: `ProductionVersionGuardListener` (validates productionVersion pointer on Application save)
  • New: `MigrateToVersionedModel` repair step (green-fields pre-versioned virtual apps)
  • Removed: `ApplicationVersionSnapshotListener` + `SeedHelloWorld` (subsumed by wizard in [6/8])
  • Schema: drops `currentVersion`, `version`, `status`, `manifest` from Application top-level; adds `productionVersion` relation

Test plan

  • composer check:strict — ALL CHECKS PASSED
  • PHPUnit — full suite under tests/Unit/ (96 tests, 0 failures)
  • All 14 hydra gates — green
  • openspec validate openbuilt-versioning-model --strict — clean
  • Visual smoke — green-field migration confirmed to RUN cleanly post-listener-fix (see [7d8b1e2 fix] in [8/8]); but Hello World seed still appears in the index — needs investigation per follow-up issue

Follow-up issues filed

See chain head ([8/8]) for full list of integration issues surfaced during visual smoke.

🤖 Generated with Claude Code

Foundation of the versioned-app deployment model. Splits the conflated
Application row into:
- Application (logical): slug, name, description, permissions,
  productionVersion (relation → ApplicationVersion).
- ApplicationVersion (deployable runtime): name, slug, manifest,
  register (per-version OR register slug), semver, status, application
  (relation → parent), promotesTo (optional relation → next version).

Drops the snapshot writeback listener (ApplicationVersionSnapshotListener
+ its PHPUnit test); audit history now comes from OR object time-travel
on the ApplicationVersion row instead of append-only snapshot rows.

Application.x-openregister-lifecycle is removed — published-ness is per
version now. ApplicationVersion.x-openregister-lifecycle declares the
draft/published/archived state machine and the BuiltAppRoute upsert
action on draft→published (relocated from Application).
… guard

New imperative surface for the versioned-app model (ADR-002 / ADR-031
§Exceptions table):

- ApplicationVersionService owns:
  * canonicaliseManifest / hashManifest / bumpPatch (SHA-256 over
    recursively-key-sorted JSON; ADR-031 §Exceptions(2) — stateful
    diff outside OR calc vocab).
  * onSave: patch-bumps semver only when canonical manifest hash
    changes (metadata-only edits leave semver + manifestHash intact).
  * guardNoCycle: walks promotesTo forward up to 100 hops; rejects
    cycles and self-loops (ADR-031 §Exceptions(1) cross-row).
  * guardProductionVersionOwnership: verifies back-reference
    integrity for Application.productionVersion.
  * deleteVersion: branching strategy logic for delete-now /
    orphan-grace / keep-register; refuses to delete the production
    version.

- ApplicationVersionsController exposes CRUD + DELETE?strategy= over
  /api/applications/{slug}/versions[/...] with #[NoAdminRequired]
  and per-Application RBAC (owners/editors for write, viewers for
  read).

- ProductionVersionGuardListener subscribes to OR's ObjectCreating /
  ObjectUpdating events on Application rows and rejects saves that
  point productionVersion at a foreign ApplicationVersion (422).

OR stubs (tests/stubs/openregister-stubs.php) and psalm.xml
suppression list both grew so out-of-container unit tests can resolve
the new OR-side types (RegisterService, ObjectCreatingEvent,
ObjectUpdatingEvent, IMcpToolProvider).

Tests: 21 new PHPUnit cases covering canonicalisation determinism,
patch-bump arithmetic, cycle detection on linear and 100-hop chains,
production-version guard, every deletion strategy, and the listener's
schema-filter / propagation-stop semantics.
MigrateToVersionedModel is a destructive but idempotent IRepairStep
that wipes every pre-migration Application row and its per-app
register (openbuilt-{slug}). ADR-002 accepts the data loss: existing
OpenBuilt installs hold only test data, and the new versioned model
re-seeds Hello World at install time via the creation-wizard
capability (sibling spec).

Short-circuit logic detects already-versioned shape — either by the
presence of the applicationVersion schema or by the absence of the
legacy currentVersion field on any surviving Application row — so the
step is safe to re-run on every install / occ maintenance:repair.

Per-app register-delete failure is isolated: the corresponding
Application row is left intact, the failure is logged via
$output->warning, and enumeration continues with the next row.

SeedHelloWorld is deleted outright (file + info.xml registration +
the legacy unit test). The wizard spec re-introduces Hello World
seeding under the new model.

Tests: 3 new PHPUnit cases covering short-circuit, three-row
deletion, and partial-failure preservation.
ADR-002 codifies the admin-defined version chain — Application as
logical app + ApplicationVersion as deployable runtime, per-version
register for data isolation, ?version= URL routing, explicit
productionVersion relation (no more currentVersion writeback cache).
ADR-001 (app assets via OR-attached files) lands alongside as a
prerequisite the rest of the chain references.

openspec/changes/openbuilt-versioning-model/ is the foundation spec
of the chain: schema split, snapshot-listener retirement, green-field
migration. Three sibling specs (openbuilt-version-promotion,
openbuilt-version-routing, openbuilt-app-creation-wizard) and the
detail-page overview spec all depend on this and ship in the same
chain delivery wave.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openbuilt @ ee7ad3a

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 100/100
npm ✅ 432/432
PHPUnit
Newman ⏭️
Playwright ⏭️

Coverage: 0% (0/19 statements)


Quality workflow — 2026-05-16 07:32 UTC

Download the full PDF report from the workflow artifacts.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant