arreio 1.0.0-dev.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 (81) hide show
  1. package/README.md +81 -0
  2. package/package.json +42 -0
  3. package/scripts/postinstall.js +50 -0
  4. package/skills/arreio-init/SKILL.md +214 -0
  5. package/skills/arreio-init/references/architecture-template.md +85 -0
  6. package/skills/arreio-init/references/learn-index-template.md +15 -0
  7. package/skills/arreio-init/references/plan-index-template.md +29 -0
  8. package/skills/arreio-init/references/tasks-index-template.md +15 -0
  9. package/skills/learn/SKILL.md +151 -0
  10. package/skills/learn/modules/capture.md +108 -0
  11. package/skills/learn/modules/index.md +94 -0
  12. package/skills/learn/modules/maintain.md +116 -0
  13. package/skills/learn/modules/refine.md +104 -0
  14. package/skills/learn/references/dedup-rules.md +129 -0
  15. package/skills/learn/references/entry-schema.md +152 -0
  16. package/skills/learn/references/error-handling.md +178 -0
  17. package/skills/learn/references/id-generation.md +114 -0
  18. package/skills/learn/references/index-format.md +140 -0
  19. package/skills/learn/references/interaction-mode-propagation.md +89 -0
  20. package/skills/learn/references/migration-bootstrap.md +142 -0
  21. package/skills/learn/references/templates/artifacts/captured-entry.md +172 -0
  22. package/skills/learn/references/templates/artifacts/index-update.md +135 -0
  23. package/skills/learn/references/templates/artifacts/learn-input.md +100 -0
  24. package/skills/learn/references/templates/artifacts/maintain-log.md +142 -0
  25. package/skills/learn/references/templates/artifacts/refined-entry.md +168 -0
  26. package/skills/plan/SKILL.md +129 -0
  27. package/skills/plan/modules/design.md +140 -0
  28. package/skills/plan/modules/generate.md +156 -0
  29. package/skills/plan/modules/research.md +122 -0
  30. package/skills/plan/modules/scope.md +121 -0
  31. package/skills/plan/modules/tasks.md +190 -0
  32. package/skills/plan/references/design-complexity-assessment.md +118 -0
  33. package/skills/plan/references/error-handling.md +155 -0
  34. package/skills/plan/references/external-research-guidance.md +61 -0
  35. package/skills/plan/references/high-risk-detection.md +111 -0
  36. package/skills/plan/references/id-generation.md +55 -0
  37. package/skills/plan/references/interaction-mode-propagation.md +75 -0
  38. package/skills/plan/references/learnings-gate-logic.md +93 -0
  39. package/skills/plan/references/plan-tier-selection.md +174 -0
  40. package/skills/plan/references/task-slicing-rules.md +220 -0
  41. package/skills/plan/references/templates/artifacts/design.md +134 -0
  42. package/skills/plan/references/templates/artifacts/final-plan.md +265 -0
  43. package/skills/plan/references/templates/artifacts/research-findings.md +50 -0
  44. package/skills/plan/references/templates/artifacts/scoped-context.md +53 -0
  45. package/skills/plan/references/templates/artifacts/task.md +192 -0
  46. package/skills/plan/references/templates/artifacts/user-input.md +112 -0
  47. package/skills/review/SKILL.md +163 -0
  48. package/skills/review/modules/analyze.md +104 -0
  49. package/skills/review/modules/prepare.md +103 -0
  50. package/skills/review/modules/report.md +109 -0
  51. package/skills/review/modules/scope.md +126 -0
  52. package/skills/review/references/approval-criteria.md +101 -0
  53. package/skills/review/references/change-set-resolution.md +126 -0
  54. package/skills/review/references/error-handling.md +172 -0
  55. package/skills/review/references/id-generation.md +80 -0
  56. package/skills/review/references/interaction-mode-propagation.md +80 -0
  57. package/skills/review/references/review-categories.md +124 -0
  58. package/skills/review/references/scope-creep-detection.md +120 -0
  59. package/skills/review/references/severity-rubric.md +107 -0
  60. package/skills/review/references/templates/artifacts/findings.md +161 -0
  61. package/skills/review/references/templates/artifacts/review-input.md +116 -0
  62. package/skills/review/references/templates/artifacts/review-kit.md +135 -0
  63. package/skills/review/references/templates/artifacts/review-report.md +175 -0
  64. package/skills/review/references/templates/artifacts/review-scope.md +146 -0
  65. package/skills/work/SKILL.md +163 -0
  66. package/skills/work/modules/execute.md +109 -0
  67. package/skills/work/modules/prepare.md +140 -0
  68. package/skills/work/modules/review.md +164 -0
  69. package/skills/work/modules/triage.md +181 -0
  70. package/skills/work/references/ad-hoc-input-resolution.md +122 -0
  71. package/skills/work/references/error-handling.md +183 -0
  72. package/skills/work/references/execution-mode-selection.md +95 -0
  73. package/skills/work/references/id-generation.md +85 -0
  74. package/skills/work/references/interaction-mode-propagation.md +80 -0
  75. package/skills/work/references/review-checklist.md +94 -0
  76. package/skills/work/references/task-execution-rules.md +116 -0
  77. package/skills/work/references/templates/artifacts/execution-log.md +123 -0
  78. package/skills/work/references/templates/artifacts/execution-plan.md +111 -0
  79. package/skills/work/references/templates/artifacts/work-input.md +78 -0
  80. package/skills/work/references/templates/artifacts/work-manifest.md +119 -0
  81. package/skills/work/references/templates/artifacts/work-report.md +143 -0
