@popmelt.com/core 0.8.5 → 0.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -164,6 +164,37 @@ type EvidenceRecord = Provenance & {
164
164
  stance?: ParticipantStance;
165
165
  artifactIds: MemoryId[];
166
166
  };
167
+ /**
168
+ * An advisory explanation is learned, revisable shared understanding. It can
169
+ * guide future work, but it is deliberately distinct from accepted product
170
+ * truth (`decision`).
171
+ */
172
+ type AdvisoryExplanationKind = 'intention' | 'principle' | 'pattern';
173
+ type AdvisoryExplanationState = 'emerging' | 'testing' | 'grounded' | 'challenged' | 'retired';
174
+ type AdvisoryExplanationScope = {
175
+ kind: 'project' | 'route' | 'component' | 'selector' | 'file';
176
+ values: string[];
177
+ };
178
+ type AdvisoryConcreteBinding = {
179
+ id: string;
180
+ modelPath: string;
181
+ value: JsonValue;
182
+ createdAt: Timestamp;
183
+ updatedAt: Timestamp;
184
+ };
185
+ type AdvisoryExplanationRecord = Provenance & {
186
+ recordType: 'advisory_explanation';
187
+ kind: AdvisoryExplanationKind;
188
+ state: AdvisoryExplanationState;
189
+ statement: string;
190
+ rationale: string;
191
+ scope: AdvisoryExplanationScope;
192
+ subjectIds: MemoryId[];
193
+ evidenceIds: MemoryId[];
194
+ concreteBindings: AdvisoryConcreteBinding[];
195
+ supersededById?: MemoryId;
196
+ updatedAt: Timestamp;
197
+ };
167
198
  type CoverageClaim = {
168
199
  decisionId: MemoryId;
169
200
  coverage: 'partial' | 'full';
@@ -305,13 +336,13 @@ type ModelProjectionRecord = Provenance & {
305
336
  status: 'unprojected' | 'partially_projected' | 'projected' | 'stale';
306
337
  }>;
307
338
  };
308
- type EntityType = 'participant' | 'authority_grant' | 'subject' | 'observation' | 'proposal' | 'decision' | 'thread' | 'iteration' | 'evidence' | 'implementation_attempt' | 'eval_spec' | 'verification_attempt' | 'model_entry' | 'model_projection' | 'freshness_signal';
339
+ type EntityType = 'participant' | 'authority_grant' | 'subject' | 'observation' | 'proposal' | 'decision' | 'thread' | 'iteration' | 'evidence' | 'advisory_explanation' | 'implementation_attempt' | 'eval_spec' | 'verification_attempt' | 'model_entry' | 'model_projection' | 'freshness_signal';
309
340
  type MemoryObjectType = EntityType | 'relationship' | 'lifecycle_event' | 'artifact';
310
341
  type EntityReference = {
311
342
  entityType: EntityType;
312
343
  entityId: MemoryId;
313
344
  };
