lumina-wiki 1.6.2 → 1.7.1

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 (39) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +2 -1
  3. package/README.vi.md +2 -1
  4. package/README.zh.md +2 -1
  5. package/package.json +3 -1
  6. package/src/installer/commands.js +6 -1
  7. package/src/scripts/schemas.mjs +7 -0
  8. package/src/scripts/wiki.mjs +25 -20
  9. package/src/skills/core/ask/SKILL.md +13 -2
  10. package/src/skills/core/check/SKILL.md +11 -7
  11. package/src/skills/core/check/references/lint-checks.md +21 -5
  12. package/src/skills/core/edit/SKILL.md +5 -1
  13. package/src/skills/core/ingest/SKILL.md +1 -1
  14. package/src/skills/core/ingest/references/step-01-draft.md +16 -1
  15. package/src/skills/core/ingest/references/step-04-finalize.md +1 -1
  16. package/src/skills/core/init/SKILL.md +7 -0
  17. package/src/skills/core/migrate-legacy/SKILL.md +24 -9
  18. package/src/skills/core/reset/SKILL.md +58 -25
  19. package/src/skills/core/verify/SKILL.md +1 -0
  20. package/src/skills/packs/learning/reflect/SKILL.md +1 -1
  21. package/src/skills/packs/reading/chapter-ingest/SKILL.md +2 -2
  22. package/src/skills/packs/reading/character-track/SKILL.md +2 -2
  23. package/src/skills/packs/reading/theme-map/SKILL.md +2 -2
  24. package/src/skills/packs/research/prefill/SKILL.md +6 -2
  25. package/src/skills/packs/research/rank/SKILL.md +170 -0
  26. package/src/skills/packs/research/rank/references/4c-rubric.md +62 -0
  27. package/src/skills/packs/research/rank/references/three-pass.md +40 -0
  28. package/src/skills/packs/research/survey/SKILL.md +125 -15
  29. package/src/skills/packs/research/topic/SKILL.md +20 -17
  30. package/src/skills/packs/research/watch-run/SKILL.md +18 -11
  31. package/src/skills/packs/research/watchlist/SKILL.md +11 -8
  32. package/src/templates/.env.example +8 -0
  33. package/src/templates/README.md +2 -1
  34. package/src/templates/README.vi.md +2 -1
  35. package/src/templates/README.zh.md +2 -1
  36. package/src/templates/_lumina/schema/lumi-help.csv +1 -0
  37. package/src/templates/_lumina/schema/page-templates.md +23 -0
  38. package/src/tools/fetch_altmetric.py +229 -0
  39. package/src/tools/fetch_scite.py +236 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,57 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [1.7.1] - 2026-07-02
9
+
10
+ ### Added
11
+
12
+ - `wiki.mjs init --pack learning` now creates `wiki/reflections/`, matching the
13
+ learning pack's entity schema. Valid `--pack` values are derived from the
14
+ schema instead of hardcoded, so future packs stay in sync automatically.
15
+
16
+ ### Fixed
17
+
18
+ - `/lumi-research-topic` previously failed every `add-edge` call with "Unknown
19
+ edge type" because the topic-organization edges it relies on
20
+ (`includes_source`/`included_in_topic`, `covers_concept`/`covered_by_topic`)
21
+ were missing from the schema. Added all four to `EDGE_TYPES`.
22
+ - Corrected skill-prompt and documentation drift: the reset skill's dry-run
23
+ output format, the internal lint-check reference table (was missing
24
+ L10-L12), and the documented behavior of ingest phase checkpoints (keyed
25
+ by file basename, not slug, since the checkpoint exists before slug
26
+ generation; the checkpoint JSON's `slug` field, written once the slug
27
+ phase completes, is now documented as the way other skills match a
28
+ checkpoint to its wiki entry).
29
+
30
+ ## [1.7.0] - 2026-06-16
31
+
32
+ ### Added
33
+
34
+ - **Advanced paper ranking** via the new research-pack skill
35
+ `/lumi-research-rank`. It scores an already-ingested paper and records the
36
+ results on its source page, both as a machine-readable `ranking:` frontmatter
37
+ block and a human-readable `## Ranking` scorecard. Re-running refreshes the
38
+ ranking and preserves any notes inside `<!-- user-edited -->` markers.
39
+ - **Citation influence signal**: surfaces Semantic Scholar's influential-citation
40
+ count alongside the raw citation count (reuses the existing `fetch_s2.py`; no
41
+ new key required).
42
+ - **4C qualitative rubric** (Correctness, Clarity, Contribution, Context, each
43
+ scored 1-5) produced with a three-pass reading method to keep the assessment
44
+ efficient. Scores are explicitly recorded as LLM-assessed with a timestamp.
45
+ - **Venue prestige** recorded from the agent's own knowledge and explicitly
46
+ flagged as an estimate (`venue_source: llm-estimated`) — no live API or
47
+ bundled dataset.
48
+ - **Optional, key-gated influence fetchers** `fetch_scite.py` (Scite.ai Smart
49
+ Citation tallies) and `fetch_altmetric.py` (Altmetric attention score). Both
50
+ degrade gracefully: with no key set they exit with a clear message and the
51
+ skill simply skips that signal. New `.env` keys `SCITE_API_KEY` and
52
+ `ALTMETRIC_API_KEY`.
53
+
54
+ ### Changed
55
+
56
+ - Source page schema gains an optional `ranking` frontmatter object (no change
57
+ required for existing un-ranked pages).
58
+
8
59
  ## [1.6.2] - 2026-06-15
