Repository navigation
feat(dashboard): browse, compare, and roll back artifact revisions - #1813
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>
| @@ -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.
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.
|
please update & resolve conflicts |
…artifact Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
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 |
|
please update & resolve conflicts |
|
Regarding your scope questions, please proceed in this PR with the following scope:
Please update from master, resolve the conflicts, and address the Topic revision-cursor issue with a regression test. Update the PR description and relevant docs/RFC notes to match this scope, then run the relevant checks. We can review the updated implementation once those changes are ready. |
hireview001
left a comment
There was a problem hiding this comment.
- Resolve merge conflicts with the target branch.
Resolve the conflicts with Atomic Memory. Each Atomic Memory now shows and compares its own revisions read-only on the Notes page, and replace rejects rollback fields for it. The legacy collection history and manifest compare are gone. Revision metadata columns move into migration p0005 instead of startup DDL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Updated from master and resolved the conflicts, following the scope in your comment:
Local checks: |
…t revisions Compare instruction-only Skill revisions in their packaged form on both sides, so a legacy revision can be rolled forward. Opening a missing Prompt revision shows the read error instead of the current configuration and offers no history or rollback controls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hidb4ai
left a comment
There was a problem hiding this comment.
Reviewed 8088d6b5. The original Topic cursor case is fixed, and per-artifact Atomic Memory history/comparison with a read-only boundary matches the agreed scope. Three remaining issues need addressing before merge: the existing-database upgrade path, Notes revision-cursor cleanup, and downstream generated contracts.
The upgrade and Notes failures were reproduced through public HTTP routes with isolated SQLite databases. OceanBase/SeekDB behavior was not exercised locally.
| created_at: | ||
| type: string | ||
| format: date-time | ||
| nullable: true | ||
| description: When this revision was committed. Absent for revisions stored before this field existed. |
There was a problem hiding this comment.
[P2] Regenerate the downstream revision contracts
Adding these ArtifactRevision fields also changes the Dify tool response schemas and Rust-exported Desktop IPC types. Dify's generate_contract.py --check fails for pc_memory_get.yaml, pc_memory_revise.yaml, and contract.json; the same generator reports no drift with base 06794f6's OpenAPI schema. Desktop's pnpm ipc:check also fails because desktop/ui/src/generated/ipc.ts still declares ArtifactRevision without the four new fields. Both failures are visible in the Dify CI job and Desktop CI job. Please regenerate and commit these downstream outputs alongside the OpenAPI/Rust updates.
There was a problem hiding this comment.
Regenerated. The Dify tool contract (contract.json, pc_memory_get.yaml, pc_memory_revise.yaml) and desktop/ui/src/generated/ipc.ts now include the four ArtifactRevision fields. generate_contract.py --check and pnpm ipc:check both pass locally.
…ursors Replace migration p0005 with a startup step that adds the nullable revision metadata columns to an existing pc_artifacts table, matching how other compatibility columns are added. This keeps databases created by the current release readable and frees the migration number. Drop a revision cursor whenever a link clears the selected artifact, so Notes directory paging and state changes keep the history panel. Regenerate the Dify tool contract and the desktop IPC types for the new revision fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| Column("artifact_id", identity_string(MAX_ARTIFACT_ID_LENGTH), primary_key=True), | ||
| Column("revision", Integer, primary_key=True), | ||
| Column("content", _canonical_payload_type(), nullable=False), | ||
| Column("created_at", DateTime(timezone=True), nullable=True), |
There was a problem hiding this comment.
[P2] Upgrade metadata before offline projection rebuilds
On a pre-upgrade database, powercontext server atomic-memory-rebuild-projection now fails because Artifact reads select these new columns, while the command bypasses the startup schema upgrader. Apply the nullable-column upgrade in the writable maintenance path before reading artifacts so offline repair remains usable during upgrades.
| if family == "experience": | ||
| return {name: content.get(name) for name in _EXPERIENCE_FIELDS} | ||
| if family == "skill": | ||
| return {name: content.get(name) for name in _SKILL_FIELDS} |
There was a problem hiding this comment.
[P2] Normalize legacy Skill revisions in dashboard comparisons
Comparing an instruction-only legacy Skill revision with its equivalent packaged revision reports false changes and enables a rollback that validation rejects as unchanged. Normalize legacy content to packaged form in both dashboard comparison and same_content checks.
| <div class="card-body"> | ||
| <dl class="row mb-3"><dt class="col-sm-4">{{ t.prompt_revision }}</dt><dd class="col-sm-8">{{ prompt.artifact.revision if prompt.artifact else t.prompt_auto }}</dd><dt class="col-sm-4">{{ t.prompt_demonstrations }}</dt><dd class="col-sm-8">{{ prompt.effective.demonstrations|length if prompt.effective else 0 }}</dd></dl> | ||
| {% if prompt.effective %}<h3 class="h4">{{ t.prompt_instructions }}</h3><pre class="page-body-pre text-break">{{ prompt.effective.instructions }}</pre>{% elif prompt.builtin %}<h3 class="h4">{{ t.prompt_instructions }}</h3><pre class="page-body-pre text-break">{{ prompt.builtin.instructions }}</pre>{% endif %} | ||
| {% set opened = prompt_opened if prompt_opened and prompt.prompt_key == prompt_key else none %} |
There was a problem hiding this comment.
[P3] Display the selected Prompt revision's mode
When a Prompt's head is auto and an older custom revision is opened, the page shows historical instructions but labels their mode using the current head; the reverse transition is also mislabeled. Compute opened before rendering the header and use its content mode for the badge.
Which issue or RFC does this PR close?
Closes #1634
Rationale for this change
The 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.Profile, Prompt, Experience, Skill, Handoff, and Topic Memory support history, comparison, and rollback. Each Atomic Memory shows and compares its own revisions read-only. Restoring Atomic Memory is a follow-up that will go through the existing restoration preview/restore flow, so the full set of affected memories is shown before confirmation.
What changes are included in this PR?
created_at. A rollback revision also stores the actor,restored_from_revision, andreason. Server startup adds the four nullable columns to an existingpc_artifactstable on SQLite and MySQL/OceanBase, the same way it adds other compatibility columns. Existing rows are not backfilled and read back as unknown history. No Alembic revision is added, so this PR does not take a migration number.restored_from_revisionandreason. Every other family, including Atomic 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.POST /dashboard/rollbackrequires a same-originOriginheader.kindandtext. No rollback form is shown.allOfreference, which the new nullablecreated_byfield uses.Are there any user-facing changes?
Yes. Dashboard pages for these families show revision history, comparison, and, where allowed, rollback. The Notes page shows read-only history and comparison for each Atomic Memory. 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.Upgrading adds nullable columns only, at Server startup.
How was this change tested?
uv run prek run -a(ruff, format, ty)make unit-testmake contract-testpnpm lint,pnpm ipc:check, andcargo checkindesktop/integrations/dify/generate_contract.py --checkpc_artifactslacks the metadata columns still reads and replaces a Profile after restart.code-seekdband OceanBase CI jobs.AI usage statement
Used Cursor with Grok 4.7 to implement the original revision history, comparison, and rollback flow. Used Claude Code (Claude Opus 5.5) to merge master, rebuild Memory history on Atomic Memory, add the startup column upgrade, fix review findings, and update the contract, docs, and tests.
🤖 Generated with Claude Code