Skip to content
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
1cc7bba
docs(rfc): propose atomic memory as independent artifacts
frf12 Sep 30, 2026
9348391
feat(memory): implement independent atomic memory
frf12 Oct 5, 2026
2027559
fix(memory): repair migration receipts and normalize writes
frf12 Oct 6, 2026
d6dd04a
fix(memory): preserve history when NFC expands text
frf12 Oct 6, 2026
e860477
fix(atomic-memory): resolve runtime and transport regressions
frf12 Oct 6, 2026
df3dcc4
fix(atomic-memory): keep short reads on a consistent snapshot
frf12 Oct 6, 2026
2b90329
test(zcode): verify atomic memory source lineage
frf12 Oct 6, 2026
a5c35a2
test(dream): make superseded worker recovery deterministic
frf12 Oct 6, 2026
3d96ebd
fix(atomic-memory): align reconciliation and host contracts
frf12 Oct 6, 2026
acf1600
fix(ci): update atomic memory integration contracts
frf12 Oct 6, 2026
a6d1c37
fix(atomic-memory): preserve authorization and evidence boundaries
frf12 Oct 7, 2026
81540bf
test(atomic-memory): cover supervisor generation and automatic merge
frf12 Oct 7, 2026
46e4cee
test(oceanbase): isolate HTTP databases and enable CI coverage
frf12 Oct 7, 2026
f97529c
test(memory): add live temporal conflict coverage
frf12 Oct 7, 2026
25cec75
chore: merge upstream master into atomic memory
frf12 Oct 7, 2026
bc65ebd
fix(memory): tolerate candidate drift during context preparation
frf12 Oct 7, 2026
18fde95
fix(dify): align atomic memory tools after upstream merge
frf12 Oct 7, 2026
51f288e
feat(artifacts): share merge and restoration across families
frf12 Oct 8, 2026
7000204
chore: merge upstream master into atomic memory
frf12 Oct 8, 2026
3177357
fix(artifacts): append revisions when restoring merge groups
frf12 Oct 8, 2026
8b5d5aa
fix(memory): clarify temporal fact reconciliation
frf12 Oct 8, 2026
5907753
chore: sync atomic memory dependency and resolve conflicts
frf12 Oct 8, 2026
f483d8a
fix(memory): reconcile against current published content
frf12 Oct 8, 2026
f1b7748
chore: add missing test license headers
frf12 Oct 8, 2026
f09cae4
fix(memory): keep creation metadata out of model output
frf12 Oct 9, 2026
6d0d440
fix(atomic-memory): restore scope retrieval authorization
frf12 Oct 9, 2026
7b54fde
merge: integrate master artifact search
frf12 Oct 9, 2026
77dc6f7
fix(desktop): repair atomic memory integration
frf12 Oct 9, 2026
f702c04
fix(server): advertise atomic memory capabilities
frf12 Oct 9, 2026
1f9b91c
fix(desktop): qualify atomic memory protocol
frf12 Oct 9, 2026
2405d0a
merge: integrate evaluation suite reorganization
frf12 Oct 9, 2026
a02e77d
Merge upstream/master into codex/atomic-memory
frf12 Oct 9, 2026
9bebc45
docs(memory): add atomic memory clean migration design
frf12 Oct 9, 2026
196dfc0
test(dify): exercise the Atomic search hit schema in contract regener…
frf12 Oct 9, 2026
d100439
refactor(atomic-memory): use shared access control instead of a famil…
frf12 Oct 9, 2026
e72c999
fix(desktop): report the fixture contract digest from the real-Server…
frf12 Oct 9, 2026
d4ea42f
refactor(memory): serve legacy Memory routes from Atomic Memory at th…
frf12 Oct 10, 2026
9b88e2c
fix(desktop): keep contract digest in compatibility selection
frf12 Oct 10, 2026
5fddc0c
refactor(atomic-memory): import entries with their direct evidence
frf12 Oct 10, 2026
fd830a3
Merge upstream/master into codex/atomic-memory
frf12 Oct 10, 2026
6ba2d44
refactor(tags): drop legacy Memory entry tag targets
frf12 Oct 10, 2026
8b7a953
feat(atomic-memory): archive legacy Memory and convert references
frf12 Oct 10, 2026
e8e6b25
fix(atomic-memory): close migration gaps found in review
frf12 Oct 10, 2026
6e923f3
refactor(atomic-memory): remove legacy Memory from the runtime and co…
frf12 Oct 10, 2026
33d9320
Merge upstream/master into codex/atomic-memory
frf12 Oct 10, 2026
97c5b84
chore: sync atomic memory migration and shared access
frf12 Oct 10, 2026
cdd4b7e
chore: sync master recall gate and statistics
frf12 Oct 10, 2026
62da8c3
chore: record latest atomic memory dependency
frf12 Oct 10, 2026
f69c2f9
Merge upstream/master into codex/atomic-memory
frf12 Oct 10, 2026
d233cc8
test: sync integration fixtures with atomic memory contract
frf12 Oct 10, 2026
400602e
chore(skill-up): refresh tool contract fixtures without legacy Memory…
frf12 Oct 10, 2026
3be389c
fix(atomic-memory): finish clean migration and receipt compatibility
frf12 Oct 10, 2026
38432c5
fix(atomic-memory): close migration boundary and validation gaps
frf12 Oct 10, 2026
8097d38
chore(skill-up): refresh migrated memory guidance pin
frf12 Oct 10, 2026
60eb009
chore(desktop): refresh generated migration contract
frf12 Oct 10, 2026
50c3568
ci: serialize atomic memory migration acceptance
frf12 Oct 10, 2026
f912f99
fix(memory): support long SQLite full-text queries
frf12 Oct 10, 2026
fefc285
chore: sync latest atomic memory changes
frf12 Oct 11, 2026
cee50bc
chore: sync master after atomic memory merge
frf12 Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
172 changes: 172 additions & 0 deletions .github/workflows/e2e-harness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,127 @@ jobs:
if: always()
run: docker rm --force recall-effort-oceanbase || true