9
60
 
10
61
  ### Fixed
package/README.md CHANGED
@@ -185,6 +185,7 @@ These are the commands you can use when chatting with your AI agent.
185
185
  | | `/lumi-research-survey` | Create a survey or summary from existing knowledge. |
186
186
  | | `/lumi-research-prefill` | Seed foundational concepts to avoid duplicates. |
187
187
  | | `/lumi-research-topic` | Create a topic page at `wiki/topics/<slug>.md` by gathering related concepts and sources already in your wiki. The AI proposes what to include and you confirm before anything is written. Use this after several `/lumi-ingest` runs when you want to give a theme its own page. |
188
+ | | `/lumi-research-rank` | Score a paper you have already ingested so you know what to read first. It looks up how influential the paper is (citation signals), estimates how respected its venue is, and rates its quality on four points — Correctness, Clarity, Contribution, and Context — then adds a clear scorecard to the paper's page. Measured numbers and the AI's own estimates are always kept separate. |
188
189
  | | `/lumi-research-setup` | Help configure API keys for research tools. |
189
190
  | | `/lumi-research-watch-run` | Run one scheduled-discovery pass over your watchlist (topics + RSS / Atom feeds). Polls only when you ask. |
190
191
  | **Reading** | `/lumi-reading-chapter-ingest` | Ingest a book chapter by chapter. |
@@ -209,7 +210,7 @@ Lumina-Wiki is evolving rapidly. Here is our user-facing roadmap:
209
210
  - [x] **Improved CI/CD:** Native support for Bun and Node 22 environments. *(shipped in v1.2)*
210
211
  - [x] **Global Source Expansion:** Direct integration with OpenAlex, CORE, and Unpaywall for reliable DOI-to-PDF resolution. *(shipped in v1.6)*
211
212
  - [x] **RSS & Blog Monitoring:** Automatically surface new papers from your favorite lab blogs and journals via `type: feed` watchlist items. *(shipped in v1.6)*
212
- - [ ] **Advanced Paper Ranking:** See influence scores and quality signals for your research papers.
213
+ - [x] **Advanced Paper Ranking:** See influence scores and quality signals for your research papers via `/lumi-research-rank`. *(shipped in v1.7)*
213
214
 
214
215
  **Long-term (Deep Research & Integration)**
215
216
  - [ ] **Image OCR & Scanned PDFs:** Ingest screenshots and scanned PDFs into your wiki.
package/README.vi.md CHANGED
@@ -185,6 +185,7 @@ Xem [Hướng dẫn Nâng cao](docs/user-guide/advanced-qmd.vi.md) để biết
185
185
  | | `/lumi-research-survey` | Tạo một bài tổng quan/khảo sát từ kiến thức hiện có. |
186
186
  | | `/lumi-research-prefill` | Tạo trước các khái niệm nền tảng để tránh trùng lặp. |
187
187
  | | `/lumi-research-topic` | Gom các khái niệm và nguồn liên quan trong wiki thành một trang chủ đề tại `wiki/topics/<slug>.md`. AI đề xuất danh sách để bạn xem và xác nhận trước khi trang được tạo. Dùng sau khi đã nạp nhiều tài liệu và muốn tổng hợp một nhóm ý tưởng thành trang riêng. |
188
+ | | `/lumi-research-rank` | Chấm điểm một bài báo bạn đã nạp để biết nên đọc gì trước. Nó tra mức độ ảnh hưởng của bài (tín hiệu trích dẫn), ước lượng uy tín nơi công bố, và đánh giá chất lượng theo bốn tiêu chí — Tính đúng đắn, Sự rõ ràng, Đóng góp, và Bối cảnh — rồi thêm một bảng điểm rõ ràng vào trang của bài báo. Các con số đo được và ước lượng của AI luôn được tách bạch. |
188
189
  | | `/lumi-research-setup` | Giúp cấu hình API key cho các công cụ nghiên cứu. |
189
190
  | | `/lumi-research-watch-run` | Chạy một lượt khám phá theo lịch dựa trên watchlist (chủ đề + nguồn RSS / Atom). Chỉ chạy khi bạn yêu cầu. |
190
191
  | **Reading** | `/lumi-reading-chapter-ingest`| Nạp kiến thức sách theo từng chương. |
@@ -209,7 +210,7 @@ Lumina-Wiki đang phát triển nhanh chóng. Dưới đây là lộ trình hư
209
210
  - [x] **Cải thiện CI/CD:** Hỗ trợ chính thức cho môi trường Bun và Node 22. *(đã phát hành trong v1.2)*
