You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AppPlugin registers artifact security metadata in memory from the RAW bundle, bypassing the artifact door's ADR-0087 conversion — a second unconverted reader of the same bytes #12844
Observation recorded while fixing #12772 (dev seat of PM session session_01SVYmuhHW6qZmNBqciaS7BN; fix PR: #12843). Filed as a finding — no reachable defect measured today — for the triage round to grade.
What was measured
The framework artifact boot reads the same artifact bytes through TWO independent readers:
AppPlugin (packages/runtime/src/app-plugin.ts, the ADR-0057 block) — receives the bundle from loadArtifactBundle (packages/runtime/src/load-artifact-bundle.ts, no validation, no conversion) and registers positions / permissions / capabilities / sharingRules / policies items into the metadata service via registerInMemory, RAW.
So after an artifact boot of a pre-17.2 artifact, the converted copy (keys stripped) and the raw copy (keys present) of the same permission sets both enter the metadata registry, and which one a reader sees depends on registration order and read path.
The two-reader shape means "artifact metadata is converted at ingestion" is only half-true: any FUTURE retired key on the five security collections whose value a consumer does read would diverge between the two copies, silently, with the failure landing at whatever seam re-validates (e.g. a Studio re-save through saveMetaItem, which rejects with the current schema). One policy, one funnel would mean AppPlugin's bundle path either consumes applyArtifactForwardConversions (now exported from @objectstack/metadata-core, spec-only dependency) or stops duplicating the registration that MetadataPlugin already performs on the same boot (route-ownership question — one route, one owner).
Dedup: targeted search for this shape returned zero with a positive control hitting (#12772 family found), so no twin exists as of filing.
Observation recorded while fixing #12772 (dev seat of PM session
session_01SVYmuhHW6qZmNBqciaS7BN; fix PR: #12843). Filed as afinding— no reachable defect measured today — for the triage round to grade.What was measured
The framework artifact boot reads the same artifact bytes through TWO independent readers:
MetadataPlugin._parseAndRegisterArtifact(packages/metadata/src/plugin.ts) — re-reads the artifact file named byartifactSource, strict-parses it, and (since feat(metadata): versioned ADR-0087 forward conversion at the artifact-ingestion door #12843) runs the versioned ADR-0087 forward conversion first. Registered items are canonical.AppPlugin(packages/runtime/src/app-plugin.ts, the ADR-0057 block) — receives the bundle fromloadArtifactBundle(packages/runtime/src/load-artifact-bundle.ts, no validation, no conversion) and registerspositions/permissions/capabilities/sharingRules/policiesitems into the metadata service viaregisterInMemory, RAW.So after an artifact boot of a pre-17.2 artifact, the converted copy (keys stripped) and the raw copy (keys present) of the same permission sets both enter the metadata registry, and which one a reader sees depends on registration order and read path.
Why no defect is reachable today
registerInMemorycopies (measured: the fullOS_ARTIFACT_URLboot of the real 17.1-built hotcrm artifact is green end-to-end on the feat(metadata): versioned ADR-0087 forward conversion at the artifact-ingestion door #12843 branch —Migration complete, 37 plugins, exit 0; the multi-org battery on the epic-Epic: hotcrm as a single-DB multi-org SaaS (isolated posture) — tenant customization surface + tenant readiness #12701 program passed the same shape).allowRestore/allowPurge) gate nothing by definition of the retirement (spec: retire theallowRestore/allowPurgepermission props (ruled 2026-08-26; M2 anchor stays open, keys return with M2) #12497) — an unread extra key on an in-memory item is inert.Why it is still worth a card
The two-reader shape means "artifact metadata is converted at ingestion" is only half-true: any FUTURE retired key on the five security collections whose value a consumer does read would diverge between the two copies, silently, with the failure landing at whatever seam re-validates (e.g. a Studio re-save through
saveMetaItem, which rejects with the current schema). One policy, one funnel would meanAppPlugin's bundle path either consumesapplyArtifactForwardConversions(now exported from@objectstack/metadata-core, spec-only dependency) or stops duplicating the registration thatMetadataPluginalready performs on the same boot (route-ownership question — one route, one owner).Dedup: targeted search for this shape returned zero with a positive control hitting (#12772 family found), so no twin exists as of filing.
Generated by Claude Code