Found while implementing #6563 (the RESTORE half of the same loop). Recording only, per Prime Directive #10 — a different line with a different cause (a hard-coded literal, not an unstated default), and outside #6563's ruled file surface.
Evidence
ObjectStackProtocolImplementation.revertCommit (packages/metadata-protocol/src/protocol.ts) has two limbs. #6563 fixes the existedBefore one. The OTHER limb — an artifact the commit CREATED, which the revert soft-removes — states its intent as a constant:
if (!it.existedBefore) {
// Created by this commit -> soft-remove (metadata only; table stays).
if (current) {
await repo.delete(ref, {
parentVersion: current.hash,
actor,
source: 'protocol.revertCommit',
intent: 'override-artifact',
state: 'active',
});
}
reverted.push({ type: it.type, name: it.name, action: 'removed' });
}
SysMetadataRepository.delete opens with this.assertAllowed(ref.type, opts.intent) — the same gate put uses — which refuses any type whose registry entry is not allowOrgOverride. object is exactly such a type, so a commit that created an object cannot be undone.
Measured on origin/main @ e39dd66 against a real SysMetadataRepository over an in-memory sys_metadata / sys_metadata_history / sys_metadata_commit double (the #6215 harness in packages/objectql/src/protocol-commit-history.test.ts): an object created once through saveMetaItem under a Studio package workspace, recorded in a commit as existedBefore: false, then reverted through revertCommit:
{
"success": false, "revertedCount": 0, "failedCount": 1, "reverted": [],
"failed": [{ "type": "object", "name": "myapp_invoice",
"error": "[NOT_OVERRIDABLE] 'object' is not allowOrgOverride in the registry. ...",
"code": "NOT_OVERRIDABLE" }]
}
…and the sys_metadata row is still there afterwards (1 row remaining). The same measurement re-run on #6563's branch is byte-identical: fixing the restore limb does not touch this one.
Why it matters
This is the first-build revert — the AI/Studio flow that publishes a brand-new app and then undoes it. Every object the commit created stays behind, success is false with a populated failed[], and the package is left half-reverted (its overlay-allowed items removed, its objects not). rollbackToPackageCommit reverts through the same loop, so it inherits this.
Suggested direction (not a ruling)
Same shape as #6563's ruling, applied to the other limb: derive the intent from the artifact per item (isArtifactBacked -> 'override-artifact' : 'runtime-only'), exactly as the sibling caller rollbackMetaItem does, rather than stating a constant. A genuinely artifact-backed item must still be refused. The repository's gate is right; the caller is what never says which of the two cases it is.
Note the delete-limb equivalent of #6563's premise check is worth re-running before implementing: deleteMetaItem (the per-item delete path) should be read first to see which intent it derives, so the two delete callers agree.
Related: #6563 (the restore limb, same loop), ADR-0067, ADR-0005.
Found while implementing #6563 (the RESTORE half of the same loop). Recording only, per Prime Directive #10 — a different line with a different cause (a hard-coded literal, not an unstated default), and outside #6563's ruled file surface.
Evidence
ObjectStackProtocolImplementation.revertCommit(packages/metadata-protocol/src/protocol.ts) has two limbs. #6563 fixes theexistedBeforeone. The OTHER limb — an artifact the commit CREATED, which the revert soft-removes — states its intent as a constant:SysMetadataRepository.deleteopens withthis.assertAllowed(ref.type, opts.intent)— the same gateputuses — which refuses any type whose registry entry is notallowOrgOverride.objectis exactly such a type, so a commit that created an object cannot be undone.Measured on
origin/main@ e39dd66 against a realSysMetadataRepositoryover an in-memorysys_metadata/sys_metadata_history/sys_metadata_commitdouble (the #6215 harness inpackages/objectql/src/protocol-commit-history.test.ts): an object created once throughsaveMetaItemunder a Studio package workspace, recorded in a commit asexistedBefore: false, then reverted throughrevertCommit:…and the
sys_metadatarow is still there afterwards (1 row remaining). The same measurement re-run on #6563's branch is byte-identical: fixing the restore limb does not touch this one.Why it matters
This is the first-build revert — the AI/Studio flow that publishes a brand-new app and then undoes it. Every object the commit created stays behind,
successisfalsewith a populatedfailed[], and the package is left half-reverted (its overlay-allowed items removed, its objects not).rollbackToPackageCommitreverts through the same loop, so it inherits this.Suggested direction (not a ruling)
Same shape as #6563's ruling, applied to the other limb: derive the intent from the artifact per item (
isArtifactBacked->'override-artifact':'runtime-only'), exactly as the sibling callerrollbackMetaItemdoes, rather than stating a constant. A genuinely artifact-backed item must still be refused. The repository's gate is right; the caller is what never says which of the two cases it is.Note the delete-limb equivalent of #6563's premise check is worth re-running before implementing:
deleteMetaItem(the per-item delete path) should be read first to see which intent it derives, so the two delete callers agree.Related: #6563 (the restore limb, same loop), ADR-0067, ADR-0005.