lumina-wiki 1.7.0 → 1.7.2

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 (30) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/package.json +1 -1
  3. package/src/scripts/schemas.mjs +6 -0
  4. package/src/scripts/wiki.mjs +25 -20
  5. package/src/skills/core/ask/SKILL.md +13 -2
  6. package/src/skills/core/check/SKILL.md +11 -7
  7. package/src/skills/core/check/references/lint-checks.md +21 -5
  8. package/src/skills/core/edit/SKILL.md +5 -1
  9. package/src/skills/core/ingest/SKILL.md +1 -1
  10. package/src/skills/core/ingest/references/dedup-policy.md +41 -1
  11. package/src/skills/core/ingest/references/step-01-draft.md +35 -6
  12. package/src/skills/core/ingest/references/step-03-verify.md +5 -4
  13. package/src/skills/core/ingest/references/step-04-finalize.md +1 -1
  14. package/src/skills/core/init/SKILL.md +7 -0
  15. package/src/skills/core/migrate-legacy/SKILL.md +24 -9
  16. package/src/skills/core/reset/SKILL.md +58 -25
  17. package/src/skills/core/verify/SKILL.md +1 -0
  18. package/src/skills/packs/learning/reflect/SKILL.md +1 -1
  19. package/src/skills/packs/reading/chapter-ingest/SKILL.md +2 -2
  20. package/src/skills/packs/reading/character-track/SKILL.md +2 -2
  21. package/src/skills/packs/reading/theme-map/SKILL.md +2 -2
  22. package/src/skills/packs/research/prefill/SKILL.md +6 -2
  23. package/src/skills/packs/research/rank/SKILL.md +1 -1
  24. package/src/skills/packs/research/survey/SKILL.md +125 -15
  25. package/src/skills/packs/research/topic/SKILL.md +20 -17
  26. package/src/skills/packs/research/watch-run/SKILL.md +18 -11
  27. package/src/skills/packs/research/watchlist/SKILL.md +11 -8
  28. package/src/templates/README.md +1 -0
  29. package/src/templates/README.vi.md +1 -0
  30. package/src/templates/README.zh.md +1 -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.2] - 2026-07-05
9
+
10
+ ### Fixed
11
+
12
+ - `/lumi-ingest` step-03-verify referenced `src/skills/core/verify/` — the
13
+ repo source tree — instead of the installed workspace path. On any
14
+ non-Claude-Code IDE target (Codex, Gemini, Cursor, generic), the file
15
+ never existed post-install, so grounding verification silently had
16
+ nothing to follow. Fixed all three references to
17
+ `.agents/skills/lumi-verify/`, which the installer copies unconditionally
18
+ for every IDE target.
19
+ - Added an `ingest_status` handler for the `not_applicable` verify verdict,
20
+ which was previously unhandled during ingest.
21
+
22
+ ### Added
23
+
24
+ - `/lumi-ingest` now checks external identifiers (DOI/arxiv/S2) for an
25
+ existing source page before generating a slug, so the same paper
26
+ ingested under a different title no longer creates a duplicate page.
27
+ - Concept stub creation now scans existing concepts for acronym/expansion
28
+ and singular/plural variants before creating a new one.
29
+ - Key Claims in drafted source pages now require a source locator
30
+ (section/page/heading), so the grounding reviewer in step-03 no longer
31
+ has to re-scan the whole raw file to check a claim.
32
+ - A concept-count rubric (roughly 3-7 per source) to keep the graph from
33
+ being diluted by over-extracted keyword stubs.
34
+ - PDF preprocessing now runs before type detection in step-01, so runtimes
35
+ without native PDF reading don't fail attempting to read the raw binary.
36
+
37
+ ## [1.7.1] - 2026-07-02
38
+
39
+ ### Added
40
+
41
+ - `wiki.mjs init --pack learning` now creates `wiki/reflections/`, matching the
42
+ learning pack's entity schema. Valid `--pack` values are derived from the
43
+ schema instead of hardcoded, so future packs stay in sync automatically.
44
+
45
+ ### Fixed
46
+
47
+ - `/lumi-research-topic` previously failed every `add-edge` call with "Unknown
48
+ edge type" because the topic-organization edges it relies on
49
+ (`includes_source`/`included_in_topic`, `covers_concept`/`covered_by_topic`)
50
+ were missing from the schema. Added all four to `EDGE_TYPES`.
51
+ - Corrected skill-prompt and documentation drift: the reset skill's dry-run
52
+ output format, the internal lint-check reference table (was missing
53
+ L10-L12), and the documented behavior of ingest phase checkpoints (keyed
54
+ by file basename, not slug, since the checkpoint exists before slug
55
+ generation; the checkpoint JSON's `slug` field, written once the slug
56
+ phase completes, is now documented as the way other skills match a
57
+ checkpoint to its wiki entry).
58
+
8
59
  ## [1.7.0] - 2026-06-16
9
60
 
10
61
  ### Added
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.7.0",
4
+ "version": "1.7.2",
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",
@@ -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' },
@@ -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
 
@@ -3,6 +3,31 @@
3
3
  Use this reference before creating or updating source, concept, person, and graph
4
4
  records during `/lumi-ingest`.
5
5
 
6
+ ## Identifier Dedup (Before Slug Generation)
7
+
8
+ Slug comparison alone misses duplicates: the same paper ingested under two title
9
+ variants (with/without subtitle, arxiv version suffix, translated title) produces
10
+ two different slugs. External identifiers are the stronger key, so check them
11
+ first whenever one is known (from `resolve_pdf.py` output, or parsed from the
12
+ input URL).
13
+
14
+ ```bash
15
+ # One grep per known identifier, over source-page frontmatter.
16
+ # Use the normalized value: bare DOI (10.x/y), bare arxiv id (2604.03501 — no version suffix).
17
+ grep -rln "10.48550/arxiv.2604.03501" wiki/sources/
18
+ grep -rln "2604.03501" wiki/sources/
19
+ ```
20
+
21
+ - **Hit** — an existing page carries the same identifier. This run is a re-ingest
22
+ of that page's slug, regardless of what slug the current title would generate.
23
+ Confirm with the user, then follow the re-ingest path below; do not create a
24
+ second page.
25
+ - **No hit** — proceed to slug generation.
26
+
27
+ A plain substring grep is deliberate: identifiers are unique enough that false
28
+ positives are rare, and a rare false positive only costs one confirmation
29
+ question. A false negative (skipping the check) costs a duplicate source page.
30
+
6
31
  ## Source Pages
7
32
 
8
33
  Generate the source slug with:
@@ -47,7 +72,22 @@ making any `add-edge concepts/<slug>` calls.
47
72
 
48
73
  ## Concept And Person Stubs
49
74
 
