# Repository API (implementation contract) 当前0.14.0增加只读[3D记忆关联图](memory-graph-3d.md):展示有实际依据的记录、来源、人物和会话关系,后端有界读取,原文按需详情。图不调用模型、不触发回忆或人格更新;旧版QQ恢复与技术修复保留原范围,最终全量、实机与正式加载另验,不预填成功。 ESM exports: JsonStore from core/store.js; MemoryRepository from core/repository.js; schema utilities from core/schema.js. Persistent mutations resolve after durable local commits; reads and the explicitly volatile retrieval caches/diagnostics do not imply a disk write. Returned data are detached copies. Times are epoch ms. Clock may be a function or {now()}. JsonStore(root,{fault?,journalMaxBytes?}): open(), close(), readJson(relativePath,fallback=null), readLines(relativePath), listFiles(prefix=""), availableBytes(), transaction({runId,json={},jsonl={},expectedVersions={},remove=[]}). Both json and jsonl maps replace complete files. remove lists safe relative files to unlink idempotently as part of recovery. expectedVersions checks JSON document versions before preparing WAL. Transaction returns {runId,duplicate}. Fault hook receives (phase,details): after_prepare, before_apply, after_apply, after_commit. A fault after preparation poisons the instance until close/open; recovery rolls the entire prepared transaction forward before readers are allowed. Only safe relative files under the root are accepted, symlinks/junctions are refused. An active process writer lock cannot be taken by a second instance. MemoryRepository({root,config={},clock=Date.now,fault?,semanticPort=null}): - open(), close(). Opening an existing v3 store also sanitizes temporary caches against already recorded explicit revocations and corrects exact assistant C1/nonhuman H1 speakerId===personId relationship placeholders to null. Independent actors, source facts and relationship ownership remain intact; frozen run bytes, candidates and review fingerprints are not rewritten. Unsupported schema preflight still refuses before recovery or sanitation writes. - ingest(input): participant ChatRecord-like input with sourceSessionId/sourceEventId/sourceKind/contentClass/role/text/channelId, optional personId, sourceAt, observedAt, origin. Returns {duplicate,record,eventId,gap?}. Non-dialogue classification is rejected; never infers a person from a session. - validateSourceRefs(refs,{requireOriginal=false}={}): queued read-only structural/stable-source preflight, returning detached refs. Unknown and explicitly revoked sources throw SOURCE_UNKNOWN/SOURCE_REVOKED before identity creation or effect persistence. Empty refs and a first single accepted event are valid; no role, authentication or evidence quorum is imposed. requireOriginal:true checks only the technical prerequisite for actual reassignment and throws SOURCE_UNAVAILABLE when the original was naturally evicted; default validation still permits the stable receipt. - captureHot(input): HotRecord-like input plus optional stable blockIndex, dependencyRefs, dependencyRecordIds, opaque contextGroupId and dependencyScanComplete. Returns {duplicate,record,eventId,gap?}. Structural provenance is extracted from cached JSON and JSON strings before overflow can replace text with host_trace. Explicit supplied dependencies are retained too; the hot event's own top-level sourceRef is not automatically a content dependency. Revoked dependencies and invalidated same-turn process groups are not cached; incomplete known JSON previews or explicitly incomplete scans return a diagnostic gap. Cached content or host_trace source pointer; hot duplicates are keyed by source, kind, and blockIndex (or explicit stable id). Distinct same-kind content blocks from one host event remain distinct. - upsertPerson({personId?,displayName?,aliases?,locale?,timezone?,clues?}): returns identity. - assign({sourceSessionId,sourceEventId,personId,reason?,environmentVersion?}): moves/reprojects the selected original into a relationship partition without creating a second root experience. personId is relationship ownership; assistant role, actual speakerId, source IDs, text and time remain intact. A human user speaker placeholder may follow the recognized person. An assistant may retain null or an independent AI actor ID; associating its original does not turn it into a human statement. Returns {assignment,record}. - listPeople(): identity array. - search(input,{personId?,requestId?}={}): {items:[...record,score,recordType,retrieval],diagnostics?,needsTarget?}. Additive 0.10.0 input modes, time filters, stored associations and optional source diversity are defined below. Public score retains lexical relevance semantics. Explicit cross-person/all queries retain actual subjects; no importance, owner or silence penalty. - forget({ids?,targetPersonId?,before?,reason,action?:"forget"|"correction",replacementIds?},{personId?}={}): returns {revocation,affectedIds} or {needsSelection:true}/{needsTarget:true}. No selector never means delete all. Before any write, 0.13.5 refuses MEMORY_RECORD_AMBIGUOUS when selected or source-dependent records have colliding bare IDs. Legacy dependency/revocation receipts still use bare IDs, so a person-qualified selection alone cannot make destructive revocation safe. Refusal preserves every file; unique IDs retain existing selective source revocation. No stored schema or legacy revokedIds/sourceRecordIds migration is introduced. - introspect({targetPersonId?,section?},{personId?}={}): selected persona/relationship/state data, no administrator ACL implied. - getPersona(), getRuntime(), saveRuntime(state,{expectedVersion?}={}): save returns stored state with incremented version. - patchRuntime(base,next): queued atomic top-level compare-and-swap. Only keys genuinely changed from base to next (excluding version/updatedAt) are applied to the latest stored state. Each changed key must still deeply equal base in current state or VERSION_CONFLICT is raised. Unchanged repository-owned source/consolidation cursors and memory gaps remain intact. Returns the full latest validated RuntimeState; no blanket stale-state merge and no automatic side-effect retry. - getPersonaHistory(), rollbackPersona(version): bounded pre-change persona versions; rollback becomes a new version, and explicit revocation remains effective. History is cleared on explicit forget so it cannot revive removed text. - getPersonState(personId), savePersonState(personId,state,{expectedVersion?}={}). - getContext({personId=null,query?,includeIndexes=false}={}): {persona,identity,impression,interpretations,codes,deepMemories,deepMemoryVersion,state,records,recent,pending,memories,sourceDependencies,memoryIndexes?}. records/recent/pending contain full available ChatRecords with source/channel identity; unknown context reads staging. sourceDependencies:{refs,recordIds} is a conservative provenance superset of eligible personality, relationship and retrieved material, including stored lineage for plain scalar summaries/anchor. buildSnapshot carries this read-only metadata for the adapter to mark temporary runtime-context copies; it is not an authentication, retrieval, attention or personality rule. - getPending({personId?}={}): accepted records referenced by pending IDs, including staging when no person specified. - readSources({eventIds?,sourceRefs?}={}): queued read-only access to still-retained, unrevoked original C1 ChatRecords, detached from storage. Matches the union of exact eventIds and stable sourceSessionId/sourceEventId pairs; empty selectors return []. Does not depend on pending status, infer a subject, reconstruct naturally evicted originals, or revive explicit revocations. Unknown/unavailable selections simply have no returned original. - clearPending(eventIds): marks only the listed events consumed; no other queued messages removed. - prepareConsolidation({personId=null,maxInputChars?}={}): durable run with input:{chat,hot,context}; context excludes duplicated full chat/recent/pending arrays. Oversized cached originals are paged using run.inputSlices and record.fragment:{from,to,total}; committed offsets advance only the fragment actually consumed. inputEndEventId does not pass an incomplete original. No personality sleep is imposed. - getConsolidationRun(runId), listConsolidationRuns({status?}={}): retrieve incomplete durable model work after restart; prepared runs count toward bounded workspace capacity and are never silently discarded. - recordConsolidationAttempt(runId,{candidatePatch,validationError}): queued durable replacement of the latest uncommitted candidatePatch and validationError:{code,message} on a prepared run, returning the detached updated run. This does not validate or commit the candidate, bump document versions, consume hot/source pages, or alter pending queues. Failed/source-revoked work refuses the write; completed work returns RUN_NOT_PREPARED. Workspace capacity remains bounded. Explicit retry can present the retained actual error to the model; no automatic retry, entry deletion or semantic enum mapping occurs. Successful commit or explicit source invalidation clears the uncommitted candidate/error. - applyConsolidation(run,patch): patch may be an array of ValidatedPatchEntry or {entries:[...],evictSourceIds?:[...]}. documentKey allows persona, person::index|codes|impression|pending, global:index|codes|deep. upsert/remove target IDs; persona scalar fields use recordId anchor/axes; persona arrays use facets:, signatures:, habits:, retired:. All fields are structurally validated before writes. Returns {committed:true,duplicate,run}; consumes only run-selected hot records; stale touched versions conflict. evictSourceIds expresses model-selected natural eviction and preserves summaries. - evictSources(ids): natural raw-chat eviction; retained derived memories remain, source availability updates. Pending originals are retained until the chosen receive/wake consumer clears their pending event IDs, so natural storage cleanup cannot silently lose an accepted message. - getCapacity(): logical persistent text/hot text, physical bytes, freeBytes, targets/pressure facts; does not force sleep/forget. - resolveMemoryGaps({sourceSessionId,sourceCursor?,sourceEventId?,updateReceivedCursor?}): after the adapter actually recovers a source, marks only matching cursor/event gaps with resolvedAt. sourceEventId matches pre-admission message:id gaps even when the final host cursor is numeric seq. Optional updateReceivedCursor updates only the received cursor, not an invented durable-write checkpoint. Returns {resolvedIds,version}; historical resolved rows remain bounded diagnostics. - getOutbox(), saveOutbox(records): array replace; bounded completed receipts, unresolved deliveries retained. - saveSnapshot(snapshot), getSnapshots(): bounded request diagnostics. - recordUsage(entry), getUsage(): bounded independent usage diagnostics. - updateConfig(partial): validates and persists config; mode switch retains all source/consolidation cursors. Schema exports: SCHEMA_VERSION, SchemaError, defaultConfig(overrides={}), mergeConfig(base,overrides), validateConfig, validateChat, validateHot, validatePersona, validateMemoryItem, validateDeepMemory, validateDecision, validatePatch, emptyPersona(now), emptyRuntime(now), newId(prefix), sourceKey(ref), countChars. Validators return validated input or throw. They validate structure and executable signals, never personality correctness or evidence thresholds. Optional identityPlan:{action:"new"|"associate"|"unknown",personId?,displayName?,sourceRefs?,reason?} expresses autonomous recognition. Source-dedup receipts persist independently of natural chat eviction. Operational metadata is subject to configured physical reserve/journal capacity; if it cannot safely grow, new redundant memory copies return memory_gap instead of deleting receipts or silently claiming durable acceptance. Adapter source replay/offset checkpoints remain necessary for very long runs. Sources unavailable in host_trace are reported, not fabricated. Local files cannot erase independent host logs. core/source-dependencies.js exports extractSourceDependencies(value)->{refs,recordIds,complete}. It follows named source/record fields and recursively decodes JSON string containers with bounded depth/work; it does not inspect ordinary words or infer a topic. Explicit forget removes dependent H1 copies and related same-turn process copies, invalidates prepared runs/candidates using them, and leaves unrelated C1 untouched. _hot/prepare enforce the same dependency rules as a read guard. Older unannotated process copies and host traces in affected source sessions are conservatively pruned on open/restore; structured cross-session references extend only that temporary-copy cleanup to the affected session. meta.dependencyCleanups retains at most 20 bounded diagnostics and invalidatedHotContextGroups at most 256 temporary context keys. Neither is added to revokedSources. New unrevoked roots, including exactly the same words, remain acceptable. ## Offline maintenance Import core/maintenance.js: validateMemoryRoot(root,{maxBytes?,extensionValidator?}), validateBackup(source,{maxBytes?,extensionValidator?}), createBackup({root,destination,maxBytes?,clock?,fault?,extensionValidator?}), restoreBackup({root,source,maxBytes?,fault?,extensionValidator?}), recoverRestore({root,maxBytes?,fault?,extensionValidator?}). exportMemory aliases createBackup; importMemory aliases restoreBackup. Default read/validation hard cap is 64 MiB. Backup/restore additionally honor the smaller deployment retention.backupMaxBytes (8 MiB initially); maxBytes can tighten but cannot bypass deployment capacity. To intentionally increase capacity, update the deployment config first. Only persona-memory/3 is accepted. No old-format automatic migration exists: unknown versions are preserved and rejected before WAL recovery, without leaving an owned writer lock. Backup requires the service stopped; validates all JSON, known record types and file hashes; refuses links, overlapping source/destination and unmanaged target directories. A backup directory contains manifest.json and data/. Repeated backups retain one fixed destination.previous. Restore copies a validated candidate beside the target, places a persistent maintenance gate and switch journal outside it, then uses two atomic directory renames. Node/Windows has no atomic directory exchange: interrupted switches require recoverRestore, and normal JsonStore.open refuses RESTORE_PENDING rather than initializing an empty replacement. The prior root is retained at root.rollback; only an existing rollback with a matching tool marker can be replaced. An unrelated directory is never recursively removed. Current-root explicit revocations are carried into an older backup candidate and applied before installation; historical pending/submitted outbound messages become unknown and require real host reconciliation. A new machine/root only knows revocations actually present in its imported backup; independent backups elsewhere are not silently erased or globally synchronized. Usage details are rolling diagnostics, not an all-time billing ledger. Repeated requestId within retained rows is deduplicated; native dsh:: usage also keeps a per-session high-water checkpoint beyond row rotation. This assumes adapter replay is in source seq order. Unknown units/rates never become invented currency totals. ## Verification and deployment limits The combined storage-writer verification on 2026-10-25, before the subsequent runtime-key CAS regression, ran: node --test test/storage.test.js test/memory.test.js test/maintenance.test.js Result: 38 passed, 0 failed (7 storage, 23 memory, 8 maintenance; approximately 8.09 seconds). The root's final complete-suite and real-host report supersede this scoped count; it is not a claim that a mock model proves longitudinal personality quality. The follow-up memory suite passed 25/25 after adding patchRuntime and its two exact-interleaving regressions: an actual intervening ingest commit cannot lose its source cursor when a sleep decision is saved; an intervening consolidation commit cannot lose its cursor when wake state is saved; a genuine same-top-level-key conflict still rejects without changing that key. This fixes runtime lock versus direct repository-write races without blanket stale-state merging. After adding readSources and retained uncommitted consolidation feedback, the combined command `node --test test/storage.test.js test/memory.test.js test/maintenance.test.js test/observation-plan.test.js` passed 51/51 (7 storage, 32 memory, 8 maintenance, 4 observation/shape-guide; approximately 9.67 seconds). New cases confirm acknowledged originals remain queryable, natural/explicit disappearance is respected, a rejected candidate does not consume input or become a commit, explicit corrected structure can commit, revoked candidates cannot survive forget or older-backup restore, and diagnostics cannot exceed the workspace capacity. These are isolated local regressions; diagnostic-clone commits are not production personality growth. The H1 provenance follow-up added source-dependencies.test.js and the adapter-owned dsh-process-dependencies.test.js to that command: 62/62 passed, approximately 10.16 seconds. It reproduces the three nested JSON tool-result copies, turn-related reasoning, overflow to host traces, explicit incomplete previews, new-sequence replay, legacy migration, restored backups and unchanged unrelated C1/personality. A static clone of the real phase-05 snapshot was also opened: all three known stale tool results disappeared and were absent from the next prepared run; all 13 checked business files were byte-for-byte unchanged. The cleanup removed 51 legacy temporary process copies across the affected B source session, recorded a diagnostic, and kept the two original revocation source keys unchanged. Production memory was not changed by this clone verification; its next normal open performs the same migration. Meaningful covered cases include a child process exiting between WAL file replacements; stale/live writer locks; transient Windows rename contention without unlinking the live file; version conflicts; stable source and block deduplication; unknown assignment/reassignment; exact hot-prefix consumption; cached-text fragments without advancing past unread input; concurrent new arrivals; user-only pending queues; a nonempty evolution patch creating anchor/axes/facets/signatures/habits, a shared global code, distinct personal codes and relation signatures, subjective interpretation and a soft commitment; natural forgetting preserving summaries; explicit revocation invalidating frozen prepared runs; two mode switches preserving cursors; future schema rejection without rewriting original bytes; gap resolution by real message identity and final seq; native usage replay after detail rotation; bounded rollback; backup hash checks, tamper rejection, capacity, active-lock rejection and interrupted directory-switch recovery. The maintenance tests also restore an older snapshot after newer explicit revocations, retain those revocations and reject replay of a later revoked source absent from the old snapshot. A historical outbound pending/submitted item restores as unknown rather than being blindly sent again. Backup/restore use fixed previous/rollback directories; a directory without a matching managed marker is not removed. Latest adapter source review confirms that inbox trace locators carry both seq and messageId, an agent/inbox/spliced trace selects the exact inserted message before normalization, unread backfill tails continue in bounded 256-event batches, blocked gaps survive later live events, and fork replay excludes seq values below inheritedEventCount. These are code-path findings; actual SDK observations belong in the root's integration evidence. Repository tombstones independently prevent forgotten chat/hot from being reintroduced during source replay. Limits to preserve in product claims: - Only the published persona-memory/3 storage format is implemented. Legacy automatic conversion is not implemented; unknown configuration/persona/runtime schema versions are preserved and refused before WAL replay. The adapter may keep ordinary host chat available while reporting the memory initialization failure. - Retrieval is local word, Chinese-bigram and substring matching, not an embedding or semantic-vector index. The tests establish behavior and attribution, not a measured long-term recall rate. - Finite source receipts, operational metadata, workspaces and backups have explicit capacity. At a safe boundary the core records a gap or refuses an oversized maintenance operation. It cannot guarantee indefinitely lossless history when the host no longer retains a recoverable source. - Resolved gaps retain a resolvedAt timestamp within bounded diagnostic history; their existence does not prove an unavailable host source was recovered. The adapter must call resolveMemoryGaps only after the actual source is successfully processed. - Local file recovery cannot prove external delivery. Provider usage is retained when available; missing usage is unknown and never converted into an invented charge. Directory exchange is two atomic renames plus a durable recovery journal, not one atomic multi-directory operation. - Windows may not support directory fsync through Node. Files are fsynced and replacements are atomic; bounded rename retries handle transient EPERM/EBUSY/EACCES on existing same-directory ordinary-file replacements. This is not an absolute guarantee against every storage device or OS power-loss behavior. ## Final H1 verification boundary (0.1.1) After the isolated clone check above, a normal open of the actual isolated real-model test root performed the same legacy dependency migration. It removed 51 affected temporary copies, retained exactly the two existing revoked source roots and left all 17 checked business files byte-for-byte unchanged. This is not a change to the user desktop memory root. Final complete-suite evidence is 155/155; the earlier scoped counts remain historical. See [real-model validation](real-model-validation.md). ## Capacity accounting and prepared progress (0.2.0) capacityLimits adds per-artifact text/serialized bytes, logical JSON document bytes and persistent instance bytes. Arrays, extra string values, retired entries and bounded persona history count; structural property names are also bounded by serialized bytes. JSONL is bounded per row and by the instance total. A rejected patch does not mutate memory or consume sources. The transaction preflight and its WAL peak are checked separately from the semantic text target. recordConsolidationProgress(runId,{reviewState,candidatePatch?}) persists only a prepared run with bounded finite progress and the uncommitted candidate. It does not advance source cursors, clear H1 or create a commit. Revocation wins over saved progress. Exact limits, local scan costs and real-model unknown-source observations are in [the current report](evolution-and-wake-validation.md). ## Management reads and explicit null scopes (0.3.0) browseMemory({query,scope:"all"|"person"|"global"|"unknown",targetPersonId,recordType,offset,limit}) returns {items,total,offset,nextOffset,revision}; limit is 1..100. It does not silently cap the catalogue at search's 1000 results. Unknown selects only staging, and an unknown person is not created. getMemoryRecord(id, selector={recordKey?,personId?,scope?,recordType?}) returns a uniquely selected retained unrevoked record or null. Detail scope uses the actual row values person/global/staging. Browse, search, timeline and detail rows include read-only recordKey=JSON.stringify([recordType,scope,personId,id]); omitted selector fields are not constraints, while personId:null is explicit. An unqualified or still-ambiguous selection throws MEMORY_RECORD_AMBIGUOUS instead of choosing the first record. Matching source receipts select only their actual archive shards; unrelated archive bodies are not scanned solely for detail lookup. Both are queued read-only methods. forget adds explicit scope unknown/global plus concrete IDs; those scopes reject before-time bulk selection and preserve the old default needsTarget behavior. They use the same dependency/revocation/history cleanup, preserving source roles and preventing revival. Runtime settings update only after repository persistence succeeds. Management ops/management.json contains bounded operator receipts, not personality judgments or an endless audit history. See [management surface](management-ui.md). ## 0.7.0 deep records and consolidation supply global:deep maps to global/deep.json, a versioned document of global-scope DeepMemoryItem records. validateDeepMemory requires MemoryMeta plus title/reference/experience/feltThen/meaningNow and cues/aboutPersonIds/relatedMemoryIds/supersedesIds. The default limits are128 records and100000 string characters; existing per-record, document and instance caps also apply. No count minimum, emotion score, automatic healing, decay or eviction policy is introduced. upsert/remove is selected by the personality through the existing consolidation contract. search, browseMemory(recordType:"deep") and getMemoryRecord include retained deep entries; introspect(section:"deep") returns the module version/items with referenceOnly:true and automaticRecall:false. Owner browsing is not a personality recall event. getContext always supplies shared deep references; includeIndexes:true additionally supplies memoryIndexes:{global,person}. prepareConsolidation and refreshConsolidationContext freeze those versioned ordinary indexes and deep records so the model can read relevant old material via actual context cursors. Legacy prepared inputs remain labelled; unseen context is not interpreted as an empty document. applyConsolidation validates nonempty srcRefs against accepted source identities, role/origin/kind and explicit revocations before committing. Supplied metadata cannot rename an assistant source into a human source. Empty refs are valid for unreferenced subjective interpretations and do not create an evidence quorum. Stable source reuse is not a new independent event. Deep records participate in capacity accounting, browsing, natural source availability, explicit forgetting, backup validation and restore revocation. reviewState may retain a bounded assistantReceipt describing optional material advice. The receipt has no patch authority and does not advance source cursors or the personality's context-read ranges. Optional advice and current/historical evidence are described in [the0.7.0 note](memory-reflection-and-social-identities.md). ### Committed source-dependency receipt (0.7.0) Committed runs retain sourceDependencies:{format:"sha256-identities/1",sourceHashes,recordHashes,complete}; the bounds are8192 source hashes and16384 record hashes. This records actual frozen-input/patch/review provenance without copying original dialogue. Explicit forgetting and open-recovery remove related committed validatedPatch, helper reports and body-bearing diagnostic fields, preserving commitMarker/status/call count and sanitized helper receipt. Legacy or incomplete provenance is conservatively scrubbed after a revocation; unrelated complete run diagnostics remain. Natural source eviction does not invoke this explicit-revocation cleanup. Restore carries current revocations and removes old journal bodies before reuse. A redacted journal is a minimal technical receipt, not the full pre-redaction run view. Retained task material is a source with task session, document ID, SHA and Unicode range. Explicit forgetting of a derived memory referencing it also revokes that task archive through the DSH adapter; another page range cannot reintroduce it. New unrelated tasks and natural source eviction remain separate. Independent host/platform logs and external engineering copies are not claimed erased. ## 0.10.0 Hybrid candidate retrieval and volatile semantic port The field authority is [schema §22](plan/persona/persona-schema.md#22-混合候选检索与可选平台扩展0100); resource defaults and numeric ranges have one executable source, [retrieval-config.js](../core/retrieval-config.js). The core does not read credentials, process environment or networks. - search accepts mode:auto|lexical|hybrid, timeMode:all|current|past|asOf, asOf epoch milliseconds, seedIds, associationDepth and diversity:none|source. Default scope remains person, limit remains5 (technical range0–1000), and mode/timeMode/depth/diversity are auto/all/1/none. lexical disables vector calls; explicitly selected stored associations may still contribute. Empty query without seeds never embeds a query or expands the graph. - setSemanticPort(port|null) serially replaces the provider and clears document/query caches plus provider error state; bounded exposure history is retained. Port: {id,version,dimensions?,embed({texts,purpose:'document'|'query',signal}) -> Promise<{vectors:number[][]}>}. Responses require finite, consistent, nonzero vectors; no string hash is treated as semantics. - prepareRetrievalIndex({scope:'all'|'person'|'global',targetPersonId?,offset=0,limit?}) explicitly embeds one selected document page. No search or startup automatically indexes all documents. partialTexts marks document-prefix embedding; original text is intact. nextOffset/pageComplete describe traversal, while coverage.indexed/eligible/complete describe actual retained coverage when reported. Cached-only or failed pages must not be interpreted as universal coverage. - getRetrievalDiagnostics(), clearRetrievalDiagnostics(), clearRetrievalCache() and recordRetrievalExposure({requestId,recordIds,kind:'snapshot'|'tool_result'}) are queued, volatile operations. Logs retain bounded IDs/source hashes/scores and query fingerprints, without extra query plaintext; repeated same-kind/request exposure is idempotent. Restart clears these diagnostics, not source memory. saveSnapshot records its actual injectedIds only after its normal persistent write succeeds. The returned item.retrieval includes channels, rankScore, lexicalScore, semanticScore, matchedTerms, associationPaths, temporal, referenceOnly:true and automaticRecall:false. Existing item.score does not become a fused importance score. diagnostics reports actual semantic configuration, availability, query cache hit, indexed/eligible/coverageComplete, reason/degraded, and graph partial coverage. Service errors degrade to real lexical/association candidates without fabricated vectors; explicit revocations remove affected cache/diagnostic references. Provider and document/query fingerprints, TTL and entry/byte caps govern regenerable caches only. Selection, recollection and personality meaning remain autonomous. Owner provider actions retrieval.inspect/configure/prepare, retrieval.diagnostics/detail/clearDiagnostics and memory.search are DSH-adapter operations, not core network behavior. Their configuration, privacy and paid-service limits are documented in [0.10.0 接入与检索说明](integrations-and-retrieval.md). ## 0.11.0 Explicit extension admission during maintenance The optional adapter-supplied extensionValidator({path,value,kind:'content'|'writerLock'}) must return true to admit an extension. All five public maintenance entries, candidate validation, fingerprints and restore completion propagate the same port. Without it, extension data and foreign schemas remain rejected; a caller must also provide it when recovering an interrupted extension restore. Candidate contents are validated before the directory switch, including the already-installed recovery branch before its journal is cleared. Core does not import DSH or recognize QQ fields. The DSH validator admits only precise qq-account and existing qq-social paths and structures, checks nested JsonStore WAL names/checksums/entries, and rejects an active nested writer. Writer locks are not copied into backups. Immutable extension records are preserved rather than rewritten by the personality-source revocation walk; source revocations remain applied to the core personality records. DSH instance lifecycle releases the account root before offline maintenance and uses an exact clear allowlist. Current account-archive validation covers restoration to the same personality and original root; cross-root/instance archive migration is not implemented. External platform credentials and the shared native-operation journal are outside the personality backup/clear scope. See [QQ account operations](qq-account-operations.md) and [schema §24](plan/persona/persona-schema.md#24-独立qq账号工具与维护扩展0110). ## 0.14.0 bounded read-only memory graph getMemoryGraph({scope:"global"|"person"|"unknown"="global",personId?,seedRecordKey?,sourceRef?:{sourceSessionId,sourceEventId},query?,recordTypes?,limit=80,edgeLimit=160}) returns format persona-memory-graph/1, nodes, edges, coverage, readBudget, revision, referenceOnly:true and automaticRecall:false. Query is at most200 Unicode characters, display caps are120 nodes/200 edges. The port does not call _allMemory, ordinary search or a model. Default reads selected derived documents; explicit original selection alone may open its actual source shard, verifying archived bytes/SHA. Shared/person/unknown scopes and composite identities are retained. Missing, ambiguous or unread links do not become guessed edges. Hard budgets are8 opened files/4MiB cumulative reads,2MiB metadata,512KiB per derived file,1MiB per selected archive,256KiB catalog,2048 projected records/4096 metadata receipts and114688 response bytes. Size is checked before bounded reads. coverage.total is null and entireStoreRead false; catalogueComplete describes selected derived documents only. Skips or display truncation never delete source memory. See [full graph contract and user semantics](memory-graph-3d.md).