Skip to content

Commit fefc285

Browse files
committed
chore: sync latest atomic memory changes
2 parents d233cc8 + f912f99 commit fefc285

57 files changed

Lines changed: 2168 additions & 1510 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/e2e-harness.yml‎

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,127 @@ jobs:
163163
if: always()
164164
run: docker rm --force recall-effort-oceanbase || true
165165

166+
atomic-memory-clean-oceanbase:
167+
name: Atomic Memory clean migration (OceanBase)
168+
if: github.event_name != 'workflow_dispatch' || inputs.suite != 'recall-effort'
169+
runs-on: ubuntu-latest
170+
timeout-minutes: 60
171+
env:
172+
OCEANBASE_IMAGE: ghcr.io/oceanbase/oceanbase-ce:4.3.5.6-106000012026040916
173+
POWERCONTEXT_TEST_MIGRATION_OCEANBASE_URL: >-
174+
mysql+aoceanbase://root%40test:powercontext-e2e@127.0.0.1:2881/powercontext_test?charset=utf8mb4
175+
PYTHONUNBUFFERED: "1"
176+
MIGRATION_REPORTS: ${{ github.workspace }}/.powercontext/atomic-memory-clean-oceanbase
177+
steps:
178+
- name: Check out
179+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
180+
with:
181+
persist-credentials: false
182+
183+
- name: Set up the environment
184+
uses: ./.github/actions/setup-python-env
185+
with:
186+
python-version: "3.12"
187+
188+
- name: Start the isolated OceanBase test instance
189+
run: |
190+
docker run --detach --name atomic-memory-clean-oceanbase \
191+
--publish 127.0.0.1:2881:2881 \
192+
--ulimit nofile=65536:65536 \
193+
--env MODE=slim \
194+
--env OB_DATABASE=powercontext_test \
195+
--env OB_TENANT_PASSWORD=powercontext-e2e \
196+
"$OCEANBASE_IMAGE"
197+
for attempt in $(seq 1 120); do
198+
if docker exec atomic-memory-clean-oceanbase \
199+
obclient -h127.0.0.1 -P2881 -uroot@test -ppowercontext-e2e \
200+
-Dpowercontext_test -e 'SELECT 1' >/dev/null 2>&1; then
201+
# The slim image's default 1 GB maximum is too small for the
202+
# indexes created across the clean migration acceptance cases.
203+
docker exec atomic-memory-clean-oceanbase \
204+
obclient -h127.0.0.1 -P2881 -uroot@sys \
205+
-e "ALTER SYSTEM SET datafile_maxsize='8G'; ALTER SYSTEM SET datafile_next='512M'; ALTER SYSTEM SET datafile_size='4G';"
206+
datafile_ready=false
207+
for config_attempt in $(seq 1 30); do
208+
docker exec atomic-memory-clean-oceanbase \
209+
obclient -h127.0.0.1 -P2881 -uroot@sys --batch --skip-column-names \
210+
-e "SHOW PARAMETERS WHERE name IN ('datafile_size', 'datafile_maxsize', 'datafile_next');" \
211+
> "$RUNNER_TEMP/atomic-memory-datafile.tsv"
212+
if awk '
213+
$5 == "datafile_size" && $7 == "4G" { size = 1 }
214+
$5 == "datafile_maxsize" && $7 == "8G" { maximum = 1 }
215+
$5 == "datafile_next" && $7 == "512M" { increment = 1 }
216+
END { exit !(size && maximum && increment) }
217+
' "$RUNNER_TEMP/atomic-memory-datafile.tsv"; then
218+
datafile_ready=true
219+
break
220+
fi
221+
sleep 2
222+
done
223+
cat "$RUNNER_TEMP/atomic-memory-datafile.tsv"
224+
if [ "$datafile_ready" != true ]; then
225+
echo 'OceanBase datafile configuration did not become effective within one minute.' >&2
226+
exit 1
227+
fi
228+
docker exec atomic-memory-clean-oceanbase \
229+
obclient -h127.0.0.1 -P2881 -uroot@test -ppowercontext-e2e \
230+
-Dpowercontext_test \
231+
-e "SET GLOBAL recyclebin=OFF; SELECT VERSION(); SHOW VARIABLES LIKE 'ob_compatibility_mode'; SHOW VARIABLES LIKE 'recyclebin';"
232+
exit 0
233+
fi
234+
if [ "$(docker inspect --format '{{.State.Running}}' atomic-memory-clean-oceanbase)" != true ]; then
235+
echo 'OceanBase exited before becoming ready.' >&2
236+
exit 1
237+
fi
238+
sleep 5
239+
done
240+
echo 'OceanBase did not become ready within 10 minutes.' >&2
241+
exit 1
242+
243+
- name: Run clean migration evidence, grants and vectors without skips
244+
timeout-minutes: 45
245+
run: |
246+
uv run --locked python scripts/run_atomic_memory_clean_migration.py \
247+
oceanbase --output "$MIGRATION_REPORTS"
248+
249+
- name: Collect the database log
250+
if: always()
251+
run: |
252+
mkdir -p "$MIGRATION_REPORTS"
253+
docker logs atomic-memory-clean-oceanbase > "$MIGRATION_REPORTS/oceanbase.log" 2>&1 || true
254+
for logfile in observer.log observer.log.wf; do
255+
docker exec atomic-memory-clean-oceanbase tail -n 20000 "/root/demo/log/$logfile" \
256+
> "$MIGRATION_REPORTS/$logfile" 2>&1 || true
257+
done
258+
docker inspect --format 'MemoryBytes={{.HostConfig.Memory}} NanoCpus={{.HostConfig.NanoCpus}} CpuQuota={{.HostConfig.CpuQuota}}' \
259+
atomic-memory-clean-oceanbase > "$MIGRATION_REPORTS/container-resources.txt" 2>&1 || true
260+
docker stats --no-stream atomic-memory-clean-oceanbase \
261+
> "$MIGRATION_REPORTS/container-stats.txt" 2>&1 || true
262+
docker exec atomic-memory-clean-oceanbase \
263+
obclient -h127.0.0.1 -P2881 -uroot@sys \
264+
-e "SHOW PARAMETERS WHERE name IN ('datafile_size', 'datafile_maxsize', 'datafile_next', 'memory_limit', 'system_memory', 'cpu_count');" \
265+
> "$MIGRATION_REPORTS/database-parameters.txt" 2>&1 || true
266+
267+
- name: Save complete observer logs on failure
268+
if: failure()
269+
run: |
270+
mkdir -p "$MIGRATION_REPORTS/observer"
271+
docker cp atomic-memory-clean-oceanbase:/root/demo/log/. "$MIGRATION_REPORTS/observer/" || true
272+
273+
- name: Save clean migration reports
274+
if: always()
275+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
276+
with:
277+
name: atomic-memory-clean-oceanbase-${{ github.sha }}
278+
path: ${{ env.MIGRATION_REPORTS }}/
279+
include-hidden-files: true
280+
if-no-files-found: error
281+
retention-days: 7
282+
283+
- name: Stop and remove the test instance
284+
if: always()
285+
run: docker rm --force atomic-memory-clean-oceanbase || true
286+
166287
acceptance:
167288
needs: validate
168289
runs-on: ubuntu-latest

