@codyswann/lisa 2.296.0 → 2.296.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/dist/core/learnings-contract.d.ts +23 -1
- package/dist/core/learnings-contract.d.ts.map +1 -1
- package/dist/core/learnings-contract.js +26 -2
- package/dist/core/learnings-contract.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/SKILL.md +14 -0
- package/plugins/lisa/skills/lisa-persist-learning/SKILL.md +14 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-persist-learning/SKILL.md +14 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/skills/lisa-persist-learning/SKILL.md +14 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-persist-learning/SKILL.md +14 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/skills/lisa-persist-learning/SKILL.md +14 -0
|
@@ -7,6 +7,28 @@
|
|
|
7
7
|
export declare const LEARNING_CONFIDENCE_VALUES: readonly ["low", "medium", "high"];
|
|
8
8
|
/** Confidence vocabulary persisted in every learning entry. */
|
|
9
9
|
export type LearningConfidence = (typeof LEARNING_CONFIDENCE_VALUES)[number];
|
|
10
|
+
/**
|
|
11
|
+
* Average per-entry byte allowance used to DERIVE the whole-file byte budget
|
|
12
|
+
* (`maxTokens = maxEntries * PER_ENTRY_BYTE_ALLOWANCE`), so the entry cap and
|
|
13
|
+
* the byte cap can never contradict.
|
|
14
|
+
*
|
|
15
|
+
* This is an AVERAGE budget, not a per-entry maximum: `maxTokens` is enforced
|
|
16
|
+
* against the whole rendered document — every entry plus the ```jsonl framing
|
|
17
|
+
* (~72 B observed) — and there is NO per-entry byte cap (`rule` is char-capped
|
|
18
|
+
* at `maxRuleCharacters`; `why` is bounded only by the document total). At 600
|
|
19
|
+
* against a ~490 B observed average, each entry carries ~110 B of headroom, so
|
|
20
|
+
* a full 20-entry ledger budgets 12000 B while real content lands near 9800 B —
|
|
21
|
+
* the ~2.2 KB slack absorbs the document framing many times over and leaves room
|
|
22
|
+
* for larger-than-average entries. A single pathologically large `why` can
|
|
23
|
+
* consume a disproportionate share; that is intended — the document total is the
|
|
24
|
+
* real constraint, and the near-boundary regression test pins that behavior.
|
|
25
|
+
*
|
|
26
|
+
* Historically these were two independently hardcoded numbers — a 20-entry cap
|
|
27
|
+
* and a flat 4000-byte cap — that bound the ledger at ~8 entries, stranding
|
|
28
|
+
* valid captures far under the entry ceiling (CodySwannGT/lisa#1959). Deriving
|
|
29
|
+
* the byte cap from the entry cap removes that contradiction at the source.
|
|
30
|
+
*/
|
|
31
|
+
export declare const PER_ENTRY_BYTE_ALLOWANCE = 600;
|
|
10
32
|
export declare const LEARNINGS_CONTRACT: Readonly<{
|
|
11
33
|
readonly version: 1;
|
|
12
34
|
readonly fields: readonly ["id", "rule", "why", "provenance", "first_learned", "last_confirmed", "confidence"];
|
|
@@ -14,7 +36,7 @@ export declare const LEARNINGS_CONTRACT: Readonly<{
|
|
|
14
36
|
readonly maxRuleLines: 2;
|
|
15
37
|
readonly maxProvenanceReferences: 20;
|
|
16
38
|
readonly maxEntries: 20;
|
|
17
|
-
readonly maxTokens:
|
|
39
|
+
readonly maxTokens: number;
|
|
18
40
|
readonly measurement: "utf8-bytes-upper-bound";
|
|
19
41
|
}>;
|
|
20
42
|
/** Complete persisted schema for one project learning. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-contract.d.ts","sourceRoot":"","sources":["../../src/core/learnings-contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,0BAA0B,oCAAqC,CAAC;AAE7E,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"learnings-contract.d.ts","sourceRoot":"","sources":["../../src/core/learnings-contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,0BAA0B,oCAAqC,CAAC;AAE7E,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAK7E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,eAAO,MAAM,kBAAkB;;;;;;;;;EAiBpB,CAAC;AAEZ,0DAA0D;AAC1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;CACzC;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D"}
|
|
@@ -5,6 +5,30 @@
|
|
|
5
5
|
* @module learnings-contract
|
|
6
6
|
*/
|
|
7
7
|
export const LEARNING_CONFIDENCE_VALUES = ["low", "medium", "high"];
|
|
8
|
+
/** Maximum number of durable entries the ledger retains. */
|
|
9
|
+
const MAX_ENTRIES = 20;
|
|
10
|
+
/**
|
|
11
|
+
* Average per-entry byte allowance used to DERIVE the whole-file byte budget
|
|
12
|
+
* (`maxTokens = maxEntries * PER_ENTRY_BYTE_ALLOWANCE`), so the entry cap and
|
|
13
|
+
* the byte cap can never contradict.
|
|
14
|
+
*
|
|
15
|
+
* This is an AVERAGE budget, not a per-entry maximum: `maxTokens` is enforced
|
|
16
|
+
* against the whole rendered document — every entry plus the ```jsonl framing
|
|
17
|
+
* (~72 B observed) — and there is NO per-entry byte cap (`rule` is char-capped
|
|
18
|
+
* at `maxRuleCharacters`; `why` is bounded only by the document total). At 600
|
|
19
|
+
* against a ~490 B observed average, each entry carries ~110 B of headroom, so
|
|
20
|
+
* a full 20-entry ledger budgets 12000 B while real content lands near 9800 B —
|
|
21
|
+
* the ~2.2 KB slack absorbs the document framing many times over and leaves room
|
|
22
|
+
* for larger-than-average entries. A single pathologically large `why` can
|
|
23
|
+
* consume a disproportionate share; that is intended — the document total is the
|
|
24
|
+
* real constraint, and the near-boundary regression test pins that behavior.
|
|
25
|
+
*
|
|
26
|
+
* Historically these were two independently hardcoded numbers — a 20-entry cap
|
|
27
|
+
* and a flat 4000-byte cap — that bound the ledger at ~8 entries, stranding
|
|
28
|
+
* valid captures far under the entry ceiling (CodySwannGT/lisa#1959). Deriving
|
|
29
|
+
* the byte cap from the entry cap removes that contradiction at the source.
|
|
30
|
+
*/
|
|
31
|
+
export const PER_ENTRY_BYTE_ALLOWANCE = 600;
|
|
8
32
|
export const LEARNINGS_CONTRACT = Object.freeze({
|
|
9
33
|
version: 1,
|
|
10
34
|
fields: Object.freeze([
|
|
@@ -19,8 +43,8 @@ export const LEARNINGS_CONTRACT = Object.freeze({
|
|
|
19
43
|
maxRuleCharacters: 240,
|
|
20
44
|
maxRuleLines: 2,
|
|
21
45
|
maxProvenanceReferences: 20,
|
|
22
|
-
maxEntries:
|
|
23
|
-
maxTokens:
|
|
46
|
+
maxEntries: MAX_ENTRIES,
|
|
47
|
+
maxTokens: MAX_ENTRIES * PER_ENTRY_BYTE_ALLOWANCE,
|
|
24
48
|
measurement: "utf8-bytes-upper-bound",
|
|
25
49
|
});
|
|
26
50
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-contract.js","sourceRoot":"","sources":["../../src/core/learnings-contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAK7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9C,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;QACpB,IAAI;QACJ,MAAM;QACN,KAAK;QACL,YAAY;QACZ,eAAe;QACf,gBAAgB;QAChB,YAAY;KACJ,CAAC;IACX,iBAAiB,EAAE,GAAG;IACtB,YAAY,EAAE,CAAC;IACf,uBAAuB,EAAE,EAAE;IAC3B,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"learnings-contract.js","sourceRoot":"","sources":["../../src/core/learnings-contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAK7E,4DAA4D;AAC5D,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAE5C,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC9C,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;QACpB,IAAI;QACJ,MAAM;QACN,KAAK;QACL,YAAY;QACZ,eAAe;QACf,gBAAgB;QAChB,YAAY;KACJ,CAAC;IACX,iBAAiB,EAAE,GAAG;IACtB,YAAY,EAAE,CAAC;IACf,uBAAuB,EAAE,EAAE;IAC3B,UAAU,EAAE,WAAW;IACvB,SAAS,EAAE,WAAW,GAAG,wBAAwB;IACjD,WAAW,EAAE,wBAAwB;CAC7B,CAAC,CAAC;AAaZ;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,OAAO,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -485,7 +485,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
485
485
|
"plugins/src/base/skills/lisa-parity-sentry-seer/SKILL.md": "f44216fa7c8f0c3c3371c65ff73bbeadd1717579502a5603f16b3b33291cab7a",
|
|
486
486
|
"plugins/src/base/skills/lisa-parity-skill-creator/SKILL.md": "616e0493f75fe92c18137548d7c86a91a9b04d9844ca76fa3f14156e3e7814e5",
|
|
487
487
|
"plugins/src/base/skills/lisa-performance-review/SKILL.md": "351542c256e54940e6d672a70606b8414425c6435ae6f026841bcc02f9fce9c4",
|
|
488
|
-
"plugins/src/base/skills/lisa-persist-learning/SKILL.md": "
|
|
488
|
+
"plugins/src/base/skills/lisa-persist-learning/SKILL.md": "d682b944ae099cdad8c91762b6665b8ef613b58bb8b041335841c116c94dd891",
|
|
489
489
|
"plugins/src/base/skills/lisa-plan/SKILL.md": "9c372e106afd53ff988046119cf36b0f6519c4426775dd8ad3c9d9baeee5d3e2",
|
|
490
490
|
"plugins/src/base/skills/lisa-plugin-sync-explain/SKILL.md": "b41619f3d0d342af2438afd54cb97db7d2445e54e3fc7bb012292079acbc6a4f",
|
|
491
491
|
"plugins/src/base/skills/lisa-posthog-access/SKILL.md": "977aef803160b04312c0408136882ac106d8357caf5063a523e72f265bf20cb1",
|
package/package.json
CHANGED
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"brace-expansion": ">=5.0.6"
|
|
114
114
|
},
|
|
115
115
|
"name": "@codyswann/lisa",
|
|
116
|
-
"version": "2.296.
|
|
116
|
+
"version": "2.296.1",
|
|
117
117
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
118
118
|
"main": "dist/index.js",
|
|
119
119
|
"exports": {
|
|
@@ -174,6 +174,20 @@ No learning content is ever committed without a PR — there is no other write p
|
|
|
174
174
|
- **Related entry found** → consolidate via `persistConsolidatedLearning(projectRoot, entry, { supersede: [<related ids>] })`, merging the old entry's still-true content into the new rule. Never append a near-duplicate sibling — a sibling is a bug that fails review.
|
|
175
175
|
- **No related entry** → append via `persistLearningEntry(projectRoot, entry)` and state in the PR body why appending was correct.
|
|
176
176
|
- Entry mapping: `id` = the fingerprint; `rule`/`why`/`provenance` from the candidate; `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
|
|
177
|
+
- **On a budget-forced drop, signal saturation once (never silent).** When the writer's budget re-assertion cannot fit the entry even after consolidating harder — a durable capture has to be DROPPED for budget — the ledger is saturated, and that pressure must be visible to an operator instead of swallowed. Emit **exactly one** tracker signal via `lisa-tracker-write` (`issue_type: Task`; GitHub trackers carry the `type:Task` label), then continue — dropping the capture never blocks the build. Follow the same marker-dedupe discipline as every other comment here (match on the **marker, never the title**; **exactly one marker per body**; the eventual-consistency guard when the search index is stale), with **one deliberate difference: dedupe against OPEN signals only.** A *closed* saturation ticket means room was already reclaimed, so a fresh saturation is a new actionable event — searching closed tickets too (as the drop/upstream markers do) would permanently suppress every later saturation.
|
|
178
|
+
|
|
179
|
+
The saturation fingerprint keys on the **ledger, not the candidate**, so the signal fires once per saturation episode — never once per capture:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
saturation-fingerprint = "sat-" + first 12 hex chars of sha1(<resolved learnings-file path>)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```markdown
|
|
186
|
+
<!-- [lisa-ledger-saturated] key=<saturation-fingerprint> -->
|
|
187
|
+
Learnings ledger saturated — a durable capture was dropped for budget. The projection is now omitting entries; promote or retire a learning to reclaim room. This is an operator-visible budget-pressure signal, not itself a new learning.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `[lisa-ledger-saturated]` marker sits **outside the `[lisa-learning-*]` namespace** that the gardener (`lisa-learnings-audit`) auto-excludes from candidacy. The gardener already derives budget pressure independently — it measures the entries its `projectLearnings` projection has to omit — so this ticket does not feed that measurement mechanically; its job is an idempotent, operator-visible notification that saturation happened. Keeping it outside `[lisa-learning-*]` matters so the audit tooling does not silently filter it as learning-machinery noise before an operator sees it. **Do not reuse a `[lisa-learning-*]` marker here.** The candidate itself is still dropped; this signal records the saturation, it does not persist the rule.
|
|
177
191
|
4. **Branch + commit.** Work on branch `learning/<fingerprint>`. Commit only the learnings file; verify with `git diff --name-only` that the diff touches nothing else.
|
|
178
192
|
5. **PR body.** Exactly one marker line plus the reviewable story:
|
|
179
193
|
|
|
@@ -174,6 +174,20 @@ No learning content is ever committed without a PR — there is no other write p
|
|
|
174
174
|
- **Related entry found** → consolidate via `persistConsolidatedLearning(projectRoot, entry, { supersede: [<related ids>] })`, merging the old entry's still-true content into the new rule. Never append a near-duplicate sibling — a sibling is a bug that fails review.
|
|
175
175
|
- **No related entry** → append via `persistLearningEntry(projectRoot, entry)` and state in the PR body why appending was correct.
|
|
176
176
|
- Entry mapping: `id` = the fingerprint; `rule`/`why`/`provenance` from the candidate; `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
|
|
177
|
+
- **On a budget-forced drop, signal saturation once (never silent).** When the writer's budget re-assertion cannot fit the entry even after consolidating harder — a durable capture has to be DROPPED for budget — the ledger is saturated, and that pressure must be visible to an operator instead of swallowed. Emit **exactly one** tracker signal via `lisa-tracker-write` (`issue_type: Task`; GitHub trackers carry the `type:Task` label), then continue — dropping the capture never blocks the build. Follow the same marker-dedupe discipline as every other comment here (match on the **marker, never the title**; **exactly one marker per body**; the eventual-consistency guard when the search index is stale), with **one deliberate difference: dedupe against OPEN signals only.** A *closed* saturation ticket means room was already reclaimed, so a fresh saturation is a new actionable event — searching closed tickets too (as the drop/upstream markers do) would permanently suppress every later saturation.
|
|
178
|
+
|
|
179
|
+
The saturation fingerprint keys on the **ledger, not the candidate**, so the signal fires once per saturation episode — never once per capture:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
saturation-fingerprint = "sat-" + first 12 hex chars of sha1(<resolved learnings-file path>)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```markdown
|
|
186
|
+
<!-- [lisa-ledger-saturated] key=<saturation-fingerprint> -->
|
|
187
|
+
Learnings ledger saturated — a durable capture was dropped for budget. The projection is now omitting entries; promote or retire a learning to reclaim room. This is an operator-visible budget-pressure signal, not itself a new learning.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `[lisa-ledger-saturated]` marker sits **outside the `[lisa-learning-*]` namespace** that the gardener (`lisa-learnings-audit`) auto-excludes from candidacy. The gardener already derives budget pressure independently — it measures the entries its `projectLearnings` projection has to omit — so this ticket does not feed that measurement mechanically; its job is an idempotent, operator-visible notification that saturation happened. Keeping it outside `[lisa-learning-*]` matters so the audit tooling does not silently filter it as learning-machinery noise before an operator sees it. **Do not reuse a `[lisa-learning-*]` marker here.** The candidate itself is still dropped; this signal records the saturation, it does not persist the rule.
|
|
177
191
|
4. **Branch + commit.** Work on branch `learning/<fingerprint>`. Commit only the learnings file; verify with `git diff --name-only` that the diff touches nothing else.
|
|
178
192
|
5. **PR body.** Exactly one marker line plus the reviewable story:
|
|
179
193
|
|
|
@@ -174,6 +174,20 @@ No learning content is ever committed without a PR — there is no other write p
|
|
|
174
174
|
- **Related entry found** → consolidate via `persistConsolidatedLearning(projectRoot, entry, { supersede: [<related ids>] })`, merging the old entry's still-true content into the new rule. Never append a near-duplicate sibling — a sibling is a bug that fails review.
|
|
175
175
|
- **No related entry** → append via `persistLearningEntry(projectRoot, entry)` and state in the PR body why appending was correct.
|
|
176
176
|
- Entry mapping: `id` = the fingerprint; `rule`/`why`/`provenance` from the candidate; `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
|
|
177
|
+
- **On a budget-forced drop, signal saturation once (never silent).** When the writer's budget re-assertion cannot fit the entry even after consolidating harder — a durable capture has to be DROPPED for budget — the ledger is saturated, and that pressure must be visible to an operator instead of swallowed. Emit **exactly one** tracker signal via `lisa-tracker-write` (`issue_type: Task`; GitHub trackers carry the `type:Task` label), then continue — dropping the capture never blocks the build. Follow the same marker-dedupe discipline as every other comment here (match on the **marker, never the title**; **exactly one marker per body**; the eventual-consistency guard when the search index is stale), with **one deliberate difference: dedupe against OPEN signals only.** A *closed* saturation ticket means room was already reclaimed, so a fresh saturation is a new actionable event — searching closed tickets too (as the drop/upstream markers do) would permanently suppress every later saturation.
|
|
178
|
+
|
|
179
|
+
The saturation fingerprint keys on the **ledger, not the candidate**, so the signal fires once per saturation episode — never once per capture:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
saturation-fingerprint = "sat-" + first 12 hex chars of sha1(<resolved learnings-file path>)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```markdown
|
|
186
|
+
<!-- [lisa-ledger-saturated] key=<saturation-fingerprint> -->
|
|
187
|
+
Learnings ledger saturated — a durable capture was dropped for budget. The projection is now omitting entries; promote or retire a learning to reclaim room. This is an operator-visible budget-pressure signal, not itself a new learning.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `[lisa-ledger-saturated]` marker sits **outside the `[lisa-learning-*]` namespace** that the gardener (`lisa-learnings-audit`) auto-excludes from candidacy. The gardener already derives budget pressure independently — it measures the entries its `projectLearnings` projection has to omit — so this ticket does not feed that measurement mechanically; its job is an idempotent, operator-visible notification that saturation happened. Keeping it outside `[lisa-learning-*]` matters so the audit tooling does not silently filter it as learning-machinery noise before an operator sees it. **Do not reuse a `[lisa-learning-*]` marker here.** The candidate itself is still dropped; this signal records the saturation, it does not persist the rule.
|
|
177
191
|
4. **Branch + commit.** Work on branch `learning/<fingerprint>`. Commit only the learnings file; verify with `git diff --name-only` that the diff touches nothing else.
|
|
178
192
|
5. **PR body.** Exactly one marker line plus the reviewable story:
|
|
179
193
|
|
|
@@ -174,6 +174,20 @@ No learning content is ever committed without a PR — there is no other write p
|
|
|
174
174
|
- **Related entry found** → consolidate via `persistConsolidatedLearning(projectRoot, entry, { supersede: [<related ids>] })`, merging the old entry's still-true content into the new rule. Never append a near-duplicate sibling — a sibling is a bug that fails review.
|
|
175
175
|
- **No related entry** → append via `persistLearningEntry(projectRoot, entry)` and state in the PR body why appending was correct.
|
|
176
176
|
- Entry mapping: `id` = the fingerprint; `rule`/`why`/`provenance` from the candidate; `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
|
|
177
|
+
- **On a budget-forced drop, signal saturation once (never silent).** When the writer's budget re-assertion cannot fit the entry even after consolidating harder — a durable capture has to be DROPPED for budget — the ledger is saturated, and that pressure must be visible to an operator instead of swallowed. Emit **exactly one** tracker signal via `lisa-tracker-write` (`issue_type: Task`; GitHub trackers carry the `type:Task` label), then continue — dropping the capture never blocks the build. Follow the same marker-dedupe discipline as every other comment here (match on the **marker, never the title**; **exactly one marker per body**; the eventual-consistency guard when the search index is stale), with **one deliberate difference: dedupe against OPEN signals only.** A *closed* saturation ticket means room was already reclaimed, so a fresh saturation is a new actionable event — searching closed tickets too (as the drop/upstream markers do) would permanently suppress every later saturation.
|
|
178
|
+
|
|
179
|
+
The saturation fingerprint keys on the **ledger, not the candidate**, so the signal fires once per saturation episode — never once per capture:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
saturation-fingerprint = "sat-" + first 12 hex chars of sha1(<resolved learnings-file path>)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```markdown
|
|
186
|
+
<!-- [lisa-ledger-saturated] key=<saturation-fingerprint> -->
|
|
187
|
+
Learnings ledger saturated — a durable capture was dropped for budget. The projection is now omitting entries; promote or retire a learning to reclaim room. This is an operator-visible budget-pressure signal, not itself a new learning.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `[lisa-ledger-saturated]` marker sits **outside the `[lisa-learning-*]` namespace** that the gardener (`lisa-learnings-audit`) auto-excludes from candidacy. The gardener already derives budget pressure independently — it measures the entries its `projectLearnings` projection has to omit — so this ticket does not feed that measurement mechanically; its job is an idempotent, operator-visible notification that saturation happened. Keeping it outside `[lisa-learning-*]` matters so the audit tooling does not silently filter it as learning-machinery noise before an operator sees it. **Do not reuse a `[lisa-learning-*]` marker here.** The candidate itself is still dropped; this signal records the saturation, it does not persist the rule.
|
|
177
191
|
4. **Branch + commit.** Work on branch `learning/<fingerprint>`. Commit only the learnings file; verify with `git diff --name-only` that the diff touches nothing else.
|
|
178
192
|
5. **PR body.** Exactly one marker line plus the reviewable story:
|
|
179
193
|
|
|
@@ -174,6 +174,20 @@ No learning content is ever committed without a PR — there is no other write p
|
|
|
174
174
|
- **Related entry found** → consolidate via `persistConsolidatedLearning(projectRoot, entry, { supersede: [<related ids>] })`, merging the old entry's still-true content into the new rule. Never append a near-duplicate sibling — a sibling is a bug that fails review.
|
|
175
175
|
- **No related entry** → append via `persistLearningEntry(projectRoot, entry)` and state in the PR body why appending was correct.
|
|
176
176
|
- Entry mapping: `id` = the fingerprint; `rule`/`why`/`provenance` from the candidate; `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
|
|
177
|
+
- **On a budget-forced drop, signal saturation once (never silent).** When the writer's budget re-assertion cannot fit the entry even after consolidating harder — a durable capture has to be DROPPED for budget — the ledger is saturated, and that pressure must be visible to an operator instead of swallowed. Emit **exactly one** tracker signal via `lisa-tracker-write` (`issue_type: Task`; GitHub trackers carry the `type:Task` label), then continue — dropping the capture never blocks the build. Follow the same marker-dedupe discipline as every other comment here (match on the **marker, never the title**; **exactly one marker per body**; the eventual-consistency guard when the search index is stale), with **one deliberate difference: dedupe against OPEN signals only.** A *closed* saturation ticket means room was already reclaimed, so a fresh saturation is a new actionable event — searching closed tickets too (as the drop/upstream markers do) would permanently suppress every later saturation.
|
|
178
|
+
|
|
179
|
+
The saturation fingerprint keys on the **ledger, not the candidate**, so the signal fires once per saturation episode — never once per capture:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
saturation-fingerprint = "sat-" + first 12 hex chars of sha1(<resolved learnings-file path>)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```markdown
|
|
186
|
+
<!-- [lisa-ledger-saturated] key=<saturation-fingerprint> -->
|
|
187
|
+
Learnings ledger saturated — a durable capture was dropped for budget. The projection is now omitting entries; promote or retire a learning to reclaim room. This is an operator-visible budget-pressure signal, not itself a new learning.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `[lisa-ledger-saturated]` marker sits **outside the `[lisa-learning-*]` namespace** that the gardener (`lisa-learnings-audit`) auto-excludes from candidacy. The gardener already derives budget pressure independently — it measures the entries its `projectLearnings` projection has to omit — so this ticket does not feed that measurement mechanically; its job is an idempotent, operator-visible notification that saturation happened. Keeping it outside `[lisa-learning-*]` matters so the audit tooling does not silently filter it as learning-machinery noise before an operator sees it. **Do not reuse a `[lisa-learning-*]` marker here.** The candidate itself is still dropped; this signal records the saturation, it does not persist the rule.
|
|
177
191
|
4. **Branch + commit.** Work on branch `learning/<fingerprint>`. Commit only the learnings file; verify with `git diff --name-only` that the diff touches nothing else.
|
|
178
192
|
5. **PR body.** Exactly one marker line plus the reviewable story:
|
|
179
193
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.296.
|
|
3
|
+
"version": "2.296.1",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.296.
|
|
3
|
+
"version": "2.296.1",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.296.
|
|
3
|
+
"version": "2.296.1",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.296.
|
|
3
|
+
"version": "2.296.1",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.296.
|
|
3
|
+
"version": "2.296.1",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -174,6 +174,20 @@ No learning content is ever committed without a PR — there is no other write p
|
|
|
174
174
|
- **Related entry found** → consolidate via `persistConsolidatedLearning(projectRoot, entry, { supersede: [<related ids>] })`, merging the old entry's still-true content into the new rule. Never append a near-duplicate sibling — a sibling is a bug that fails review.
|
|
175
175
|
- **No related entry** → append via `persistLearningEntry(projectRoot, entry)` and state in the PR body why appending was correct.
|
|
176
176
|
- Entry mapping: `id` = the fingerprint; `rule`/`why`/`provenance` from the candidate; `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
|
|
177
|
+
- **On a budget-forced drop, signal saturation once (never silent).** When the writer's budget re-assertion cannot fit the entry even after consolidating harder — a durable capture has to be DROPPED for budget — the ledger is saturated, and that pressure must be visible to an operator instead of swallowed. Emit **exactly one** tracker signal via `lisa-tracker-write` (`issue_type: Task`; GitHub trackers carry the `type:Task` label), then continue — dropping the capture never blocks the build. Follow the same marker-dedupe discipline as every other comment here (match on the **marker, never the title**; **exactly one marker per body**; the eventual-consistency guard when the search index is stale), with **one deliberate difference: dedupe against OPEN signals only.** A *closed* saturation ticket means room was already reclaimed, so a fresh saturation is a new actionable event — searching closed tickets too (as the drop/upstream markers do) would permanently suppress every later saturation.
|
|
178
|
+
|
|
179
|
+
The saturation fingerprint keys on the **ledger, not the candidate**, so the signal fires once per saturation episode — never once per capture:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
saturation-fingerprint = "sat-" + first 12 hex chars of sha1(<resolved learnings-file path>)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```markdown
|
|
186
|
+
<!-- [lisa-ledger-saturated] key=<saturation-fingerprint> -->
|
|
187
|
+
Learnings ledger saturated — a durable capture was dropped for budget. The projection is now omitting entries; promote or retire a learning to reclaim room. This is an operator-visible budget-pressure signal, not itself a new learning.
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `[lisa-ledger-saturated]` marker sits **outside the `[lisa-learning-*]` namespace** that the gardener (`lisa-learnings-audit`) auto-excludes from candidacy. The gardener already derives budget pressure independently — it measures the entries its `projectLearnings` projection has to omit — so this ticket does not feed that measurement mechanically; its job is an idempotent, operator-visible notification that saturation happened. Keeping it outside `[lisa-learning-*]` matters so the audit tooling does not silently filter it as learning-machinery noise before an operator sees it. **Do not reuse a `[lisa-learning-*]` marker here.** The candidate itself is still dropped; this signal records the saturation, it does not persist the rule.
|
|
177
191
|
4. **Branch + commit.** Work on branch `learning/<fingerprint>`. Commit only the learnings file; verify with `git diff --name-only` that the diff touches nothing else.
|
|
178
192
|
5. **PR body.** Exactly one marker line plus the reviewable story:
|
|
179
193
|
|