atomic-memory-clean-oceanbase:
name: Atomic Memory clean migration (OceanBase)
if: github.event_name != 'workflow_dispatch' || inputs.suite != 'recall-effort'
runs-on: ubuntu-latest
timeout-minutes: 60
env:
OCEANBASE_IMAGE: ghcr.io/oceanbase/oceanbase-ce:4.3.5.6-106000012026040916
POWERCONTEXT_TEST_MIGRATION_OCEANBASE_URL: >-
mysql+aoceanbase://root%40test:powercontext-e2e@127.0.0.1:2881/powercontext_test?charset=utf8mb4
PYTHONUNBUFFERED: "1"
MIGRATION_REPORTS: ${{ github.workspace }}/.powercontext/atomic-memory-clean-oceanbase
steps:
- name: Check out
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Set up the environment
uses: ./.github/actions/setup-python-env
with:
python-version: "3.12"

- name: Start the isolated OceanBase test instance
run: |
docker run --detach --name atomic-memory-clean-oceanbase \
--publish 127.0.0.1:2881:2881 \
--ulimit nofile=65536:65536 \
--env MODE=slim \
--env OB_DATABASE=powercontext_test \
--env OB_TENANT_PASSWORD=powercontext-e2e \
"$OCEANBASE_IMAGE"
for attempt in $(seq 1 120); do
if docker exec atomic-memory-clean-oceanbase \
obclient -h127.0.0.1 -P2881 -uroot@test -ppowercontext-e2e \
-Dpowercontext_test -e 'SELECT 1' >/dev/null 2>&1; then
# The slim image's default 1 GB maximum is too small for the
# indexes created across the clean migration acceptance cases.
docker exec atomic-memory-clean-oceanbase \
obclient -h127.0.0.1 -P2881 -uroot@sys \
-e "ALTER SYSTEM SET datafile_maxsize='8G'; ALTER SYSTEM SET datafile_next='512M'; ALTER SYSTEM SET datafile_size='4G';"
datafile_ready=false
for config_attempt in $(seq 1 30); do
docker exec atomic-memory-clean-oceanbase \
obclient -h127.0.0.1 -P2881 -uroot@sys --batch --skip-column-names \
-e "SHOW PARAMETERS WHERE name IN ('datafile_size', 'datafile_maxsize', 'datafile_next');" \
> "$RUNNER_TEMP/atomic-memory-datafile.tsv"
if awk '
$5 == "datafile_size" && $7 == "4G" { size = 1 }
$5 == "datafile_maxsize" && $7 == "8G" { maximum = 1 }
$5 == "datafile_next" && $7 == "512M" { increment = 1 }
END { exit !(size && maximum && increment) }
' "$RUNNER_TEMP/atomic-memory-datafile.tsv"; then
datafile_ready=true
break
fi
sleep 2
done
cat "$RUNNER_TEMP/atomic-memory-datafile.tsv"
if [ "$datafile_ready" != true ]; then
echo 'OceanBase datafile configuration did not become effective within one minute.' >&2
exit 1
fi
docker exec atomic-memory-clean-oceanbase \
obclient -h127.0.0.1 -P2881 -uroot@test -ppowercontext-e2e \
-Dpowercontext_test \
-e "SET GLOBAL recyclebin=OFF; SELECT VERSION(); SHOW VARIABLES LIKE 'ob_compatibility_mode'; SHOW VARIABLES LIKE 'recyclebin';"
exit 0
fi
if [ "$(docker inspect --format '{{.State.Running}}' atomic-memory-clean-oceanbase)" != true ]; then
echo 'OceanBase exited before becoming ready.' >&2
exit 1
fi
sleep 5
done
echo 'OceanBase did not become ready within 10 minutes.' >&2
exit 1

