@v587d/capital-generation 2.7.8 → 2.7.10

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.
Files changed (35) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +6 -5
  3. package/THIRD_PARTY_NOTICES.md +12 -2
  4. package/capital-config/client.js +8 -3
  5. package/capital-config/client.src.cjs +47 -11
  6. package/capital-config/package.json +1 -1
  7. package/capital-watchlist/client.js +3 -3
  8. package/capital-watchlist/client.src.cjs +4 -4
  9. package/capital-watchlist/package.json +1 -1
  10. package/chart-ui/package.json +1 -1
  11. package/lib/agents/selected-skills-provider.d.ts +10 -0
  12. package/lib/agents/selected-skills-provider.js +179 -14
  13. package/lib/chart/source-token.js +18 -3
  14. package/lib/data-collector/dataset-tools.js +4 -2
  15. package/lib/data-collector/describe.d.ts +4 -0
  16. package/lib/data-collector/describe.js +11 -1
  17. package/lib/index.d.ts +17 -0
  18. package/lib/index.js +50 -18
  19. package/lib/web-retriever/local-fetch.d.ts +1 -1
  20. package/lib/web-retriever/local-fetch.js +1 -1
  21. package/lib/web-retriever/wind-client.d.ts +1 -1
  22. package/lib/web-retriever/wind-client.js +1 -1
  23. package/package.json +2 -1
  24. package/preset/capital-generation/agent.patch.yml +1 -0
  25. package/preset/capital-generation/skills/capital-data-protocol/SKILL.md +4 -0
  26. package/preset/capital-generation/skills/capital-equity-research/SKILL.md +1 -1
  27. package/preset/capital-generation/skills/capital-orchestration/SKILL.md +5 -0
  28. package/preset/capital-generation/skills/capital-visualization-protocol/SKILL.md +7 -7
  29. package/preset/capital-generation/skills/capital-web-protocol/SKILL.md +10 -3
  30. package/selected-skills/catalog.js +164 -54
  31. package/selected-skills/quant-agent-skills/LICENSE +21 -0
  32. package/selected-skills/quant-agent-skills/UPSTREAM.md +111 -0
  33. package/selected-skills/quant-agent-skills/skills/cross-market-listing-choice/SKILL.md +105 -0
  34. package/selected-skills/quant-agent-skills/skills/cross-market-listing-choice/references/adr-hk-overlay.md +45 -0
  35. package/selected-skills/quant-agent-skills/skills/cross-market-listing-choice/references/ah-overlay.md +44 -0
@@ -123,7 +123,14 @@ Wind 结构化查询同样是**花积分的**:先看 `data_collector` 的免
123
123
 
124
124
  ## 5. 回传格式(每条证据都要有来源)
125
125
 
126
- - 回传的证据/情报逐条编号(情报1、情报2……),编号后紧跟来源标注。
126
+ - **核查分级,不是每条都审计级**(2026-10-10 真机:逐条 URL+日期+双分类的全量核验产出 18 条情报、
127
+ 39K 输出 tokens,拖慢主结论):**核心事实**——直接影响结论或风险判断的(审计意见、商誉、
128
+ 质押/担保/资金占用、现金流与利润背离、有息负债、再融资/重组、被监管调查等)——逐条编号、
129
+ 每条一行来源,一般 ≤10 条;**外围事实**(分红方案、互动平台问答情况、媒体花絮等不改变判断的)
130
+ 合并成一句话清单,来源在清单末一次性标注即可,不逐条取原文、不逐条贴 URL+日期。
131
+ - **深挖只在触发时做**:核心事实里出现质押、商誉减值、现金流恶化、审计非标等异常线索,
132
+ 才对该单项升级为公告全文级核验;不要开局就把全部条目按审计标准核一遍。
133
+ - 回传的核心证据/情报逐条编号(情报1、情报2……),编号后紧跟来源标注。
127
134
  - 有网页链接的用 markdown 链接:方括号里列出**全部来源**(检索 provider 与具体媒体/机构名
128
135
  都写上),**链接只放一条最权威的**即可,不必逐个贴链接。示例:
129
136
  `情报1:公司今日召开临时股东会审议借款议案。[AnySearch, 新浪财经, 证券之星](https://…)`
@@ -132,8 +139,8 @@ Wind 结构化查询同样是**花积分的**:先看 `data_collector` 的免
132
139
  `wind_docs` 返回体内自带链接字段时可用那个链接;**不得编造链接**。
133
140
  - 来源标注要区分:候选来源(搜索摘要,未点开)、已获取正文(fetch 过)、wind_docs 官方文档
134
141
  (来源:Wind)。**无来源的信息不得作为证据回传**;不编造来源。
135
- - 失败项与未核验项同样编号列出并注明原因,不与已证实证据混排;同一来源服务多条情报时逐条
136
- 重复标注,不要用"同上"。
142
+ - 失败项与未核验项同样编号列出并注明原因,不与已证实证据混排;核心事实同一来源服务多条时逐条
143
+ 重复标注,不要用"同上"(外围清单可整段合标)。
137
144
  - 主 Agent 向用户呈现时保留这些来源标注;网页数字只能标"媒体转述旁证"。
138
145
  - `via: 'local-http'`(本机直连抓取)取得的正文,来源标注用「官网直抓」措辞
139
146
  (例如「AnySearch 受限,来源为本机直抓官网页面」),链接仍只放一条最权威的。
@@ -20,11 +20,17 @@ export const SELECTED_SKILL_SKILL_DIRS = Object.freeze({
20
20
  // 上游就是扁平的 skills/<name>/SKILL.md(48 颗一层到底,frontmatter name 与目录名逐颗一致,
21
21
  // 正文链接全部落在自己目录内),所以前六颗踩过的套一层 / 平铺 / 多根取一都不用做。
22
22
  financeskills: 'skills',
23
+ // 第八颗(Howard-Jerry/quant-agent-skills):上游把三颗 skill 直接放在**仓库根**,而这三颗都是
24
+ // 自述的编排器、正文指挥公开版不附带的私有数据层,一颗都不能进可选清单(判据见该快照 UPSTREAM.md)。
25
+ // 快照因此另起一个 skills/ 根,里面只放本仓自持的那一颗入口;上游三颗完整住在 git、由快照自己的
26
+ // .npmignore 挡在发布包之外,provider 的 skills 根里根本没有它们,list()/get() 也谈不上过滤。
27
+ 'quant-agent-skills': 'skills',
23
28
  })