210
211
  - [x] **Mở rộng nguồn dữ liệu toàn cầu:** Tích hợp trực tiếp với OpenAlex, CORE và Unpaywall để tra cứu DOI-to-PDF đáng tin cậy. *(ra mắt trong v1.6)*
211
212
  - [x] **Theo dõi RSS & Blog:** Tự động phát hiện bài báo mới từ các blog phòng thí nghiệm và tạp chí yêu thích qua các mục `type: feed` trong watchlist. *(ra mắt trong v1.6)*
212
- - [ ] **Xếp hạng bài báo nâng cao:** Xem điểm số ảnh hưởng và tín hiệu chất lượng cho các nghiên cứu của bạn.
213
+ - [x] **Xếp hạng bài báo nâng cao:** Xem điểm số ảnh hưởng và tín hiệu chất lượng cho các nghiên cứu của bạn qua `/lumi-research-rank`. *(ra mắt ở v1.7)*
213
214
 
214
215
  **Dài hạn (Nghiên cứu sâu & Tích hợp)**
215
216
  - [ ] **OCR ảnh & PDF scan:** Nạp ảnh chụp màn hình và PDF dạng scan vào wiki.
package/README.zh.md CHANGED
@@ -186,6 +186,7 @@ npx skills add https://github.com/tobi/qmd --skill qmd
186
186
  | | `/lumi-research-survey` | 从现有知识创建综述/调研。 |
187
187
  | | `/lumi-research-prefill` | 预先生成基础概念,避免重复。 |
188
188
  | | `/lumi-research-topic` | 把 wiki 中已有的相关概念和来源汇聚成一个主题页,保存在 `wiki/topics/<slug>.md`。AI 会提议收录哪些内容,由你确认后再生成页面。多次 `/lumi-ingest` 之后,用它把一组相关想法整理成独立的主题页。 |
189
+ | | `/lumi-research-rank` | 给已经纳入的论文打分,帮你决定先读哪一篇。它会查询论文的影响力(引用信号)、估计发表场所的声望,并从四个方面评估质量——正确性、清晰度、贡献、背景——然后在论文页面上加上一份清晰的评分卡。实测数据与 AI 的估计始终分开标注。 |
189
190
  | | `/lumi-research-setup` | 帮助配置研究工具的 API key。 |
190
191
  | | `/lumi-research-watch-run` | 基于 watchlist 运行一次计划式发现(主题 + RSS / Atom 源)。仅在你要求时才运行。 |
191
192
  | **Reading** | `/lumi-reading-chapter-ingest`| 按章节导入书籍知识。 |
@@ -210,7 +211,7 @@ Lumina-Wiki 正在快速演进。这是我们的用户路线图:
210
211
  - [x] **改进的 CI/CD:** 正式支持 Bun 和 Node 22 环境。*(v1.2 已发布)*
211
212
  - [x] **全球数据源扩展:** 直接集成 OpenAlex、CORE 和 Unpaywall,实现可靠的 DOI-to-PDF 解析。*(在 v1.6 中发布)*
212
213
  - [x] **RSS 与博客监控:** 通过 watchlist 中的 `type: feed` 项,自动从您喜爱的实验室博客和期刊中发现新论文。*(在 v1.6 中发布)*
213
- - [ ] **高级论文排名:** 查看研究论文的影响力评分和质量信号。
214
+ - [x] **高级论文排名:** 通过 `/lumi-research-rank` 查看研究论文的影响力评分和质量信号。*(在 v1.7 中发布)*
214
215
 
215
216
  **长期计划(深度研究与集成)**
216
217
  - [ ] **图片 OCR 与扫描 PDF:** 将截图与扫描版 PDF 导入维基。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "lumina-wiki",
4
- "version": "1.6.2",
4
+ "version": "1.7.1",
5
5
  "description": "Domain-agnostic, multi-IDE wiki scaffolder — Karpathy's LLM-Wiki vision, cross-platform and pack-based.",
