@popmelt.com/core 0.8.6 → 0.8.8

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';
@@ -185,12 +216,15 @@ type VerificationTarget = {
185
216
  entityType: 'decision' | 'implementation_attempt' | 'model_entry';
186
217
  entityId: MemoryId;
187
218
  };
219
+ /** @deprecated Retained only so existing memory journals remain readable. */
188
220
  type EvalSpecState = 'draft' | 'active' | 'retired';
221
+ /** @deprecated Retained only so existing memory journals remain readable. */
189
222
  type EvalDependency = {
190
223
  kind: 'model_path' | 'source_file' | 'route' | 'subject';
191
224
  value: string;
192
225
  subjectId?: MemoryId;
193
226
  };
227
+ /** @deprecated Retained only so existing memory journals remain readable. */
194
228
  type EvalScenario = {
195
229
  id: string;
196
230
  label?: string;
@@ -213,6 +247,7 @@ type EvalScenario = {
213
247
  value?: string;
214
248
  }>;
215
249
  };
250
+ /** @deprecated Retained only so existing memory journals remain readable. */
216
251
  type EvalSpecRecord = Provenance & {
217
252
  recordType: 'eval_spec';
218
253
  state: EvalSpecState;
@@ -252,7 +287,7 @@ type VerificationAttemptRecord = Provenance & {
252
287
  targets: VerificationTarget[];
253
288
  summary?: string;
254
289
  evidenceIds: MemoryId[];
255
- /** Compact presentation data for an eval run; raw output remains an artifact/thread detail. */
290
+ /** @deprecated Historical presentation data retained for journal compatibility. */
256
291
  evalRun?: {
257
292
  id: string;
258
293
  threadId?: string;
@@ -305,13 +340,13 @@ type ModelProjectionRecord = Provenance & {
305
340
  status: 'unprojected' | 'partially_projected' | 'projected' | 'stale';
306
341
  }>;
307
342
  };
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';
343
+ 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
344
  type MemoryObjectType = EntityType | 'relationship' | 'lifecycle_event' | 'artifact';
310
345
  type EntityReference = {
311
346
  entityType: EntityType;
312
347
  entityId: MemoryId;
313
348
  };
314
- type RelationshipType = 'supports' | 'contradicts' | 'supersedes' | 'excepts' | 'duplicates' | 'implements' | 'verifies' | 'replaces' | 'derived_from';
349
+ type RelationshipType = 'supports' | 'contradicts' | 'supersedes' | 'excepts' | 'duplicates' | 'implements' | 'verifies' | 'replaces' | 'derived_from' | 'operationalizes' | 'refines' | 'instantiates';
315
350
  type RelationshipRecord = Provenance & {
316
351
  recordType: 'relationship';
317
352
  relationshipType: RelationshipType;
@@ -374,8 +409,8 @@ type Tombstone = {
374
409
  erasureLevel: 'content' | 'content_and_evidence' | 'full_where_permitted';
375
410
  invalidates: EntityReference[];
376
411
  };
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';
412
+ type CanonicalRecord = ParticipantRecord | AuthorityGrantRecord | SubjectRecord | ObservationRecord | ProposalRecord | DecisionRecord | ThreadRecord | IterationRecord | EvidenceRecord | AdvisoryExplanationRecord | ImplementationAttemptRecord | EvalSpecRecord | VerificationAttemptRecord | ModelEntryRecord | ModelProjectionRecord | FreshnessSignalRecord;
413
+ type MemoryFeature = 'authority' | 'subjects' | 'decisions' | 'advisory_explanations' | 'implementations' | 'verification' | 'eval_specs' | 'model_projection' | 'freshness' | 'portable_artifacts' | 'bounded_retrieval';
379
414
  type ProjectMemoryManifest = {
380
415
  formatVersion: MemoryFormatVersion;
381
416
  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","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';
@@ -185,12 +216,15 @@ type VerificationTarget = {
185
216
  entityType: 'decision' | 'implementation_attempt' | 'model_entry';
186
217
  entityId: MemoryId;
187
218
  };
219
+ /** @deprecated Retained only so existing memory journals remain readable. */
188
220
  type EvalSpecState = 'draft' | 'active' | 'retired';
221
+ /** @deprecated Retained only so existing memory journals remain readable. */
189
222
  type EvalDependency = {
190
223
  kind: 'model_path' | 'source_file' | 'route' | 'subject';
191
224
  value: string;
192
225
  subjectId?: MemoryId;
193
226
  };
227
+ /** @deprecated Retained only so existing memory journals remain readable. */
194
228
  type EvalScenario = {
195
229
  id: string;
196
230
  label?: string;
@@ -213,6 +247,7 @@ type EvalScenario = {
213
247
  value?: string;
214
248
  }>;
215
249
  };
250
+ /** @deprecated Retained only so existing memory journals remain readable. */
216
251
  type EvalSpecRecord = Provenance & {
217
252
  recordType: 'eval_spec';
218
253
  state: EvalSpecState;
@@ -252,7 +287,7 @@ type VerificationAttemptRecord = Provenance & {
252
287
  targets: VerificationTarget[];
253
288
  summary?: string;
254
289
  evidenceIds: MemoryId[];
255
- /** Compact presentation data for an eval run; raw output remains an artifact/thread detail. */
290
+ /** @deprecated Historical presentation data retained for journal compatibility. */
256
291
  evalRun?: {
257
292
  id: string;
258
293
  threadId?: string;
@@ -305,13 +340,13 @@ type ModelProjectionRecord = Provenance & {
305
340
  status: 'unprojected' | 'partially_projected' | 'projected' | 'stale';
306
341
  }>;
307
342
  };
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';
343
+ 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
344
  type MemoryObjectType = EntityType | 'relationship' | 'lifecycle_event' | 'artifact';
310
345
  type EntityReference = {
311
346
  entityType: EntityType;
312
347
  entityId: MemoryId;
313
348
  };
314
- type RelationshipType = 'supports' | 'contradicts' | 'supersedes' | 'excepts' | 'duplicates' | 'implements' | 'verifies' | 'replaces' | 'derived_from';
349
+ type RelationshipType = 'supports' | 'contradicts' | 'supersedes' | 'excepts' | 'duplicates' | 'implements' | 'verifies' | 'replaces' | 'derived_from' | 'operationalizes' | 'refines' | 'instantiates';
315
350
  type RelationshipRecord = Provenance & {
316
351
  recordType: 'relationship';
317
352
  relationshipType: RelationshipType;
@@ -374,8 +409,8 @@ type Tombstone = {
374
409
  erasureLevel: 'content' | 'content_and_evidence' | 'full_where_permitted';
375
410
  invalidates: EntityReference[];
376
411
  };
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';
412
+ type CanonicalRecord = ParticipantRecord | AuthorityGrantRecord | SubjectRecord | ObservationRecord | ProposalRecord | DecisionRecord | ThreadRecord | IterationRecord | EvidenceRecord | AdvisoryExplanationRecord | ImplementationAttemptRecord | EvalSpecRecord | VerificationAttemptRecord | ModelEntryRecord | ModelProjectionRecord | FreshnessSignalRecord;
413
+ type MemoryFeature = 'authority' | 'subjects' | 'decisions' | 'advisory_explanations' | 'implementations' | 'verification' | 'eval_specs' | 'model_projection' | 'freshness' | 'portable_artifacts' | 'bounded_retrieval';
379
414
  type ProjectMemoryManifest = {
380
415
  formatVersion: MemoryFormatVersion;
381
416
  projectId: MemoryId;
@@ -450,15 +485,6 @@ type RetrievalPacket = {
450
485
  value: JsonValue;
451
486
  decisionIds: MemoryId[];
452
487
  }>;
453
- evalSpecs: Array<{
454
- id: MemoryId;
455
- legacyId: string;
456
- state: EvalSpecState;
457
- title: string;
458
- assertionCount: number;
459
- decisionIds: MemoryId[];
460
- expansionRef: SourceReference;
461
- }>;
462
488
  decisions: RetrievalDecision[];
463
489
  conflicts: RetrievalConflict[];
464
490
  uncertainties: RetrievalUncertainty[];
@@ -567,6 +593,8 @@ type OwnerReviewPlanResult = {
567
593
 
568
594
  type MemoryJournalMutation = {
569
595
  records: CanonicalRecord[];
596
+ /** Targeted replacement for revisable advisory records; other truth stays event-driven. */
597
+ recordReplacements?: CanonicalRecord[];
570
598
  events: LifecycleEvent[];
571
599
  relationships: RelationshipRecord[];
572
600
  artifacts: ArtifactManifestEntry[];
@@ -716,7 +744,21 @@ type RetrievalQuery = {
716
744
  };
717
745
  declare function retrieveActionPacket(bundle: ProjectMemoryBundle, query: RetrievalQuery): RetrievalPacket;
718
746
 
747
+ type ImprintExplanationKind = 'intention' | 'principle' | 'pattern';
719
748
  type ImprintExplanationState = 'emerging' | 'testing' | 'grounded' | 'challenged' | 'retired';
749
+ type ImprintScopeKind = 'project' | 'route' | 'component' | 'selector' | 'file';
750
+ type ImprintScope = {
751
+ kind: ImprintScopeKind;
752
+ values: string[];
753
+ };
754
+ type ImprintConcrete = {
755
+ id: string;
756
+ modelPath: string;
757
+ value: unknown;
758
+ createdAt: string;
759
+ updatedAt: string;
760
+ };
761
+ type ImprintRelationType = 'operationalizes' | 'refines' | 'supports' | 'contradicts' | 'excepts' | 'instantiates' | 'supersedes';
720
762
  type ImprintSummaryKind = 'added' | 'strengthened' | 'refined' | 'challenged' | 'exception' | 'consolidated';
721
763
  type ImprintThreadSummary = {
722
764
  transactionId: string;
@@ -739,6 +781,56 @@ type ImprintThreadSummary = {
739
781
  resolvedAction?: ImprintGroundingAction;
740
782
  };
741
783
  type ImprintGroundingAction = 'confirm' | 'reason_wrong' | 'narrow' | 'exception' | 'edit' | 'dont_learn' | 'undo';
784
+ type ImprintViewEvidence = {
785
+ id: string;
786
+ kind: 'judgment' | 'user_feedback' | 'project_state' | 'other';
787
+ summary: string;
788
+ createdAt: string;
789
+ participantKind: 'human' | 'ai' | 'system' | 'integration' | 'unknown';
790
+ threadId?: string;
791
+ jobId?: string;
792
+ };
793
+ type ImprintViewRelation = {
794
+ id: string;
795
+ type: ImprintRelationType | 'supersedes';
796
+ direction: 'outgoing' | 'incoming';
797
+ explanationId: string;
798
+ statement: string;
799
+ rationale: string;
800
+ };
801
+ type ImprintViewExplanation = {
802
+ id: string;
803
+ kind: ImprintExplanationKind;
804
+ state: ImprintExplanationState;
805
+ statement: string;
806
+ rationale: string;
807
+ scope: ImprintScope;
808
+ createdAt: string;
809
+ updatedAt: string;
810
+ evidenceCount: number;
811
+ recentEvidence: ImprintViewEvidence[];
812
+ concrete: ImprintConcrete[];
813
+ relations: ImprintViewRelation[];
814
+ sourceThreadIds: string[];
815
+ needsGrounding: boolean;
816
+ };
817
+ /** Human-shaped read model derived exclusively from canonical project memory. */
818
+ type ImprintView = {
819
+ head: {
820
+ sequence: number;
821
+ updatedAt: string;
822
+ };
823
+ counts: {
824
+ total: number;
825
+ emerging: number;
826
+ testing: number;
827
+ grounded: number;
828
+ challenged: number;
829
+ retired: number;
830
+ needsGrounding: number;
831
+ };
832
+ explanations: ImprintViewExplanation[];
833
+ };
742
834
 
743
835
  type MemoryReviewReceipt = {
744
836
  status: 'committed' | 'not_ready' | 'rejected';
@@ -749,58 +841,6 @@ type MemoryReviewReceipt = {
749
841
  headSequence?: number;
750
842
  };
751
843
 
752
- type EvalCaseStatus = 'pending' | 'approved' | 'rejected';
753
- type EvalCase = {
754
- id: string;
755
- title: string;
756
- status: EvalCaseStatus;
757
- category: 'component' | 'layout' | 'copy' | 'interaction' | 'visual' | 'workflow';
758
- prompt: string;
759
- assertions: string[];
760
- rationale: string;
761
- sourceDecisionIds: string[];
762
- sourceThreadIds: string[];
763
- dependencies?: EvalDependency[];
764
- scenarios?: EvalScenario[];
765
- };
766
- type EvalRunStatus = 'pass' | 'fail' | 'needs_review';
767
- type EvalAssertionRunResult = {
768
- assertion: string;
769
- status: EvalRunStatus;
770
- summary: string;
771
- evidence: string[];
772
- };
773
- type EvalRunScope = {
774
- type: 'current_page';
775
- url: string;
776
- viewport: {
777
- width: number;
778
- height: number;
779
- };
780
- };
781
- type EvalRun = {
782
- id: string;
783
- evalId: string;
784
- threadId?: string;
785
- status: EvalRunStatus;
786
- createdAt: number;
787
- completedAt: number;
788
- durationMs: number;
789
- scope: EvalRunScope;
790
- summary: string;
791
- assertionResults: EvalAssertionRunResult[];
792
- tooling: {
793
- chromeDevtools: 'available' | 'unavailable' | 'unknown';
794
- evidenceTypes: string[];
795
- };
796
- provider?: string;
797
- model?: string;
798
- screenshotPath?: string;
799
- codeFingerprint?: string;
800
- scopeFingerprint?: string;
801
- rawResponse?: string;
802
- };
803
-
804
844
  type ConversationalReviewIntent = {
805
845
  proposalId: string;
806
846
  action: 'accept' | 'edit_and_accept' | 'reject' | 'defer';
@@ -896,12 +936,6 @@ type MemoryContextResult = {
896
936
  actionPacket: ReturnType<typeof retrieveActionPacket>;
897
937
  reviewSelection: ReturnType<typeof selectContextualReviewPackets>;
898
938
  };
899
- type JournalEvalCase = EvalCase & {
900
- canonicalSpecId: string;
901
- verificationState: 'draft' | 'unverified' | 'passing' | 'failing' | 'needs_review' | 'stale' | 'retired';
902
- verifiedScopeFingerprint?: string;
903
- verificationAttemptId?: string;
904
- };
905
939
  declare class MemoryService {
906
940
  private readonly projectRoot;
907
941
  private readonly store;
@@ -917,13 +951,7 @@ declare class MemoryService {
917
951
  writerVersion?: string;
918
952
  }): Promise<MemoryServiceStatus>;
919
953
  analyzeLegacy(options?: Omit<LegacyImportOptions, 'projectRoot'>): Promise<LegacyImportReport>;
920
- /** One-time cutover import. Legacy eval files are never read during normal queries. */
921
- migrateLegacyEvals(): Promise<{
922
- migrated: boolean;
923
- specs: number;
924
- runs: number;
925
- }>;
926
- /** One-time identity/evidence bridge from the prototype Imprint journal. */
954
+ /** One-time cutover from the prototype graph into canonical advisory memory. */
927
955
  migrateImprintSnapshot(): Promise<{
928
956
  migrated: boolean;
929
957
  explanations: number;
@@ -952,10 +980,7 @@ declare class MemoryService {
952
980
  proposalIds: string[];
953
981
  headSequence?: number;
954
982
  }>;
955
- /**
956
- * Mirrors Imprint identity and evidence into the canonical journal without
957
- * promoting advisory explanations into product decisions.
958
- */
983
+ /** Continuously syncs changed Imprint explanations into canonical advisory memory. */
959
984
  recordImprintEvidence(input: {
960
985
  summary: ImprintThreadSummary;
961
986
  threadId: string;
@@ -963,6 +988,13 @@ declare class MemoryService {
963
988
  action?: ImprintGroundingAction;
964
989
  occurredAt?: string;
965
990
  }): Promise<void>;
991
+ /** Reconciles the durable Imprint graph into the human-facing canonical memory view. */
992
+ syncImprintGraph(): Promise<{
993
+ status: 'synced' | 'not_ready' | 'no_change';
994
+ relationships: number;
995
+ explanations: number;
996
+ headSequence?: number;
997
+ }>;
966
998
  recover(confirmed: boolean): Promise<MemoryJournalLoadResult>;
967
999
  diagnostics(): Promise<{
968
1000
  status: MemoryServiceStatus;
@@ -973,6 +1005,7 @@ declare class MemoryService {
973
1005
  }>;
974
1006
  getProjectableDecisions(limit?: number): Promise<DecisionRecord[]>;
975
1007
  getCanonicalModelEntries(): Promise<ModelEntryRecord[]>;
1008
+ getImprintView(pendingGroundingExplanationIds?: string[]): Promise<ImprintView>;
976
1009
  getModelView(): Promise<{
977
1010
  decisions: Array<{
978
1011
  id: string;
@@ -988,7 +1021,6 @@ declare class MemoryService {
988
1021
  decisionIds: string[];
989
1022
  }>;
990
1023
  }>;
991
- getEvalDependenciesForDecisions(decisionIds: string[]): Promise<EvalDependency[]>;
992
1024
  recordDirectModelMutation(input: {
993
1025
  key: string;
994
1026
  value: JsonValue;
@@ -997,24 +1029,6 @@ declare class MemoryService {
997
1029
  decisionId: string;
998
1030
  entryId: string;
999
1031
  }>;
1000
- syncEvalSpecs(cases: EvalCase[]): Promise<JournalEvalCase[]>;
1001
- getJournalEvalCases(): Promise<JournalEvalCase[]>;
1002
- findJournalEvalCase(id: string): Promise<JournalEvalCase | null>;
1003
- updateJournalEvalCase(id: string, patch: Partial<Pick<EvalCase, 'status' | 'title' | 'assertions'>>): Promise<JournalEvalCase | null>;
1004
- getJournalEvalRuns(): Promise<EvalRun[]>;
1005
- recordEvalVerification(evalCase: EvalCase, run: EvalRun): Promise<void>;
1006
- syncLegacyEvalRuns(cases: EvalCase[], runs: EvalRun[]): Promise<void>;
1007
- markEvalVerificationExpired(input: {
1008
- evalSpecId: string;
1009
- verificationAttemptId: string;
1010
- previousFingerprint?: string;
1011
- currentFingerprint?: string;
1012
- }): Promise<void>;
1013
- reconcileEvalCases(cases: EvalCase[]): Promise<{
1014
- valid: EvalCase[];
1015
- discardedIds: string[];
1016
- }>;
1017
- private latestEvalSpec;
1018
1032
  findPendingProposalForLegacyDecision(legacyDecisionId: string): Promise<{
1019
1033
  proposalId: string;
1020
1034
  claim: string;