memleaf 0.2.56__tar.gz → 0.2.58__tar.gz

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.
Files changed (114) hide show
  1. {memleaf-0.2.56 → memleaf-0.2.58}/CHANGELOG.md +13 -0
  2. {memleaf-0.2.56/src/memleaf.egg-info → memleaf-0.2.58}/PKG-INFO +4 -3
  3. {memleaf-0.2.56 → memleaf-0.2.58}/README.en.md +3 -2
  4. {memleaf-0.2.56 → memleaf-0.2.58}/README.md +3 -2
  5. {memleaf-0.2.56 → memleaf-0.2.58}/pyproject.toml +1 -1
  6. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/__init__.py +1 -1
  7. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/hermes_provider/plugin.yaml +1 -1
  8. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/single_pass_memory_planner.py +9 -62
  9. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/single_pass_plan.py +2 -2
  10. {memleaf-0.2.56 → memleaf-0.2.58/src/memleaf.egg-info}/PKG-INFO +4 -3
  11. {memleaf-0.2.56 → memleaf-0.2.58}/LICENSE +0 -0
  12. {memleaf-0.2.56 → memleaf-0.2.58}/MANIFEST.in +0 -0
  13. {memleaf-0.2.56 → memleaf-0.2.58}/docs/capture-budget-design.md +0 -0
  14. {memleaf-0.2.56 → memleaf-0.2.58}/docs/config-migrations.md +0 -0
  15. {memleaf-0.2.56 → memleaf-0.2.58}/docs/core-refactor.md +0 -0
  16. {memleaf-0.2.56 → memleaf-0.2.58}/docs/evidence-retention.md +0 -0
  17. {memleaf-0.2.56 → memleaf-0.2.58}/docs/extraction-latency.md +0 -0
  18. {memleaf-0.2.56 → memleaf-0.2.58}/docs/gate-evidence-boundary.md +0 -0
  19. {memleaf-0.2.56 → memleaf-0.2.58}/docs/general-processing.md +0 -0
  20. {memleaf-0.2.56 → memleaf-0.2.58}/docs/hermes-mcp-runtime.md +0 -0
  21. {memleaf-0.2.56 → memleaf-0.2.58}/docs/processing-quality-acceptance.md +0 -0
  22. {memleaf-0.2.56 → memleaf-0.2.58}/docs/v0.2.26-processing-status.md +0 -0
  23. {memleaf-0.2.56 → memleaf-0.2.58}/examples/README.md +0 -0
  24. {memleaf-0.2.56 → memleaf-0.2.58}/examples/basic_usage.py +0 -0
  25. {memleaf-0.2.56 → memleaf-0.2.58}/examples/mcp_stdio.ndjson +0 -0
  26. {memleaf-0.2.56 → memleaf-0.2.58}/install.ps1 +0 -0
  27. {memleaf-0.2.56 → memleaf-0.2.58}/install.sh +0 -0
  28. {memleaf-0.2.56 → memleaf-0.2.58}/setup.cfg +0 -0
  29. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/__main__.py +0 -0
  30. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/adapters/__init__.py +0 -0
  31. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/adapters/antigravity.py +0 -0
  32. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/adapters/base.py +0 -0
  33. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/adapters/codex.py +0 -0
  34. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/adapters/hermes.py +0 -0
  35. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/admission.py +0 -0
  36. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/batch_review.py +0 -0
  37. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/budget.py +0 -0
  38. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/capture.py +0 -0
  39. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/cli.py +0 -0
  40. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/compaction.py +0 -0
  41. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/config.py +0 -0
  42. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/create_coordinator.py +0 -0
  43. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/credentials.py +0 -0
  44. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/evidence_budget.py +0 -0
  45. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/evidence_policy.py +0 -0
  46. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/evidence_structure.py +0 -0
  47. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/evidence_syntax.py +0 -0
  48. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/extraction_budget.py +0 -0
  49. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/extraction_capability.py +0 -0
  50. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/extraction_work_state.py +0 -0
  51. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/frontmatter.py +0 -0
  52. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/hermes_provider/README.md +0 -0
  53. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/hermes_provider/__init__.py +0 -0
  54. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/hermes_provider/_mcp_client.py +0 -0
  55. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/hermes_provider/_provider.py +0 -0
  56. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/hermes_provider/_shared.py +0 -0
  57. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/hermes_provider/evidence_budget.py +0 -0
  58. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/hermes_runtime.py +0 -0
  59. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/host_events.py +0 -0
  60. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/host_runtime.py +0 -0
  61. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/inbox.py +0 -0
  62. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/index.py +0 -0
  63. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/inspection.py +0 -0
  64. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/installer.py +0 -0
  65. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/llm/__init__.py +0 -0
  66. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/llm/base.py +0 -0
  67. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/llm/claude_compatible.py +0 -0
  68. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/llm/gemini.py +0 -0
  69. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/llm/openai_compatible.py +0 -0
  70. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/llm/router.py +0 -0
  71. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/llm/thinking.py +0 -0
  72. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/locking.py +0 -0
  73. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/mcp_server.py +0 -0
  74. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/memory_commit.py +0 -0
  75. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/memory_planner.py +0 -0
  76. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/memory_writer.py +0 -0
  77. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/model_capabilities.py +0 -0
  78. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/model_discovery.py +0 -0
  79. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/model_execution.py +0 -0
  80. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/models.py +0 -0
  81. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/native_index.py +0 -0
  82. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/native_registration.py +0 -0
  83. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/parallel_model.py +0 -0
  84. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/planning_context.py +0 -0
  85. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/process_common.py +0 -0
  86. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/process_jobs.py +0 -0
  87. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/process_journal.py +0 -0
  88. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/process_owner.py +0 -0
  89. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/processing.py +0 -0
  90. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/prompts.py +0 -0
  91. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/provenance.py +0 -0
  92. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/recording_policy.py +0 -0
  93. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/redaction.py +0 -0
  94. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/retention.py +0 -0
  95. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/retrieval.py +0 -0
  96. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/retrieval_gate.py +0 -0
  97. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/scope_maintenance.py +0 -0
  98. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/scope_state.py +0 -0
  99. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/service.py +0 -0
  100. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/source_policy.py +0 -0
  101. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/state_layout.py +0 -0
  102. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/subprocess_flags.py +0 -0
  103. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/summary_batch.py +0 -0
  104. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/target_reconciliation.py +0 -0
  105. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/turn_audit.py +0 -0
  106. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/turn_plan.py +0 -0
  107. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/update_coordinator.py +0 -0
  108. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/update_review.py +0 -0
  109. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/validation.py +0 -0
  110. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf/vault.py +0 -0
  111. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf.egg-info/SOURCES.txt +0 -0
  112. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf.egg-info/dependency_links.txt +0 -0
  113. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf.egg-info/entry_points.txt +0 -0
  114. {memleaf-0.2.56 → memleaf-0.2.58}/src/memleaf.egg-info/top_level.txt +0 -0
