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.
- package/README.md +81 -0
- package/package.json +42 -0
- package/scripts/postinstall.js +50 -0
- package/skills/arreio-init/SKILL.md +214 -0
- package/skills/arreio-init/references/architecture-template.md +85 -0
- package/skills/arreio-init/references/learn-index-template.md +15 -0
- package/skills/arreio-init/references/plan-index-template.md +29 -0
- package/skills/arreio-init/references/tasks-index-template.md +15 -0
- package/skills/learn/SKILL.md +151 -0
- package/skills/learn/modules/capture.md +108 -0
- package/skills/learn/modules/index.md +94 -0
- package/skills/learn/modules/maintain.md +116 -0
- package/skills/learn/modules/refine.md +104 -0
- package/skills/learn/references/dedup-rules.md +129 -0
- package/skills/learn/references/entry-schema.md +152 -0
- package/skills/learn/references/error-handling.md +178 -0
- package/skills/learn/references/id-generation.md +114 -0
- package/skills/learn/references/index-format.md +140 -0
- package/skills/learn/references/interaction-mode-propagation.md +89 -0
- package/skills/learn/references/migration-bootstrap.md +142 -0
- package/skills/learn/references/templates/artifacts/captured-entry.md +172 -0
- package/skills/learn/references/templates/artifacts/index-update.md +135 -0
- package/skills/learn/references/templates/artifacts/learn-input.md +100 -0
- package/skills/learn/references/templates/artifacts/maintain-log.md +142 -0
- package/skills/learn/references/templates/artifacts/refined-entry.md +168 -0
- package/skills/plan/SKILL.md +129 -0
- package/skills/plan/modules/design.md +140 -0
- package/skills/plan/modules/generate.md +156 -0
- package/skills/plan/modules/research.md +122 -0
- package/skills/plan/modules/scope.md +121 -0
- package/skills/plan/modules/tasks.md +190 -0
- package/skills/plan/references/design-complexity-assessment.md +118 -0
- package/skills/plan/references/error-handling.md +155 -0
- package/skills/plan/references/external-research-guidance.md +61 -0
- package/skills/plan/references/high-risk-detection.md +111 -0
- package/skills/plan/references/id-generation.md +55 -0
- package/skills/plan/references/interaction-mode-propagation.md +75 -0
- package/skills/plan/references/learnings-gate-logic.md +93 -0
- package/skills/plan/references/plan-tier-selection.md +174 -0
- package/skills/plan/references/task-slicing-rules.md +220 -0
- package/skills/plan/references/templates/artifacts/design.md +134 -0
- package/skills/plan/references/templates/artifacts/final-plan.md +265 -0
- package/skills/plan/references/templates/artifacts/research-findings.md +50 -0
- package/skills/plan/references/templates/artifacts/scoped-context.md +53 -0
- package/skills/plan/references/templates/artifacts/task.md +192 -0
- package/skills/plan/references/templates/artifacts/user-input.md +112 -0
- package/skills/review/SKILL.md +163 -0
- package/skills/review/modules/analyze.md +104 -0
- package/skills/review/modules/prepare.md +103 -0
- package/skills/review/modules/report.md +109 -0
- package/skills/review/modules/scope.md +126 -0
- package/skills/review/references/approval-criteria.md +101 -0
- package/skills/review/references/change-set-resolution.md +126 -0
- package/skills/review/references/error-handling.md +172 -0
- package/skills/review/references/id-generation.md +80 -0
- package/skills/review/references/interaction-mode-propagation.md +80 -0
- package/skills/review/references/review-categories.md +124 -0
- package/skills/review/references/scope-creep-detection.md +120 -0
- package/skills/review/references/severity-rubric.md +107 -0
- package/skills/review/references/templates/artifacts/findings.md +161 -0
- package/skills/review/references/templates/artifacts/review-input.md +116 -0
- package/skills/review/references/templates/artifacts/review-kit.md +135 -0
- package/skills/review/references/templates/artifacts/review-report.md +175 -0
- package/skills/review/references/templates/artifacts/review-scope.md +146 -0
- package/skills/work/SKILL.md +163 -0
- package/skills/work/modules/execute.md +109 -0
- package/skills/work/modules/prepare.md +140 -0
- package/skills/work/modules/review.md +164 -0
- package/skills/work/modules/triage.md +181 -0
- package/skills/work/references/ad-hoc-input-resolution.md +122 -0
- package/skills/work/references/error-handling.md +183 -0
- package/skills/work/references/execution-mode-selection.md +95 -0
- package/skills/work/references/id-generation.md +85 -0
- package/skills/work/references/interaction-mode-propagation.md +80 -0
- package/skills/work/references/review-checklist.md +94 -0
- package/skills/work/references/task-execution-rules.md +116 -0
- package/skills/work/references/templates/artifacts/execution-log.md +123 -0
- package/skills/work/references/templates/artifacts/execution-plan.md +111 -0
- package/skills/work/references/templates/artifacts/work-input.md +78 -0
- package/skills/work/references/templates/artifacts/work-manifest.md +119 -0
- package/skills/work/references/templates/artifacts/work-report.md +143 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Index Format
|
|
3
|
+
description: Authoritative reference for the Index phase (upsert) and Maintain phase (rebuild). Defines the canonical docs/learn/index.md structure: a YAML entries block (the read-contract record per entry — filename/domain/tags/applicability/summary) plus the human-readable By Category / By Domain markdown tables. Defines the applicability-enum derivation from the per-entry numeric scores and the idempotency rule.
|
|
4
|
+
type: reference
|
|
5
|
+
version: 1.0
|
|
6
|
+
timestamp: "2026-08-08"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Index Format
|
|
10
|
+
|
|
11
|
+
Authoritative reference for the canonical `docs/learn/index.md` format. Defines the **hybrid structure** — a YAML `entries:` block (the read-contract record per entry) plus the human-readable **By Category** / **By Domain** markdown tables — and the **`applicability` enum derivation** from the per-entry numeric scores (the write→read projection). Index upserts one record per authoring run; Maintain rebuilds the whole index from the file tree (the source of truth). Both apply this format; neither re-encodes it.
|
|
12
|
+
|
|
13
|
+
> This is the file Plan, Work, and Review all read via [learnings-gate-logic.md](../../plan/references/learnings-gate-logic.md). The YAML `entries:` block is the **read contract** — the five-field record shape the gate-logic parses. The markdown tables are the human-readable projection of the same data. Both are derived from the per-entry frontmatter ([entry-schema.md](entry-schema.md)); the index never stores a field the entry's frontmatter cannot produce. **No second formula** — the search algorithm lives in Plan's gate-logic; the format lives here.
|
|
14
|
+
|
|
15
|
+
## Canonical Structure
|
|
16
|
+
|
|
17
|
+
```markdown
|
|
18
|
+
# Knowledge Index
|
|
19
|
+
|
|
20
|
+
The project's durable knowledge base. Source of truth for decisions, patterns,
|
|
21
|
+
gotchas, and workflows. Plan/Work/Review search this index via the YAML block.
|
|
22
|
+
|
|
23
|
+
**Last updated:** <ISO-8601>
|
|
24
|
+
|
|
25
|
+
## Entries
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
entries:
|
|
29
|
+
- filename: docs/learn/decision/critical-risk-tier-security-payments-2026-07-04.md
|
|
30
|
+
domain: planning
|
|
31
|
+
tags: [risk-assessment, security]
|
|
32
|
+
applicability: DIRECT
|
|
33
|
+
summary: CRITICAL risk tier above HIGH for security/payments; always external research
|
|
34
|
+
- filename: docs/learn/gotcha/secondary-spec-contradicts-authoritative-matrix.md
|
|
35
|
+
domain: skill-design
|
|
36
|
+
tags: [single-source-of-truth, contradictions]
|
|
37
|
+
applicability: DIRECT
|
|
38
|
+
summary: Don't re-encode an authoritative matrix as a contradicting secondary formula
|
|
39
|
+
# ...one record per on-disk entry; de-indexed (obsolete/superseded) entries are EXCLUDED
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## By Category
|
|
43
|
+
|
|
44
|
+
### Decision (N)
|
|
45
|
+
|
|
46
|
+
| File | Title | Domain | Applicability |
|
|
47
|
+
|------|-------|--------|---------------|
|
|
48
|
+
| [critical-risk-tier-security-payments-2026-07-04.md](decision/critical-risk-tier-security-payments-2026-07-04.md) | Introduce CRITICAL Risk Tier Above HIGH for Security/Payments Areas | planning | DIRECT |
|
|
49
|
+
| ... | ... | ... | ... |
|
|
50
|
+
|
|
51
|
+
### Pattern (N)
|
|
52
|
+
... (same table shape, a row per pattern)
|
|
53
|
+
|
|
54
|
+
### Gotcha (N)
|
|
55
|
+
... (same table shape, a row per gotcha)
|
|
56
|
+
|
|
57
|
+
### Workflow (N)
|
|
58
|
+
... (same table shape, a row per workflow)
|
|
59
|
+
|
|
60
|
+
## By Domain
|
|
61
|
+
|
|
62
|
+
- **planning:** critical-risk-tier-security-payments-2026-07-04, plan-tier-selection-algorithm-2026-07-04, ...
|
|
63
|
+
- **skill-design:** pipeline-phase-module-template-2026-07-04, quality-gates-pipeline-orchestration-2026-07-04, ...
|
|
64
|
+
- **artifact-naming:** daily-counter-artifact-naming-2026-07-02, cross-phase-id-chaining-2026-07-04, ...
|
|
65
|
+
- ... (one bullet per domain, listing the slugs; de-indexed entries excluded)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Read-Contract Record (the YAML `entries:` block)
|
|
69
|
+
|
|
70
|
+
Each record carries **exactly these five fields** — the gate-logic's read contract. No more, no fewer:
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
- filename: docs/learn/<type>/<slug>.md # REQUIRED. Repo-relative path to the entry file.
|
|
74
|
+
domain: <primary-domain> # REQUIRED. The entry's frontmatter domain.
|
|
75
|
+
tags: [<tag>, ...] # REQUIRED. The entry's frontmatter tags (carried verbatim).
|
|
76
|
+
applicability: <enum> # REQUIRED. Derived per the table below — never stored on the entry.
|
|
77
|
+
summary: <1-2 sentence summary> # REQUIRED. The frontmatter summary, or the body Problem/Solution derivation.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- `filename` — repo-relative; uses forward slashes; stable (the slug is the upsert key, so the filename is stable across re-authors).
|
|
81
|
+
- `domain`, `tags` — carried verbatim from the entry's frontmatter.
|
|
82
|
+
- `applicability` — **derived** (see below), never stored on the entry's frontmatter (the entry keeps the numeric scores; the index projects to the enum).
|
|
83
|
+
- `summary` — the entry's frontmatter `summary` field if present; else the first 1–2 sentences of the entry's Problem/Solution body (Capture/Refine/Index derive this; Maintain re-derives on rebuild).
|
|
84
|
+
|
|
85
|
+
## Applicability Enum Derivation (authoritative)
|
|
86
|
+
|
|
87
|
+
The write side (the entry frontmatter per [entry-schema.md](entry-schema.md)) stores `applicability: { current_project: N, general: N }`. The index-record projects this to a single enum (the read side's vocabulary). The derivation:
|
|
88
|
+
|
|
89
|
+
| Condition (write-side numerics) | Enum | Gate-logic handling |
|
|
90
|
+
| ----------------------------------------- | ------------- | ----------------------------------- |
|
|
91
|
+
| `current_project ≥ 8 AND general ≥ 7` | `DIRECT` | HIGH relevance — included |
|
|
92
|
+
| `current_project ≥ 5 AND general ≥ 5` | `RECOMMENDED` | MEDIUM relevance — included |
|
|
93
|
+
| `general ≥ 5` | `CONTEXTUAL` | MEDIUM relevance — included |
|
|
94
|
+
| `general ≥ 3` | `HISTORICAL` | LOW relevance — excluded by gate |
|
|
95
|
+
| otherwise | `INFORMATIONAL` | LOW relevance — excluded |
|
|
96
|
+
|
|
97
|
+
The enum is computed by Index Step 1 (for upsert) and Maintain Step 5 (for rebuild) from the entry's frontmatter. **It is never stored on the entry** — projecting from the numeric scores to the enum at index time avoids a second-source contradiction (honoring the secondary-spec gotcha: one mapping lives here, the entry keeps the rich numerics).
|
|
98
|
+
|
|
99
|
+
> Gate-logic relevance: gate-logic matches keywords, then scores HIGH/MEDIUM/LOW. The enum above maps DIRECT/RECOMMENDED/CONTEXTUAL/HISTORICAL/INFORMATIONAL to that HIGH/MEDIUM/LOW banding (DIRECT/RECOMMENDED/CONTEXTUAL are potentially HIGH/MEDIUM; HISTORICAL/INFORMATIONAL are LOW). The mapping lives in the gate-logic, not here — here we only produce the enum the gate-logic expects.
|
|
100
|
+
|
|
101
|
+
## By Category / By Domain Tables
|
|
102
|
+
|
|
103
|
+
The human-readable projection. Both are **derived** from the same on-disk entries (the YAML block and the tables are in lockstep; Index/Maintain never allow them to drift):
|
|
104
|
+
|
|
105
|
+
- **By Category** — four `### <Type> (N)` subsections (Decision/Pattern/Gotcha/Workflow), each a `| File | Title | Domain | Applicability |` markdown table, one row per entry of that type. The `(N)` is the count of that type's entries.
|
|
106
|
+
- **By Domain** — one bullet per domain, listing the slugs of that domain's entries, comma-separated. Covering all on-disk domains (the union of every entry's `domain`).
|
|
107
|
+
|
|
108
|
+
`Title` is the entry's body `# <Title>` heading (Title Case), carried verbatim. `Applicability` is the same derived enum as the YAML record. `De-indexed` entries (frontmatter `status: obsolete` or a `superseded-by` whose canonical is present) are **excluded** from both the YAML block and the tables.
|
|
109
|
+
|
|
110
|
+
## Idempotency
|
|
111
|
+
|
|
112
|
+
`docs/learn/index.md` is upserted by `slug`:
|
|
113
|
+
|
|
114
|
+
- **Upsert (Index Step 3)** — the record is updated in place in the YAML `entries:` block (matched on `filename`), and the row is updated in place in the By Category table and the By Domain bullet (matched on `slug`/title). A re-author with the same `slug` overwrites the record, never appends a second.
|
|
115
|
+
- **Rebuild (Maintain Step 5)** — the file tree is the source of truth: re-scan `docs/learn/<type>/*.md`, regenerate the YAML block and the tables, recompute the per-type `(N)` counts and the By Domain bullets. Idempotent (re-running rebuild over an unchanged tree produces an identical file).
|
|
116
|
+
|
|
117
|
+
**Totals coherence** is the invariant: the YAML `entries:` block length must equal the count of non-de-indexed entry files on disk; each `### <Type> (N)` count must equal the number of records of that type in the YAML block; the By Domain bullets must list the same entries. If any drifts, Index reconciles in-place (non-destructive) and Maintain fully rebuilds.
|
|
118
|
+
|
|
119
|
+
## Validation (Index Step 3 / Maintain Step 5 re-checks)
|
|
120
|
+
|
|
121
|
+
- Every on-disk entry (non-de-indexed) has exactly one YAML record and exactly one row in By Category and one slug in By Domain.
|
|
122
|
+
- Every `applicability` enum in the index matches the derivation for that entry's frontmatter numerics (no drift).
|
|
123
|
+
- The `(N)` counts match the YAML records per type.
|
|
124
|
+
- The `summary` is present for every record (body-derived if absent in frontmatter).
|
|
125
|
+
- No two records share a `filename` (the upsert key is unique).
|
|
126
|
+
|
|
127
|
+
## Failure-Condition Reference
|
|
128
|
+
|
|
129
|
+
| Trigger | Outcome per this reference |
|
|
130
|
+
| -------------------------------------------------------- | ------------------------------------------------------- |
|
|
131
|
+
| An entry's frontmatter lacks numerics entirely (legacy pre-Schema entry) | Migration/Maintain infers from the legacy `severity` per [migration-bootstrap.md](migration-bootstrap.md); no inference here. |
|
|
132
|
+
| Two on-disk entries have the same `slug` (corrupt store) | Index/Maintain detect the duplicate `filename` in the YAML; flag; the user picks the canonical (dedup per [dedup-rules.md](dedup-rules.md)). |
|
|
133
|
+
| An entry has a `superseded-by` but is still in the YAML block | Refine/Maintain de-index it (remove the record + row); the canonical's `related` already links its slug. |
|
|
134
|
+
|
|
135
|
+
## Notes
|
|
136
|
+
|
|
137
|
+
- This reference is the single source of truth for the canonical index format, the read-contract record (five fields), the applicability-enum derivation, and the idempotency rules. Index and Maintain apply it; the orchestrator and modules never re-encode the format inline.
|
|
138
|
+
- The YAML block and the markdown tables are **two projections of one on-disk truth** (the entry files). Allowing them to drift would re-introduce the secondary-spec gotcha at the index level; the idempotency invariant prevents that.
|
|
139
|
+
- The `index-applicability` enum is the bridge between the write side (rich numerics) and the read side (HIGH/MEDIUM/LOW banding). It is **derived**, never stored on the entry — stored once here, derived once at index time.
|
|
140
|
+
- De-indexed entries (obsolete / superseded) remain on disk but are removed from the index. `docs/learn/index.md` is an index of **active** knowledge, not a registry of every file ever written.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Interaction Mode Propagation
|
|
3
|
+
description: Reference for how `interactionMode` propagates through the Learn pipeline (Capture -> Refine -> Index -> Maintain). Set at the Orchestrator; each phase reads and applies mode-specific behavior. The Learn skill has no execution mode — only interactionMode.
|
|
4
|
+
type: reference
|
|
5
|
+
version: 1.0
|
|
6
|
+
timestamp: "2026-08-08"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Interaction Mode Propagation
|
|
10
|
+
|
|
11
|
+
Reference for how `interactionMode` propagates through the Learn pipeline (`Capture → Refine → Index → Maintain`). Set at the Orchestrator; each phase reads and applies mode-specific behavior.
|
|
12
|
+
|
|
13
|
+
> `interactionMode` governs **when to pause for the user**. Like Review, the Learn skill has **no execution mode** — curation is a single forward pass per entry (or a reconcile pass for Maintain), not a multi-task run, so there is no `executionMode` selector. Only `interactionMode` is carried through every artifact.
|
|
14
|
+
|
|
15
|
+
## Modes
|
|
16
|
+
|
|
17
|
+
| Mode | Behavior | Use Case |
|
|
18
|
+
| ------------- | ----------------------------------------------------- | ------------------------------------ |
|
|
19
|
+
| **Detailed** | Pause at each phase; present artifacts; require approval | Authoritative decisions, sensitive maintenance, unfamiliar curation |
|
|
20
|
+
| **Smart** | Auto-proceed; pause only on destructive/ambiguous operations (a likely-duplicate, a merge, a prune, a migration rewrite, a draft inferred from a short text) | Most routine curation |
|
|
21
|
+
| **Autopilot** | Auto-proceed for non-destructive steps; **still pause** for destructive operations (migration, prune, merge — never silently delete or rewrite paths) | Routine, well-scoped entries |
|
|
22
|
+
|
|
23
|
+
## Phase Behavior by Mode
|
|
24
|
+
|
|
25
|
+
| Phase | Detailed | Smart | Autopilot |
|
|
26
|
+
| ------------ | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | --------------------------------- |
|
|
27
|
+
| **Capture** | Present captured entry; ask Proceed/Edit/Abort | Auto-proceed; pause if candidate/inferred draft (inferred type, domain, tags, body), or a bare ref that could not be read | Auto-proceed (still confirms inferred content per below) |
|
|
28
|
+
| **Refine** | Present refined entry; ask Proceed/Edit/Abort | Auto-proceed; pause on `dup-status: exact` (update vs new-slug), `dup-status: analog` (merge vs keep), a failed frontmatter field, or a missing body section | Auto-proceed (still surfaces duplicate/merge conflicts — destructive, never silent) |
|
|
29
|
+
| **Index** | Present index update; ask Finalize/Edit/Abort | Auto-proceed; pause on `index-action: created` (overwrite of existing `slug`), `index-action: merged` (analog de-index), or an incoherent prior index that needed reconcile | Auto-proceed (still confirms overwrite + merge — destructive) |
|
|
30
|
+
| **Maintain** | Present maintain log; ask Finalize/Edit/Abort | Auto-proceed for non-destructive (refresh, rebuild); pause for migration rewrite, prune, merge, or incoherent rebuild | Auto-proceed for non-destructive; **still pauses** for migration/prune/merge (destructive — Autopilot never silently deletes or rewrites 28 paths) |
|
|
31
|
+
|
|
32
|
+
**Smart mode pauses only on each phase's documented triggers above** (the canonical list lives in each module's confirmation step; this table is a summary).
|
|
33
|
+
|
|
34
|
+
**Destructive operations are never silent, even in Autopilot.** This is the Learn skill's guardrail against corrupting the canonical knowledge base: a migration that rewrites 28 entry paths, a prune that deletes a file, and a merge that de-indexes an analog all surface for user confirmation regardless of the interaction mode. Non-destructive curation (drafting a new entry, refreshing frontmatter defaults, rebuilding the index from the file tree) automates freely.
|
|
35
|
+
|
|
36
|
+
## Artifact Schema
|
|
37
|
+
|
|
38
|
+
All phase artifacts include `interactionMode`:
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
interactionMode: detailed | smart | autopilot # Passed from previous phase
|
|
42
|
+
status: pending | complete | failed
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Implementation
|
|
46
|
+
|
|
47
|
+
**Each phase must:**
|
|
48
|
+
|
|
49
|
+
1. Read `interactionMode` from the incoming artifact (or context, for Capture).
|
|
50
|
+
2. Apply mode-specific behavior per the table above.
|
|
51
|
+
3. Include `interactionMode` in the output artifact.
|
|
52
|
+
|
|
53
|
+
## Example
|
|
54
|
+
|
|
55
|
+
**SMART mode on an explicit decision author:**
|
|
56
|
+
|
|
57
|
+
- Capture reads user-provided prose grounded in a commit ref (not inferred) → auto-proceeds
|
|
58
|
+
- Refine finds no exact/analog duplicate → auto-proceeds
|
|
59
|
+
- Index creates a new entry file (no overwrite) and upserts the index → auto-proceeds (the `created` action was not an overwrite)
|
|
60
|
+
- Result: a durable decision entry written with no pause; faster than Detailed, safe because the run was non-destructive
|
|
61
|
+
|
|
62
|
+
**AUTOPilot mode on a `/learn maintain` after the store drifted:**
|
|
63
|
+
|
|
64
|
+
- Maintain Step 1 migration: skips (`no-op, already migrated`)
|
|
65
|
+
- Maintain Step 2 dedup: finds an analog pair → **pauses** (merge is destructive — Autopilot confirms)
|
|
66
|
+
- User confirms the merge → Maintain de-indexes the analog with lineage
|
|
67
|
+
- Maintain Step 3 refresh: auto-proceeds (non-destructive)
|
|
68
|
+
- Maintain Step 4 prune: finds an obsolete entry → **pauses** (prune is destructive — Autopilot confirms; default = de-index, not delete)
|
|
69
|
+
- Maintain Step 5 rebuild: auto-proceeds (non-destructive)
|
|
70
|
+
|
|
71
|
+
**Result:** Paused only for the two destructive operations; the non-destructive refresh/rebuild ran automatically.
|
|
72
|
+
|
|
73
|
+
## No Execution Mode (contrast with Work)
|
|
74
|
+
|
|
75
|
+
Learn deliberately has **no** `executionMode`:
|
|
76
|
+
|
|
77
|
+
- Work's `executionMode` (`inline`/`serial`/`parallel`) governs how multiple independent **tasks** run — Learn has no multi-task concept; curation is one entry per run (or a reconcile pass).
|
|
78
|
+
- The orchestrator's quality gate #2 for Learn cross-checks **only** `interactionMode` (not `interactionMode` + `executionMode` as in Work).
|
|
79
|
+
- A duplicate/migration/prune is the Learn analog of Work's HIGH-risk flag: it triggers pause behavior via `interactionMode`'s Smart triggers, not a separate mode.
|
|
80
|
+
|
|
81
|
+
## Error Handling
|
|
82
|
+
|
|
83
|
+
| Scenario | Recovery |
|
|
84
|
+
| --------------------------- | ------------------------------------- |
|
|
85
|
+
| Mode missing | Default to "smart"; log warning |
|
|
86
|
+
| Invalid mode value | Reject; re-prompt Orchestrator |
|
|
87
|
+
| Artifact missing mode field | Assume "smart"; log warning; continue |
|
|
88
|
+
| User selects "Abort" | Stop immediately; inform Orchestrator |
|
|
89
|
+
| Timeout/connection lost | Pause; ask user to retry or abort |
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Migration Bootstrap
|
|
3
|
+
description: Authoritative reference for the Maintain phase (Step 1, one-time, self-gating). Defines the procedure for migrating the legacy docs/learnings/ store into the canonical docs/learn/ store: slug derivation from legacy filenames, frontmatter normalization per entry-schema, cross-reference rewriting (entry body + related links), the migrated-from lineage note, the .migrated marker, the self-gate (no-op if already migrated), and the rule that the legacy store is never deleted.
|
|
4
|
+
type: reference
|
|
5
|
+
version: 1.0
|
|
6
|
+
timestamp: "2026-08-08"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Migration Bootstrap
|
|
10
|
+
|
|
11
|
+
Authoritative reference for the **Maintain** phase (Step 1, one-time, self-gating). Defines the procedure for migrating the legacy `docs/learnings/` store into the canonical `docs/learn/` store: **slug derivation** from legacy filenames, **frontmatter normalization** per [entry-schema.md](entry-schema.md), **cross-reference rewriting** (entry bodies + `related` links), the **`migrated-from` lineage note**, the **`.migrated` marker**, the **self-gate** (a no-op when already migrated), and the hard rule that **the legacy store is never deleted by the migration**. Maintain invokes this reference; it does not re-derive the procedure.
|
|
12
|
+
|
|
13
|
+
## Core Principle
|
|
14
|
+
|
|
15
|
+
> **One-time, self-gating, idempotent, lineage-preserving.** The migration runs once (the `.migrated` marker and slug-set parity prevent re-runs); it is idempotent (re-invoking is a no-op); it preserves lineage (each migrated entry records its `migrated-from: docs/learnings/<type>/<file>.md`, so the old path knowledge is not lost — the `path-convention-split` gotcha is the model: a migrated entry carries both the old and new path knowledge, never just the new). The legacy store stays on disk, read-only and superseded, until the user explicitly prunes it (a destructive, confirm-each step in Maintain, never part of the migration itself).
|
|
16
|
+
|
|
17
|
+
## Trigger & Self-Gate
|
|
18
|
+
|
|
19
|
+
Maintain runs the migration only when **all** are true:
|
|
20
|
+
|
|
21
|
+
1. `docs/learnings/` exists and is non-empty (legacy store present).
|
|
22
|
+
2. `docs/learn/` does not yet have the `.migrated` marker **and** the on-disk slug-set in `docs/learn/` does **not** match the legacy slug-set (par·ity detection — migration is already complete iff the canonical store has, for every legacy file, a matching slug).
|
|
23
|
+
|
|
24
|
+
Otherwise: record `migration: no-op (already migrated)` and skip to Maintain Step 2 (base-wide dedup). A subsequent `/learn maintain` invocation is a clean no-op.
|
|
25
|
+
|
|
26
|
+
## Procedure
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
1. For each file under docs/learnings/<type>/*.md (type ∈ decision/gotcha/pattern/workflow):
|
|
30
|
+
1.1 Read the legacy entry (frontmatter + body).
|
|
31
|
+
1.2 Derive the canonical slug:
|
|
32
|
+
- Slug = kebab-case(normalize(legacy filename minus extension))
|
|
33
|
+
- The introduction of a date in the filename is preserved as a date suffix:
|
|
34
|
+
2026-07-04-critical-risk-tier-security-payments.md -> critical-risk-tier-security-payments-2026-07-04
|
|
35
|
+
daily-counter-artifact-naming-2026-07-02.md -> daily-counter-artifact-naming-2026-07-02
|
|
36
|
+
- Verify global uniqueness across docs/learn/; on collision, append a qualifier
|
|
37
|
+
(e.g., -a / -b) and record the rename in the log.
|
|
38
|
+
1.3 Normalize the frontmatter per [entry-schema.md](entry-schema.md):
|
|
39
|
+
- Newer-layout (slug/type/domain/priority/applicability.{current_project,general}/tags/confidence):
|
|
40
|
+
ALREADY canonical — preserve, add migrated-from.
|
|
41
|
+
- Older-layout (title/category/severity/domain/tags/source: commit <sha>):
|
|
42
|
+
Convert:
|
|
43
|
+
* type = category
|
|
44
|
+
* slug = <derived above>
|
|
45
|
+
* priority = important if severity==important else normal
|
|
46
|
+
* applicability.current_project = inferred from severity (important->9, recommended->6, informational->3)
|
|
47
|
+
* applicability.general = inferred from severity (important->7, recommended->5, informational->4)
|
|
48
|
+
* confidence = medium
|
|
49
|
+
* source = { type: commit, reference: <sha>, extracted_at: <legacy created_at or date> }
|
|
50
|
+
* The legacy `title` becomes the body `# <Title>` heading.
|
|
51
|
+
* Mark inferred numerics with a comment/note: `# inferred from legacy severity:important` so
|
|
52
|
+
the inference is explicit, not silent.
|
|
53
|
+
1.4 Rewrite cross-references (the entry's body + its related links):
|
|
54
|
+
- Any `../learnings/...` or `docs/learnings/...` link -> canonical `docs/learn/...` path
|
|
55
|
+
- Any legacy filename link -> canonical slug-relative link
|
|
56
|
+
- Preserve the link target's anchor text (do not silently change the prose)
|
|
57
|
+
1.5 Add lineage: set migrated-from: docs/learnings/<type>/<original-filename>.md
|
|
58
|
+
(so a future "where did this come from?" query resolves to the legacy path).
|
|
59
|
+
1.6 Write the canonical entry to docs/learn/<type>/<slug>.md (create <type>/ subdir as needed).
|
|
60
|
+
2. Write the .migrated marker at docs/learn/.migrated containing:
|
|
61
|
+
migrated-at: <ISO-8601>
|
|
62
|
+
migrated-entries: <N>
|
|
63
|
+
legacy-path: docs/learnings/
|
|
64
|
+
3. After all entries are written, build docs/learn/index.md from the canonical entries
|
|
65
|
+
(per [index-format.md](index-format.md) — Index phase's format; Maintain's rebuild step
|
|
66
|
+
runs the same format). The legacy docs/learnings/INDEX.md is NOT carried over — the new
|
|
67
|
+
index is derived from the canonical entry files (single source of truth).
|
|
68
|
+
4. Do NOT delete docs/learnings/ (the legacy store stays; superseded, read-only).
|
|
69
|
+
Record migration: <N> entries migrated in the maintain log.
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Lineage Preservation (authoritative)
|
|
73
|
+
|
|
74
|
+
Every migrated entry carries:
|
|
75
|
+
|
|
76
|
+
- `migrated-from: docs/learnings/<type>/<original-filename>.md` — the old path, so a reader tracking an old `docs/learnings/...` reference in a commit, a doc, or another entry's `related` link can resolve it to the canonical file.
|
|
77
|
+
- The **rewritten cross-references** — any `docs/learnings/...` link in the body becomes `docs/learn/...`, but the link's old form is not erased from the project's history: it is in git, and the `migrated-from` field is the in-file breadcrumb.
|
|
78
|
+
|
|
79
|
+
This is the deliberate avoid-the-gotcha move: the [path-convention-split](../../../docs/learn/gotcha/2026-08-07-path-convention-split-silently-noops.md) trap is that a convention change silently no-ops. The migration prevents the no-op by (a) recording the old path on every entry, (b) rewriting links so readers land on the new path, and (c) keeping the legacy store on disk so nothing is destroyed mid-migration. The old path knowledge and the new path knowledge **both** live in the canonical entry.
|
|
80
|
+
|
|
81
|
+
## Slug Derivation Rules (authoritative)
|
|
82
|
+
|
|
83
|
+
| Legacy filename pattern | Canonical slug | Notes |
|
|
84
|
+
| ----------------------- | -------------- | ----- |
|
|
85
|
+
| `<date>-<descriptive>.md` (date-prefixed) | `<descriptive>-<date>` | Date moved to suffix; the descriptive part stays. |
|
|
86
|
+
| `<descriptive>-<date>.md` (date-suffixed) | `<descriptive>-<date>` | Already in the canonical form; preserve. |
|
|
87
|
+
| `<descriptive>.md` (no date) | `<descriptive>` | Date found from the entry's `created_at`/`timestamp`; if present, optionally append as suffix for chronology. |
|
|
88
|
+
| `<descriptive>.md` with non-kebab chars | kebab-case(normalize) | Spaces/underscores → hyphens; collapse repeats; trim. |
|
|
89
|
+
| Collision (two legacy files normalize to the same slug) | `<slug>-a`, `<slug>-b` | Track the rename in the log; flag the duplicate for dedup in Maintain Step 2 (the collision likely indicates analogs). |
|
|
90
|
+
|
|
91
|
+
## Self-Gate Mechanics
|
|
92
|
+
|
|
93
|
+
The `.migrated` marker is the fast-path check. The slug-set-parity check is the robust path (covers the case where the marker was deleted but the entries migrated). Maintain runs both:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
if docs/learn/.migrated exists OR slug-set(docs/learn/) == slug-set(docs/learnings/):
|
|
97
|
+
migration: no-op (already migrated)
|
|
98
|
+
else:
|
|
99
|
+
run the migration procedure
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Slug-set parity is computed by listing the canonical files' slugs and the legacy files' derived slugs and comparing as sets; full equality = already migrated.
|
|
103
|
+
|
|
104
|
+
## Legacy Store Handling
|
|
105
|
+
|
|
106
|
+
- **Never deleted by the migration.** `docs/learnings/` stays on disk; its files are untouched by the migration's writes (migration only writes to `docs/learn/`). The legacy store becomes read-only in practice (no skill writes to it after migration).
|
|
107
|
+
- **Removal is a separate, explicit prune.** If the user wants to delete `docs/learnings/`, it is a prune operation in Maintain Step 4 (destructive, confirm each) — never part of the migration procedure itself. The recommended default is **keep** (knowledge is rarely deleted; the superseded store is a fallback if a `migrated-from` link needs the original).
|
|
108
|
+
- **The legacy `INDEX.md` is not migrated.** The new `docs/learn/index.md` is built from the canonical entries per [index-format.md](index-format.md). The legacy markdown-table `INDEX.md` is a different format; carrying it over would re-introduce the format-mismatch the canonical hybrid format resolves.
|
|
109
|
+
|
|
110
|
+
## Smart Pause Triggers
|
|
111
|
+
|
|
112
|
+
The migration rewrite is destructive (it rewrites 28 entry paths + every cross-reference). It pauses in Smart mode and **always surfaces in Autopilot** (per [interaction-mode-propagation.md](interaction-mode-propagation.md) — destructive never silent):
|
|
113
|
+
|
|
114
|
+
- The migration will run for the first time (rewrite 28 entries + cross-refs) — confirm before starting.
|
|
115
|
+
- A slug collision was detected during derivation (decide the qualifier; likely an analog for Maintain Step 2).
|
|
116
|
+
- An inferred numeric score from a legacy `severity` value is being recorded (the user may want to override the inference).
|
|
117
|
+
|
|
118
|
+
## Validation (Maintain Step 1 re-checks)
|
|
119
|
+
|
|
120
|
+
- Every legacy file has a corresponding canonical file at `docs/learn/<type>/<slug>.md` with:
|
|
121
|
+
- canonical frontmatter (per [entry-schema.md](entry-schema.md))
|
|
122
|
+
- `migrated-from` set
|
|
123
|
+
- cross-references rewritten to `docs/learn/...`
|
|
124
|
+
- The `.migrated` marker exists with `migrated-at` and `migrated-entries: <N>` matching the count.
|
|
125
|
+
- `docs/learn/index.md` was built from the canonical entries (not the legacy `INDEX.md`).
|
|
126
|
+
- `docs/learnings/` is untouched by the migration writes.
|
|
127
|
+
|
|
128
|
+
## Failure-Condition Reference
|
|
129
|
+
|
|
130
|
+
| Trigger | Outcome per this reference |
|
|
131
|
+
| -------------------------------------------------------- | ------------------------------------------------------- |
|
|
132
|
+
| `docs/learnings/` exists but `docs/learn/` cannot be created (perms) | Category 4 recovery per [error-handling.md](error-handling.md); ask the user to fix perms |
|
|
133
|
+
| A legacy entry's body has an unresolvable cross-ref (target not in the legacy store, not a slug) | Keep the link's prose; log it; the user fixes the target later |
|
|
134
|
+
| Slug-set parity is partial (half-migrated state) | Run the migration for the missing files only; do not rewrite the already-migrated ones (the idempotency invariant) |
|
|
135
|
+
| A collision requires a `-a`/`-b` qualifier | Apply the qualifier, log the rename, flag the analog for Maintain Step 2 (dedup) |
|
|
136
|
+
|
|
137
|
+
## Notes
|
|
138
|
+
|
|
139
|
+
- This reference is the single source of truth for the migration procedure. Maintain invokes it; the modules and the orchestrator never re-derive the slug rules or the frontmatter normalization inline.
|
|
140
|
+
- The migration is **decisions-not-logs** in action: it converts a stale `INDEX.md`-based legacy store into a canonical, schema-conformant knowledge base with lineage — not a session dump. The migration's output is durable knowledge, reorganized and normalized, never a transient record.
|
|
141
|
+
- The `.migrated` marker is a soundness check, not a load-bearing file: deleting it triggers slug-set-parity verification on the next Maintain run, and the migration is a no-op if parity holds. The marker is the fast path, not the gate.
|
|
142
|
+
- The legacy store's `severity` field maps to the canonical `applicability` numeric scores **only** because the canonical enum is derived from those scores ([index-format.md](index-format.md)). The migration does the inference once; the enum derivation happens at index time exactly as it does for new entries.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Captured Entry Artifact
|
|
3
|
+
description: Template for the Captured Entry Artifact produced by the Capture phase. Carries the drafted entry (frontmatter + per-type body per entry-schema), the proposed slug, the learn-id umbrella, the allocate capture-id, the source-candidate trace, and the inferred-flag; consumed by Refine for validation + dedup.
|
|
4
|
+
type: template
|
|
5
|
+
version: 1.0
|
|
6
|
+
timestamp: "2026-08-08"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Captured Entry Artifact
|
|
10
|
+
|
|
11
|
+
The product of the **Capture** phase is a drafted entry — the per-type frontmatter and body per the authoritative [entry-schema.md](../../entry-schema.md) (which Capture looks up, never re-encodes) — plus the proposed `slug`, the allocated `learn-id` umbrella, and the `source-candidate` trace. Refine consumes it for validation + duplicate/analog check. Capture drafts; it does not validate uniqueness or write the file.
|
|
12
|
+
|
|
13
|
+
## Schema
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
capture-id: YYYY-MM-DD-NNN-capture
|
|
17
|
+
learn-id: YYYY-MM-DD-NNN # umbrella id, allocated here, carried through Capture→Refine→Index
|
|
18
|
+
input-shape: explicit | candidate
|
|
19
|
+
interactionMode: detailed | smart | autopilot
|
|
20
|
+
status: complete
|
|
21
|
+
timestamp: ISO-8601 timestamp
|
|
22
|
+
|
|
23
|
+
target-type: decision | pattern | gotcha | workflow # the entry's type; matches the prepared body section template
|
|
24
|
+
slug: "<proposed-kebab-case-slug>" # global, descriptive; Refine uniqueness-checks; Index upserts
|
|
25
|
+
|
|
26
|
+
frontmatter: # authored per entry-schema.md; Capture drafts, Refine validates
|
|
27
|
+
type: <same as target-type>
|
|
28
|
+
slug: <same as above>
|
|
29
|
+
domain: <primary-domain>
|
|
30
|
+
priority: important | normal | null
|
|
31
|
+
applicability: { current_project: <0-10>, general: <0-10> }
|
|
32
|
+
tags: [tag-1, ...]
|
|
33
|
+
created_at: ISO-8601
|
|
34
|
+
updated_at: ISO-8601
|
|
35
|
+
source: { type: commit | candidate | user, reference: <sha | report-id#finding-id | text>, extracted_at: ISO-8601 }
|
|
36
|
+
confidence: high | medium | low | null
|
|
37
|
+
# Lineage fields intentionally absent at capture (set by Maintain/Index on merge/migrate).
|
|
38
|
+
|
|
39
|
+
body: | # the per-type section template per entry-schema.md
|
|
40
|
+
# <Title in Title Case>
|
|
41
|
+
|
|
42
|
+
## Problem
|
|
43
|
+
<drafted from the text/candidate>
|
|
44
|
+
|
|
45
|
+
## Solution / Pattern / Trap / Convention (per type)
|
|
46
|
+
<drafted content>
|
|
47
|
+
|
|
48
|
+
## ...remaining sections for the type... (Decision Rationale / When to Apply / Solution-Prevention / Why / Application / Example / Related Learnings / Source)
|
|
49
|
+
|
|
50
|
+
source-candidate: | null # the picked Work/Review candidate (type, domain, source {finding-id}, summary),
|
|
51
|
+
# or null for explicit input; carried for source traceability
|
|
52
|
+
inferred: true | false # true when drafted from a short description or candidate (a pause trigger);
|
|
53
|
+
# false when grounded in a concrete ref/file the user provided
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Also save the Captured Entry Artifact to `docs/plans/.learn/.capture/<capture-id>.md`.
|
|
57
|
+
|
|
58
|
+
## Validation Rules
|
|
59
|
+
|
|
60
|
+
- **capture-id:** Required. Format `YYYY-MM-DD-NNN-capture` per [id-generation.md](../../id-generation.md).
|
|
61
|
+
- **learn-id:** Required. Allocated by Capture (the umbrella); reuses the capture counter's NNN.
|
|
62
|
+
- **input-shape:** Required. `explicit` or `candidate` (a `maintain` shape must not reach Capture — routing error per [error-handling.md](../../error-handling.md)).
|
|
63
|
+
- **interactionMode:** Required, propagated from the Learn Input Artifact.
|
|
64
|
+
- **status:** Required. `complete`.
|
|
65
|
+
- **target-type:** Required. One of `decision` / `pattern` / `gotcha` / `workflow`.
|
|
66
|
+
- **slug:** Required. Proposed kebab-case; globally unique namespace; descriptive. Refine uniqueness-checks.
|
|
67
|
+
- **frontmatter:** Required. Authored per [entry-schema.md](../../entry-schema.md). Required fields: `type`, `slug`, `domain`, `applicability.current_project`, `applicability.general`, `tags` (2–6), `created_at`, `updated_at`, `source`. Optional: `priority` (default `normal`), `confidence` (default `medium`). Lineage fields (`migrated-from`/`superseded-by`/`related`/`status`) absent at capture.
|
|
68
|
+
- **body:** Required. The per-type section template per [entry-schema.md](../../entry-schema.md) (e.g., a `decision` body has Problem / Solution / Decision Rationale / Application / Related Learnings). Refine validates the sections are present.
|
|
69
|
+
- **source-candidate:** Required (= the picked candidate) when `input-shape: candidate`; `null` when `input-shape: explicit`. Carried so Refine/Index can set the entry's `source` field pointing back at the Work/Review report + finding id.
|
|
70
|
+
- **inferred:** Required. `true` is a Capture Smart pause trigger (the draft was inferred from a short description or candidate — confirm intent).
|
|
71
|
+
|
|
72
|
+
## Example (explicit decision, grounded in a commit ref)
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
capture-id: 2026-08-08-001-capture
|
|
76
|
+
learn-id: 2026-08-08-001
|
|
77
|
+
input-shape: explicit
|
|
78
|
+
interactionMode: smart
|
|
79
|
+
status: complete
|
|
80
|
+
timestamp: 2026-08-08T14:30:00Z
|
|
81
|
+
target-type: decision
|
|
82
|
+
slug: use-pnpm-when-both-lockfiles-exist
|
|
83
|
+
frontmatter:
|
|
84
|
+
type: decision
|
|
85
|
+
slug: use-pnpm-when-both-lockfiles-exist
|
|
86
|
+
domain: tooling
|
|
87
|
+
priority: normal
|
|
88
|
+
applicability: { current_project: 8, general: 6 }
|
|
89
|
+
tags: [package-management, npm, pnpm, lockfiles]
|
|
90
|
+
created_at: 2026-08-08T14:30:00Z
|
|
91
|
+
updated_at: 2026-08-08T14:30:00Z
|
|
92
|
+
source: { type: commit, reference: "1ee04e2", extracted_at: 2026-08-08T14:30:00Z }
|
|
93
|
+
confidence: high
|
|
94
|
+
body: |
|
|
95
|
+
# Use pnpm When Both Lockfiles Exist
|
|
96
|
+
|
|
97
|
+
## Problem
|
|
98
|
+
When a repo has both package-lock.json and pnpm-lock.yaml, invocations must pick one; the wrong choice causes ghost deps.
|
|
99
|
+
|
|
100
|
+
## Solution
|
|
101
|
+
Prefer the lockfile matching package.json's packageManager field; otherwise ask the user.
|
|
102
|
+
|
|
103
|
+
## Decision Rationale
|
|
104
|
+
Reuses the Work skill's Prepare-phase npm-vs-pnpm resolution; one consistent packageManager recorded across phases.
|
|
105
|
+
|
|
106
|
+
## Application
|
|
107
|
+
Work skill Prepare Step 1; Review skill Prepare Step 3 detects the runner + packageManager for the test-context.
|
|
108
|
+
|
|
109
|
+
## Related Learnings
|
|
110
|
+
(none yet)
|
|
111
|
+
source-candidate: null
|
|
112
|
+
inferred: false
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Example (candidate gotcha, inferred from a Work Report)
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
capture-id: 2026-08-08-002-capture
|
|
119
|
+
learn-id: 2026-08-08-002
|
|
120
|
+
input-shape: candidate
|
|
121
|
+
interactionMode: smart
|
|
122
|
+
status: complete
|
|
123
|
+
timestamp: 2026-08-08T14:35:00Z
|
|
124
|
+
target-type: gotcha
|
|
125
|
+
slug: ttl-must-propagate-to-redis-set
|
|
126
|
+
frontmatter:
|
|
127
|
+
type: gotcha
|
|
128
|
+
slug: ttl-must-propagate-to-redis-set
|
|
129
|
+
domain: data-storage
|
|
130
|
+
priority: important
|
|
131
|
+
applicability: { current_project: 8, general: 7 }
|
|
132
|
+
tags: [redis, ttl, session-store, caching]
|
|
133
|
+
created_at: 2026-08-08T14:35:00Z
|
|
134
|
+
updated_at: 2026-08-08T14:35:00Z
|
|
135
|
+
source: { type: candidate, reference: "2026-07-10-001-review#F02", extracted_at: 2026-08-08T14:35:00Z }
|
|
136
|
+
confidence: medium
|
|
137
|
+
body: |
|
|
138
|
+
# Redis TTL Must Propagate to the SET Command
|
|
139
|
+
|
|
140
|
+
## Problem
|
|
141
|
+
The session-store TTL test failed after the green gate.
|
|
142
|
+
|
|
143
|
+
## Trap
|
|
144
|
+
Setting the TTL on the key separately rather than on SET ... EX silently loses the TTL on overwrite.
|
|
145
|
+
|
|
146
|
+
## Solution
|
|
147
|
+
Pass the TTL on SET with EX; do not issue a separate EXPIRE.
|
|
148
|
+
|
|
149
|
+
## Prevention
|
|
150
|
+
Assert the TTL is observable on the next get within the AC test; a separate EXPIRE path fails the test.
|
|
151
|
+
|
|
152
|
+
## Related Learnings
|
|
153
|
+
(none yet)
|
|
154
|
+
|
|
155
|
+
## Source
|
|
156
|
+
2026-07-10-001-review#F02 (redis TTL test blocked at Green gate)
|
|
157
|
+
source-candidate:
|
|
158
|
+
title: "Redis TTL must be propagated to the SET command, not just the key"
|
|
159
|
+
domain: data-storage
|
|
160
|
+
source: { type: candidate, reference: "2026-07-10-001-review#F02" }
|
|
161
|
+
summary: "TTL test failed because SET ... EX must carry the TTL."
|
|
162
|
+
type: gotcha
|
|
163
|
+
inferred: true
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Notes
|
|
167
|
+
|
|
168
|
+
- Capture is the **allocating phase** for the `learn-id` umbrella (see [id-generation.md](../../id-generation.md)); Refine and Index inherit it unchanged.
|
|
169
|
+
- The `slug` is **proposed** here, not validated — Capture never silently collides; Refine's dedup check resolves any exact/analog match per [dedup-rules.md](../../dedup-rules.md).
|
|
170
|
+
- `inferred: true` (a short description or candidate sourced the draft) is the Capture Smart pause trigger; the user confirms the draft matches intent before Refine runs.
|
|
171
|
+
- The frontmatter's `source.reference` for a candidate points at the Work/Review report + finding id (`<review-id>#<finding-id>`) — the traceability link from the durable entry back to where it was first surfaced.
|
|
172
|
+
- Lineage fields are intentionally **absent** at capture — they are set only by Maintain (migration, base-wide merge) or Index (a Refine-time merge), per [entry-schema.md](../../entry-schema.md).
|