‎.github/workflows/master.yml‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,56 @@ jobs:
205205
seekdb-native.log
206206
if-no-files-found: ignore
207207

208+
atomic-memory-clean-seekdb:
209+
name: Atomic Memory clean migration (SeekDB)
210+
timeout-minutes: 40
211+
runs-on: ubuntu-latest
212+
env:
213+
POWERCONTEXT_TEST_MIGRATION_SEEKDB: "1"
214+
PYTHONUNBUFFERED: "1"
215+
MIGRATION_REPORTS: ${{ github.workspace }}/.powercontext/atomic-memory-clean-seekdb
216+
steps:
217+
- name: Check out
218+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
219+
with:
220+
persist-credentials: false
221+
222+
- name: Set up the environment
223+
uses: ./.github/actions/setup-python-env
224+
with:
225+
python-version: "3.12"
226+
227+
- name: Run clean migration evidence, grants and vectors without skips
228+
timeout-minutes: 35
229+
env:
230+
TMPDIR: ${{ runner.temp }}/am-seekdb
231+
run: |
232+
mkdir -p "$TMPDIR"
233+
uv run --locked --extra seekdb python scripts/run_atomic_memory_clean_migration.py \
234+
seekdb --output "$MIGRATION_REPORTS"
235+
236+
- name: Collect native diagnostics
237+
if: always()
238+
env:
239+
TMPDIR: ${{ runner.temp }}/am-seekdb
240+
run: |
241+
mkdir -p "$MIGRATION_REPORTS"
242+
df -h . /tmp > "$MIGRATION_REPORTS/disk.txt"
243+
if [ -d "$TMPDIR" ]; then
244+
find "$TMPDIR" -type f \( -name '*.log' -o -name '*.log.wf' \) \
245+
-print -exec tail -c 8388608 {} \; > "$MIGRATION_REPORTS/seekdb-native.log"
246+
fi
247+
248+
- name: Save clean migration reports
249+
if: always()
250+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
251+
with:
252+
name: atomic-memory-clean-seekdb-${{ github.sha }}
253+
path: ${{ env.MIGRATION_REPORTS }}/
254+
include-hidden-files: true
255+
if-no-files-found: error
256+
retention-days: 7
257+
208258
windows-unit-portability:
209259
timeout-minutes: 20
210260
runs-on: windows-latest

