Skip to content

Log plan metadata changes in unified history feed (COPLAN-26)#115

Open
HamptonMakes wants to merge 1 commit into
mainfrom
hampton/coplan-26/log-metadata-changes
Open

Log plan metadata changes in unified history feed (COPLAN-26)#115
HamptonMakes wants to merge 1 commit into
mainfrom
hampton/coplan-26/log-metadata-changes

Conversation

@HamptonMakes
Copy link
Copy Markdown
Collaborator

Why

The History tab only shows content revisions today. Metadata mutations — title, status, tags, references, plan_type — are silent. There's no answer to "who changed the status to developing yesterday?" or "when did this tag disappear?" without digging through audit logs.

COPLAN-26 asks for these changes to show up in the History tab with actor, timestamp, and before/after, without bumping current_revision (which would conflate content edits with metadata churn).

What

A new CoPlan::PlanEvent model that lives alongside PlanVersion. Content snapshots and metadata entries are two different things conceptually — PlanVersion requires content_markdown / content_sha256 and drives revision numbering, while metadata events are append-only log entries with before/after values. Forcing them into one table would make both messier.

  • New table/model: coplan_plan_events with actor, actor_type, event_type, field, before_value, after_value, metadata JSON, created_at. Standard CoPlan conventions (UUID PK, no DB-level JSON default, frozen constants + inclusion: validation).
  • Plans::LogEvent service: normalizes values to strings, no-ops when before == after, infers actor_type.
  • Unified history feed: Plan#history_items merges plan_versions + plan_events sorted newest-first. history_kind (:version / :event) lets templates branch without class introspection.
  • UI: content versions stay clickable into the version-diff frame; metadata events render as inline non-clickable rows. History badge count now sums both. Turbo broadcasts prepend new events live and refresh the badge.
  • Wired mutation surfaces:
    • Web: PlansController#update (title), PlansController#update_status, ReferencesController#create/destroy
    • API: Api::V1::PlansController#update logs title, status, and tag add/remove diffs in a single request; reference additions emit reference_added
  • Helper inclusion in ApplicationController so broadcasted partials can call render_event_summary.

Event types defined: status_changed, title_changed, plan_type_changed, tag_added, tag_removed, reference_added, reference_removed. plan_type_changed is model-ready; the mutation path lands with COPLAN-25.

Verification

bundle exec rspec — 857 examples, 0 failures. New coverage:

  • spec/services/plans/log_event_spec.rb — service normalization + no-op behavior
  • spec/models/plan_event_spec.rb — validations, defaults, cascade configuration
  • spec/requests/plan_events_spec.rb — every mutation surface (web title/status/references, API title/status/tags/references) actually emits the right events, and Plan#history_items interleaves correctly.

References

@codex please review

🤖 Generated with Amp

Adds a CoPlan::PlanEvent model alongside PlanVersion so that metadata
mutations (status, title, tags, references, plan_type) are visible in
the History tab with actor, timestamp, and before/after values — without
bumping the content revision counter.

- New coplan_plan_events table + model + admin
- Plans::LogEvent service normalizes & no-ops unchanged events
- Plan#history_items merges versions + events into one feed
- _event_item partial renders inline metadata entries; content versions
  remain clickable into the diff frame
- Web title/status, references, and API PATCH paths now log events
- History badge count includes both versions and events
- Turbo broadcasts prepend new events live and refresh the count badge

Refs COPLAN-26

Amp-Thread-ID: https://ampcode.com/threads/T-019e22e9-1c86-71bc-a076-f5e6d06b03d0
Co-authored-by: Amp <amp@ampcode.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2506d9653

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


if permitted.key?(:title) && @plan.saved_change_to_title?
Plans::LogEvent.call(
plan: @plan, actor: current_user, event_type: "title_changed",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve API actor type when logging metadata

When this API endpoint is called with a bearer token, current_user is the token owner, while the rest of the API records content edits with api_author_type == "local_agent" and api_actor_id from the token. Passing current_user here makes all API title/status/tag/reference metadata events look like human edits by the owner, so the new history feed gives the wrong answer for agent-driven metadata changes; the other Plans::LogEvent.call sites in this action have the same attribution issue.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant