Repository navigation
Conversation
Record created_at on every new revision, and keep the rollback source, reason, and actor on the replacement revision. Dashboard history reuses conditional replace instead of a dedicated rollback route. Co-authored-by: Cursor <cursoragent@cursor.com>
- Increased the length of the `created_by` column in the artifacts table to accommodate longer principal IDs. - Implemented a new function to widen the `created_by` column if necessary during schema updates. - Updated the dashboard to handle historical notes more effectively, including displaying notes from older memory revisions and managing pagination. - Added a new label for truncated comparison results in the dashboard UI. - Improved the handling of memory artifact IDs in links and context management. Co-authored-by: Cursor <cursoragent@cursor.com>
| from powercontext.builtin.persistence.sources import SourceRepository | ||
| from powercontext.builtin.persistence.sqlite import SQLiteConfig, SQLiteProfile | ||
| from powercontext.builtin.persistence.tables import BUILTIN_TABLES | ||
| from powercontext.builtin.persistence.tables import ARTIFACTS_TABLE, BUILTIN_TABLES, CREATED_BY_LENGTH |
There was a problem hiding this comment.
承接说明:Teingi 已在同一行提过同一问题(
#discussion_r4157459143,[P2])。本条不是新发现,而是补上 CI 日志级证据并把影响面定级到 P1:该ImportError让tests (3.11)/(3.12)/(3.13)/(3.14)四个作业在收集阶段就中断,一条测试都不执行(相当于这四个作业当前不提供任何信号),故建议按「必须清零」而非「普通待办」处理。修复方式仍是同一处:把常量定义出来并让导入与断言同源。
[P1] 导入的 CREATED_BY_LENGTH 在 tables.py 中不存在,tests 作业在收集阶段整体中断
tables.py 把 created_by 写成字面量 Column("created_by", String(2048), nullable=True)(src/powercontext/builtin/persistence/tables.py:199),从未定义 CREATED_BY_LENGTH;本行是新加的导入,第 287 行的 assert column == CREATED_BY_LENGTH 也是新加的。
后果不是"某个用例失败",而是 pytest 在导入阶段就报错,tests 作业里一条测试都不会执行。head fc3767f2 的 CI 日志(tests (3.13)):
E ImportError: cannot import name 'CREATED_BY_LENGTH' from 'powercontext.builtin.persistence.tables' (/home/runner/work/powercontext/powercontext/src/powercontext/builtin/persistence/tables.py)
=========================== short test summary info ============================
ERROR tests/builtin/persistence/test_prompt_records.py
!!!!!!!!!!!!!!!!!!! Interrupted: 2 errors during collection !!!!!!!!!!!!!!!!!!!!
============================= 2 errors in 12.18s ==============================
make: *** [Makefile:43: unit-test] Error 2
tests (3.11) / (3.12) / (3.14) 同因失败;quality 的 ty 步骤另报 error[unresolved-import]: Module powercontext.builtin.persistence.tables has no member CREATED_BY_LENGTH。
本机在 head 上复现(隔离 venv,uv sync --frozen):
$ pytest tests/test_dashboard_profile_handoff.py tests/builtin/persistence/test_prompt_records.py tests/e2e/test_profile_api.py -q
ERROR tests/builtin/persistence/test_prompt_records.py
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
这正是 PR 描述 "How was this change tested" 里给出的那条命令,因此该验证按当前 head 无法通过。
建议:本仓库的列宽常量集中在 powercontext/limits.py(tables.py:36-54 逐个导入 MAX_*_LENGTH),在那里补 CREATED_BY_LENGTH = 2048,并让 tables.py:199 改成 String(CREATED_BY_LENGTH),使第 287 行的断言与列定义共享同一个来源。
There was a problem hiding this comment.
Fixed in c2afbc7, using the shared constant in limits.py as suggested. Thanks for the CI log evidence.
| @@ -0,0 +1,108 @@ | |||
| {% if history %} | |||
There was a problem hiding this comment.
[P1] 新模板缺少仓库统一的 OceanBase 授权头,Check License Header 作业失败
head fc3767f2 的 Check License Header(skywalking-eyes)日志直接点名本文件:
ERROR the following files don't have a valid license header:
src/powercontext/server/dashboard/templates/components/revision-history.html
ERROR one or more files does not have a valid license header
同目录的其它组件都以 Apache 头开始(components/brand.html、components/comparison-chart.html、components/evidence-modal.html、templates/topics.html …),本文件是本 PR 新增文件中唯一缺头的。
建议在首行前补上与兄弟模板一致的 HTML 注释头:
<!--
Copyright (c) 2026 OceanBase.
...
-->
There was a problem hiding this comment.
Added the standard Apache header to revision-history.html.
| UsageReportingStructuredGenerator, | ||
| ) | ||
| from powercontext.builtin.persistence.dream_schema import ensure_dream_schema | ||
| from powercontext.builtin.persistence.revision_meta import ensure_revision_metadata_schema |
There was a problem hiding this comment.
[P2] 新增导入的插入位置触发 ruff I001,quality 的 ruff 钩子因此失败
本行插在 dream_schema 与 memory_index 之间,破坏了该导入块的有序性。ruff check 报 I001 [*] Import block is un-sorted or un-formatted(定位在块首 composition.py:17),并把它自动修掉,prek 因此判失败,quality 作业在 Makefile:30 挂掉:
ruff check...............................................................Failed
- hook id: ruff-check
- files were modified by this hook
Found 1 error (1 fixed, 0 remaining).
ruff format..............................................................Failed
- hook id: ruff-format
- files were modified by this hook
3 files reformatted, 961 files left unchanged
ruff format 要重排的 3 个文件都是本 PR 的:src/powercontext/builtin/persistence/revision_meta.py、tests/builtin/persistence/test_prompt_records.py、tests/test_dashboard_profile_handoff.py。
本机在 head 上以无副作用方式复现:
$ ruff check --no-fix --output-format=concise .
src/powercontext/builtin/runtime/composition.py:17:1: I001 [*] Import block is un-sorted or un-formatted
$ ruff format --check .
3 files would be reformatted, 951 files already formatted
建议把本行移到 memory_index 之后(revision_meta 的字母序位置),并对上述 3 个文件跑一次 ruff format。
There was a problem hiding this comment.
Fixed. The import now sits in sorted position, and I ran ruff format on the three files you listed. prek run -a is clean locally.
| columns = await connection.run_sync(lambda sync: inspect(sync).get_columns(ARTIFACTS_TABLE.name)) | ||
| column = next((item for item in columns if item["name"] == "created_by"), None) | ||
| length = None if column is None else getattr(column["type"], "length", None) | ||
| target = ARTIFACTS_TABLE.c.created_by.type.length |
There was a problem hiding this comment.
[P2] TypeEngine.length 触发 ty 报错,quality 的 ty 钩子失败(head 上合计 6 条诊断)
ARTIFACTS_TABLE.c.created_by.type 的静态类型是 TypeEngine[Any],不含 length:
error[unresolved-attribute]: Object of type `TypeEngine[Any]` has no attribute `length`
--> src/powercontext/builtin/persistence/revision_meta.py:152:14
152 | target = ARTIFACTS_TABLE.c.created_by.type.length
(CI 的行号是它的 ruff 钩子先重排过该文件之后的;未重排时对应 head 的 157 行。同一写法在 tests/builtin/persistence/test_prompt_records.py:284 也各报一条。)
运行期没有问题——created_by 确实是 String(2048)——但 quality 的 ty 钩子是硬失败。head 上 ty 合计 6 条诊断,除上面两条外还有:
tests/builtin/persistence/test_prompt_records.py:325merged_source_revision实参类型不符(Command不是BaseModel)tests/test_dashboard_profile_handoff.py:223在可调用对象上取.statetests/test_dashboard_profile_handoff.py:407_memory_text_rows传入Api而非DashboardAPI
本机 ty check 在 head 上同样得到 6 条,与 CI 一致。
建议:先用 isinstance(ARTIFACTS_TABLE.c.created_by.type, String) 收窄再取 .length(或与 powercontext/limits.py 里的常量比较),并顺带清掉测试里的 4 条。
There was a problem hiding this comment.
Fixed. The migration compares against the shared constant instead of .type.length. The other four diagnostics are also gone: a BaseModel subclass for the fake command, and cast for the app state and the DashboardAPI stub. ty check reports no diagnostics.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rollback Define the actor column width in limits so tests and DDL share one source, add the missing license header, restore import order and formatting, fix the ty diagnostics, and clear the retained note citation when switching Memory revisions. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Merged master into the branch and resolved the conflicts in |
…tdates the revision Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
hidb4ai
left a comment
There was a problem hiding this comment.
Found one reproducible Topic Memory navigation issue on d4f5368f.
| "prompt_key", | ||
| "prompt_revision", | ||
| "prompt_revision_cursor", | ||
| "topic_revision_cursor", |
There was a problem hiding this comment.
[P2] Clear the revision cursor when switching Topic Memory artifacts
After paging the history of Topic A (8 revisions), clicking Topic B in the inventory keeps A's topic_revision_cursor in B's URL. Revision cursors are bound to artifact_id, so B's revisions request raises InvalidCursorError; load_history() catches it and returns None. The page still responds 200 but loses its entire history/compare panel. Reproduced through the Dashboard HTTP routes with SQLite on d4f5368f; opening B without that cursor restores the panel. Please clear the history cursor when topic_artifact changes and cover this navigation sequence.
|
please update & resolve conflicts |
|
Merging the latest master conflicts in 14 files, and not mechanically: #1857/#1880 removed the legacy Memory collection in favor of Atomic Memory, and this PR's Memory history and compare is built on that collection (manifest, I plan to rework Memory history and compare on Atomic Memory in this PR, aligned with the restoration flow now on master, instead of splitting it out. Before I start, could you confirm the scope? In particular:
I'll update the PR description and RFC notes once the scope is settled. |
|
please update & resolve conflicts |
Which issue or RFC does this PR close?
Closes #1634
Rationale for this change
Dashboard can browse an artifact's revisions, open one exact revision, compare two revisions, and roll an older revision forward. Rollback reuses conditional replace (
If-Match: "revision:{n}"). There is no new rollback route and no new permission.Memory stays history and compare only. Profile, Prompt, Experience, Skill, Handoff, and Topic Memory can roll back.
What changes are included in this PR?
created_at. A rollback revision also stores the actor,restored_from_revision, andreason. Old rows are not backfilled.restored_from_revisionandreason. Memory rejects both. A source revision requires a non-blank reason of at most 1024 characters. The submitted content must match that revision and differ from the current head.Are there any user-facing changes?
Yes. Dashboard pages for these families show revision history, comparison, and, where allowed, rollback. Revision reads and replace responses gain nullable
created_at,created_by,restored_from_revision, andreason. Existing clients can ignore the new fields. Rollback does not delete or rewrite older revisions, and it does not change a Skill's lifecycle state.How was this change tested?
uv run pytest tests/test_dashboard_profile_handoff.py tests/builtin/persistence/test_prompt_records.py tests/e2e/test_profile_api.pyAI usage statement
Used Cursor with Grok 4.7 to implement the revision history, comparison, and rollback flow, update the contract and docs, and add the regression tests.