- name: Run clean migration evidence, grants and vectors without skips
timeout-minutes: 45
run: |
uv run --locked python scripts/run_atomic_memory_clean_migration.py \
oceanbase --output "$MIGRATION_REPORTS"

- name: Collect the database log
if: always()
run: |
mkdir -p "$MIGRATION_REPORTS"
docker logs atomic-memory-clean-oceanbase > "$MIGRATION_REPORTS/oceanbase.log" 2>&1 || true
for logfile in observer.log observer.log.wf; do
docker exec atomic-memory-clean-oceanbase tail -n 20000 "/root/demo/log/$logfile" \
> "$MIGRATION_REPORTS/$logfile" 2>&1 || true
done
docker inspect --format 'MemoryBytes={{.HostConfig.Memory}} NanoCpus={{.HostConfig.NanoCpus}} CpuQuota={{.HostConfig.CpuQuota}}' \
atomic-memory-clean-oceanbase > "$MIGRATION_REPORTS/container-resources.txt" 2>&1 || true
docker stats --no-stream atomic-memory-clean-oceanbase \
> "$MIGRATION_REPORTS/container-stats.txt" 2>&1 || true
docker exec atomic-memory-clean-oceanbase \
obclient -h127.0.0.1 -P2881 -uroot@sys \
-e "SHOW PARAMETERS WHERE name IN ('datafile_size', 'datafile_maxsize', 'datafile_next', 'memory_limit', 'system_memory', 'cpu_count');" \
> "$MIGRATION_REPORTS/database-parameters.txt" 2>&1 || true

- name: Save complete observer logs on failure
if: failure()
run: |
mkdir -p "$MIGRATION_REPORTS/observer"
docker cp atomic-memory-clean-oceanbase:/root/demo/log/. "$MIGRATION_REPORTS/observer/" || true

- name: Save clean migration reports
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: atomic-memory-clean-oceanbase-${{ github.sha }}
path: ${{ env.MIGRATION_REPORTS }}/
include-hidden-files: true
if-no-files-found: error
retention-days: 7

- name: Stop and remove the test instance
if: always()
run: docker rm --force atomic-memory-clean-oceanbase || true

acceptance:
needs: validate
runs-on: ubuntu-latest
Expand All @@ -184,6 +305,57 @@ jobs:
with:
version: ${{ env.UV_VERSION }}

