@codyswann/lisa 2.298.1 → 2.299.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 (105) hide show
  1. package/all/copy-contents/.gitattributes +6 -0
  2. package/dist/cli/doctor-readiness-domain.d.ts.map +1 -1
  3. package/dist/cli/doctor-readiness-domain.js +10 -0
  4. package/dist/cli/doctor-readiness-domain.js.map +1 -1
  5. package/dist/cli/doctor-readiness-guardrails.d.ts.map +1 -1
  6. package/dist/cli/doctor-readiness-guardrails.js +10 -4
  7. package/dist/cli/doctor-readiness-guardrails.js.map +1 -1
  8. package/dist/cli/gate-commands.d.ts +8 -6
  9. package/dist/cli/gate-commands.d.ts.map +1 -1
  10. package/dist/cli/gate-commands.js +21 -0
  11. package/dist/cli/gate-commands.js.map +1 -1
  12. package/dist/cli/learnings-overflow-cmd.d.ts +27 -0
  13. package/dist/cli/learnings-overflow-cmd.d.ts.map +1 -0
  14. package/dist/cli/learnings-overflow-cmd.js +57 -0
  15. package/dist/cli/learnings-overflow-cmd.js.map +1 -0
  16. package/dist/core/learnings-alias.d.ts +156 -0
  17. package/dist/core/learnings-alias.d.ts.map +1 -0
  18. package/dist/core/learnings-alias.js +199 -0
  19. package/dist/core/learnings-alias.js.map +1 -0
  20. package/dist/core/learnings-document.d.ts +18 -0
  21. package/dist/core/learnings-document.d.ts.map +1 -1
  22. package/dist/core/learnings-document.js +23 -2
  23. package/dist/core/learnings-document.js.map +1 -1
  24. package/dist/core/learnings-merge-driver.d.ts +8 -33
  25. package/dist/core/learnings-merge-driver.d.ts.map +1 -1
  26. package/dist/core/learnings-merge-driver.js +15 -0
  27. package/dist/core/learnings-merge-driver.js.map +1 -1
  28. package/dist/core/learnings-overflow.d.ts +76 -0
  29. package/dist/core/learnings-overflow.d.ts.map +1 -0
  30. package/dist/core/learnings-overflow.js +212 -0
  31. package/dist/core/learnings-overflow.js.map +1 -0
  32. package/dist/core/learnings-writer.d.ts +6 -0
  33. package/dist/core/learnings-writer.d.ts.map +1 -1
  34. package/dist/core/learnings-writer.js +57 -8
  35. package/dist/core/learnings-writer.js.map +1 -1
  36. package/dist/core/learnings.d.ts +2 -0
  37. package/dist/core/learnings.d.ts.map +1 -1
  38. package/dist/core/learnings.js +2 -0
  39. package/dist/core/learnings.js.map +1 -1
  40. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  41. package/dist/core/upstream-evidence-manifest.js +11 -3
  42. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  43. package/package.json +1 -1
  44. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa/.codex-plugin/skills/lisa-learnings-audit/SKILL.md +42 -6
  47. package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/SKILL.md +7 -2
  48. package/plugins/lisa/skills/lisa-learnings-audit/SKILL.md +42 -6
  49. package/plugins/lisa/skills/lisa-persist-learning/SKILL.md +7 -2
  50. package/plugins/lisa-agy/plugin.json +1 -1
  51. package/plugins/lisa-agy/skills/lisa-learnings-audit/SKILL.md +42 -6
  52. package/plugins/lisa-agy/skills/lisa-persist-learning/SKILL.md +7 -2
  53. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  56. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-copilot/skills/lisa-learnings-audit/SKILL.md +42 -6
  60. package/plugins/lisa-copilot/skills/lisa-persist-learning/SKILL.md +7 -2
  61. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-cursor/skills/lisa-learnings-audit/SKILL.md +42 -6
  63. package/plugins/lisa-cursor/skills/lisa-persist-learning/SKILL.md +7 -2
  64. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-expo-agy/plugin.json +1 -1
  67. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  71. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  72. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  76. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  77. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  81. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  82. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  86. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  87. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  91. package/plugins/lisa-rails-agy/plugin.json +1 -1
  92. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  96. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  97. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  100. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  101. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  102. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  104. package/plugins/src/base/skills/lisa-learnings-audit/SKILL.md +42 -6
  105. package/plugins/src/base/skills/lisa-persist-learning/SKILL.md +7 -2
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Reference survival across supersede-in-place consolidation.
3
+ *
4
+ * ## The problem
5
+ *
6
+ * `persistConsolidatedLearning(..., { supersede: [ids] })` removes the
7
+ * superseded entries and adds a new one under the caller's own id — the
8
+ * learner's content fingerprint. So every consolidation churns the id, and
9
+ * anything that had cited the old id (a tracker comment, a gardener ticket, a
10
+ * cross-link from another learning) silently points at an entry that no longer
11
+ * exists (CodySwannGT/lisa#1997).
12
+ *
13
+ * ## Why an alias map and NOT "carry the earliest superseded id forward"
14
+ *
15
+ * The issue offered both. Carry-forward was implemented first and had to be
16
+ * abandoned, because the churning fingerprint id is doing a second job nobody
17
+ * wrote down: it is an accidental **compare-and-swap token**.
18
+ *
19
+ * Two learner passes racing to consolidate the same entry `base` each hold a
20
+ * stale snapshot. Today the first writer removes `base` and lands under `a`; the
21
+ * second finds `base` already gone, is tolerated rather than fatal (#1995), and
22
+ * lands under `b`. Both learnings survive — "at worst two entries where one
23
+ * consolidation was intended," exactly the cost the writer documents.
24
+ *
25
+ * Carry the id forward and that protection evaporates: the first writer lands
26
+ * under `base`, so the second writer's stale "supersede base" now MATCHES,
27
+ * removes the first writer's entry, and overwrites it. `learnings-supersede-race`
28
+ * proves the damage — nine writers consolidating one target went from nine
29
+ * preserved learnings to **one**, destroying eight. That is the #1995 data-loss
30
+ * symptom re-opened, which the brief explicitly forbids.
31
+ *
32
+ * The fix is undecidable from the seven fields alone: a stale "supersede base"
33
+ * and a legitimate chained "supersede base" are the same bytes. Telling them
34
+ * apart needs a real version token — the fingerprint retained as an eighth,
35
+ * disambiguating field, per the issue's parenthetical. That is a persisted-schema
36
+ * change: a contract version bump propagated through every reader, the merge
37
+ * driver, the CI budget gate, and all six plugin skill projections. It is the
38
+ * principled long-term answer and it deserves its own change.
39
+ *
40
+ * So this takes the issue's second option. Ids keep churning — the CAS token,
41
+ * the #1995 guarantee, and the fingerprint-is-the-id dedupe model are all left
42
+ * exactly as they are — and references survive because the consolidated entry
43
+ * *records what it replaced*.
44
+ *
45
+ * ## Where the map lives
46
+ *
47
+ * In the entry's own `provenance`, as `supersedes:<old id>` references. No new
48
+ * field, no new file, no new format: provenance is already a validated,
49
+ * rendered, merged, budget-counted list of stable references, and "this entry
50
+ * replaced that one" is precisely a provenance claim.
51
+ *
52
+ * Resolution is ONE HOP, never transitive. When an entry is consolidated, the
53
+ * writer copies the removed entries' own alias references forward, so a lineage
54
+ * `base → a → b` leaves `b` carrying both `supersedes:a` and `supersedes:base`.
55
+ * There is no chain for a reader to walk and therefore no cycle or depth limit
56
+ * to get wrong.
57
+ *
58
+ * An alias is recorded ONLY for a target that was actually present and removed.
59
+ * A supersede naming an already-consolidated id removed nothing, so claiming its
60
+ * reference would hijack a pointer that the earlier writer legitimately owns —
61
+ * in the nine-writer race, only the one writer that truly removed `base` claims
62
+ * `base`, and the reference stays unambiguous.
63
+ * @module core/learnings-alias
64
+ */
65
+ import { LEARNINGS_CONTRACT, } from "./learnings-contract.js";
66
+ /** Prefix marking a provenance reference as a superseded-id alias. */
67
+ export const SUPERSEDES_PREFIX = "supersedes:";
68
+ /**
69
+ * Build the provenance reference recording that an entry replaced another.
70
+ * @param id - Id of the entry that was removed
71
+ * @returns Canonical alias reference
72
+ */
73
+ export function buildSupersedesReference(id) {
74
+ return `${SUPERSEDES_PREFIX}${id}`;
75
+ }
76
+ /**
77
+ * Reject a caller trying to mint its own `supersedes:` reference.
78
+ *
79
+ * The prefix is WRITER-OWNED. An alias is a factual claim that this write
80
+ * removed that entry, and the writer is the only party that knows whether it
81
+ * did — so a hand-written `supersedes:<id>` would let any caller capture a
82
+ * reference to an entry it never touched, silently redirecting an old id at
83
+ * content of its choosing.
84
+ *
85
+ * This lives at the writer's entry point rather than inside
86
+ * `validateLearningEntry` on purpose: that validator also runs on every entry
87
+ * parsed back off disk and on every side of a merge, where writer-added
88
+ * `supersedes:` references are legitimate and must be accepted. Rejecting there
89
+ * would make the contract unable to read its own output.
90
+ * @param entry - Validated entry exactly as the caller composed it
91
+ * @returns The rejection to throw, or undefined when the provenance is clean
92
+ */
93
+ export function findCallerMintedAliasError(entry) {
94
+ const minted = entry.provenance.filter(reference => reference.startsWith(SUPERSEDES_PREFIX));
95
+ return minted.length === 0
96
+ ? undefined
97
+ : new Error(`Invalid provenance: '${SUPERSEDES_PREFIX}' references are added by the writer, not the caller (found ${minted.join(", ")})`);
98
+ }
99
+ /**
100
+ * Read the ids one entry declares it superseded.
101
+ * @param entry - Validated learning entry
102
+ * @returns Superseded ids, in the order they were recorded
103
+ */
104
+ export function readSupersededIds(entry) {
105
+ return entry.provenance
106
+ .filter(reference => reference.startsWith(SUPERSEDES_PREFIX))
107
+ .map(reference => reference.slice(SUPERSEDES_PREFIX.length))
108
+ .filter(id => id !== "");
109
+ }
110
+ /**
111
+ * Compose the alias references a consolidated entry must carry.
112
+ *
113
+ * Ordering is oldest-lineage-first: the ids inherited from the removed entries
114
+ * come before the removed entries' own ids, so the reference that has existed
115
+ * longest sits earliest and survives longest under the cap below.
116
+ *
117
+ * An entry that supersedes its OWN id is editing itself in place, not renaming
118
+ * itself — the reference never broke, so it earns no alias. Its inherited
119
+ * lineage is still carried forward, because an in-place edit must not drop the
120
+ * ancestors that already resolve through it.
121
+ * @param removed - Entries this write actually removed from the document
122
+ * @param selfId - Id of the entry being written
123
+ * @returns Deduplicated alias references in lineage order
124
+ */
125
+ function composeAliasReferences(removed, selfId) {
126
+ const inherited = removed.flatMap(entry => readSupersededIds(entry));
127
+ const direct = removed.map(entry => entry.id);
128
+ return [...new Set([...inherited, ...direct])]
129
+ .filter(id => id !== selfId)
130
+ .map(buildSupersedesReference);
131
+ }
132
+ /**
133
+ * Fold alias references into a caller's provenance within the contract cap.
134
+ *
135
+ * Caller-supplied provenance is NEVER sacrificed for an alias. It is the
136
+ * evidence the learning rests on — the tracker links and commits that justify
137
+ * the rule existing at all — while an alias is a convenience for finding the
138
+ * entry by a name it used to have. Evicting evidence to store a convenience
139
+ * would quietly delete the reason a learning is believed.
140
+ *
141
+ * When the two together exceed `maxProvenanceReferences`, the NEWEST aliases
142
+ * drop first, so the oldest surviving reference is kept longest. An alias gets
143
+ * MORE valuable as it ages, not less: an id that churned in this very pull
144
+ * request is still discoverable from the branch, the commit, and the capture
145
+ * report, whereas a months-old tracker comment citing an old id has no other
146
+ * way home — and silently breaking exactly those references is what
147
+ * CodySwannGT/lisa#1997 exists to fix. (An earlier revision dropped oldest-first
148
+ * on the theory that ancient references were probably already closed out; that
149
+ * has it backwards. A closed ticket citing an id is precisely where someone
150
+ * searching history lands.)
151
+ * @param entry - New entry as the caller composed it
152
+ * @param removed - Entries this write actually removed from the document
153
+ * @returns Merged provenance plus any alias references that did not fit
154
+ */
155
+ export function applySupersedeAliases(entry, removed) {
156
+ const provenance = entry.provenance;
157
+ const existing = new Set(provenance);
158
+ const aliases = composeAliasReferences(removed, entry.id).filter(reference => !existing.has(reference));
159
+ const room = Math.max(0, LEARNINGS_CONTRACT.maxProvenanceReferences - provenance.length);
160
+ return {
161
+ provenance: [...provenance, ...aliases.slice(0, room)],
162
+ dropped: aliases.slice(room),
163
+ };
164
+ }
165
+ /**
166
+ * Resolve every entry an id could refer to, live id first.
167
+ *
168
+ * A live id always wins: if an entry still carries the id, that entry IS the
169
+ * reference and no alias can shadow it.
170
+ *
171
+ * More than one entry can claim the same alias in exactly one situation — the
172
+ * union merge driver joined two branches that had each removed the same target
173
+ * — so this returns all claimants in deterministic id order rather than
174
+ * pretending the ambiguity away. {@link resolveLearningReference} takes the
175
+ * first for callers that just need a pointer.
176
+ * @param entries - Validated entries from the document
177
+ * @param id - Possibly-superseded id to resolve
178
+ * @returns Matching entries, deterministically ordered
179
+ */
180
+ export function resolveLearningReferences(entries, id) {
181
+ const live = entries.find(entry => entry.id === id);
182
+ if (live !== undefined) {
183
+ return [live];
184
+ }
185
+ const alias = buildSupersedesReference(id);
186
+ return entries
187
+ .filter(entry => entry.provenance.includes(alias))
188
+ .sort((left, right) => (left.id < right.id ? -1 : 1));
189
+ }
190
+ /**
191
+ * Resolve one id to the entry that now carries its content.
192
+ * @param entries - Validated entries from the document
193
+ * @param id - Possibly-superseded id to resolve
194
+ * @returns The entry the reference now points at, when one exists
195
+ */
196
+ export function resolveLearningReference(entries, id) {
197
+ return resolveLearningReferences(entries, id)[0];
198
+ }
199
+ //# sourceMappingURL=learnings-alias.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-alias.js","sourceRoot":"","sources":["../../src/core/learnings-alias.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,24 @@ export declare function renderLearningsFile(entries: readonly LearningEntry[]):
17
17
  * @returns Revalidated entries from the document
18
18
  */
19
19
  export declare function parseLearningsFile(content: string): LearningEntry[];
20
+ /**
21
+ * A document that does not fit the hard entry-count or token budget.
22
+ *
23
+ * Typed so the writer can tell "this capture has nowhere to go" apart from every
24
+ * other write failure. That distinction is load-bearing: a budget breach is the
25
+ * one failure whose dropped CONTENT is still worth preserving in the overflow
26
+ * file (CodySwannGT/lisa#1996), whereas an unsafe path or a corrupted document
27
+ * must fail outright rather than have content salvaged out of it. The messages
28
+ * are unchanged from the plain-`Error` era so existing diagnostics and their
29
+ * assertions still read the same.
30
+ */
31
+ export declare class LearningsBudgetError extends Error {
32
+ /**
33
+ * Build a budget breach carrying the caller-facing diagnosis.
34
+ * @param message - Single-line budget diagnosis
35
+ */
36
+ constructor(message: string);
37
+ }
20
38
  /**
21
39
  * Enforce the shared entry-count and model-agnostic token upper bounds.
22
40
  * @param content - Canonical document
@@ -1 +1 @@
1
- {"version":3,"file":"learnings-document.d.ts","sourceRoot":"","sources":["../../src/core/learnings-document.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,yBAAyB,CAAC;AA+BjC;;;GAGG;AACH,eAAO,MAAM,yBAAyB,0DACmB,CAAC;AAE1D;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAG7E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CA8BnE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,IAAI,CAYN;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK1E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAIvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,UAAU,GACjB,MAAM,GAAG,SAAS,CAEpB"}
1
+ {"version":3,"file":"learnings-document.d.ts","sourceRoot":"","sources":["../../src/core/learnings-document.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,yBAAyB,CAAC;AA+BjC;;;GAGG;AACH,eAAO,MAAM,yBAAyB,0DACmB,CAAC;AAE1D;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAG7E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CA8BnE;AAED;;;;;;;;;;GAUG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C;;;OAGG;gBACS,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,IAAI,CAYN;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK1E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAIvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,UAAU,GACjB,MAAM,GAAG,SAAS,CAEpB"}
@@ -71,6 +71,27 @@ export function parseLearningsFile(content) {
71
71
  assertDocumentBudget(content, entries.length, "Project learnings payload");
72
72
  return entries;
73
73
  }
74
+ /**
75
+ * A document that does not fit the hard entry-count or token budget.
76
+ *
77
+ * Typed so the writer can tell "this capture has nowhere to go" apart from every
78
+ * other write failure. That distinction is load-bearing: a budget breach is the
79
+ * one failure whose dropped CONTENT is still worth preserving in the overflow
80
+ * file (CodySwannGT/lisa#1996), whereas an unsafe path or a corrupted document
81
+ * must fail outright rather than have content salvaged out of it. The messages
82
+ * are unchanged from the plain-`Error` era so existing diagnostics and their
83
+ * assertions still read the same.
84
+ */
85
+ export class LearningsBudgetError extends Error {
86
+ /**
87
+ * Build a budget breach carrying the caller-facing diagnosis.
88
+ * @param message - Single-line budget diagnosis
89
+ */
90
+ constructor(message) {
91
+ super(message);
92
+ this.name = "LearningsBudgetError";
93
+ }
94
+ }
74
95
  /**
75
96
  * Enforce the shared entry-count and model-agnostic token upper bounds.
76
97
  * @param content - Canonical document
@@ -79,11 +100,11 @@ export function parseLearningsFile(content) {
79
100
  */
80
101
  export function assertDocumentBudget(content, entryCount, context) {
81
102
  if (entryCount > LEARNINGS_CONTRACT.maxEntries) {
82
- throw new Error(`${context} exceeds maxEntries: measured ${entryCount}, allowed ${LEARNINGS_CONTRACT.maxEntries}`);
103
+ throw new LearningsBudgetError(`${context} exceeds maxEntries: measured ${entryCount}, allowed ${LEARNINGS_CONTRACT.maxEntries}`);
83
104
  }
84
105
  const estimatedTokens = estimateLearningTokens(content);
85
106
  if (estimatedTokens > LEARNINGS_CONTRACT.maxTokens) {
86
- throw new Error(`${context} exceeds maxTokens ${LEARNINGS_CONTRACT.maxTokens} (measured ${estimatedTokens})`);
107
+ throw new LearningsBudgetError(`${context} exceeds maxTokens ${LEARNINGS_CONTRACT.maxTokens} (measured ${estimatedTokens})`);
87
108
  }
88
109
  }
89
110
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"learnings-document.js","sourceRoot":"","sources":["../../src/core/learnings-document.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"learnings-document.js","sourceRoot":"","sources":["../../src/core/learnings-document.ts"],"names":[],"mappings":"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"}
@@ -1,36 +1,3 @@
1
- /**
2
- * Registration contract for the project-learnings union merge driver.
3
- *
4
- * A git merge driver has two halves that live in different places:
5
- *
6
- * 1. **The attribute** (`.gitattributes`) says WHICH driver a path uses. It is
7
- * a committed file, so Lisa ships it to the repository and to every host
8
- * project through the template pipeline.
9
- * 2. **The driver command** (`merge.<name>.driver`) says HOW to run it. Git
10
- * deliberately keeps this in machine-local config and never reads it from
11
- * the repository, because a committed driver command would let a cloned
12
- * repository execute arbitrary code on `git merge`.
13
- *
14
- * So the attribute alone is inert. Until the command is registered, git falls
15
- * back to its built-in text merge — which is exactly today's behavior, so an
16
- * unregistered checkout is degraded, never broken. That fallback is asserted in
17
- * `tests/unit/core/learnings-merge-driver.test.ts`.
18
- *
19
- * Registration is AUTOMATIC, not operator-initiated. `EnsureLearningsMergeDriver`
20
- * runs on every `lisa apply`, and the TypeScript stack's `package.lisa.json`
21
- * wires `lisa apply` into `postinstall` — so an ordinary `npm install` in a host
22
- * project writes `merge.lisa-learnings.driver` into `.git/config` with no
23
- * separate human step, and against Lisa's own repository too.
24
- *
25
- * That is worth stating plainly because of what it implies: the registration
26
- * persists an executable hook in local git config that fires on ordinary git
27
- * operations, outside npm's lifecycle. It is not an escalation over `npm
28
- * install` itself (which already runs arbitrary code), but it does outlive it.
29
- * Hosts that would rather not carry that hook set `learnings.mergeDriver: false`
30
- * in `.lisa.config.json`; `lisa install-merge-driver` remains available to
31
- * register it by hand in a clone that apply has not touched.
32
- * @module core/learnings-merge-driver
33
- */
34
1
  /** Git merge-driver name shared by `.gitattributes` and the local git config. */
35
2
  export declare const LEARNINGS_MERGE_DRIVER_NAME = "lisa-learnings";
36
3
  /** Human-readable driver name recorded alongside the command. */
@@ -76,6 +43,14 @@ export declare function buildLearningsAttributeLine(ledgerPath: string): string;
76
43
  * Wrapped in the same guardrail markers the `.gitignore` template uses, so the
77
44
  * `copy-contents` strategy replaces exactly this block on re-apply and leaves
78
45
  * every host-authored rule outside it untouched.
46
+ *
47
+ * Both halves of the learnings surface are bound. The overflow file
48
+ * (CodySwannGT/lisa#1996) is written by the same concurrent learner passes, on
49
+ * the same per-fingerprint branches, in the same canonical document format — so
50
+ * it has the ledger's exact merge problem and the exact same union-by-id
51
+ * resolution. Binding only the ledger would leave the overflow on git's default
52
+ * text merge, silently re-introducing the corruption this driver exists to
53
+ * remove, on the one file whose whole job is not losing content.
79
54
  * @param ledgerPath - Project-relative learnings file path
80
55
  * @returns Managed block, newline-terminated
81
56
  */
@@ -1 +1 @@
1
- {"version":3,"file":"learnings-merge-driver.d.ts","sourceRoot":"","sources":["../../src/core/learnings-merge-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,mBAAmB,CAAC;AAE5D,iEAAiE;AACjE,eAAO,MAAM,kCAAkC,wCACR,CAAC;AAExC,wEAAwE;AACxE,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AAEnE,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,yBAAyB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAa5E"}
1
+ {"version":3,"file":"learnings-merge-driver.d.ts","sourceRoot":"","sources":["../../src/core/learnings-merge-driver.ts"],"names":[],"mappings":"AAmCA,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,mBAAmB,CAAC;AAE5D,iEAAiE;AACjE,eAAO,MAAM,kCAAkC,wCACR,CAAC;AAExC,wEAAwE;AACxE,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AAEnE,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,yBAAyB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iCAAiC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAmB5E"}
@@ -31,6 +31,7 @@
31
31
  * register it by hand in a clone that apply has not touched.
32
32
  * @module core/learnings-merge-driver
33
33
  */
34
+ import { resolveLearningsOverflowFile } from "./learnings-overflow.js";
34
35
  /** Git merge-driver name shared by `.gitattributes` and the local git config. */
35
36
  export const LEARNINGS_MERGE_DRIVER_NAME = "lisa-learnings";
36
37
  /** Human-readable driver name recorded alongside the command. */
@@ -80,6 +81,14 @@ export function buildLearningsAttributeLine(ledgerPath) {
80
81
  * Wrapped in the same guardrail markers the `.gitignore` template uses, so the
81
82
  * `copy-contents` strategy replaces exactly this block on re-apply and leaves
82
83
  * every host-authored rule outside it untouched.
84
+ *
85
+ * Both halves of the learnings surface are bound. The overflow file
86
+ * (CodySwannGT/lisa#1996) is written by the same concurrent learner passes, on
87
+ * the same per-fingerprint branches, in the same canonical document format — so
88
+ * it has the ledger's exact merge problem and the exact same union-by-id
89
+ * resolution. Binding only the ledger would leave the overflow on git's default
90
+ * text merge, silently re-introducing the corruption this driver exists to
91
+ * remove, on the one file whose whole job is not losing content.
83
92
  * @param ledgerPath - Project-relative learnings file path
84
93
  * @returns Managed block, newline-terminated
85
94
  */
@@ -93,6 +102,12 @@ export function renderLearningsGitattributesBlock(ledgerPath) {
93
102
  "# command is machine-local — run `lisa install-merge-driver` to register it.",
94
103
  buildLearningsAttributeLine(ledgerPath),
95
104
  "",
105
+ "# The overflow buffer holds captures the ledger had no budget for, until",
106
+ "# the gardener drains them. Same writers, same branches, same format — so",
107
+ "# it needs the same union merge, or a merge could destroy the very content",
108
+ "# it exists to preserve.",
109
+ buildLearningsAttributeLine(resolveLearningsOverflowFile(ledgerPath)),
110
+ "",
96
111
  GITATTRIBUTES_END_MARKER,
97
112
  "",
98
113
  ].join("\n");
@@ -1 +1 @@
1
- {"version":3,"file":"learnings-merge-driver.js","sourceRoot":"","sources":["../../src/core/learnings-merge-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC;AAE5D,iEAAiE;AACjE,MAAM,CAAC,MAAM,kCAAkC,GAC7C,qCAAqC,CAAC;AAExC,wEAAwE;AACxE,MAAM,CAAC,MAAM,0BAA0B,GAAG,wBAAwB,CAAC;AAEnE,wEAAwE;AACxE,MAAM,CAAC,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,gCAAgC,CAAC,UAAkB;IACjE,OAAO,GAAG,UAAU,4DAA4D,CAAC;AACnF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,UAAkB;IAC5D,OAAO,GAAG,UAAU,UAAU,2BAA2B,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iCAAiC,CAAC,UAAkB;IAClE,OAAO;QACL,0BAA0B;QAC1B,EAAE;QACF,6EAA6E;QAC7E,2EAA2E;QAC3E,0EAA0E;QAC1E,8EAA8E;QAC9E,2BAA2B,CAAC,UAAU,CAAC;QACvC,EAAE;QACF,wBAAwB;QACxB,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"learnings-merge-driver.js","sourceRoot":"","sources":["../../src/core/learnings-merge-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAEvE,iFAAiF;AACjF,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC;AAE5D,iEAAiE;AACjE,MAAM,CAAC,MAAM,kCAAkC,GAC7C,qCAAqC,CAAC;AAExC,wEAAwE;AACxE,MAAM,CAAC,MAAM,0BAA0B,GAAG,wBAAwB,CAAC;AAEnE,wEAAwE;AACxE,MAAM,CAAC,MAAM,wBAAwB,GAAG,sBAAsB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,gCAAgC,CAAC,UAAkB;IACjE,OAAO,GAAG,UAAU,4DAA4D,CAAC;AACnF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,UAAkB;IAC5D,OAAO,GAAG,UAAU,UAAU,2BAA2B,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,iCAAiC,CAAC,UAAkB;IAClE,OAAO;QACL,0BAA0B;QAC1B,EAAE;QACF,6EAA6E;QAC7E,2EAA2E;QAC3E,0EAA0E;QAC1E,8EAA8E;QAC9E,2BAA2B,CAAC,UAAU,CAAC;QACvC,EAAE;QACF,0EAA0E;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,0BAA0B;QAC1B,2BAA2B,CAAC,4BAA4B,CAAC,UAAU,CAAC,CAAC;QACrE,EAAE;QACF,wBAAwB;QACxB,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { type LearningEntry } from "./learnings-contract.js";
2
+ import { LearningsBudgetError } from "./learnings-document.js";
3
+ /**
4
+ * Derive the overflow path from a project's configured ledger path.
5
+ *
6
+ * Derived rather than separately configurable so a project that relocates its
7
+ * ledger through `learnings.file` cannot end up with the two halves of one
8
+ * mechanism in different directories — and so there is no second config key to
9
+ * validate, contain, and keep in sync.
10
+ * @param learningsFile - Project-relative ledger path
11
+ * @returns Project-relative overflow path
12
+ */
13
+ export declare function resolveLearningsOverflowFile(learningsFile: string): string;
14
+ /** Entries currently awaiting drain, and where they live. */
15
+ export interface LearningsOverflowContents {
16
+ /** Absolute overflow path, whether or not the file exists yet. */
17
+ readonly file: string;
18
+ /** Validated entries awaiting drain. */
19
+ readonly entries: readonly LearningEntry[];
20
+ }
21
+ /**
22
+ * Read the overflow without modifying it.
23
+ *
24
+ * An absent file is the common, expected case and reads as empty — a project
25
+ * that has never dropped a capture must not have to special-case its absence.
26
+ * @param projectRoot - Absolute path to the host project root
27
+ * @returns Overflow path and the entries awaiting drain
28
+ */
29
+ export declare function readLearningsOverflow(projectRoot: string): Promise<LearningsOverflowContents>;
30
+ /** Outcome of draining entries the gardener has finished with. */
31
+ export interface LearningsOverflowDrain {
32
+ /** Absolute overflow path. */
33
+ readonly file: string;
34
+ /** Ids that were present and have now been removed. */
35
+ readonly drained: readonly string[];
36
+ /** Requested ids that were not in the overflow — reported, never fatal. */
37
+ readonly absent: readonly string[];
38
+ /** How many entries still await drain. */
39
+ readonly remaining: number;
40
+ }
41
+ /**
42
+ * Remove entries the gardener has durably captured elsewhere.
43
+ *
44
+ * Drain is BY ID and never "empty the file", because the gardener's real
45
+ * sequence is read → file a ticket per entry → drain. Clearing everything up
46
+ * front would lose any entry whose ticket failed to file; removing only the ids
47
+ * that already have a durable home makes a partial run safely resumable.
48
+ *
49
+ * An unknown id is reported rather than thrown, for the same reason an absent
50
+ * supersede target is tolerated: on a re-run, an id another pass already drained
51
+ * is indistinguishable from a bogus one, and failing the drain would strand
52
+ * every other entry in the batch.
53
+ * @param projectRoot - Absolute path to the host project root
54
+ * @param ids - Entry ids to remove
55
+ * @returns Which ids were drained, which were absent, and what remains
56
+ */
57
+ export declare function drainLearningsOverflow(projectRoot: string, ids: readonly string[]): Promise<LearningsOverflowDrain>;
58
+ /**
59
+ * Preserve a capture the ledger had no budget for, then re-raise the breach.
60
+ *
61
+ * Never returns normally: the capture genuinely did not land in the ledger, and
62
+ * a caller that treated preservation as success would report a learning as
63
+ * persisted when the projection will never serve it. The re-raised error names
64
+ * the overflow file so the drop is actionable rather than merely fatal.
65
+ *
66
+ * If the overflow is itself full, the original ledger breach is re-raised with
67
+ * both surfaces named. Nothing is evicted to make room — silently discarding an
68
+ * older dropped learning to store a newer one is the exact data loss this whole
69
+ * mechanism exists to prevent.
70
+ * @param projectRoot - Absolute path to the host project root
71
+ * @param entry - The validated entry the ledger rejected
72
+ * @param breach - The budget breach the ledger write raised
73
+ * @returns Never — always throws
74
+ */
75
+ export declare function preserveDroppedLearning(projectRoot: string, entry: LearningEntry, breach: LearningsBudgetError): Promise<never>;
76
+ //# sourceMappingURL=learnings-overflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learnings-overflow.d.ts","sourceRoot":"","sources":["../../src/core/learnings-overflow.ts"],"names":[],"mappings":"AAkDA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,oBAAoB,EAIrB,MAAM,yBAAyB,CAAC;AAejC;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAI1E;AAmCD,6DAA6D;AAC7D,MAAM,WAAW,yBAAyB;IACxC,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CAC5C;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,yBAAyB,CAAC,CAGpC;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,SAAS,MAAM,EAAE,GACrB,OAAO,CAAC,sBAAsB,CAAC,CAwBjC;AAqBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,KAAK,CAAC,CAyBhB"}