@@ -2,6 +2,19 @@
2
2
 
3
3
  All notable changes to memleaf are documented here.
4
4
 
5
+ ## 0.2.58 — 2026-09-15
6
+
7
+ - Make `due_date` mean only the stated deadline of the todo action. Core no longer fills it from a candidate's other date mentions, which could describe the subject or desired outcome rather than when the action is due. The B3 contract says to omit the field unless that action deadline is explicit; any supplied date remains subject to candidate-local deadline validation.
8
+ - Remove the Core-side inference and ambiguous-date counter emission. Date-to-action association is semantic: when the evidence does not establish an unambiguous deadline for the todo itself, omission is safer than converting a nearby date into a deadline.
9
+
10
+ Verification for this release used 18 local synthetic regression tests with no model call and no production Vault write. They cover the action-deadline instruction, omission of an unsupported `due_date`, candidate-local date grounding and deadline-cue boundaries. Python 3.11 compilation and `git diff --check` pass; real-model adherence and a newly installed Hermes replay remain post-release runtime acceptance.
11
+
12
+ ## 0.2.57 — 2026-09-14
13
+
14
+ - Let the model decide project ownership, and stop Core deciding it by string. Core required a model-selected project name to occur literally in the candidate's evidence, which cannot work: two descriptions of one project need share no substring, so "记录账单的项目" can never match a registered `记账`, and a literal test rejects a correct answer. It also cost whole memories. The reproduced turn is "跟你分享一下,最近在弄个记账的小玩意儿,就扔家里那台 N100 上跑,没打算上云"; the model named the project `记账小玩意儿`, the user wrote `记账的小玩意儿`, the literal test failed, and the candidate was deferred -- so the N100 deployment and the no-cloud decision were lost with the name. Deferring did not recover it either: deferred candidates are replayed from the journal rather than re-attempted, so a preview of that session makes zero model calls and processes zero turns. The guard is removed; a project name is a label, not a fact, and the model judges the ownership.
15
+ - State the rule generally, with no worked instance. The contract now says ownership is judged by meaning and never by wording, that a scope already listed in `scope_registry` is reused when the evidence means it even if the wording differs, and that a name does not have to appear in the evidence. A deferral is reserved for the case where the evidence is about a project but which project it is cannot be determined; a fact that simply has no project is `global` and is never deferred. An earlier draft stated that clause backwards and would have deferred every standing preference and environment fact. An earlier draft also carried a worked example naming one real project; an instance only ever helps the project it names, so it was removed and the same stability was obtained from the directive itself.
16
+ - Verification used the real model. 115 tests pass with no model call. Replaying the reproduced turn now writes the memory in both variants (with and without the assistant's reply). Four sentences were run against a registry holding one project: the same wording, a paraphrase ("我那个记录账单的小项目,部署挪到 Mac mini 上了"), an indirect reference, and an unrelated new project -- the first three all landed on the existing scope and the fourth correctly minted its own, so paraphrase is recognised and distinct projects are not merged. Six sentences carrying no project (a rule, a preference, an environment fact, a bare product mention) still resolved to `global` rather than deferring.
17
+
5
18
  ## 0.2.56 — 2026-09-14
6
19
 
7
20
  - Keep assistant reports source-safe at candidate granularity. Markdown headings, paragraphs and list items become exact immutable evidence units with section context; broad whole-report `whole_unit` claims are deferred, while short unstructured replies remain intact. An assistant-only offer, question or forward commitment cannot establish user intent, but a factual report can still be admitted when its evidence and future value are independently grounded.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memleaf
3
- Version: 0.2.56
3
+ Version: 0.2.58
4
4
  Summary: A local-first Markdown memory core for AI agents
5
5
  Author: memleaf contributors
6
6
  License-Expression: MIT
@@ -23,8 +23,9 @@ Dynamic: license-file
23
23
 
24
24
  [English](README.en.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
25
25
 
26
- > **版本:0.2.56。**
27
- > 自动提取按助手回复中的 Markdown 结构建立候选级来源,过宽的整段引用和未被用户接受的助手意图不会形成记忆;项目 Scope 只由候选自身证据确认,无法 grounding 的候选会延后而不会被改写为 `global`。日期和截止日期使用统一的边界安全解析,todo 只在候选自己的证据给出唯一明确截止日时填充。Markdown 仍是唯一事实源。
26
+ > **版本:0.2.58。**
27
+ > 待办 `due_date` 只表示待办动作本身明确声明的截止日;Core 不再从候选证据中的其他日期自动补填。属于待办主题或预期结果的日期不会被误作截止日,无法确认动作截止日时就省略。
28
+ > 自动提取按助手回复中的 Markdown 结构建立候选级来源,过宽的整段引用和未被用户接受的助手意图不会形成记忆。项目归属由模型按语义判断,不再要求项目名在证据里逐字出现:同一个项目换个说法也能落到已有 Scope 上,名字也不再决定这条记忆的生死。日期和截止日期使用统一的边界安全解析,todo 只在候选自己的证据给出唯一明确截止日时填充。Markdown 仍是唯一事实源。
28
29
  > **当前版本支持 Hermes 和 Codex。** Antigravity(反重力)不检测、不安装、不配置。
29
30
 
30
31
  ## 项目定位
@@ -4,8 +4,9 @@
4
4
 
5
5
  [中文](README.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
6
6
 
7
- > **Version: 0.2.56.**
8
- > Automatic extraction now creates candidate-local source units from Markdown structure in assistant replies; broad whole-report citations and assistant-only intent are not allowed to create memories. Project Scope is grounded only from each candidate's own evidence, and an ungrounded candidate is deferred instead of being rewritten as `global`. Dates and deadlines use one boundary-safe parser, and a todo receives a due date only when its own evidence supplies one unambiguous deadline. Markdown remains the sole source of truth with no SQLite runtime dependency. Acceptance covers deterministic regression suites and synthetic inputs; it does not claim real-mail or customer-business acceptance.
7
+ > **Version: 0.2.58.**
8
+ > A todo's `due_date` now means only the explicit deadline of the todo action. Core no longer fills it from other dates in candidate evidence; dates describing the todo's subject or desired outcome are not deadlines, and an unconfirmed action deadline is omitted.
9
+ > Automatic extraction now creates candidate-local source units from Markdown structure in assistant replies; broad whole-report citations and assistant-only intent are not allowed to create memories. Project ownership is the model's semantic judgement and no longer requires the project name to appear literally in the evidence: one project referred to in different words lands on the existing Scope, and the name no longer decides whether the memory survives. Dates and deadlines use one boundary-safe parser, and a todo receives a due date only when its own evidence supplies one unambiguous deadline. Markdown remains the sole source of truth with no SQLite runtime dependency. Acceptance covers deterministic regression suites and synthetic inputs; it does not claim real-mail or customer-business acceptance.
9
10
  > **The current release supports Hermes and Codex.** Antigravity is not detected, installed, or configured.
10
11
 
11
12
  ## Project scope
@@ -4,8 +4,9 @@
4
4
 
5
5
  [English](README.en.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
6
6
 
7
- > **版本:0.2.56。**
8
- > 自动提取按助手回复中的 Markdown 结构建立候选级来源,过宽的整段引用和未被用户接受的助手意图不会形成记忆;项目 Scope 只由候选自身证据确认,无法 grounding 的候选会延后而不会被改写为 `global`。日期和截止日期使用统一的边界安全解析,todo 只在候选自己的证据给出唯一明确截止日时填充。Markdown 仍是唯一事实源。
7
+ > **版本:0.2.58。**
8
+ > 待办 `due_date` 只表示待办动作本身明确声明的截止日;Core 不再从候选证据中的其他日期自动补填。属于待办主题或预期结果的日期不会被误作截止日,无法确认动作截止日时就省略。
9
+ > 自动提取按助手回复中的 Markdown 结构建立候选级来源,过宽的整段引用和未被用户接受的助手意图不会形成记忆。项目归属由模型按语义判断,不再要求项目名在证据里逐字出现:同一个项目换个说法也能落到已有 Scope 上,名字也不再决定这条记忆的生死。日期和截止日期使用统一的边界安全解析,todo 只在候选自己的证据给出唯一明确截止日时填充。Markdown 仍是唯一事实源。
9
10
  > **当前版本支持 Hermes 和 Codex。** Antigravity(反重力)不检测、不安装、不配置。
10
11
 
11
12
  ## 项目定位
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "memleaf"
7
- version = "0.2.56"
7
+ version = "0.2.58"
8
8
  description = "A local-first Markdown memory core for AI agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  """Local-first Markdown memory core for AI agents."""
2
2
 
3
- __version__ = "0.2.56"
3
+ __version__ = "0.2.58"
4
4
 
5
5
  from .config import DEFAULT_CONFIG, default_config, load_config, save_config
6
6
  from .frontmatter import FrontmatterError, dump_frontmatter, dump_yaml, load_yaml, parse_frontmatter
@@ -1,5 +1,5 @@
1
1
  name: memleaf
2
- version: 0.2.56
2
+ version: 0.2.58
3
3
  description: "Hermes-native external MemoryProvider for local-first Markdown memory shared with the memleaf MCP server."
4
4
  hooks:
5
5
  - prefetch
@@ -10,7 +10,6 @@ from __future__ import annotations
10
10
 
11
11
  import json
12
12
  from copy import deepcopy
13
- from dataclasses import replace
14
13
  from typing import Any, Iterable, Mapping, Optional
15
14
 
16
15
  from .admission import (
@@ -22,7 +21,6 @@ from .extraction_capability import supports_single_pass_protocol
22
21
  from .memory_planner import (
23
22
  MemoryPlanner,
24
23
  _explicit_project_scope_authorizations,
25
- _model_project_scope_is_source_grounded,
26
24
  )
27
25
  from .process_common import (
28
26
  ProcessingError,
@@ -80,23 +78,6 @@ def _claim_date_evidence(
80
78
  return result
81
79
 
82
80
 
83
- def _fill_unambiguous_todo_deadline(
84
- memory_type: Any,
85
- summary: Mapping[str, Any],
86
- deadline_dates: Iterable[str],
87
- ) -> tuple[dict[str, Any], bool]:
88
- """Fill an omitted todo date only when candidate evidence proves one deadline."""
89
-
90
- normalized = dict(summary)
91
- dates = {value for value in deadline_dates if isinstance(value, str)}
92
- if memory_type != "todo" or normalized.get("due_date") is not None:
93
- return normalized, False
94
- if len(dates) == 1:
95
- normalized["due_date"] = next(iter(dates))
96
- return normalized, False
97
- return normalized, len(dates) > 1
98
-
99
-
100
81
  def _global_scope_conflicts_with_candidate_evidence(
101
82
  scopes: Iterable[Any],
102
83
  candidate_evidence: Iterable[Mapping[str, Any]],
@@ -423,8 +404,6 @@ class SinglePassMemoryPlanner(MemoryPlanner):
423
404
  no_memory_by_unit: dict[str, str] = {}
424
405
  observed_scopes: list[str] = []
425
406
  requests: list[dict[str, Any]] = []
426
- ambiguous_todo_deadlines: set[str] = set()
427
-
428
407
  if not planning_units:
429
408
  self._finalize_evidence_audit(
430
409
  turn=turn,
@@ -543,33 +522,15 @@ class SinglePassMemoryPlanner(MemoryPlanner):
543
522
  "global scope conflicts with an explicit project label",
544
523
  validation_detail="scope_not_grounded",
545
524
  )
546
- # Scope grounding must use each candidate's exact admitted claims,
547
- # including their section context, rather than the complete sibling
548
- # units in the batch. An unproven project scope is deferred; it is
549
- # never silently rewritten as global or unscoped.
550
- candidate_scope_units = tuple(
551
- replace(
552
- by_unit[claim["unit_id"]],
553
- text=claim["quote"],
554
- start=0,
555
- end=len(claim["quote"]),
556
- )
557
- for claim in claims
558
- if isinstance(claim, Mapping)
559
- and isinstance(claim.get("unit_id"), str)
560
- and claim["unit_id"] in by_unit
561
- and isinstance(claim.get("quote"), str)
562
- )
563
- if decision in {"CREATE", "UPDATE"} and not _model_project_scope_is_source_grounded(
564
- candidate,
565
- candidate_scope_units,
566
- validation_scope_registry,
567
- authorized_project_scopes,
568
- ):
569
- raise ModelOutputError(
570
- "project scope is not grounded by this candidate's evidence",
571
- validation_detail="scope_not_grounded",
572
- )
525
+ # Ownership is a semantic judgement and belongs to the model, not
526
+ # to Core. Core used to require the project name to occur in the
527
+ # candidate's evidence, which cannot work: "记录账单的项目" and
528
+ # "记账" are the same project and share no substring, so a literal
529
+ # test rejects a correct answer, and a name the model composed from
530
+ # the user's own words ("记账小玩意儿" for "记账的小玩意儿") was
531
+ # refused and cost the whole memory. A project name is a label, not
532
+ # a fact, so the model's choice is kept; the guard against inventing
533
+ # ownership stays where it can be judged, in the contract.
573
534
  if (
574
535
  decision == "UPDATE"
575
536
  and target_memory is not None
@@ -618,11 +579,6 @@ class SinglePassMemoryPlanner(MemoryPlanner):
618
579
  summary["update_memory_id"] = target_memory.memory_id
619
580
  else:
620
581
  summary.setdefault("tags", [])
621
- summary, deadline_is_ambiguous = _fill_unambiguous_todo_deadline(
622
- memory_type, summary, deadline_dates
623
- )
624
- if deadline_is_ambiguous:
625
- ambiguous_todo_deadlines.add(candidate_id)
626
582
  summary["type"] = memory_type
627
583
  summary["scopes"] = scopes
628
584
  if isinstance(scope_source, str) and scope_source:
@@ -693,15 +649,6 @@ class SinglePassMemoryPlanner(MemoryPlanner):
693
649
  },
694
650
  )
695
651
 
696
- if ambiguous_todo_deadlines:
697
- metric = getattr(self.model, "_record_metric_event", None)
698
- if callable(metric):
699
- for _ in ambiguous_todo_deadlines:
700
- metric(
701
- {"stage": "single_pass", "operation": "single_pass_primary"},
702
- "b3_due_date_ambiguous_count",
703
- )
704
-
705
652
  raw_defer_details = result.get("_defer_details") if isinstance(result, Mapping) else None
706
653
  defer_details = (
707
654
  {key: value for key, value in raw_defer_details.items()
@@ -148,10 +148,10 @@ Keep independently retrievable facts useful for future answers, actions, commitm
148
148
 
149
149
  SCOPES
150
150
  Legal values: global | domain:<name> | portfolio:<name> | project:<name> | unscoped. scopes is a nonempty array; at most one project:<name> per memory; unscoped must be the only value, and Core then records insufficient_context.
151
- Scope to one project only when this candidate's evidence identifies it as owner of the work, decision, state or deadline; use a name present in that evidence, whether or not registered. A platform, product or vendor mention alone is not ownership; defer when ownership is unclear. Use global for cross-project facts, standing preferences and environment-wide rules.
151
+ Scope a candidate to a project when its evidence shows the user is doing that project's work, or shows that project owning the decision, state or deadline. Judge ownership by meaning, never by wording: name it with a short simple name, or reuse the scope already listed in scope_registry when the evidence means it, even if the wording differs. A name does not have to appear in the evidence. A platform, product or vendor mention alone is not ownership. Use global for a fact that no single project owns, such as a standing preference, a tool-wide or machine-wide rule, or an environment fact. Defer only when the evidence is about a project but which project it is cannot be determined; never guess a project, and never defer a fact that simply has none.
152
152
 
153
153
  DATES
154
- An evidence unit may carry an ISO-8601 UTC timestamp. Use it ONLY to resolve a relative, partial or yearless date that the unit's own text expresses; never borrow another unit's timestamp and never guess a missing year. The timestamp is an anchor, not content: never write its own date into a memory, and add no date the evidence text does not state. A date literal in a memory must appear in that memory's cited evidence, either verbatim or as the same month and day. Write due_date as YYYY-MM-DD; a todo with one unambiguous evidence-grounded deadline must include it. Omit due_date when no deadline is stated or it cannot be resolved. Any memory carrying a date that no admitted evidence grounds is rejected and costs the whole turn, so defer instead of approximating.
154
+ An evidence unit may carry an ISO-8601 UTC timestamp. Use it ONLY to resolve a relative, partial or yearless date that the unit's own text expresses; never borrow another unit's timestamp and never guess a missing year. The timestamp is an anchor, not content: never write its own date into a memory, and add no date the evidence text does not state. A date literal in a memory must appear in that memory's cited evidence, either verbatim or as the same month and day. due_date is only the stated deadline of the todo action, never a date belonging to its subject or desired outcome. Format it YYYY-MM-DD; otherwise omit it. Any memory carrying a date that no admitted evidence grounds is rejected and costs the whole turn, so defer instead of approximating.
155
155
 
156
156
  {B3_COMPACT_CONTRACT}"""
157
157
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memleaf
3
- Version: 0.2.56
3
+ Version: 0.2.58
4
4
  Summary: A local-first Markdown memory core for AI agents
5
5
  Author: memleaf contributors
6
6
  License-Expression: MIT
@@ -23,8 +23,9 @@ Dynamic: license-file
23
23
 
24
24
  [English](README.en.md) · [PyPI](https://pypi.org/project/memleaf/) · [GitHub](https://github.com/miffyblueboo/memleaf)
25
25
 
26
- > **版本:0.2.56。**
27
- > 自动提取按助手回复中的 Markdown 结构建立候选级来源,过宽的整段引用和未被用户接受的助手意图不会形成记忆;项目 Scope 只由候选自身证据确认,无法 grounding 的候选会延后而不会被改写为 `global`。日期和截止日期使用统一的边界安全解析,todo 只在候选自己的证据给出唯一明确截止日时填充。Markdown 仍是唯一事实源。
26
+ > **版本:0.2.58。**
27
+ > 待办 `due_date` 只表示待办动作本身明确声明的截止日;Core 不再从候选证据中的其他日期自动补填。属于待办主题或预期结果的日期不会被误作截止日,无法确认动作截止日时就省略。
28
+ > 自动提取按助手回复中的 Markdown 结构建立候选级来源,过宽的整段引用和未被用户接受的助手意图不会形成记忆。项目归属由模型按语义判断,不再要求项目名在证据里逐字出现:同一个项目换个说法也能落到已有 Scope 上,名字也不再决定这条记忆的生死。日期和截止日期使用统一的边界安全解析,todo 只在候选自己的证据给出唯一明确截止日时填充。Markdown 仍是唯一事实源。
28
29
  > **当前版本支持 Hermes 和 Codex。** Antigravity(反重力)不检测、不安装、不配置。
29
30
 
30
31
  ## 项目定位
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes