Skip to content

Commit a6a04de

Browse files
committed
data: exclude market-class competitors from the downstream market feed
Add 105 plugin markets / directories / stores / registries (including desktop shells with a built-in plugin market and a fork of this directory) to curated.market_exclusions so the downstream data/market.json feed no longer lists competing market surfaces — market-in-market conflict. - rebuild data/market.json via scripts/market.mjs: pool 4495 -> 4412, 14 competitor entries dropped from the published 300, MARKET.md rebuilt alongside - document the rule in data/review/README.md and scripts/market.mjs - add a regression test: market_exclusions entries never reach the feed Validated: node --test scripts/test-market.mjs (23/23), validate-market.mjs, validate-curated.mjs --from-snapshot (0 errors), regeneration idempotent.
1 parent abf2a06 commit a6a04de

6 files changed

Lines changed: 432 additions & 295 deletions

File tree

MARKET.md

Lines changed: 291 additions & 291 deletions
Large diffs are not rendered by default.

data/curated.json

Lines changed: 105 additions & 0 deletions
Large diffs are not rendered by default.

data/market.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

data/review/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ This directory is the review stage of the "raw data → human verification → u
1010
| --- | --- | --- |
1111
| `data/repositories.json` | 脚本(`scripts/update.mjs`,每日) | 原始快照:`dsh-plugin` Topic 下的全部仓库,无过滤、无审核 |
1212
| `data/approved.json` | 维护者 / AI 审核 | 核实通过的仓库清单,`"owner/name": "YYYY-MM-DD"`**用户可见页面的门控** |
13-
| `data/curated.json` | 维护者 / AI 审核 | 编辑部裁决:`excluded_repos`(剔除 + 理由)、`leaderboard_exclusions`(只进目录不进榜单)、`market_exclusions`(可进目录/榜单、不进下游市场)、`category_overrides`(分类) |
13+
| `data/curated.json` | 维护者 / AI 审核 | 编辑部裁决:`excluded_repos`(剔除 + 理由)、`leaderboard_exclusions`(只进目录不进榜单)、`market_exclusions`(可进目录/榜单、不进下游市场——包括非插件形态与 market 类竞品,避免市场套市场冲突)、`category_overrides`(分类) |
1414
| `data/review/pending.json` / `pending.md` | 脚本(`scripts/update.mjs`,每日) | 待审核队列:新增到 Topic、带简介、尚未核实的仓库(自动生成,勿手改) |
1515
| `data/market.json` | 脚本(`scripts/market.mjs`,每日 cron 与 curation 合并后) | 下游市场(dsh-desktop-safe-market)消费的精选文件:快照 + curation 的纯投影,按类目均衡发牌、≤300 条、≤500 KB。**不受 `approved.json` 门控**(只按排除名单过滤),接口约定见下游 `docs/market-json-spec.md` |
1616
| `CATALOG.md``TOP200.md` | `scripts/merge.mjs`(仅审核合并时) | 用户可见页面;**脚本不会自动更新它们** |
@@ -23,6 +23,7 @@ This directory is the review stage of the "raw data → human verification → u
2323
- **剔除** → 加入 `data/curated.json``excluded_repos`,理由写明(照抄现有条目风格)
2424
- **只进目录、不进榜单** → 同时加入 `approved.json``curated.json``leaderboard_exclusions`
2525
- **非插件形态(桌面壳/启动器、Docker 部署、手册教程、VS Code 扩展等)**:可留在目录与榜单,但加入 `curated.json``market_exclusions` 以免进入下游市场文件
26+
- **market 类竞品(插件市场 / 商店 / 目录 / registry / 插件中心等,包括内置插件市场的桌面端)**:可留在目录与榜单,但必须加入 `curated.json``market_exclusions`,避免下游市场文件出现市场套市场冲突
2627
3. **合并**:运行 `node scripts/merge.mjs`,重新生成 `CATALOG.md``TOP200.md` 与待审核队列,然后提交。
2728

2829
## AI 一句话审核 / One-line AI review

scripts/market.mjs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ export function filterPool(snapshot, curated) {
113113
Object.keys(curated.leaderboard_exclusions || {}).map((key) => key.toLowerCase()),
114114
);
115115
// Non-plugin forms (desktop shells, launchers, docs, Docker packaging, VS Code
116-
// extensions, …) stay in the catalog and leaderboard but must not reach the
117-
// downstream market — spec §4.2, editorial list in curated.json.
116+
// extensions, …) and competing plugin markets / directories / stores
117+
// (market-in-market conflict) stay in the catalog and leaderboard but must
118+
// not reach the downstream market — spec §4.2, editorial list in curated.json.
118119
const marketExcluded = new Set(
119120
Object.keys(curated.market_exclusions || {}).map((key) => key.toLowerCase()),
120121
);

scripts/test-market.mjs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,36 @@ test('filterPool applies every exclusion rule', () => {
128128
);
129129
});
130130

131+
test('filterPool drops market-class competitors listed in market_exclusions', () => {
132+
const market = repo({
133+
id: 1,
134+
full_name: 'competitor/plugin-market',
135+
name: 'plugin-market',
136+
description: 'A plugin marketplace for DSH.',
137+
});
138+
const ordinary = repo({ id: 2, full_name: 'keep/me' });
139+
const c = curated({
140+
market_exclusions: {
141+
'competitor/plugin-market':
142+
'A competing DSH plugin market — market-in-market conflict; stays in the catalog and leaderboard, excluded from the downstream market.',
143+
},
144+
});
145+
const { repos: kept } = filterPool(snapshot([market, ordinary]), c);
146+
assert.deepEqual(
147+
kept.map(({ repo: r }) => r.full_name),
148+
['keep/me'],
149+
);
150+
// The market-class entry must not reappear in the published feed either.
151+
const result = buildMarket({
152+
snapshot: snapshot([market, ordinary]),
153+
curated: c,
154+
previous: null,
155+
now: new Date('2026-08-16T01:30:00Z'),
156+
});
157+
assert.equal(result.outcome, 'written');
158+
assert.deepEqual(result.envelope.entries.map((entry) => entry.full_name), ['keep/me']);
159+
});
160+
131161
test('filterPool reports unknown category_overrides values without dropping the repo', () => {
132162
const c = curated({ category_overrides: { 'a/agent-thing': 'no-such-category' } });
133163
const { repos, warnings } = filterPool(snapshot([repo({ full_name: 'a/agent-thing', name: 'agent-thing' })]), c);

0 commit comments

Comments
 (0)