@gobing-ai/knowledge-kit 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/dist/index.js +2359 -1721
- package/package.json +1 -1
- package/plugins/generations/image-gen/README.md +108 -0
- package/plugins/generations/image-gen/assets/sample/cover__clean-webapp-ui.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__cute.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__daily-news.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__editorial.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__fresh.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__minimalist.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__photorealistic.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__sketch.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__technical-diagram.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__vibrant.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__warm.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/cover__xhs-knowledge.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__clean-webapp-ui.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__cute.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__daily-news.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__editorial.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__fresh.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__minimalist.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__photorealistic.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__sketch.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__technical-diagram.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__vibrant.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__warm.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/daily-news-cover__xhs-knowledge.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__clean-webapp-ui.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__cute.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__daily-news.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__editorial.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__fresh.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__minimalist.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__photorealistic.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__sketch.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__technical-diagram.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__vibrant.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__warm.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/free__xhs-knowledge.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__clean-webapp-ui.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__cute.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__daily-news.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__editorial.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__fresh.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__minimalist.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__photorealistic.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__sketch.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__technical-diagram.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__vibrant.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__warm.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/illustration__xhs-knowledge.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__clean-webapp-ui.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__cute.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__daily-news.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__editorial.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__fresh.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__minimalist.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__photorealistic.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__sketch.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__technical-diagram.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__vibrant.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__warm.jpg +0 -0
- package/plugins/generations/image-gen/assets/sample/xhs-card__xhs-knowledge.jpg +0 -0
- package/plugins/generations/image-gen/dist/index.js +102 -58
- package/plugins/generations/image-gen/scripts/compose-e2e-artifact.ts +5 -21
- package/plugins/generations/image-gen/scripts/gen-samples.ts +208 -0
- package/plugins/generations/image-gen/src/compose/chromium.ts +2 -3
- package/plugins/generations/image-gen/src/presets.ts +6 -3
- package/plugins/generations/image-gen/src/providers/errors.ts +16 -1
- package/plugins/generations/image-gen/src/providers/minimax.ts +46 -17
- package/plugins/ingestions/web-search/src/index.ts +1 -1
- package/plugins/kk/README.md +18 -0
- package/plugins/kk/commands/image-extract.md +1 -0
- package/plugins/kk/commands/image-generate.md +1 -0
- package/plugins/kk/commands/tell-me.md +1 -0
- package/plugins/kk/commands/workflow-run.md +7 -1
- package/plugins/kk/decisions/extract/it-topics.yaml +24 -0
- package/plugins/kk/decisions/kk-itc.yaml +6 -4
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/publish-presets/daily-ai-voice-migration.json +146 -0
- package/plugins/kk/publish-presets/daily-ai-voice.json +11 -3
- package/plugins/kk/schedules/kk-collect.grok-bot.md.tmpl +69 -0
- package/plugins/kk/schedules/kk-daily-ai-voice3.cron.tmpl +18 -0
- package/plugins/kk/schedules/kk-daily-publish3-cn-peak.cron.tmpl +15 -5
- package/plugins/kk/schedules/kk-daily-publish3-overseas.cron.tmpl +9 -4
- package/plugins/kk/scripts/daily-stages.ts +346 -48
- package/plugins/kk/scripts/kk-workflow-stages.ts +190 -0
- package/plugins/kk/scripts/safety-artifact-check.ts +70 -28
- package/plugins/kk/scripts/voice3-publish-window.ts +202 -0
- package/plugins/kk/skills/article-adapt/SKILL.md +1 -0
- package/plugins/kk/skills/audio-authoring/SKILL.md +1 -0
- package/plugins/kk/skills/content-judge/SKILL.md +1 -0
- package/plugins/kk/skills/content-safety/SKILL.md +1 -0
- package/plugins/kk/skills/explain-things/SKILL.md +1 -0
- package/plugins/kk/skills/image-authoring/SKILL.md +1 -0
- package/plugins/kk/skills/itc-generating/SKILL.md +1 -0
- package/plugins/kk/skills/publish/SKILL.md +1 -0
- package/plugins/kk/skills/smart-seo/SKILL.md +1 -0
- package/plugins/kk/skills/storm-research/SKILL.md +1 -0
- package/plugins/kk/skills/taste-unslop/SKILL.md +1 -0
- package/plugins/kk/skills/topic/SKILL.md +1 -0
- package/plugins/kk/skills/web-automation/SKILL.md +1 -0
- package/plugins/kk/skills/xhs-images/SKILL.md +1 -0
- package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +9 -7
- package/plugins/kk/workflows/kk-daily-ai-voice3.yaml +161 -61
- package/plugins/kk/workflows/kk-daily-publish3.yaml +82 -26
- package/plugins/kk/workflows/kk-daily-safety.yaml +39 -31
- package/plugins/kk/workflows/kk-itc-author.yaml +75 -0
- package/plugins/kk/workflows/kk-itc-publish-tail.yaml +25 -3
- package/plugins/kk/workflows/kk-itc.yaml +36 -4
- package/plugins/publishings/linkedin-pub/dist/index.js +21333 -0
- package/plugins/publishings/linkedin-pub/dist/profile-check.js +21005 -0
- package/plugins/publishings/linkedin-pub/package.json +19 -0
- package/plugins/publishings/linkedin-pub/plugin.json +12 -0
- package/plugins/publishings/linkedin-pub/src/index.ts +705 -0
- package/plugins/publishings/linkedin-pub/src/profile-check.ts +17 -0
- package/plugins/publishings/linkedin-pub/tsconfig.json +4 -0
- package/plugins/publishings/surfdash-pub/dist/index.js +1 -1
- package/plugins/publishings/surfdash-pub/src/index.ts +3 -1
- package/plugins/publishings/threads-pub/dist/index.js +7 -0
- package/plugins/publishings/threads-pub/src/index.ts +12 -0
- package/plugins/publishings/wechatmp-pub/dist/index.js +5 -2
- package/plugins/publishings/wechatmp-pub/src/flow.ts +11 -3
- package/plugins/publishings/x-pub/dist/index.js +7 -0
- package/plugins/publishings/x-pub/src/index.ts +11 -0
|
@@ -6,6 +6,7 @@ description: >-
|
|
|
6
6
|
this saved audit", "explain these SEO findings", or "check GEO readiness". Read-only results: no
|
|
7
7
|
site mutation, no ranking and no citation promises.
|
|
8
8
|
version: 0.1.0
|
|
9
|
+
requires: [cli:kk, cli:spur, local-fs]
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# smart-seo — evidence-grounded SEO/GEO audits
|
|
@@ -8,6 +8,7 @@ description: >-
|
|
|
8
8
|
(prepare → ingest → generate → render) over the 0056 works layout. Research is separate from
|
|
9
9
|
authoring: topic owns init→outline→draft and this skill never merges into topic.
|
|
10
10
|
version: 0.1.0
|
|
11
|
+
requires: [cli:kk, local-fs]
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
# storm-research — STORM daily research (topic sentence XOR markdown file → content.md)
|
|
@@ -5,6 +5,7 @@ description: >-
|
|
|
5
5
|
voice and substance — "make this sound human", "remove the AI tells", "audit this
|
|
6
6
|
copy for canned patterns", "restore my voice after AI editing". Not for code,
|
|
7
7
|
translation-only work, or proofreading that must preserve style.
|
|
8
|
+
requires: [local-fs]
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
# taste-unslop
|
|
@@ -7,6 +7,7 @@ description: >-
|
|
|
7
7
|
Runs the topic-core authoring loop (init → outline → draft) through four
|
|
8
8
|
operations with explicit operator gates and safe resume. knowledge-kit's
|
|
9
9
|
cohesive topic-authoring core, harvested from the WT 7-stage wrappers.
|
|
10
|
+
requires: [cli:kk, cli:spur, local-fs]
|
|
10
11
|
---
|
|
11
12
|
|
|
12
13
|
# topic — topic-core authoring (create | init | outline | draft)
|
|
@@ -9,6 +9,7 @@ description: >-
|
|
|
9
9
|
web-automation skill. Owns method and evidence; transport stays in kk
|
|
10
10
|
plugins; orchestration is a @gobing-ai/ts-dual-workflow-engine
|
|
11
11
|
transition-flow (see docs/design/web-automation-engine.md).
|
|
12
|
+
requires: [cli:spur, local-fs]
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
# web-automation — discover, enhance, automate with a real browser
|
|
@@ -7,6 +7,7 @@ description: >-
|
|
|
7
7
|
closing) grounded in the source, renders them through the image-gen executor
|
|
8
8
|
with the xhs-card/xhs-knowledge presets, packages a publishable Content, and
|
|
9
9
|
hands off to kk:publish channel xhs. Never publishes directly.
|
|
10
|
+
requires: [cli:kk, local-fs]
|
|
10
11
|
---
|
|
11
12
|
|
|
12
13
|
# xhs-images — source-grounded XHS card series (plan → render → package → handoff)
|
|
@@ -509,7 +509,7 @@ nodes:
|
|
|
509
509
|
# 0238 R3: reads 21-plan/<date>_03_plan_plan.json, so it must not start before the plan
|
|
510
510
|
# producers settle. `script-style` stays first in the list: a done dependency in the mix keeps
|
|
511
511
|
# this node runnable when the plan-authoring nodes are disabled (all-skipped deps skip a node).
|
|
512
|
-
dependsOn: [script-style, plan-translate, plan-translate-retry]
|
|
512
|
+
dependsOn: [script-style, plan-translate, plan-translate-retry, article]
|
|
513
513
|
condition:
|
|
514
514
|
kind: shell
|
|
515
515
|
options:
|
|
@@ -620,8 +620,8 @@ nodes:
|
|
|
620
620
|
kk store pool-count "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json" --min 1
|
|
621
621
|
action:
|
|
622
622
|
kind: shell
|
|
623
|
+
onError: continue
|
|
623
624
|
options:
|
|
624
|
-
onError: continue
|
|
625
625
|
command: >-
|
|
626
626
|
OMNIVOICE_SPEED=1.06 kk stage daily-generate "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.transcode_mp3}" "${vars.vdriver}" "1" "${vars.episode_max_minutes}" "${vars.episode_min_minutes}"
|
|
627
627
|
|
|
@@ -641,8 +641,8 @@ nodes:
|
|
|
641
641
|
&& ! jq -e '(.metadata.generator == "kk:voxcpm-tts" or .metadata.generator == "kk:gemini-tts") and .metadata.qc.passed == true' "${vars.work_dir}/30-audio/${vars.run_date}_11_generate_content.json"
|
|
642
642
|
action:
|
|
643
643
|
kind: shell
|
|
644
|
+
onError: continue
|
|
644
645
|
options:
|
|
645
|
-
onError: continue
|
|
646
646
|
command: >-
|
|
647
647
|
kk stage daily-generate "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.transcode_mp3}" "gemini" "1" "${vars.episode_max_minutes}" "${vars.episode_min_minutes}"
|
|
648
648
|
|
|
@@ -829,7 +829,9 @@ nodes:
|
|
|
829
829
|
|
|
830
830
|
- id: translate
|
|
831
831
|
description: >-
|
|
832
|
-
Agent translates both scaffolded locale drafts
|
|
832
|
+
Agent translates both scaffolded locale drafts into <run_date>_21_translate_<locale>.md under the
|
|
833
|
+
work dir (2026-11-04: both executor sandboxes refuse writes into the Surfdash checkout, and the
|
|
834
|
+
step still exits 0); translate-refine installs them over the drafts. The two draft paths are read from the
|
|
833
835
|
marker files at their fixed paths (no var projection after the fan-out: concurrent setVars is
|
|
834
836
|
last-writer-wins, design §6), and an empty marker means that locale is absent. The local
|
|
835
837
|
validation node gates final Surfdash publish so its strict all-locale CMS policy is met.
|
|
@@ -856,11 +858,11 @@ nodes:
|
|
|
856
858
|
Translate the en/ja draft posts of the zh article. Read the two marker files at these fixed paths — each holds one draft path, or is empty when that locale was not scaffolded:
|
|
857
859
|
English: ${vars.work_dir}/31-publish/${vars.run_date}_20_translate-localize_en-post-path.txt
|
|
858
860
|
Japanese: ${vars.work_dir}/31-publish/${vars.run_date}_20_translate-localize_ja-post-path.txt
|
|
859
|
-
For each: if the marker is empty or unreadable, skip that locale. Otherwise
|
|
861
|
+
For each: if the marker is empty or unreadable, skip that locale. Otherwise read the named draft but do NOT edit it (it sits in the Surfdash checkout, outside your writable workspace): write the complete translated file — frontmatter and body — to ${vars.work_dir}/31-publish/${vars.run_date}_21_translate_en.md (English) or ${vars.work_dir}/31-publish/${vars.run_date}_21_translate_ja.md (Japanese); a later stage installs it over the draft. Translate the frontmatter title and the whole markdown body to natural English/Japanese respectively. Keep frontmatter keys, dates, URLs, code, and the assets/ image reference untouched. Set draft: false (the translated post publishes to the site) and remove any canonical: frontmatter line pointing at a different locale's URL.
|
|
860
862
|
Also translate these frontmatter values into the target locale, keeping all other keys untouched: description, seo_title, seo_description, and each key_points item. Each stays one coherent standalone sentence that summarizes the same story as the zh source — never splice fragments from different items or stories into one, and key_points must keep exactly the same number of items as the zh post. The 2026-10-23 run failed this: spliced description/key_points had to be hand-repaired before sync.
|
|
861
863
|
Series names are fixed product identity, never invented or freely translated: the en series name is "Daily AI Stew" (show "Salty Talk"); the ja series name is "デイリーAIシチュー" (show "咸話咸説"). Never emit 毎日AIブレンド, ごった煮, "Daily AI Medley", "hodgepodge", "Daily AI Briefing", or the zh name 每日AI乱炖 in en/ja prose or link text (a URL keeps whatever it contains). Openers: en "Your Daily AI Stew from Robin, on Salty Talk."; ja "咸話咸説のデイリーAIシチュー、Robin がお届けします。" Listen links: en "[listen to Daily AI Stew · <date>](<url>)", ja "[デイリーAIシチュー · <date> を聴く](<url>)". In each key_points item keep the "Label — sentence" shape: the label before " — " stays a short phrase of at most 14 characters (ja) / 28 (en), never truncated with "…". The local translate-validate stage rewrites known retired names deterministically and fails the publish gate on leftovers.
|
|
862
864
|
Keep frontmatter valid YAML: double-quote any value containing ': '. Read the surfdash translator glossary if present at the surfdash checkout root under .agents/skills/surfdash-translator/glossary.md and apply its terminology.
|
|
863
|
-
Do not wait for operator confirmation. Each
|
|
865
|
+
Do not wait for operator confirmation. Each written file must end fully in its target language.
|
|
864
866
|
|
|
865
867
|
# 2026-10-24: the locale translation carried `onError: continue` with NO retry sibling, so a
|
|
866
868
|
# failed executor left the en/ja drafts untranslated and the old sync stage could not distinguish
|
|
@@ -874,7 +876,7 @@ nodes:
|
|
|
874
876
|
options:
|
|
875
877
|
command: >-
|
|
876
878
|
test "$(cat "${vars.work_dir}/31-publish/${vars.run_date}_20_translate-localize_zh-post-path.txt" 2>/dev/null)" != ""
|
|
877
|
-
&& { for L in en ja; do M="${vars.work_dir}/31-publish/${vars.run_date}_20_translate-localize_$L-post-path.txt"; P="$(cat "$M" 2>/dev/null)"; [ -z "$P" ] && continue; grep -q '^draft: *false' "$
|
|
879
|
+
&& { for L in en ja; do M="${vars.work_dir}/31-publish/${vars.run_date}_20_translate-localize_$L-post-path.txt"; P="$(cat "$M" 2>/dev/null)"; [ -z "$P" ] && continue; O="${vars.work_dir}/31-publish/${vars.run_date}_21_translate_$L.md"; grep -q '^draft: *false' "$O" || { echo "untranslated: $L ($O)"; exit 0; }; done; exit 1; }
|
|
878
880
|
action:
|
|
879
881
|
kind: agent.run
|
|
880
882
|
options:
|
|
@@ -24,6 +24,12 @@ vars:
|
|
|
24
24
|
publish_window: "after-generate"
|
|
25
25
|
publish_preset: ""
|
|
26
26
|
publish_dummy: "false"
|
|
27
|
+
# 0334 R7: opt-in live consent channel, forwarded verbatim to the nested publish3
|
|
28
|
+
# `live_channels`. Empty by default — this variable alone can never produce a live send
|
|
29
|
+
# (ADR-022: only an operator launch that sets it, with tokens the plan stage validates
|
|
30
|
+
# against the window, promotes rows; `publish_dummy=true` and a non-empty token list
|
|
31
|
+
# refuse each other at plan time).
|
|
32
|
+
publish_live_channels: ""
|
|
27
33
|
# Composed by the `prepare` node (`kk daily prepare`), then read back into vars through the
|
|
28
34
|
# single-node read chain below — shell actions cannot set vars, and a concurrent `setVars` merge
|
|
29
35
|
# is last-writer-wins, so the DAG exchanges data by fixed paths under work_dir, never by vars.
|
|
@@ -140,6 +146,7 @@ nodes:
|
|
|
140
146
|
command: >-
|
|
141
147
|
kk stage daily-preflight plugins/kk/workflows/kk-daily-ai-voice2.yaml
|
|
142
148
|
plugins/kk/workflows/kk-daily-safety.yaml
|
|
149
|
+
plugins/kk/workflows/kk-daily-publish3.yaml
|
|
143
150
|
&& kk daily prepare --workflow kk-daily-ai-voice2 --run-date "${vars.run_date}" --ledger-sync
|
|
144
151
|
--run "${vars.__runId}" --definition-digest "${vars.__definitionDigest}"
|
|
145
152
|
--setting window="${vars.window}" --setting language="${vars.language}" --setting vdriver="${vars.vdriver}"
|
|
@@ -243,6 +250,31 @@ nodes:
|
|
|
243
250
|
command: >-
|
|
244
251
|
kk stage daily-qc-content "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.qc_categories}" "${vars.qc_min_quality}" "${vars.qc_min_importance}" "${vars.qc_min_urgency}" "${vars.qc_min_impact}" "${vars.qc_min_episode_items}" "${vars.episode_min_minutes}" "${vars.vdriver}"
|
|
245
252
|
|
|
253
|
+
# One guard for the whole pool (0324 R3; 0329 F01/F15): it sits right after `qc-content`, in
|
|
254
|
+
# front of every token reader, and NEVER exits non-zero — in this engine a failed dependency
|
|
255
|
+
# never releases its dependents, so a failing gate on an empty pool wedges the graph into
|
|
256
|
+
# dag-unreachable and turns a thin day into a failed run. The token carries the verdict
|
|
257
|
+
# instead: PASS opens the content fan-out, EMPTY makes every token-gated node skip, and the
|
|
258
|
+
# run still closes `done` with a no-content run report.
|
|
259
|
+
- id: pool-gate
|
|
260
|
+
description: >-
|
|
261
|
+
The single pool guard (0324 R3, 0329): `kk store pool-count --min 1` over the candidates
|
|
262
|
+
file that `qc-content` wrote, recorded once as a token at
|
|
263
|
+
`.spur/run/<runId>-pool-gate.status`. A token, not a bare dependency, because the engine
|
|
264
|
+
skips a node only when ALL its dependencies were skipped — so a failed gate beside a done
|
|
265
|
+
dependency would still admit the node. The gate itself always exits 0 (0329: an empty pool
|
|
266
|
+
is a no-content day, not a failed run).
|
|
267
|
+
dependsOn: [qc-content]
|
|
268
|
+
action:
|
|
269
|
+
kind: shell
|
|
270
|
+
options:
|
|
271
|
+
command: >-
|
|
272
|
+
OUT=".spur/run/${vars.__runId}-pool-gate.status";
|
|
273
|
+
mkdir -p "$(dirname "$OUT")";
|
|
274
|
+
if kk store pool-count "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json" --min 1;
|
|
275
|
+
then echo PASS > "$OUT";
|
|
276
|
+
else echo EMPTY > "$OUT"; rm -f "${vars.work_dir}/bundle.json"; fi
|
|
277
|
+
|
|
246
278
|
- id: select
|
|
247
279
|
description: >-
|
|
248
280
|
Record today's planned set in the store's topic-scoped `selections` ledger (0228). It runs at
|
|
@@ -250,7 +282,7 @@ nodes:
|
|
|
250
282
|
depends on the DAG reaching its tail: a run that fails, pauses at review or skips publish still
|
|
251
283
|
excludes what it planned. Guarded on the QC candidates — a pool that filtered to zero items
|
|
252
284
|
selects nothing.
|
|
253
|
-
dependsOn: [qc-content]
|
|
285
|
+
dependsOn: [qc-content, pool-gate]
|
|
254
286
|
condition:
|
|
255
287
|
kind: shell
|
|
256
288
|
options:
|
|
@@ -275,7 +307,7 @@ nodes:
|
|
|
275
307
|
|
|
276
308
|
- id: plan-translate
|
|
277
309
|
description: "Translate the needsTranslation plan items into the output plan.json via agent.run; onError: continue — plan-translate-retry below is the loud gate (0238 R2)"
|
|
278
|
-
dependsOn: [qc-content]
|
|
310
|
+
dependsOn: [qc-content, pool-gate]
|
|
279
311
|
condition:
|
|
280
312
|
kind: shell
|
|
281
313
|
options:
|
|
@@ -315,7 +347,7 @@ nodes:
|
|
|
315
347
|
VALID expectFile (missing or contract-violating JSON), retries the same input on a different
|
|
316
348
|
tier, and carries NO onError — a second miss fails the run loudly instead of letting an
|
|
317
349
|
untranslated or truncated plan flow downstream.
|
|
318
|
-
dependsOn: [plan-translate]
|
|
350
|
+
dependsOn: [plan-translate, pool-gate]
|
|
319
351
|
condition:
|
|
320
352
|
kind: shell
|
|
321
353
|
options:
|
|
@@ -335,7 +367,7 @@ nodes:
|
|
|
335
367
|
|
|
336
368
|
- id: article-write
|
|
337
369
|
description: "Write the tech-sharing prose article from the translated plan via agent.run (3-format split: surfdash gets prose, not a news list); onError: continue — article-write-retry below is the loud gate (0238 R2)"
|
|
338
|
-
dependsOn: [qc-content, plan-translate, plan-translate-retry]
|
|
370
|
+
dependsOn: [qc-content, plan-translate, plan-translate-retry, pool-gate]
|
|
339
371
|
condition:
|
|
340
372
|
kind: shell
|
|
341
373
|
options:
|
|
@@ -369,7 +401,7 @@ nodes:
|
|
|
369
401
|
Bounded recovery for article-write (0238 R2): runs only when the primary settled without its
|
|
370
402
|
expectFile, retries the same input on a different tier, and carries NO onError — a second miss
|
|
371
403
|
fails the run loudly instead of publishing an article nobody wrote.
|
|
372
|
-
dependsOn: [article-write]
|
|
404
|
+
dependsOn: [article-write, pool-gate]
|
|
373
405
|
condition:
|
|
374
406
|
kind: shell
|
|
375
407
|
options:
|
|
@@ -394,7 +426,7 @@ nodes:
|
|
|
394
426
|
this node: a done dependency in the mix keeps it runnable) as well as on both authoring nodes
|
|
395
427
|
AND their retry siblings, and it carries the same candidates guard — a pool that filtered to
|
|
396
428
|
zero items must not build an empty article.
|
|
397
|
-
dependsOn: [qc-content, plan-translate, plan-translate-retry, article-write, article-write-retry]
|
|
429
|
+
dependsOn: [qc-content, plan-translate, plan-translate-retry, article-write, article-write-retry, pool-gate]
|
|
398
430
|
condition:
|
|
399
431
|
kind: shell
|
|
400
432
|
options:
|
|
@@ -411,7 +443,7 @@ nodes:
|
|
|
411
443
|
# 0238 R3: reads 21-plan/<date>_03_plan_plan.json, so it must not start before the plan
|
|
412
444
|
# producers settle. `qc-content` stays in the list: a done dependency in the mix keeps this node
|
|
413
445
|
# runnable when the plan-authoring nodes are disabled (all-skipped deps skip a node).
|
|
414
|
-
dependsOn: [qc-content, plan-translate, plan-translate-retry]
|
|
446
|
+
dependsOn: [qc-content, plan-translate, plan-translate-retry, pool-gate]
|
|
415
447
|
condition:
|
|
416
448
|
kind: shell
|
|
417
449
|
options:
|
|
@@ -458,7 +490,7 @@ nodes:
|
|
|
458
490
|
|
|
459
491
|
- id: script-style
|
|
460
492
|
description: "Snapshot the shipped zh style contract into the work dir (separate node: it is also an audit input for the revision loop)"
|
|
461
|
-
dependsOn: [qc-content]
|
|
493
|
+
dependsOn: [qc-content, pool-gate]
|
|
462
494
|
condition:
|
|
463
495
|
kind: shell
|
|
464
496
|
options:
|
|
@@ -475,7 +507,7 @@ nodes:
|
|
|
475
507
|
# 0238 R3: reads 21-plan/<date>_03_plan_plan.json, so it must not start before the plan
|
|
476
508
|
# producers settle. `script-style` stays first in the list: a done dependency in the mix keeps
|
|
477
509
|
# this node runnable when the plan-authoring nodes are disabled (all-skipped deps skip a node).
|
|
478
|
-
dependsOn: [script-style, plan-translate, plan-translate-retry]
|
|
510
|
+
dependsOn: [script-style, plan-translate, plan-translate-retry, article, pool-gate]
|
|
479
511
|
condition:
|
|
480
512
|
kind: shell
|
|
481
513
|
options:
|
|
@@ -505,7 +537,7 @@ nodes:
|
|
|
505
537
|
Compile the episode plan Doc[] into structured broadcast VoiceScript YAML Content. Depends on
|
|
506
538
|
`article` so the node still runs when the plan-authoring nodes were disabled or skipped (the
|
|
507
539
|
builder falls back to templates) — but not when the whole content branch is skipped.
|
|
508
|
-
dependsOn: [article, script-style, script-write]
|
|
540
|
+
dependsOn: [article, script-style, script-write, pool-gate]
|
|
509
541
|
condition:
|
|
510
542
|
kind: shell
|
|
511
543
|
options:
|
|
@@ -558,7 +590,7 @@ nodes:
|
|
|
558
590
|
|
|
559
591
|
- id: wrap-docs
|
|
560
592
|
description: "Wrap VoiceScript into Doc[] input for the voice generator plugin (the generate-side variant input)"
|
|
561
|
-
dependsOn: [script, review]
|
|
593
|
+
dependsOn: [script, review, pool-gate]
|
|
562
594
|
condition:
|
|
563
595
|
kind: shell
|
|
564
596
|
options:
|
|
@@ -574,7 +606,7 @@ nodes:
|
|
|
574
606
|
description: "Voice tier, primary driver (vars.vdriver — voxcpm; its 40 ms lattice is known and monitored, see the vdriver comment). onError: continue — the fallback siblings below are the loud chain (same pattern as 0238 R2)."
|
|
575
607
|
# wrap-docs is a data dependency, not a sibling: daily-generate reads its _10_wrap-docs_docs.json
|
|
576
608
|
# as the TTS input. Without this edge the two nodes race in the same wave (0212 dogfood finding).
|
|
577
|
-
dependsOn: [script, safety, review, wrap-docs]
|
|
609
|
+
dependsOn: [script, safety, review, wrap-docs, pool-gate]
|
|
578
610
|
condition:
|
|
579
611
|
kind: shell
|
|
580
612
|
options:
|
|
@@ -582,8 +614,8 @@ nodes:
|
|
|
582
614
|
command: 'test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
583
615
|
action:
|
|
584
616
|
kind: shell
|
|
617
|
+
onError: continue
|
|
585
618
|
options:
|
|
586
|
-
onError: continue
|
|
587
619
|
command: >-
|
|
588
620
|
OMNIVOICE_SPEED=1.06 kk stage daily-generate "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.transcode_mp3}" "${vars.vdriver}" "1" "${vars.episode_max_minutes}" "${vars.episode_min_minutes}"
|
|
589
621
|
|
|
@@ -595,7 +627,7 @@ nodes:
|
|
|
595
627
|
|
|
596
628
|
- id: generate-fallback
|
|
597
629
|
description: "Voice tier fallback 1: gemini (gemini-tts) when the primary driver left no valid Content — the measured-dry escape hatch from voxcpm's lattice"
|
|
598
|
-
dependsOn: [generate]
|
|
630
|
+
dependsOn: [generate, pool-gate]
|
|
599
631
|
condition:
|
|
600
632
|
kind: shell
|
|
601
633
|
options:
|
|
@@ -605,14 +637,14 @@ nodes:
|
|
|
605
637
|
&& ! jq -e '(.metadata.generator == "kk:voxcpm-tts" or .metadata.generator == "kk:gemini-tts") and .metadata.qc.passed == true' "${vars.work_dir}/30-audio/${vars.run_date}_11_generate_content.json"
|
|
606
638
|
action:
|
|
607
639
|
kind: shell
|
|
640
|
+
onError: continue
|
|
608
641
|
options:
|
|
609
|
-
onError: continue
|
|
610
642
|
command: >-
|
|
611
643
|
kk stage daily-generate "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.transcode_mp3}" "gemini" "1" "${vars.episode_max_minutes}" "${vars.episode_min_minutes}"
|
|
612
644
|
|
|
613
645
|
- id: generate-fallback2
|
|
614
646
|
description: "Voice tier fallback 2 (last, loud): omni-voice-gen when neither voxcpm nor gemini delivered"
|
|
615
|
-
dependsOn: [generate-fallback]
|
|
647
|
+
dependsOn: [generate-fallback, pool-gate]
|
|
616
648
|
condition:
|
|
617
649
|
kind: shell
|
|
618
650
|
options:
|
|
@@ -626,9 +658,17 @@ nodes:
|
|
|
626
658
|
command: >-
|
|
627
659
|
OMNIVOICE_SPEED=1.06 kk stage daily-generate "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.transcode_mp3}" "ominivoice" "1" "${vars.episode_max_minutes}" "${vars.episode_min_minutes}"
|
|
628
660
|
|
|
661
|
+
# 0329 F15: a script-gate refusal produces no audio, but the sting must not fail the day —
|
|
662
|
+
# the refusal artifact admits intro (and duration closes the run as no-content on it).
|
|
629
663
|
- id: intro
|
|
630
664
|
description: "Prepend the 8s intro sting (intro_music var; empty = skip), update duration/audioPath"
|
|
631
665
|
dependsOn: [generate, generate-fallback, generate-fallback2]
|
|
666
|
+
condition:
|
|
667
|
+
kind: shell
|
|
668
|
+
options:
|
|
669
|
+
command: >-
|
|
670
|
+
test -f "${vars.work_dir}/30-audio/${vars.run_date}_11_generate_content.json"
|
|
671
|
+
-o -f "${vars.work_dir}/30-audio/${vars.run_date}_11_generate_content_duration-refusal.json"
|
|
632
672
|
action:
|
|
633
673
|
kind: shell
|
|
634
674
|
options:
|
|
@@ -658,32 +698,39 @@ nodes:
|
|
|
658
698
|
onError: continue
|
|
659
699
|
|
|
660
700
|
- id: duration
|
|
661
|
-
description: "Measured duration gate: under episode_min_minutes the run refuses and closes as no-content (refusal artifact + emptied candidates, exit 0 — 0266); above episode_max_minutes it still fails loud. Duration is authoritative."
|
|
701
|
+
description: "Measured duration gate: under episode_min_minutes the run refuses and closes as no-content (refusal artifact + emptied candidates + publish-path invalidation, exit 0 — 0266/0329); above episode_max_minutes it still fails loud. Duration is authoritative."
|
|
662
702
|
dependsOn: [intro]
|
|
663
703
|
action:
|
|
664
704
|
kind: shell
|
|
665
705
|
options:
|
|
666
706
|
command: >-
|
|
667
|
-
kk stage daily-episode-duration "${vars.work_dir}" "${vars.run_date}" "${vars.episode_min_minutes}" "${vars.episode_max_minutes}" "${vars.vdriver}"
|
|
707
|
+
kk stage daily-episode-duration "${vars.work_dir}" "${vars.run_date}" "${vars.episode_min_minutes}" "${vars.episode_max_minutes}" "${vars.vdriver}" "${vars.__runId}"
|
|
668
708
|
|
|
669
709
|
- id: quality
|
|
670
710
|
description: >-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
711
|
+
Print the daily QC table (daily-quality-report) and then gate on it (0329 F23): the print
|
|
712
|
+
alone never gated anything — a 41/100 episode sailed into show-notes, the bundle and the
|
|
713
|
+
publish windows. The verdict stage fails loud when the generator's audio qc verdict is
|
|
714
|
+
missing or `passed` is false, so a bad episode dies here instead of at a tier-0 send.
|
|
715
|
+
dependsOn: [duration, wrap-docs, pool-gate]
|
|
716
|
+
condition:
|
|
717
|
+
kind: shell
|
|
718
|
+
options:
|
|
719
|
+
# 0324 R3: the pool verdict is `pool-gate`'s token, never a repeated `kk store pool-count`.
|
|
720
|
+
command: 'test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
675
721
|
action:
|
|
676
722
|
kind: shell
|
|
677
723
|
options:
|
|
678
724
|
command: >-
|
|
679
725
|
kk stage daily-quality-report "${vars.work_dir}" "${vars.run_date}"
|
|
726
|
+
&& kk stage run daily-quality-verdict "${vars.work_dir}" "${vars.run_date}"
|
|
680
727
|
|
|
681
728
|
- id: show-notes
|
|
682
729
|
description: >-
|
|
683
730
|
Render timeline show notes from the episode plan — content, not publishing: the publish half
|
|
684
731
|
ships them as the episode variant's `metadata.showNotes`, and the link placeholders stay
|
|
685
732
|
unresolved until a send resolves them."
|
|
686
|
-
dependsOn: [quality]
|
|
733
|
+
dependsOn: [quality, pool-gate]
|
|
687
734
|
condition:
|
|
688
735
|
kind: shell
|
|
689
736
|
options:
|
|
@@ -694,13 +741,36 @@ nodes:
|
|
|
694
741
|
options:
|
|
695
742
|
command: >-
|
|
696
743
|
kk stage daily-show-notes "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}" "${vars.title}"
|
|
744
|
+
|
|
745
|
+
# 0329 F02: voice3 lost daily-publish-prep in the migration (voice2 keeps it at its :704), so
|
|
746
|
+
# `31-publish/<date>_13_publish-prep_content.json` — the episode variant's source — was never
|
|
747
|
+
# written by this workflow, and a freeze only succeeded against a stale same-day voice2 prep
|
|
748
|
+
# file. Rebuilt per the voice2 template: after duration (it reads the generate content's
|
|
749
|
+
# mp3Path, and ID3 stamps must land on the final post-intro MP3), pool-gated so a refused
|
|
750
|
+
# episode packages nothing.
|
|
751
|
+
- id: publish-prep
|
|
752
|
+
description: >-
|
|
753
|
+
Package the publish-ready episode Content (ID3 tags on the final post-intro MP3, cover
|
|
754
|
+
path, article link) into 31-publish/<date>_13_publish-prep_content.json — the episode
|
|
755
|
+
variant's source for bundle-variants.
|
|
756
|
+
dependsOn: [duration, article, safety, pool-gate]
|
|
757
|
+
condition:
|
|
758
|
+
kind: shell
|
|
759
|
+
options:
|
|
760
|
+
# 0324 R3: the pool verdict is `pool-gate`'s token, never a repeated `kk store pool-count`.
|
|
761
|
+
command: 'test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
762
|
+
action:
|
|
763
|
+
kind: shell
|
|
764
|
+
options:
|
|
765
|
+
command: >-
|
|
766
|
+
kk stage daily-publish-prep "${vars.work_dir}" "${vars.run_date}" "${vars.podcast_artist}" "${vars.podcast_album}"
|
|
697
767
|
- id: cards-write
|
|
698
768
|
description: "Plan the card series across the episode's plan items via agent.run; onError: continue — a failed plan skips the card series, never the run"
|
|
699
769
|
dependsOn: [script, review, pool-gate]
|
|
700
770
|
condition:
|
|
701
771
|
kind: shell
|
|
702
772
|
options:
|
|
703
|
-
command: 'test "${vars.cards_enabled}" = "true"'
|
|
773
|
+
command: 'test "${vars.cards_enabled}" = "true" && test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
704
774
|
action:
|
|
705
775
|
kind: agent.run
|
|
706
776
|
onError: continue
|
|
@@ -720,14 +790,14 @@ nodes:
|
|
|
720
790
|
|
|
721
791
|
- id: cards-render
|
|
722
792
|
description: "Render the card series through the pinned xhs-card/xhs-knowledge presets, attach the episode cover last and pair every image with its numbered line (0235 note_scope=episode); onError: continue — the publish node names the missing series and stays soft"
|
|
723
|
-
dependsOn: [cards-write]
|
|
793
|
+
dependsOn: [cards-write, pool-gate]
|
|
724
794
|
# A skipped cards-write still admits its dependents, so each card node keeps its own switch:
|
|
725
795
|
# without it a run with cards_enabled=false would re-package a stale same-day 25-xhs/ series.
|
|
726
796
|
# The pool guard is `pool-gate`'s alone in voice3 (0324 R3).
|
|
727
797
|
condition:
|
|
728
798
|
kind: shell
|
|
729
799
|
options:
|
|
730
|
-
command: 'test "${vars.cards_enabled}" = "true"'
|
|
800
|
+
command: 'test "${vars.cards_enabled}" = "true" && test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
731
801
|
action:
|
|
732
802
|
kind: shell
|
|
733
803
|
onError: continue
|
|
@@ -737,31 +807,12 @@ nodes:
|
|
|
737
807
|
|
|
738
808
|
# ---- generate-side payloads and the frozen bundle (0324 R2/R3) ----
|
|
739
809
|
|
|
740
|
-
# One guard for the whole pool (0324 R3): every node that used to repeat `kk store pool-count`
|
|
741
|
-
# depends on this one, so a refused pool empties the candidates file once and the rest of the
|
|
742
|
-
# graph skips through the engine's all-deps-skipped rule.
|
|
743
|
-
- id: pool-gate
|
|
744
|
-
description: >-
|
|
745
|
-
The single pool guard (0324 R3): `kk store pool-count --min 1` over the candidates file that
|
|
746
|
-
`qc-content` wrote, recorded once as a token at `.spur/run/<runId>-pool-gate.status`. voice2
|
|
747
|
-
repeated the same guard on twenty-one conditions. A token, not a bare dependency, because the
|
|
748
|
-
engine skips a node only when ALL its dependencies were skipped — so a failed gate beside a
|
|
749
|
-
done dependency would still admit the node. Everything downstream reads the token.
|
|
750
|
-
dependsOn: [qc-content]
|
|
751
|
-
action:
|
|
752
|
-
kind: shell
|
|
753
|
-
options:
|
|
754
|
-
command: >-
|
|
755
|
-
OUT=".spur/run/${vars.__runId}-pool-gate.status";
|
|
756
|
-
if kk store pool-count "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json" --min 1;
|
|
757
|
-
then echo PASS > "$OUT";
|
|
758
|
-
else echo EMPTY > "$OUT"; exit 1; fi
|
|
759
|
-
|
|
760
810
|
- id: social-write
|
|
761
811
|
description: >-
|
|
762
|
-
Author one short post per social platform (x, weibo, threads) from the approved
|
|
763
|
-
inside each platform's character cap. `daily-bundle-variants` truncates as a
|
|
764
|
-
missed cap degrades rather than fails; a missing file simply skips that
|
|
812
|
+
Author one short post per social platform (x, weibo, threads, linkedin) from the approved
|
|
813
|
+
plan, in zh, inside each platform's character cap. `daily-bundle-variants` truncates as a
|
|
814
|
+
backstop, so a missed cap degrades rather than fails; a missing file simply skips that
|
|
815
|
+
platform's variant.
|
|
765
816
|
dependsOn: [quality]
|
|
766
817
|
action:
|
|
767
818
|
kind: agent.run
|
|
@@ -771,10 +822,11 @@ nodes:
|
|
|
771
822
|
agent: ${vars.agent}
|
|
772
823
|
input: |
|
|
773
824
|
Read the approved episode plan at ${vars.work_dir}/21-plan/${vars.run_date}_03_plan_plan.json.
|
|
774
|
-
Write
|
|
825
|
+
Write four short zh posts, one per file:
|
|
775
826
|
- ${vars.work_dir}/26-social/x.md — at most 280 weighted characters (this feed counts CJK as 2, so ~140 汉字 or 280 Latin letters)
|
|
776
827
|
- ${vars.work_dir}/26-social/weibo.md — at most 2000 characters
|
|
777
828
|
- ${vars.work_dir}/26-social/threads.md — at most 500 characters
|
|
829
|
+
- ${vars.work_dir}/26-social/linkedin.md — at most 3000 characters
|
|
778
830
|
Each post: the day's single most interesting item, one concrete number or name from the
|
|
779
831
|
plan, no hashtag spam, no emoji, no "点击链接", no invented facts. Plain text, no markdown
|
|
780
832
|
headings. Deliver with your file-write tool; each file must be non-empty.
|
|
@@ -784,35 +836,83 @@ nodes:
|
|
|
784
836
|
description: >-
|
|
785
837
|
Build the channel payloads from the run's own artifacts (0327 builders): `30-variants/<key>`
|
|
786
838
|
for article / episode / cards plus the channel-specific keys and the social posts, all with
|
|
787
|
-
`{{article_url}}` / `{{podcast_url}}` placeholders because nothing is published yet.
|
|
788
|
-
|
|
839
|
+
`{{article_url}}` / `{{podcast_url}}` placeholders because nothing is published yet. 0329
|
|
840
|
+
F16: depends on every producer it reads (the 0324 file order alone was not a guarantee),
|
|
841
|
+
wipes stale variants first, and follows the cards/cover switches so a disabled producer's
|
|
842
|
+
variant is a skip, not a stale re-read.
|
|
843
|
+
dependsOn: [quality, social-write, publish-prep, cover-normalize, cards-render, pool-gate]
|
|
844
|
+
condition:
|
|
845
|
+
kind: shell
|
|
846
|
+
options:
|
|
847
|
+
# 0324 R3: the pool verdict is `pool-gate`'s token, never a repeated `kk store pool-count`.
|
|
848
|
+
command: 'test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
789
849
|
action:
|
|
790
850
|
kind: shell
|
|
791
851
|
options:
|
|
792
852
|
command: >-
|
|
793
853
|
kk stage run daily-bundle-variants "${vars.work_dir}" "${vars.run_date}" "${vars.plugins_path}"
|
|
854
|
+
"${vars.cards_enabled}" "${vars.cover_enabled}"
|
|
855
|
+
|
|
856
|
+
- id: safety-variants
|
|
857
|
+
description: >-
|
|
858
|
+
Final-variant safety review through the same nested kk-daily-safety machine (0331): the
|
|
859
|
+
manifest stage registers every `30-variants/*.content.json` first, then the machine runs in
|
|
860
|
+
the variants scope (`safety_scope_dir=4-safety-variants` re-roots its stages, guards and
|
|
861
|
+
prompts; the drafts review above is untouched). On an admitted outcome the machine leaves
|
|
862
|
+
`4-safety-variants/safety.json` — status, exclusion record and the sha256 of every reviewed
|
|
863
|
+
variant's current bytes — which publish-matrix-bundle freezes into the bundle so live
|
|
864
|
+
launches and social edits are gated on exactly the reviewed bytes. Fails closed: a block or
|
|
865
|
+
an integrity failure fails this node (the drafts scope's non-zero = never publish contract).
|
|
866
|
+
dependsOn: [bundle-variants, pool-gate]
|
|
867
|
+
condition:
|
|
868
|
+
kind: shell
|
|
869
|
+
options:
|
|
870
|
+
# 0324 R3: the pool verdict is `pool-gate`'s token, never a repeated `kk store pool-count`.
|
|
871
|
+
command: 'test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
872
|
+
action:
|
|
873
|
+
kind: shell
|
|
874
|
+
options:
|
|
875
|
+
command: >-
|
|
876
|
+
kk stage run daily-safety-manifest "${vars.work_dir}" "${vars.run_date}" &&
|
|
877
|
+
env -u SPUR_WORKFLOW_RUN_ACTIVE -u SPUR_EXPECTED_DEFINITION_DIGEST
|
|
878
|
+
spur workflow run plugins/kk/workflows/kk-daily-safety.yaml
|
|
879
|
+
--vars "{\"work_dir\":\"${vars.work_dir}\",\"run_date\":\"${vars.run_date}\",\"safety_max_revise\":\"${vars.safety_max_revise}\",\"safety_platforms\":\"${vars.safety_platforms}\",\"agent\":\"${vars.agent}\",\"safety_scope_dir\":\"4-safety-variants\"}"
|
|
880
|
+
--quiet --no-plan
|
|
794
881
|
|
|
795
882
|
- id: bundle-freeze
|
|
796
883
|
description: >-
|
|
797
884
|
Freeze `bundle.json` (0321 `BundleSchema`): every `30-variants/*` file with its sha256 plus the
|
|
798
885
|
episode title, so the publish half can run later, or three times a day, against exactly these
|
|
799
886
|
bytes. Fails when the article or episode variant is missing — a bundle never advertises what
|
|
800
|
-
generate did not produce.
|
|
801
|
-
|
|
887
|
+
generate did not produce. 0329 F15: token-gated, so a refused episode never freezes — the
|
|
888
|
+
duration gate also drops this run's bundle.json on a refusal. 0331: after safety-variants, so
|
|
889
|
+
the freeze reads the review's evidence (or the bundle stays without it, on a skipped run).
|
|
890
|
+
dependsOn: [bundle-variants, safety-variants, pool-gate]
|
|
891
|
+
condition:
|
|
892
|
+
kind: shell
|
|
893
|
+
options:
|
|
894
|
+
# 0324 R3: the pool verdict is `pool-gate`'s token, never a repeated `kk store pool-count`.
|
|
895
|
+
command: 'test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
802
896
|
action:
|
|
803
897
|
kind: shell
|
|
804
898
|
options:
|
|
805
899
|
command: >-
|
|
806
|
-
|
|
900
|
+
case "${vars.publish_preset}" in '') ARGS='' ;; *) ARGS="--preset ${vars.publish_preset}" ;; esac;
|
|
901
|
+
kk stage run publish-matrix-bundle "${vars.work_dir}" --run-date "${vars.run_date}" --run-id "${vars.__runId}" $ARGS
|
|
807
902
|
|
|
808
903
|
- id: generation-report
|
|
809
|
-
description: "The generate half's report (the publish half writes its own, per window)."
|
|
810
|
-
dependsOn: [bundle-freeze]
|
|
904
|
+
description: "The generate half's report (the publish half writes its own, per window). 0329 F15: real run-report flags — the phantom skip flag made every invocation exit 1; the pool/candidates/qc inputs are what let the report record a no-content close. Depends on pool-gate beside bundle-freeze: pool-gate always completes, so the report (and the ledger after it) also land on a no-content close — the design requires the report reachable from extract/QC/no-content, not only bundle-freeze."
|
|
905
|
+
dependsOn: [bundle-freeze, pool-gate]
|
|
811
906
|
action:
|
|
812
907
|
kind: shell
|
|
813
908
|
options:
|
|
814
909
|
command: >-
|
|
815
|
-
kk daily run-report --work-dir "${vars.work_dir}" --run-date "${vars.run_date}"
|
|
910
|
+
kk daily run-report --work-dir "${vars.work_dir}" --run-date "${vars.run_date}"
|
|
911
|
+
--pool "${vars.work_dir}/10-collect/pool.json"
|
|
912
|
+
--candidates "${vars.work_dir}/21-plan/${vars.run_date}_04_quality-control-content_candidates.json"
|
|
913
|
+
--plugins-path "${vars.plugins_path}"
|
|
914
|
+
--qc-min-quality "${vars.qc_min_quality}" --qc-min-importance "${vars.qc_min_importance}"
|
|
915
|
+
--qc-min-urgency "${vars.qc_min_urgency}" --qc-min-impact "${vars.qc_min_impact}"
|
|
816
916
|
|
|
817
917
|
- id: publish
|
|
818
918
|
description: >-
|
|
@@ -820,18 +920,18 @@ nodes:
|
|
|
820
920
|
window against the bundle this run just froze. The launcher vars are stripped at the nested
|
|
821
921
|
boundary (the same two voice2 strips for the safety machine), and the nested run's exit code is
|
|
822
922
|
surfaced — a failed publish window is a failed generate run's last step, never a silent one.
|
|
823
|
-
dependsOn: [generation-report]
|
|
923
|
+
dependsOn: [generation-report, pool-gate]
|
|
824
924
|
condition:
|
|
825
925
|
kind: shell
|
|
826
926
|
options:
|
|
827
|
-
command: 'test "${vars.auto_publish}" = "true"'
|
|
927
|
+
command: 'test "${vars.auto_publish}" = "true" && test "$(cat ".spur/run/${vars.__runId}-pool-gate.status" 2>/dev/null)" = PASS'
|
|
828
928
|
action:
|
|
829
929
|
kind: shell
|
|
830
930
|
options:
|
|
831
931
|
command: >-
|
|
832
932
|
env -u SPUR_WORKFLOW_RUN_ACTIVE -u SPUR_EXPECTED_DEFINITION_DIGEST
|
|
833
933
|
spur workflow run plugins/kk/workflows/kk-daily-publish3.yaml
|
|
834
|
-
--vars "{\"work_dir\":\"${vars.work_dir}\",\"run_date\":\"${vars.run_date}\",\"window\":\"${vars.publish_window}\",\"preset\":\"${vars.publish_preset}\",\"dummy\":\"${vars.publish_dummy}\"}"
|
|
934
|
+
--vars "{\"work_dir\":\"${vars.work_dir}\",\"run_date\":\"${vars.run_date}\",\"window\":\"${vars.publish_window}\",\"preset\":\"${vars.publish_preset}\",\"dummy\":\"${vars.publish_dummy}\",\"live_channels\":\"${vars.publish_live_channels}\"}"
|
|
835
935
|
|
|
836
936
|
- id: ledger
|
|
837
937
|
description: "Append this run to the workflow ledger; bookkeeping never fails a generation."
|