- name: Verify OceanBase Atomic Memory and HTTP regressions
if: matrix.database == 'oceanbase'
env:
COMPOSE_PROJECT_NAME: powercontext-e2e-oceanbase
POWERCONTEXT_E2E_OUTPUT: ${{ github.workspace }}/.powercontext-e2e/oceanbase/acceptance
run: |
mkdir -p "$POWERCONTEXT_E2E_OUTPUT"
compose=(docker compose -f e2e/bub/compose.yaml -f e2e/bub/compose.oceanbase.yaml)
"${compose[@]}" up --detach --wait --wait-timeout 660 oceanbase
container_id=$("${compose[@]}" ps -q oceanbase)
oceanbase_ip=$(docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$container_id")
test -n "$oceanbase_ip"
export POWERCONTEXT_TEST_OCEANBASE_URL="mysql+aoceanbase://root%40test:powercontext-e2e@${oceanbase_ip}:2881/powercontext?charset=utf8mb4"
uv run --locked --extra server python - <<'PY'
import asyncio
import os

from pydantic import SecretStr

from powercontext.builtin.persistence.oceanbase import OceanBaseConfig, OceanBaseProfile

async def version():
config = OceanBaseConfig(url=SecretStr(os.environ["POWERCONTEXT_TEST_OCEANBASE_URL"]))
async with OceanBaseProfile.open(config, tables=()) as profile:
async with profile.database.transaction() as connection:
result = await connection.exec_driver_sql("SELECT VERSION()")
print("OceanBase engine:", result.scalar_one())

asyncio.run(version())
PY
uv run --locked --extra server python -m pytest -vv -ra \
tests/e2e/test_atomic_memory_search_authorization_snapshot.py \
tests/e2e/test_atomic_memory_read_snapshot.py \
tests/e2e/test_runtime_server.py -k oceanbase \
--junitxml="$RUNNER_TEMP/atomic-memory-oceanbase-snapshots.xml"
uv run --locked --extra server python - <<'PY'
import json
import os
import xml.etree.ElementTree as ET
from pathlib import Path

suites = ET.parse(Path(os.environ["RUNNER_TEMP"]) / "atomic-memory-oceanbase-snapshots.xml").iter("testsuite")
counts = {key: 0 for key in ("tests", "failures", "errors", "skipped")}
for suite in suites:
for key in counts:
counts[key] += int(suite.get(key, "0"))
print("OceanBase Atomic Memory and HTTP results:", json.dumps(counts))
if not counts["tests"] or any(counts[key] for key in ("failures", "errors", "skipped")):
raise SystemExit("OceanBase Atomic Memory and HTTP regressions must execute without failures, errors, or skips")
PY

- name: Run deterministic scenarios
id: acceptance_scenarios
env:
Expand Down
50 changes: 50 additions & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,56 @@ jobs:
seekdb-native.log
if-no-files-found: ignore

atomic-memory-clean-seekdb:
name: Atomic Memory clean migration (SeekDB)
timeout-minutes: 40
runs-on: ubuntu-latest
env:
POWERCONTEXT_TEST_MIGRATION_SEEKDB: "1"
PYTHONUNBUFFERED: "1"
MIGRATION_REPORTS: ${{ github.workspace }}/.powercontext/atomic-memory-clean-seekdb
steps:
- name: Check out
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Set up the environment
uses: ./.github/actions/setup-python-env
with:
python-version: "3.12"

- name: Run clean migration evidence, grants and vectors without skips
timeout-minutes: 35
env:
TMPDIR: ${{ runner.temp }}/am-seekdb
run: |
mkdir -p "$TMPDIR"
uv run --locked --extra seekdb python scripts/run_atomic_memory_clean_migration.py \
seekdb --output "$MIGRATION_REPORTS"

- name: Collect native diagnostics
if: always()
env:
TMPDIR: ${{ runner.temp }}/am-seekdb
run: |
mkdir -p "$MIGRATION_REPORTS"
df -h . /tmp > "$MIGRATION_REPORTS/disk.txt"
if [ -d "$TMPDIR" ]; then
find "$TMPDIR" -type f \( -name '*.log' -o -name '*.log.wf' \) \
-print -exec tail -c 8388608 {} \; > "$MIGRATION_REPORTS/seekdb-native.log"
fi

- name: Save clean migration reports
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: atomic-memory-clean-seekdb-${{ github.sha }}
path: ${{ env.MIGRATION_REPORTS }}/
include-hidden-files: true
if-no-files-found: error
retention-days: 7

windows-unit-portability:
timeout-minutes: 20
runs-on: windows-latest
Expand Down
8 changes: 4 additions & 4 deletions desktop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ Profiles persist under the app data directory; credentials never appear in profi

After explicitly activating a qualified connection and choosing a Scope, use Home's note form or **My memories → Add note**. The target connection and exact Scope are shown before submission. Enter inserts a newline; only the save button submits. The input is plain text, limited conservatively to 8192 raw UTF-8 bytes without truncation. The Server owns normalization and the returned text is authoritative.

Search uses FTS in the selected Scope and returns at most 10 matches. This is not a full directory or history, and ten matches do not establish a total count. **Read exact version** sends the complete returned citation; it never substitutes the latest version. Copy buttons explicitly copy either the full plain text or citation JSON.
Search uses FTS in the selected Scope and returns at most 10 matches. This is not a full directory or history, and ten matches do not establish a total count. **Read exact version** reads the returned Atomic Memory reference (`{family: "atomic-memory", artifact_id, revision}`) at that exact revision; it never substitutes the latest version. Copy buttons explicitly copy either the full plain text or the reference JSON.

A successful save without an entry is reported as an operation success without inventing a citation. A timeout or interrupted dispatched write is **unknown**, not a safe invitation to retry: inspect the original Server/Scope before deciding whether to submit again. Identical text alone cannot identify that operation. Desktop does not automatically replay writes or keep an offline queue. Switching context hides old results while retaining minimal original-operation metadata for this session. See [validation guide](VALIDATION.md) for tested behavior and qualification gaps.
A successful save that returns no memory record is reported as an operation success without inventing a reference. A timeout or interrupted dispatched write is **unknown**, not a safe invitation to retry: inspect the original Server/Scope before deciding whether to submit again. Identical text alone cannot identify that operation. Desktop does not automatically replay writes or keep an offline queue. Switching context hides old results while retaining minimal original-operation metadata for this session. See [validation guide](VALIDATION.md) for tested behavior and qualification gaps.

## Contracts and resources

Expand Down Expand Up @@ -104,7 +104,7 @@ Version verification has a 15-second deadline, service status 20 seconds, and in

## Remote installed-package acceptance

Windows GitHub Actions builds an unsigned installer, installs into a temporary Chinese path, and uses a matching Microsoft-signed WebDriver to operate the actual installed WebView2 page. An independent SQLite Server with synthetic data supports explicit connection activation, exact Scope selection, multiline Chinese note save, FTS search, exact reading, and paste-back verification of copied text and citation. The fixture Server and its temporary workspace are cleaned up afterward.
Windows GitHub Actions builds an unsigned installer, installs into a temporary Chinese path, and uses a matching Microsoft-signed WebDriver to operate the actual installed WebView2 page. An independent SQLite Server with synthetic data supports explicit connection activation, exact Scope selection, multiline Chinese note save, FTS search, exact reading, and paste-back verification of copied text and reference. The fixture Server and its temporary workspace are cleaned up afterward.

Reports, a screenshot and driver logs accompany the installer in the `desktop-windows-internal-unsigned` artifact. Failed or pending steps are not acceptance passes. The UI script permits only GitHub Windows runners and does not operate your local desktop. Hosted runners do not establish clean standard-user Windows 11, actual IME, screen-reader or Agent-host qualification.

Expand All @@ -116,4 +116,4 @@ The CI-only lifecycle scenario forcibly ends its own installed Desktop process a

Installed boundary checks exercise an 8192-byte Unicode note, reject over-budget input, display zero and capped-ten search results, and verify cancel/confirm behavior when disconnecting with an unsaved draft. Each result requires its matching remote report.

After upgrading from the earlier preview, select `sqlite-6e237568-v1` and recheck your connection. The previous `sqlite-1.1.1-v1` / `sqlite-63f918b7-v1` / `sqlite-ab43e3a7-v1` / `sqlite-f1089f4e-v1` selection is not silently upgraded to a different contract. See [current qualification](VALIDATION.md).
After upgrading from an earlier preview, select `sqlite-atomic-f702c041-v1` and recheck your connection. A previous `sqlite-1.1.1-v1` / `sqlite-63f918b7-v1` / `sqlite-ab43e3a7-v1` / `sqlite-f1089f4e-v1` / `sqlite-6e237568-v1` / `sqlite-legacy-58f7f4f6-v1` selection is not silently upgraded to a different contract. See [current qualification](VALIDATION.md).
6 changes: 3 additions & 3 deletions desktop/README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ Desktop 在每次诊断前检查固定路径、摘要,并用固定的 `--versi

明确启用合格连接并选择精确范围后,在首页填写笔记,或在「我的记忆」中点击「记一条」。提交前会显示目标连接和范围。Enter 只换行,点击保存才提交。正文是纯文本,保守限制为原始文本最多 8192 个 UTF-8 字节,不会截断;规范化由 Server 完成,以返回的正文为准。

全文搜索只在当前范围执行,每次最多返回 10 条,不代表完整目录、历史或总数。阅读使用完整引用读取精确版本,不自动改读最新版本。复制按钮分别复制纯文本正文和引用 JSON。
全文搜索只在当前范围执行,每次最多返回 10 条,不代表完整目录、历史或总数。阅读按返回的 Atomic Memory 引用(`{family: "atomic-memory", artifact_id, revision}`)读取该精确版本,不自动改读最新版本。复制按钮分别复制纯文本正文和引用 JSON。

保存成功但没有返回 entry 时,只报告操作成功,不编造引用。请求发出后的超时或中断可能意味着「结果未知」:先核对原连接和范围,再决定是否重新提交;相同正文不能证明属于这次操作。应用不会自动重试写入,也没有离线队列。切换连接或范围后隐藏旧结果,本次会话只保留最小操作状态和原目标。测试范围与剩余验收见 [验证说明](VALIDATION.md)。
保存成功但没有返回记忆记录时,只报告操作成功,不编造引用。请求发出后的超时或中断可能意味着「结果未知」:先核对原连接和范围,再决定是否重新提交;相同正文不能证明属于这次操作。应用不会自动重试写入,也没有离线队列。切换连接或范围后隐藏旧结果,本次会话只保留最小操作状态和原目标。测试范围与剩余验收见 [验证说明](VALIDATION.md)。

[验证说明](VALIDATION.md)列出可复现的检查方式和待完成的平台、产品验收项。

Expand All @@ -98,4 +98,4 @@ Windows GitHub Actions 会构建未签名安装包,安装到临时中文路径

安装版边界测试覆盖 8192 字节 Unicode 正文、超限输入禁止提交、搜索无结果和最多 10 条的提示,以及未保存草稿时取消或确认断开连接的行为。是否通过以对应远程报告为准。

从早期预览版升级后,请选择 `sqlite-6e237568-v1` 并重新检查连接。旧的 `sqlite-1.1.1-v1` / `sqlite-63f918b7-v1` / `sqlite-ab43e3a7-v1` / `sqlite-f1089f4e-v1` 选择不会静默升级为另一份契约。当前验证范围见[验证说明](VALIDATION.md)。
从早期预览版升级后,请选择 `sqlite-atomic-f702c041-v1` 并重新检查连接。旧的 `sqlite-1.1.1-v1` / `sqlite-63f918b7-v1` / `sqlite-ab43e3a7-v1` / `sqlite-f1089f4e-v1` / `sqlite-6e237568-v1` / `sqlite-legacy-58f7f4f6-v1` 选择不会静默升级为另一份契约。当前验证范围见[验证说明](VALIDATION.md)。
Loading
Loading