6
6
  "keywords": [
7
7
  "llm-wiki",
@@ -69,6 +69,8 @@
69
69
  "src/tools/fetch_core.py",
70
70
  "src/tools/resolve_pdf.py",
71
71
  "src/tools/fetch_rss.py",
72
+ "src/tools/fetch_scite.py",
73
+ "src/tools/fetch_altmetric.py",
72
74
  "src/tools/id_utils.py",
73
75
  "src/tools/requirements.txt",
74
76
  "CHANGELOG.md",
@@ -131,7 +131,7 @@ const RESEARCH_TOOL_FILES = [
131
131
  '_env.py', '_cache.py', 'discover.py', 'init_discovery.py', 'prepare_source.py',
132
132
  'fetch_arxiv.py', 'fetch_wikipedia.py', 'fetch_s2.py', 'fetch_deepxiv.py',
133
133
  'fetch_openalex.py', 'fetch_unpaywall.py', 'fetch_core.py', 'resolve_pdf.py',
134
- 'fetch_rss.py',
134
+ 'fetch_rss.py', 'fetch_scite.py', 'fetch_altmetric.py',
135
135
  ];
136
136
 
137
137
  async function findEnclosingWorkspace(startDir) {
@@ -1234,6 +1234,7 @@ function getSkillDefs(packs) {
1234
1234
  { name: 'prefill', canonicalId: 'lumi-research-prefill', displayName: '/lumi-research-prefill' },
1235
1235
  { name: 'setup', canonicalId: 'lumi-research-setup', displayName: '/lumi-research-setup' },
1236
1236
  { name: 'topic', canonicalId: 'lumi-research-topic', displayName: '/lumi-research-topic' },
1237
+ { name: 'rank', canonicalId: 'lumi-research-rank', displayName: '/lumi-research-rank' },
1237
1238
  { name: 'watchlist', canonicalId: 'lumi-research-watchlist', displayName: '/lumi-research-watchlist' },
1238
1239
  { name: 'watch-run', canonicalId: 'lumi-research-watch-run', displayName: '/lumi-research-watch-run' },
1239
1240
  ];
@@ -1322,6 +1323,10 @@ async function renderEnvExample(projectRoot) {
1322
1323
  `OPENALEX_API_KEY=\n\n` +
1323
1324
  `# DeepXiv token (optional; enables full-text PDF access)\n` +
1324
1325
  `DEEPXIV_TOKEN=\n\n` +
1326
+ `# Scite.ai API key (optional; enables Smart Citation tallies in /lumi-research-rank)\n` +
1327
+ `SCITE_API_KEY=\n\n` +
1328
+ `# Altmetric API key (optional; enables attention scores in /lumi-research-rank)\n` +
1329
+ `ALTMETRIC_API_KEY=\n\n` +
1325
1330
  `# arXiv does not require an API key in v0.1\n`;
1326
1331
  }
1327
1332
  await atomicWrite(destPath, content);
@@ -215,6 +215,12 @@ export const EDGE_TYPES = [
215
215
  { name: 'part_of', from: 'concepts', to: 'concepts', reverse: 'has_part', symmetric: false, pack: 'core' },
216
216
  { name: 'has_part', from: 'concepts', to: 'concepts', reverse: 'part_of', symmetric: false, pack: 'core' },
217
217
 
218
+ // --- research pack: topic organization edges -----------------------------
219
+ { name: 'includes_source', from: 'topics', to: 'sources', reverse: 'included_in_topic', symmetric: false, pack: 'research' },
220
+ { name: 'included_in_topic', from: 'sources', to: 'topics', reverse: 'includes_source', symmetric: false, pack: 'research' },
221
+ { name: 'covers_concept', from: 'topics', to: 'concepts', reverse: 'covered_by_topic', symmetric: false, pack: 'research' },
222
+ { name: 'covered_by_topic', from: 'concepts', to: 'topics', reverse: 'covers_concept', symmetric: false, pack: 'research' },
223
+
218
224
  // --- terminal edges (no reverse) — exempt-only rule applies -------------
219
225
  // Any entity -> foundations/** (research pack)
220
226
  { name: 'grounded_in', from: '*', to: 'foundations', reverse: null, terminal: true, pack: 'research' },
@@ -283,6 +289,7 @@ export const REQUIRED_FRONTMATTER = {
283
289
  { key: 'findings', type: 'array', required: false },
284
290
  { key: 'external_ids', type: 'object', required: false },
285
291
  { key: 'sources', type: 'array', required: false },
292
+ { key: 'ranking', type: 'object', required: false },
286
293
  ],
287
294
 
288
295
  // Concept page
@@ -1179,26 +1179,33 @@ const CORE_WIKI_DIRS = [
1179
1179
  'wiki/graph',
1180
1180
  ];
1181
1181
 
1182
- /** Research pack additional wiki dirs */
1183
- const RESEARCH_WIKI_DIRS = [
1184
- 'wiki/foundations',
1185
- 'wiki/topics',
1186
- ];
1182
+ /**
1183
+ * Installable (non-core) pack names, derived from ENTITY_DIRS so a new pack
1184
+ * added to schemas.mjs becomes selectable via `init --pack` without touching
1185
+ * this file.
1186
+ * @type {string[]}
1187
+ */
1188
+ const INSTALLABLE_PACKS = [...new Set(Object.values(ENTITY_DIRS).map(e => e.pack))]
1189
+ .filter(pack => pack !== 'core');
1187
1190
 
1188
- /** Reading pack additional wiki dirs */
1189
- const READING_WIKI_DIRS = [
1190
- 'wiki/chapters',
1191
- 'wiki/characters',
1192
- 'wiki/themes',
1193
- 'wiki/plot',
1194
- ];
1191
+ /**
1192
+ * Additional wiki dirs owned by a given pack, derived from ENTITY_DIRS.
1193
+ * Preserves ENTITY_DIRS declaration order.
1194
+ * @param {string} pack
1195
+ * @returns {string[]}
1196
+ */
1197
+ function wikiDirsForPack(pack) {
1198
+ return Object.values(ENTITY_DIRS)
1199
+ .filter(e => e.pack === pack)
1200
+ .map(e => `wiki/${e.dir}`.replace(/\/$/, ''));
1201
+ }
1195
1202
 
1196
1203
  /**
1197
1204
  * Initialize a workspace skeleton.
1198
1205
  * Idempotent: re-running on an existing workspace is a no-op.
1199
1206
  * @param {string} projectRoot
1200
1207
  * @param {object} [opts]
1201
- * @param {string} [opts.pack] - 'research' | 'reading' | undefined
1208
+ * @param {string} [opts.pack] - one of INSTALLABLE_PACKS | undefined
1202
1209
  * @returns {Promise<{created: string[], skipped: string[]}>}
1203
1210
  */
1204
1211
  async function initWorkspace(projectRoot, opts = {}) {
@@ -1206,10 +1213,8 @@ async function initWorkspace(projectRoot, opts = {}) {
1206
1213
  const skipped = [];
1207
1214
 
1208
1215
  let dirs = [...CORE_WIKI_DIRS];
1209
- if (opts.pack === 'research') {
1210
- dirs = [...dirs, ...RESEARCH_WIKI_DIRS];
1211
- } else if (opts.pack === 'reading') {
1212
- dirs = [...dirs, ...READING_WIKI_DIRS];
1216
+ if (opts.pack && INSTALLABLE_PACKS.includes(opts.pack)) {
1217
+ dirs = [...dirs, ...wikiDirsForPack(opts.pack)];
1213
1218
  }
1214
1219
 
1215
1220
  // Add _lumina/_state dir
@@ -1506,7 +1511,7 @@ async function main(argv) {
1506
1511
  'Usage: node wiki.mjs <subcommand> [flags]',
1507
1512
  '',
1508
1513
  'Subcommands:',
1509
- ' init [--pack research|reading] Create workspace skeleton',
1514
+ ` init [--pack ${INSTALLABLE_PACKS.join('|')}] Create workspace skeleton`,
1510
1515
  ' slug <title> Emit kebab-case slug',
1511
1516
  ' log <skill> <details...> Append to wiki/log.md',
1512
1517
  ' read-meta <slug> Read entity frontmatter as JSON',
@@ -1539,8 +1544,8 @@ async function main(argv) {
1539
1544
  // init does not require an existing workspace; it creates one
1540
1545
  const projectRoot = process.cwd();
1541
1546
  const pack = flags.pack && typeof flags.pack === 'string' ? flags.pack : undefined;
1542
- if (pack && pack !== 'research' && pack !== 'reading') {
1543
- emitError(`Invalid --pack value: ${pack}. Must be research or reading.`, 2);
1547
+ if (pack && !INSTALLABLE_PACKS.includes(pack)) {
1548
+ emitError(`Invalid --pack value: ${pack}. Must be one of: ${INSTALLABLE_PACKS.join(', ')}.`, 2);
1544
1549
  process.exit(2);
1545
1550
  }
1546
1551
  const result = await initWorkspace(projectRoot, { pack });
@@ -127,6 +127,16 @@ Do not ingest the file yourself. The user decides whether to proceed.
127
127
 
128
128
  If the user asks to save the answer:
129
129
 
130
+ First check whether the target page already exists:
131
+
132
+ ```bash
133
+ node _lumina/scripts/wiki.mjs read-meta outputs/<slug>
134
+ ```
135
+
136
+ Exit 0 means the page exists. If it does, ask the user whether to overwrite
137
+ it or pick a new slug — do not silently overwrite. Exit 2 ("Entity not
138
+ found") means the slug is free; proceed.
139
+
130
140
  Ask for confirmation before writing. Then write
131
141
  `wiki/outputs/<slug>.md` or `wiki/summary/<slug>.md` with:
132
142
  ```yaml
@@ -232,5 +242,6 @@ Before reporting done, verify:
232
242
 
233
243
  (a) Every cited page in the answer exists in `wiki/` (readable)
234
244
  (b) If a page was filed: `wiki/log.md` has a new `## [YYYY-MM-DD] ask | ...` entry
235
- (c) If a page was filed: running `/lumi-ask` again with the same question does not
236
- create a second output page (confirm with user or check for existing slug)
245
+ (c) If a page was filed: the Step 6 existence check (`read-meta outputs/<slug>`)
246
+ ran before writing, so running `/lumi-ask` again with the same question
247
+ does not silently create or overwrite a second output page
@@ -99,7 +99,9 @@ node _lumina/scripts/lint.mjs --fix --json
99
99
 
100
100
  The `--fix` pass:
101
101
  - Applies the supported auto-fixes listed in `references/lint-checks.md`
102
- - Leaves L02, L05, and L08 for manual correction
102
+ (L01, L03, L06, L07, L09)
103
+ - Leaves every other check (L02, L04, L05, L08, L10, L11, L12, L13, L14, L16)
104
+ for manual correction
103
105
 
104
106
  ### Step 4 — Self-check re-run
105
107
 
@@ -117,8 +119,10 @@ If errors remain, do not report done. Address each remaining error specifically:
117
119
  ```bash
118
120
  node _lumina/scripts/wiki.mjs set-meta <slug> <key> "<value>"
119
121
  ```
120
- - If L02, L05, or L08 remain, report the exact fields, wikilinks, or edges that
121
- need manual correction.
122
+ - If L02, L05, L08, or L10 remain, report the exact fields, wikilinks, edges,
123
+ or alias conflicts that need manual correction.
124
+ - If L13 or L16 persist, suggest `/lumi-migrate-legacy --backfill-ids` — these
125
+ are not fixed by `lint.mjs --fix`.
122
126
 
123
127
  Repeat until `summary.errors === 0`. Do not loop more than 3 times — if errors
124
128
  persist, surface them to the user as needing manual attention.
@@ -137,12 +141,12 @@ Present findings in a structured list. Group errors first, then warnings.
137
141
  Lint check: <scanned_files> files scanned
138
142
 
139
143
  Errors (N):
140
- [L06] concepts/positional-encoding.md:18 — Missing reverse edge to sources/attention-revisited
141
- [L05] summary/transformers-overview.md:42 — Broken link [[flash-decoding]] (page not found)
144
+ concepts/positional-encoding.md:18 — a return link is missing, pointing back to sources/attention-revisited (L06)
145
+ summary/transformers-overview.md:42 — a link points to a page that does not exist: [[flash-decoding]] (L05)
142
146
 
143
147
  Warnings (M, advisory):
144
- [L04] concepts/rotary-embeddings.md — Orphan page (no inbound links)
145
- [L09] wiki/index.md — Index catalog is stale
148
+ concepts/rotary-embeddings.md — this page has no inbound or outbound links yet (L04)
149
+ wiki/index.md — the page catalog is out of date (L09)
146
150
 
147
151
  Fixes available: L06, L09 (N total). Apply? [yes/no]
148
152
  ```
@@ -14,8 +14,16 @@ output in `/lumi-check`.
14
14
  | L05 | Broken wikilink | error | No — user must correct or create target |
15
15
  | L06 | Missing reverse edge | error | Yes — writes the reverse edge |
16
16
  | L07 | Duplicate symmetric edge | warning | Yes — deduplicates |
17
- | L08 | Missing required confidence field | error | No — user must add confidence |
17
+ | L08 | Missing required confidence field on an edge | error | No — user must add confidence |
18
18
  | L09 | Index out of sync | warning | Yes — rebuilds the index catalog |
19
+ | L10 | Foundation alias conflict | error | No — user must rename or merge the colliding title/alias |
20
+ | L11 | Missing `confidence` field on a source/concept page | warning | No — user must set a value |
21
+ | L12 | `raw_paths` entry missing, unsafe, or parked in `raw/tmp/` | warning | No — user must move or fix the file, then update `raw_paths` |
22
+ | L13 | `external_ids` missing a namespace derivable from `urls[]` | warning | No — run `/lumi-migrate-legacy --backfill-ids` |
23
+ | L14 | `external_ids` value fails validation for its namespace | error | No — user must correct or remove the value |
24
+ | L16 | `external_ids` value disagrees with the value derived from `urls[]` | warning | No — run `/lumi-migrate-legacy --backfill-ids` to reconcile |
25
+
26
+ (L15 is intentionally unassigned — reserved for a future collision check.)
19
27
 
20
28
  ## Classification
21
29
 
@@ -26,13 +34,19 @@ Errors that must be resolved before done:
26
34
  - L03: non-kebab slugs
27
35
  - L05: broken wikilinks
28
36
  - L06: missing reverse edges
29
- - L08: missing required confidence fields
37
+ - L08: missing required confidence field on an edge
38
+ - L10: foundation alias conflicts
39
+ - L14: invalid `external_ids` values
30
40
 
31
41
  Advisories to surface to the user:
32
42
 
33
43
  - L04: orphan pages
34
44
  - L07: duplicate symmetric edges
35
45
  - L09: index out of sync
46
+ - L11: missing `confidence` on a source/concept page
47
+ - L12: `raw_paths` missing, unsafe, or transient
48
+ - L13: `external_ids` missing a derivable namespace
49
+ - L16: `external_ids` disagrees with `urls[]`
36
50
 
37
51
  ## Fix Behavior
38
52
 
@@ -44,9 +58,11 @@ Advisories to surface to the user:
44
58
  - L07 deduplicates symmetric edges.
45
59
  - L09 regenerates the `<!-- lumina:index --> ... <!-- /lumina:index -->` block.
46
60
 
47
- L02, L05, and L08 require manual correction. If L06 remains after `--fix`, the
48
- target page may not exist; identify it and suggest `/lumi-ingest` or
49
- `/lumi-edit`.
61
+ L02, L04, L05, L08, L10, L11, L12, L13, L14, and L16 require manual
62
+ correction none of them are touched by `--fix`. If L06 remains after
63
+ `--fix`, the target page may not exist; identify it and suggest
64
+ `/lumi-ingest` or `/lumi-edit`. For L13 and L16, the fix path is
65
+ `/lumi-migrate-legacy --backfill-ids`, not `lint.mjs --fix`.
50
66
 
51
67
  The linter reads `_lumina/config/lumina.config.yaml` for exemption globs.
52
68
  `foundations/**`, `outputs/**`, and external URL targets are exempt from L06.
@@ -123,6 +123,10 @@ manual follow-up.
123
123
  node _lumina/scripts/wiki.mjs log edit "Updated <slug>: <brief description>"
124
124
  ```
125
125
 
126
+ After logging, suggest the user run `/lumi-check` in a fresh session or via a
127
+ sub-agent. Blank context catches bias from the reasoning chain that just made
128
+ this edit.
129
+
126
130
  ## Output Format
127
131
 
128
132
  Report to the user:
@@ -135,7 +139,7 @@ Example:
135
139
  Edited concepts/softmax-temperature.md:
136
140
  - Added definition paragraph in ## Overview
137
141
  - Linked back to sources/attention-revisited (used_in edge added)
138
- Lint: 0 errors, 1 warning (L04: orphan page advisory)
142
+ Links check out one advisory note: this page has no inbound links yet (L04)
139
143
  ```
140
144
 
141
145
  ## Examples
@@ -58,7 +58,7 @@ This is the only logic in this body — everything else lives in step files. The
58
58
  | `drafted` | → `./references/step-02-lint.md` |
59
59
  | `linted` | → `./references/step-03-verify.md` |
60
60
  | `verified` | → `./references/step-04-finalize.md` |
61
- | `finalized` | HALT, ask "this entry is already finalized; restart from scratch?" On `[Q]` (decline): exit cleanly, exit 0 — declining is not an error. On confirm, do these in order before re-entering step-01: (1) `set-meta sources/<slug> ingest_status drafted` (so a session crash mid-restart leaves the entry in a coherent stage, not a stale-finalized one), (2) delete the phase checkpoint at `_lumina/_state/ingest-<file-basename>.json`, (3) → `./references/step-01-draft.md`. |
61
+ | `finalized` | HALT, ask "this entry is already finalized; restart from scratch?" On `[Q]` (decline): exit cleanly, exit 0 — declining is not an error. On confirm, do these in order before re-entering step-01: (1) `set-meta sources/<slug> ingest_status drafted` (so a session crash mid-restart leaves the entry in a coherent stage, not a stale-finalized one), (2) delete the phase checkpoint at `_lumina/_state/ingest-<file-basename>.json` — at this point you may only know the slug, not the file basename, so derive it first: read `raw_paths[0]` via `read-meta sources/<slug>` and take its basename; if `raw_paths` is empty or unavailable, list `_lumina/_state/ingest-*.json` and read each one to find the checkpoint whose `slug` field equals `sources/<slug>`; if no checkpoint matches either way, there is nothing to delete — simply proceed, (3) → `./references/step-01-draft.md`. |
62
62
 
63
63
  ## Examples
64
64
 
@@ -88,7 +88,22 @@ node _lumina/scripts/wiki.mjs slug "<Title>"
88
88
 
89
89
  If `wiki/sources/<slug>.md` already exists: re-ingest — confirm with user before overwriting.
90
90
 
91
- Write checkpoint: `phase: "slug"`.
91
+ The phase checkpoint is keyed by file basename (`ingest-<file-basename>.json`)
92
+ because it is written before the slug exists. Now that the slug is known,
93
+ merge it into the checkpoint so later skills (e.g. `/lumi-migrate-legacy`) can
94
+ match a checkpoint to a wiki entry by reading its content instead of guessing
95
+ the filename:
96
+
97
+ ```bash
98
+ # 1) Read current state
99
+ node _lumina/scripts/wiki.mjs checkpoint-read ingest <file-basename>
100
+ # 2) Merge {"phase":"slug","slug":"sources/<slug>","source_basename":"<file-basename>"}
101
+ # into the JSON above (preserve all other fields).
102
+ # 3) Write back via stdin:
103
+ echo '<merged-json>' | node _lumina/scripts/wiki.mjs checkpoint-write ingest <file-basename>
104
+ ```
105
+
106
+ Write checkpoint: `phase: "slug"` (already included in the merge above).
92
107
 
93
108
  ### Phase 3 — Write source page
94
109
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  - All frontmatter writes go through `wiki.mjs set-meta`.
6
6
  - `wiki/log.md` is append-only. Use `wiki.mjs log` — never edit the file directly.
7
- - The phase-level checkpoint at `_lumina/_state/ingest-<slug>.json` ends here; mark it `phase: "done"`.
7
+ - The phase-level checkpoint at `_lumina/_state/ingest-<file-basename>.json` ends here; mark it `phase: "done"`.
8
8
 
9
9
  ## Why this step exists
10
10
 
@@ -69,6 +69,11 @@ For reading pack (if installed):
69
69
  node _lumina/scripts/wiki.mjs init --pack reading
70
70
  ```
71
71
 
72
+ For learning pack (if installed):
73
+ ```bash
74
+ node _lumina/scripts/wiki.mjs init --pack learning
75
+ ```
76
+
72
77
  Each call returns `{ ok: true, created: [...], skipped: [...] }`. Report which
73
78
  directories were newly created and which already existed.
74
79
 
@@ -168,6 +173,8 @@ node _lumina/scripts/lint.mjs --json
168
173
  node _lumina/scripts/wiki.mjs log init "Wiki initialized. Packs: core, research. Created: 8 dirs."
169
174
  ```
170
175
  Additional dirs created: `wiki/foundations/`, `wiki/topics/`, `raw/discovered/`
176
+ (research pack). The learning pack (`init --pack learning`) additionally
177
+ creates `wiki/reflections/`.
171
178
  </example>
172
179
 
173
180
  <example>
@@ -178,11 +178,22 @@ Use the following inference order. Stop at the first tier that yields a result.
178
178
 
179
179
  **Tier 1 (authoritative): read the ingest checkpoint.**
180
180
 
181
+ Ingest checkpoints are keyed by the source file's basename
182
+ (`_lumina/_state/ingest-<file-basename>.json`), not by slug — there is no
183
+ direct `<slug>` lookup. List every ingest checkpoint and match by content:
184
+
181
185
  ```bash
182
- node _lumina/scripts/wiki.mjs checkpoint-read ingest <slug>
186
+ ls _lumina/_state/ingest-*.json 2>/dev/null
183
187
  ```
184
188
 
185
- If a checkpoint exists with a `source_path` field:
189
+ Read each match with the Read tool and check its `slug` field. Newer ingests
190
+ (post-checkpoint-slug-merge) store `"slug": "sources/<slug>"` directly in the
191
+ checkpoint — match the checkpoint whose `slug` equals the entry being
192
+ migrated. Older checkpoints predate this field and won't have it; if no
193
+ checkpoint's `slug` matches (including the case where none carry the field at
194
+ all), fall through to Tier 2.
195
+
196
+ If a matching checkpoint is found and has a `source_path` field:
186
197
  - If `source_path` is under `raw/tmp/*`: do NOT write `raw_paths`. Tell the user:
187
198
  "`<slug>` was ingested from a transient location (`<source_path>`). Move the
188
199
  file to `raw/sources/` or `raw/download/<resource>/` and re-run
@@ -308,13 +319,14 @@ URL=$(node _lumina/scripts/wiki.mjs read-meta sources/<slug> | node -e "process.
308
319
 
309
320
  # Step 2 — write urls array
310
321
  node _lumina/scripts/wiki.mjs set-meta sources/<slug> urls "[\"$URL\"]" --json-value
311
-
312
- # Step 3 — remove legacy url key (set-meta with empty string removes the key)
313
- node _lumina/scripts/wiki.mjs set-meta sources/<slug> url --remove
314
322
  ```
315
323
 
316
- If `set-meta --remove` is not supported by the installed wiki.mjs version, use `Edit` to
317
- remove the `url:` line directly after confirming `urls:` was written successfully.
324
+ `set-meta` cannot remove a frontmatter key today there is no `--remove`
325
+ flag. After confirming `urls:` was written successfully, remove the legacy
326
+ `url:` line with the `Edit` tool directly. This is the one sanctioned
327
+ exception to "never hand-edit wiki frontmatter" in this skill, and it is
328
+ limited strictly to deleting the obsolete `url:` key — do not use `Edit` for
329
+ any other frontmatter change.
318
330
 
319
331
  After backfilling all entries, proceed immediately to Phase 4.
320
332
 
@@ -402,7 +414,7 @@ Report to the user:
402
414
  2. Entries updated — count and slugs grouped by field.
403
415
  3. Inferred values — the inference table from Phase 2 (so the user can review).
404
416
  4. Lint result after backfill — must show 0 errors.
405
- 5. Whether `legacyMigrationNeeded` was cleared in the manifest.
417
+ 5. Whether the upgrade cleanup is finished.
406
418
 
407
419
  ## Examples
408
420
 
@@ -464,7 +476,10 @@ Re-running this skill on a clean wiki produces zero file changes.
464
476
  - Never modify files in `raw/`. Read-only.
465
477
  - Never hand-edit `wiki/graph/edges.jsonl` or `wiki/graph/citations.jsonl`.
466
478
  - `set-meta` is the only permitted write path for frontmatter changes in this
467
- skill. Do not use Edit or Write on wiki pages directly.
479
+ skill, with one sanctioned exception: deleting the obsolete `url:` key
480
+ during the `url` → `urls` schema-shape upgrade (Phase 3), since `set-meta`
481
+ has no key-removal flag. Do not use Edit or Write on wiki pages for
482
+ anything else.
468
483
  - Do not clear `legacyMigrationNeeded` until lint confirms 0 errors.
469
484
  - If the CHANGELOG has no `### Migration` section for the detected version gap,
470
485
  rely entirely on the L01/L11 finding messages to identify which fields need