@@ -0,0 +1,129 @@
1
+ ---
2
+ title: Dedup Rules
3
+ description: Authoritative reference for Refine (per-entry dup/analog check) and Maintain (base-wide dedup). Defines what counts as an exact duplicate vs an analog (clearly distinct from exact), the matching signals, the resolution options (update-existing / new-slug / merge-into-canonical / keep-separate), and the lineage-preserving merge procedure — de-index the analog, keep its file with superseded-by, never delete.
4
+ type: reference
5
+ version: 1.0
6
+ timestamp: "2026-08-08"
7
+ ---
8
+
9
+ # Dedup Rules
10
+
11
+ Authoritative reference for the **Refine** phase (per-entry duplicate+analog check) and the **Maintain** phase (base-wide dedup). Defines what counts as an **exact duplicate** vs an **analog** (a distinct category), the matching signals, the resolution options, and the **lineage-preserving merge procedure** — de-index the analog, keep its file with a `superseded-by` note, never delete. Refine and Maintain apply this reference; they do not re-encode it.
12
+
13
+ ## Core Principle
14
+
15
+ > **Decisions don't duplicate, but analogs exist.** An exact duplicate (same `slug`) means a re-author; the user updates the existing entry or picks a new `slug`. An analog (same conclusion about the same domain, different `slug`) is a dedup candidate: merging the analog into the canonical entry **preserves lineage** — the analog is de-indexed (its index record removed, its file kept with a `superseded-by` note), never deleted. This is why dedup **merges**, never **deletes**: knowledge is rarely destroyed, it is superseded and absorbed. The `path-convention-split` gotcha is the model — a merged/migrated entry carries both the old and new knowledge, not just the new.
16
+
17
+ ## Matching Categories
18
+
19
+ | Match | Definition | Detection signals (authoritative) |
20
+ | ---------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------- |
21
+ | `exact` | An existing entry with the same `slug` (case-insensitive, hyphen-normalized), or the same canonicalized title. | Identical `slug`; or kebab-case(title) matches slug. |
22
+ | `analog` | An existing entry addressing the **same conclusion** on the **same domain** with overlapping `tags`, under a different `slug`. | Same `domain` + ≥2 overlapping `tags` + same `type` + semantically same Problem/Solution. |
23
+ | `insignificant` | Loose/distant matches: same `domain` only, or one overlapping tag, or a different `type` on a related topic. | Same `domain` with ≤1 overlapping `tags`; or different `type` (a decision about caching is not an analog of a gotcha about caching). |
24
+
25
+ **The matching algorithm** (run by Refine on the new draft; by Maintain on all pairs):
26
+
27
+ ```
28
+ 1. Canonicalize the candidate's slug and title (kebab-case, lowercase, hyphen-collapsed).
29
+ 2. For each existing entry in docs/learn/<type>/ (and cross-type — slug namespace is global):
30
+ - if slug matches (hyphen-normalized, case-insensitive) -> EXACT
31
+ 3. Else, for each existing entry:
32
+ - compute overlap: domain-strict-match + (shared-tags count) + same-type
33
+ - if same domain AND >=2 shared tags AND same type:
34
+ read both bodies' Problem/Solution; if semantically the same conclusion -> ANALOG
35
+ - else -> INSIGNIFICANT (ignore; not a dedup candidate)
36
+ 4. Record the matches with evidence (the shared signals + the matched slug).
37
+ ```
38
+
39
+ Only `exact` and `analogs` surface for resolution; `insignificant` matches are ignored (no dedup, no pause).
40
+
41
+ ## Resolution Options (the user picks)
42
+
43
+ ### exact
44
+
45
+ A re-author of the same `slug`. Two options:
46
+
47
+ | Option | Action |
48
+ | ----------------- | --------------------------------------------------------------------------------------------- |
49
+ | **update-existing** | Overwrite the existing entry file at `docs/learn/<type>/<slug>.md` with the refined content; upsert its index record (idempotent on `slug`); bump `updated_at`. The canonical way to revise a decision. |
50
+ | **new-slug** | Pick a different `slug` for the draft (e.g., append `-v2` or a domain qualifier); both entries coexist. Use when the new draft is a genuinely different decision that happened to share a slug by coincidence. |
51
+
52
+ ### analog
53
+
54
+ A same-conclusion, same-domain entry under a different `slug`. Two options:
55
+
56
+ | Option | Action |
57
+ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
58
+ | **merge-into-canonical** | Fold the draft's evidence into the matched canonical entry (append/consolidate the body; add the draft's tags; bump `updated_at`). The canonical `slug` stays. The draft (or, in Maintain, the analog) keeps its **file** with `superseded-by: <canonical-slug>` added and its index record **removed** (de-indexed, not deleted). The canonical entry's `related` list records the analog's `slug`. This is the lineage-preserving merge. |
59
+ | **keep-separate** | Keep the draft as its own entry under the proposed `slug`. Use when the analog is genuinely a different angle (e.g., a cache-invalidation decision and a separate cache-key-naming decision that share `domain + 2 tags` but resolve different problems). |
60
+
61
+ ### none
62
+
63
+ Proceed — a genuine new entry. No resolution.
64
+
65
+ ## Lineage-Preserving Merge Procedure (authoritative)
66
+
67
+ On a `merge-into-canonical` resolution, Index (for a Refine-time merge) or Maintain (for a base-wide merge) executes:
68
+
69
+ ```
70
+ 1. Pick the canonical slug:
71
+ - Prefer the older entry (earlier created_at)
72
+ - On tie, prefer the higher-priority
73
+ - On tie, prefer the existing entry (keep the in-place one canonical)
74
+ 2. Fold the analog's body into the canonical:
75
+ - Append the analog's Problem paragraph (or merge into the canonical's Problem if clearer)
76
+ - Append the analog's Solution/example
77
+ - Append the analog's tags (union into the canonical's tags; cap at 6; if union exceeds 6, keep the top-6 by domain-relevance, log the trim)
78
+ - Bump the canonical's updated_at
79
+ 3. Mark the analog (de-index, keep file):
80
+ - In the analog's frontmatter, add `superseded-by: <canonical-slug>` and `status: obsolete`
81
+ - Do NOT delete the analog's file
82
+ - Remove the analog's record from docs/learn/index.md (YAML block + By Category / By Domain tables)
83
+ 4. Link the canonical:
84
+ - Add the analog's slug to the canonical's `related` list (the lineage link)
85
+ - The canonical's index record now reflects the merged content (richer body; same or expanded tags)
86
+ 5. Record the merge in the artifact (Refine's lineage field / Maintain's merges list):
87
+ merge: <analog-slug> -> <canonical-slug>
88
+ ```
89
+
90
+ **Why de-index and not delete:** the analog's file may be referenced by a `related` link in another entry, or by external docs/commits. Deleting its file would orphan those links. De-indexing keeps the file reachable (the `superseded-by` note redirects readers to the canonical) and the canonical's `related` link proves the absorption. The analog's content is **not** lost — it lives in its file, superseded, plus absorbed into the canonical.
91
+
92
+ ## Refine vs Maintain Scope
93
+
94
+ | Phase | Scope of dedup | When |
95
+ | -------- | ---------------------------------------------------------------- | -------------------------------------------------------------------- |
96
+ | Refine | The **one** draft against all existing entries (per-entry) | Every authoring run (`/learn <type> <text>` or candidate curation) |
97
+ | Maintain | **All** pairs in the canonical store (base-wide) | On-demand (`/learn maintain`), after the migration step |
98
+
99
+ Refine catches duplicates at author-time (prevents creating a duplicate). Maintain catches **inter-existing** analogs across an already-built store (the store may have accumulated analogs from many separate runs). Both use the same matching algorithm and the same resolution options above.
100
+
101
+ ## Smart Pause Triggers
102
+
103
+ Dedup operations are destructive (a merge de-indexes an analog; a slug collision forces a choice). They pause in Smart mode and **always surface in Autopilot** (per [interaction-mode-propagation.md](interaction-mode-propagation.md) — destructive ops never silent):
104
+
105
+ - Refine: `dup-status: exact` (update vs new-slug) or `dup-status: analog` (merge vs keep).
106
+ - Maintain: any analog pair found in the base-wide scan (merge vs keep, per pair).
107
+
108
+ ## Edge Cases
109
+
110
+ | Scenario | Resolution |
111
+ | ----------------------------------------------------------------------- | ----------------------------------------------------------------------- |
112
+ | Analog pair but different `type` (e.g., a `decision` and a `gotcha` on caching) | **Not an analog** — different `type` blocks the analog match (a decision is not a gotcha). Keep separate. |
113
+ | Two entries with the same `slug` already on disk (corrupt store) | Maintain flags both; the user picks the canonical; the other renames. Index reconciliation detects the duplicate row. |
114
+ | An analog referenced in another entry's `related` list | Still merge — but the canonical's `related` now points to the analog's old slug; readers follow the analog's `superseded-by` to the canonical. No orphan. |
115
+ | Merge would push the canonical's `tags` over 6 | Trim to top-6 by domain-relevance; log the trim; the analog's tags are noted in the body. |
116
+ | The canonical entry is itself `obsolete` | Do not merge into an obsolete entry; surface to user — likely the analog is the live one; reverse the canonical choice. |
117
+
118
+ ## Validation (Refine Step 3 / Maintain Step 2 re-checks)
119
+
120
+ - A match was recorded for every same-slug / same-domain-overlapping pair (no silent matches).
121
+ - A `merge-into-canonical` always sets `superseded-by` on the analog and adds the analog's slug to the canonical's `related` (lineage preserved both ways).
122
+ - No analog file was deleted on a merge (only de-indexed).
123
+ - The matched evidence is recorded (`slug` + the shared signals) so the user can confirm the match is real, not a false positive.
124
+
125
+ ## Notes
126
+
127
+ - This reference is the single source of truth for the matching algorithm, the resolution options, and the lineage-preserving merge procedure. Refine and Maintain apply it; the modules never re-encode the matching signals inline.
128
+ - **Decisions-not-logs** is honored: dedup operates on durable knowledge entries, never on session records. Two analogs reached the store because they were authored at different times as separate conclusions; merging absorbs them as one durable conclusion with lineage.
129
+ - The `keep-separate` option is a first-class choice: analogs that resolve *different* problems should stay separate even when they share a domain and tags. Refine/Maintain's job is to surface the candidate, not to auto-merge.
@@ -0,0 +1,152 @@
1
+ ---
2
+ title: Entry Schema
3
+ description: Authoritative write-contract reference for Capture (drafts) and Refine (validates). Defines the canonical per-entry frontmatter (the unified schema the legacy decision+pattern entries converged to), the per-type body section templates, and the index-record shape that the read side (Plan/Work/Review's learnings-gate-logic) parses. Single source of truth for the entry's shape.
4
+ type: reference
5
+ version: 1.0
6
+ timestamp: "2026-08-08"
7
+ ---
8
+
9
+ # Entry Schema
10
+
11
+ Authoritative **write contract** for a knowledge entry. Capture drafts the frontmatter and body from this schema; Refine validates against it; Index derives the index-record enum from it; Maintain refreshes stale entries to it. The schema unifies the two historical layouts observed in the legacy store (the newer `decision`/`gotcha` layout with `slug`+`priority`+`applicability`+`confidence`, and the older `pattern`/`workflow` layout with `title`+`category`+`severity`) into one canonical form. Capture/Refine **look this schema up**; they do not re-encode the field list.
12
+
13
+ > **Write side / read side (single source of truth).** This reference owns the **write side** — the per-entry frontmatter and the `index-record` shape. The Plan skill owns the **read side** — the search algorithm in [learnings-gate-logic.md](../../plan/references/learnings-gate-logic.md). The two contracts share the **index-record shape** (`filename`, `domain`, `tags`, `applicability`, `summary`). Capturing this schema here, once, prevents the secondary-spec-contradicts-authoritative-matrix gotcha: no other reference re-encodes the entry's fields.
14
+
15
+ ## The Four Entry Types
16
+
17
+ | Type | Carries | Section template (body) |
18
+ | ---------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
19
+ | `decision` | An authoritative choice with rationale | Problem / Solution / Decision Rationale / Application / Related Learnings |
20
+ | `pattern` | A confirmed, reusable approach | Problem / Pattern / When to Apply / Example / Related Learnings |
21
+ | `gotcha` | A recurring trap with prevention | Problem / Trap / Solution / Prevention / Related Learnings / Source |
22
+ | `workflow` | A project convention | Convention / Why / How / Related Learnings |
23
+
24
+ Each entry is **exactly one** conclusion; one entry per conclusion; never a bundle.
25
+
26
+ ## Per-Entry Frontmatter (canonical, unified)
27
+
28
+ ```yaml
29
+ ---
30
+ slug: <kebab-case-slug> # REQUIRED. Globally unique. The upsert key for the entry file + index record.
31
+ type: decision | pattern | gotcha | workflow # REQUIRED. One of the four.
32
+ domain: <primary-domain> # REQUIRED. A single primary domain.
33
+ priority: important | normal # OPTIONAL (default normal).
34
+ applicability: # REQUIRED. Numeric scores per side.
35
+ current_project: <0-10> # How directly the project uses this.
36
+ general: <0-10> # How broadly it generalizes.
37
+ tags: [<related-domain-1>, ...] # REQUIRED. 2-6 related domains.
38
+ created_at: <ISO-8601> # REQUIRED. Set by Capture; Refine preserves.
39
+ updated_at: <ISO-8601> # REQUIRED. Stamped on any edit (Refine/Index/Maintain).
40
+ source: # REQUIRED. Where the entry came from.
41
+ type: commit | candidate | user # commit: derived from a commit; candidate: from Work/Review; user: freeform author.
42
+ reference: <commit-sha | report-id#finding-id | text> # The locator.
43
+ extracted_at: <ISO-8601> # When the entry was captured.
44
+ confidence: high | medium | low # OPTIONAL (default medium). The author's confidence.
45
+ # Lineage (set by Maintain / migration, optional):
46
+ migrated-from: <docs/learnings/<type>/<file>.md> # Only for a migrated legacy entry.
47
+ superseded-by: <canonical-slug> # Only for an analog merged into a canonical entry.
48
+ status: active | obsolete # OPTIONAL (default active). `obsolete` de-indexes the entry.
49
+ related: [<slug>, ...] # OPTIONAL. Linked entries (a canonical entry lists the analogs it absorbed).
50
+ ---
51
+ ```
52
+
53
+ **Field rules (authoritative):**
54
+
55
+ - `slug` — kebab-case; globally unique across all four types (one slug namespace); descriptive (date suffix allowed for time-bound decisions). Capture proposes; Refine uniqueness-checks; Index upserts on it.
56
+ - `type` — one of the four; the body section template is determined by it (see above). Type does not change after authoring (a `decision` may not be reclassified as a `pattern` post-hoc — that's a new entry with a new `slug`, and the old one de-indexes).
57
+ - `domain` — a single primary domain (never a list); the `tags` carry the related domains.
58
+ - `priority` — `important` for entries that block or strongly steer a skill; `normal` otherwise. Defaults to `normal` when absent.
59
+ - `applicability.current_project` / `general` — integers 0–10. The **write side** stores the rich numerics; the **read side** projects to the enum (see [index-format.md](index-format.md)).
60
+ - `tags` — a list of **2–6** related domains (no more, no fewer; Refine validates the count).
61
+ - `confidence` — `high` / `medium` / `low`; defaults to `medium` when absent.
62
+ - `source.type` — `commit` (derived from a commit sha), `candidate` (from a Work/Review `learnings-to-capture` list), or `user` (freeform `/learn <type> <text>`).
63
+ - `migrated-from` / `superseded-by` / `related` — lineage fields set by Maintain (or Index on a merge), not by Capture. See [dedup-rules.md](dedup-rules.md) and [migration-bootstrap.md](migration-bootstrap.md).
64
+
65
+ ## Per-Type Body Section Templates (authoritative)
66
+
67
+ A `decision` body has exactly these sections (in order); body sections are validated by Refine:
68
+
69
+ ### decision
70
+ ```
71
+ # <Title in Title Case>
72
+
73
+ ## Problem [what problem this decision resolves]
74
+ ## Solution [the decision — what was chosen]
75
+ ## Decision Rationale [why this choice over alternatives]
76
+ ## Application [where in the project this decision lives — files, skills, phases]
77
+ ## Related Learnings [linked slug(s) + one-line role]
78
+ ```
79
+
80
+ ### pattern
81
+ ```
82
+ # <Title in Title Case>
83
+
84
+ ## Problem [the recurring problem the pattern solves]
85
+ ## Pattern [the confirmed approach]
86
+ ## When to Apply [signals that this pattern fits]
87
+ ## Example [a concrete use of the pattern, ideally in-repo]
88
+ ## Related Learnings [linked slug(s) + one-line role]
89
+ ```
90
+
91
+ ### gotcha
92
+ ```
93
+ # <Title in Title Case>
94
+
95
+ ## Problem [the surface symptom]
96
+ ## Trap [the silent failure mode]
97
+ ## Solution [how to fix it once hit]
98
+ ## Prevention [how to avoid it next time — the durable part]
99
+ ## Related Learnings [linked slug(s) + one-line role]
100
+ ## Source [file/commit/ref where this was confirmed — optional duplicate of frontmatter.source for human readability]
101
+ ```
102
+
103
+ ### workflow
104
+ ```
105
+ # <Title in Title Case>
106
+
107
+ ## Convention [the agreed-upon practice]
108
+ ## Why [the reason for the convention]
109
+ ## How [the steps to apply it — concrete, repo-relative]
110
+ ## Related Learnings [linked slug(s) + one-line role]
111
+ ```
112
+
113
+ ## Index-Record Shape (the read-contract projection)
114
+
115
+ `docs/learn/index.md` carries one record per entry in its YAML `entries:` block (format in [index-format.md](index-format.md)). That record projects the full frontmatter to the **five fields** the read side parses:
116
+
117
+ ```yaml
118
+ - filename: docs/learn/<type>/<slug>.md
119
+ domain: <primary-domain>
120
+ tags: [tag-1, tag-2]
121
+ applicability: DIRECT | RECOMMENDED | CONTEXTUAL | HISTORICAL | INFORMATIONAL
122
+ summary: <1-2 sentence summary — derived from the entry's Problem/Solution>
123
+ ```
124
+
125
+ The `applicability` enum is **derived** from the frontmatter's numeric scores per [index-format.md](index-format.md)'s derivation — never stored twice. The `summary` is the frontmatter's `summary` if present, else the first 1–2 sentences of the entry's Problem/Solution paragraphs. **Field set is fixed**: `filename`, `domain`, `tags`, `applicability`, `summary` — exactly these five (the gate-logic's read contract).
126
+
127
+ > Note: the canonical frontmatter above does **not** include a `summary` field. Capture/Refine derive the index `summary` from the entry's Problem/Solution body by default; a user may add a `summary` frontmatter field to override. Either way, the index-record carries the `summary`. (Adding `summary` to the frontmatter block above is a non-destructive optional extension; the body sections remain the source of truth by default.)
128
+
129
+ ## Validation Rules (Refine applies)
130
+
131
+ 1. **Frontmatter:** all REQUIRED fields present and well-typed; `type` ∈ the four; `domain` non-empty; `tags` length 2–6; `applicability` scores integers 0–10; `confidence` ∈ enum; `slug` kebab-case.
132
+ 2. **Body:** the per-type section template present (all the sections for the type); no extra top-level sections that contradict the template.
133
+ 3. **Coherence:** the body title's kebab-case matches the `slug`; the frontmatter `domain` is among the `tags`; the index-record projection (filename/domain/tags/applicability/summary) is computable from the entry.
134
+ 4. **On a missing `summary` field:** derive from the body; do not block. On a wrong type/wrong shape: block and ask (Category 2 recovery).
135
+
136
+ ## Migration (legacy → canonical)
137
+
138
+ Legacy entries use one of two prior layouts; the migration ([migration-bootstrap.md](migration-bootstrap.md)) normalizes both to the canonical schema:
139
+
140
+ | Legacy layout | Fields present | Canonical conversion |
141
+ | ------------- | -------------- | -------------------- |
142
+ | Newer (decision/gotcha) | `slug`, `type`, `domain`, `priority`, `applicability.{current_project,general}`, `tags`, `confidence` | Already canonical; preserve; add `migrated-from` lineage. |
143
+ | Older (pattern/workflow) | `title`, `category`, `severity`, `domain`, `tags`, `source: commit <sha>` | Convert: `type = category` (the legacy `category` field); `slug = <kebab-case-of-title>[-<date>]`; `priority = important if severity==important else normal`; `applicability.{current_project,general}` inferred from `severity` (`important`→{9,7}, `recommended`→{6,5}, `informational`→{3,4}); `confidence = medium`; restructure `source` to `{type: commit, reference: <sha>, extracted_at: <date>}`. Add `migrated-from`. |
144
+
145
+ The conversion **preserves content** — the body sections are kept, frontmatter is normalized, lineage is recorded. No legacy entry is silently dropped; no canonical field is invented where the legacy had no basis (an inferred score from `severity` is noted as inferred, never silently exact).
146
+
147
+ ## Notes
148
+
149
+ - This reference is the single source of truth for the entry's shape. Capture drafts from it; Refine validates against it; Index projects to the index-record from it; Maintain refreshes to it. None re-encode the field list or body templates inline.
150
+ - The schema deliberately separates the **write side** (rich numeric `applicability` + `confidence` + lineage) from the **read side** (the enum projection in the index-record). This honors the secondary-spec gotcha: the search algorithm lives once in Plan's gate-logic; the entry schema lives once here.
151
+ - A `summary` field is **optional** in the frontmatter (overriding the body-derived default); the index-record always carries a `summary`.
152
+ - Changing an entry's `type` post-hoc is a **new entry** (new `slug`), and the old entry de-indexes — never an in-place reclassification (a decision is a decision; a pattern is a pattern).
@@ -0,0 +1,178 @@
1
+ ---
2
+ title: Error Handling & Recovery
3
+ description: Reference for all Learn Skill phases (Capture, Refine, Index, Maintain). Defines the Step 0 artifact verification procedure, per-type required fields, error categories, recovery workflow, retry limits, and cross-phase consistency checks. Applies to durable knowledge curation, not transient sessions.
4
+ type: reference
5
+ version: 1.0
6
+ timestamp: "2026-08-08"
7
+ ---
8
+
9
+ # Error Handling & Recovery
10
+
11
+ This file documents the error handling and recovery strategies shared across all Learn Skill phases (Capture, Refine, Index, Maintain). Each phase begins with a **Step 0: Verification** that validates the incoming artifact; this reference defines the validation rules, recovery actions, and termination conditions.
12
+
13
+ ## Core Principle
14
+
15
+ **Fail explicitly, never silently.** When an artifact is missing, malformed, or inconsistent, the phase must surface a clear error with a recovery suggestion rather than guessing or proceeding with bad data. Silent failures corrupt the canonical knowledge base — a wrong `slug` collision, a silently coerced field, or a skipped duplicate check cascades into a polluted index that Plan/Work/Review then read as source of truth. The one recognized non-block is a **missing `docs/learn/` store entirely** (the Orchestrator's Pre-Flight seeds it), and a **no-op maintain step** (e.g. migration when already migrated, or no analogs to merge) which records `no-op` and proceeds — these are deliberate non-blocks with explicit notes, not silent skips.
16
+
17
+ ## Step 0: Artifact Verification
18
+
19
+ Every phase receives an artifact from the previous phase (or the Orchestrator, for Capture). Step 0 validates the artifact before any work begins.
20
+
21
+ ### Verification Procedure
22
+
23
+ ```
24
+ 1. Confirm the artifact exists and is non-empty
25
+ 2. Confirm the required frontmatter fields are present and well-formed
26
+ 3. Confirm the artifact type matches the expected phase input
27
+ 4. Confirm interactionMode is present and valid (default to "smart" if missing)
28
+ 5. Confirm cross-phase IDs match the upstream artifacts
29
+ 6. Confirm routing: a "maintain" shape must not reach Capture/Refine/Index; an authoring shape must not reach Maintain
30
+ ```
31
+
32
+ ### Required Fields by Artifact Type
33
+
34
+ | Artifact Type | Required Fields | Produced By |
35
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
36
+ | `learn-input` | `type`, `timestamp`, `source`, `status`, input shape (`explicit: {type, text}` **or** `candidate: {ref}` **or** `maintain: true`), `interactionMode` | Orchestrator |
37
+ | `captured-entry` | `capture-id`, `learn-id`, `input-shape`, `status`, `interactionMode`, `target-type` (one of the four), proposed `slug`, drafted `frontmatter`, drafted `body`, `source-candidate` | Capture |
38
+ | `refined-entry` | `refine-id`, `capture-id`, `learn-id`, `input-shape`, `status`, `interactionMode`, validated `type`, resolved `slug`, validated `frontmatter`/`body`, `dup-status`, `resolution` | Refine |
39
+ | `index-update` | `index-id`, `refine-id`, `capture-id`, `learn-id`, `input-shape`, `status`, `interactionMode`, `entry-path`, `slug`, `type`, `index-applicability`, `index-action`, `index-coherent` | Index |
40
+ | `maintain-log` | `maintain-id`, `interactionMode`, `status`, `migration`, `merges`, `refresh`, `prune`, `rebuild`, `index-coherent` (no `learn-id` umbrella — Maintain authors no new entry) | Maintain |
41
+
42
+ ## Error Categories
43
+
44
+ ### Category 1: Missing Artifact
45
+
46
+ The expected input artifact was not provided by the Orchestrator or previous phase.
47
+
48
+ | Trigger | Recovery Action | Terminate? |
49
+ | --------------------------------- | ------------------------------------------------------------- | ------------------ |
50
+ | Artifact object is null/undefined | Ask Orchestrator to re-run previous phase | Yes, after 1 retry |
51
+ | Artifact file path does not exist | Log warning; ask user to locate file or re-run previous phase | No |
52
+ | Artifact file is empty (0 bytes) | Re-run previous phase from its saved context | Yes, after 1 retry |
53
+
54
+ ### Category 2: Malformed Artifact
55
+
56
+ The artifact exists but is missing required fields or has invalid structure.
57
+
58
+ | Trigger | Recovery Action | Terminate? |
59
+ | --------------------------------------------- | ----------------------------------------------------------- | ---------- |
60
+ | Missing required frontmatter field | Re-run previous phase to regenerate artifact | No |
61
+ | `interactionMode` missing or invalid | Default to `smart`; log warning; continue | No |
62
+ | `status` field is `failed` or `pending` | Reject; ask Orchestrator to re-run previous phase | Yes |
63
+ | Artifact `type` does not match expected input | Reject; ask Orchestrator to check phase ordering | Yes |
64
+ | YAML frontmatter has syntax errors | Log error with line number; ask user to fix or re-run phase | No |
65
+ | Routing: `maintain` reached Capture/Refine/Index | Reject; Orchestrator routes maintain directly to Maintain | Yes |
66
+ | Routing: authoring shape reached Maintain | Reject; Orchestrator should route to Capture | Yes |
67
+ | Target-type not one of the four (Capture Step 1) | Ask user to pick from `decision`/`pattern`/`gotcha`/`workflow` | No |
68
+
69
+ ### Category 3: Invalid Learn Input
70
+
71
+ Only applies to the Capture phase (Step 0) when resolving a Learn Input Artifact.
72
+
73
+ | Trigger | Recovery Action | Terminate? |
74
+ | ---------------------------------------------------- | --------------------------------------------------------- | ---------- |
75
+ | All three input shapes empty or ambiguous | Ask: "What would you like to capture? Type + text, candidate ref, or `maintain`." | No |
76
+ | Explicit `<type>` not one of the four | Ask the user to pick from the four | No |
77
+ | Explicit `<text>` is a bare ref that cannot be read (file/commit) | Ask the user to supply the decision in prose | No |
78
+ | Candidate `ref` does not resolve to a report file | Ask the user to pick a valid Work `review-id` / Review `report-id` | No |
79
+ | Candidate report's `learnings-to-capture` list is empty | Inform the user (no candidates to curate); stop | No |
80
+ | Maintain requested but `docs/learn/` and `docs/learnings/` are both absent | Inform the user; the store must exist (or legacy) before a maintain | No |
81
+
82
+ ### Category 4: File System Errors
83
+
84
+ Errors encountered while saving or reading entry/index files.
85
+
86
+ | Trigger | Recovery Action | Terminate? |
87
+ | ------------------------------------------------ | ----------------------------------------------------------------- | ------------------ |
88
+ | `docs/learn/` does not exist | Create it (Orchestrator Pre-Flight creates; Index creates `<type>/` subdir); continue | No |
89
+ | `docs/learn/index.md` does not exist | Seed it from [index-format.md](index-format.md) (YAML block + tables headers); continue | No |
90
+ | Phase save directory does not exist | Create it; treat counter as 0; start from 001 (Pre-Flight creates) | No |
91
+ | Counter directory exists but no files match date | Start counter at 001 | No |
92
+ | File write permission denied | Log error; ask user to check permissions; retry once | Yes, after 1 retry |
93
+ | De-indexing an analog whose canonical entry is itself absent | Log; revert the merge; ask the user (the lineage link is broken) | No |
94
+
95
+ ### Category 5: Interaction Mode Errors
96
+
97
+ Errors related to `interactionMode` propagation.
98
+
99
+ | Trigger | Recovery Action | Terminate? |
100
+ | ---------------------------------------- | ---------------------------------------------------------- | ---------- |
101
+ | Mode missing from incoming artifact | Default to "smart"; log warning; continue | No |
102
+ | Mode value is not in enum | Reject; re-prompt Orchestrator to set valid mode | Yes |
103
+ | User selects "Abort" during confirmation | Stop immediately; inform Orchestrator of abort with reason | Yes |
104
+ | User does not respond (timeout) | Pause; ask user to retry or abort | No |
105
+
106
+ ### Category 6: Curation Errors (Refine / Index / Maintain)
107
+
108
+ | Trigger | Recovery Action | Terminate? |
109
+ | ---------------------------------------------------- | ------------------------------------------------------------------ | ---------- |
110
+ | Refine: a required body section is missing | Ask the user to add it (never auto-fill silently) | No |
111
+ | Refine: a frontmatter field has a wrong type/value | Surface the field, suggest the fix, ask the user; never coerce | No |
112
+ | Refine: exact `slug` found (a re-author) | Smart pause: update-existing vs new-slug; never silently two | No |
113
+ | Index: `index-coherent: false` after the upsert | Reconcile (the file tree is source of truth); warn; suggest `/learn maintain` | No |
114
+ | Maintain: a prune candidate's canonical reference is live in `related` | Do not prune; it is referenced (lineage would break) — surface to user | No |
115
+ | Maintain: rebuild left `index-coherent: false` | Re-run Step 5 (the rebuild); if still failing, terminate | Yes, after 1 retry |
116
+
117
+ ## Recovery Workflow
118
+
119
+ When a verification failure is detected in Step 0, apply this workflow:
120
+
121
+ ```
122
+ 1. Identify the error category (1-6) from the tables above
123
+ 2. Look up the specific trigger to find the recovery action
124
+ 3. Execute the recovery action:
125
+ - If recovery is "ask user": ask one question with clear options (2-4 concrete choices)
126
+ - If recovery is "re-run previous phase": return to Orchestrator with error context
127
+ - If recovery is "default and continue": apply default, log warning, proceed
128
+ 4. If terminate = Yes: stop and inform Orchestrator with:
129
+ - Error category and trigger
130
+ - Recovery action attempted
131
+ - Reason for termination
132
+ 5. If terminate = No: after recovery, continue to Step 1 of the phase
133
+ ```
134
+
135
+ ## Retry Limits
136
+
137
+ - **Maximum retries per error:** 1
138
+ - **Maximum total retries per phase:** 2
139
+ - After exhausting phase retries, terminate with a clear error suggesting the user re-run the Learn run from the start or resume from the last complete phase.
140
+
141
+ > An authoring run (`/learn <type> <text>`) is **not resume-safe**: re-running over the same content upserts on `slug` (idempotent — better than resuming). A maintain run is idempotent and self-gating (the migration is one-time, no-op thereafter).
142
+
143
+ ## Error Reporting Format
144
+
145
+ When reporting an error to the Orchestrator or user, use this format:
146
+
147
+ ```yaml
148
+ error:
149
+ phase: capture | refine | index | maintain
150
+ step: 0 | 1 | 2 | ...
151
+ category: 1 | 2 | 3 | 4 | 5 | 6
152
+ trigger: "[specific trigger description]"
153
+ recovery_attempted: "[action taken]"
154
+ outcome: recovered | terminated
155
+ suggestion: "[next step for the user or Orchestrator]"
156
+ ```
157
+
158
+ ## Cross-Phase Consistency Checks
159
+
160
+ The Orchestrator should verify consistency between phases:
161
+
162
+ | Check | Action on Failure |
163
+ | --------------------------------------------------------------------- | ------------------------------------------- |
164
+ | `learn-id` in downstream artifact matches the Capture output | Reject; re-run from Capture |
165
+ | `capture-id` in Refine+ matches Capture output | Reject; re-run from Capture |
166
+ | `refine-id` in Index matches Refine output | Reject; re-run from Refine |
167
+ | `interactionMode` is identical across all artifacts | Log warning; use earliest non-default value |
168
+ | `maintain-id` standalone (no `learn-id` expected for a maintain run) | If a `learn-id` is present on a maintain artifact, log warning; treat as orphan |
169
+ | Routing: authoring shape produces Capture→Refine→Index; `maintain` shape produces only Maintain | Reject; surface routing bug |
170
+
171
+ ## Notes
172
+
173
+ - All errors and warnings should be logged with a timestamp for debugging.
174
+ - When a phase terminates, its saved artifact (if any) should be marked `status: failed`.
175
+ - The Orchestrator is responsible for deciding whether to retry the entire workflow or resume from the last successful phase.
176
+ - ID assignment and re-use (including recycle-on-edit) is defined in [id-generation.md](id-generation.md); this reference covers only verification and recovery.
177
+ - The per-entry frontmatter schema (the write contract) is defined in [entry-schema.md](entry-schema.md); the index format is defined in [index-format.md](index-format.md); the duplicate/merge logic is defined in [dedup-rules.md](dedup-rules.md); the one-time migration is defined in [migration-bootstrap.md](migration-bootstrap.md). This reference covers only verification/recovery and never re-encodes those contracts.
178
+ - This reference is shared by all four phases; phase-specific handling is documented inline in the respective module.
@@ -0,0 +1,114 @@
1
+ ---
2
+ title: Artifact ID Generation
3
+ description: Reference for Capture, Refine, Index, and Maintain phases. Defines the daily-counter algorithm for unique phase artifacts, the learn-id umbrella allocation, the maintain-id standalone allocation (no learn-id), the entry slug derivation, and the recycle-on-edit rule.
4
+ type: reference
5
+ version: 1.0
6
+ timestamp: "2026-08-08"
7
+ ---
8
+
9
+ # Artifact ID Generation
10
+
11
+ Shared ID algorithm for the `capture`, `refine`, `index`, and `maintain` phases, plus the `learn-id` umbrella (Capture is the allocating phase), the `maintain-id` standalone allocation, and the **entry `slug`** derivation (the upsert key for the entry file and the index record). Each phase assigns exactly one ID per newly produced artifact; the ID is reused (never re-incremented) when the user picks **Edit & Retry** at the phase confirmation.
12
+
13
+ ## ID Format by Phase
14
+
15
+ | Phase | ID format | Saved to |
16
+ | -------- | ----------------------------------- | ----------------------------------- |
17
+ | Capture | `YYYY-MM-DD-NNN-capture` | `docs/plans/.learn/.capture/<id>.md` |
18
+ | Refine | `YYYY-MM-DD-NNN-refine` | `docs/plans/.learn/.refine/<id>.md` |
19
+ | Index | `YYYY-MM-DD-NNN-index` | `docs/plans/.learn/.index/<id>.md` |
20
+ | Maintain | `YYYY-MM-DD-NNN-maintain` | `docs/plans/.learn/.maintain/<id>.md` |
21
+
22
+ `learn-id` (see below) is the umbrella shared across Capture → Refine → Index. **Maintain has no `learn-id`** — it authors no new entry; it allocates only a standalone `maintain-id`.
23
+
24
+ ## learn-id (umbrella — authoring runs)
25
+
26
+ Allocated **only in Capture** Step 4:
27
+
28
+ ```
29
+ 1. Get the current date in UTC
30
+ 2. List existing files under docs/plans/.learn/.capture/ matching YYYY-MM-DD-NNN-capture.md for that date
31
+ 3. NNN = (highest existing NNN for that date), zero-padded to 3 digits
32
+ - if none exist for that date, start at 001
33
+ 4. learn-id = "<date>-<NNN>" (the same NNN as the capture-id being allocated)
34
+ 5. Write the capture artifact with both learn-id and capture-id
35
+ ```
36
+
37
+ Because `learn-id` reuses the capture counter's NNN, the umbrella id and the `capture-id` share the same date+counter suffix (e.g., `learn-id: 2026-08-08-001` → `capture-id: 2026-08-08-001-capture`). Refine and Index **inherit** that same NNN — they do **not** independently allocate a competing NNN. If the NNN is taken by an unrelated artifact on the same date in a later phase directory (rare), the later phase appends and notes the divergence in its artifact (the umbrella `learn-id` is still carried everywhere).
38
+
39
+ ## maintain-id (standalone — maintain runs)
40
+
41
+ Allocated **only in Maintain** Step 6:
42
+
43
+ ```
44
+ 1. Get the current date in UTC
45
+ 2. List existing files under docs/plans/.learn/.maintain/ matching YYYY-MM-DD-NNN-maintain.md for that date
46
+ 3. NNN = (count + 1), zero-padded to 3 digits
47
+ 4. maintain-id = "<date>-<NNN>-maintain"
48
+ ```
49
+
50
+ A maintain artifact carries only `maintain-id`, never `learn-id` (a `learn-id` on a maintain artifact is treated as an orphan and logged per [error-handling.md](error-handling.md) Cross-Phase Consistency Checks).
51
+
52
+ ## entry slug (upsert key — authored knowledge)
53
+
54
+ The `slug` is the stable, globally-unique key for a knowledge entry — it keys the entry file path (`docs/learn/<type>/<slug>.md`) and the index record. Capture **proposes** it; Refine **validates** uniqueness; Index **upserts** on it.
55
+
56
+ **Algorithm (Capture Step 4 proposes):**
57
+
58
+ ```
59
+ 1. Extract a concise, descriptive phrase from the entry title / problem statement
60
+ 2. Convert to kebab-case (lowercase, non-alphanumeric → hyphen, collapse repeats, trim)
61
+ 3. For time-bound decisions, a date suffix is allowed when the legacy/source used one:
62
+ critical-risk-tier-security-payments-2026-07-04
63
+ 4. The slug must be globally unique across docs/learn/<type>/ (all types share one slug
64
+ namespace — a decision's slug cannot collide with a pattern's slug)
65
+ 5. Capture proposes; Refine checks against the existing entries
66
+ ```
67
+
68
+ **On a collision (Refine Step 3):** Refine runs the duplicate/analog check per [dedup-rules.md](dedup-rules.md). An exact match gives the user two choices: **update-existing** (keep the `slug`, overwrite the file + index record) or **new-slug** (append a distinguishing suffix, e.g., `<slug>-v2` or a domain qualifier). Capture does **not** pre-resolve collisions.
69
+
70
+ > **Slug is the upsert key, not a timestamp id.** A re-author with the same `slug` overwrites in place (idempotent); a new `slug` creates a new entry. The slug namespace is shared across all four types — there is one global `docs/learn/` slug space, not four.
71
+
72
+ ## Algorithm (new phase artifact)
73
+
74
+ ```
75
+ 1. Get the current date in UTC (e.g., 2026-08-08)
76
+ 2. List existing files for today in the phase's save directory:
77
+ - capture -> docs/plans/.learn/.capture/ matching YYYY-MM-DD-*-capture.md
78
+ - refine -> docs/plans/.learn/.refine/ matching YYYY-MM-DD-*-refine.md
79
+ - index -> docs/plans/.learn/.index/ matching YYYY-MM-DD-*-index.md
80
+ - maintain -> docs/plans/.learn/.maintain/ matching YYYY-MM-DD-*-maintain.md
81
+ 3. NNN = (count + 1), zero-padded to 3 digits (001, 002, ..., 010, ...)
82
+ 4. id = "<date>-<NNN>-<phase>"
83
+ ```
84
+
85
+ Counters are independent per phase; each phase counts only its own files.
86
+
87
+ ## Recycle on Edit & Retry
88
+
89
+ When the user picks **Edit & Retry** at a phase confirmation, **reuse the original ID** and overwrite the existing artifact file. Do **not** increment the counter. This keeps IDs stable across iterations and prevents orphaned artifacts. The Index phase's upsert on `slug` is likewise idempotent (overwrite the entry file + index record, never duplicate). Maintain's `maintain-id` reuses the same id across re-run steps within one maintain session.
90
+
91
+ ## Migration Note (entry slugs on legacy entries)
92
+
93
+ The legacy `docs/learnings/` store uses filenames, not slugs, as the key. The migration ([migration-bootstrap.md](migration-bootstrap.md)) **derives the canonical `slug`** from each legacy filename:
94
+
95
+ - `2026-07-04-critical-risk-tier-security-payments.md` → `slug: critical-risk-tier-security-payments-2026-07-04` (date kept as suffix when the file used one; the type-prefixed files already carry the date in)
96
+ - `daily-counter-artifact-naming-2026-07-02.md` → `slug: daily-counter-artifact-naming-2026-07-02`
97
+ - The original filename is preserved in the entry's `migrated-from` lineage field, so the old path knowledge is not lost.
98
+
99
+ ## Error Handling
100
+
101
+ | Trigger | Action |
102
+ | ----------------------------------------------- | -------------------------------------------- |
103
+ | Phase save directory does not exist | Create it (Pre-Flight already creates); treat count as 0; start from 001 |
104
+ | Directory exists but no files match today's date | Start counter at 001 |
105
+ | `docs/learn/` missing | Create it; Index creates `<type>/` subdir; Maintain seeds the index (Pre-Flight helps) |
106
+ | Write permission denied | Log error; ask the user; retry once |
107
+ | Slug collision at Capture (should not happen — Refine's job) | Capture proposes; Refine resolves — never silently two |
108
+
109
+ ## Notes
110
+
111
+ - IDs reuse the daily-counter algorithm for cross-skill consistency with `/plan`, `/work`, and `/review`; the Learn skill's counters are independent from those skills (separate save directories under `docs/plans/.learn/`).
112
+ - `learn-id` carries through Capture → Refine → Index; Maintain uses the standalone `maintain-id` only. Cross-phase chaining is `capture-id → refine-id → index-id`, all sharing one `learn-id` (see [error-handling.md](error-handling.md) "Cross-Phase Consistency Checks").
113
+ - The `slug` is a **separate** key from the phase ids — it identifies the durable knowledge entry across re-authors, not the pipeline run. A single `slug` may be authored by many `learn-id` runs over time (each upsert overwrites); the `slug` is stable, the `learn-id` is per-run.
114
+ - Counter collisions are impossible within a date because each phase writes to its own directory and recomputes the count from the directory listing.