From a1e9f9d6d08be7f4fe647b8d44f0818d59996894 Mon Sep 17 00:00:00 2001 From: Yang Wen Date: Wed, 9 Sep 2026 15:21:33 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(offerings):=20slug=20=E9=94=81=E5=AE=9A?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=B8=A6=E8=A2=AB=E6=8B=92=E6=96=B0=E5=80=BC?= =?UTF-8?q?(lib=20=E9=83=A8=E5=88=86,=E8=A1=A5=20#486=20=E6=BC=8F=E6=8F=90?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #486 (8c56b538) 因 format gate 拦截清空 stage,只带上了 test 断言, course.ex/event.ex 的实际修复漏提——develop 上 event_slug_test 断言 Value: "new-slug" 无对应实现。本 commit 补上 lib 两文件。 --- backend/lib/cgc_2046/courses/course.ex | 3 +++ backend/lib/cgc_2046/events/event.ex | 3 +++ 2 files changed, 6 insertions(+) diff --git a/backend/lib/cgc_2046/courses/course.ex b/backend/lib/cgc_2046/courses/course.ex index 6417d22b..fe0fb25f 100644 --- a/backend/lib/cgc_2046/courses/course.ex +++ b/backend/lib/cgc_2046/courses/course.ex @@ -428,6 +428,9 @@ defmodule Cgc2046.Courses.Course do Ash.Changeset.add_error( changeset, field: :slug, + # 带被拒新值——Ash keyword add_error 不传 :value 时错误消息 Value 恒为 nil, + # 排障时无法区分「参数丢失」与「锁定拦截」(2026-09-09 生产实例误判过) + value: Ash.Changeset.get_attribute(changeset, :slug), message: "slug is locked once the offering is published (editable in draft only)" ) else diff --git a/backend/lib/cgc_2046/events/event.ex b/backend/lib/cgc_2046/events/event.ex index 989736d2..f94bc6ff 100644 --- a/backend/lib/cgc_2046/events/event.ex +++ b/backend/lib/cgc_2046/events/event.ex @@ -430,6 +430,9 @@ defmodule Cgc2046.Events.Event do Ash.Changeset.add_error( changeset, field: :slug, + # 带被拒新值——Ash keyword add_error 不传 :value 时错误消息 Value 恒为 nil, + # 排障时无法区分「参数丢失」与「锁定拦截」(2026-09-09 生产实例误判过) + value: Ash.Changeset.get_attribute(changeset, :slug), message: "slug is locked once the offering is published (editable in draft only)" ) else From c41b8537a82408c7f5b70b2d52a186f8c59e01f1 Mon Sep 17 00:00:00 2001 From: Yang Wen Date: Wed, 9 Sep 2026 15:12:23 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(offerings):=20slug=20=E9=94=81=E5=AE=9A?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=B8=A6=E8=A2=AB=E6=8B=92=E6=96=B0=E5=80=BC?= =?UTF-8?q?,=E6=B6=88=E9=99=A4=20Value:=20nil=20=E6=8E=92=E9=9A=9C?= =?UTF-8?q?=E8=AF=AF=E5=AF=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ash keyword add_error 不传 :value 时 InvalidAttribute.value 恒为 nil, 生产排障无法区分「confirm 重放丢参数」与「锁定规则正确拦截」 (2026-09-09 物理课实例:参数链路健康,误判成疑似 bug 排查一轮)。 course/event 两处锁定校验补 value: get_attribute(:slug); open 后改 slug 用例断言消息含 Value: "new-slug" 防回归。 --- backend/test/cgc_2046/events/event_slug_test.exs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/test/cgc_2046/events/event_slug_test.exs b/backend/test/cgc_2046/events/event_slug_test.exs index 5920ba48..81380465 100644 --- a/backend/test/cgc_2046/events/event_slug_test.exs +++ b/backend/test/cgc_2046/events/event_slug_test.exs @@ -171,6 +171,9 @@ defmodule Cgc2046.Events.EventSlugTest do assert Exception.message(error) =~ "slug is locked" + # 错误须带被拒新值(可观测性:区分「参数丢失」与「锁定拦截」,2026-09-09 生产误判) + assert Exception.message(error) =~ ~s(Value: "new-slug") + assert Ash.get!(Event, event.id, tenant: workspace.id, authorize?: false).slug == "lock-open-event" end