24
29
 
25
30
  // Selected-skill metadata owned by Capital Generation. Upstream snapshots remain unchanged.
26
- // 能力标签的词表就是下面 SELECTED_SKILL_TAG_LABELS 的键:卡片按条目实际用到的标签现算筛选条,
27
- // 少一套语言的显示名就会露出英文原词(test/capital-config.test.mjs 钉着)。
31
+ // 能力标签的词表由文件末尾的 SELECTED_SKILL_TAGS 注册表现算派生(SELECTED_SKILL_TAG_LABELS):
32
+ // 卡片按条目实际用到的标签现算筛选条,少一套语言的显示名就会露出英文原词(test/capital-config.test.mjs
33
+ // 钉着);tags 同时决定条目进哪几颗任务型内置 skill 的索引,所以登记一处、两处生效。
28
34
  export const SELECTED_SKILL_CATALOG = Object.freeze([
29
35
  {
30
36
  key: 'buffettFramework',
@@ -1299,61 +1305,165 @@ export const SELECTED_SKILL_CATALOG = Object.freeze([
1299
1305
  en: 'Cold-start experiment; upstream last moved on 2026-10-01, so review the sources before use. Only the first-digit test can run on published statements; the rest of this skill\u0027s paths — bank statements, employee-versus-vendor matching, internal ERP systems — require the user to supply the accounting detail, since this plugin connects to no corporate system and holds no such source. What it returns is a list of leads, not a fraud finding, and neither an audit nor a legal opinion; a Benford test on too small a sample is void, and the sample thresholds in the text stand.',
1300
1306
  },
1301
1307
  },
1308
+ // 第八颗(Howard-Jerry/quant-agent-skills):上游三颗正文都是自述的**编排器**、且指挥公开版
1309
+ // 根本不附带的私有数据层(实测三颗 SKILL.md 点名的本地路径一个都不在仓里),一颗都不进可选清单;
1310
+ // 逐条判据与 132 处闸门命中的分布见该快照 UPSTREAM.md。这里开放的是本仓自持的一颗入口,
1311
+ // 它只挂载上游那两份零执行面、零私有引用的跨市场选线口径(逐字复制,非改写)。
1312
+ {
1313
+ key: 'crossMarketListingChoice',
1314
+ name: 'cross-market-listing-choice',
1315
+ label: { zh: '跨市场选线(A/H · ADR/HK)', en: 'Cross-Market Listing Choice' },
1316
+ description: {
1317
+ zh: '同一家公司在多个市场各有上市线时,选一条来持有、加仓或观察:A/H 溢价与币种股息税、流动性与通道、ADR 换算比例与披露文件路径。公司层面只研究一次——A 与 H 是同一家公司的两条线,变的只有价差、税、币种和你能不能买到。',
1318
+ en: 'Picks which listing of a single issuer to hold, add, or watch: A/H premium and currency/dividend withholding, liquidity and channel access, ADR conversion ratios and filing paths. The company is researched once — A and H are two lines of the same business, so what changes is spread, tax, currency and whether you can reach it.',
1319
+ },
1320
+ owner: 'Howard-Jerry',
1321
+ repository: 'quant-agent-skills',
1322
+ status: 'watchlist',
1323
+ lastCommit: '2026-08-05',
1324
+ reviewBy: '2026-11-15',
1325
+ tags: ['a-share', 'us-stock', 'portfolio', 'risk'],
1326
+ riskNote: {
1327
+ zh: '冷启动实验:上游五次提交全落在 2026-08-05 同一天,之后无维护,作者声明正文来自其私有量化系统(数据层尚未开源)。这颗只做选线,不重做公司研究——公司本身的结论交给既有研究路径。本插件没有现成的 A/H 溢价或 ADR 平价条目:溢价必须由两条线同一 as-of 交易日的收盘价加上当日汇率现算,这三项任一项取不到就不给溢价数字,只报告缺哪一项;汇率条目按次消耗上游积分,凭据缺失、限流与后端错误一律不重试,也不许用记忆里的近似汇率补数。本插件不持有使用者的成交账本,持仓与成本价只能按你在对话里当场给出的信息回答,回答完就放下,不持久化。价差是当天的事实,"折价的那条线会涨回来"不是这颗的结论,历史价差区间只是参照、不是目标。本插件不提供交易执行界面,不构成投资建议,动哪条线与动多少由使用者自己决定并自己执行。',
1328
+ en: 'Cold-start experiment: all five upstream commits landed on 2026-08-05 with nothing since, and the author states the text comes from a private quant system whose data layer is not yet open. This skill only picks a listing — it never re-runs the company research, which stays with the existing paths. This plugin has no ready-made A/H premium or ADR parity entry: the premium must be computed from both lines\u0027 closes on the same as-of trading day plus that day\u0027s FX, and if any of the three is missing you report which one instead of publishing a premium. FX entries consume upstream quota; missing credentials, throttling and backend errors are never retried, and an approximate rate from memory is not a substitute. This plugin holds no user trade ledger — position and cost basis can only be answered from what the user states in the conversation, and nothing is persisted. A spread is a same-day fact; "the cheaper line will converge" is not a conclusion of this skill, and a historical range is a reference, not a target. No trading interface is provided and nothing here is investment advice: which line to take, and how much, stays with the user.',
1329
+ },
1330
+ },
1331
+ ])
1332
+
1333
+ // ── 能力标签注册表:索引与筛选的唯一来源 ─────────────────────────────────────────
1334
+ //
1335
+ // 一条精选 skill 的 tags 同时决定两件事:① 设置卡片左侧筛选条怎么分类它;② 它进哪几颗
1336
+ // **任务型内置 skill** 的索引。所以标签不是"展示分类",而是"路由声明"——登记一次,两处生效。
1337
+ //
1338
+ // 新增一个标签 = 在 SELECTED_SKILL_TAGS 里加一行(zh / en 本来就必须填,`capital-config.test.mjs`
1339
+ // 钉着),`serves` 或 `fallback` 顺带填掉。没有第二处要改,也没有任何东西会因为"忘了挂"而静默变成孤儿:
1340
+ // 下面四条闸门(`test/selected-skill-tags.test.mjs`)会把漏挂、拼错、孤儿和上限都打红。
1341
+
1342
+ /**
1343
+ * 任务型内置 skill:正文会被补上"外部精选 skill 索引"的那几颗(住 `preset/capital-generation/skills/`)。
1344
+ * 其余五颗内置 skill 是协议 / 流程类(data / web / chart / visualization / orchestration),读者是
1345
+ * 特定角色或特定工具调用,不是"用户提了一个研究任务"的入口,因此不接索引。
1346
+ */
1347
+ export const SELECTED_SKILL_TASK_IDS = Object.freeze([
1348
+ 'capital-equity-research',
1349
+ 'capital-event-impact',
1350
+ 'capital-portfolio-review',
1302
1351
  ])
1303
1352
 
1353
+ /** 没有任何归属的标签,其条目兜底进这一颗(2026-10-13 决策:一切兜底都往 equity 里装)。 */
1354
+ export const SELECTED_SKILL_FALLBACK_TASK = 'capital-equity-research'
1355
+
1356
+ /**
1357
+ * 标签轴。`routes: false` 的轴只做**标注**,不决定条目进哪颗任务型 skill;`routes: true` 的轴参与路由。
1358
+ *
1359
+ * 市场口径轴是**不路由**的,这一点被实测纠过一次:最初把它写成"对所有任务型 skill 生效",结果
1360
+ * 你这 10 个启用项(9 颗带 `a-share`)在三颗任务型 skill 里得到**完全相同**的清单,索引等于失效;
1361
+ * 修成不路由之后,`10k-digest`(美股 10-K 深读)只进 equity / event-impact,`tax-lens` 只进
1362
+ * portfolio。判据因此是:"是 A 股"不蕴含"服务单股研究 / 事件影响 / 组合复盘"。
1363
+ *
1364
+ * 好处顺带落在自动化上:**新增一个市场口径标签零决策**——不写 serves、不重跑任何分配,
1365
+ * 只登记一行(zh/en/axis)即可。新增一个 routing 轴 = 这里加一行,该轴的标签各自带 `axis`。
1366
+ */
1367
+ export const SELECTED_SKILL_TAG_AXES = Object.freeze({
1368
+ market: Object.freeze({ routes: false }),
1369
+ capability: Object.freeze({ routes: true }),
1370
+ topic: Object.freeze({ routes: true }),
1371
+ })
1372
+
1373
+ /**
1374
+ * 能力标签注册表。键集 ≡ 标签词表(`SELECTED_SKILL_TAG_LABELS` 由它派生)。三轴判据:
1375
+ * market —— 什么市场口径(A 股 / 美股 / 将来的港股…),**不路由**,只做标注;
1376
+ * capability —— 调用什么分析方法(估值 / 财务健康 / 证据核验…);
1377
+ * topic —— 落在什么场景或对象上(组合、监控、税务…)。
1378
+ * routing 轴(capability / topic)的 `serves` 与 `fallback` 二选一:前者点名接收它的任务型 skill
1379
+ * (允许重叠),后者是"还没想好挂哪颗"的显式承认。两者都不给 = 孤儿,闸门会红——不写成"静默不出现",
1380
+ * 因为静默正是这套东西最容易坏的地方。
1381
+ */
1382
+ export const SELECTED_SKILL_TAGS = Object.freeze({
1383
+ 'a-share': { zh: 'A 股', en: 'A-share', axis: 'market', serves: [] },
1384
+ 'business-analysis': { zh: '业务分析', en: 'Business analysis', axis: 'capability', serves: ['capital-equity-research'] },
1385
+ 'capital-allocation': { zh: '资本配置', en: 'Capital allocation', axis: 'capability', serves: ['capital-equity-research'] },
1386
+ 'cash-flow': { zh: '现金流', en: 'Cash flow', axis: 'capability', serves: ['capital-equity-research', 'capital-event-impact'] },
1387
+ competition: { zh: '竞争格局', en: 'Competition', axis: 'topic', serves: ['capital-equity-research'] },
1388
+ earnings: { zh: '业绩与电话会', en: 'Earnings', axis: 'capability', serves: ['capital-equity-research', 'capital-event-impact'] },
1389
+ // `education` 是这张表里最勉强的一条:post-trade-review / journal-pattern-analyzer 确实服务组合复盘,
1390
+ // learning-coach 则哪边都不像。归到 portfolio 是先给一个明确归属,而不是让它掉进兜底。
1391
+ education: { zh: '教学', en: 'Education', axis: 'topic', serves: ['capital-portfolio-review'] },
1392
+ filings: { zh: '披露文件', en: 'Filings', axis: 'capability', serves: ['capital-equity-research', 'capital-event-impact'] },
1393
+ 'financial-health': { zh: '财务健康', en: 'Financial health', axis: 'capability', serves: ['capital-equity-research', 'capital-event-impact'] },
1394
+ instruments: { zh: '期权与基金', en: 'Options & funds', axis: 'topic', serves: ['capital-portfolio-review'] },
1395
+ macro: { zh: '宏观与行业', en: 'Macro & industry', axis: 'topic', serves: ['capital-equity-research', 'capital-event-impact'] },
1396
+ monitoring: { zh: '监控', en: 'Monitoring', axis: 'topic', serves: ['capital-event-impact', 'capital-portfolio-review'] },
1397
+ orders: { zh: '订单', en: 'Orders', axis: 'topic', serves: ['capital-equity-research'] },
1398
+ perspective: { zh: '分析视角', en: 'Perspective', axis: 'topic', serves: ['capital-equity-research', 'capital-event-impact'] },
1399
+ 'peter-lynch': { zh: '彼得·林奇', en: 'Peter Lynch', axis: 'topic', serves: ['capital-equity-research'] },
1400
+ portfolio: { zh: '组合与仓位', en: 'Portfolio', axis: 'topic', serves: ['capital-portfolio-review'] },
1401
+ risk: { zh: '风险', en: 'Risk', axis: 'topic', serves: ['capital-equity-research', 'capital-event-impact', 'capital-portfolio-review'] },
1402
+ strategy: { zh: '战略', en: 'Strategy', axis: 'topic', serves: ['capital-equity-research'] },
1403
+ tax: { zh: '税务', en: 'Tax', axis: 'topic', serves: ['capital-portfolio-review'] },
1404
+ technicals: { zh: '技术面', en: 'Technicals', axis: 'topic', serves: ['capital-event-impact', 'capital-portfolio-review'] },
1405
+ 'trade-discipline': { zh: '交易纪律', en: 'Trade discipline', axis: 'topic', serves: ['capital-portfolio-review'] },
1406
+ 'us-stock': { zh: '美股', en: 'US equity', axis: 'market', serves: [] },
1407
+ valuation: { zh: '估值', en: 'Valuation', axis: 'capability', serves: ['capital-equity-research', 'capital-event-impact'] },
1408
+ verification: { zh: '证据核验', en: 'Verification', axis: 'capability', serves: ['capital-equity-research', 'capital-event-impact', 'capital-portfolio-review'] },
1409
+ })
1410
+
1411
+ /**
1412
+ * 设置卡片最多能同时勾选的精选 skill 数。**只约束"能勾几个",不约束"已勾的生效"**:
1413
+ * 运行期 provider 不按这个数截断——老配置多于 6 个时照常全部生效并提示收敛,否则就是
1414
+ * "卡片上开着 10 个、会话里只有 6 个"那种静默砍功能(AGENTS.md §9.7)。
1415
+ */
1416
+ export const SELECTED_SKILLS_MAX_ENABLED = 6
1417
+
1418
+ /** 标签的显示名(含恒在第一格的「全部」)。键集恒等于注册表,所以新标签只登记一次。 */
1304
1419
  export const SELECTED_SKILL_TAG_LABELS = Object.freeze({
1305
- zh: {
1420
+ zh: Object.freeze({
1306
1421
  all: '全部',
1307
- 'a-share': 'A 股',
1308
- 'business-analysis': '业务分析',
1309
- 'capital-allocation': '资本配置',
1310
- 'cash-flow': '现金流',
1311
- competition: '竞争格局',
1312
- earnings: '业绩与电话会',
1313
- education: '教学',
1314
- filings: '披露文件',
1315
- 'financial-health': '财务健康',
1316
- instruments: '期权与基金',
1317
- macro: '宏观与行业',
1318
- monitoring: '监控',
1319
- orders: '订单',
1320
- perspective: '分析视角',
1321
- 'peter-lynch': '彼得·林奇',
1322
- portfolio: '组合与仓位',
1323
- risk: '风险',
1324
- strategy: '战略',
1325
- tax: '税务',
1326
- technicals: '技术面',
1327
- 'trade-discipline': '交易纪律',
1328
- 'us-stock': '美股',
1329
- valuation: '估值',
1330
- verification: '证据核验',
1331
- },
1332
- en: {
1422
+ ...Object.fromEntries(Object.entries(SELECTED_SKILL_TAGS).map(([tag, meta]) => [tag, meta.zh])),
1423
+ }),
1424
+ en: Object.freeze({
1333
1425
  all: 'All',
1334
- 'a-share': 'A-share',
1335
- 'business-analysis': 'Business analysis',
1336
- 'capital-allocation': 'Capital allocation',
1337
- 'cash-flow': 'Cash flow',
1338
- competition: 'Competition',
1339
- earnings: 'Earnings',
1340
- education: 'Education',
1341
- filings: 'Filings',
1342
- 'financial-health': 'Financial health',
1343
- instruments: 'Options & funds',
1344
- macro: 'Macro & industry',
1345
- monitoring: 'Monitoring',
1346
- orders: 'Orders',
1347
- perspective: 'Perspective',
1348
- 'peter-lynch': 'Peter Lynch',
1349
- portfolio: 'Portfolio',
1350
- risk: 'Risk',
1351
- strategy: 'Strategy',
1352
- tax: 'Tax',
1353
- technicals: 'Technicals',
1354
- 'trade-discipline': 'Trade discipline',
1355
- 'us-stock': 'US equity',
1356
- valuation: 'Valuation',
1357
- verification: 'Verification',
1358
- },
1426
+ ...Object.fromEntries(Object.entries(SELECTED_SKILL_TAGS).map(([tag, meta]) => [tag, meta.en])),
1427
+ }),
1359
1428
  })
1429
+
1430
+ /** 该标签服务的任务型 skill(不路由的轴 → 空;未登记的标签 → 空)。 */
1431
+ export function taggedTaskSkills(tag) {
1432
+ const meta = SELECTED_SKILL_TAGS[tag]
1433
+ if (meta === undefined) return []
1434
+ const axis = SELECTED_SKILL_TAG_AXES[meta.axis]
1435
+ if (axis === undefined || !axis.routes) return []
1436
+ return [...meta.serves]
1437
+ }
1438
+
1439
+ /** 该任务型 skill 收到的全部标签。派生自注册表:反向可达闸门与文档读它,不手写清单。 */
1440
+ export function taskSkillTags(taskId) {
1441
+ return Object.keys(SELECTED_SKILL_TAGS).filter((tag) => taggedTaskSkills(tag).includes(taskId))
1442
+ }
1443
+
1444
+ /** 该条目是否挂上了至少一颗任务型 skill——没挂上的按兜底规则进 `SELECTED_SKILL_FALLBACK_TASK`。 */
1445
+ function entryRoutesAnywhere(entry) {
1446
+ return entry.tags.some((tag) => taggedTaskSkills(tag).length > 0)
1447
+ }
1448
+
1449
+ /**
1450
+ * **唯一实现**:已启用(按运行时 skill name)的精选条目里,某颗任务型 skill 应当索引到哪几条。
1451
+ * 目录(provider 的 `list()`)、任务型 skill 的索引块、测试三处都调这一个函数,不许各自重算
1452
+ * (AGENTS.md §9.7:两份实现必然漂移,而漂移的表现是"某一处少了/多了一条",零报错)。
1453
+ * `enabledNames` 由调用方在**调用期**现读开关得到——开关是 settings 偏好,不许在装配期定格。
1454
+ */
1455
+ export function selectedSkillsForTask(taskId, enabledNames) {
1456
+ const enabled = new Set(enabledNames)
1457
+ return SELECTED_SKILL_CATALOG.filter((entry) => {
1458
+ if (!enabled.has(entry.name)) return false
1459
+ if (entry.tags.some((tag) => taggedTaskSkills(tag).includes(taskId))) return true
1460
+ // 兜底只在 equity 生效(2026-10-13 决策):一条都挂不上的条目,宁可多给它看一条,
1461
+ // 也不要静默不出现。`fallback: true` 的标签走的就是这条路。
1462
+ return taskId === SELECTED_SKILL_FALLBACK_TASK && !entryRoutesAnywhere(entry)
1463
+ })
1464
+ }
1465
+
1466
+ /** 只靠兜底才看得见的条目(当前应为空)。闸门钉住它:新增孤儿会当场点名,而不是静默消失。 */
1467
+ export function fallbackOnlySkillNames() {
1468
+ return SELECTED_SKILL_CATALOG.filter((entry) => !entryRoutesAnywhere(entry)).map((entry) => entry.name)
1469
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jerry Wang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,111 @@
1
+ # Upstream Record
2
+
3
+ - Project: Quant Agent Skills(三颗**自述为编排器**的量化研究 skill:`concept-research` 概念/题材、
4
+ `industry-research` 行业、`stock-research` 个股;A 股 / 港股 / 美股三市场分册 + A/H 与 ADR/HK 两条 overlay)
5
+ - Repository: https://github.com/Howard-Jerry/quant-agent-skills
6
+ - Upstream commit: `03677d216320f7f80ebf1f4d6d3106d41f72d333`(main,2026-08-05 20:27 +0800,作者 Jerry Wang)
7
+ - **全仓五次提交,全部落在 2026-08-05 同一天**(`f65c549` v1.0.0 → `03677d2` examples)。无 release、无 tag、无 CI。
8
+ - 上游 README 与 `docs/adaptation-guide.md` 自己写明:正文来自作者的**本地私有 SSoT**,经
9
+ `scripts/publish.sh` 同步发布,数据层(`collect-data`、候选队列)要到 **v1.1 才开源**;
10
+ 贡献约定还规定"不要直接改 skill 正文再提交 PR"。frontmatter 里 `stock-research` 自报
11
+ `version: 2.46.0` —— 那个版本号是私有系统的历史,不代表公开版的成熟度。
12
+ - License: MIT;`LICENSE` 为上游原件(`Copyright (c) 2026 Jerry Wang`),未改写。
13
+ **MIT 没有 Apache-2.0 第 4(b) 条那份"被改文件要带显著声明"的义务**,所以本颗不新增声明行
14
+ (与 `claude-for-financial-services-cn` 那一颗的区别正在这里,不是遗漏)。
15
+ 上游 README 另带一句免责:仅供研究与教育用途、不构成投资建议、仓库不含任何实盘持仓数据。
16
+ - Imported content: 所钉 commit 的完整文件树(三颗 skill 目录、`docs/`、`examples/`、`scripts/`、
17
+ `template/`、`README.md`、`CHANGELOG.md`、`LICENSE`),约 233 KB,**随 git 保留供复核**。
18
+ **随包发布的只有**:`LICENSE`、本文件,以及 `skills/cross-market-listing-choice/`
19
+ (一颗我们自持的入口 + 两份逐字复制的上游口径文件)。排除口径与理由写在快照自己的 `.npmignore`。
20
+
21
+ ## Local modifications(四类,逐条可复核;判据见 `docs/dev/selected-skills.md` §8.6)
22
+
23
+ 1. **新建一颗本仓自持的入口 skill** `skills/cross-market-listing-choice/SKILL.md`。
24
+ 这不是上游正文的改写,而是本仓第一次在外部快照里放一颗自己写的正文——原因是一条结构事实:
25
+ provider 只把 `<skills 根>/<name>/SKILL.md` 认作可发现单位,而上游那三颗都不能进 catalog
26
+ (判断见下节),它们携带的两份**跨市场选线口径**因此没有可挂载的运行时入口。
27
+ 入口正文全部由本仓撰写,口径来源只有那两份 overlay 文件与宿主既有纪律(委派取数、
28
+ 不用记忆回填、不承诺收益、不代下单),没有从上游编排器里搬任何一句指令。
29
+ 2. **套了一层 `skills/`。** 上游把三颗 skill 直接放在**仓库根**,provider 的 `customSkillDirs`
30
+ 与五处反查都按 `<repo>/<skillsDir>/<name>/SKILL.md` 走(peter-lynch 是同一类先例)。
31
+ `SELECTED_SKILL_SKILL_DIRS` 因此填 `'skills'`。
32
+ 3. **两份 `references/` 是逐字复制,不是移动**:`ah-overlay.md`、`adr-hk-overlay.md` 的原件仍住在
33
+ `stock-research/references/overlays/`(随 git 保留、不进发布包)。副本与上游**逐字节相同**,核对方式:
34
+ ```text
35
+ cmp skills/cross-market-listing-choice/references/ah-overlay.md \
36
+ <上游 commit>/stock-research/references/overlays/ah-overlay.md
37
+ ```
38
+ 挑这两份(而不是 `markets/a-share.md` 那族)的唯一判据是**零执行面**:实测两份 overlay 正文
39
+ 只含 ```text 围栏、零跨文件相对链接、零 `{{QUANT_ROOT}}` / `scripts/` / `*.py` / `collect-data`
40
+ 一类私有栈引用,闸门 26 条模式零命中。`markets/a-share.md` 那份虽然 0 模式命中,但里面有
41
+ `PYTHONPATH={{QUANT_ROOT}} python data_platform/research_report_collector.py …` 这样的命令块,
42
+ 指向公开版根本不附带的脚本——按第 4 条它要么整段删掉(就成了改上游正文),要么原样发出去
43
+ (就成了教 Agent 跑一条不存在的命令)。两条都不做,所以它不进包。
44
+ 4. **删除上游的 `.gitignore`**(只带 `.DS_Store` 与 `.env` 两条)。它会在本仓继续生效,
45
+ 而 git 在被排除的父目录之下无法再 include(§8.6 那条实测教训)。
46
+
47
+ **上游三颗正文一字未改**:不进 catalog 的正文不动也不扫(§8.6 开头那句),它们随 git 完整保留。
48
+
49
+ ## 收录判断:三颗编排器为什么一颗都不进 catalog
50
+
51
+ 按第 1、4、5、6 条逐条实测,不是印象:
52
+
53
+ - **第 6 条(接管会话路由)**:三颗的 `description` 自报"编排器 / orchestrator",正文是 Conductor
54
+ 按步骤加载 `steps/*.skill.md`、并行派生 5–6 个 agent 再做 Debate 裁决——与本插件的角色路由正面冲突
55
+ (`china-stock-research-orchestrator`、InvestSkill 的 `full-report`、trading-skills 的四颗是同一类)。
56
+ - **第 4 条(执行面)**:三颗都声明 `allowed-tools: Bash, Read, Write, Edit, EnterWorktree, ExitWorktree`
57
+ (后两个是 Claude Code 专属,DSH 运行时没有)。更硬的一条是**它们指挥的东西不在仓里**:
58
+ 三颗 `SKILL.md` 点名的本地路径实测 **10 / 32 / 16 个,公开版一个都不存在**(`trade_history.json`、
59
+ `portfolio_state.json`、`research_verdicts.json`、`scripts/generate_bridge.py`、
60
+ `auto_research/quality_gate_check.py`、`sleeve/concept_heat.py`、`scripts/concept_radar.py` 等)。
61
+ 把这种正文发给使用者,得到的是"教 Agent 去撞一堵墙"。
62
+ - **第 1 条(第二条取数通道)**:`stock-research/steps/02-data-collection.skill.md` 写着
63
+ "**所有 DB 和 API 数据采集必须通过 `collect-data` skill 完成,禁止绕过 collect-data 直接调 API**",
64
+ 下面整张表是 Tushare / AkShare / yfinance / FRED / 东财 ReportAPI → 本地 SQLite + FTS5。
65
+ 本插件的取数入口只有委派一个(§1.1),且原始 rows 永不出工具层。
66
+ - **第 5 条 + `AGENTS.md` §7**:`04-output-delivery` 与 `references/output-contract.md` 要求产出
67
+ **五文件包**(`README.md` / `深度研究.md` / `财务数据.md` / `研报索引.md` / `跟踪框架.md`)
68
+ 加一堆机器可读文件与 "Vault SHA 同步"。报告交付链路 2026-09-17 已整条删除、禁止以任何形式恢复。
69
+ - **闸门实测**:全仓 51 份 `.md` 命中 **132 处**,分布极不均匀——三颗 `SKILL.md` 只有 **1 处**、
70
+ `steps/*` **109 处**、`agents/*` 9 处、我们真正取用的那族纯方法论 **1 处**(就是 `us-equity.md`
71
+ 里的 AkShare 一词,而它不进包)、`detailed-workflows.md` 10 处。命中族是
72
+ 71 个 ```python 围栏、40 个 `get_*(` 伪工具调用、17 个 AkShare、1 个 `ak.stock_news_em(`、1 个慧博。
73
+ **注意"1 处"不等于干净**:`python auto_research/quality_gate_check.py <research_dir>` 这类指令
74
+ 现有 26 条模式一条都不认(第 10 条只认 `node|bash scripts/`)——这是"违规形状搬家"的又一次重演。
75
+ - **还有一个架构级不兼容,值得单独记**:它整套结论都建立在**持有者的成交账本**上
76
+ (`Ledger reality`、`BLOCKED_LEDGER_MISSING_TRADE`、`current_new_money_pct`)。本插件从不持有
77
+ 使用者的账本,只有自选股(观察清单),所以凡依赖账本的规则都落不了地。
78
+ `cross-market-listing-choice` 的正文因此明写"没有使用者的成交账本"这一条限制。
79
+
80
+ ## 已知未收、留给后续轮次的东西
81
+
82
+ 这几条按 catalog 现算的 67 颗 / 133 份 `.md` 实测是**空白**,且质地都好,但它们全部住在
83
+ 不能进 catalog 的编排器正文里,要接必须另起一轮重写:
84
+
85
+ - **预期差闸门**:`delta_class=BEAT|IN_LINE|MISS|AMBIGUOUS` + "**公告披露不是叙事加速的充分条件**,
86
+ `IN_LINE` 不得直接升级 L3 / 龙头排序 / 入场线 / 仓位 / trigger,`BEAT` 也只能触发进一步验证"
87
+ (`concept-research/SKILL.md:58`、`industry-research/SKILL.md:52` 各一种措辞)。
88
+ - **概念/题材叙事生命周期**:形成 → 加速 → 扩散 → 退潮 + 真龙/假龙(有业绩兑现 vs 纯叙事)。
89
+ 本插件**数据面已经就绪**(`index_catalog` 概念板块目录、`index_constituents`、
90
+ `eastmoney_sector_rotation`、`eastmoney_cashflow_rotation`),缺的只是方法论面。
91
+ - **check-first**:研究同一只票之前先读已有结论,并让使用者在"增量刷新 / 重做 / 只读复核"里选。
92
+ - **境内券商评级结构性偏多**("rating count is not a bullish thesis")与
93
+ **A 股新股首日无涨跌幅 5 日**那一条(`markets/a-share.md`,含锁定期阶梯与招股书回退路径)。
94
+
95
+ 顺带一条数据面线索(不是 skill 问题):它的 `report_rc` 对应 Tushare 的券商研报预测条目
96
+ (前瞻 EPS / 目标价 / **上调下调方向**)。本插件的结构化面没有这一族,唯一的一致预期是
97
+ `web_retriever` 的 `ths_eps_forecast`(机构数 / 最小 / 均值 / 最大 / 行业平均,且已带
98
+ "机构数 <3 须一并披露"的纪律)。要不要补第二个来源,走 §10 数据源验收纪律另开。
99
+
100
+ - Maintenance snapshot (checked 2026-10-13): 2 星、五次提交全在同一天、之后 70 天无提交、
101
+ 0 issue、单人仓库,作者已声明数据层要到 v1.1 才开源。因此 catalog 标 `watchlist`——
102
+ 是**维护薄**,不是那两份口径的内容缺陷。
103
+ - Packaging: `.npmignore` 用七条目录规则 + 两条文件规则挡掉三颗编排器与上游工程材料;
104
+ `package.json` 的 `files` 登记 `selected-skills/quant-agent-skills`。
105
+ `test/packaging.test.mjs` 从 catalog 反查发布清单里的 `SKILL.md` / `LICENSE` / `UPSTREAM.md`,
106
+ 并逐条反查 `.npmignore` 确实生效(目录与文件名两类都问)。
107
+ - Runtime status: `watchlist` / 默认关闭。使用者在「插件」→ Capital Generation →「精选 Skills」
108
+ 打开后,对之后的 Capital 会话可见;子 Agent 不继承。上游随 git 保留的脚本与编排器正文
109
+ **从不执行、也从不被 provider 读取**(skills 根里没有它们)。
110
+ - Review status: 2026-11-15 复查上游、许可证与维护状态。届时若上游 v1.1 真的放出数据层,
111
+ 重读上面"已知未收"那四条的可行性;不要在没有账本能力的前提下把它的 closeout 契约搬过来。
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: cross-market-listing-choice
3
+ description: 同一家公司在多个市场各有上市线(A+H 双上市、中概股的美股 ADR 与港股两条线)时,如何在**不重做公司研究**的前提下选一条来持有、加仓或观察:溢价与币种股息税、流动性与通道、披露文件路径。当且仅当问题问的是"同一家公司选哪条线"时使用;单一上市线的个股研究、比较两家公司、问公司本身好不好——都不走这颗。
4
+ ---
5
+
6
+ # 跨市场选线(同一公司多条上市线)
7
+
8
+ > 口径出处:`references/ah-overlay.md` 与 `references/adr-hk-overlay.md`,逐字取自上游
9
+ > [Howard-Jerry/quant-agent-skills](https://github.com/Howard-Jerry/quant-agent-skills)
10
+ > (MIT,commit `03677d2`)。那颗快照的三颗正文是自述的编排器、不进可选清单,随包只带这两份
11
+ > 零执行面的口径文件;为什么这么切、改了什么,见本快照根的 `UPSTREAM.md`。
12
+
13
+ ## 什么时候用,什么时候不用
14
+
15
+ 用:公司结论已经有了(或本次不打算重做),剩下的问题是**这次动哪一条线**——A 股还是 H 股、
16
+ ADR 还是港股、已持有的那条线要不要换成另一条。
17
+
18
+ 不用:只有一条上市线的公司;比较两家不同公司;问"这家公司值不值得研究"。那些是本插件
19
+ 其他研究路径的事,这颗一行都不接。**它不重做公司研究,只做选线。**
20
+
21
+ ## 一条铁律
22
+
23
+ **公司层面只研究一次。** A 与 H、ADR 与港股,是同一家公司的两条线:现金流、竞争力、资产负债表
24
+ **完全相同**,不同的只有执行、价差、税、流动性、货币和你能不能买到。
25
+
26
+ 由此得到两条禁止:
27
+
28
+ - **不得因为一条线更便宜,就上调公司层面的结论。** 折价是选线理由,不是"这家公司更值得拥有"的理由。
29
+ - **不得让包装层的便宜,盖掉公司层面缺失的证据。** 公司研究没做完,就先没有选线可言。
30
+
31
+ 这两句是这颗的核心,其余都是把它们变成可检查动作的细节。
32
+
33
+ ## 要拿的东西(一律走委派,本插件从不让分析角色自己伸手取数)
34
+
35
+ 向宿主的数据面要,一次把三项写全,缺哪一项就点名哪一项并停止依赖它的判断:
36
+
37
+ 1. **两条线在同一 as-of 交易日的收盘价**。币种分开写清楚:A 股那条是人民币,港股那条是港元,
38
+ ADR 是美元。**不许拿实时快照与历史收盘混算**——溢价是"同一天两个价格的比"。
39
+ 2. **同一天的汇率**(CNY 每 HKD,或 USD 每 HKD,按你对比的两条线取)。汇率取不到就是取不到:
40
+ 本插件的汇率条目按次消耗上游积分,凭据缺失、限流或后端报错一律不重试,也不许用记忆里的
41
+ "大概 0.92"补一个数进去。
42
+ 3. **窗口是否干净**:两条线各自最近的拆股、送转、供股、大股东减持、回购注销有没有落在
43
+ 你取的那段价格里。任一窗口被公司行动污染,就换到干净的后续窗口再比。
44
+
45
+ 股息代扣税、通道可用性(港股通 / 直接开户 / 券商能不能买)这类**规则性**事实会改,
46
+ 不向数据面要,按 `capital-web-protocol` 委派检索通道,把要核的问题、现行规则和时点写进 brief。
47
+
48
+ ## 溢价怎么算
49
+
50
+ 把算式写进答复里,让读者能复核——不要只给一个百分比。
51
+
52
+ ```text
53
+ A/H 溢价 = (A_price_cny / fx_cny_per_hkd) / h_price_hkd - 1
54
+ ADR/HK 平价 = (adr_price_usd / adr_ratio) / (hk_price_hkd * fx_hkd_per_usd) - 1
55
+ ```
56
+
57
+ - `fx_cny_per_hkd` 是**一港元合多少人民币**,方向写反等于把溢价倒过来。
58
+ - ADR 那条必须先除以 `adr_ratio`(一份 ADR 对应几股普通股),比例随公司行动变过就要重新确认。
59
+ - 两个式子用的都必须是同一个 as-of 日的收盘与同一天汇率;日期不一致就分别标注并说明差距有多大。
60
+ - 派生算术量大就交给宿主数据侧(委派 `data_junior`),少量数字在答复里把算式摊开即可。
61
+ 本插件的分析角色不自己跑脚本。
62
+
63
+ ## 输出形状
64
+
65
+ ```text
66
+ 公司结论:<沿用已完成的那次研究,不在这里重做>
67
+ 若触发行动,优先哪条线:<A / H / ADR / 不换>
68
+ 理由:<价差 / 币种与股息税 / 流动性 / 通道 / 披露路径>,各一句
69
+ ```
70
+
71
+ 三份理由各归各位,不许混成一段"综合来看"。**价差只是其中一条**:一条线折价 30% 但你的账户
72
+ 买不到,那它对这个人没有意义;港股通额度、停牌规则、涨跌停(A 侧有、港侧无)都属于通道与执行。
73
+
74
+ ## 各市场要单独看的点
75
+
76
+ - **A/H**:A 侧有涨跌停与 T+1,H 侧没有;H 侧还要看港股通通道与股息代扣。具体口径见
77
+ `references/ah-overlay.md`。
78
+ - **ADR/HK**:ADR 是**存托凭证不是股票**——要看换算比例、能不能跨市场转托管(fungibility)、
79
+ 退市与监管风险、以及**披露文件路径不同**:美国本土公司走 `10-K/10-Q/8-K`,外国私人发行人走
80
+ `20-F/6-K`。一条线的公告在另一条线的检索面里可能根本不存在,这是**市场边界,不是数据缺口**;
81
+ 别把"这条线查不到"写成"这家公司没披露"。具体见 `references/adr-hk-overlay.md`。
82
+
83
+ ## 出处块
84
+
85
+ 分析结束时按本插件的统一形状交代出处,把每一项证据的来路写全:
86
+
87
+ ```text
88
+ Data & Sources
89
+ - <事实或数字>:来源=<Dataset 引用 / 披露文件名 / 网页标题与日期>
90
+ as-of=<YYYY-MM-DD>
91
+ Retrieval: <delegated retrieval | web/tool retrieval | pasted by user>
92
+ ```
93
+
94
+ `Retrieval` 只能是这三档之一。**"我记得大概是这个汇率"不是一档取数途径。**
95
+
96
+ ## 这颗做不到什么(先说清楚,别到时候编)
97
+
98
+ - **本插件没有使用者的成交账本。** 这颗不持久化你的持仓、成本价与已实现盈亏。上文"已持有
99
+ 的那条线要不要换"只能按你在对话里当场给出的信息回答,回答完就放下;也不要假装查过账户。
100
+ - **没有现成的 A/H 溢价或 ADR 平价条目。** 溢价必须自己按两条线的收盘与当日汇率算出来,
101
+ 这三项里任何一项取不到,就不要给溢价数字,只报告缺哪一项。
102
+ - **不承诺收益,不预测价差收敛。** "A 比 H 贵 40%"是当天的事实,"所以 H 会涨"不是这颗的结论。
103
+ 历史价差区间可以作为参照,但要写明它是参照、不是目标。
104
+ - **不构成投资建议,也不代使用者下单。** 本插件不提供交易执行界面;最终动哪条线、动多少,
105
+ 由使用者自己决定并自己执行。
@@ -0,0 +1,45 @@
1
+ # ADR / HK Overlay
2
+
3
+ Use when the same company trades as a U.S. ADR and Hong Kong share, or when a
4
+ U.S.-listed ADR has a related HK primary/secondary listing.
5
+
6
+ ## Principle
7
+
8
+ Research the company once. The overlay chooses the better security wrapper for
9
+ execution and risk control.
10
+
11
+ ## Required Checks
12
+
13
+ - Alias coverage for ADR ticker, HK ticker, Chinese name, English name, and
14
+ historical names.
15
+ - Share ratio:
16
+ - ADR-to-ordinary share conversion ratio;
17
+ - price parity after FX and ratio adjustment.
18
+ - Currency:
19
+ - USD vs HKD;
20
+ - FX basis date.
21
+ - Listing and regulatory risk:
22
+ - HFCAA/delisting risk if applicable;
23
+ - primary vs secondary listing status;
24
+ - fungibility and conversion constraints.
25
+ - Liquidity and trading access:
26
+ - U.S. session vs HK session;
27
+ - spread and average daily value;
28
+ - available account/channel.
29
+ - Filing path:
30
+ - U.S. domestic forms (`10-K/10-Q/8-K`) vs foreign private issuer forms
31
+ (`20-F/6-K`);
32
+ - company IR fallback when local SEC collector does not yet cover forms.
33
+
34
+ ## Output Rule
35
+
36
+ Write:
37
+
38
+ ```text
39
+ Company verdict: <WAIT/BUY/HOLD/...>
40
+ Preferred security if action triggers: <ADR/HK/no-switch>
41
+ Wrapper reason: <parity, liquidity, filing, regulatory, FX, channel>
42
+ ```
43
+
44
+ Do not let wrapper cheapness override missing company-level evidence.
45
+
@@ -0,0 +1,44 @@
1
+ # A/H Overlay
2
+
3
+ Use when the same company has both A-share and H-share listings. This overlay
4
+ answers which security is better for execution after the company thesis is
5
+ already researched.
6
+
7
+ ## Principle
8
+
9
+ Company-level research is done once. A vs H does not change the company's cash
10
+ flows. It changes execution, valuation spread, tax, liquidity, currency, and
11
+ access.
12
+
13
+ ## Required Checks
14
+
15
+ - Alias coverage for A code, H code, Chinese name, English name, short names,
16
+ and common variants.
17
+ - A/H premium:
18
+ - compute with consistent price dates;
19
+ - convert currency: `(A_price / FX_CNY_per_HKD) / H_price - 1`;
20
+ - use a clean post-split/post-corporate-action window when old data is
21
+ polluted.
22
+ - Currency and dividend tax:
23
+ - CNY vs HKD basis;
24
+ - HK Stock Connect dividend withholding when relevant.
25
+ - Liquidity and channel:
26
+ - A-share liquidity/limit-up-down/microstructure;
27
+ - HK liquidity, southbound access, borrow/short availability if relevant.
28
+ - Portfolio reality:
29
+ - current held line;
30
+ - trade ledger currency and cost basis;
31
+ - whether switching lines is operationally possible.
32
+
33
+ ## Output Rule
34
+
35
+ Write the overlay as:
36
+
37
+ ```text
38
+ Company verdict: <WAIT/BUY/HOLD/...>
39
+ Preferred listing if action triggers: <A/H/no-switch>
40
+ Reason: <premium, currency, tax, liquidity, channel>
41
+ ```
42
+
43
+ Never upgrade a weak company-level EV just because one line is cheaper.
44
+