314
- type RelationshipType = 'supports' | 'contradicts' | 'supersedes' | 'excepts' | 'duplicates' | 'implements' | 'verifies' | 'replaces' | 'derived_from';
345
+ type RelationshipType = 'supports' | 'contradicts' | 'supersedes' | 'excepts' | 'duplicates' | 'implements' | 'verifies' | 'replaces' | 'derived_from' | 'operationalizes' | 'refines' | 'instantiates';
315
346
  type RelationshipRecord = Provenance & {
316
347
  recordType: 'relationship';
317
348
  relationshipType: RelationshipType;
@@ -374,8 +405,8 @@ type Tombstone = {
374
405
  erasureLevel: 'content' | 'content_and_evidence' | 'full_where_permitted';
375
406
  invalidates: EntityReference[];
376
407
  };
377
- type CanonicalRecord = ParticipantRecord | AuthorityGrantRecord | SubjectRecord | ObservationRecord | ProposalRecord | DecisionRecord | ThreadRecord | IterationRecord | EvidenceRecord | ImplementationAttemptRecord | EvalSpecRecord | VerificationAttemptRecord | ModelEntryRecord | ModelProjectionRecord | FreshnessSignalRecord;
378
- type MemoryFeature = 'authority' | 'subjects' | 'decisions' | 'implementations' | 'verification' | 'eval_specs' | 'model_projection' | 'freshness' | 'portable_artifacts' | 'bounded_retrieval';
408
+ type CanonicalRecord = ParticipantRecord | AuthorityGrantRecord | SubjectRecord | ObservationRecord | ProposalRecord | DecisionRecord | ThreadRecord | IterationRecord | EvidenceRecord | AdvisoryExplanationRecord | ImplementationAttemptRecord | EvalSpecRecord | VerificationAttemptRecord | ModelEntryRecord | ModelProjectionRecord | FreshnessSignalRecord;
409
+ type MemoryFeature = 'authority' | 'subjects' | 'decisions' | 'advisory_explanations' | 'implementations' | 'verification' | 'eval_specs' | 'model_projection' | 'freshness' | 'portable_artifacts' | 'bounded_retrieval';
379
410
  type ProjectMemoryManifest = {
380
411
  formatVersion: MemoryFormatVersion;
381
412
  projectId: MemoryId;
@@ -1 +1 @@
1
- import{createHash as Me}from"crypto";import{readFile as Le,readdir as Pe,realpath as Be}from"fs/promises";import{join as X,relative as De}from"path";var Ae=/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function Se(n){return Ae.test(n)}function Re(n){return{valid:!n.some(e=>e.severity==="error"),issues:n}}function d(n,e,i,m){n.push({path:e,code:i,message:m,severity:"error"})}function oe(n,e,i,m){n.push({path:e,code:i,message:m,severity:"warning"})}function I(n,e,i){Se(i)||d(n,e,"invalid_uuid_v7","Canonical IDs must be UUIDv7 values.")}function P(n,e,i){(!i||Number.isNaN(Date.parse(i)))&&d(n,e,"invalid_timestamp","Timestamps must be parseable ISO-8601 strings.")}function D(n,e,i,m=!1){m&&i.level==="contributor"&&d(n,`${e}.level`,"insufficient_authority","Contributors cannot accept or change normative product truth."),i.level==="delegate"&&!i.grantId&&d(n,`${e}.grantId`,"missing_authority_grant","Delegate authority must reference the grant used for this action.")}var Ee={observation:new Set(["null->open","open->resolved","open->dismissed","resolved->open","dismissed->open"]),proposal:new Set(["null->draft","draft->pending","pending->accepted","pending->rejected","pending->withdrawn","pending->deferred","deferred->pending"]),decision:new Set(["null->active","active->superseded","active->revoked"]),implementation_attempt:new Set(["null->planned","planned->in_progress","planned->abandoned","in_progress->completed","in_progress->failed","in_progress->abandoned"]),eval_spec:new Set(["null->draft","null->active","draft->active","draft->retired","active->retired"]),verification_attempt:new Set(["null->queued","queued->running","queued->cancelled","running->passed","running->failed","running->inconclusive","running->error","running->cancelled"]),freshness_signal:new Set(["null->open","open->resolved"])},we=new Set(["proposal:accepted","proposal:rejected","decision:superseded","decision:revoked"]);function xe(n,e,i){I(n,`${i}.id`,e.id),I(n,`${i}.projectId`,e.projectId),I(n,`${i}.participantId`,e.participantId),I(n,`${i}.entity.entityId`,e.entity.entityId),P(n,`${i}.createdAt`,e.createdAt),D(n,`${i}.authority`,e.authority);let m=Ee[e.entity.entityType],$=`${e.fromState??"null"}->${e.toState}`;m&&!m.has($)&&d(n,i,"invalid_lifecycle_transition",`${e.entity.entityType} does not allow ${$}.`);let j=`${e.entity.entityType}:${e.toState}`;if(we.has(j)&&(D(n,`${i}.authority`,e.authority,!0),e.reason?.trim()||d(n,`${i}.reason`,"missing_normative_reason","Normative acceptance, rejection, supersession, and revocation require a reason.")),e.entity.entityType==="proposal"&&e.toState==="deferred"){let g=e.transitionContext;(g?.kind!=="proposal_deferral"||g.resurfaceWhen.length===0)&&d(n,`${i}.transitionContext`,"missing_deferral_policy","Deferred proposals require structured resurfacing conditions."),g?.resurfaceWhen.includes("after_date")&&!g.revisitAfter&&d(n,`${i}.transitionContext.revisitAfter`,"missing_revisit_date","after_date resurfacing requires revisitAfter."),g?.revisitAfter&&P(n,`${i}.transitionContext.revisitAfter`,g.revisitAfter)}}function ke(n,e,i,m){I(n,`${i}.id`,e.id),I(n,`${i}.projectId`,e.projectId),I(n,`${i}.participantId`,e.participantId),P(n,`${i}.createdAt`,e.createdAt),e.projectId!==m&&d(n,`${i}.projectId`,"project_mismatch","Record belongs to another project."),"subjects"in e&&e.subjects.length===0&&d(n,`${i}.subjects`,"missing_subject","Proposals and decisions need a subject."),"subjects"in e&&e.subjects.length>1&&!e.subjectSemantics?.trim()&&d(n,`${i}.subjectSemantics`,"missing_subject_semantics","Multi-subject claims must explain why the subjects are inseparable."),e.recordType==="proposal"&&e.origin.mode==="inferred"&&(!e.origin.sourceText||!e.origin.iterationId||!e.origin.inferredById)&&d(n,`${i}.origin`,"incomplete_inference_provenance","Inferred structure requires source text, iteration, and inferring participant."),e.recordType==="decision"&&(D(n,`${i}.authority`,e.authority,!0),e.claim.trim()||d(n,`${i}.claim`,"empty_claim","Accepted decisions require a claim.")),e.recordType==="authority_grant"&&e.level==="owner"&&oe(n,`${i}.level`,"owner_grant_requires_policy_review","Owner grants are valid but should receive explicit policy review."),e.recordType==="freshness_signal"&&e.state==="resolved"&&(!e.resolvedAt||!e.resolvedByEventId)&&d(n,i,"incomplete_freshness_resolution","Resolved freshness signals need a time and resolving event."),e.recordType==="model_projection"&&(P(n,`${i}.appliedAt`,e.appliedAt),D(n,`${i}.authority`,e.authority,!0),e.entryIds.length===0&&d(n,`${i}.entryIds`,"empty_model_projection","Applied model projections need at least one model entry.")),e.recordType==="eval_spec"&&((!e.legacyId.trim()||!e.title.trim()||!e.prompt.trim())&&d(n,i,"incomplete_eval_spec","Eval specs need a stable id, title, and prompt."),(e.assertions.length===0||e.assertions.some($=>!$.trim()))&&d(n,`${i}.assertions`,"empty_eval_assertions","Eval specs need at least one non-empty assertion."),e.targets.length===0&&e.decisionIds.length===0&&oe(n,i,"unbound_eval_spec","Eval spec is not yet bound to canonical product truth."),(e.dependencies?.length??0)===0&&oe(n,`${i}.dependencies`,"unscoped_eval_spec","Eval spec has no freshness dependencies."))}function Ce(n,e,i){I(n,`${i}.id`,e.id),I(n,`${i}.projectId`,e.projectId),I(n,`${i}.participantId`,e.participantId),I(n,`${i}.from.entityId`,e.from.entityId),I(n,`${i}.to.entityId`,e.to.entityId),P(n,`${i}.createdAt`,e.createdAt),e.reason.trim()||d(n,`${i}.reason`,"missing_relationship_reason","Relationships need a reason."),new Set(["supports","contradicts","supersedes","excepts"]).has(e.relationshipType)&&((e.from.entityType!=="decision"||e.to.entityType!=="decision")&&d(n,i,"invalid_normative_relationship","Normative relationships connect decisions to decisions."),e.authority?D(n,`${i}.authority`,e.authority,!0):d(n,`${i}.authority`,"missing_relationship_authority","Normative relationships require explicit authority context.")),e.relationshipType==="implements"&&(e.from.entityType!=="implementation_attempt"||e.to.entityType!=="decision")&&d(n,i,"invalid_implements_relationship","`implements` points from an implementation attempt to a decision."),e.relationshipType==="verifies"&&(e.from.entityType!=="verification_attempt"||!["decision","implementation_attempt","model_entry"].includes(e.to.entityType))&&d(n,i,"invalid_verifies_relationship","`verifies` points from a verification attempt to a verifiable target."),e.relationshipType==="replaces"&&e.from.entityType!==e.to.entityType&&d(n,i,"invalid_replaces_relationship","`replaces` connects records of the same entity type.")}function ye(n){let e=[];I(e,"manifest.projectId",n.manifest.projectId),P(e,"manifest.createdAt",n.manifest.createdAt),P(e,"manifest.updatedAt",n.manifest.updatedAt);let i=new Map,m=(t,a)=>{let s=i.get(t);s?d(e,a,"duplicate_id",`ID is already used at ${s}.`):i.set(t,a)};n.records.forEach((t,a)=>{let s=`records[${a}]`;m(t.id,s),ke(e,t,s,n.manifest.projectId)}),n.events.forEach((t,a)=>{let s=`events[${a}]`;m(t.id,s),xe(e,t,s),t.projectId!==n.manifest.projectId&&d(e,`${s}.projectId`,"project_mismatch","Event belongs to another project.")}),n.relationships.forEach((t,a)=>{let s=`relationships[${a}]`;m(t.id,s),Ce(e,t,s),t.projectId!==n.manifest.projectId&&d(e,`${s}.projectId`,"project_mismatch","Relationship belongs to another project.")}),n.artifacts.forEach((t,a)=>{m(t.id,`artifacts[${a}]`),I(e,`artifacts[${a}].id`,t.id)}),n.tombstones.forEach((t,a)=>{let s=`tombstones[${a}]`;m(t.id,s),I(e,`${s}.id`,t.id),I(e,`${s}.objectId`,t.objectId),I(e,`${s}.deletedById`,t.deletedById),P(e,`${s}.deletedAt`,t.deletedAt),D(e,`${s}.authority`,t.authority,!0)});let $=new Set(n.records.map(t=>`${t.recordType}:${t.id}`)),j=new Set(n.tombstones.map(t=>`${t.objectType}:${t.objectId}`)),g=(t,a)=>{let s=`${t.entityType}:${t.entityId}`;!$.has(s)&&!j.has(s)&&d(e,a,"dangling_entity_reference",`No record or tombstone exists for ${s}.`)};n.events.forEach((t,a)=>g(t.entity,`events[${a}].entity`)),n.relationships.forEach((t,a)=>{g(t.from,`relationships[${a}].from`),g(t.to,`relationships[${a}].to`)});let Q=new Set(n.artifacts.map(t=>t.id)),S=(t,a)=>{Q.has(t)||d(e,a,"dangling_artifact_reference","No artifact manifest entry exists.")},u=(t,a,s)=>{!$.has(`${t}:${a}`)&&!j.has(`${t}:${a}`)&&d(e,s,"dangling_entity_reference",`No ${t} record or tombstone exists.`)};n.records.forEach((t,a)=>{let s=`records[${a}]`;switch(t.recordType){case"authority_grant":u("participant",t.granteeId,`${s}.granteeId`),u("participant",t.grantedById,`${s}.grantedById`),t.subjectIds.forEach((r,o)=>u("subject",r,`${s}.subjectIds[${o}]`));break;case"observation":t.captureContext.subjectIds.forEach((r,o)=>u("subject",r,`${s}.captureContext.subjectIds[${o}]`)),t.captureContext.artifactIds.forEach((r,o)=>S(r,`${s}.captureContext.artifactIds[${o}]`));break;case"proposal":case"decision":t.subjects.forEach((r,o)=>u("subject",r.subjectId,`${s}.subjects[${o}].subjectId`));break;case"thread":t.messageArtifactIds.forEach((r,o)=>S(r,`${s}.messageArtifactIds[${o}]`)),t.resultRefs.forEach((r,o)=>g(r,`${s}.resultRefs[${o}]`));break;case"iteration":t.threadIds.forEach((r,o)=>u("thread",r,`${s}.threadIds[${o}]`)),t.artifactIds.forEach((r,o)=>S(r,`${s}.artifactIds[${o}]`));break;case"evidence":t.artifactIds.forEach((r,o)=>S(r,`${s}.artifactIds[${o}]`));break;case"implementation_attempt":t.iterationIds.forEach((r,o)=>u("iteration",r,`${s}.iterationIds[${o}]`)),t.coverageClaims.forEach((r,o)=>u("decision",r.decisionId,`${s}.coverageClaims[${o}].decisionId`)),t.artifactIds.forEach((r,o)=>S(r,`${s}.artifactIds[${o}]`));break;case"eval_spec":t.replacesSpecId&&u("eval_spec",t.replacesSpecId,`${s}.replacesSpecId`),t.decisionIds.forEach((r,o)=>u("decision",r,`${s}.decisionIds[${o}]`)),t.subjectIds.forEach((r,o)=>u("subject",r,`${s}.subjectIds[${o}]`)),(t.dependencies??[]).forEach((r,o)=>{r.kind==="subject"&&r.subjectId&&u("subject",r.subjectId,`${s}.dependencies[${o}].subjectId`)}),(t.scenarios??[]).forEach((r,o)=>{r.subjectIds?.forEach((f,x)=>u("subject",f,`${s}.scenarios[${o}].subjectIds[${x}]`))}),t.targets.forEach((r,o)=>u(r.entityType,r.entityId,`${s}.targets[${o}]`));break;case"verification_attempt":t.evalSpecId&&u("eval_spec",t.evalSpecId,`${s}.evalSpecId`),t.targets.forEach((r,o)=>u(r.entityType,r.entityId,`${s}.targets[${o}]`)),t.evidenceIds.forEach((r,o)=>u("evidence",r,`${s}.evidenceIds[${o}]`));break;case"model_entry":t.subjectIds.forEach((r,o)=>u("subject",r,`${s}.subjectIds[${o}]`)),t.decisionIds.forEach((r,o)=>u("decision",r,`${s}.decisionIds[${o}]`));break;case"model_projection":D(e,`${s}.authority`,t.authority,!0),u("participant",t.appliedById,`${s}.appliedById`),t.decisionIds.forEach((r,o)=>u("decision",r,`${s}.decisionIds[${o}]`)),t.entryIds.forEach((r,o)=>u("model_entry",r,`${s}.entryIds[${o}]`)),t.coverage.forEach((r,o)=>u("decision",r.decisionId,`${s}.coverage[${o}].decisionId`));break;case"freshness_signal":g(t.target,`${s}.target`),t.evidenceIds.forEach((r,o)=>u("evidence",r,`${s}.evidenceIds[${o}]`));break;default:break}});let ne=new Map(n.events.map(t=>[t.id,t])),M=new Map(n.records.map(t=>[`${t.recordType}:${t.id}`,t])),q=new Map;n.events.forEach((t,a)=>{let s=`${t.entity.entityType}:${t.entity.entityId}:${t.fromState??"null"}`,r=q.get(s)??new Set;r.add(t.toState),q.set(s,r),r.size>1&&d(e,`events[${a}]`,"concurrent_incompatible_transitions","The same entity state has multiple incompatible successor states.")});let _=new Map(n.records.flatMap(t=>t.recordType==="authority_grant"?[[t.id,t]]:[])),h=(t,a,s,r,o)=>{if(t.level!=="delegate"||!t.grantId)return;let f=_.get(t.grantId);if(!f){d(e,o,"invalid_authority_grant","Delegated authority references a missing grant.");return}(f.granteeId!==a||f.level!=="delegate")&&d(e,o,"authority_grantee_mismatch","The grant does not authorize this participant as a delegate.");let x=Date.parse(s);(x<Date.parse(f.startsAt)||f.endsAt&&x>Date.parse(f.endsAt)||f.revokedAt&&x>=Date.parse(f.revokedAt))&&d(e,o,"inactive_authority_grant","The delegated authority grant was not active at this time."),f.subjectIds.length&&r.length&&!r.every(W=>f.subjectIds.includes(W))&&d(e,o,"authority_scope_mismatch","The delegated action exceeds the grant subject scope.")};for(let t of n.records)t.recordType==="decision"&&h(t.authority,t.acceptedById,t.createdAt,t.subjects.map(a=>a.subjectId),`records:${t.id}.authority`);n.events.forEach((t,a)=>{let s=M.get(`${t.entity.entityType}:${t.entity.entityId}`),r=s&&"subjects"in s?s.subjects.map(o=>o.subjectId):[];h(t.authority,t.participantId,t.createdAt,r,`events[${a}].authority`)}),n.relationships.forEach((t,a)=>{if(!t.authority)return;let s=[t.from,t.to].flatMap(r=>{let o=M.get(`${r.entityType}:${r.entityId}`);return o&&"subjects"in o?o.subjects.map(f=>f.subjectId):[]});h(t.authority,t.participantId,t.createdAt,s,`relationships[${a}].authority`)});for(let t of n.records){if(t.recordType!=="decision")continue;let a=ne.get(t.acceptanceEventId);(!a||a.entity.entityType!=="proposal"||a.entity.entityId!==t.proposalId||a.toState!=="accepted")&&d(e,`records:${t.id}.acceptanceEventId`,"invalid_acceptance_event","A decision must reference the proposal event that explicitly accepted it."),a&&a.participantId!==t.acceptedById&&d(e,`records:${t.id}.acceptedById`,"acceptor_mismatch","Decision acceptor must match the acceptance event participant."),M.has(`proposal:${t.proposalId}`)||d(e,`records:${t.id}.proposalId`,"missing_proposal","Accepted decisions must retain their proposal."),t.state==="superseded"&&(n.relationships.some(r=>r.relationshipType==="supersedes"&&r.to.entityType==="decision"&&r.to.entityId===t.id)||d(e,`records:${t.id}.state`,"missing_successor","Superseded decisions require an explicit successor relationship.")),t.state==="revoked"&&(n.events.some(r=>r.entity.entityType==="decision"&&r.entity.entityId===t.id&&r.toState==="revoked"&&!!r.reason?.trim())||d(e,`records:${t.id}.state`,"missing_revocation_event","Revoked decisions require an authorized event with a reason."))}for(let t of n.records){if(t.recordType!=="proposal"||t.state!=="accepted")continue;n.records.some(s=>s.recordType==="decision"&&s.proposalId===t.id)||d(e,`records:${t.id}.state`,"accepted_proposal_without_decision","Every accepted proposal must produce an immutable decision.")}return Re(e)}var qe=["f5258a13","31ffc15e","3eae3a70","c185e614","33930045","55e04c59","f3bb881b","f8a55928","eac95a7d","e402bdc2","2854624b","cf28ad45","6a494fab","987e901b","ad7293aa","dd1d5d77","14c429d6","48494ad3","d6bbe932","e8b94260","f56fa283","7f1f6cb3","f239f4ac","bd671e61","dbe032ec","c0808b95"];function K(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)?n:null}function A(n,e=0){return new Date(Number.isFinite(n)?n:e).toISOString()}function he(...n){return n.find(e=>!!e?.trim())?.trim()}function b(n,e,i,m){let j=Math.max(0,Math.min(Math.floor(m),0xffffffffffff)).toString(16).padStart(12,"0"),g=Me("sha256").update(`${n}\0${e}\0${i}`).digest("hex"),Q=(Number.parseInt(g[3],16)&3|8).toString(16);return`${j.slice(0,8)}-${j.slice(8)}-7${g.slice(0,3)}-${Q}${g.slice(4,7)}-${g.slice(7,19)}`}async function ae(n,e){try{return JSON.parse(await Le(n,"utf8"))}catch(i){return e.push({severity:"warning",code:"source_unavailable",source:n,message:i instanceof Error?i.message:String(i)}),null}}function Ne(n){let e=K(n);if(!e)return 0;let i=0,m=$=>{let j=K($);if(!j){i+=1;return}for(let g of Object.values(j))m(g)};for(let $ of Object.values(e))m($);return i}function Oe(n){let e={};for(let i of n)e[i.recordType]=(e[i.recordType]??0)+1;return e}async function Ve(n){let e=[],i=await Be(n.projectRoot).catch(()=>n.projectRoot),m=X(i,".popmelt"),$=await ae(X(m,"threads.json"),e),j=await ae(X(m,"model.json"),e),g=K($),Q=K(g?.threads)??{},S=Object.entries(Q).map(([c,p])=>({key:c,value:K(p)})).filter(c=>!!c.value),u=X(m,"decisions"),ne=await Pe(u).catch(()=>[]),M=[];for(let c of ne.filter(p=>p.endsWith(".json")).sort()){let p=K(await ae(X(u,c),e));p&&M.push({file:c,value:p})}let q=S.flatMap(({value:c})=>[c.createdAt,c.updatedAt]).filter(c=>typeof c=="number"&&Number.isFinite(c)),_=q.length?Math.min(...q):0,h=n.projectKey??i;n.projectKey||e.push({severity:"info",code:"path_derived_project_identity",message:"Canonical project identity is stable for this path; pass projectKey to preserve it across moves."});let t=b(h,"project",h,_),a=b(h,"participant","legacy-owner",_),s=b(h,"participant","legacy-agent",_),r=b(h,"subject","project",_),o=A(Math.max(_,...q)),f=[],x=[],W=new Map,z=new Map,ce=new Map(M.map(c=>[c.value.id??c.file.replace(/^d-|\.json$/g,""),c.value])),ie=new Map,Y=(c,p,l,v,R)=>{let k=W.get(l);if(k)return k;let L=b(h,"artifact",c,v);return x.push({id:L,kind:p,mediaType:R,location:l,availability:"available"}),W.set(l,L),L};for(let{file:c,value:p}of M){let l=p.id??c.replace(/^d-|\.json$/g,""),v=p.createdAt??_,R=[Y(`${l}:envelope`,"other",`.popmelt/decisions/${c}`,v,"application/json")];p.screenshotPath&&R.push(Y(`${l}:screenshot`,"screenshot",`.popmelt/${p.screenshotPath.replace(/^\.popmelt\//,"")}`,v,p.screenshotPath.endsWith(".png")?"image/png":"image/webp"));for(let[k,L]of(p.pastedImagePaths??[]).entries())R.push(Y(`${l}:image:${k}`,"image",L,v));ie.set(l,R)}let C=(c,p,l)=>({id:c,schemaVersion:1,projectId:t,createdAt:o,participantId:p,sourceRefs:l}),Z=(c,p)=>{f.push(p);let l=z.get(c)??[];l.push(p.id),z.set(c,l)},Ie=[{...C(a,a,[]),recordType:"participant",kind:"human",displayName:"Legacy project owner",status:"active"},{...C(s,s,[]),recordType:"participant",kind:"ai",displayName:"Legacy coding agent",status:"active"}];f.push(...Ie),f.push({...C(r,a,[]),recordType:"subject",subjectType:"project",label:De(process.cwd(),i)||i,aliases:[],locators:[{id:b(h,"locator",i,_),kind:"project_root",value:i,status:"current",validFrom:A(_),sourceRefs:[]}]});let de=new Map,pe=(c,p)=>{let l=de.get(c);if(l)return l;let v=b(h,"subject",c,p),R={...C(v,a,[{kind:"external",id:c}]),createdAt:A(p),recordType:"subject",subjectType:"element",label:c,aliases:[],locators:[{id:b(h,"locator",c,p),kind:"dom_selector",value:c,status:"current",validFrom:A(p),sourceRefs:[{kind:"external",id:c}]}]};return f.push(R),de.set(c,v),v};for(let{key:c,value:p}of S){let l=p.id??c,v=p.createdAt??_,R=b(h,"thread",l,v),k={kind:"thread",id:l},L=[],H=[],ue=Array.isArray(p.messages)?p.messages:[],N,se,me=0;ue.forEach((y,O)=>{let T=y.timestamp??v,B=b(h,"artifact",`${l}:message:${O}`,T);if(L.push(B),x.push({id:B,kind:"message",mediaType:"application/json",location:`.popmelt/threads.json#/threads/${l}/messages/${O}`,availability:"available"}),W.set(`.popmelt/threads.json#/threads/${l}/messages/${O}`,B),y.screenshotPath&&Y(`${l}:message:${O}:screenshot`,"screenshot",y.screenshotPath,T),y.role==="human"){N=y;let E=y.feedbackSummary??y.replyToQuestion;if(E?.trim()){let w=b(h,"observation",`${l}:${O}`,T),U=p.elementIdentifiers??[],te={...C(w,a,[k,{kind:"message",id:B}]),createdAt:A(T),recordType:"observation",state:"open",statement:E,captureContext:{subjectIds:U.map(G=>pe(G,v)),artifactIds:[B]},resolvedByIds:[]};Z(l,te),se=w,H.push({entityType:"observation",entityId:w})}return}if(y.role!=="assistant")return;let V=y.jobId??`${l}:${O}`,F=b(h,"iteration",V,T),J=ce.get(V),je=y.cancelled?"cancelled":y.error?"failed":y.question?"question_asked":(y.resolutions?.length??0)>0?"completed":"no_change",_e={...C(F,s,[k,{kind:"message",id:B},...(ie.get(V)??[]).map(E=>({kind:"artifact",id:E}))]),createdAt:A(T),recordType:"iteration",threadIds:[R],startedAt:A(N?.timestamp,T),completedAt:A(T),requestSummary:he(N?.feedbackSummary,N?.replyToQuestion)??"[legacy request unavailable]",responseSummary:y.question??y.error??y.responseText?.slice(0,1e3),outcome:je,execution:{provider:y.provider??J?.provider,model:y.model??J?.model,sessionId:y.sessionId??J?.sessionId},artifactIds:[B,...ie.get(V)??[]]};Z(l,_e),H.push({entityType:"iteration",entityId:F});let re=y.resolutions??J?.resolutions??[];for(let[E,w]of re.entries()){if(w.status!=="resolved"||!w.summary?.trim())continue;let U=p.elementIdentifiers??[],te=(U.length?U:[i]).map(ge=>({subjectId:ge===i?r:pe(ge,v),role:"governed"})),G=b(h,"proposal",`${V}:${w.annotationId??"resolution"}:${E}`,T),Te={...C(G,s,[k,{kind:"iteration",id:F}]),createdAt:A(T),recordType:"proposal",state:"pending",claim:w.summary,subjects:te,subjectSemantics:te.length>1?"Legacy thread grouped these selected elements; independent scope requires owner review.":void 0,origin:{mode:"inferred",sourceText:he(N?.feedbackSummary,N?.replyToQuestion,w.summary),iterationId:F,inferredById:s}};Z(l,Te),H.push({entityType:"proposal",entityId:G}),e.push({severity:"warning",code:"acceptance_unresolved",source:l,message:`Proposal ${G} remains pending; legacy resolved status proves an outcome, not explicit acceptance.`})}if(re.some(E=>E.status==="resolved")||J?.gitDiff){let E=b(h,"implementation",V,T),w={...C(E,s,[k,{kind:"iteration",id:F}]),createdAt:A(T),recordType:"implementation_attempt",state:"completed",iterationIds:[F],coverageClaims:[],summary:re.map(U=>U.summary).filter(Boolean).join(" ")||"Legacy implementation outcome.",artifactIds:[]};Z(l,w),H.push({entityType:"implementation_attempt",entityId:E}),me+=1}se&&(se=void 0)});let fe=ue.at(-1),$e={...C(R,a,[k]),createdAt:A(v),recordType:"thread",state:fe?.question?"open":"resolved",messageArtifactIds:L,outcome:fe?.question?"question_unresolved":me?"implementation_only":"no_outcome",resultRefs:H};f.push($e),z.set(l,[R,...z.get(l)??[]])}let ee=Ne(j);ee&&e.push({severity:"warning",code:"model_entries_deferred",source:".popmelt/model.json",message:`${ee} model values were not promoted because their accepted decision provenance is unresolved.`});let le={manifest:{formatVersion:1,projectId:t,createdAt:A(_),updatedAt:o,features:["authority","subjects","implementations","eval_specs","portable_artifacts","bounded_retrieval"],writer:{name:"@popmelt.com/core legacy importer",version:n.writerVersion??"0.8.4-dev"}},records:f,events:[],relationships:[],artifacts:x,tombstones:[]},ve=ye(le),be=(n.proofCaseIds??qe).map(c=>({legacyId:c,threadFound:S.some(({key:p,value:l})=>(l.id??p)===c),decisionEnvelopeFound:ce.has(c),recordIds:z.get(c)??[]}));return{bundle:le,report:{projectRoot:i,source:{threads:S.length,messages:S.reduce((c,p)=>c+(p.value.messages?.length??0),0),decisionEnvelopes:M.length,modelEntries:ee,artifactsReferenced:x.length},imported:Oe(f),unresolvedAcceptance:e.filter(c=>c.code==="acceptance_unresolved").length,deferredModelEntries:ee,proofCases:be,issues:e,schemaIssues:ve.issues}}}export{Ve as importLegacyProject,b as legacyUuidV7};
1
+ import{createHash as Me}from"crypto";import{readFile as Le,readdir as Pe,realpath as Be}from"fs/promises";import{join as X,relative as De}from"path";var Ae=/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function Se(n){return Ae.test(n)}function Re(n){return{valid:!n.some(e=>e.severity==="error"),issues:n}}function d(n,e,i,m){n.push({path:e,code:i,message:m,severity:"error"})}function re(n,e,i,m){n.push({path:e,code:i,message:m,severity:"warning"})}function $(n,e,i){Se(i)||d(n,e,"invalid_uuid_v7","Canonical IDs must be UUIDv7 values.")}function x(n,e,i){(!i||Number.isNaN(Date.parse(i)))&&d(n,e,"invalid_timestamp","Timestamps must be parseable ISO-8601 strings.")}function D(n,e,i,m=!1){m&&i.level==="contributor"&&d(n,`${e}.level`,"insufficient_authority","Contributors cannot accept or change normative product truth."),i.level==="delegate"&&!i.grantId&&d(n,`${e}.grantId`,"missing_authority_grant","Delegate authority must reference the grant used for this action.")}var Ee={observation:new Set(["null->open","open->resolved","open->dismissed","resolved->open","dismissed->open"]),proposal:new Set(["null->draft","draft->pending","pending->accepted","pending->rejected","pending->withdrawn","pending->deferred","deferred->pending"]),decision:new Set(["null->active","active->superseded","active->revoked"]),advisory_explanation:new Set(["null->emerging","null->testing","null->grounded","null->challenged","null->retired","emerging->testing","emerging->grounded","emerging->challenged","emerging->retired","testing->grounded","testing->challenged","testing->retired","grounded->challenged","grounded->retired","challenged->testing","challenged->retired"]),implementation_attempt:new Set(["null->planned","planned->in_progress","planned->abandoned","in_progress->completed","in_progress->failed","in_progress->abandoned"]),eval_spec:new Set(["null->draft","null->active","draft->active","draft->retired","active->retired"]),verification_attempt:new Set(["null->queued","queued->running","queued->cancelled","running->passed","running->failed","running->inconclusive","running->error","running->cancelled"]),freshness_signal:new Set(["null->open","open->resolved"])},we=new Set(["proposal:accepted","proposal:rejected","decision:superseded","decision:revoked"]);function xe(n,e,i){$(n,`${i}.id`,e.id),$(n,`${i}.projectId`,e.projectId),$(n,`${i}.participantId`,e.participantId),$(n,`${i}.entity.entityId`,e.entity.entityId),x(n,`${i}.createdAt`,e.createdAt),D(n,`${i}.authority`,e.authority);let m=Ee[e.entity.entityType],f=`${e.fromState??"null"}->${e.toState}`;m&&!m.has(f)&&d(n,i,"invalid_lifecycle_transition",`${e.entity.entityType} does not allow ${f}.`);let I=`${e.entity.entityType}:${e.toState}`;if(we.has(I)&&(D(n,`${i}.authority`,e.authority,!0),e.reason?.trim()||d(n,`${i}.reason`,"missing_normative_reason","Normative acceptance, rejection, supersession, and revocation require a reason.")),e.entity.entityType==="proposal"&&e.toState==="deferred"){let y=e.transitionContext;(y?.kind!=="proposal_deferral"||y.resurfaceWhen.length===0)&&d(n,`${i}.transitionContext`,"missing_deferral_policy","Deferred proposals require structured resurfacing conditions."),y?.resurfaceWhen.includes("after_date")&&!y.revisitAfter&&d(n,`${i}.transitionContext.revisitAfter`,"missing_revisit_date","after_date resurfacing requires revisitAfter."),y?.revisitAfter&&x(n,`${i}.transitionContext.revisitAfter`,y.revisitAfter)}}function ke(n,e,i,m){$(n,`${i}.id`,e.id),$(n,`${i}.projectId`,e.projectId),$(n,`${i}.participantId`,e.participantId),x(n,`${i}.createdAt`,e.createdAt),e.projectId!==m&&d(n,`${i}.projectId`,"project_mismatch","Record belongs to another project."),"subjects"in e&&e.subjects.length===0&&d(n,`${i}.subjects`,"missing_subject","Proposals and decisions need a subject."),"subjects"in e&&e.subjects.length>1&&!e.subjectSemantics?.trim()&&d(n,`${i}.subjectSemantics`,"missing_subject_semantics","Multi-subject claims must explain why the subjects are inseparable."),e.recordType==="proposal"&&e.origin.mode==="inferred"&&(!e.origin.sourceText||!e.origin.iterationId||!e.origin.inferredById)&&d(n,`${i}.origin`,"incomplete_inference_provenance","Inferred structure requires source text, iteration, and inferring participant."),e.recordType==="decision"&&(D(n,`${i}.authority`,e.authority,!0),e.claim.trim()||d(n,`${i}.claim`,"empty_claim","Accepted decisions require a claim.")),e.recordType==="authority_grant"&&e.level==="owner"&&re(n,`${i}.level`,"owner_grant_requires_policy_review","Owner grants are valid but should receive explicit policy review."),e.recordType==="advisory_explanation"&&((!e.statement.trim()||!e.rationale.trim())&&d(n,i,"incomplete_advisory_explanation","Advisory explanations need a statement and rationale."),x(n,`${i}.updatedAt`,e.updatedAt),e.subjectIds.length===0&&d(n,`${i}.subjectIds`,"missing_subject","Advisory explanations need a subject."),e.scope.values.some(f=>!f.trim())&&d(n,`${i}.scope.values`,"empty_scope_value","Advisory scope values cannot be empty."),e.concreteBindings.forEach((f,I)=>{(!f.id.trim()||!f.modelPath.trim())&&d(n,`${i}.concreteBindings[${I}]`,"incomplete_concrete_binding","Concrete bindings need an id and model path."),x(n,`${i}.concreteBindings[${I}].createdAt`,f.createdAt),x(n,`${i}.concreteBindings[${I}].updatedAt`,f.updatedAt)})),e.recordType==="freshness_signal"&&e.state==="resolved"&&(!e.resolvedAt||!e.resolvedByEventId)&&d(n,i,"incomplete_freshness_resolution","Resolved freshness signals need a time and resolving event."),e.recordType==="model_projection"&&(x(n,`${i}.appliedAt`,e.appliedAt),D(n,`${i}.authority`,e.authority,!0),e.entryIds.length===0&&d(n,`${i}.entryIds`,"empty_model_projection","Applied model projections need at least one model entry.")),e.recordType==="eval_spec"&&((!e.legacyId.trim()||!e.title.trim()||!e.prompt.trim())&&d(n,i,"incomplete_eval_spec","Eval specs need a stable id, title, and prompt."),(e.assertions.length===0||e.assertions.some(f=>!f.trim()))&&d(n,`${i}.assertions`,"empty_eval_assertions","Eval specs need at least one non-empty assertion."),e.targets.length===0&&e.decisionIds.length===0&&re(n,i,"unbound_eval_spec","Eval spec is not yet bound to canonical product truth."),(e.dependencies?.length??0)===0&&re(n,`${i}.dependencies`,"unscoped_eval_spec","Eval spec has no freshness dependencies."))}function Ce(n,e,i){if($(n,`${i}.id`,e.id),$(n,`${i}.projectId`,e.projectId),$(n,`${i}.participantId`,e.participantId),$(n,`${i}.from.entityId`,e.from.entityId),$(n,`${i}.to.entityId`,e.to.entityId),x(n,`${i}.createdAt`,e.createdAt),e.reason.trim()||d(n,`${i}.reason`,"missing_relationship_reason","Relationships need a reason."),new Set(["supports","contradicts","supersedes","excepts"]).has(e.relationshipType)){let f=e.from.entityType==="decision"&&e.to.entityType==="decision",I=e.from.entityType==="advisory_explanation"&&e.to.entityType==="advisory_explanation";!f&&!I&&d(n,i,"invalid_normative_relationship","These relationships connect decisions to decisions or advisory explanations to advisory explanations."),f&&!e.authority?d(n,`${i}.authority`,"missing_relationship_authority","Normative relationships require explicit authority context."):f&&e.authority&&D(n,`${i}.authority`,e.authority,!0)}["operationalizes","refines","instantiates"].includes(e.relationshipType)&&(e.from.entityType!=="advisory_explanation"||e.to.entityType!=="advisory_explanation")&&d(n,i,"invalid_advisory_relationship","Advisory topology relationships connect advisory explanations."),e.relationshipType==="implements"&&(e.from.entityType!=="implementation_attempt"||e.to.entityType!=="decision")&&d(n,i,"invalid_implements_relationship","`implements` points from an implementation attempt to a decision."),e.relationshipType==="verifies"&&(e.from.entityType!=="verification_attempt"||!["decision","implementation_attempt","model_entry"].includes(e.to.entityType))&&d(n,i,"invalid_verifies_relationship","`verifies` points from a verification attempt to a verifiable target."),e.relationshipType==="replaces"&&e.from.entityType!==e.to.entityType&&d(n,i,"invalid_replaces_relationship","`replaces` connects records of the same entity type.")}function ye(n){let e=[];$(e,"manifest.projectId",n.manifest.projectId),x(e,"manifest.createdAt",n.manifest.createdAt),x(e,"manifest.updatedAt",n.manifest.updatedAt);let i=new Map,m=(t,a)=>{let s=i.get(t);s?d(e,a,"duplicate_id",`ID is already used at ${s}.`):i.set(t,a)};n.records.forEach((t,a)=>{let s=`records[${a}]`;m(t.id,s),ke(e,t,s,n.manifest.projectId)}),n.events.forEach((t,a)=>{let s=`events[${a}]`;m(t.id,s),xe(e,t,s),t.projectId!==n.manifest.projectId&&d(e,`${s}.projectId`,"project_mismatch","Event belongs to another project.")}),n.relationships.forEach((t,a)=>{let s=`relationships[${a}]`;m(t.id,s),Ce(e,t,s),t.projectId!==n.manifest.projectId&&d(e,`${s}.projectId`,"project_mismatch","Relationship belongs to another project.")}),n.artifacts.forEach((t,a)=>{m(t.id,`artifacts[${a}]`),$(e,`artifacts[${a}].id`,t.id)}),n.tombstones.forEach((t,a)=>{let s=`tombstones[${a}]`;m(t.id,s),$(e,`${s}.id`,t.id),$(e,`${s}.objectId`,t.objectId),$(e,`${s}.deletedById`,t.deletedById),x(e,`${s}.deletedAt`,t.deletedAt),D(e,`${s}.authority`,t.authority,!0)});let f=new Set(n.records.map(t=>`${t.recordType}:${t.id}`)),I=new Set(n.tombstones.map(t=>`${t.objectType}:${t.objectId}`)),y=(t,a)=>{let s=`${t.entityType}:${t.entityId}`;!f.has(s)&&!I.has(s)&&d(e,a,"dangling_entity_reference",`No record or tombstone exists for ${s}.`)};n.events.forEach((t,a)=>y(t.entity,`events[${a}].entity`)),n.relationships.forEach((t,a)=>{y(t.from,`relationships[${a}].from`),y(t.to,`relationships[${a}].to`)});let z=new Set(n.artifacts.map(t=>t.id)),S=(t,a)=>{z.has(t)||d(e,a,"dangling_artifact_reference","No artifact manifest entry exists.")},u=(t,a,s)=>{!f.has(`${t}:${a}`)&&!I.has(`${t}:${a}`)&&d(e,s,"dangling_entity_reference",`No ${t} record or tombstone exists.`)};n.records.forEach((t,a)=>{let s=`records[${a}]`;switch(t.recordType){case"authority_grant":u("participant",t.granteeId,`${s}.granteeId`),u("participant",t.grantedById,`${s}.grantedById`),t.subjectIds.forEach((o,r)=>u("subject",o,`${s}.subjectIds[${r}]`));break;case"observation":t.captureContext.subjectIds.forEach((o,r)=>u("subject",o,`${s}.captureContext.subjectIds[${r}]`)),t.captureContext.artifactIds.forEach((o,r)=>S(o,`${s}.captureContext.artifactIds[${r}]`));break;case"proposal":case"decision":t.subjects.forEach((o,r)=>u("subject",o.subjectId,`${s}.subjects[${r}].subjectId`));break;case"thread":t.messageArtifactIds.forEach((o,r)=>S(o,`${s}.messageArtifactIds[${r}]`)),t.resultRefs.forEach((o,r)=>y(o,`${s}.resultRefs[${r}]`));break;case"iteration":t.threadIds.forEach((o,r)=>u("thread",o,`${s}.threadIds[${r}]`)),t.artifactIds.forEach((o,r)=>S(o,`${s}.artifactIds[${r}]`));break;case"evidence":t.artifactIds.forEach((o,r)=>S(o,`${s}.artifactIds[${r}]`));break;case"advisory_explanation":t.subjectIds.forEach((o,r)=>u("subject",o,`${s}.subjectIds[${r}]`)),t.evidenceIds.forEach((o,r)=>u("evidence",o,`${s}.evidenceIds[${r}]`)),t.supersededById&&u("advisory_explanation",t.supersededById,`${s}.supersededById`);break;case"implementation_attempt":t.iterationIds.forEach((o,r)=>u("iteration",o,`${s}.iterationIds[${r}]`)),t.coverageClaims.forEach((o,r)=>u("decision",o.decisionId,`${s}.coverageClaims[${r}].decisionId`)),t.artifactIds.forEach((o,r)=>S(o,`${s}.artifactIds[${r}]`));break;case"eval_spec":t.replacesSpecId&&u("eval_spec",t.replacesSpecId,`${s}.replacesSpecId`),t.decisionIds.forEach((o,r)=>u("decision",o,`${s}.decisionIds[${r}]`)),t.subjectIds.forEach((o,r)=>u("subject",o,`${s}.subjectIds[${r}]`)),(t.dependencies??[]).forEach((o,r)=>{o.kind==="subject"&&o.subjectId&&u("subject",o.subjectId,`${s}.dependencies[${r}].subjectId`)}),(t.scenarios??[]).forEach((o,r)=>{o.subjectIds?.forEach((g,k)=>u("subject",g,`${s}.scenarios[${r}].subjectIds[${k}]`))}),t.targets.forEach((o,r)=>u(o.entityType,o.entityId,`${s}.targets[${r}]`));break;case"verification_attempt":t.evalSpecId&&u("eval_spec",t.evalSpecId,`${s}.evalSpecId`),t.targets.forEach((o,r)=>u(o.entityType,o.entityId,`${s}.targets[${r}]`)),t.evidenceIds.forEach((o,r)=>u("evidence",o,`${s}.evidenceIds[${r}]`));break;case"model_entry":t.subjectIds.forEach((o,r)=>u("subject",o,`${s}.subjectIds[${r}]`)),t.decisionIds.forEach((o,r)=>u("decision",o,`${s}.decisionIds[${r}]`));break;case"model_projection":D(e,`${s}.authority`,t.authority,!0),u("participant",t.appliedById,`${s}.appliedById`),t.decisionIds.forEach((o,r)=>u("decision",o,`${s}.decisionIds[${r}]`)),t.entryIds.forEach((o,r)=>u("model_entry",o,`${s}.entryIds[${r}]`)),t.coverage.forEach((o,r)=>u("decision",o.decisionId,`${s}.coverage[${r}].decisionId`));break;case"freshness_signal":y(t.target,`${s}.target`),t.evidenceIds.forEach((o,r)=>u("evidence",o,`${s}.evidenceIds[${r}]`));break;default:break}});let ne=new Map(n.events.map(t=>[t.id,t])),L=new Map(n.records.map(t=>[`${t.recordType}:${t.id}`,t])),q=new Map;n.events.forEach((t,a)=>{let s=`${t.entity.entityType}:${t.entity.entityId}:${t.fromState??"null"}`,o=q.get(s)??new Set;o.add(t.toState),q.set(s,o),o.size>1&&d(e,`events[${a}]`,"concurrent_incompatible_transitions","The same entity state has multiple incompatible successor states.")});let j=new Map(n.records.flatMap(t=>t.recordType==="authority_grant"?[[t.id,t]]:[])),v=(t,a,s,o,r)=>{if(t.level!=="delegate"||!t.grantId)return;let g=j.get(t.grantId);if(!g){d(e,r,"invalid_authority_grant","Delegated authority references a missing grant.");return}(g.granteeId!==a||g.level!=="delegate")&&d(e,r,"authority_grantee_mismatch","The grant does not authorize this participant as a delegate.");let k=Date.parse(s);(k<Date.parse(g.startsAt)||g.endsAt&&k>Date.parse(g.endsAt)||g.revokedAt&&k>=Date.parse(g.revokedAt))&&d(e,r,"inactive_authority_grant","The delegated authority grant was not active at this time."),g.subjectIds.length&&o.length&&!o.every(Q=>g.subjectIds.includes(Q))&&d(e,r,"authority_scope_mismatch","The delegated action exceeds the grant subject scope.")};for(let t of n.records)t.recordType==="decision"&&v(t.authority,t.acceptedById,t.createdAt,t.subjects.map(a=>a.subjectId),`records:${t.id}.authority`);n.events.forEach((t,a)=>{let s=L.get(`${t.entity.entityType}:${t.entity.entityId}`),o=s&&"subjects"in s?s.subjects.map(r=>r.subjectId):[];v(t.authority,t.participantId,t.createdAt,o,`events[${a}].authority`)}),n.relationships.forEach((t,a)=>{if(!t.authority)return;let s=[t.from,t.to].flatMap(o=>{let r=L.get(`${o.entityType}:${o.entityId}`);return r&&"subjects"in r?r.subjects.map(g=>g.subjectId):[]});v(t.authority,t.participantId,t.createdAt,s,`relationships[${a}].authority`)});for(let t of n.records){if(t.recordType!=="decision")continue;let a=ne.get(t.acceptanceEventId);(!a||a.entity.entityType!=="proposal"||a.entity.entityId!==t.proposalId||a.toState!=="accepted")&&d(e,`records:${t.id}.acceptanceEventId`,"invalid_acceptance_event","A decision must reference the proposal event that explicitly accepted it."),a&&a.participantId!==t.acceptedById&&d(e,`records:${t.id}.acceptedById`,"acceptor_mismatch","Decision acceptor must match the acceptance event participant."),L.has(`proposal:${t.proposalId}`)||d(e,`records:${t.id}.proposalId`,"missing_proposal","Accepted decisions must retain their proposal."),t.state==="superseded"&&(n.relationships.some(o=>o.relationshipType==="supersedes"&&o.to.entityType==="decision"&&o.to.entityId===t.id)||d(e,`records:${t.id}.state`,"missing_successor","Superseded decisions require an explicit successor relationship.")),t.state==="revoked"&&(n.events.some(o=>o.entity.entityType==="decision"&&o.entity.entityId===t.id&&o.toState==="revoked"&&!!o.reason?.trim())||d(e,`records:${t.id}.state`,"missing_revocation_event","Revoked decisions require an authorized event with a reason."))}for(let t of n.records){if(t.recordType!=="proposal"||t.state!=="accepted")continue;n.records.some(s=>s.recordType==="decision"&&s.proposalId===t.id)||d(e,`records:${t.id}.state`,"accepted_proposal_without_decision","Every accepted proposal must produce an immutable decision.")}return Re(e)}var qe=["f5258a13","31ffc15e","3eae3a70","c185e614","33930045","55e04c59","f3bb881b","f8a55928","eac95a7d","e402bdc2","2854624b","cf28ad45","6a494fab","987e901b","ad7293aa","dd1d5d77","14c429d6","48494ad3","d6bbe932","e8b94260","f56fa283","7f1f6cb3","f239f4ac","bd671e61","dbe032ec","c0808b95"];function K(n){return n!==null&&typeof n=="object"&&!Array.isArray(n)?n:null}function A(n,e=0){return new Date(Number.isFinite(n)?n:e).toISOString()}function he(...n){return n.find(e=>!!e?.trim())?.trim()}function _(n,e,i,m){let I=Math.max(0,Math.min(Math.floor(m),0xffffffffffff)).toString(16).padStart(12,"0"),y=Me("sha256").update(`${n}\0${e}\0${i}`).digest("hex"),z=(Number.parseInt(y[3],16)&3|8).toString(16);return`${I.slice(0,8)}-${I.slice(8)}-7${y.slice(0,3)}-${z}${y.slice(4,7)}-${y.slice(7,19)}`}async function ae(n,e){try{return JSON.parse(await Le(n,"utf8"))}catch(i){return e.push({severity:"warning",code:"source_unavailable",source:n,message:i instanceof Error?i.message:String(i)}),null}}function Oe(n){let e=K(n);if(!e)return 0;let i=0,m=f=>{let I=K(f);if(!I){i+=1;return}for(let y of Object.values(I))m(y)};for(let f of Object.values(e))m(f);return i}function Ne(n){let e={};for(let i of n)e[i.recordType]=(e[i.recordType]??0)+1;return e}async function Ve(n){let e=[],i=await Be(n.projectRoot).catch(()=>n.projectRoot),m=X(i,".popmelt"),f=await ae(X(m,"threads.json"),e),I=await ae(X(m,"model.json"),e),y=K(f),z=K(y?.threads)??{},S=Object.entries(z).map(([c,p])=>({key:c,value:K(p)})).filter(c=>!!c.value),u=X(m,"decisions"),ne=await Pe(u).catch(()=>[]),L=[];for(let c of ne.filter(p=>p.endsWith(".json")).sort()){let p=K(await ae(X(u,c),e));p&&L.push({file:c,value:p})}let q=S.flatMap(({value:c})=>[c.createdAt,c.updatedAt]).filter(c=>typeof c=="number"&&Number.isFinite(c)),j=q.length?Math.min(...q):0,v=n.projectKey??i;n.projectKey||e.push({severity:"info",code:"path_derived_project_identity",message:"Canonical project identity is stable for this path; pass projectKey to preserve it across moves."});let t=_(v,"project",v,j),a=_(v,"participant","legacy-owner",j),s=_(v,"participant","legacy-agent",j),o=_(v,"subject","project",j),r=A(Math.max(j,...q)),g=[],k=[],Q=new Map,W=new Map,ce=new Map(L.map(c=>[c.value.id??c.file.replace(/^d-|\.json$/g,""),c.value])),ie=new Map,Y=(c,p,l,b,R)=>{let C=Q.get(l);if(C)return C;let P=_(v,"artifact",c,b);return k.push({id:P,kind:p,mediaType:R,location:l,availability:"available"}),Q.set(l,P),P};for(let{file:c,value:p}of L){let l=p.id??c.replace(/^d-|\.json$/g,""),b=p.createdAt??j,R=[Y(`${l}:envelope`,"other",`.popmelt/decisions/${c}`,b,"application/json")];p.screenshotPath&&R.push(Y(`${l}:screenshot`,"screenshot",`.popmelt/${p.screenshotPath.replace(/^\.popmelt\//,"")}`,b,p.screenshotPath.endsWith(".png")?"image/png":"image/webp"));for(let[C,P]of(p.pastedImagePaths??[]).entries())R.push(Y(`${l}:image:${C}`,"image",P,b));ie.set(l,R)}let M=(c,p,l)=>({id:c,schemaVersion:1,projectId:t,createdAt:r,participantId:p,sourceRefs:l}),Z=(c,p)=>{g.push(p);let l=W.get(c)??[];l.push(p.id),W.set(c,l)},ve=[{...M(a,a,[]),recordType:"participant",kind:"human",displayName:"Legacy project owner",status:"active"},{...M(s,s,[]),recordType:"participant",kind:"ai",displayName:"Legacy coding agent",status:"active"}];g.push(...ve),g.push({...M(o,a,[]),recordType:"subject",subjectType:"project",label:De(process.cwd(),i)||i,aliases:[],locators:[{id:_(v,"locator",i,j),kind:"project_root",value:i,status:"current",validFrom:A(j),sourceRefs:[]}]});let de=new Map,pe=(c,p)=>{let l=de.get(c);if(l)return l;let b=_(v,"subject",c,p),R={...M(b,a,[{kind:"external",id:c}]),createdAt:A(p),recordType:"subject",subjectType:"element",label:c,aliases:[],locators:[{id:_(v,"locator",c,p),kind:"dom_selector",value:c,status:"current",validFrom:A(p),sourceRefs:[{kind:"external",id:c}]}]};return g.push(R),de.set(c,b),b};for(let{key:c,value:p}of S){let l=p.id??c,b=p.createdAt??j,R=_(v,"thread",l,b),C={kind:"thread",id:l},P=[],H=[],ue=Array.isArray(p.messages)?p.messages:[],O,se,me=0;ue.forEach((h,N)=>{let T=h.timestamp??b,B=_(v,"artifact",`${l}:message:${N}`,T);if(P.push(B),k.push({id:B,kind:"message",mediaType:"application/json",location:`.popmelt/threads.json#/threads/${l}/messages/${N}`,availability:"available"}),Q.set(`.popmelt/threads.json#/threads/${l}/messages/${N}`,B),h.screenshotPath&&Y(`${l}:message:${N}:screenshot`,"screenshot",h.screenshotPath,T),h.role==="human"){O=h;let E=h.feedbackSummary??h.replyToQuestion;if(E?.trim()){let w=_(v,"observation",`${l}:${N}`,T),U=p.elementIdentifiers??[],te={...M(w,a,[C,{kind:"message",id:B}]),createdAt:A(T),recordType:"observation",state:"open",statement:E,captureContext:{subjectIds:U.map(G=>pe(G,b)),artifactIds:[B]},resolvedByIds:[]};Z(l,te),se=w,H.push({entityType:"observation",entityId:w})}return}if(h.role!=="assistant")return;let V=h.jobId??`${l}:${N}`,F=_(v,"iteration",V,T),J=ce.get(V),_e=h.cancelled?"cancelled":h.error?"failed":h.question?"question_asked":(h.resolutions?.length??0)>0?"completed":"no_change",je={...M(F,s,[C,{kind:"message",id:B},...(ie.get(V)??[]).map(E=>({kind:"artifact",id:E}))]),createdAt:A(T),recordType:"iteration",threadIds:[R],startedAt:A(O?.timestamp,T),completedAt:A(T),requestSummary:he(O?.feedbackSummary,O?.replyToQuestion)??"[legacy request unavailable]",responseSummary:h.question??h.error??h.responseText?.slice(0,1e3),outcome:_e,execution:{provider:h.provider??J?.provider,model:h.model??J?.model,sessionId:h.sessionId??J?.sessionId},artifactIds:[B,...ie.get(V)??[]]};Z(l,je),H.push({entityType:"iteration",entityId:F});let oe=h.resolutions??J?.resolutions??[];for(let[E,w]of oe.entries()){if(w.status!=="resolved"||!w.summary?.trim())continue;let U=p.elementIdentifiers??[],te=(U.length?U:[i]).map(ge=>({subjectId:ge===i?o:pe(ge,b),role:"governed"})),G=_(v,"proposal",`${V}:${w.annotationId??"resolution"}:${E}`,T),Te={...M(G,s,[C,{kind:"iteration",id:F}]),createdAt:A(T),recordType:"proposal",state:"pending",claim:w.summary,subjects:te,subjectSemantics:te.length>1?"Legacy thread grouped these selected elements; independent scope requires owner review.":void 0,origin:{mode:"inferred",sourceText:he(O?.feedbackSummary,O?.replyToQuestion,w.summary),iterationId:F,inferredById:s}};Z(l,Te),H.push({entityType:"proposal",entityId:G}),e.push({severity:"warning",code:"acceptance_unresolved",source:l,message:`Proposal ${G} remains pending; legacy resolved status proves an outcome, not explicit acceptance.`})}if(oe.some(E=>E.status==="resolved")||J?.gitDiff){let E=_(v,"implementation",V,T),w={...M(E,s,[C,{kind:"iteration",id:F}]),createdAt:A(T),recordType:"implementation_attempt",state:"completed",iterationIds:[F],coverageClaims:[],summary:oe.map(U=>U.summary).filter(Boolean).join(" ")||"Legacy implementation outcome.",artifactIds:[]};Z(l,w),H.push({entityType:"implementation_attempt",entityId:E}),me+=1}se&&(se=void 0)});let fe=ue.at(-1),be={...M(R,a,[C]),createdAt:A(b),recordType:"thread",state:fe?.question?"open":"resolved",messageArtifactIds:P,outcome:fe?.question?"question_unresolved":me?"implementation_only":"no_outcome",resultRefs:H};g.push(be),W.set(l,[R,...W.get(l)??[]])}let ee=Oe(I);ee&&e.push({severity:"warning",code:"model_entries_deferred",source:".popmelt/model.json",message:`${ee} model values were not promoted because their accepted decision provenance is unresolved.`});let le={manifest:{formatVersion:1,projectId:t,createdAt:A(j),updatedAt:r,features:["authority","subjects","implementations","eval_specs","portable_artifacts","bounded_retrieval"],writer:{name:"@popmelt.com/core legacy importer",version:n.writerVersion??"0.8.4-dev"}},records:g,events:[],relationships:[],artifacts:k,tombstones:[]},Ie=ye(le),$e=(n.proofCaseIds??qe).map(c=>({legacyId:c,threadFound:S.some(({key:p,value:l})=>(l.id??p)===c),decisionEnvelopeFound:ce.has(c),recordIds:W.get(c)??[]}));return{bundle:le,report:{projectRoot:i,source:{threads:S.length,messages:S.reduce((c,p)=>c+(p.value.messages?.length??0),0),decisionEnvelopes:L.length,modelEntries:ee,artifactsReferenced:k.length},imported:Ne(g),unresolvedAcceptance:e.filter(c=>c.code==="acceptance_unresolved").length,deferredModelEntries:ee,proofCases:$e,issues:e,schemaIssues:Ie.issues}}}export{Ve as importLegacyProject,_ as legacyUuidV7};
@@ -164,6 +164,37 @@ type EvidenceRecord = Provenance & {
164
164
  stance?: ParticipantStance;
165
165
  artifactIds: MemoryId[];
166
166
  };
167
+ /**
168
+ * An advisory explanation is learned, revisable shared understanding. It can
169
+ * guide future work, but it is deliberately distinct from accepted product
170
+ * truth (`decision`).
171
+ */
172
+ type AdvisoryExplanationKind = 'intention' | 'principle' | 'pattern';
173
+ type AdvisoryExplanationState = 'emerging' | 'testing' | 'grounded' | 'challenged' | 'retired';
174
+ type AdvisoryExplanationScope = {
175
+ kind: 'project' | 'route' | 'component' | 'selector' | 'file';
176
+ values: string[];
177
+ };
178
+ type AdvisoryConcreteBinding = {
179
+ id: string;
180
+ modelPath: string;
181
+ value: JsonValue;
182
+ createdAt: Timestamp;
183
+ updatedAt: Timestamp;
184
+ };
185
+ type AdvisoryExplanationRecord = Provenance & {
186
+ recordType: 'advisory_explanation';
187
+ kind: AdvisoryExplanationKind;
188
+ state: AdvisoryExplanationState;
189
+ statement: string;
190
+ rationale: string;
191
+ scope: AdvisoryExplanationScope;
192
+ subjectIds: MemoryId[];
193
+ evidenceIds: MemoryId[];
194
+ concreteBindings: AdvisoryConcreteBinding[];
195
+ supersededById?: MemoryId;
196
+ updatedAt: Timestamp;
197
+ };
167
198
  type CoverageClaim = {
168
199
  decisionId: MemoryId;
169
200
  coverage: 'partial' | 'full';
@@ -305,13 +336,13 @@ type ModelProjectionRecord = Provenance & {
305
336
  status: 'unprojected' | 'partially_projected' | 'projected' | 'stale';
306
337
  }>;
307
338
  };
308
- type EntityType = 'participant' | 'authority_grant' | 'subject' | 'observation' | 'proposal' | 'decision' | 'thread' | 'iteration' | 'evidence' | 'implementation_attempt' | 'eval_spec' | 'verification_attempt' | 'model_entry' | 'model_projection' | 'freshness_signal';
339
+ type EntityType = 'participant' | 'authority_grant' | 'subject' | 'observation' | 'proposal' | 'decision' | 'thread' | 'iteration' | 'evidence' | 'advisory_explanation' | 'implementation_attempt' | 'eval_spec' | 'verification_attempt' | 'model_entry' | 'model_projection' | 'freshness_signal';
309
340
  type MemoryObjectType = EntityType | 'relationship' | 'lifecycle_event' | 'artifact';
310
341
  type EntityReference = {
311
342
  entityType: EntityType;
312
343
  entityId: MemoryId;
313
344
  };
314
- type RelationshipType = 'supports' | 'contradicts' | 'supersedes' | 'excepts' | 'duplicates' | 'implements' | 'verifies' | 'replaces' | 'derived_from';
345
+ type RelationshipType = 'supports' | 'contradicts' | 'supersedes' | 'excepts' | 'duplicates' | 'implements' | 'verifies' | 'replaces' | 'derived_from' | 'operationalizes' | 'refines' | 'instantiates';
315
346
  type RelationshipRecord = Provenance & {
316
347
  recordType: 'relationship';
317
348
  relationshipType: RelationshipType;
@@ -374,8 +405,8 @@ type Tombstone = {
374
405
  erasureLevel: 'content' | 'content_and_evidence' | 'full_where_permitted';
375
406
  invalidates: EntityReference[];
376
407
  };
377
- type CanonicalRecord = ParticipantRecord | AuthorityGrantRecord | SubjectRecord | ObservationRecord | ProposalRecord | DecisionRecord | ThreadRecord | IterationRecord | EvidenceRecord | ImplementationAttemptRecord | EvalSpecRecord | VerificationAttemptRecord | ModelEntryRecord | ModelProjectionRecord | FreshnessSignalRecord;
378
- type MemoryFeature = 'authority' | 'subjects' | 'decisions' | 'implementations' | 'verification' | 'eval_specs' | 'model_projection' | 'freshness' | 'portable_artifacts' | 'bounded_retrieval';
408
+ type CanonicalRecord = ParticipantRecord | AuthorityGrantRecord | SubjectRecord | ObservationRecord | ProposalRecord | DecisionRecord | ThreadRecord | IterationRecord | EvidenceRecord | AdvisoryExplanationRecord | ImplementationAttemptRecord | EvalSpecRecord | VerificationAttemptRecord | ModelEntryRecord | ModelProjectionRecord | FreshnessSignalRecord;
409
+ type MemoryFeature = 'authority' | 'subjects' | 'decisions' | 'advisory_explanations' | 'implementations' | 'verification' | 'eval_specs' | 'model_projection' | 'freshness' | 'portable_artifacts' | 'bounded_retrieval';
379
410
  type ProjectMemoryManifest = {
380
411
  formatVersion: MemoryFormatVersion;
381
412
  projectId: MemoryId;
@@ -567,6 +598,8 @@ type OwnerReviewPlanResult = {
567
598
 
568
599
  type MemoryJournalMutation = {
569
600
  records: CanonicalRecord[];
601
+ /** Targeted replacement for revisable advisory records; other truth stays event-driven. */
602
+ recordReplacements?: CanonicalRecord[];
570
603
  events: LifecycleEvent[];
571
604
  relationships: RelationshipRecord[];
572
605
  artifacts: ArtifactManifestEntry[];
@@ -716,7 +749,21 @@ type RetrievalQuery = {
716
749
  };
717
750
  declare function retrieveActionPacket(bundle: ProjectMemoryBundle, query: RetrievalQuery): RetrievalPacket;
718
751
 
752
+ type ImprintExplanationKind = 'intention' | 'principle' | 'pattern';
719
753
  type ImprintExplanationState = 'emerging' | 'testing' | 'grounded' | 'challenged' | 'retired';
754
+ type ImprintScopeKind = 'project' | 'route' | 'component' | 'selector' | 'file';
755
+ type ImprintScope = {
756
+ kind: ImprintScopeKind;
757
+ values: string[];
758
+ };
759
+ type ImprintConcrete = {
760
+ id: string;
761
+ modelPath: string;
762
+ value: unknown;
763
+ createdAt: string;
764
+ updatedAt: string;
765
+ };
766
+ type ImprintRelationType = 'operationalizes' | 'refines' | 'supports' | 'contradicts' | 'excepts' | 'instantiates';
720
767
  type ImprintSummaryKind = 'added' | 'strengthened' | 'refined' | 'challenged' | 'exception' | 'consolidated';
721
768
  type ImprintThreadSummary = {
722
769
  transactionId: string;
@@ -739,6 +786,56 @@ type ImprintThreadSummary = {
739
786
  resolvedAction?: ImprintGroundingAction;
740
787
  };
741
788
  type ImprintGroundingAction = 'confirm' | 'reason_wrong' | 'narrow' | 'exception' | 'edit' | 'dont_learn' | 'undo';
789
+ type ImprintViewEvidence = {
790
+ id: string;
791
+ kind: 'judgment' | 'user_feedback' | 'project_state' | 'other';
792
+ summary: string;
793
+ createdAt: string;
794
+ participantKind: 'human' | 'ai' | 'system' | 'integration' | 'unknown';
795
+ threadId?: string;
796
+ jobId?: string;
797
+ };
798
+ type ImprintViewRelation = {
799
+ id: string;
800
+ type: ImprintRelationType | 'supersedes';
801
+ direction: 'outgoing' | 'incoming';
802
+ explanationId: string;
803
+ statement: string;
804
+ rationale: string;
805
+ };
806
+ type ImprintViewExplanation = {
807
+ id: string;
808
+ kind: ImprintExplanationKind;
809
+ state: ImprintExplanationState;
810
+ statement: string;
811
+ rationale: string;
812
+ scope: ImprintScope;
813
+ createdAt: string;
814
+ updatedAt: string;
815
+ evidenceCount: number;
816
+ recentEvidence: ImprintViewEvidence[];
817
+ concrete: ImprintConcrete[];
818
+ relations: ImprintViewRelation[];
819
+ sourceThreadIds: string[];
820
+ needsGrounding: boolean;
821
+ };
822
+ /** Human-shaped read model derived exclusively from canonical project memory. */
823
+ type ImprintView = {
824
+ head: {
825
+ sequence: number;
826
+ updatedAt: string;
827
+ };
828
+ counts: {
829
+ total: number;
830
+ emerging: number;
831
+ testing: number;
832
+ grounded: number;
833
+ challenged: number;
834
+ retired: number;
835
+ needsGrounding: number;
836
+ };
837
+ explanations: ImprintViewExplanation[];
838
+ };
742
839
 
743
840
  type MemoryReviewReceipt = {
744
841
  status: 'committed' | 'not_ready' | 'rejected';
@@ -923,7 +1020,7 @@ declare class MemoryService {
923
1020
  specs: number;
924
1021
  runs: number;
925
1022
  }>;
926
- /** One-time identity/evidence bridge from the prototype Imprint journal. */
1023
+ /** One-time cutover from the prototype graph into canonical advisory memory. */
927
1024
  migrateImprintSnapshot(): Promise<{
928
1025
  migrated: boolean;
929
1026
  explanations: number;
@@ -952,10 +1049,7 @@ declare class MemoryService {
952
1049
  proposalIds: string[];
953
1050
  headSequence?: number;
954
1051
  }>;
955
- /**
956
- * Mirrors Imprint identity and evidence into the canonical journal without
957
- * promoting advisory explanations into product decisions.
958
- */
1052
+ /** Continuously syncs changed Imprint explanations into canonical advisory memory. */
959
1053
  recordImprintEvidence(input: {
960
1054
  summary: ImprintThreadSummary;
961
1055
  threadId: string;
@@ -963,6 +1057,13 @@ declare class MemoryService {
963
1057
  action?: ImprintGroundingAction;
964
1058
  occurredAt?: string;
965
1059
  }): Promise<void>;
1060
+ /** Reconciles the durable Imprint graph into the human-facing canonical memory view. */
1061
+ syncImprintGraph(): Promise<{
1062
+ status: 'synced' | 'not_ready' | 'no_change';
1063
+ relationships: number;
1064
+ explanations: number;
1065
+ headSequence?: number;
1066
+ }>;
966
1067
  recover(confirmed: boolean): Promise<MemoryJournalLoadResult>;
967
1068
  diagnostics(): Promise<{
968
1069
  status: MemoryServiceStatus;
@@ -973,6 +1074,7 @@ declare class MemoryService {
973
1074
  }>;
974
1075
  getProjectableDecisions(limit?: number): Promise<DecisionRecord[]>;
975
1076
  getCanonicalModelEntries(): Promise<ModelEntryRecord[]>;
1077
+ getImprintView(pendingGroundingExplanationIds?: string[]): Promise<ImprintView>;
976
1078
  getModelView(): Promise<{
977
1079
  decisions: Array<{
978
1080
  id: string;