50
- Before creating a concept or person page, check metadata:
75
+ Exact-slug lookup only catches exact matches `rlhf` and
76
+ `reinforcement-learning-from-human-feedback` would become two pages. Once per
77
+ ingest run, list the existing concepts and hold the list in mind while creating
78
+ stubs:
79
+
80
+ ```bash
81
+ node _lumina/scripts/wiki.mjs list-entities --type concept
82
+ ```
83
+
84
+ For each candidate concept, scan that list for variants of the same term:
85
+ acronym vs expansion, singular vs plural, hyphenation or word-order differences.
86
+ If a variant exists, link to the existing slug instead of creating a new stub —
87
+ and if unsure whether two terms are the same concept, ask the user rather than
88
+ guessing.
89
+
90
+ Then, before creating a concept or person page, check metadata:
51
91
 
52
92
  ```bash
53
93
  node _lumina/scripts/wiki.mjs read-meta concepts/<slug>
@@ -6,7 +6,7 @@
6
6
  - Never modify files in `raw/`. Read-only.
7
7
  - Never hand-edit `wiki/graph/edges.jsonl` or `wiki/graph/citations.jsonl`; use `wiki.mjs add-edge` and `wiki.mjs add-citation`.
8
8
  - Never overwrite an existing wiki page without user confirmation.
9
- - All frontmatter writes go through `wiki.mjs set-meta`. Never write to `wiki/*.md` directly. (Body text goes through Write tool atomically; finalizing frontmatter still uses `set-meta`.)
9
+ - Frontmatter discipline, two cases: (a) **initial creation** of a page that does not exist yet — Write the whole file (frontmatter + body) in one shot from the template; (b) **any change to an existing page's frontmatter** — always `wiki.mjs set-meta`, never Write/Edit on the frontmatter block. Body text of an existing page may be edited with Write/Edit; the frontmatter block may not.
10
10
  - `raw/tmp/` accepts additions only; never overwrite a file there.
11
11
  - `raw_paths` must list permanent artifacts only. Reject `raw/tmp/*` entries.
12
12
  - Keep a phase-level checkpoint after every phase — an interrupted run must resume cleanly.
@@ -69,9 +69,13 @@ node _lumina/scripts/wiki.mjs checkpoint-read research-discover shortlist
69
69
 
70
70
  Match title to a shortlist entry, extract URL, fall through to Mode B.
71
71
 
72
+ Fallback: if the checkpoint does not exist (research pack not installed, or no discover run yet) or no shortlist entry matches the title, do not guess. Ask the user for a URL or identifier (arxiv ID / DOI), then fall through to Mode B with their answer.
73
+
72
74
  ### Phase 1 — Detect type
73
75
 
74
- Read first ~200 lines of the source. Classify:
76
+ If the source is a PDF or too large to read comfortably in one pass, follow `pdf-preprocessing.md` **before reading anything** — on runtimes without native PDF reading, a direct Read of the binary fails here, not in Phase 3.
77
+
78
+ Read first ~200 lines of the source (or of the extracted text). Classify:
75
79
  - "Abstract", "Introduction", "References" → `paper`
76
80
  - Chapter structure → `book`
77
81
  - Web byline + publication → `article`
@@ -82,17 +86,34 @@ Write checkpoint: `phase: "detect"`.
82
86
 
83
87
  ### Phase 2 — Generate slug
84
88
 
89
+ **Identifier dedup comes first.** If any external identifier is known at this point (DOI / arxiv ID / S2 ID — from Mode B resolution or parsed from the input URL), check for an existing source page carrying the same identifier BEFORE generating a slug — title variants produce different slugs, so slug comparison alone misses duplicates. See `dedup-policy.md` § Identifier Dedup. On a hit, this run is a re-ingest of the matched slug: confirm with the user and skip new-page creation.
90
+
85
91
  ```bash
86
92
  node _lumina/scripts/wiki.mjs slug "<Title>"
87
93
  ```
88
94
 
89
95
  If `wiki/sources/<slug>.md` already exists: re-ingest — confirm with user before overwriting.
90
96
 
91
- Write checkpoint: `phase: "slug"`.
97
+ The phase checkpoint is keyed by file basename (`ingest-<file-basename>.json`)
98
+ because it is written before the slug exists. Now that the slug is known,
99
+ merge it into the checkpoint so later skills (e.g. `/lumi-migrate-legacy`) can
100
+ match a checkpoint to a wiki entry by reading its content instead of guessing
101
+ the filename:
102
+
103
+ ```bash
104
+ # 1) Read current state
105
+ node _lumina/scripts/wiki.mjs checkpoint-read ingest <file-basename>
106
+ # 2) Merge {"phase":"slug","slug":"sources/<slug>","source_basename":"<file-basename>"}
107
+ # into the JSON above (preserve all other fields).
108
+ # 3) Write back via stdin:
109
+ echo '<merged-json>' | node _lumina/scripts/wiki.mjs checkpoint-write ingest <file-basename>
110
+ ```
111
+
112
+ Write checkpoint: `phase: "slug"` (already included in the merge above).
92
113
 
93
114
  ### Phase 3 — Write source page
94
115
 
95
- For PDFs / large sources, follow `pdf-preprocessing.md` first.
116
+ For PDFs / large sources, the extraction from Phase 1 (`pdf-preprocessing.md`) applies here too — draft from the extracted text, section by section for long sources.
96
117
 
97
118
  Draft `wiki/sources/<slug>.md` from `_lumina/schema/page-templates.md` Source template. Required frontmatter: `id`, `title`, `type`, `created`, `updated`, `authors`, `year`, `importance`, `provenance`. Optional but encouraged: `urls`, `raw_paths`, `confidence`, `external_ids`.
98
119
 
@@ -116,6 +137,10 @@ node _lumina/scripts/wiki.mjs set-meta sources/<slug> sources "[$entry]" --json-
116
137
 
117
138
  Required body sections: `## Summary` (2–4 sentences), `## Key Claims` (bulleted, with confidence), `## Concepts` (`[[concept-slug]]` links), `## People` (`[[person-slug]]` links), `## Open Questions`.
118
139
 
140
+ `## Key Claims` — each claim ends with a locator pointing at where the source supports it: a section anchor, page, or heading, e.g. `(§3.2)`, `(p. 5)`, `(Table 1)`. The grounding check in step-03 reads these locators to find evidence; a claim without one forces the reviewer to re-read the whole raw file and weakens the check. If a claim synthesizes multiple places, list the primary locator.
141
+
142
+ `## Concepts` — be selective, not exhaustive. A term earns a concept link only if (a) it is central to this source's contribution, or (b) it is likely to recur across other sources in this wiki. Aim for roughly 3–7 concepts per source; minor keywords belong in body prose, not as concept links. Every linked concept implies a stub + edges in Phases 4–5, so over-extraction dilutes the graph.
143
+
119
144
  Provenance rubric (raw-centric):
120
145
  - `replayable` — `raw_paths` non-empty, every entry resolves to existing file
121
146
  - `partial` — `urls` has entries but `raw_paths` empty or missing
@@ -141,7 +166,7 @@ node _lumina/scripts/wiki.mjs resolve-alias "<concept-name>"
141
166
 
142
167
  If it resolves to a foundation, link via `[[foundations/<slug>]]` and add `grounded_in` edge instead of creating a stub. See `dedup-policy.md` § Foundation Resolution.
143
168
 
144
- Apply `dedup-policy.md` before creating/updating stubs. Existing pages are updated conservatively.
169
+ Apply `dedup-policy.md` before creating/updating stubs — including the concept variant scan (acronym vs expansion, singular vs plural), which catches duplicates that exact-slug lookup misses. Existing pages are updated conservatively.
145
170
 
146
171
  New stubs use the templates in `_lumina/schema/page-templates.md`.
147
172
 
@@ -172,10 +197,14 @@ node _lumina/scripts/wiki.mjs add-citation sources/<slug> sources/<cited-slug>
172
197
 
173
198
  Do not create stubs for cited sources not yet ingested — note them in `## Open Questions`.
174
199
 
200
+ Write checkpoint: `phase: "citations"`.
201
+
175
202
  ### Phase 7 — Update wiki/index.md
176
203
 
177
204
  Add the new source page (and any new concept/person pages) to the catalog between `<!-- lumina:index -->` markers. Format: `- [[sources/<slug>]] — <one-line description>`.
178
205
 
206
+ Write checkpoint: `phase: "index"`.
207
+
179
208
  ## Draft Gate
180
209
 
181
210
  Present a draft summary to the user:
@@ -196,7 +225,7 @@ Use the user's configured communication language. Explain "provenance", "edges",
196
225
  ```
197
226
  → NEXT
198
227
  - **E**: Take the user's revision instructions. Re-edit the affected files (source page, stubs, or edges as instructed). Re-present the draft summary. Loop back to "HALT and ask human" — do not advance.
199
- - **Q**: Leave the phase-level checkpoint in place; do not write `ingest_status`. **STOP — do not read the NEXT directive below.** Exit cleanly with no further action this run. The next `/lumi-ingest <slug>` invocation resumes from this point.
228
+ - **Q**: Leave the phase-level checkpoint in place; do not write `ingest_status`. Before exiting, tell the user in plain language that the draft pages and links written so far stay in the wiki as work-in-progress — coming back to `/lumi-ingest <slug>` continues from here, and `/lumi-reset` can clean up if they decide not to keep this source at all. **STOP — do not read the NEXT directive below.** Exit cleanly with no further action this run.
200
229
 
201
230
  ## NEXT
202
231
 
@@ -3,7 +3,7 @@
3
3
  ## RULES
4
4
 
5
5
  - Read `README.md` at the project root before this step if you have not already in this session.
6
- - Reuse the existing `/lumi-verify` skill in grounding-only mode. Do not inline a duplicate grounding reviewer here — single source of truth for grounding logic lives in `src/skills/core/verify/`.
6
+ - Reuse the existing `/lumi-verify` skill in grounding-only mode. Do not inline a duplicate grounding reviewer here — single source of truth for grounding logic lives in `.agents/skills/lumi-verify/`.
7
7
  - All frontmatter writes go through `wiki.mjs set-meta`. Never write to `wiki/*.md` directly.
8
8
  - Drift is a hard halt: a missing `raw_paths` file is a stronger signal than any finding and should not be silently downgraded.
9
9
  - This step asks the user only when there are source-check findings, missing source files, or a confidence downgrade. If the source check passes, continue automatically.
@@ -24,7 +24,7 @@ Invoke `/lumi-verify` on the entry restricted to the grounding reviewer. Three r
24
24
 
25
25
  **Tier 1 — Agent tool available (Claude Code):**
26
26
 
27
- Spawn a sub-agent with the verify SKILL prompt and the slug, instructing it to run grounding only (skip blind, skip external). Wait for completion, then read the writeback:
27
+ Spawn a sub-agent instructed to read and follow `.agents/skills/lumi-verify/SKILL.md` with this slug as the target, grounding only (skip blind, skip external). The sub-agent is deliberate: it activates the verify skill in a blank context, so the verdict is not anchored by the reasoning chain that just drafted the pages. Do not invoke the verify skill inline in this conversation (e.g. via a skill-invocation tool) — same-context verification inherits drafting bias. Wait for completion, then read the writeback:
28
28
 
29
29
  ```bash
30
30
  node _lumina/scripts/wiki.mjs read-meta sources/<slug>
@@ -32,9 +32,9 @@ node _lumina/scripts/wiki.mjs read-meta sources/<slug>
32
32
 
33
33
  **Tier 2 — Bash-only runtime (Codex, Gemini, Cursor, generic):**
34
34
 
35
- Read fully and follow `src/skills/core/verify/SKILL.md` Grounding pipeline (Section: "Grounding reviewer"), with this slug as the target. The verify skill's writeback contract is the same — `verify_status` and `findings` written to the entry frontmatter. After the grounding pass returns, control returns to this step's Phase 8.6.
35
+ Read fully and follow `.agents/skills/lumi-verify/SKILL.md` Grounding pipeline (Section: "Grounding reviewer"), with this slug as the target. The verify skill's writeback contract is the same — `verify_status` and `findings` written to the entry frontmatter. After the grounding pass returns, control returns to this step's Phase 8.6.
36
36
 
37
- If `src/skills/core/verify/references/reviewers.md` exists, it is the canonical Grounding reviewer prompt; load it as part of following the verify SKILL.
37
+ If `.agents/skills/lumi-verify/references/reviewers.md` exists, it is the canonical Grounding reviewer prompt; load it as part of following the verify SKILL.
38
38
 
39
39
  **Tier 3 — User opts out:**
40
40
 
@@ -54,6 +54,7 @@ Inspect `verify_status` and `findings`:
54
54
  | `findings_pending` | Patch/defer findings written | Present findings inline; user chooses A/E/W/Q |
55
55
  | `drift_detected` | `raw_paths` resolves to missing files | **Hard HALT** — do not present standard menu; force user to repair raw or set `provenance: missing` explicitly |
56
56
  | `skipped` | Tier 3 opt-out | Write verified status and continue automatically; the user already opted out |
57
+ | `not_applicable` | Verify refused: target is not a `sources/*` entry | Should never happen during ingest (the target is always `sources/<slug>`). Treat as an internal error: HALT, report the slug that was passed to verify, and do not advance `ingest_status`. |
57
58
 
58
59
  For `passed`, tell the user in one short sentence that the page matched the source closely enough to continue. Then write `ingest_status: verified` and go to NEXT:
59
60
 
@@ -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
@@ -47,12 +47,14 @@ Key workspace paths:
47
47
  |-------|----------------|-------------|
48
48
  | `wiki` | All files under `wiki/` (keeps directory structure) | Only from git |
49
49
  | `raw` | All files under `raw/sources/`, `raw/notes/`, `raw/assets/` | Not from wiki |
50
- | `state` | `_lumina/_state/*.json` checkpoint files | Yes — re-ingest regenerates |
51
- | `checkpoints` | `_lumina/_state/ingest-*.json` only | Yes — re-ingest regenerates |
50
+ | `state` | Everything under `_lumina/_state/`, including subfolders (saved reviewer prompts, feed state) | Yes — re-ingest regenerates |
51
+ | `checkpoints` | Every `<skill>-<phase>.json` file directly under `_lumina/_state/` — this is ANY checkpoint, not just ingest: resume points, research-discover shortlists, discovery-phase checkpoints, and saved `/lumi-verify` report files (`lumi-verify-<ts>.json`) | Yes for ingest/discover checkpoints — re-run regenerates. **No** for saved `/lumi-verify` reports — those are deleted too and are not regenerated automatically. |
52
52
  | `all` | `wiki` + `state` — leaves `raw/` untouched | Only wiki from git |
53
53
 
54
- The `checkpoints` scope is the safest reset it only clears in-progress ingest
55
- state. Use it when an ingest got stuck and you want a clean restart.
54
+ The `checkpoints` scope is the lowest-risk reset in terms of what it targets
55
+ (no wiki content), but it is not scoped to "ingest only" warn the user that
56
+ any saved `/lumi-verify` reports under `_lumina/_state/` are removed along with
57
+ stuck ingest checkpoints.
56
58
 
57
59
  ## Instructions
58
60
 
@@ -73,18 +75,37 @@ node _lumina/scripts/reset.mjs --scope <scope> --dry-run
73
75
  ```
74
76
 
75
77
  The `--dry-run` flag makes `reset.mjs` print the deletion plan without deleting
76
- anything and does not require `--yes`. Example output:
78
+ anything and does not require `--yes`. `reset.mjs` reports aggregate
79
+ per-directory counts, not a per-file list. Example output:
77
80
 
78
81
  ```
79
- [DRY RUN] Scope: wiki
80
- Would delete: wiki/sources/lora.md
81
- Would delete: wiki/concepts/lora-adapter.md
82
- Would delete: wiki/log.md
83
- ...
84
- Total: 23 files
82
+ Plan: --scope wiki --yes
83
+ Would delete:
84
+ wiki/ (23 files, 45.2 KB)
85
+ Would recreate:
86
+ wiki/index.md (empty)
87
+ wiki/log.md (empty)
88
+ Total: 23 files, 45.2 KB
85
89
  ```
86
90
 
87
- Present this list to the user verbatim.
91
+ For the `checkpoints` scope, the deleted directory is labeled to make clear
92
+ only checkpoint files count toward the total, e.g.:
93
+
94
+ ```
95
+ Plan: --scope checkpoints --yes
96
+ Would delete:
97
+ _lumina/_state/ (checkpoints only) (3 files, 1.8 KB)
98
+ Total: 3 files, 1.8 KB
99
+ ```
100
+
101
+ Present the real aggregate plan to the user, and also translate it into one
102
+ plain sentence so a non-technical reader gets the point immediately, e.g.
103
+ "This will permanently delete 23 files under wiki/ — about 45 KB."
104
+
105
+ If the plan's final line reads `Total: 0 files, 0 B`, there is nothing to
106
+ delete. Skip Step 3 (confirmation) entirely — report "Nothing to delete for
107
+ scope `<scope>`; already clean." and stop. Do not ask for a "yes" that has
108
+ nothing to confirm.
88
109
 
89
110
  ### Step 3 — Require explicit confirmation
90
111
 
@@ -139,13 +160,15 @@ re-verify directory structure).
139
160
 
140
161
  **Before execution:**
141
162
  ```
142
- Reset plan for scope: <scope>
143
- Files to delete:
144
- wiki/sources/lora.md
145
- wiki/concepts/lora-adapter.md
146
- (N more...)
147
- Total: <N> files
148
-
163
+ Plan: --scope <scope> --yes
164
+ Would delete:
165
+ wiki/ (23 files, 45.2 KB)
166
+ Would recreate:
167
+ wiki/index.md (empty)
168
+ wiki/log.md (empty)
169
+ Total: 23 files, 45.2 KB
170
+
171
+ This will permanently delete 23 files under wiki/ — about 45 KB.
149
172
  Type yes to confirm, anything else to cancel.
150
173
  ```
151
174
 
@@ -161,16 +184,25 @@ Next: run /lumi-init to re-seed the wiki, then /lumi-ingest to rebuild content.
161
184
  <example>
162
185
  User: "The ingest for attention-revisited got killed. Start it over."
163
186
 
164
- Safest reset — clear a single stuck checkpoint:
187
+ Safest reset — clear a single stuck checkpoint. `--scope checkpoints` deletes
188
+ every checkpoint file under `_lumina/_state/`, not just this one — check the
189
+ count before confirming:
165
190
  ```bash
166
191
  node _lumina/scripts/reset.mjs --scope checkpoints --dry-run
167
- # shows: Would delete: _lumina/_state/ingest-attention-revisited-2026.json
192
+ # shows:
193
+ # Plan: --scope checkpoints --yes
194
+ # Would delete:
195
+ # _lumina/_state/ (checkpoints only) (1 files, 0.4 KB)
196
+ # Total: 1 files, 0.4 KB
197
+ # Only one checkpoint exists right now, so this is safe.
168
198
  # User confirms: yes
169
199
  node _lumina/scripts/reset.mjs --scope checkpoints --yes
170
200
  node _lumina/scripts/wiki.mjs log reset "Scope: checkpoints. 1 file deleted."
171
201
  ```
172
202
  Suggest: "Now run `/lumi-ingest raw/sources/attention-revisited.pdf` to restart."
173
- Checkpoint scope is the lowest-risk reset only in-progress state is removed.
203
+ Checkpoint scope is lower-risk than `wiki` or `raw` (no wiki content touched),
204
+ but if other checkpoints exist (other stuck ingests, saved `/lumi-verify`
205
+ reports) they are deleted too — the dry-run count is the only way to know.
174
206
  </example>
175
207
 
176
208
  <example>
@@ -189,9 +221,10 @@ After reset, log.md is gone — recreate it with the reset entry, then suggest
189
221
  User: "Reset everything." (then reconsiders after seeing the plan)
190
222
 
191
223
  Escalation / reconsideration — user sees the dry-run plan for `all` scope:
192
- Show the deletion tree for wiki/ and state only. Explicitly state: "`all` does
193
- not delete raw/; use `--scope raw` only when you intend to remove user-owned
194
- sources." User replies "cancel". Report: "Reset cancelled. No files were deleted."
224
+ Show the aggregate deletion plan for `wiki/` and `_lumina/_state/` only.
225
+ Explicitly state: "`all` does not delete raw/; use `--scope raw` only when you
226
+ intend to remove user-owned sources." User replies "cancel". Report: "Reset
227
+ cancelled. No files were deleted."
195
228
  Never execute without the
196
229
  literal word "yes" — ambiguous confirmations like "ok" or "sure" do not count.
197
230
  </example>
@@ -61,6 +61,7 @@ Accepted invocations:
61
61
  - `/lumi-verify --all` — verify every `sources/*` entry
62
62
  - `/lumi-verify --since <date>` — verify entries whose `updated` >= `<date>` (ISO 8601 date or datetime). Reject malformed dates with exit 1.
63
63
  - `/lumi-verify --external` — additionally run the External reviewer (open-web check). Default is offline-only (Blind + Grounding).
64
+ - `/lumi-verify --stage <...>` — run the reviewers and report findings but do not write anything to the page (see Step 5); useful for a preview pass.
64
65
 
65
66
  Resolve the target list:
66
67
 
@@ -150,7 +150,7 @@ or update the reflection page:
150
150
  Append a log entry via the wiki engine:
151
151
 
152
152
  ```bash
153
- node _lumina/scripts/wiki.mjs log lumi-learning-reflect "reflected on <concept-id>; evolution_count=<N>"
153
+ node _lumina/scripts/wiki.mjs log learning-reflect "reflected on <concept-id>; evolution_count=<N>"
154
154
  ```
155
155
 
156
156
  Then report to the user:
@@ -76,10 +76,10 @@ re-running against the same chapter slug produces byte-identical output.
76
76
  graph files by hand.
77
77
  8. Append one line through the wiki engine:
78
78
  ```bash
79
- node _lumina/scripts/wiki.mjs log chapter-ingest "<book-slug> ch<N> \"<chapter-title>\" -> <K> characters, <M> themes"
79
+ node _lumina/scripts/wiki.mjs log reading-chapter-ingest "<book-slug> ch<N> \"<chapter-title>\" -> <K> characters, <M> themes"
80
80
  ```
81
81
  Log entry text:
82
- `## [YYYY-MM-DD] chapter-ingest | <book-slug> ch<N> "<chapter-title>" → <K> characters, <M> themes`
82
+ `## [YYYY-MM-DD] reading-chapter-ingest | <book-slug> ch<N> "<chapter-title>" → <K> characters, <M> themes`
83
83
  9. Self-verification: run `node _lumina/scripts/wiki.mjs read-edges chapters/<book-slug>/<chapter-slug> --json`
84
84
  and confirm that at least one `features` edge and one `tagged_with` edge are present.
85
85
  If either is missing, add the missing edges before finishing.
@@ -117,7 +117,7 @@ slug. The engine is idempotent: re-adding a correctly formed edge is a safe no-o
117
117
  Update `wiki/index.md` if new character pages were created, append the activity via:
118
118
 
119
119
  ```bash
120
- node _lumina/scripts/wiki.mjs log character-track "<book-slug> ch<N> -> <K> characters updated, <M> edges added"
120
+ node _lumina/scripts/wiki.mjs log reading-character-track "<book-slug> ch<N> -> <K> characters updated, <M> edges added"
121
121
  ```
122
122
 
123
123
  Run `node _lumina/scripts/lint.mjs --json` when available; use `--fix` only for
@@ -133,7 +133,7 @@ index/frontmatter fixes within this skill's scope.
133
133
  - All inter-character edges use namespaced slugs.
134
134
  - `wiki/index.md` updated when character pages were created.
135
135
  - `wiki/log.md` has a new entry:
136
- `## [YYYY-MM-DD] character-track | <book-slug> ch<N> → <K> characters updated, <M> edges added`
136
+ `## [YYYY-MM-DD] reading-character-track | <book-slug> ch<N> → <K> characters updated, <M> edges added`
137
137
  - Lint/check run where available; unresolved issues are reported with exact slugs.
138
138
 
139
139
  ## Guardrails
@@ -126,7 +126,7 @@ one, it was promoted prematurely — revert to stub status and note in the repor
126
126
  Then update `wiki/index.md` if new theme pages were created, append the activity via:
127
127
 
128
128
  ```bash
129
- node _lumina/scripts/wiki.mjs log theme-map "<book-slug> -> <K> themes promoted, <M> stubs pending"
129
+ node _lumina/scripts/wiki.mjs log reading-theme-map "<book-slug> -> <K> themes promoted, <M> stubs pending"
130
130
  ```
131
131
 
132
132
  Run `node _lumina/scripts/lint.mjs --json` when available; use `--fix` only for
@@ -140,7 +140,7 @@ index/frontmatter fixes within this skill's scope.
140
140
  - Theme stubs for single-chapter tags remain as stubs (not promoted).
141
141
  - `wiki/index.md` updated when pages were created or promoted.
142
142
  - `wiki/log.md` has a new entry:
143
- `## [YYYY-MM-DD] theme-map | <book-slug> → <K> themes promoted, <M> stubs pending`
143
+ `## [YYYY-MM-DD] reading-theme-map | <book-slug> → <K> themes promoted, <M> stubs pending`
144
144
  - Lint/check run where available; unresolved issues are reported with exact slugs.
145
145
 
146
146
  ## Guardrails
@@ -113,7 +113,7 @@ python3 _lumina/tools/fetch_wikipedia.py page "<title>"
113
113
  6. Log the addition:
114
114
 
115
115
  ```bash
116
- node _lumina/scripts/wiki.mjs log lumi-research-prefill "prefilled foundation <slug>"
116
+ node _lumina/scripts/wiki.mjs log research-prefill "prefilled foundation <slug>"
117
117
  ```
118
118
 
119
119
  7. Run lint with fix so `wiki/index.md` and structural checks stay current:
@@ -122,6 +122,10 @@ node _lumina/scripts/wiki.mjs log lumi-research-prefill "prefilled foundation <s
122
122
  node _lumina/scripts/lint.mjs --fix --json
123
123
  ```
124
124
 
125
+ 8. Suggest `/lumi-check` in a fresh session or via a subagent after this run.
126
+ A blank context catches bias from the reasoning chain that just wrote the
127
+ foundation page.
128
+
125
129
  ## Constraints
126
130
 
127
131
  - Do not create concept pages from this skill; use `/lumi-ingest` for wiki
@@ -140,6 +144,6 @@ node _lumina/scripts/lint.mjs --fix --json
140
144
  - Foundation page exists with valid frontmatter and concise source-backed body.
141
145
  - `node _lumina/scripts/lint.mjs --fix --json` has updated `wiki/index.md` if
142
146
  needed and leaves `summary.errors === 0`.
143
- - `wiki/log.md` has an append-only `lumi-research-prefill` entry.
147
+ - `wiki/log.md` has an append-only `research-prefill` entry.
144
148
  - If the page already existed, the user's choice (skip / refresh / abort) is logged
145
149
  in `wiki/log.md` with the actual decision taken.
@@ -150,7 +150,7 @@ References:
150
150
  8. **Log the activity.**
151
151
 
152
152
  ```bash
153
- node _lumina/scripts/wiki.mjs log lumi-research-rank "ranked <slug>: infl=<n>, 4C=<c/c/c/c>"
153
+ node _lumina/scripts/wiki.mjs log research-rank "ranked <slug>: infl=<n>, 4C=<c/c/c/c>"
154
154
  ```
155
155
 
156
156
  9. **Report to the user in plain language.** Summarize what you found — how
@@ -18,8 +18,23 @@ not discover or ingest new sources here; gaps should be reported explicitly.
18
18
 
19
19
  ## Context
20
20
 
21
- Read `README.md` first. Use `_lumina/scripts/wiki.mjs` for entity and graph
22
- queries:
21
+ Read `README.md` first. Survey pages live under `wiki/summary/` and use the
22
+ same frontmatter contract as any other summary page: `id`, `title`,
23
+ `type: summary`, `created`, `updated`, and `covers` (an array of every wiki
24
+ page slug the survey draws on). `covers` is required — a summary page without
25
+ it fails lint (L01).
26
+
27
+ When speaking with the user, follow the README language rule exactly. Use the
28
+ configured communication language and avoid technical tool words unless the
29
+ user asks for them.
30
+
31
+ ## Instructions
32
+
33
+ 1. Identify the topic scope and the source/concept pages that support it. Ask
34
+ the user a clarifying question if the scope is ambiguous rather than
35
+ guessing.
36
+
37
+ 2. Read only relevant wiki pages and graph edges:
23
38
 
24
39
  ```bash
25
40
  node _lumina/scripts/wiki.mjs list-entities --type sources
@@ -28,36 +43,131 @@ node _lumina/scripts/wiki.mjs read-meta sources/<slug>
28
43
  node _lumina/scripts/wiki.mjs read-edges sources/<slug>
29
44
  ```
30
45
 
31
- ## Instructions
46
+ 3. Synthesize the survey in chat. Cite every claim to a wiki page
47
+ (`[[sources/<slug>]]` or `[[concepts/<slug>]]`) and add an explicit gaps
48
+ section naming what the wiki does not yet cover or where sources disagree.
49
+ This is a draft — do not write any file yet.
50
+
51
+ 4. Ask the user whether to save the survey. Do not write
52
+ `wiki/summary/<slug>.md` until the user explicitly asks to save it. If the
53
+ user only wanted an answer in chat, stop here.
54
+
55
+ 5. If the user asks to save, generate the slug:
56
+
57
+ ```bash
58
+ node _lumina/scripts/wiki.mjs slug "<survey title>"
59
+ ```
60
+
61
+ 6. Check whether `wiki/summary/<slug>.md` already exists:
62
+
63
+ ```bash
64
+ node _lumina/scripts/wiki.mjs read-meta summary/<slug>
65
+ ```
32
66
 
33
- 1. Identify the topic scope and the source/concept pages that support it.
34
- 2. Read only relevant wiki pages and graph edges.
35
- 3. Synthesize the survey with cited source references and a section for gaps or
36
- unresolved disagreements.
37
- 4. If the user asks to save it, write `wiki/summary/<survey-slug>.md` with valid
38
- summary frontmatter and link the covered pages.
39
- 5. Log the saved survey:
67
+ - **exit 2 (not found)** continue to step 7.
68
+ - **exit 0 (exists)** read the file, then show the user the `title` and
69
+ `created` date. Ask exactly one question with three options in the user's
70
+ language (no other action until answered). Explain the choices plainly:
71
+
72
+ ```
73
+ Survey "<title>" already exists.
74
+ [s] skip — abort, no changes (default)
75
+ [r] refresh — replace the survey body with the new draft; preserve `created` and `<!-- user-edited -->` sections
76
+ [a] abort — same as skip but log the user's intent
77
+ ```
78
+
79
+ Map blank/Enter to `skip`. Do not proceed without an explicit choice.
80
+
81
+ 7. Write `wiki/summary/<slug>.md` with valid summary frontmatter and the two
82
+ standard sections. Use today's date for both `created` and `updated` on a
83
+ new page; on a refresh keep the original `created` date. `covers` must list
84
+ every wiki page slug the survey cites — omitting it is the most common way
85
+ this skill fails lint.
86
+
87
+ ```markdown
88
+ ---
89
+ id: <slug>
90
+ title: "<Survey Title>"
91
+ type: summary
92
+ created: YYYY-MM-DD
93
+ updated: YYYY-MM-DD
94
+ covers:
95
+ - sources/<slug>
96
+ - concepts/<slug>
97
+ - ...
98
+ ---
99
+
100
+ ## Survey
101
+
102
+ <!-- The narrative synthesis, written in document_output_language, with
103
+ inline [[wikilinks]] to every cited page. -->
104
+
105
+ ## Gaps
106
+
107
+ <!-- Bullet list of what the wiki does not yet cover, or where sources
108
+ disagree. Keep the section even when empty — write "none identified"
109
+ rather than omitting it. -->
110
+ ```
111
+
112
+ 8. Log the saved survey:
40
113
 
41
114
  ```bash
42
- node _lumina/scripts/wiki.mjs log lumi-research-survey "saved survey <survey-slug>"
115
+ node _lumina/scripts/wiki.mjs log research-survey "saved survey <slug>"
43
116
  ```
44
117
 
45
- 6. When a survey page is saved, run lint with fix so `wiki/index.md` and graph
46
- checks stay current:
118
+ On a refresh, write `"refreshed survey <slug> ..."` instead.
119
+
120
+ 9. Run lint with fix so `wiki/index.md` and structural checks stay current:
47
121
 
48
122
  ```bash
49
123
  node _lumina/scripts/lint.mjs --fix --json
50
124
  ```
51
125
 
126
+ If `summary.errors > 0`, read the lint output, address each error, and
127
+ re-run before telling the user the skill is done.
128
+
129
+ 10. Suggest `/lumi-check` in a fresh session or via a subagent after saving. A
130
+ blank context catches bias from the reasoning chain that just wrote the
131
+ survey.
132
+
52
133
  ## Constraints
53
134
 
54
135
  - Do not read raw source files unless the user explicitly asks for a gap audit.
55
136
  - Do not create new source or concept pages.
56
137
  - Do not claim coverage beyond the current wiki graph.
138
+ - Do not write `wiki/summary/<slug>.md` before the user explicitly asks to
139
+ save the survey — an unsaved survey lives only in the chat response.
140
+ - When refreshing an existing survey, preserve the original `created` date and
141
+ any `<!-- user-edited -->` sections verbatim. Only `updated`, the survey
142
+ body, and `covers` may change.
143
+
144
+ ## Examples
145
+
146
+ <example>
147
+ User asks: "What does the wiki know about attention mechanisms?" without
148
+ asking to save it.
149
+ Action: read the `sources` and `concepts` entity lists, read edges for the
150
+ relevant pages, then answer in chat with citations to `[[sources/...]]` and
151
+ `[[concepts/...]]`, plus a gaps note (for example: "no source yet covers
152
+ sparse attention variants"). No slug is generated and no file is written.
153
+ </example>
154
+
155
+ <example>
156
+ User asks the same question, then says "save that as a survey".
157
+ Action: generate the slug, confirm `wiki/summary/attention-mechanisms.md`
158
+ does not already exist, write the page with a `covers` array listing every
159
+ cited source and concept slug plus the `## Survey` / `## Gaps` sections, log
160
+ `research-survey "saved survey attention-mechanisms"`, run
161
+ `lint.mjs --fix --json`, and suggest running `/lumi-check` in a fresh session.
162
+ </example>
57
163
 
58
164
  ## Definition of Done
59
165
 
60
166
  - Unsaved survey responses name supporting wiki pages and explicit gaps.
61
- - Saved survey pages have valid summary frontmatter and cite covered pages.
167
+ - Saved survey pages have valid summary frontmatter, including a non-empty
168
+ `covers` array listing every cited page.
169
+ - The survey file was written only after the user explicitly asked to save it.
62
170
  - If saved, lint leaves `summary.errors === 0`, `wiki/index.md` is current, and
63
- `wiki/log.md` has an append-only `lumi-research-survey` entry.
171
+ `wiki/log.md` has an append-only `research-survey` entry.
172
+ - If the page already existed, the user's choice (skip / refresh / abort) is
173
+ logged in `wiki/log.md` with the actual decision taken.
@@ -66,14 +66,17 @@ node _lumina/scripts/wiki.mjs list-entities --type sources
66
66
  node _lumina/scripts/wiki.mjs list-entities --type concepts
67
67
  ```
68
68
 
69
- If the user named a seed concept, also fetch its immediate neighbours:
69
+ If the user named a seed concept that already exists as a concept page, also
70
+ fetch its immediate neighbours (the topic title itself is never a seed slug —
71
+ the topic page does not exist yet, so do not run read-edges against it):
70
72
 
71
73
  ```bash
72
74
  node _lumina/scripts/wiki.mjs read-edges concepts/<seed-slug>
73
75
  ```
74
76
 
75
77
  From the combined output, select 5-10 candidate sources and 5-10 candidate
76
- concepts most relevant to the topic. Present them as a numbered list with a
78
+ concepts most relevant to the topic. On a small wiki with fewer than 5 of
79
+ either, propose all relevant ones — a shorter list is fine. Present them as a numbered list with a
77
80
  one-line reason for each. Group sources and concepts separately. Explain that
78
81
  the user can:
79
82
  - confirm the list as shown,
@@ -124,29 +127,24 @@ node _lumina/scripts/wiki.mjs read-edges concepts/<seed-slug>
124
127
  Leave blank if none are obvious; the user can fill this in later. -->
125
128
  ```
126
129
 
127
- 5. Write bidirectional edges for every approved source and concept. For each
128
- approved source, add both directions:
130
+ 5. Write edges for every approved source and concept. Call `add-edge` once for
131
+ the forward relationship from the topic page — the engine writes the
132
+ reverse edge automatically. For each approved source:
129
133
 
130
134
  ```bash
131
135
  node _lumina/scripts/wiki.mjs add-edge topics/<slug> includes_source sources/<source-slug>
132
- node _lumina/scripts/wiki.mjs add-edge sources/<source-slug> included_in_topic topics/<slug>
133
136
  ```
134
137
 
135
- For each approved concept, add both directions:
138
+ For each approved concept:
136
139
 
137
140
  ```bash
138
141
  node _lumina/scripts/wiki.mjs add-edge topics/<slug> covers_concept concepts/<concept-slug>
139
- node _lumina/scripts/wiki.mjs add-edge concepts/<concept-slug> covered_by_topic topics/<slug>
140
142
  ```
141
143
 
142
- If `add-edge` is not the correct subcommand, check available subcommands with
143
- `node _lumina/scripts/wiki.mjs --help` and use the correct one before
144
- proceeding.
145
-
146
144
  6. Log the operation:
147
145
 
148
146
  ```bash
149
- node _lumina/scripts/wiki.mjs log lumi-research-topic "created topic <slug> covering <N> sources, <M> concepts"
147
+ node _lumina/scripts/wiki.mjs log research-topic "created topic <slug> covering <N> sources, <M> concepts"
150
148
  ```
151
149
 
152
150
  On a refresh, write `"refreshed topic <slug> ..."` instead.
@@ -160,15 +158,19 @@ node _lumina/scripts/lint.mjs --fix --json
160
158
  If `summary.errors > 0`, read the lint output, address each error, and re-run
161
159
  before telling the user the skill is done.
162
160
 
161
+ 8. Suggest `/lumi-check` in a fresh session or via a subagent after this run. A
162
+ blank context catches bias from the reasoning chain that just built the
163
+ topic page.
164
+
163
165
  ## Constraints
164
166
 
165
167
  - Do not read `raw/` files at any point. All information comes from already-ingested
166
168
  wiki pages and graph edges.
167
169
  - Do not create concept or source pages from this skill. If a candidate the user
168
170
  wants does not have a wiki page, tell them to run `/lumi-ingest` first.
169
- - Every forward link from the topic page to a concept or source must have a
170
- reverse edge written in the same operation. This is a hard graph rule — do not
171
- skip it.
171
+ - Every forward link from the topic page to a concept or source needs a
172
+ reverse edge the engine writes the reverse edge in the same operation.
173
+ Never add reverse edges manually.
172
174
  - When refreshing an existing topic, preserve the original `created` date and any
173
175
  `<!-- user-edited -->` sections verbatim. Only `updated`, `key_sources`, and
174
176
  non-marked sections may change.
@@ -183,9 +185,10 @@ node _lumina/scripts/lint.mjs --fix --json
183
185
  entry) and all four standard sections (Description / Key sources / Key
184
186
  concepts / Open questions).
185
187
  - Bidirectional edges exist for every linked source and concept — forward from
186
- the topic page and reverse on each source and concept page.
188
+ the topic page, written once via `add-edge`, with the reverse edge on each
189
+ source and concept page written automatically by the engine.
187
190
  - `node _lumina/scripts/lint.mjs --fix --json` leaves `summary.errors === 0`.
188
- - `wiki/log.md` has an append-only `lumi-research-topic` entry recording the
191
+ - `wiki/log.md` has an append-only `research-topic` entry recording the
189
192
  slug, source count, and concept count.
190
193
  - If the page already existed, the user's choice (skip / refresh / abort) is
191
194
  logged in `wiki/log.md` with the actual decision taken.
@@ -30,11 +30,14 @@ with the research pack and depends on:
30
30
  - `_lumina/tools/fetch_rss.py` — used by the runner for `type: feed` items.
31
31
 
32
32
  The runner is **manual** — Lumina does not poll feeds in the background. The
33
- user (or their scheduler) decides when to trigger this skill. See
34
- `docs/user-guide/advanced-scheduled-discovery.{en,vi,zh}.md` for cron /
35
- launchd / Task Scheduler templates (trilingual), and
36
- `docs/user-guide/research-watch.md` for the v1.4 feed schema, etag /
37
- XXE / per-feed-state deep-dive (English).
33
+ user (or their scheduler) decides when to trigger this skill. See the online
34
+ guide at
35
+ https://github.com/tronghieu/lumina-wiki/blob/main/docs/user-guide/advanced-scheduled-discovery.en.md
36
+ (also in Vietnamese at .../advanced-scheduled-discovery.vi.md and Simplified
37
+ Chinese at .../advanced-scheduled-discovery.zh.md) for cron / launchd / Task
38
+ Scheduler templates, and the online guide at
39
+ https://github.com/tronghieu/lumina-wiki/blob/main/docs/user-guide/research-watch.md
40
+ for the v1.4 feed schema, etag / XXE / per-feed-state deep-dive (English).
38
41
 
39
42
  ## Instructions
40
43
 
@@ -79,12 +82,16 @@ Never dump raw JSON or stack traces to the user — keep it conversational.
79
82
 
80
83
  ### 4. If the user asks about scheduling
81
84
 
82
- Point them at `docs/user-guide/advanced-scheduled-discovery.{en,vi,zh}.md`
83
- (trilingual cron / launchd / Task Scheduler patterns) and the included
84
- wrapper `_lumina/scripts/scheduler-samples/cron-daily.sh`. For v1.4 feed
85
- schema / etag / XXE specifics, the deep-dive lives at
86
- `docs/user-guide/research-watch.md` (English). Do not edit their crontab
87
- or launchd files; explain the snippets and let them paste.
85
+ Point them at the online guide (trilingual cron / launchd / Task Scheduler
86
+ patterns) at
87
+ https://github.com/tronghieu/lumina-wiki/blob/main/docs/user-guide/advanced-scheduled-discovery.en.md
88
+ (.vi.md and .zh.md for Vietnamese and Simplified Chinese) and the included
89
+ wrapper `_lumina/scripts/scheduler-samples/cron-daily.sh` that file is a
90
+ local path, shipped with the workspace. For v1.4 feed schema / etag / XXE
91
+ specifics, the deep-dive lives at the online guide
92
+ https://github.com/tronghieu/lumina-wiki/blob/main/docs/user-guide/research-watch.md
93
+ (English). Do not edit their crontab or launchd files; explain the snippets
94
+ and let them paste.
88
95
 
89
96
  ## Constraints
90
97
 
@@ -160,14 +160,17 @@ Tell the user:
160
160
  - papers are downloaded later during `/lumi-ingest`, after the user chooses a
161
161
  candidate.
162
162
 
163
- If the user asks how to schedule it, point them to
164
- `docs/user-guide/advanced-scheduled-discovery.{en,vi,zh}.md` (trilingual
165
- cron / launchd / Actions / Task Scheduler patterns) and the
166
- `/lumi-research-watch-run` skill which runs one pass over the watchlist on
167
- demand. They can also follow an RSS / Atom feed by adding a `type: feed`
168
- item (https URL required) the advanced-scheduled-discovery guide §7 has
169
- the YAML example, and `docs/user-guide/research-watch.md` carries the v1.4
170
- technical deep-dive (English).
163
+ If the user asks how to schedule it, point them to the online guide at
164
+ https://github.com/tronghieu/lumina-wiki/blob/main/docs/user-guide/advanced-scheduled-discovery.en.md
165
+ (also available in Vietnamese at
166
+ .../advanced-scheduled-discovery.vi.md and Simplified Chinese at
167
+ .../advanced-scheduled-discovery.zh.md trilingual cron / launchd / Actions /
168
+ Task Scheduler patterns) and the `/lumi-research-watch-run` skill which runs
169
+ one pass over the watchlist on demand. They can also follow an RSS / Atom feed
170
+ by adding a `type: feed` item (https URL required) — the advanced-scheduled-
171
+ discovery guide §7 has the YAML example, and the online guide at
172
+ https://github.com/tronghieu/lumina-wiki/blob/main/docs/user-guide/research-watch.md
173
+ carries the v1.4 technical deep-dive (English).
171
174
 
172
175
  ## Constraints
173
176
 
@@ -129,6 +129,7 @@ When you write a forward link, **always write the reverse link in the same opera
129
129
  | `concepts/K` writes `[[source-E]]` | `sources/E` appends K to `Related concepts`|
130
130
  | `summary/S` writes `[[concept-K]]` | `concepts/K` appends S to `Mentioned in` |
131
131
  {{#if pack_research}}| `topics/T` writes `[[concept-K]]` | `concepts/K` appends T to `Topics` |
132
+ | `topics/T` writes `[[source-A]]` | `sources/A` appends T to `Topics` |
132
133
  {{/if}}{{#if pack_reading}}| `chapters/Ch` writes `[[character-X]]` | `characters/X` appends Ch to `Key chapters`|
133
134
  | `chapters/Ch` writes `[[theme-Y]]` | `themes/Y` appends Ch to `Traced in` |
134
135
  {{/if}}
@@ -129,6 +129,7 @@ Khi bạn viết một liên kết chiều đi, **luôn viết liên kết ngư
129
129
  | `concepts/K` viết `[[source-E]]` | `sources/E` thêm K vào `Related concepts` |
130
130
  | `summary/S` viết `[[concept-K]]` | `concepts/K` thêm S vào `Mentioned in` |
131
131
  {{#if pack_research}}| `topics/T` viết `[[concept-K]]` | `concepts/K` thêm T vào `Topics` |
132
+ | `topics/T` viết `[[source-A]]` | `sources/A` thêm T vào `Topics` |
132
133
  {{/if}}{{#if pack_reading}}| `chapters/Ch` viết `[[character-X]]` | `characters/X` thêm Ch vào `Key chapters` |
133
134
  | `chapters/Ch` viết `[[theme-Y]]` | `themes/Y` thêm Ch vào `Traced in` |
134
135
  {{/if}}
@@ -130,6 +130,7 @@
130
130
  | `concepts/K` 写 `[[source-E]]` | `sources/E` 将 K 追加到 `Related concepts` |
131
131
  | `summary/S` 写 `[[concept-K]]` | `concepts/K` 将 S 追加到 `Mentioned in` |
132
132
  {{#if pack_research}}| `topics/T` 写 `[[concept-K]]` | `concepts/K` 将 T 追加到 `Topics` |
133
+ | `topics/T` 写 `[[source-A]]` | `sources/A` 将 T 追加到 `Topics` |
133
134
  {{/if}}{{#if pack_reading}}| `chapters/Ch` 写 `[[character-X]]` | `characters/X` 将 Ch 追加到 `Key chapters` |
134
135
  | `chapters/Ch` 写 `[[theme-Y]]` | `themes/Y` 将 Ch 追加到 `Traced in` |
135
136
  {{/if}}