@lmzhen/dsh-evolution-core 0.31.0 → 0.32.0

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.
package/README.md CHANGED
@@ -50,7 +50,7 @@ section, and importing the package root is its only entry.
50
50
 
51
51
  ## Events (the family's own, process-local)
52
52
 
53
- Seven process events ride the cordis bus (`evolution-core/src/events.ts` declares the payloads;
53
+ Eight process events ride the cordis bus (`evolution-core/src/events.ts` declares the payloads;
54
54
  producers call `ctx.emit`, consumers `ctx.on`). They are NOT session events — appending one to a
55
55
  session log made the session unresumable (A-line P0-1), which is why the payload file says so.
56
56
 
@@ -62,9 +62,10 @@ session log made the session unresumable (A-line P0-1), which is why the payload
62
62
  | `evolution/review-error` | emit (notification) | `evolution-review` failure paths |
63
63
  | `evolution/review-completed` | emit (notification) | `evolution-review` after a plugin branch settles |
64
64
  | `evolution/memory-applied` | emit (notification) | `memory` after a memory write |
65
+ | `evolution/memory-provider-registered` | emit (notification) | `memory` when a provider registers |
65
66
  | `evolution/approval-decided` | emit (notification) | `evolution-approval` after an approval decision lands |
66
67
 
67
- Legacy `evolution/plan-applied` remains declared so old activity ledgers stay readable, but the current production tree has no plan emitter after the review subagent/plan path was removed.
68
+ `evolution/plan-applied` is declared for old activity ledgers; `evolution-review` now emits it from a branch review once that branch settles, with real action counts. `reviewMode: "inject"` still emits none by design.
68
69
 
69
70
  The mode column is what the code does today: every one of them is an announcement, and each
70
71
  declaration carries it as a `@mode` tag (finding O-1, landed) — `verify-arch-guards`' rule **N33** checks that
package/lib/index.js CHANGED
@@ -573,6 +573,9 @@ function transactTaskGuard(what) {
573
573
  /** Lazy adapter over an IO provider registry, shared by every evolution consumer. */
574
574
  function evolutionIoAdapter(provider) {
575
575
  return {
576
+ get processScope() {
577
+ return provider().processScope;
578
+ },
576
579
  readText: (path) => provider().readText(path),
577
580
  writeText: (path, content) => provider().writeText(path, content),
578
581
  remove: (path) => provider().remove(path),
@@ -824,6 +827,7 @@ function nodeEvolutionIo() {
824
827
  }
825
828
  };
826
829
  return {
830
+ processScope: "single-process",
827
831
  async readText(path) {
828
832
  try {
829
833
  return await readFile(path, "utf8");
@@ -1037,13 +1041,14 @@ function atomicWriteFiles(targetDir, writes, fs = defaultFs, logger = console.wa
1037
1041
  //#endregion
1038
1042
  //#region lib/types/tree-lock.js
1039
1043
  /**
1040
- * Cross-process tree write lock.
1044
+ * Tree write lock.
1041
1045
  *
1042
1046
  * The merge run holds this lock for its whole lifetime; curator's pass takes the same
1043
- * lock. The lock is a cooperative file record, created through `transactIo` so two
1044
- * processes cannot both win the create. A holder whose pid is gone is stale and may be
1045
- * taken over; a live pid is always respected, even for a long run (a live long run is
1046
- * exactly what the lock protects).
1047
+ * lock. The record is created through `transactIo`, so exclusion is exactly as strong as
1048
+ * the IO backend's `transact`: the platform `ctx.fs` provider is cross-process, while the
1049
+ * standalone `nodeEvolutionIo` is explicitly single-process (G2 S4). This module builds no
1050
+ * file lock or WAL of its own. A holder whose pid is gone is stale and may be taken over;
1051
+ * a live pid is respected, even for a long run (a live long run is what the lock protects).
1047
1052
  *
1048
1053
  * `commitMerge` deliberately does NOT take this lock itself: the run shell owns it, so a
1049
1054
  * run and its commit share one acquisition. Taking it inside the store would also
@@ -2402,7 +2407,6 @@ const DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS = 20;
2402
2407
  const DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS = 3;
2403
2408
  const DEFAULT_SUBSTANTIVE_MIN_USER_CHARS = 200;
2404
2409
  const DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS = 500;
2405
- const DEFAULT_MAX_OPS_PER_PLAN = 32;
2406
2410
  const DEFAULT_CURATOR_INTERVAL_HOURS = 168;
2407
2411
  const DEFAULT_MIN_IDLE_HOURS = 2;
2408
2412
  const DEFAULT_STALE_AFTER_DAYS = 30;
@@ -5905,9 +5909,10 @@ function buildLearnPrompt(userRequest) {
5905
5909
  /**
5906
5910
  * A process-local serial task queue: each task starts only after the previous
5907
5911
  * one settles (success or failure), so read-modify-write sequences that share
5908
- * one file never interleave inside this process. The durable cross-process
5909
- * serialization layer is the IO backend's transact lock; this chain is the
5910
- * second layer (0.3.17 S2.8, T-1: the shape was duplicated in state-json and
5912
+ * one file never interleave inside this process. When the IO backend provides
5913
+ * a cross-process transact lock, that is the first layer; the node backend does
5914
+ * not, so this chain is its only serialization. (0.3.17 S2.8, T-1: the shape was
5915
+ * duplicated in state-json and
5911
5916
  * memory-files — one factory now).
5912
5917
  */
5913
5918
  function makeSerialQueue() {
@@ -9160,6 +9165,11 @@ const PLATFORM_SERVICE_PROBES = Object.freeze([
9160
9165
  feature: "the state facade behind activity and replay",
9161
9166
  side: "host"
9162
9167
  },
9168
+ {
9169
+ service: "evolutionStateStore",
9170
+ feature: "generic durable state store for assignment queue and future collections",
9171
+ side: "host"
9172
+ },
9163
9173
  {
9164
9174
  service: "llm",
9165
9175
  feature: "the curator one-shot review model call",
@@ -9247,8 +9257,9 @@ function absentHostServices(has) {
9247
9257
  * B3 / G4 (0.3.78): the family's single-instance contract, made explicit.
9248
9258
  *
9249
9259
  * Every persisted sidecar is written under TWO assumptions: the IO backend's
9250
- * cross-process write lock serializes different processes, and exactly ONE
9251
- * instance of each writer service exists per evolution home. The second half
9260
+ * transact serializes different processes when the provider guarantees it (the
9261
+ * node backend is process-local only), and exactly ONE instance of each writer
9262
+ * service exists per evolution home. The second half
9252
9263
  * was implicit — `makeSerialQueue()` and the module-scope stores are
9253
9264
  * per-instance, so two rows writing one home interleave inside one file (the
9254
9265
  * "two instances, one file" class). This module makes that half enforceable: a
@@ -9265,8 +9276,9 @@ function absentHostServices(has) {
9265
9276
  * `claims` below is a module-scope Map: two ROWS over one home in ONE process
9266
9277
  * contend, while the SAME home in another process gets its own Map and is
9267
9278
  * granted the key. That is by construction, not a gap to close here — the
9268
- * cross-process half of the contract is the IO backend's write lock
9269
- * (`transactIo`, core/io.ts), which serializes a per-target read-modify-write.
9279
+ * cross-process half of the contract is the IO backend's transact
9280
+ * (`transactIo`, core/io.ts) when the provider guarantees it; the node backend
9281
+ * is process-local, so a shared home across processes is not protected by it alone.
9270
9282
  * The FLOW2-1 finding was three call sites reading a GRANTED claim as "no other
9271
9283
  * process can be doing this work", so the caller contract is stated here:
9272
9284
  * - granted means "no other row OF THIS PROCESS owns the key";
@@ -10216,9 +10228,8 @@ function foldTurnEvents(events, fromSeq = 0) {
10216
10228
  /**
10217
10229
  * Which session frames are EVIDENCE, and which are bookkeeping.
10218
10230
  *
10219
- * A plan op must cite `evidence` seqs, and the validator's range rule
10220
- * (`evolution-plan-validator`, rule `EVIDENCE_RANGE`) answers only "is this an integer inside
10221
- * the window the plan was authored against". A boundary frame satisfies that while carrying
10231
+ * The session's evidence index answers "does this seq carry content"; a bare range check used
10232
+ * to accept any integer inside the authoring window. A boundary frame satisfies that while carrying
10222
10233
  * nothing a claim can rest on: the `turn/start` seq is the frame a claim about that turn was
10223
10234
  * most likely read out of, and citing it is indistinguishable from citing a real exchange. This
10224
10235
  * module owns the ONE classification of a session frame by what it CARRIES, so the plan path can
@@ -17299,17 +17310,6 @@ const PARAM_EXPOSURE = Object.freeze([
17299
17310
  summary: "Name this package registers as the memory provider.",
17300
17311
  why: "identity"
17301
17312
  },
17302
- {
17303
- id: "maxOpsPerPlan",
17304
- group: "deployment",
17305
- tier: "E2",
17306
- authority: "cordis",
17307
- owner: "evolution-plan-validator",
17308
- applies: "none",
17309
- docAnchor: "PARAMETERS.md#deployment",
17310
- summary: "Operation cap one staged plan may carry.",
17311
- why: "internal"
17312
- },
17313
17313
  {
17314
17314
  id: "substantiveMinToolCalls",
17315
17315
  group: "deployment",
@@ -18247,4 +18247,4 @@ function isIgnorableEvent(event) {
18247
18247
  return classifySessionEvent(event) !== "model";
18248
18248
  }
18249
18249
  //#endregion
18250
- export { AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, BASELINE_ACTION, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEDUP_MAX_PAIR_COMPARISONS, DEDUP_SIMILARITY_THRESHOLD, DEFAULT_ADMISSION, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_PROBE_TIMEOUT_MS, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_RUN_RECORDS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SKILL_VERSION_KEEP, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DEFAULT_WRITE_CONFIRM_MODE, DEFAULT_WRITE_CONFIRM_TIMEOUT_SECONDS, DIAGNOSTICS_FACT_KEYS, DIAGNOSTICS_RUNTIME_KEYS, DIAGNOSTICS_VIEW_SCHEMA_VERSION, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_PRESET_IDS, EVOLUTION_WRITE_TOOLS, EXTRACT_PROMPT_HASH, EXTRACT_PROMPT_V1, EXTRACT_PROMPT_VERSION, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, FUZZY_MAX_PATTERN_CHARS, FUZZY_MAX_WORK, HEALTH_STAMP_RE, HISTORY_DIR, HISTORY_INDEX_VERSION, HOOK_LINE_RE, HOST_ROUTES, INSTANCE_KEYS, KEEP_LINE_RE, LONG_RUNS, LOW_QUALITY_THRESHOLD, MAINTAINER_PRESET_ID, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_REQUEST_BODY_BYTES, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MODEL_SESSION_EVENT_TYPES as MODEL_SESSION_EVENTS, MODEL_SESSION_EVENT_TYPES, MUTATIONS_FILE_VERSION, MemoryStore, MutationUnit, NAMESPACE_MIGRATIONS, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_CATALOG_DESCRIPTION_DEFAULT, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, PLATFORM_LINE, PLATFORM_SERVICE_PROBES, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, READ_REQUIRED_ACTIONS, RESTRICTED_PRESET_DISPLAY, RESTRICTED_TOOLS_ROW_ID, RESTRICTOR_MODULE, RESTRUCTURE_TARGET_RE, RETENTION_FEEDBACK_KEEP_RATIO, RETENTION_FEEDBACK_MIN_CHARS, REVIEWER_PRESET_ID, RULES, RUNS_SCHEMA_VERSION, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, STORE_LEDGER, SUMMARY_DUPLICATE_HINT_THRESHOLD, SUPPORT_DIRS, SUPPORT_SPRAWL_FILES, SUPPRESSED_FILE_VERSION, SkillLibrary, SkillModel, TEXT_DIFF_MAX_CHARS, TEXT_DIFF_MAX_LINES, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UNIT_JOURNAL_PHASES, UNIT_JOURNAL_SCHEMA_VERSION, UNIT_STORAGE_SCHEMA_VERSION, UNTRUSTED_LINE_BREAK, UNTRUSTED_LINE_MARK, UPSTREAM_LIMIT_CHARS_PER_TOKEN, UnitTransactions, VERSION_SUMMARY_MAX_CHARS, absentHostServices, acquireTreeWriteLock, admissionVerdict, advanceReview, affinity, ageCopyKey, allowRowCollisions, anchorVerdict, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyNamespaceMigration, applyReferenceRewrite, asRecord, assertDispatchPayload, assertSkillsRootAliasRetired, assertUnitJournalTransition, assessStructureHealth, atomicWriteFiles, authoringFeedback, authorityFrom, backupsReachability, blobPath, bodyCost, buildCuratorRunReport, buildExtractPlanFromLibrary, buildHealthBaseline, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, candidateSkills, canonicalWriteId, claimInstance, clampOnce, clampedNumber, classifyNamespaceMigration, classifySessionEvent, clearReviewChannel, collectReadSkillNames, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, contentRetentionFeedback, countDispatches, countReferenceFiles, createGateSet, createSubagentChannel, daysSinceIso, declaredReportStamp, describeReferenceRewrite, diffFindings, dispatchKeyOf, dispatchStepOf, displayBodyOf, duplicateHeadings, elapsedSince, emptyRecord, ensureSkillFrontmatter, entryTarget, errorText, evaluateThreat, eventsFile, evidenceKindIndex, evolutionActivityProjection, evolutionEventPayloadIssue, evolutionEvidenceProjection, evolutionHome, evolutionIoAdapter, evolutionReadsProjection, evolutionRoot, evolutionSignalsProjection, executeUnitUndo, externalRefs, fileMutationLock, filterUnreadSkillOps, findDriftSignal, findOwnerCandidate, foldCuratorFields, foldToolDispatches, foldTurnEvent, foldTurnEvents, foldUntrustedLines, frontmatterBlock, frontmatterCatalogInvalid, fuzzyPatch, getRecord, h2Sections, historyIndexFile, historyReachability, historyRoot, hostSurface, identity, idleDays, initialTurnFold, installEvolutionProjections, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isBookkeepingFrame, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isIgnorableEvent, isLandmark, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isRecord, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, json, landmarkVerdict, latestActivityAt, latestVersionAt, lifecycleCandidate, lintBody, lintSkill, listEventArchives, liveBool, liveEnum, liveNumber, liveString, loadMutations, loadSuppressedNames, loadUsage, loadVersionContent, loadVersions, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, methodNotAllowed, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nearDuplicateSummaries, newRunRegistry, newSkillLibrary, nextHistoryIndex, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, normalizeVersionSummary, observeEvent, orderVersions, overlongLines, ownerCandidatesFromSummaries, ownerDecisionText, paramNamespace, paramRowId, paramSettingsId, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseHistoryIndex, partitionVersions, payloadText, persistedWriteSite, persistedWriteSites, pickWithPolicy, planExtract, planNamespaceMigration, planReferenceRewrite, planRehoming, planUnitUndoAcross, policyStageLimits, probeAbsent, probeChannelState, probeList, probeMtime, probePresent, probeReason, probeText, probeUnknown, projectExtractBodies, projectionText, proposalFromPlan, proposalReportDir, proposalReportName, protectedSkillNamesOf, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readExternalSupport, readHistoryIndex, readJsonObject, readNumberParam, readParam, readProposalReports, readTreeLock, readUnitEvidence, readUnitIndex, readUnitJournal, readUnitReceipt, readUnitSnapshot, readingStats, recordMutation, recordVersions, redactSecrets, referencedBlobs, registerHostRoutes, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, renderLongRunTable, reportTime, reportsReachability, reportsSweepLockTarget, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, resolveUnitMembers, resolveUnitMembersFromIndexes, restructureCandidates, retainEventArchives, retirementReport, reviewPrompt, revisionAnchor, revisionAnchorOf, revisionFingerprint, revisionSupportDigest, runWriteGates, runsFile, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopeOfNearestManifest, scopedPackageName, scopedProbeReport, selectSections, sessionAudited, sessionEvidenceIndex, sessionLastEventTime, sessionReadNames, sessionReadSkillNames, sessionSeesFamilyTools, sessionTurnSignals, skillLibraryUnitBackend, skillReadNameOf, skillRowCells, skillStateKey, skillWriteGateContext, skillsRoot, staleRouteStubs, subagentChannelState, supportFileReadOf, supportRefs, suppressedFile, sweepReports, sweepReviewChannelSessions, textDiffFacts, tokenLineFor, transactIo, transactTaskGuard, treeLockFile, trimPatternBoundaries, unhookedSupportPointers, unitEvidenceDigest, unitEvidencePath, unitIndexPath, unitJournalPath, unitJournalPhaseRank, unitJournalPort, unitMembersAreComplete, unitReceiptPath, unitSnapshotPath, unitSnapshotPort, unitSnapshotsDir, unitStorageKey, unwrapLive, updateSuppressedNames, upsertUnitIndex, usageFile, usageObserved, userSetKeys, validateFrontmatter, validateMutationRequest, validateRestructureTarget, validateSupportPath, valueOr, verifyPromptBundle, versionActionKind, versionRowCells, versionSummaryPrompt, versionTarget, vocabulary, withTreeWrite, withTreeWriteLock, writeDurableTmp, writePathSymbols, writeProposalReport, writeUnitEvidence, writeUnitJournal, writeUnitReceipt, writeUnitSnapshot, yamlPlainScalarNeedsQuotes };
18250
+ export { AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, BASELINE_ACTION, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEDUP_MAX_PAIR_COMPARISONS, DEDUP_SIMILARITY_THRESHOLD, DEFAULT_ADMISSION, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_PROBE_TIMEOUT_MS, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_RUN_RECORDS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SKILL_VERSION_KEEP, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DEFAULT_WRITE_CONFIRM_MODE, DEFAULT_WRITE_CONFIRM_TIMEOUT_SECONDS, DIAGNOSTICS_FACT_KEYS, DIAGNOSTICS_RUNTIME_KEYS, DIAGNOSTICS_VIEW_SCHEMA_VERSION, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_ERRORS, EVOLUTION_PRESET_IDS, EVOLUTION_WRITE_TOOLS, EXTRACT_PROMPT_HASH, EXTRACT_PROMPT_V1, EXTRACT_PROMPT_VERSION, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, FUZZY_MAX_PATTERN_CHARS, FUZZY_MAX_WORK, HEALTH_STAMP_RE, HISTORY_DIR, HISTORY_INDEX_VERSION, HOOK_LINE_RE, HOST_ROUTES, INSTANCE_KEYS, KEEP_LINE_RE, LONG_RUNS, LOW_QUALITY_THRESHOLD, MAINTAINER_PRESET_ID, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_REQUEST_BODY_BYTES, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MODEL_SESSION_EVENT_TYPES as MODEL_SESSION_EVENTS, MODEL_SESSION_EVENT_TYPES, MUTATIONS_FILE_VERSION, MemoryStore, MutationUnit, NAMESPACE_MIGRATIONS, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_CATALOG_DESCRIPTION_DEFAULT, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, PLATFORM_LINE, PLATFORM_SERVICE_PROBES, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, READ_REQUIRED_ACTIONS, RESTRICTED_PRESET_DISPLAY, RESTRICTED_TOOLS_ROW_ID, RESTRICTOR_MODULE, RESTRUCTURE_TARGET_RE, RETENTION_FEEDBACK_KEEP_RATIO, RETENTION_FEEDBACK_MIN_CHARS, REVIEWER_PRESET_ID, RULES, RUNS_SCHEMA_VERSION, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, STORE_LEDGER, SUMMARY_DUPLICATE_HINT_THRESHOLD, SUPPORT_DIRS, SUPPORT_SPRAWL_FILES, SUPPRESSED_FILE_VERSION, SkillLibrary, SkillModel, TEXT_DIFF_MAX_CHARS, TEXT_DIFF_MAX_LINES, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UNIT_JOURNAL_PHASES, UNIT_JOURNAL_SCHEMA_VERSION, UNIT_STORAGE_SCHEMA_VERSION, UNTRUSTED_LINE_BREAK, UNTRUSTED_LINE_MARK, UPSTREAM_LIMIT_CHARS_PER_TOKEN, UnitTransactions, VERSION_SUMMARY_MAX_CHARS, absentHostServices, acquireTreeWriteLock, admissionVerdict, advanceReview, affinity, ageCopyKey, allowRowCollisions, anchorVerdict, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyNamespaceMigration, applyReferenceRewrite, asRecord, assertDispatchPayload, assertSkillsRootAliasRetired, assertUnitJournalTransition, assessStructureHealth, atomicWriteFiles, authoringFeedback, authorityFrom, backupsReachability, blobPath, bodyCost, buildCuratorRunReport, buildExtractPlanFromLibrary, buildHealthBaseline, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, candidateSkills, canonicalWriteId, claimInstance, clampOnce, clampedNumber, classifyNamespaceMigration, classifySessionEvent, clearReviewChannel, collectReadSkillNames, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, contentRetentionFeedback, countDispatches, countReferenceFiles, createGateSet, createSubagentChannel, daysSinceIso, declaredReportStamp, describeReferenceRewrite, diffFindings, dispatchKeyOf, dispatchStepOf, displayBodyOf, duplicateHeadings, elapsedSince, emptyRecord, ensureSkillFrontmatter, entryTarget, errorText, evaluateThreat, eventsFile, evidenceKindIndex, evolutionActivityProjection, evolutionEventPayloadIssue, evolutionEvidenceProjection, evolutionHome, evolutionIoAdapter, evolutionReadsProjection, evolutionRoot, evolutionSignalsProjection, executeUnitUndo, externalRefs, fileMutationLock, filterUnreadSkillOps, findDriftSignal, findOwnerCandidate, foldCuratorFields, foldToolDispatches, foldTurnEvent, foldTurnEvents, foldUntrustedLines, frontmatterBlock, frontmatterCatalogInvalid, fuzzyPatch, getRecord, h2Sections, historyIndexFile, historyReachability, historyRoot, hostSurface, identity, idleDays, initialTurnFold, installEvolutionProjections, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isBookkeepingFrame, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isIgnorableEvent, isLandmark, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isRecord, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, isUnreadWrite, json, landmarkVerdict, latestActivityAt, latestVersionAt, lifecycleCandidate, lintBody, lintSkill, listEventArchives, liveBool, liveEnum, liveNumber, liveString, loadMutations, loadSuppressedNames, loadUsage, loadVersionContent, loadVersions, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, methodNotAllowed, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, nearDuplicateSummaries, newRunRegistry, newSkillLibrary, nextHistoryIndex, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, normalizeVersionSummary, observeEvent, orderVersions, overlongLines, ownerCandidatesFromSummaries, ownerDecisionText, paramNamespace, paramRowId, paramSettingsId, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseHistoryIndex, partitionVersions, payloadText, persistedWriteSite, persistedWriteSites, pickWithPolicy, planExtract, planNamespaceMigration, planReferenceRewrite, planRehoming, planUnitUndoAcross, policyStageLimits, probeAbsent, probeChannelState, probeList, probeMtime, probePresent, probeReason, probeText, probeUnknown, projectExtractBodies, projectionText, proposalFromPlan, proposalReportDir, proposalReportName, protectedSkillNamesOf, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readExternalSupport, readHistoryIndex, readJsonObject, readNumberParam, readParam, readProposalReports, readTreeLock, readUnitEvidence, readUnitIndex, readUnitJournal, readUnitReceipt, readUnitSnapshot, readingStats, recordMutation, recordVersions, redactSecrets, referencedBlobs, registerHostRoutes, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, renderLongRunTable, reportTime, reportsReachability, reportsSweepLockTarget, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, resolveUnitMembers, resolveUnitMembersFromIndexes, restructureCandidates, retainEventArchives, retirementReport, reviewPrompt, revisionAnchor, revisionAnchorOf, revisionFingerprint, revisionSupportDigest, runWriteGates, runsFile, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopeOfNearestManifest, scopedPackageName, scopedProbeReport, selectSections, sessionAudited, sessionEvidenceIndex, sessionLastEventTime, sessionReadNames, sessionReadSkillNames, sessionSeesFamilyTools, sessionTurnSignals, skillLibraryUnitBackend, skillReadNameOf, skillRowCells, skillStateKey, skillWriteGateContext, skillsRoot, staleRouteStubs, subagentChannelState, supportFileReadOf, supportRefs, suppressedFile, sweepReports, sweepReviewChannelSessions, textDiffFacts, tokenLineFor, transactIo, transactTaskGuard, treeLockFile, trimPatternBoundaries, unhookedSupportPointers, unitEvidenceDigest, unitEvidencePath, unitIndexPath, unitJournalPath, unitJournalPhaseRank, unitJournalPort, unitMembersAreComplete, unitReceiptPath, unitSnapshotPath, unitSnapshotPort, unitSnapshotsDir, unitStorageKey, unwrapLive, updateSuppressedNames, upsertUnitIndex, usageFile, usageObserved, userSetKeys, validateFrontmatter, validateMutationRequest, validateRestructureTarget, validateSupportPath, valueOr, verifyPromptBundle, versionActionKind, versionRowCells, versionSummaryPrompt, versionTarget, vocabulary, withTreeWrite, withTreeWriteLock, writeDurableTmp, writePathSymbols, writeProposalReport, writeUnitEvidence, writeUnitJournal, writeUnitReceipt, writeUnitSnapshot, yamlPlainScalarNeedsQuotes };
@@ -90,7 +90,6 @@ export declare const DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS = 20;
90
90
  export declare const DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS = 3;
91
91
  export declare const DEFAULT_SUBSTANTIVE_MIN_USER_CHARS = 200;
92
92
  export declare const DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS = 500;
93
- export declare const DEFAULT_MAX_OPS_PER_PLAN = 32;
94
93
  export declare const DEFAULT_CURATOR_INTERVAL_HOURS = 168;
95
94
  export declare const DEFAULT_MIN_IDLE_HOURS = 2;
96
95
  export declare const DEFAULT_STALE_AFTER_DAYS = 30;
@@ -109,7 +109,6 @@ export const DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS = 20;
109
109
  export const DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS = 3;
110
110
  export const DEFAULT_SUBSTANTIVE_MIN_USER_CHARS = 200;
111
111
  export const DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS = 500;
112
- export const DEFAULT_MAX_OPS_PER_PLAN = 32;
113
112
  export const DEFAULT_CURATOR_INTERVAL_HOURS = 168;
114
113
  export const DEFAULT_MIN_IDLE_HOURS = 2;
115
114
  export const DEFAULT_STALE_AFTER_DAYS = 30;
@@ -12,6 +12,8 @@
12
12
  * these events off `session.append`). Plan-outcome durability lives in the
13
13
  * evolution-activity store, not the session log.
14
14
  */
15
+ import type { EvolutionPlanAppliedEvent, EvolutionSkillMutatedEvent } from '@lmzhen/dsh-evolution-contract';
16
+ export type { EvolutionPlanAppliedEvent, EvolutionSkillMutatedEvent } from '@lmzhen/dsh-evolution-contract';
15
17
  import type { ReviewKind } from './signals.ts';
16
18
  export interface EvolutionReviewScheduledEvent {
17
19
  /** Owning session (payload v2): process events carry no session envelope. */
@@ -71,52 +73,6 @@ export interface EvolutionReviewCompletedEvent {
71
73
  readonly promptVersion?: string | undefined;
72
74
  readonly error?: string | undefined;
73
75
  }
74
- export interface EvolutionPlanAppliedEvent {
75
- /** Owning session (payload v2): process events carry no session envelope. */
76
- sessionId: string;
77
- planId: string;
78
- /** Stable fingerprint of the policy snapshot that produced this plan. */
79
- policyFingerprint?: string | undefined;
80
- memoryApplied: number;
81
- skillApplied: number;
82
- /** Validation rejects ONLY (see the contract note below). V27 R-03: a plan op
83
- * that was skipped because the session had not read the skill is NOT a
84
- * validation reject and now travels in `skippedUnread`. */
85
- rejectedOps: number;
86
- /** 0.3.31 (V5-19): execution-layer failures — ops that reached execution but
87
- * did not land (non-throw `ok:false` results). `rejectedOps` counts only
88
- * VALIDATION rejects; a consumer that treats rejectedOps as "work not done"
89
- * would otherwise miss a partial application. */
90
- executionFailures?: number | undefined;
91
- /** V27 R-03: "not done" has a third, independent cause — an op naming a skill
92
- * this session never read (the review pipeline refuses to touch unread
93
- * skills). It is neither a validation reject nor an execution failure, so it
94
- * has its own field; folding it into `rejectedOps` broke that field's stated
95
- * contract and made the replay leaderboard penalize one refusal twice
96
- * (rejectedOps weight AND the executionFailures dimension). */
97
- skippedUnread?: number | undefined;
98
- /** First execution-layer failure message (abort reason or op failure). */
99
- executionError?: string | undefined;
100
- /** Batch D (2026-09-27): ops whose ENTIRE evidence list cites bookkeeping frames
101
- * (a turn/step boundary) — the report-only phase of the plan path's
102
- * `EVIDENCE_CLASS` rule. Not a refusal and not a "not done" cause: the ops in
103
- * this count executed. It rides the same payload as the other dimensions so the
104
- * observation window has a durable record; the model's notice says nothing about
105
- * it. */
106
- evidenceClassReports?: number | undefined;
107
- evidenceQuotes?: number | undefined;
108
- estimatedInputChars?: number | undefined;
109
- }
110
- export interface EvolutionSkillMutatedEvent {
111
- action: string;
112
- name: string;
113
- /** 0.3.16 (E-50): was `filePath` with mixed semantics — skill-directory ops
114
- * carried the DIRECTORY while file ops (write_file/remove_file) carried the
115
- * FILE path. Split into explicit fields so a subscriber can distinguish. */
116
- skillDir?: string;
117
- file?: string;
118
- archivedPath?: string;
119
- }
120
76
  /** 0.3.18 (E-6): a turn-end review pipeline failure was caught (never an
121
77
  * unhandled rejection); this event lets operators/observability see it. The
122
78
  * reason is already logged by the emitter — the event is a timestamped signal. */
@@ -167,5 +123,4 @@ declare module '@deepseek-ai/cordis' {
167
123
  'evolution/review-error'(event: EvolutionReviewErrorEvent): void;
168
124
  }
169
125
  }
170
- export {};
171
126
  //# sourceMappingURL=events.d.ts.map
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * Which session frames are EVIDENCE, and which are bookkeeping.
3
3
  *
4
- * A plan op must cite `evidence` seqs, and the validator's range rule
5
- * (`evolution-plan-validator`, rule `EVIDENCE_RANGE`) answers only "is this an integer inside
6
- * the window the plan was authored against". A boundary frame satisfies that while carrying
4
+ * The session's evidence index answers "does this seq carry content"; a bare range check used
5
+ * to accept any integer inside the authoring window. A boundary frame satisfies that while carrying
7
6
  * nothing a claim can rest on: the `turn/start` seq is the frame a claim about that turn was
8
7
  * most likely read out of, and citing it is indistinguishable from citing a real exchange. This
9
8
  * module owns the ONE classification of a session frame by what it CARRIES, so the plan path can
@@ -33,8 +32,7 @@ export declare function isBookkeepingFrame(type: string): boolean;
33
32
  *
34
33
  * Structural on purpose — {@link evidenceKindIndex} materializes the dense set of content seqs,
35
34
  * while the projection answers by complement over the sparse boundary seqs
36
- * (`session-projection.ts`). Both satisfy this interface, and it is all the plan path reads
37
- * (`evolution-plan-validator/src/index.ts:164`).
35
+ * (`session-projection.ts`). Both satisfy this interface; `session-projection` is the reader.
38
36
  */
39
37
  export interface EvidenceIndex {
40
38
  /** @param seq - a cited evidence seq. @returns true when that frame carries content. */
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * Which session frames are EVIDENCE, and which are bookkeeping.
3
3
  *
4
- * A plan op must cite `evidence` seqs, and the validator's range rule
5
- * (`evolution-plan-validator`, rule `EVIDENCE_RANGE`) answers only "is this an integer inside
6
- * the window the plan was authored against". A boundary frame satisfies that while carrying
4
+ * The session's evidence index answers "does this seq carry content"; a bare range check used
5
+ * to accept any integer inside the authoring window. A boundary frame satisfies that while carrying
7
6
  * nothing a claim can rest on: the `turn/start` seq is the frame a claim about that turn was
8
7
  * most likely read out of, and citing it is indistinguishable from citing a real exchange. This
9
8
  * module owns the ONE classification of a session frame by what it CARRIES, so the plan path can
@@ -2,8 +2,9 @@
2
2
  * B3 / G4 (0.3.78): the family's single-instance contract, made explicit.
3
3
  *
4
4
  * Every persisted sidecar is written under TWO assumptions: the IO backend's
5
- * cross-process write lock serializes different processes, and exactly ONE
6
- * instance of each writer service exists per evolution home. The second half
5
+ * transact serializes different processes when the provider guarantees it (the
6
+ * node backend is process-local only), and exactly ONE instance of each writer
7
+ * service exists per evolution home. The second half
7
8
  * was implicit — `makeSerialQueue()` and the module-scope stores are
8
9
  * per-instance, so two rows writing one home interleave inside one file (the
9
10
  * "two instances, one file" class). This module makes that half enforceable: a
@@ -20,8 +21,9 @@
20
21
  * `claims` below is a module-scope Map: two ROWS over one home in ONE process
21
22
  * contend, while the SAME home in another process gets its own Map and is
22
23
  * granted the key. That is by construction, not a gap to close here — the
23
- * cross-process half of the contract is the IO backend's write lock
24
- * (`transactIo`, core/io.ts), which serializes a per-target read-modify-write.
24
+ * cross-process half of the contract is the IO backend's transact
25
+ * (`transactIo`, core/io.ts) when the provider guarantees it; the node backend
26
+ * is process-local, so a shared home across processes is not protected by it alone.
25
27
  * The FLOW2-1 finding was three call sites reading a GRANTED claim as "no other
26
28
  * process can be doing this work", so the caller contract is stated here:
27
29
  * - granted means "no other row OF THIS PROCESS owns the key";
@@ -2,8 +2,9 @@
2
2
  * B3 / G4 (0.3.78): the family's single-instance contract, made explicit.
3
3
  *
4
4
  * Every persisted sidecar is written under TWO assumptions: the IO backend's
5
- * cross-process write lock serializes different processes, and exactly ONE
6
- * instance of each writer service exists per evolution home. The second half
5
+ * transact serializes different processes when the provider guarantees it (the
6
+ * node backend is process-local only), and exactly ONE instance of each writer
7
+ * service exists per evolution home. The second half
7
8
  * was implicit — `makeSerialQueue()` and the module-scope stores are
8
9
  * per-instance, so two rows writing one home interleave inside one file (the
9
10
  * "two instances, one file" class). This module makes that half enforceable: a
@@ -20,8 +21,9 @@
20
21
  * `claims` below is a module-scope Map: two ROWS over one home in ONE process
21
22
  * contend, while the SAME home in another process gets its own Map and is
22
23
  * granted the key. That is by construction, not a gap to close here — the
23
- * cross-process half of the contract is the IO backend's write lock
24
- * (`transactIo`, core/io.ts), which serializes a per-target read-modify-write.
24
+ * cross-process half of the contract is the IO backend's transact
25
+ * (`transactIo`, core/io.ts) when the provider guarantees it; the node backend
26
+ * is process-local, so a shared home across processes is not protected by it alone.
25
27
  * The FLOW2-1 finding was three call sites reading a GRANTED claim as "no other
26
28
  * process can be doing this work", so the caller contract is stated here:
27
29
  * - granted means "no other row OF THIS PROCESS owns the key";
package/lib/types/io.d.ts CHANGED
@@ -6,6 +6,13 @@
6
6
  */
7
7
  import { open } from 'node:fs/promises';
8
8
  export interface EvolutionIoLike {
9
+ /**
10
+ * The process scope this backend actually guarantees. `transact` is NOT proof:
11
+ * nodeEvolutionIo's transact serializes in-process only (G2 S4). Required for
12
+ * any backend that claims cross-process; omitted/`single-process` means the
13
+ * caller must keep its own chain and the family must report the weaker truth.
14
+ */
15
+ readonly processScope?: 'single-process' | 'cross-process' | undefined;
9
16
  readText(path: string): Promise<string | null>;
10
17
  writeText(path: string, content: string): Promise<void>;
11
18
  remove(path: string): Promise<void>;
package/lib/types/io.js CHANGED
@@ -78,6 +78,7 @@ export function transactTaskGuard(what) {
78
78
  /** Lazy adapter over an IO provider registry, shared by every evolution consumer. */
79
79
  export function evolutionIoAdapter(provider) {
80
80
  return {
81
+ get processScope() { return provider().processScope; },
81
82
  readText: path => provider().readText(path),
82
83
  writeText: (path, content) => provider().writeText(path, content),
83
84
  remove: path => provider().remove(path),
@@ -382,6 +383,7 @@ export function nodeEvolutionIo() {
382
383
  }
383
384
  };
384
385
  return {
386
+ processScope: 'single-process',
385
387
  async readText(path) {
386
388
  try {
387
389
  return await readFile(path, 'utf8');
@@ -178,7 +178,6 @@ export const PARAM_EXPOSURE = Object.freeze([
178
178
  { id: 'evolution-state.provider', group: 'deployment', tier: 'E2', authority: 'cordis', owner: 'evolution-state', applies: 'none', docAnchor: 'PARAMETERS.md#deployment', summary: 'Registered state-store provider name.', why: 'identity' },
179
179
  { id: 'memory.provider', group: 'deployment', tier: 'E2', authority: 'cordis', owner: 'memory', applies: 'none', docAnchor: 'PARAMETERS.md#deployment', summary: 'Registered memory provider name.', why: 'identity' },
180
180
  { id: 'memory-files.providerName', group: 'deployment', tier: 'E2', authority: 'cordis', owner: 'memory-files', applies: 'none', docAnchor: 'PARAMETERS.md#deployment', summary: 'Name this package registers as the memory provider.', why: 'identity' },
181
- { id: 'maxOpsPerPlan', group: 'deployment', tier: 'E2', authority: 'cordis', owner: 'evolution-plan-validator', applies: 'none', docAnchor: 'PARAMETERS.md#deployment', summary: 'Operation cap one staged plan may carry.', why: 'internal' },
182
181
  { id: 'substantiveMinToolCalls', group: 'deployment', tier: 'E2', authority: 'cordis', owner: 'evolution-review', applies: 'none', docAnchor: 'PARAMETERS.md#deployment', summary: 'Tool calls that make a turn count as substantive.', why: 'internal' },
183
182
  { id: 'substantiveMinUserChars', group: 'deployment', tier: 'E2', authority: 'cordis', owner: 'evolution-review', applies: 'none', docAnchor: 'PARAMETERS.md#deployment', summary: 'User characters that make a turn count as substantive.', why: 'internal' },
184
183
  { id: 'substantiveMinAgentChars', group: 'deployment', tier: 'E2', authority: 'cordis', owner: 'evolution-review', applies: 'none', docAnchor: 'PARAMETERS.md#deployment', summary: 'Assistant characters that make a turn count as substantive.', why: 'internal' },
@@ -11,15 +11,8 @@
11
11
  * `client` probes run in the browser half, where the host has no view of the seats.
12
12
  * @module @lmzhen/dsh-evolution-core
13
13
  */
14
- /** One platform service the family probes, with the feature that goes quiet without it. */
15
- export interface PlatformServiceProbe {
16
- /** The service key as `ctx.get` spells it. */
17
- readonly service: string;
18
- /** The family feature that silently degrades when the service is absent. */
19
- readonly feature: string;
20
- /** Where the probe runs. */
21
- readonly side: 'host' | 'client';
22
- }
14
+ import type { PlatformServiceProbe } from '@lmzhen/dsh-evolution-contract';
15
+ export type { PlatformServiceProbe } from '@lmzhen/dsh-evolution-contract';
23
16
  /** The 30 probes, in service-name order (the guard checks this list against the tree). */
24
17
  export declare const PLATFORM_SERVICE_PROBES: readonly PlatformServiceProbe[];
25
18
  /**
@@ -29,6 +29,7 @@ export const PLATFORM_SERVICE_PROBES = Object.freeze([
29
29
  { service: 'evolutionPolicy', feature: 'the policy snapshot that shadows row knobs', side: 'host' },
30
30
  { service: 'evolutionReplay', feature: '/evolution replay', side: 'host' },
31
31
  { service: 'evolutionState', feature: 'the state facade behind activity and replay', side: 'host' },
32
+ { service: 'evolutionStateStore', feature: 'generic durable state store for assignment queue and future collections', side: 'host' },
32
33
  { service: 'llm', feature: 'the curator one-shot review model call', side: 'host' },
33
34
  { service: 'memory', feature: 'the cross-session memory store (review and learning-graph reads)', side: 'host' },
34
35
  { service: 'pluginInventory', feature: 'the plugin inventory view', side: 'host' },
@@ -185,7 +185,8 @@ export function newRunRegistry(options) {
185
185
  };
186
186
  const persist = async () => {
187
187
  try {
188
- // Read-modify-write under the io backend's cross-process lock. The file is the
188
+ // Read-modify-write under io.transact when the backend provides it; the node
189
+ // backend serializes in-process only. The file is the
189
190
  // BASE and only THIS process's rows are laid over it ("one writer per row"); the
190
191
  // single write a non-owner may make is the orphan verdict for a row whose owner is
191
192
  // gone. The row read inside this transaction IS the compare-and-swap: if its owner
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * A process-local serial task queue: each task starts only after the previous
3
3
  * one settles (success or failure), so read-modify-write sequences that share
4
- * one file never interleave inside this process. The durable cross-process
5
- * serialization layer is the IO backend's transact lock; this chain is the
6
- * second layer (0.3.17 S2.8, T-1: the shape was duplicated in state-json and
4
+ * one file never interleave inside this process. When the IO backend provides
5
+ * a cross-process transact lock, that is the first layer; the node backend does
6
+ * not, so this chain is its only serialization. (0.3.17 S2.8, T-1: the shape was
7
+ * duplicated in state-json and
7
8
  * memory-files — one factory now).
8
9
  */
9
10
  export declare function makeSerialQueue(): <T>(task: () => Promise<T>) => Promise<T>;
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * A process-local serial task queue: each task starts only after the previous
3
3
  * one settles (success or failure), so read-modify-write sequences that share
4
- * one file never interleave inside this process. The durable cross-process
5
- * serialization layer is the IO backend's transact lock; this chain is the
6
- * second layer (0.3.17 S2.8, T-1: the shape was duplicated in state-json and
4
+ * one file never interleave inside this process. When the IO backend provides
5
+ * a cross-process transact lock, that is the first layer; the node backend does
6
+ * not, so this chain is its only serialization. (0.3.17 S2.8, T-1: the shape was
7
+ * duplicated in state-json and
7
8
  * memory-files — one factory now).
8
9
  */
9
10
  export function makeSerialQueue() {
@@ -1,11 +1,12 @@
1
1
  /**
2
- * Cross-process tree write lock.
2
+ * Tree write lock.
3
3
  *
4
4
  * The merge run holds this lock for its whole lifetime; curator's pass takes the same
5
- * lock. The lock is a cooperative file record, created through `transactIo` so two
6
- * processes cannot both win the create. A holder whose pid is gone is stale and may be
7
- * taken over; a live pid is always respected, even for a long run (a live long run is
8
- * exactly what the lock protects).
5
+ * lock. The record is created through `transactIo`, so exclusion is exactly as strong as
6
+ * the IO backend's `transact`: the platform `ctx.fs` provider is cross-process, while the
7
+ * standalone `nodeEvolutionIo` is explicitly single-process (G2 S4). This module builds no
8
+ * file lock or WAL of its own. A holder whose pid is gone is stale and may be taken over;
9
+ * a live pid is respected, even for a long run (a live long run is what the lock protects).
9
10
  *
10
11
  * `commitMerge` deliberately does NOT take this lock itself: the run shell owns it, so a
11
12
  * run and its commit share one acquisition. Taking it inside the store would also
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-core",
3
3
  "description": "Shared stores, prompts, signals and lifecycle logic for the dsh-evolution plugin family (community build)",
4
- "version": "0.31.0",
4
+ "version": "0.32.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -48,7 +48,8 @@
48
48
  "dependencies": {
49
49
  "yaml": "^2.4.2",
50
50
  "zod": "^4.4.3",
51
- "js-yaml": "^4.1.0"
51
+ "js-yaml": "^4.1.0",
52
+ "@lmzhen/dsh-evolution-contract": "^0.32.0"
52
53
  },
53
54
  "peerDependencies": {
54
55
  "@deepseek-ai/cordis": "^4.0.5",
@@ -297,6 +297,15 @@
297
297
  "marker": "transactIo(io, pairIndexPath(home)",
298
298
  "state": [],
299
299
  "note": "pairKey → result/runId/target index; RMW under the same IO lock so two merge runs cannot lose each other's entries."
300
+ },
301
+ {
302
+ "id": "state-store-collections",
303
+ "path": "<evolutionHome>/state-store/<collection>.json",
304
+ "writer": "evolution-state-json/src/state-store.ts",
305
+ "serializedBy": "transact",
306
+ "marker": "transactIo(this.io, this.path(collection)",
307
+ "state": [],
308
+ "note": "Generic contract StateStore collections (one file per collection); provider serial queue plus transactIo. cross-process false on the node backend."
300
309
  }
301
310
  ]
302
311
  }