feat(shared-triggers): author + persist + validate shared templates (M2.4)
`shared = true` on a group [[triggers.kv|docs|files]] flows manifest → Bundle → insert_trigger_tx (new shared column), mirroring sealed: shared lives on the Trigger DTO + is part of the apply diff identity (bundle + current sides) so a toggle re-applies. validate_bundle_for rejects shared on an app owner, on a non-collection kind (pubsub/cron/etc.), and on a concrete collection the group does not declare as a shared collection of that kind. Emission (M2.3) now has authored triggers to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -161,8 +161,9 @@ pub async fn run(app_ident: &str, dir: &Path, force: bool, mode: OutputMode) ->
|
||||
ops: d.ops,
|
||||
dispatch_mode,
|
||||
retry_max_attempts,
|
||||
// app-owned triggers are never sealed (group-template only).
|
||||
// app-owned triggers are never sealed/shared (group-only).
|
||||
sealed: false,
|
||||
shared: false,
|
||||
});
|
||||
}
|
||||
"docs" => {
|
||||
@@ -174,6 +175,7 @@ pub async fn run(app_ident: &str, dir: &Path, force: bool, mode: OutputMode) ->
|
||||
dispatch_mode,
|
||||
retry_max_attempts,
|
||||
sealed: false,
|
||||
shared: false,
|
||||
});
|
||||
}
|
||||
"files" => {
|
||||
@@ -185,6 +187,7 @@ pub async fn run(app_ident: &str, dir: &Path, force: bool, mode: OutputMode) ->
|
||||
dispatch_mode,
|
||||
retry_max_attempts,
|
||||
sealed: false,
|
||||
shared: false,
|
||||
});
|
||||
}
|
||||
"cron" => {
|
||||
|
||||
@@ -419,6 +419,10 @@ pub struct KvTriggerSpec {
|
||||
/// non-suppressible (event kinds only; group-only). Omitted ⇒ unsealed.
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
pub sealed: bool,
|
||||
/// §11.6: `shared = true` on a `[group]` template makes it watch the group's
|
||||
/// SHARED collection (not per-app ones); group-only. Omitted ⇒ per-app.
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
pub shared: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
@@ -434,6 +438,9 @@ pub struct DocsTriggerSpec {
|
||||
/// See [`KvTriggerSpec::sealed`].
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
pub sealed: bool,
|
||||
/// See [`KvTriggerSpec::shared`].
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
pub shared: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
@@ -449,6 +456,9 @@ pub struct FilesTriggerSpec {
|
||||
/// See [`KvTriggerSpec::sealed`].
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
pub sealed: bool,
|
||||
/// See [`KvTriggerSpec::shared`].
|
||||
#[serde(default, skip_serializing_if = "is_false")]
|
||||
pub shared: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
@@ -626,6 +636,7 @@ mod tests {
|
||||
dispatch_mode: Some(DispatchMode::Async),
|
||||
retry_max_attempts: Some(5),
|
||||
sealed: false,
|
||||
shared: false,
|
||||
}],
|
||||
..ManifestTriggers::default()
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user