‎desktop/src-tauri/src/transport/operations.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"contractSha256": "14042de547922b20804bd5503a5eeb2e2ad29079156135a1566e03567d3aa7f1",
2+
"contractSha256": "6ac34926b9c7f4fa975512833ca026ec43da9073e92b53068e2a987b730f2bb8",
33
"operations": {
44
"get_liveness": {
55
"method": "GET",

‎desktop/ui/src/generated/api.d.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ export interface paths {
989989
put?: never;
990990
/**
991991
* Unsupported continuous legacy collection changes
992-
* @description Continuous legacy collection changes have no Atomic equivalent and return operation_not_supported. Exact historical references remain readable.
992+
* @description Continuous legacy collection changes have no Atomic equivalent and return operation_not_supported. Legacy collection history is archived offline; read exact Atomic Memory revisions through the Artifact API.
993993
*/
994994
post: operations["list_memory_changes"];
995995
delete?: never;
@@ -6552,7 +6552,7 @@ export interface operations {
65526552
};
65536553
};
65546554
responses: {
6555-
/** @description Compact changes through the selected Memory Revision. */
6555+
/** @description Reserved legacy response shape; this operation returns operation_not_supported. */
65566556
200: {
65576557
headers: {
65586558
"X-PowerContext-Request-ID": components["headers"]["RequestId"];

‎desktop/ui/src/generated/operations.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
// Generated from openapi/powercontext.yaml. Do not edit.
18-
export const contractSha256 = "14042de547922b20804bd5503a5eeb2e2ad29079156135a1566e03567d3aa7f1";
18+
export const contractSha256 = "6ac34926b9c7f4fa975512833ca026ec43da9073e92b53068e2a987b730f2bb8";
1919
export const operations = {
2020
"get_liveness": {
2121
"method": "GET",

‎docs/en/docs/operate/atomic-memory-migration.md‎

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,11 @@ Apply runs these steps in order; each can be repeated after an interruption:
107107
from online lineage, Candidate `artifact_refs`, Task Outcome `produced_artifacts`, and `kind: artifact`
108108
citations of a whole collection in Handoff content and Work claims or checks. A Handoff receipt's
109109
`unavailable_evidence` records evidence that was unavailable rather than support: its collection references
110-
move unchanged into the receipt's `historical_data` (format `powercontext.handoff-receipt-history.v1`), which
111-
is shown as history and never resolved.
110+
remain unchanged in that field as historical unavailable addresses. Reading the receipt does not query
111+
the archive, and these addresses cannot support new requests. Exact entry citations still become Atomic references.
112112
5. Finished Dream runs move to a historical format: the original request, input manifest and request digest
113-
move to `historical_data` and are no longer read as an executable request. Unfinished runs drop the empty
114-
legacy entry citation fields from their request and input manifest. Request digests are recomputed in the
113+
move to `historical_data` and are no longer read as an executable request. Unfinished runs without legacy
114+
snapshots drop the empty entry citation field from their request. Request digests are recomputed in the
115115
current request format, so retrying the same request with the same idempotency key still replays the run.
116116
A request that cited legacy entries cannot be sent again; its run keeps the accepted digest, so reusing its
117117
key conflicts.
@@ -136,7 +136,12 @@ reference that does not resolve to an exact imported Atomic revision; a Handoff
136136
claim or check left without evidence once collection citations are removed; and a Candidate version left
137137
without any Source or Artifact evidence once its collection references are removed.
138138

139-
The last case requires a decision file, passed with `--decisions`, that names replacement evidence for each
139+
Finish unfinished Dream runs that have saved an input manifest in the legacy format before migration,
140+
even if they selected only Experiences without Memory citations. Their Artifact digests include the empty
141+
legacy lineage field, so removing it invalidates those snapshots. Queued runs without a saved manifest can
142+
migrate when their selected inputs are unaffected; current-format snapshots remain usable when their inputs are unchanged.
143+
144+
Candidates left without evidence require a decision file, passed with `--decisions`, that names replacement evidence for each
140145
blocked Candidate version:
141146

142147
```json
@@ -203,14 +208,16 @@ Use the target deployment configuration:
203208
powercontext server atomic-memory-rebuild-projection --env-file .env --maintenance-confirmed
204209
```
205210

206-
This command requires completed legacy history migration, valid authoritative content revisions and head
207-
lifecycle data. It rebuilds only active current rows and removes nonactive or orphan current rows. Heads, content
208-
revisions, lifecycle states, retained history and Source/processing progress keep their exact identities and
209-
values. It cannot repair or bypass missing legacy history imports.
211+
This command checks that legacy objects, columns and foreign keys have been removed from public storage and
212+
that Atomic heads, content revisions and head lifecycle data are valid. It rebuilds only active current rows and removes nonactive
213+
or orphan current rows. Heads, content revisions, lifecycle states, retained history and Source/processing
214+
progress keep their exact identities and values. Rebuilding reads neither the archive nor legacy entry tables.
215+
The offline migration `verify` command checks whether legacy history was imported completely; projection
216+
rebuilding cannot supply missing history.
210217

211218
Each active body's embedding is prepared outside the write transaction. Before publishing, the command
212219
locks and rechecks its exact revision, state version and deployment profile, then loads the latest formal
213-
tags and immutable Owner in that transaction. With vectors disabled, it retains body/full-text
220+
tags in that transaction. With vectors disabled, it retains body/full-text
214221
data and clears embedding, profile and input hashes. SQLite refreshes its derived FTS helper using stable
215222
Scope/Artifact identity tokens, independent of rowids changed by `VACUUM`.
216223

‎docs/en/rfcs/1809-atomic-memory.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,10 @@ writing, tags, and authorization, and restart queries and pagination under the n
240240
target the same Atomic Memory.
241241

242242
The SDK and runtime do not retain the legacy Memory domain model, `MemoryCitation`, or other legacy typed Memory references.
243-
Terminal Dream runs and historical receipts with old structures are converted offline into explicit untyped historical
244-
data. They are for display only, without evidence resolution, execution, or recovery.
243+
Terminal Dream runs with old structures are converted offline into explicit untyped historical data for display only,
244+
without evidence resolution, execution, or recovery. Historical receipts retain unavailable collection addresses in
245+
`unavailable_evidence` as descriptions of what was unavailable. These addresses are not resolved or accepted as new evidence;
246+
exact entry citations are converted to Atomic references.
245247
Frozen legacy decoding belongs only to offline migration tools. The runtime keeps no legacy decoder and depends on
246248
neither old tables nor online mapping tables.
247249

0 commit comments

Comments
 (0)