Files
krow_backend/go-api/internal/httpserver
Suriyakumarvijayanayagam 80ba57ace3 Refuse an edit that would rewrite an already-published version
§3 says a published version is immutable and editing publishes a new one.
The machinery for that was all present — an append-only definition_versions
table, a trigger, and repo.VersionsRepo.Snapshot, which already refuses to
store a version number whose content differs from what is stored.

Nothing acted on that refusal. snapshotIfPublished's error was discarded at
both call sites (`_ = s.snapshotIfPublished(...)`), and deliberately so: the
comment there explains that losing an author's work to protect a record of it
is the wrong trade. That is right for a recording failure and wrong for
exactly one case. A conflict is not the history failing to record; it is the
invariant firing.

The effect was silent. Editing a published agent without raising the
frontmatter version answered 200: the live row took the new text, the history
kept the old, and two different definitions were both called v1. Because
runtime.LoadAgentVersion resolves a pin by returning the CURRENT definition
whenever the pinned number equals the current one, a conversation pinned to v1
then ran the rewritten instructions while the audit trail showed the
originals. Verified against a live stack before the fix: PATCH answered 200,
agent_definitions held "SILENTLY CHANGED" and definition_versions still held
the published text, both labelled v2.

So the conflict is now detected before anything is written, where refusing
costs the author nothing but a version bump. The post-write snapshot keeps its
original contract for every other kind of failure, and republishing a version
unchanged stays the no-op it was. Drafts are untouched: they carry no promise,
and are still rewritten in place.

Not addressed here, and each its own change:

  - cmd/importagents never creates versions at all (documented at main.go:10),
    so the nine file-published organization agents are outside this entirely
    and every deploy still mutates v1 in place.
  - skill definitions never snapshot, so KindSkill exists with nothing writing
    it. Fixing that changes skill authoring behaviour and wants its own pass.
  - a concurrent publish of one version number with differing content can still
    pass this check and be caught by the unique index afterwards, where it is
    swallowed as before. That is the pre-existing behaviour, narrowed rather
    than removed.

Tests: the new case fails without the fix — the live row takes the rewritten
text at version 1 — and passes with it. Full suite green against PostgreSQL,
with only TestLive* skipped, which is what CI allows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJvibeSc1JYXjatankqM1g
2026-08-28 18:28:20 +05:30
..
2026-08-28 12:21:44 +05:30
2026-08-25 16:37:05 +05:30
2026-08-24 13:06:29 +05:30
2026-08-28 12:21:44 +05:30
2026-08-24 13:06:29 +05:30
2026-08-25 16:37:05 +05:30
2026-08-24 13:06:29 +05:30
2026-08-25 16:37:05 +05:30
2026-08-24 13:06:29 +05:30
2026-08-28 12:21:44 +05:30
2026-08-28 12:21:44 +05:30
2026-08-28 12:21:44 +05:30
2026-08-24 13:06:29 +05:30
2026-08-25 16:37:05 +05:30
2026-08-24 13:06:29 +05:30
2026-08-28 12:21:44 +05:30
2026-08-28 12:21:44 +05:30
2026-08-28 12:21:44 +05:30
2026-08-28 12:21:44 +05:30
2026-08-25 16:37:05 +05:30
2026-08-25 16:37:05 +05:30