Take users from zero to being able to run their first prediction, all in ≤ 5 minutes (those with no posting history) or ≤ 10 minutes (those who have posted and need to import history).
Overview
[用户首次说"初始化"]
↓
[Phase 0: 检测当前状态]
↓
[Phase 1: 首屏文案 — 适用性 + 期望管理]
↓
[Phase 2: 6 个问题(Q1-Q5 都问;Q2 决定是否走 user-history import)]
↓
[Phase 2.5: 对标账号 — 强烈建议(cold-start 必须问,已发用户可选)]
↓
[Phase 3: 创建脚手架(含 scripts/ + videos/ + samples/ 空目录 + 模板文件含 benchmark.md)]
↓
[Phase 3.5: user-history import 流程(仅 Q2=有发过历史 + 用户同意)]
↓
[Phase 4: 测试 hook 是否生效]
↓
[Phase 5: 给"下一步该说什么"清单]
Constants
- DEFAULT_RETRO_WINDOW_DAYS = 3
- INSTALL_HOOKS = ask — default ask; user selects
autoinstall directly;skipdo not install - TREND_DEFAULT_SOURCES = ["manual-paste"]
Inputs
None. All information is collected from the 6 conversation questions.
Workflow
Phase 0: Detect current state
- Read the user's current working directory (the user's content project, not cheat-on-content itself)
- Check whether
.cheat-state.json:- already exists → prompt "The project appears to already be initialized (state file exists). Reinitializing will overwrite the existing configuration—confirm?" and continue only after the user explicitly confirms
- does not exist → proceed to Phase 1
- Check whether
rubric_notes.md/predictions/and other core files already exist—they exist but the state file does not → this is a "half-initialized" state; prompt the user and ask "Do you want to infer state from the existing files or reset?"
Phase 1: State expectations plainly on the first screen (including applicability validation)
Output to the user (word for word, do not soften):
🎯 Cheat on Content / 网红外挂 — 初始化
你的下一条内容已经在改写 3 个月后的你。
规律是客观存在的,区别是你**看见**还是**没看见**。
这套让你看见。
接下来 5-10 分钟我会问你 5-6 个问题搞清楚你做什么、有什么、怎么用。
两件事先说在前面:
1. **早期预测会不准**——前 5 篇精度大概 ±50%,这是数学事实。
工具用 🔴🟠🟡🟢🔵 标 confidence 等级,不藏数字——
你自己判断这次能不能信。
2. **强烈建议导对标账号**——5-10 条对标视频,工具立刻有 anchor。
不然第一批预测基本是占星。后面 Q5 会再问一次。
准备好开始吗?
If the user answers "continue" or a similar affirmative response → Phase 2.
No longer refuse to continue because of content_form—any form is allowed, it's just that the rubric_form_mismatch field marks it as true, and cheat-status will subsequently keep reminding the user "your form requires bump weight tuning."
Phase 2: 6 questions (one question one answer,do notask in batch)
Q1: Content form
"Which of these is your content closer to? a) opinion video(commentary / current affairs / argumentation / issue discussion / personal opinion) — directly matches the built-in rubric b) long-form essay(WeChat Official Account / Substack / Medium) — can start by borrowing the opinion video rubric, adjust weights when bumping c) short post / thread(X / Weibo / Jike) — same as above d) podcast / long-form video content(YouTube long-form / podcast) — same as above e) tutorial / tool teaching / Builder(teaching others how to use X tool / how to do Y project) — same as above f) other(gaming / food / makeup tutorials / news / narrative) — the workflow is general-purpose, but the rubric dimensions need adjustment (the ER / SR / HP set may not be very predictive for your form; you'll need to break out suitable dimensions yourself) g) mixed"
Record to content_form + rubric_form_mismatch。
Q1 → content_form enum mapping(must store the enum value, not the letter):
| User answers | content_form write value |
|---|---|
| a | "opinion-video" |
| b | "long-essay" |
| c | "short-text" |
| d | "podcast" |
| e | "tutorial-builder" |
| f | "other" |
| g | "mixed" |
rubric_form_mismatch derive:
- choose a →
false - choose b/c/d/e/f/g →
true, cheat-status keeps reminding "your form may require bump weight tuning" - there is no longer a "severe mismatch" tier—all forms can run the workflow, it's just that some rubrics need more aggressive bumping
Q1.5: Typical duration(only asked when Q1=a/d/f)
"Typical length of your videos? a) 30 seconds-1 minute b) 1-3 minutes c) 3-5 minutes (recommended starting point) d) 5-10 minutes e) 10+ minutes"
Record to typical_duration_seconds(30 / 90 / 240 / 450 / 900)。
Q1.6: Publishing frequency
"How often do you plan to post? a) Daily b) Every other day c) Weekly d) Flexible / irregular (turn off buffer monitoring)"
Record to target_publish_cadence_days(1 / 2 / 7 / null)。
Q2: Have you ever posted videos on this channel?
"a) Never posted — I'll help you brainstorm 5 candidates from your interests + hot topics + write 5 first drafts b) Have posted — whether it's 1 or 100, I'll help you pull your history so later brainstorms align better with what you've done"
If a is chosen → write state calibration_samples: 0,Phase 3.5 skipped, go straight to Phase 4.
If b is chosen → go to Q2.1。
Q2.1: Platform + scrape plan(only if Q2=b)
"Which platform is your content mainly on? a) Douyin — install the douyin-session adapter (Playwright + scan QR code to log in to Douyin Creator Center) b) Xiaohongshu — install the xhs-explore adapter (Playwright + scan QR code to log in to Xiaohongshu Creator Center) c) YouTube — install the youtube-data-api adapter (requires API key) d) Bilibili — bilibili-stat adapter e) LinkedIn — install the linkedin-session adapter (Playwright + log in to LinkedIn, scrape single-post analytics) f) WeChat Channels — install the wechat-channels adapter (Playwright + scan QR code to log in to Channels Assistant, only scrapes your own account's backend data) g) Other / multiple platforms — use manual paste mode"
If a/b/c/d/e/f is chosen → ask Q2.2; if g is chosen → skip to Q2.3 manual.
Q2.2: When to install the adapter(only if Q2.1=a/b/c/d/e/f)
"Install the adapter now for automatic scraping, or tell me manually first?
- Install now — I'll guide you through installing Playwright + scanning the QR code → scrape back the most recent N posts
- Install later — use manual mode for now, mark state as 'pending_adapter_setup', cheat-status keeps reminding you to install"
If "install now" is chosen → go through the adapter install guide (see each adapter's README for details) → verify scraping works → Q2.3. If "later" is chosen → skip to Q2.3 manual.
Q2.3: Scrape scope / history size
If the adapter is installed and verified working:
"How many of your most recent posts can I scrape as a baseline? (suggested 10-25; the more samples, the more accurate the baseline. Up to your account's actual count)" → user gives a number N, Phase 3.5 scrapes N posts
If manual mode:
"Roughly how many posts have you made? A range is fine (e.g. '5-10 posts' / '20+ posts'), this is only used to estimate calibration_samples, it doesn't need to be exact." → user gives an estimate, Phase 3.5 skips scraping, calibration_samples is set to the estimate
Q3: Data collection method
"How do you get data for the T+3 day review?
a) Manual paste — fallback option.You must paste the top 20+ comments (with like counts), not just the view count. Comments are the real signal — a meme explosion like 'she's different' can only be seen from comments, view count will never tell you what content really hit the audience. b) [recommended default] adapter auto-scrape — comments + data, all of it. If you don't have an adapter installed right now, that's fine, mark state as 'pending_adapter_setup', just install it before your first publish (cheat-status will keep reminding you to install). The install guide is at adapters/perf-data//README.md."
Q3 → data_collection enum mapping:
| User answer | data_collection write value |
|---|---|
| a | "manual" |
| b (default) | "adapter" |
Default recommendation is b—unless the user explicitly says "a, I want manual".
Q4: Candidate topics
"Do you currently have a candidate topic list? (e.g., maintained externally in markdown / Notion) a) No (default) — I'll help you brainstorm in a bit, or use /cheat-trends to scrape on a daily basis b) Yes, a markdown list c) Yes, Notion / other"
Q4 → pool_status enum mapping:
| User answer | pool_status write value |
|---|---|
| a (default) | "none" |
| b | "markdown" |
| c | "notion" |
Q5: Install a few hooks (installed by default, no need for you to decide)
"Q5: I'll install a few hooks along the way; reply 'yes' or 'enter' to install:
Prediction lock — After we finish making predictions together, the file is locked. Neither you nor I can modify the prediction section. Retrospectives can only be appended to the lower half of the same file, without polluting the judgment in the upper half. (Without this lock, after seeing the data, wanting to "fix the prediction from back then" is almost inevitable—both you and I would do it)
SessionStart automatic report — Display buffer / pending retrospectives / candidate top at the top of every new session
Silent usage log — Asynchronously record usage frequency, non-blocking, for future diagnostics
Install all three together.Not installing is also fine(reply 'no') but you lose the prediction lock, and calibration value will decrease.
Reply yes / no."
Q5 → hooks_installed mapping:
| User answer | hooks_installed write value |
|---|---|
| yes / enter / default | true(bool,Not a string "yes") |
| no | false |
Default is yes—unless the user explicitly says no.
Phase 2.5: Benchmark accounts (asked of all users, strongly recommended for cold-start)
The most important signal source in the tool's early stage isbenchmark accounts—After you init, there's no data, and an equal-weight v0 rubric is equivalent to astrology. But if you can find an account you want to become like, and import 5-10 of its high / medium / low samples, the tool has an anchor.
Ask:
🎯 对标账号
你能找一个对标账号吗?至少 3 条该账号的视频。
- 你**完全没发过历史**(Q2=a)→ **强烈建议**——rubric 没 anchor 全靠对标。
不找的话用通用 v0 等权 rubric,前 5 篇精度更差更久
- 你**已发历史**(Q2=b)→ **可选**——你也可以只用自己历史 calibrate;
但建议至少导 1 个对标做 sanity check(看你账号是否真的偏离对标方向)
a) 现在找 → 立刻进入 /cheat-learn-from(5-15 分钟,看你材料准备程度)
b) 等下找 → state 标 `benchmark_status: pending`,cheat-status 持续提醒
c) 不找 → state 标 `benchmark_status: none`,用通用 v0 起步
回 a / b / c。
Behavior:
- Choose a → After Phase 3 finishes creating the scaffold,automatically dispatch to /cheat-learn-from(don't make the user run it manually—it's already in the init flow). After completion, return to init Phase 4
- Choose b → mark state as
benchmark_status: pending+benchmark_name: null - Choose c → mark state as
benchmark_status: none
Record to benchmark_status / benchmark_name(if a is chosen, write it in cheat-learn-from).
Phase 3: Create scaffold (explain item by item)
Create in order andexplain the purpose of each item:
-
.gitignore(security — must be created as the first step)"先创建 .gitignore,把账号凭证挡在版本控制外——这是第一件事。 .auth/ / .auth-xhs/ / .auth-linkedin/ / .auth-wechat-channels/ 存的是各平台登录态(等同账号密码), .cheat-secrets.json 存 API key / cookie——一旦被 commit 或云同步就等于泄露账号。 注意:predictions/ videos/ scripts/ 这些**不**忽略——原则 #1/#3 依赖 git history 作为预测的不可变档案,必须入库。"- Copy
cheat-on-content/templates/gitignore.template→<user-repo>/.gitignore - If
<user-repo>/.gitignorealready exists → do not overwrite; check line by line andappend missing lines, at minimum ensure.auth/、.auth-xhs/、.auth-linkedin/、.auth-wechat-channels/、.cheat-secrets.jsonfive lines exist - Even if the user's project currentlyis not yet a git repositorycreate it as usual—it will take effect immediately at the moment the user
git inittakes effect immediately at the moment of - After creating, remind them: if the project has already
git initand may have mistakenly added.auth/, letting users rungit rm -r --cached .auth .auth-xhs .auth-linkedin .auth-wechat-channels .cheat-secrets.jsonmove the already-staged credentials out
- Copy
-
.cheat-state.json"正在创建 .cheat-state.json — 各子 skill 共享上下文的地方。 这次 init 收集的所有答案都会写在这里。"write (all
<...>placeholders must be looked up in the Q mapping table above and replaced with concrete enum values; never store the letters directly):{ "schema_version": "1.4", "skill_version": "1.0.0", "rubric_version": "v0", "content_form": "<查 Q1 映射表,写 enum 字符串如 \"opinion-video\">", "typical_duration_seconds": <Q1.5 派生:30/90/240/450/900>, "target_publish_cadence_days": <Q1.6 派生:1/2/7/null>, "rubric_form_mismatch": <Q1=a→false;其他→true>, "benchmark_status": "<Phase 2.5 派生:a→\"imported\"/b→\"pending\"/c→\"none\">", "benchmark_name": <imported 则字符串名,否则 null>, "benchmark_sample_count": <imported 则数字,否则 0>, "baseline_plays": null, "calibration_samples": <Q2=a→0;Q2=b→Phase 3.5 import 回填或 Q2.3 估值>, "data_collection": "<查 Q3 映射表,写 \"manual\" 或 \"adapter\">", "pool_status": "<查 Q4 映射表,写 \"none\"/\"markdown\"/\"notion\">", "data_layer": "markdown", "hooks_installed": <查 Q5 映射表,写 bool true/false>, "enabled_trend_sources": ["manual-paste"], "enabled_perf_adapters": <Q2.1=a→[\"douyin-session\"];b→[\"xhs-explore\"];c→[\"youtube-data-api\"];d→[\"bilibili-stat\"];e→[\"linkedin-session\"];f→[\"wechat-channels\"];其他→[]>, "last_bump_at": null, "last_bump_self_audited": false, "last_published_at": null, "last_published_file": null, "last_retro_at": null, "last_trends_run_at": null, "last_trends_added_count": 0, "last_prediction_self_scored": false, "last_self_scored_at": null, "consecutive_directional_errors": [], "pending_retros": [], "shoots": [], "in_progress_session": null, "initialized_at": "<本地 ISO 8601 含时区,如 \"2026-05-05T20:11:13+08:00\",**不要用 UTC 的 Z 后缀**>" } -
rubric_notes.md"正在创建 rubric_notes.md — 你的评分维度的真实来源。 用的是 v0 占位 rubric——等权 7 维(每个维度同等重要)。 为什么叫 v0:v0 是没校准前的占位。你的账号自己的真权重要从你 的数据反推,不是预设。跑完 5 篇有数据的内容后,会自动提议 升级到「校准 v1」(你的第一个真正校准过的 rubric)。 ⚠️ rubric_notes.md 是 blind sub-agent (channel B) 的白名单文件—— 只能含通用语言(公式 / 维度定义 / bucket 边界),不能含真实视频名 / 实绩。 每次 bump 升级时的 Memo(含证据数据 + 派生证据)写到 rubric-memo.md(下一步创建)。"- Copy
cheat-on-content/starter-rubrics/<form>-zero.md(cold-start) or<form>.md(can still be referenced when data already exists)
- Copy
2.5. rubric-memo.md(new—together with the cheat-score-blind isolation protocol)
"正在创建 rubric-memo.md — bump 升级 Memo 累积档案。
这是 cheat-bump Phase 5 写入 Memo 全文(含真实视频名 + 实绩 + 派生证据)的位置。
为什么单独一个文件:blind sub-agent 的白名单是 rubric_notes.md,
历史上 bump Memo 写进 rubric_notes.md 会让 blind sub-agent 通过白名单
拿到本该看不到的实绩数据——本文件是隔离修复,sub-agent 硬禁读本文件。
现在是空的,等第一次 cheat-bump 升级后 append 第一段 Memo。"
- Copy
cheat-on-content/templates/rubric-memo.template.md→<user-repo>/rubric-memo.md
-
script_patterns.md"正在创建 script_patterns.md — 你的写作 pattern 沉淀(与 rubric 解耦)。 rubric_notes.md 教 Claude 怎么打分; script_patterns.md 教 Claude 怎么写。"- Copy
cheat-on-content/templates/script_patterns.template.md
- Copy
-
four directories:
scripts/+predictions/+videos/+samples/(all add.gitkeep)"正在创建四个目录: scripts/ — 拍前的草稿(cheat-seed 写或你写) predictions/ — immutable 预测日志(hook 保护) videos/ — 拍后的工作目录(cheat-shoot 创建子目录) samples/ — 对标账号视频 / 转录(cheat-learn-from 创建子目录) 前三处用同一组 <date>_<id>_<short> 命名相互关联。 samples/ 按对标账号名分组:samples/<账号名>/<video-id>/。"
4.5. benchmark.md(only when choosing a/b in Phase 2.5)
"正在复制 benchmark.md 占位模板(实际内容由 cheat-learn-from 填)——
这是你的对标账号的中央 reference。
前期工具的 rubric / pattern / 选题方向感大量从这里推;
后期 N≥10 后影响淡出,但保留作 sanity check。"
- Copy
cheat-on-content/templates/benchmark.template.md→<user-repo>/benchmark.md - Phase 2.5 choosing c does not create → benchmark.md does not exist, state marked
benchmark_status: none
4.7. audience.md
"正在创建 audience.md — 你账号的受众画像('谁在看')。
现在是空骨架。它和 rubric_notes.md 平行——rubric 教 Claude 怎么打分,
audience 告诉 Claude 你的观众是谁。跑够几篇复盘后跑 /cheat-persona,
它会从评论数据聚类出真实画像,cheat-seed 选题写稿时就有了一面镜子。
注意:audience.md 由评论派生 → 含实绩信号 → blind 打分 sub-agent 硬禁读它。"
- Copy
cheat-on-content/templates/audience.template.md→<user-repo>/audience.md - If Phase 2.5 chose a/b (has benchmark) → in the Phase 5 checklist, prompt "can run
/cheat-persona — seed-from-benchmarkseed an unverified profile first"
-
WORKFLOW.md+STATUS.md- Copy the corresponding file from templates/
-
If Q5=yes → install hooks
- Read
.claude/settings.json(if it does not exist, create an empty{}) - merge into
hooks/prediction-immutability.json'shooks.PreToolUse - merge into
hooks/session-start.json'shooks.SessionStart - merge into
hooks/meta-logging.json's hooks (if enabled at the same time) - Copy
prediction-immutability.sh+session-start.sh+log-event.shto.cheat-hooks/,chmod +x - the command path inside settings.json uses
${CLAUDE_PROJECT_DIR}/.cheat-hooks/
- Read
-
(Pool option c—Notion) only record to the state file's
pool_status: notion, to be handled later when cheat-trends is called
Phase 3.5: import flow (only Q2=b and user agrees to scrape)
If Q2.2=install now → go through adapter install + login (see adapters/perf-data//README.md)。
After a successful scrape, for each published video:
- create video folder:
videos/<date>_<id>_<short>/<date>= the video's actual publish date<id>= 12-digit hash, sha256 of (title + platform ID)<short>= first 3-8 characters of the title
- write report.md: fill in with the data scraped back from the adapter (plays / likes / comments / shares / top comments)
- ask the user for the original script: "video 「{title}」 did you keep the original script?"
- Yes → user provides it → save as
videos/<id>/script.md - No → mark
script_lost(still create the video folder, just script.md is missing)
- Yes → user provides it → save as
- write reconstructed prediction:
predictions/<date>_<id>_<short>.md- header marked
**Reconstructed retrospective — NOT a blind prediction** - 7-dimension scoring is based on script + retrospective-period actual performance datascore in reverse—make clear this is for non-calibration purposes
- not counted in calibration_samples (this is imported history, not calibration accumulation)
- header marked
After import is complete:
- derive
baseline_plays= median plays of the scraped videos → write to state file - derive confidence level → use it directly later when cheat-predict writes predictions
- output summary: "Imported N history entries. The most recent one has X w plays, median Y w, created N video folders + reconstructed predictions"
Phase 4: test whether the hook takes effect (only when Q5=yes)
run a fake Edit interception test:
- create a temporary file
predictions/_test_hook.md, including## 预测\n[test]\n## 复盘\n - Attempt to Edit this file's
## 预测section - The hook should exit 1 to block → report "✅ immutability hook is in effect"
- Delete the test file
- SessionStart hook verification: call it once directly
bash .cheat-hooks/session-start.sh→ should output a report (even an empty one is fine)
If the hook is not in effect → do not pretend success, clearly tell the user: "Hook installation failed; it may be that the .claude/settings.json configuration did not take effect. It is recommended to check manually or restart Claude Code."
Phase 4.5: if Phase 2.5 chose a → dispatch to /cheat-learn-from
If the user chose a in Phase 2.5 (import a benchmark account now) → automatically trigger /cheat-learn-from:
✅ 脚手架 + hooks 装完。
下面立刻进入 /cheat-learn-from 帮你导入对标账号——
你 init 时选了"现在找",不让你又开一个会话才跑。
[invoke /cheat-learn-from]
After cheat-learn-from completes, return to init's Phase 5.
If Phase 2.5 chose b/c → skip Phase 4.5, go directly to Phase 5.
Phase 5: give a "what to say next" checklist
✅ 初始化完成(rubric: v0,calibration_samples: <N>,confidence: <emoji 等级>)
下次你可以直接说这些:
📝 写完一篇稿子 → "打分这篇 scripts/<...>.md"
🎯 准备发布前 → "启动预测 scripts/<...>.md"
🎬 拍完了 → "拍了 scripts/<...>.md" → 建 video folder + buffer +1
🚀 发布后 → "已发布 https://..."
📊 T+3 天 → "复盘 videos/<...>/"
📈 任何时候 → "状态"(看完整看板)
<如果 Q4=没有候选选题:>
🌱 现在跑 /cheat-seed 找选题?
- 没发过历史的:纯 brainstorm(兴趣 × 热点)
- 发过历史的(已 import):brainstorm 会基于你过去做过什么给推荐
回 "yes, seed" 立刻跑,回 "no" 你自己想。
💡 你的 confidence 是 <当前等级> —— 它会随着你跑更多复盘自动提升。
不要因为 confidence 低就跳过预测——预测的纪律本身就是工具的核心,
早期预测的"价值"是数据采集,不是决策。第 5 次复盘后 rubric 第一次校准,
confidence 会跨入 🟡 偏低;第 10 次后 🟢 中。
Key Rules
- Do not pretend success: if any step fails → clearly tell the user which step went wrong. Never write "✅ Initialization complete" if it is not actually complete
- Do not ask questions in bulk: ask the 5 questions one at a time
- Do not silently mkdir: explain the purpose of every file you create
- Do not push SQLite: give all users markdown, and just mention "once you reach 30 entries, an upgrade will be recommended"
- Unify state fields: delete enum fields such as mode / prediction_complexity / bucket_scheme — use only the calibration_samples integer + confidence derivation
- Import failures do not block: Q2=b but adapter installation fails / scraping fails → gracefully degrade to "mark calibration_samples as an estimate, do not import the historical video folder"
Refusals
- "Skip Q1-Q5, just create all the files for me" → refuse. The question answers directly affect the default configuration (content_form, cadence, hooks)
- "I have already initialized elsewhere, sync that project's configuration over" → be cautious. Tell the user to manually cp the existing
.cheat-state.jsonandrubric_notes.md, do not automatically sync across projects - "Do not install hooks but keep the immutability promise" → allowed, mark state as
hooks_installed: false, and cheat-status continuously reminds "your immutability is a gentleman's agreement"
Integration
- After writing is complete, the routing in the main SKILL.md unlocks all other sub-skills
cheat-statusreads the.cheat-state.json'scalibration_samplesfield to decide which confidence level to display- If Q2=b took the import path → historical reconstructed predictions go into
predictions/andvideos/<...>/, butdo notcount toward calibration_samples (they are not real calibration samples) /cheat-seedreads all historical reconstructed predictions inpredictions/→ during brainstorm it knows "what the user has done in the past"
State field write checklist
| Field | When to write | Source |
|---|---|---|
schema_version |
Phase 3 | Hardcoded "1.4" |
skill_version |
Phase 3 | Hardcoded "1.0.0" |
rubric_version |
Phase 3 | "v0" |
content_form |
Phase 3 | Q1 → look up the mapping table to convert the enum value (not letters) |
typical_duration_seconds |
Phase 3 | Derived from Q1.5 |
target_publish_cadence_days |
Phase 3 | Derived from Q1.6 |
rubric_form_mismatch |
Phase 3 | Q1≠a → true |
benchmark_status |
Phase 3 / 2.5 | Derived from the Q2.5 answer |
benchmark_name |
Phase 3 / 2.5 | Q2.5 user-provided |
benchmark_sample_count |
Phase 3 / 2.5 | cheat-learn-from backfilled after import |
baseline_plays |
Phase 3.5 (if import succeeds) | median of imported data; otherwise null |
calibration_samples |
Phase 3 / Phase 3.5 | Q2=a→0; Q2=b→Q2.3 estimated or imported number |
data_collection |
Phase 3 | Q3 → look up mapping table and replace with enum value |
pool_status |
Phase 3 | Q4 → look up mapping table and replace with enum value |
enabled_perf_adapters |
Phase 3 | Q2.1 derived (if Q2=a then []) |
hooks_installed |
Phase 3-4 | Q5 → bool (not a string) |
last_bump_at / last_published_at / last_published_file / last_retro_at / last_trends_run_at |
Phase 3 | all null |
last_bump_self_audited |
Phase 3 | false |
last_trends_added_count |
Phase 3 | 0 |
last_prediction_self_scored |
Phase 3 | false |
last_self_scored_at |
Phase 3 | null |
initialized_at |
Phase 3 | now() local ISO 8601, including +08:00 timezone,do not use UTC Z |