@geoly-ai/social-hub-cli 0.3.18 → 0.3.19
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/CHANGELOG.md +14 -0
- package/dist/cmd-manifest.json +2 -2
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +69 -7
- package/dist/index.js.map +1 -1
- package/dist/scrape-output.test.d.ts +2 -0
- package/dist/scrape-output.test.d.ts.map +1 -0
- package/dist/scrape-output.test.js +58 -0
- package/dist/scrape-output.test.js.map +1 -0
- package/package.json +2 -2
- package/skills/manifest.json +1 -1
- package/skills/reddit-content-writing/SKILL.md +1 -1
- package/skills/reddit-content-writing/references/phase4-execution-table.md +24 -3
- package/skills/reddit-content-writing/references/phase4-writing.md +123 -3
- package/skills/reddit-content-writing/references/post-writing-templates.md +14 -6
- package/skills/reddit-delivery-check/SKILL.md +1 -0
- package/skills/reddit-delivery-check/references/phase5-delivery.md +7 -1
- package/skills/reddit-matrix.lock.json +8 -8
- package/skills/reddit-phase-brief/SKILL.md +25 -9
- package/skills/reddit-phase-brief/references/brand-SKU-PGC-rules.md +223 -36
- package/skills/reddit-phase-brief/references/phase4-brief-workflow.md +364 -18
- package/skills/reddit-phase-planning/SKILL.md +13 -0
- package/skills/reddit-phase-planning/references/phase4-execution-table.md +16 -2
- package/skills/reddit-phase-planning/references/phase4-planning.md +74 -15
- package/skills/reddit-phase-planning/references/scheduling-decision-procedure.md +386 -0
- package/skills/reddit-phase-research/SKILL.md +7 -1
- package/skills/reddit-phase-research/references/phase01-research.md +93 -29
- package/skills/reddit-strategy-orchestrator/SKILL.md +120 -18
- package/skills/reddit-strategy-shared/SKILL.md +4 -2
- package/skills/reddit-strategy-shared/references/content-diversity-contract.md +19 -3
- package/skills/reddit-strategy-shared/references/context-contract.md +45 -11
- package/skills/reddit-strategy-shared/references/evidence-policy.md +139 -0
- package/skills/reddit-strategy-shared/references/handoff-schemas.md +16 -1
- package/skills/reddit-strategy-shared/references/path-conventions.md +26 -4
- package/skills/reddit-strategy-shared/references/prerequisites/README.md +57 -0
- package/skills/reddit-strategy-shared/references/prerequisites/{reddit-master-canvas-agent-prompt-template.md → archive/reddit-master-canvas-agent-prompt-template.md} +7 -0
- package/skills/reddit-strategy-shared/references/prerequisites/{reddit-sop-v2-universal.md → archive/reddit-sop-v2-universal.md} +7 -0
- package/skills/reddit-strategy-shared/references/prerequisites/{reddit-strategy-prerequisites-read.md → archive/reddit-strategy-prerequisites-read.md} +7 -0
- package/skills/reddit-strategy-shared/references/prerequisites/{reddit-strategy-reuse-playbook.md → archive/reddit-strategy-reuse-playbook.md} +7 -0
- package/skills/reddit-strategy-shared/references/subreddit-research-profile.md +514 -0
- package/skills/reddit-strategy-shared/references/version-manifest.md +29 -2
- package/skills/reddit-voc-volume/matrix-contract.md +16 -1
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
# SubredditResearchProfile(SRP)契约
|
|
2
|
+
|
|
3
|
+
板块级研究画像的**唯一契约源**。research / compliance / brief / planning 四个阶段直接消费它,
|
|
4
|
+
writing 侧**只间接消费 Brief 传下来的结果**(writing 是 baseline-first,不得临场拿 SRP 改结构)。
|
|
5
|
+
因为消费者跨阶段,它住在 shared 层——放进任一阶段的 references 会造成 owner 争夺(现有两份分叉的
|
|
6
|
+
`reddit-phase-planning/references/phase4-execution-table.md` 就是这么来的)。
|
|
7
|
+
|
|
8
|
+
本文件定义 **schema、采样帧规则、分母不变量、分字段 TTL、置信度状态机、S1–S9 标准作业步骤、
|
|
9
|
+
校验规则**。**具体板块的画像实例不放在 skill 里**——实例存 Hub,运行时由 CLI 拉取并校验
|
|
10
|
+
`schemaVersion` 与 freshness(见 §9)。
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. SRP 回答什么、不回答什么
|
|
15
|
+
|
|
16
|
+
SRP 回答:**这个板块整体是什么样、数据覆盖到什么程度、哪些进入方式有证据支持、有哪些风险信号。**
|
|
17
|
+
|
|
18
|
+
**SRP 不做发布放行。** 板块资格(eligibility)仍然只由 `reddit-subreddit-compliance` 的输出决定;
|
|
19
|
+
这与 `references/evidence-policy.md` 的 Source Layers 一致,SRP 不改这条。SRP 为 compliance 提供
|
|
20
|
+
统计证据与风险信号,但**不得自行宣布「允许 / 禁止 / 可以进」**。
|
|
21
|
+
|
|
22
|
+
### 1.1 三层不合表(与 `docs/subreddit-ops-data-and-post-style-design.md` 的三层不合表要求同源)
|
|
23
|
+
|
|
24
|
+
| 层 | 回答 | 粒度 | 治理 | 不承担 |
|
|
25
|
+
|---|---|---|---|---|
|
|
26
|
+
| **SRP**(本文件) | 板块整体是什么样、覆盖度多少、进入方式有哪些证据 | subreddit × 时间窗 | Hub 实例 + HITL 审批 | 发布放行、替代 compliance、写作模板 |
|
|
27
|
+
| **baseline 卡**(`reddit-content-writing/references/phase4-writing.md` W-1.b) | **这个 flair** 的帖该怎么写 | subreddit × `AssignedFlair` | Brief 阶段产出,新鲜期默认 60 天 | 板块整体分布、合规裁决 |
|
|
28
|
+
| **`subreddit_style_profiles`**(`packages/contracts/src/subreddit-style-profile.ts`) | 审核门 prompt 的 tone/style/taboo **soft enrich** | subreddit(+ brand override) | 四眼 propose/approve/retire | 研究统计、发布资格 |
|
|
29
|
+
|
|
30
|
+
**三者不合并、不互相覆盖、不互相绕过:**
|
|
31
|
+
|
|
32
|
+
- SRP 的 `flairDistribution` **不能**替代 baseline 卡;baseline 卡 60 天新鲜期门禁不因为 SRP 是
|
|
33
|
+
`Verified`(TTL 90 天)而放宽。SRP 是 baseline 的**研究输入**,不是它的替代品。
|
|
34
|
+
- `subreddit_style_profiles` 很薄(`tone` / `stylePoints` / `taboos` / `brandFriendliness`),且其
|
|
35
|
+
生成器只取**近 30 天 score Top N**(`apps/worker/src/handlers/subreddit-style-profile-generation.ts`)。
|
|
36
|
+
**它的取样帧在方法上就不能作为 SRP 的全窗口分母**,SRP 不得复用它的 status,也不得把 SRP JSON
|
|
37
|
+
塞进它的 `profile` 字段。
|
|
38
|
+
- `brandFirstMentionHistogram` 在 SRP 与 baseline 卡里都存在:**SRP 记板块整体,baseline 卡记单
|
|
39
|
+
flair / 单内容功能**。两处都必须标明统计层级;层级不同的直方图不得互相覆盖或平均。
|
|
40
|
+
- `contentTypes[]` 必须是对既有**帖子级分类**(`content_classification_runs` 的输出)的
|
|
41
|
+
**板块级投影**,**不得另造一套 taxonomy**。`subreddit_post_annotations` 是 1–5 分的人工评价,
|
|
42
|
+
**不是** content type 来源(详见 §5.2)。
|
|
43
|
+
|
|
44
|
+
### 1.2 为什么需要 SRP:top-N 采样产不出全板占比
|
|
45
|
+
|
|
46
|
+
现有研究 SOP(`reddit-phase-research/references/phase01-research.md` 步骤 0.5.5「板块内容深度分析」)用
|
|
47
|
+
`--sort top --limit 50` 采样。**top-N 是按 score 排序的偏差样本,统计上不可能产出可信的全板块占比。**
|
|
48
|
+
标杆产物的核心资产是**全窗口的 flair 分布**——分母明确的全量占比。这个方法论差距由 §4 的采样帧
|
|
49
|
+
硬规则制度化:**采样帧决定一张卡能声称什么,而不是由作者的措辞决定。**
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 2. 头部字段(identity / 采样帧 / 分母 / 治理)
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
# --- identity(实例身份,不是 schema 身份)---
|
|
57
|
+
profileId: # Hub 侧不可变实例 id
|
|
58
|
+
revisionId: # 同一 profileId 的修订号;内容变更即新 revision
|
|
59
|
+
schemaVersion: # 本契约的版本(如 srp/1)。schemaVersion ≠ 实例版本
|
|
60
|
+
subreddit: # 规范化:剥 r/ 前缀、trim、小写
|
|
61
|
+
|
|
62
|
+
# --- 采样帧 ---
|
|
63
|
+
windowStart: # ISO8601,内容时间(created_utc)口径,非观测时间
|
|
64
|
+
windowEnd:
|
|
65
|
+
samplingFrame: # FullWindow | TimeStratified | TopN
|
|
66
|
+
timeStratification: # 仅 TimeStratified:切片粒度 + 每片是否全量 + 加权方法
|
|
67
|
+
provider: # 采集通道(hub_cache | hub_dispatch | emergency_local | arctic ...)
|
|
68
|
+
|
|
69
|
+
# --- 分母三件套(缺一不可,见 §3)---
|
|
70
|
+
fetchedN: # 抓到的原始条数(未去重)
|
|
71
|
+
dedupedN: # 去重后条数
|
|
72
|
+
eligibleN: # 资格过滤后、进入统计的分母
|
|
73
|
+
excludedByReason: # {Removed, Deleted, ModPost, AutoMod, TemplateDuplicate, Unresolved}
|
|
74
|
+
# Unresolved = 无法判定是否合资格;必须显式计数,不得蒸发
|
|
75
|
+
unknownFlairN: # eligibleN 的子集:无 flair 或 flair 不可判定
|
|
76
|
+
|
|
77
|
+
# --- 治理 ---
|
|
78
|
+
confidence: # Verified | Provisional | Insufficient(见 §7)
|
|
79
|
+
computedAt:
|
|
80
|
+
fieldTtls: # 见 §6
|
|
81
|
+
effectiveFreshUntil: # 见 §6.2,派生值
|
|
82
|
+
approvalStatus: # Draft | InReview | Approved | Superseded | Rejected
|
|
83
|
+
approvedBy:
|
|
84
|
+
approvedAt:
|
|
85
|
+
supersedes: # 被本卡取代的 profileId/revisionId
|
|
86
|
+
lineage: # 见 §2.1,必填
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 2.1 `lineage`:可追溯性不能只靠 `provider`
|
|
90
|
+
|
|
91
|
+
`provider` 只说明「走的哪条通道」,**不足以复现**。`lineage` 必须能把每一项派生统计指回 Hub 的
|
|
92
|
+
真实记录:
|
|
93
|
+
|
|
94
|
+
```yaml
|
|
95
|
+
lineage:
|
|
96
|
+
evidenceRefs: [] # subreddit_evidence 的记录引用(含 evidenceType/status/capturedAt/expiresAt)
|
|
97
|
+
runIds: [] # 采集 run
|
|
98
|
+
sampleSetIds: [] # 帖子样本集合(与 baseline 卡的 SampleSetID 同命名空间)
|
|
99
|
+
derivationNotes: # 分片边界、去重键、加权方法等复现所需说明
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**原始版规 / flair / about / pinned 证据一律来自 `subreddit_evidence`**(它已带
|
|
103
|
+
`status/provider/runId/capturedAt/expiresAt`)。**不要**用 team-scoped 的 `subreddit_rule_caches`
|
|
104
|
+
生成系统级 SRP——租户作用域不同,会把某个团队的缓存冒充成板块事实。
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 3. 分母不变量(机械可校验,不是修辞)
|
|
109
|
+
|
|
110
|
+
分母是 SRP 的全部可信度所在,因此写成不变量:
|
|
111
|
+
|
|
112
|
+
1. `fetchedN ≥ dedupedN ≥ eligibleN`。
|
|
113
|
+
2. `dedupedN = eligibleN + Σ excludedByReason[*]`,其中 `Unresolved`(无法判定)是**受控的排除
|
|
114
|
+
原因之一**,不得让未知样本在等式里蒸发。
|
|
115
|
+
3. `excludedByReason` 的各 reason **互斥**:一帖多因命中时按固定优先级归一
|
|
116
|
+
`Removed > Deleted > ModPost > AutoMod > TemplateDuplicate > Unresolved`,并在 `derivationNotes`
|
|
117
|
+
记优先级版本。
|
|
118
|
+
`TemplateDuplicate` 是**语义/模板重复**过滤(同一模板反复发的帖),发生在 `dedupedN` 之后;
|
|
119
|
+
`fetchedN → dedupedN` 的是**物理去重**(同一 post id)。两者不得重复计数。
|
|
120
|
+
4. `unknownFlairN ⊆ eligibleN`(是 eligibleN 的子集,不是它之外的另一堆)。
|
|
121
|
+
5. **flair 占比的分母显式声明**:默认分母是 `eligibleN`,且 `Unknown` 作为**显式 bucket** 出现在
|
|
122
|
+
`flairDistribution[]` 里。若改用 `eligibleN - unknownFlairN` 作分母,必须在字段上标注,且
|
|
123
|
+
`Unknown` 不得同时再作为 bucket 出现(否则占比和 > 100%)。
|
|
124
|
+
6. 去重键必须写明(推荐 reddit post id;跨源合并时记合并规则)。
|
|
125
|
+
|
|
126
|
+
任一不变量不成立 → 该卡 `confidence: Insufficient`,不得发布派生占比。
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 4. 采样帧硬规则与 `claimScope`
|
|
131
|
+
|
|
132
|
+
### 4.1 硬规则:`samplingFrame: TopN` 不得填 `flairDistribution`
|
|
133
|
+
|
|
134
|
+
`samplingFrame: TopN` 的 SRP **不得填写 `flairDistribution`**,只能标 `confidence: Insufficient`
|
|
135
|
+
并进 HITL。这是 §1.2 那个症结的制度化:top-N 样本按 score 排序,其 flair 构成是「高分帖的 flair
|
|
136
|
+
构成」,**不是板块的 flair 构成**,两者不可互换。
|
|
137
|
+
|
|
138
|
+
### 4.2 `claimScope`:每个统计字段自带声称范围
|
|
139
|
+
|
|
140
|
+
禁填 `flairDistribution` 还不够——`contentTypes` / `removalStats` / `engagementPercentiles` 在
|
|
141
|
+
TopN 下同样会被误读成全板块总体结论。因此**每个统计字段必带**:
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
claimScope: Population | SampleOnly
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
| `samplingFrame` | 允许的 `claimScope` | 说明 |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| `FullWindow` | `Population` 或 `SampleOnly` | 窗口内全量,可作总体声称 |
|
|
150
|
+
| `TimeStratified` | `Population`(每片全量时)/ `SampleOnly`(片内抽样时) | 片内抽样必须给权重与估计方法,否则只能 `SampleOnly` |
|
|
151
|
+
| `TopN` | **只能 `SampleOnly`** | 且 `flairDistribution` 禁填 |
|
|
152
|
+
|
|
153
|
+
`claimScope: SampleOnly` 的字段**不得**在下游被表述为「板块里 X% 的帖……」;只能表述为
|
|
154
|
+
「本样本中 X 条…(样本口径:<采样帧>)」。
|
|
155
|
+
|
|
156
|
+
### 4.3 `TimeStratified` 的额外义务
|
|
157
|
+
|
|
158
|
+
必须说明每个时间片是**全量抓取**还是**片内抽样**:
|
|
159
|
+
|
|
160
|
+
- 每片全量 → 可 `Population`。
|
|
161
|
+
- 片内抽样 → 必须给出每片权重与估计方法(含估计量与区间口径),否则整卡降 `SampleOnly`。
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 5. 主体字段
|
|
166
|
+
|
|
167
|
+
### 5.1 `flairDistribution[]`
|
|
168
|
+
|
|
169
|
+
```yaml
|
|
170
|
+
- flair: # 原始 flair 文本;"Unknown" 为显式 bucket(见 §3 第 5 条)
|
|
171
|
+
count:
|
|
172
|
+
share: # count / 声明的分母
|
|
173
|
+
ci: # 置信区间(给出区间与方法名,如 Wilson 95%)
|
|
174
|
+
claimScope:
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 5.2 `contentTypes[]` —— 给样本,不给形容词
|
|
178
|
+
|
|
179
|
+
标杆产物的隐性方法论是:**不总结成形容词,给真实样本。**
|
|
180
|
+
|
|
181
|
+
```yaml
|
|
182
|
+
taxonomy: # 必填:所复用的既有 taxonomy 名 + spec/版本
|
|
183
|
+
# 权威源是 content_classification_runs 的分类结果
|
|
184
|
+
# (packages/contracts/src/content-classification.ts)
|
|
185
|
+
aggregationMode: # Primary | MultiLabel
|
|
186
|
+
sampledN: # 本字段实际统计的样本基数(必须与 claimScope 一致:
|
|
187
|
+
# claimScope=Population 且 FullWindow 时 sampledN = eligibleN;
|
|
188
|
+
# SampleOnly 时 sampledN 是样本基数,**不得**拿 eligibleN 参与运算)
|
|
189
|
+
classifiedN: # sampledN 中被成功分类的条数
|
|
190
|
+
unclassifiedN: # sampledN - classifiedN,必须显式给出
|
|
191
|
+
items:
|
|
192
|
+
- typeKey: # 取值来自上面声明的 taxonomy,**不新造**
|
|
193
|
+
count:
|
|
194
|
+
share: # 分母 = classifiedN(在字段上写明;与 sampledN 同一采样帧)
|
|
195
|
+
exampleTitles: [] # 5 条真实标题原文(verbatim,禁止改写/意译/清洗)
|
|
196
|
+
claimScope:
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**`aggregationMode: MultiLabel` 时 share 之和可以超过 100%**(`content_forms` 就是多标签轴),
|
|
200
|
+
必须在卡上显式声明,否则下游会把它当互斥占比读。
|
|
201
|
+
|
|
202
|
+
**`subreddit_post_annotations` 不是 content type 来源**——那张表存的是帖子对板块/品牌的 1–5 分
|
|
203
|
+
**人工评价**(`style_fit` / `brand_friendliness`),不是内容 taxonomy。若要消费它作为质量参考,
|
|
204
|
+
只允许系统全局行(`team_id IS NULL`),且必须与 `contentTypes` 分开字段呈现。
|
|
205
|
+
|
|
206
|
+
`exampleTitles` 要求 **5 条真实标题原文**,例如
|
|
207
|
+
`Just picked up a new 6mm right curb from Lirys.` 这种原样抄录。
|
|
208
|
+
**不足 5 条时诚实少给,禁止补齐**——不得用模型生成、改写、或从别的板块借来的标题凑数;
|
|
209
|
+
少给的原因写进 `dataQualityCaveats`。
|
|
210
|
+
|
|
211
|
+
### 5.3 `topPosts[]`
|
|
212
|
+
|
|
213
|
+
```yaml
|
|
214
|
+
- title:
|
|
215
|
+
permalink:
|
|
216
|
+
postedAt:
|
|
217
|
+
score:
|
|
218
|
+
sourceScoreStatus: # 原样保留来源状态,合法值仅四个:
|
|
219
|
+
# Backfilled | VerifiedLive | StaleArchive | Unverified
|
|
220
|
+
# (ArchivedSnapshot 是**评论/板块指标**的状态,不是本字段的合法值)
|
|
221
|
+
scoreUsable: # 派生布尔:sourceScoreStatus ∈ {Backfilled, VerifiedLive}
|
|
222
|
+
urlStatus: # G3 存活状态字段,见 references/evidence-policy.md
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**只有 `scoreUsable: true` 的条目可以参与按 score 的排序与汇总。**
|
|
226
|
+
`StaleArchive` / `Unverified` 的 score 禁止排序汇总(评论侧的 `ArchivedSnapshot` 指标同理;与
|
|
227
|
+
`reddit-voc-volume/scripts/reddit_voc_volume.py` 的既有告警同则:那类条目的 `num_comments` /
|
|
228
|
+
`upvote_ratio` 有回填可用,score 不可用)。这类条目**可以留在清单里**(`scoreUsable: false`),
|
|
229
|
+
但不得进入任何 score 派生统计——保留原始状态而不是丢弃,是为了让下游能自己判断而不是被动信任。
|
|
230
|
+
|
|
231
|
+
### 5.4 `engagementPercentiles`
|
|
232
|
+
|
|
233
|
+
```yaml
|
|
234
|
+
metric: # 必填:score | num_comments | upvote_ratio(逐指标一组分位数)
|
|
235
|
+
denominatorN: # 必填:参与计算的条数
|
|
236
|
+
scoreUsableOnly: # metric=score 时必须为 true(stale score 不得污染分位数)
|
|
237
|
+
percentiles: # p50 / p75 / p90 / p95 ...
|
|
238
|
+
claimScope:
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**跨板块只比 percentile,不比 raw score**——不同板块的 score 基数不可比,把 raw score 跨板块
|
|
242
|
+
对比是无意义的。
|
|
243
|
+
|
|
244
|
+
### 5.5 `titleStyle`
|
|
245
|
+
|
|
246
|
+
标题句式分布(陈述结论 / 问句 / 场景 / 数字背书 / 时长锚定 …)与标题长度分布,**带 `claimScope`
|
|
247
|
+
与分母**。与 baseline 卡的同名维度**层级不同**(这里是板块整体,那里是单 flair),互不覆盖。
|
|
248
|
+
|
|
249
|
+
### 5.6 `brandFirstMentionHistogram`
|
|
250
|
+
|
|
251
|
+
```yaml
|
|
252
|
+
buckets: # 恰好四档:标题 / 首段 / 中段 / 结论(分母 = BrandMentionSampleCount)
|
|
253
|
+
ComparableSampleCount: # 必填:可比样本总数
|
|
254
|
+
BrandMentionSampleCount: # 必填:其中出现品牌提及的样本数
|
|
255
|
+
NoBrandMentionRate: # 必填:不出现品牌的比例(= 1 - BrandMentionSampleCount / ComparableSampleCount)
|
|
256
|
+
claimScope:
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
> **「不出现」不是直方图的一档**,由 `NoBrandMentionRate` 单独表示——与 baseline 卡、
|
|
260
|
+
> G2 `BrandPlacementGate` 的口径完全一致(`reddit-phase-brief/references/brand-SKU-PGC-rules.md` §2.5)。
|
|
261
|
+
> 把「不出现」并进四档会稀释各档分母,让 G2 读出错误的位置结论。
|
|
262
|
+
|
|
263
|
+
`ComparableSampleCount` / `BrandMentionSampleCount` **是必填项**,因为 writing 侧的
|
|
264
|
+
`BrandPlacementGate`(G2)把本直方图列为 `BrandPlacementBasis` 的备选来源,其拦截判据要读这两个
|
|
265
|
+
计数(见 `reddit-content-writing/references/phase4-writing.md` W-1.b-brand)。缺这两个计数的直方图不得作为
|
|
266
|
+
`BrandPlacementBasis`。
|
|
267
|
+
|
|
268
|
+
这个机制已存在于 baseline 卡(用于校准 `BrandEntryMode`);SRP 把它**提到板块层并持久化**,
|
|
269
|
+
让 planning 阶段在还没有单 flair baseline 时也有依据。**下游取值优先级:同 flair 的 baseline 卡 >
|
|
270
|
+
SRP 板块层。**
|
|
271
|
+
|
|
272
|
+
### 5.7 `removalStats` —— 必须拆分 mod 与用户
|
|
273
|
+
|
|
274
|
+
```yaml
|
|
275
|
+
removalStats:
|
|
276
|
+
denominatorN: # 必填:分母是哪一批,且必须与 claimScope 同帧——
|
|
277
|
+
# Population(FullWindow) 通常用 dedupedN(Removed/Deleted 已被排除出
|
|
278
|
+
# eligibleN);SampleOnly 时用样本基数,不得借用全窗口分母
|
|
279
|
+
removedByMod: # [removed]:版主/自动化移除——**仅当来源明确给出 removalKind 时才可计入**
|
|
280
|
+
deletedByAuthor: # [deleted]:作者自删——同上
|
|
281
|
+
unknown: # 来源未给出 removalKind、或不可判定,一律进这里
|
|
282
|
+
claimScope:
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**合并值不得解释为「品牌导致」。** 作者自删与版主移除是完全不同的信号;把两者相加然后归因给
|
|
286
|
+
「品牌内容被打压」是标准的误读。任何据 `removalStats` 得出的归因结论,必须分别引用
|
|
287
|
+
`removedByMod` 与 `deletedByAuthor`。
|
|
288
|
+
|
|
289
|
+
### 5.8 `selfPromoPolicy`
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
selfPromoPolicy:
|
|
293
|
+
value: # Prohibited | Conditional | Allowed | Unknown
|
|
294
|
+
# **证据派生的观察值,不是 compliance verdict**——
|
|
295
|
+
# 最终的允许/禁止仍由 reddit-subreddit-compliance 裁决
|
|
296
|
+
dependsOnEvidence: [] # 必填:本字段依赖哪几类证据(通常 rules / wiki / submit_text)
|
|
297
|
+
evidenceRefs: []
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**本字段所依赖的证据 `status=failed` 时必须填 `Unknown`,不得当作「无限制」。**
|
|
301
|
+
判定只看 `dependsOnEvidence` 列出的那几类——`pinned` / `flair` / `installed_apps` 采集失败
|
|
302
|
+
**不**使 `selfPromoPolicy` 变 `Unknown`(那会把无关失败误升成阻断)。
|
|
303
|
+
这与证据层的既有语义一致:`failed` ≠「没有规则」;只有页面明确显示不存在(`not_visible`)才是
|
|
304
|
+
负证据。`Unknown` 不是放行,下游按 fail-closed 处理(见 `references/evidence-policy.md` G6)。
|
|
305
|
+
|
|
306
|
+
### 5.9 `boardUniqueFlows[]` —— 「独有」必须反向检索确认
|
|
307
|
+
|
|
308
|
+
板块特有的互动流程/仪式(如某种固定的求助格式、每周固定帖、特定 flair 的隐性用法)。
|
|
309
|
+
|
|
310
|
+
**写「独有」之前必须做反向检索确认**(在可比板块集合里检索同一流程是否存在)。未做或未确认时
|
|
311
|
+
**只能写「本样本未观察到」**,不得写「该板块独有」。
|
|
312
|
+
|
|
313
|
+
```yaml
|
|
314
|
+
- flow:
|
|
315
|
+
evidenceRefs: []
|
|
316
|
+
uniquenessCheck: # Confirmed | NotChecked
|
|
317
|
+
comparedAgainst: [] # uniquenessCheck=Confirmed 时必填:反向检索覆盖了哪些板块
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### 5.10 `flairBoundaryNotes[]`
|
|
321
|
+
|
|
322
|
+
flair 之间的边界模糊处、易混淆对、版主实际执行与字面定义的差异。
|
|
323
|
+
|
|
324
|
+
### 5.11 `lowSignalFlairs[]`
|
|
325
|
+
|
|
326
|
+
样本量过小、不足以支撑任何占比结论的 flair。**必须写明判定阈值**(如 `count < 10` 或 CI 宽度
|
|
327
|
+
超过某值)。列出来是为了**防止下游把小基数百分比当结论**;这些 flair 在 `flairDistribution` 里
|
|
328
|
+
仍然出现,但其 `claimScope` 只能是 `SampleOnly`。
|
|
329
|
+
|
|
330
|
+
### 5.12 `dataQualityCaveats[]` —— 负证据必须显式记录
|
|
331
|
+
|
|
332
|
+
**负证据不得静默丢弃。** 抓取失败的片段、被限流的时间窗、无法解析的 flair、少给的样本、
|
|
333
|
+
未做的反向检索——全部显式记录在这里。一张没有 caveats 的卡,只有在确实没有 caveat 时才合法;
|
|
334
|
+
「没写」不等于「没有」,HITL 复核会追问。
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## 6. 分字段 TTL
|
|
339
|
+
|
|
340
|
+
TTL **不是整卡一个**,因为各字段的变化速率差一个数量级。
|
|
341
|
+
|
|
342
|
+
| 字段族 | TTL |
|
|
343
|
+
|---|---|
|
|
344
|
+
| 版规**派生**结论(`selfPromoPolicy` 等) | 30 天 |
|
|
345
|
+
| `flairDistribution` / `contentTypes` | 90 天 |
|
|
346
|
+
| `topPosts` / `engagementPercentiles` | 30 天 |
|
|
347
|
+
| `removalStats` | 30 天 |
|
|
348
|
+
| 静态结构性知识(板块 identity、schema 语义、长期稳定的板块定位) | 180 天 |
|
|
349
|
+
| 动态板块行为(`titleStyle` / `boardUniqueFlows` / `flairBoundaryNotes`) | 90 天 |
|
|
350
|
+
|
|
351
|
+
> **180 天只给静态项。** 标题风格、板块特有流程、内容类型构成、互动习惯都可能在数周到数月内变化,
|
|
352
|
+
> 因此它们归「动态板块行为」的 90 天,不享受 180 天。超过 TTL 的旧数据只能作历史参考,
|
|
353
|
+
> **不得满足执行锁定**。
|
|
354
|
+
|
|
355
|
+
### 6.1 与证据层 TTL 的关系(不冲突,但要分清)
|
|
356
|
+
|
|
357
|
+
上表是 **SRP 派生字段**的 TTL,**不是原始证据的 TTL**。原始证据 TTL 由证据层自己定义
|
|
358
|
+
(`social-hub-intelligence`:rules/wiki/about/submit_text 30 天、pinned 24 小时、
|
|
359
|
+
flair/page_signals/installed_apps 7 天)。两套 TTL 并存不矛盾——一个管「结论多久要重算」,
|
|
360
|
+
一个管「原料多久要重采」。
|
|
361
|
+
|
|
362
|
+
### 6.2 `effectiveFreshUntil`:取两者的较早者
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
effectiveFreshUntil = min(该字段 TTL 到期时刻, 其所有依赖证据的 expiresAt)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
否则一个依赖 `pinned`(24 小时)或 `flair`(7 天)证据的「版规派生结论」,会在原始证据早已过期后
|
|
369
|
+
仍显示 `Verified`。**字段级计算,整卡取最小值作为卡级 `effectiveFreshUntil`。**
|
|
370
|
+
|
|
371
|
+
**并非所有依赖都有 `expiresAt`。** `subreddit_evidence` 的 `expiresAt` 可空——**为空时按
|
|
372
|
+
`evidenceType` 的既有 TTL 从 `capturedAt` 派生**(rules/wiki/about/submit_text 30 天、pinned 24 小时、
|
|
373
|
+
flair/page_signals/installed_apps 7 天),不得视为无期限,也不得因此直接判该字段不可 `Verified`。
|
|
374
|
+
帖子样本集(hot-post 快照、分类 run、样本集合)目前没有统一的过期契约。对这类依赖:在 `lineage` 里记下其
|
|
375
|
+
`capturedAt`,按本表的字段 TTL 从 `capturedAt` 起算作为替代到期时刻,并在 `derivationNotes` 注明
|
|
376
|
+
用的是替代口径——**不得因为「它没有 expiresAt」就当作永不过期**。
|
|
377
|
+
|
|
378
|
+
### 6.3 过期的后果
|
|
379
|
+
|
|
380
|
+
任一**必需字段**过期 → **整卡降 `Provisional`**:可读、可作研究参考,
|
|
381
|
+
**但不得用于锁定执行表**(Phase 4 执行表锁定要求 `Verified`)。
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## 7. `confidence` 状态机与 `approvalStatus` 的关系
|
|
386
|
+
|
|
387
|
+
| `confidence` | 条件 | 允许用途 |
|
|
388
|
+
|---|---|---|
|
|
389
|
+
| `Verified` | 分母不变量全成立 + 采样帧支持所声称的 `claimScope` + 所有必需字段在 `effectiveFreshUntil` 内 + HITL 已复核 + `approvalStatus: Approved` | 板块级结论可作**执行表锁定的必要输入**(不是充分条件,见下) |
|
|
390
|
+
| `Provisional` | 结构完整但有字段过期、或部分 `claimScope: SampleOnly`、或停止条件未满足 | 研究参考、planning 输入;**不得锁定执行表** |
|
|
391
|
+
| `Insufficient` | 分母不变量不成立、或 `TopN` 帧却需要总体结论、或关键证据 `failed` | 只能作线索;必须进 HITL 补采 |
|
|
392
|
+
|
|
393
|
+
**`Verified` 不等于可以锁执行表。** `Verified` 只说明「这张卡的板块统计站得住」。执行表锁定仍必须
|
|
394
|
+
**独立**通过既有各门:baseline 卡(`Fresh` + 10 维 + `AssignedFlair` + `FlairCoverageStatus`)、
|
|
395
|
+
Brief、compliance 裁决、`BrandPlacementGate`(G2)。SRP 是这些门的输入,**不是它们的替代品,也不能
|
|
396
|
+
免除任何一门**。
|
|
397
|
+
|
|
398
|
+
**`approvalStatus: Approved` 不能提升 `confidence`。** 一张 `Provisional` 的卡即使被审批通过,
|
|
399
|
+
仍然不得作为执行表锁定的输入——审批解决的是「这张卡可以被消费」,不是「这张卡的统计可信到可以锁
|
|
400
|
+
执行」。两个维度正交,不得互相顶替;反过来,`Verified` 机械要求 `approvalStatus: Approved`,
|
|
401
|
+
不存在 `Verified + Draft` 的组合。
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## 8. 标准作业步骤 S1–S9
|
|
406
|
+
|
|
407
|
+
**S1 · 声明窗口与目标决策。** 先写下 `windowStart` / `windowEnd` 与**这张卡要支持哪个决策**
|
|
408
|
+
(如「该板块本月排几帖、分到哪些 flair」)。目标决策决定 S5 的停止条件,不能事后补。
|
|
409
|
+
|
|
410
|
+
**S2 · 拉证据层 8 类。** about / rules / wiki / submit_text / pinned / flair / page_signals /
|
|
411
|
+
installed_apps,来源为 `subreddit_evidence`(**不要**用 team-scoped 的 `subreddit_rule_caches`)。
|
|
412
|
+
逐类记 `status`;**依赖该证据的字段**遇 `failed` 不得当作「无限制」(如 `selfPromoPolicy: Unknown`,
|
|
413
|
+
判定范围见 §5.8)。先走 Hub cache,缺口按 `reddit-voc-volume/references/hub-first.md` 的
|
|
414
|
+
L1→L2→L3 派发。
|
|
415
|
+
|
|
416
|
+
**S3 · 全窗口分片抓取。** 按时间窗切片累积、**逐片去重**,而不是一次 top-N 拉一把。
|
|
417
|
+
分片边界与去重键写进 `lineage.derivationNotes`。这一步是 SRP 与旧 SOP 0.5.5 的方法论分水岭。
|
|
418
|
+
|
|
419
|
+
**S4 · 帖子/样本资格过滤**(注意:这是**样本**是否进入统计,与 subreddit 的 eligibility 无关,
|
|
420
|
+
后者是 compliance 的裁决)。按 §3 的互斥优先级逐条判定,累计 `excludedByReason`(含 `Unresolved`),
|
|
421
|
+
校验分母不变量。
|
|
422
|
+
|
|
423
|
+
**S5 · 停止条件是决策驱动,不是统一 N。**
|
|
424
|
+
|
|
425
|
+
> 继续扩窗/扩片,直到 **关键分布的置信区间不再改变 S1 声明的那个目标决策的离散取值**为止。
|
|
426
|
+
|
|
427
|
+
最常见的形态是排期分配:如果把 flair 占比取到区间上下界,排期的整数分配(几帖分到哪个 flair)
|
|
428
|
+
都不变,那么样本已经足够——不需要更多。**目标决策不是排期分配时,S1 必须同时声明该决策的离散
|
|
429
|
+
判据**(如「是否进入该板块」的阈值、「是否需要单独 baseline」的门限),停止条件对着那个判据算;
|
|
430
|
+
S1 没声明可判定的离散判据 → 不得用 S5 停止,只能按固定预算跑并标 `Provisional`。
|
|
431
|
+
|
|
432
|
+
若扩到通道上限仍不满足 → `confidence: Provisional` + HITL,**不得用「差不多了」自行放行**。
|
|
433
|
+
|
|
434
|
+
**S6 · 派生统计。** 计算 §5.1–5.8 各统计字段,逐字段标 `claimScope` 与分母。
|
|
435
|
+
|
|
436
|
+
**S7 · 板块特有层。** `boardUniqueFlows`(含反向检索确认)、`flairBoundaryNotes`、
|
|
437
|
+
`lowSignalFlairs`、`dataQualityCaveats`。
|
|
438
|
+
|
|
439
|
+
**S8 · URL 存活状态字段。** 卡内的**证据 URL、历史样本 URL、当期排期 URL** 按
|
|
440
|
+
`references/evidence-policy.md` 的 G3 补齐存活状态字段(纯导航 URL 按 G3 豁免)。
|
|
441
|
+
排期对标帖走 G3 的 current-planning 口径;**注意 `CurrentStatus: Live` 不等于「可评论」**——
|
|
442
|
+
外部评论目标仍须过 `reddit-ext-post-audit` 的可评论性检查,G3 不替代它。
|
|
443
|
+
|
|
444
|
+
**S9 · HITL 复核后写 Hub。** 人工复核分母、采样帧与 `claimScope` 的自洽性、caveats 是否诚实,
|
|
445
|
+
通过后写 Hub 并置 `approvalStatus: Approved`。**未经 HITL 的卡最高只能是 `Provisional`。**
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## 9. 存哪里:skill 冻结契约,Hub 存实例
|
|
450
|
+
|
|
451
|
+
| 内容 | 位置 | 理由 |
|
|
452
|
+
|---|---|---|
|
|
453
|
+
| schema、采样帧规则、分母不变量、TTL、S1–S9、校验规则 | **本 skill reference**(随 CLI vendor 冻结) | 规则要跟 skill 版本一起冻结,才能保证同一版 CLI 的行为一致 |
|
|
454
|
+
| **具体板块的画像实例** | **Hub** | 改一个板块的画像**不需要发 CLI 版本**;实例有 identity/审批/lineage,天然属于服务端 |
|
|
455
|
+
|
|
456
|
+
运行时:CLI 从 Hub 拉取实例 → 校验 `schemaVersion` 与 `effectiveFreshUntil` → 不匹配或过期则按 §6.3
|
|
457
|
+
降级处理。
|
|
458
|
+
|
|
459
|
+
**Hub 侧不要塞进 `subreddit_insight_snapshots`**(`packages/db/src/schema.ts`):它虽有表级主键,
|
|
460
|
+
但**不具备 SRP 所需的 identity/revision、`schemaVersion`、TTL、lineage 与审批语义**——只是一个
|
|
461
|
+
无 schema 的通用 payload 快照,塞进去等于把 SRP 的全部治理丢掉。
|
|
462
|
+
同理不复用 `subreddit_style_profiles`(§1.1)。SRP 的落库形态由后续 Hub 侧变更定义,本文件只定义契约。
|
|
463
|
+
|
|
464
|
+
---
|
|
465
|
+
|
|
466
|
+
## 10. 校验规则(命名检查点)
|
|
467
|
+
|
|
468
|
+
下列检查点在 SRP 被消费前逐条判定;**任一 FAIL → 该卡不得用于其声称的用途**。
|
|
469
|
+
|
|
470
|
+
| 规则 | 判据 | 失败后果 |
|
|
471
|
+
|---|---|---|
|
|
472
|
+
| `SRP-C1` 分母自洽 | §3 六条不变量全成立 | `Insufficient` |
|
|
473
|
+
| `SRP-C2` 采样帧一致 | `TopN` 无 `flairDistribution`;`claimScope` 与 `samplingFrame` 匹配(§4.2) | `Insufficient` |
|
|
474
|
+
| `SRP-C3` 样本诚实 | `exampleTitles` 全部 verbatim;不足 5 条时有对应 caveat | 该 `contentTypes` 项作废 |
|
|
475
|
+
| `SRP-C3b` taxonomy 未新造 | `contentTypes.taxonomy` + `aggregationMode` + `classifiedN` 齐全,取值来自既有 taxonomy | 该字段作废 |
|
|
476
|
+
| `SRP-C4` score 可信 | 只有 `scoreUsable: true`(`sourceScoreStatus ∈ {Backfilled, VerifiedLive}`)的条目参与排序/汇总 | 该条目退出统计(可留清单) |
|
|
477
|
+
| `SRP-C5` removal 已拆分 | `removalStats` 三项分列,无合并归因 | 该字段作废 |
|
|
478
|
+
| `SRP-C6` failed≠无限制 | 证据 `failed` 对应字段为 `Unknown` | `Insufficient` |
|
|
479
|
+
| `SRP-C7` 独有已确认 | `boardUniqueFlows[].uniquenessCheck=Confirmed` 才允许「独有」措辞 | 降为「本样本未观察到」 |
|
|
480
|
+
| `SRP-C8` freshness | 每字段 `effectiveFreshUntil > now`(§6.2) | 整卡降 `Provisional` |
|
|
481
|
+
| `SRP-C8b` 治理自洽 | `Verified` ⇒ `approvalStatus: Approved`(§7) | 降 `Provisional` |
|
|
482
|
+
| `SRP-C9` lineage 完整 | `lineage.evidenceRefs` / `runIds` / `sampleSetIds` 能指回真实记录 | `Insufficient` |
|
|
483
|
+
| `SRP-C10` URL 三字段 | 卡内的**证据 URL / 历史样本 URL / 当期排期 URL** 过 G3(纯导航 URL 豁免) | 剔除该 URL |
|
|
484
|
+
|
|
485
|
+
这些是**规则名**,不是已存在的可执行 validator——runtime validator 与 gold fixtures 属于后续变更。
|
|
486
|
+
下游 skill 引用检查点时用规则名(如 `SRP-C2`),不要引用尚不存在的脚本路径。
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## 11. 输出卡模板
|
|
491
|
+
|
|
492
|
+
```markdown
|
|
493
|
+
## SubredditResearchProfile
|
|
494
|
+
- ProfileId / RevisionId / SchemaVersion:
|
|
495
|
+
- Subreddit:
|
|
496
|
+
- Window: <start> → <end>
|
|
497
|
+
- SamplingFrame: # FullWindow | TimeStratified | TopN
|
|
498
|
+
- Denominators: fetchedN= / dedupedN= / eligibleN= / unknownFlairN=
|
|
499
|
+
- ExcludedByReason:
|
|
500
|
+
- Confidence: # Verified | Provisional | Insufficient
|
|
501
|
+
- EffectiveFreshUntil:
|
|
502
|
+
- ApprovalStatus:
|
|
503
|
+
- FailedChecks: # SRP-C1..C10(含 C3b / C8b)中未通过的
|
|
504
|
+
- AllowedUses: # 是否可锁定执行表
|
|
505
|
+
- DataQualityCaveats:
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## 12. Handoff
|
|
509
|
+
|
|
510
|
+
SRP 作为 research → planning/brief 的交付物时,随 `HandoffContract` 一并给出,并在
|
|
511
|
+
`RequiredFieldsProvided` 里点名 `Confidence` 与 `AllowedUses`。
|
|
512
|
+
`Confidence: Insufficient` 的 SRP 进入下游即构成阻断:`HandoffContract` 记 `BlockingGaps`、
|
|
513
|
+
`ReadyForNextSkill: No`;走 Hub handoff 时对应 `readyForNextSkill=false` 且 `blockingIssues` 非空。
|
|
514
|
+
不得以「先用着」放行(见 `references/evidence-policy.md` G6)。
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Version Manifest
|
|
2
2
|
|
|
3
|
-
Package: `reddit-skill-sop-v2.12.
|
|
3
|
+
Package: `reddit-skill-sop-v2.12.31`
|
|
4
|
+
|
|
5
|
+
> 该包自 v2.12.30 起在本仓库 `skills/reddit-*` 直接维护;`skills/reddit-matrix.lock.json`
|
|
6
|
+
> 的 `version` 字段记的是 vendor 基线归档版本(2.12.30),与本行的内容版本各自独立,不必相等。
|
|
4
7
|
|
|
5
8
|
| Skill | Status | Source |
|
|
6
9
|
|---|---|---|
|
|
@@ -23,7 +26,7 @@ Copied independent skills should stay independently installable. Matrix wrappers
|
|
|
23
26
|
|
|
24
27
|
## Restored Legacy References
|
|
25
28
|
|
|
26
|
-
- `reddit-strategy-shared/references/prerequisites/`
|
|
29
|
+
- `reddit-strategy-shared/references/prerequisites/archive/` 存放四份 legacy startup/prerequisite 文件,仅供**人工**查阅历史背景;`AgentReadPolicy: DoNotRead`,不进 agent 上下文(见同目录 `README.md`)。
|
|
27
30
|
- `reddit-phase-planning/references/phase3-master-canvas.md` restores the 21-board Master Canvas prompt and gate.
|
|
28
31
|
- `reddit-content-writing/references/comp-mention-strategy.md` restores the competitor mention helper reference.
|
|
29
32
|
- `reddit-content-writing/references/` restores Phase 4 writing examples, post templates, PGC strategy, post rules, and execution-table reference.
|
|
@@ -42,6 +45,30 @@ Copied independent skills should stay independently installable. Matrix wrappers
|
|
|
42
45
|
fields, hard prohibitions, soft distribution targets, rolling window,
|
|
43
46
|
exception rules, `SampleSetID`, draft hash, and producer/consumer duties.
|
|
44
47
|
|
|
48
|
+
## v2.12.31 New Contracts
|
|
49
|
+
|
|
50
|
+
- `reddit-strategy-shared/references/subreddit-research-profile.md` — the
|
|
51
|
+
**SubredditResearchProfile (SRP)** contract: schema, sampling-frame hard rules
|
|
52
|
+
(`samplingFrame: TopN` may not carry `flairDistribution`), per-field `claimScope`
|
|
53
|
+
(`Population` | `SampleOnly`), the denominator invariants, per-field TTL and
|
|
54
|
+
`effectiveFreshUntil`, the `confidence` × `approvalStatus` state machine, the S1–S9
|
|
55
|
+
procedure, and the `SRP-C1..C10` check names. It lives in shared because research,
|
|
56
|
+
compliance, planning, and brief all consume it. **The skill freezes the contract; Hub
|
|
57
|
+
stores the instances** (§9). SRP never decides subreddit eligibility —
|
|
58
|
+
`reddit-subreddit-compliance` still does.
|
|
59
|
+
- `reddit-phase-planning/references/scheduling-decision-procedure.md` — the **D1–D7
|
|
60
|
+
scheduling decision procedure**: how the fixed brand quotas land on board × SKU × flair
|
|
61
|
+
× lifecycle stage. It defines `SRPMode` (`Full` / `Provisional` / `Fallback` /
|
|
62
|
+
`Insufficient`), `ProposedFlair`, `LifecycleStage`, `SearchAnchors[]`, `capacityMax` /
|
|
63
|
+
`brandEntryAllowedSet`, the D6 solver split (mechanical hard constraints vs. the
|
|
64
|
+
weighting a human must lock), the 0-post / 1-post exploration-slot criteria, and the
|
|
65
|
+
per-post `memory/phase4-排期决策台账.md` ledger. Item numbers are **not** execution
|
|
66
|
+
order — the real order is **D1 → D5 → D2 → D3 → D4 → D6 → D7**. It replaces the three
|
|
67
|
+
hardcoded heuristics (single-board share ≤ 40% / core board ≤ 8 posts / ≥ 4 boards
|
|
68
|
+
covered), which now apply as hard constraints only under `SRPMode: Fallback` and as
|
|
69
|
+
warning-level sanity checks under `SRPMode: Full` / `Provisional`; the first two are
|
|
70
|
+
per-board, the coverage count is plan-level (hard only when every board is `Fallback`).
|
|
71
|
+
|
|
45
72
|
## v2.12.30 Sample-Eligibility Contract
|
|
46
73
|
|
|
47
74
|
A baseline card may only be built from **real user posts with an intact body**.
|
|
@@ -64,7 +64,7 @@ substitute an archived `stickied` flag.
|
|
|
64
64
|
- Query:
|
|
65
65
|
- SampleSize:
|
|
66
66
|
- TopSubreddits:
|
|
67
|
-
- TopFlairs:
|
|
67
|
+
- TopFlairs: # 采样信号(本次 sample 内的 flair 频次 Top-N),claimScope: SampleOnly
|
|
68
68
|
- SubredditMetricsStatus:
|
|
69
69
|
- Items:
|
|
70
70
|
- RateLimitStatus:
|
|
@@ -74,6 +74,21 @@ substitute an archived `stickied` flag.
|
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
> **`TopFlairs` 是样本信号,不是板块占比。** 它统计的是**本次采样命中的帖子**里
|
|
78
|
+
> flair 的出现频次(top-N 排序,分母 = 本次 `SampleSize`),因此只能表述为
|
|
79
|
+
> 「样本中 X 条带该 flair」,**不得**说成「板块里 X% 的帖是该 flair」。
|
|
80
|
+
>
|
|
81
|
+
> **不得与 SRP 的 `flairDistribution` 混用、互填或互相校验。** SRP
|
|
82
|
+
> (`reddit-strategy-shared/references/subreddit-research-profile.md`)的
|
|
83
|
+
> `flairDistribution[]` 的分母是 `eligibleN`,且只有在 `samplingFrame: FullWindow`
|
|
84
|
+
> (或 `TimeStratified` 且每个时间片都是全量抓取)时才允许 `claimScope: Population`;
|
|
85
|
+
> 契约 §4.1 更明令 `samplingFrame: TopN` 的卡**根本不许有** `flairDistribution`。
|
|
86
|
+
> 无论 SRP 那张卡的 `claimScope` 是 `Population` 还是 `SampleOnly`,
|
|
87
|
+
> **都不得用 `TopFlairs` 回填、替代或「交叉验证」它**。
|
|
88
|
+
> 把 `TopFlairs` 填进 `flairDistribution`(或反过来拿它当 D2 的 flair 依据)会把一个
|
|
89
|
+
> top-N 偏差样本伪装成全量分布——这正是要靠 SRP 采样帧硬规则堵住的那个错误。
|
|
90
|
+
> `TopFlairs` 的合法用途:选题启发、判断本次采样覆盖到哪些 flair、给 SRP 的 S 步骤当**输入线索**。
|
|
91
|
+
|
|
77
92
|
## Hub-First 输出信封(v2.12.25 已自动执行,向后兼容)
|
|
78
93
|
|
|
79
94
|
所有模式输出在既有结构上追加(不修改既有字段):provenance("social_hub_cache"|"hub_dispatch"|"emergency_local")、runId、fetchedAt、freshUntil(evidence 类)、fingerprint、fallbackReason("hub_failed"|"timeout"|"hub_unreachable"|"self_crawl_forced"|"no_hub_dispatch_path"|null)、writebackStatus("not_applicable"|"done"|"pending"|"failed")。旧下游解析器无需变更;新下游应优先按 provenance 判断数据来源与可信度。
|