@codyswann/lisa 4.6.3 → 4.6.4
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/cli/check-learnings-budget-cmd.d.ts +3 -2
- package/dist/cli/check-learnings-budget-cmd.d.ts.map +1 -1
- package/dist/cli/check-learnings-budget-cmd.js +11 -4
- package/dist/cli/check-learnings-budget-cmd.js.map +1 -1
- package/dist/core/learnings-budget-check.d.ts +84 -0
- package/dist/core/learnings-budget-check.d.ts.map +1 -1
- package/dist/core/learnings-budget-check.js +88 -1
- package/dist/core/learnings-budget-check.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-agy/plugin.json +1 -1
- 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-cursor/.claude-plugin/plugin.json +1 -1
- 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/scripts/check-learnings-budget.ts +94 -31
|
@@ -9,8 +9,9 @@ export interface CheckLearningsBudgetDependencies {
|
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* Run the budget check for one project and return the intended process exit
|
|
12
|
-
* code (0 pass or missing
|
|
13
|
-
* condition — a missing learnings file resolves to a silent,
|
|
12
|
+
* code (0 pass, saturated, or missing; 1 violation). Never throws for an
|
|
13
|
+
* expected condition — a missing learnings file resolves to a silent,
|
|
14
|
+
* successful pass.
|
|
14
15
|
* @param fileArg - Optional explicit learnings file to check (default: resolved
|
|
15
16
|
* from `.lisa.config.json`)
|
|
16
17
|
* @param dependencies - Injectable collaborators for tests
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-learnings-budget-cmd.d.ts","sourceRoot":"","sources":["../../src/cli/check-learnings-budget-cmd.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"check-learnings-budget-cmd.d.ts","sourceRoot":"","sources":["../../src/cli/check-learnings-budget-cmd.ts"],"names":[],"mappings":"AA0BA,oEAAoE;AACpE,MAAM,WAAW,gCAAgC;IAC/C,qEAAqE;IACrE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C;AAoBD;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,YAAY,GAAE,gCAAqC,GAClD,OAAO,CAAC,MAAM,CAAC,CA2BjB"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* @module cli/check-learnings-budget-cmd
|
|
15
15
|
*/
|
|
16
16
|
import * as path from "node:path";
|
|
17
|
-
import { checkLearningsBudget, formatDiagnosticPath, } from "../core/learnings-budget-check.js";
|
|
17
|
+
import { checkLearningsBudget, formatBudgetVerdict, formatDiagnosticPath, } from "../core/learnings-budget-check.js";
|
|
18
18
|
import { readProjectConfig, resolveProjectLearningsFile, } from "../core/project-config.js";
|
|
19
19
|
/**
|
|
20
20
|
* Resolve the learnings file to check: an explicit path argument wins;
|
|
@@ -32,8 +32,9 @@ async function resolveLearningsPath(fileArg, cwd) {
|
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Run the budget check for one project and return the intended process exit
|
|
35
|
-
* code (0 pass or missing
|
|
36
|
-
* condition — a missing learnings file resolves to a silent,
|
|
35
|
+
* code (0 pass, saturated, or missing; 1 violation). Never throws for an
|
|
36
|
+
* expected condition — a missing learnings file resolves to a silent,
|
|
37
|
+
* successful pass.
|
|
37
38
|
* @param fileArg - Optional explicit learnings file to check (default: resolved
|
|
38
39
|
* from `.lisa.config.json`)
|
|
39
40
|
* @param dependencies - Injectable collaborators for tests
|
|
@@ -53,7 +54,13 @@ export async function runCheckLearningsBudget(fileArg, dependencies = {}) {
|
|
|
53
54
|
error(`check-learnings-budget: ${formatDiagnosticPath(resolvedFile)}: ${result.detail}`);
|
|
54
55
|
return 1;
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
+
// A saturated ledger logs a distinct `learnings budget saturated` verdict and
|
|
58
|
+
// still exits 0 — deliberately, and not an oversight: the ledger is a shared
|
|
59
|
+
// corpus that fills up over weeks, so failing here would stop a host
|
|
60
|
+
// project's unrelated pull request for a state its change never created, and
|
|
61
|
+
// the remedy (retire or promote an entry) belongs to the gardener, not to
|
|
62
|
+
// whoever is mid-change. See describeLearningsSaturation.
|
|
63
|
+
log(formatBudgetVerdict(resolvedFile, result));
|
|
57
64
|
return 0;
|
|
58
65
|
}
|
|
59
66
|
//# sourceMappingURL=check-learnings-budget-cmd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-learnings-budget-cmd.js","sourceRoot":"","sources":["../../src/cli/check-learnings-budget-cmd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AAYnC;;;;;;GAMG;AACH,KAAK,UAAU,oBAAoB,CACjC,OAA2B,EAC3B,GAAW;IAEX,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,2BAA2B,CAAC,MAAM,CAAC,CAAC,CAAC;AAChE,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"check-learnings-budget-cmd.js","sourceRoot":"","sources":["../../src/cli/check-learnings-budget-cmd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AAYnC;;;;;;GAMG;AACH,KAAK,UAAU,oBAAoB,CACjC,OAA2B,EAC3B,GAAW;IAEX,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,2BAA2B,CAAC,MAAM,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAA2B,EAC3B,eAAiD,EAAE;IAEnD,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC9C,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5E,MAAM,KAAK,GACT,YAAY,CAAC,KAAK,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,MAAM,YAAY,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,YAAY,CAAC,CAAC;IACxD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,GAAG,CACD,wBAAwB,oBAAoB,CAAC,YAAY,CAAC,qBAAqB,CAChF,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,KAAK,CACH,2BAA2B,oBAAoB,CAAC,YAAY,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,CAClF,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,8EAA8E;IAC9E,6EAA6E;IAC7E,qEAAqE;IACrE,6EAA6E;IAC7E,0EAA0E;IAC1E,0DAA0D;IAC1D,GAAG,CAAC,mBAAmB,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -5,6 +5,19 @@ export interface LearningsBudgetOk {
|
|
|
5
5
|
readonly maxEntries: number;
|
|
6
6
|
readonly measuredTokens: number;
|
|
7
7
|
readonly maxTokens: number;
|
|
8
|
+
/**
|
|
9
|
+
* Operator-readable clause when the ledger is inside its budget but has no
|
|
10
|
+
* room for a further learning, `undefined` when room remains.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately a field on the SUCCESS result rather than a fourth result
|
|
13
|
+
* kind. A new kind would have been silently mishandled by every consumer
|
|
14
|
+
* whose branch order ends in "otherwise it passed" — the shipped
|
|
15
|
+
* `check-learnings-budget` CLI subcommand is written exactly that way — so
|
|
16
|
+
* adding one would have reproduced this defect in the consumers while
|
|
17
|
+
* appearing to fix it in the core. Saturation is also genuinely NOT a
|
|
18
|
+
* failure: see {@link describeLearningsSaturation}.
|
|
19
|
+
*/
|
|
20
|
+
readonly saturation: string | undefined;
|
|
8
21
|
}
|
|
9
22
|
/** No learnings file exists at the resolved path — an expected, silent case. */
|
|
10
23
|
export interface LearningsBudgetMissing {
|
|
@@ -26,6 +39,77 @@ export type LearningsBudgetResult = LearningsBudgetOk | LearningsBudgetMissing |
|
|
|
26
39
|
* @returns Structured budget-check result
|
|
27
40
|
*/
|
|
28
41
|
export declare function checkLearningsBudget(file: string): Promise<LearningsBudgetResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Describe a ledger that is inside its hard budget but has no room left for a
|
|
44
|
+
* further learning, or `undefined` when room remains.
|
|
45
|
+
*
|
|
46
|
+
* ## Why saturation is a verdict at all
|
|
47
|
+
*
|
|
48
|
+
* Before this, the budget had exactly two states: `passed` up to the cap and
|
|
49
|
+
* `exceeded` past it. This repository's own ledger sat at 20/20 entries and
|
|
50
|
+
* 11924/12000 bytes and the check called it `passed`
|
|
51
|
+
* (CodySwannGT/lisa#3089) — a control reporting health right up to the moment
|
|
52
|
+
* it could no longer do its job. A gate that reads green at 100% gives an
|
|
53
|
+
* operator no warning at all; the next agent to capture a learning is the one
|
|
54
|
+
* who finds out, and the message they get tells them to shorten THEIR entry.
|
|
55
|
+
*
|
|
56
|
+
* The 20/20 `passed` was considered and rejected as the correct output. So was
|
|
57
|
+
* the reflex fix of failing at the cap — see below — and so was raising the
|
|
58
|
+
* cap, which silences the signal without doing the work the signal asks for and
|
|
59
|
+
* puts the ledger back here with a higher ceiling.
|
|
60
|
+
*
|
|
61
|
+
* ## Why this is a warning and not a failure
|
|
62
|
+
*
|
|
63
|
+
* At exactly the cap nothing has overflowed yet: the document is valid, every
|
|
64
|
+
* entry is serveable, and the projection works. Failing there converts a
|
|
65
|
+
* working state into a red build.
|
|
66
|
+
*
|
|
67
|
+
* More importantly it fails the WRONG PERSON. The learnings ledger is a shared
|
|
68
|
+
* document that fills up over weeks; the gate runs on every pull request. A
|
|
69
|
+
* failure would stop whoever happens to be mid-change for a corpus their change
|
|
70
|
+
* never touched, and retirement is not theirs to do — it is the gardener's
|
|
71
|
+
* human-gated call (`/lisa:learnings:audit`). Blaming an unrelated change is
|
|
72
|
+
* the CURRENT failure mode moved one step earlier, and it is the shape that
|
|
73
|
+
* gets a guard disabled rather than obeyed. So saturation is loud in the output
|
|
74
|
+
* and exit code 0.
|
|
75
|
+
*
|
|
76
|
+
* The hard caps still fail, unchanged. Nothing here weakens them.
|
|
77
|
+
*
|
|
78
|
+
* ## Why this boundary
|
|
79
|
+
*
|
|
80
|
+
* Not a percentage. Saturation is "the next capture does not fit", derived from
|
|
81
|
+
* the same {@link PER_ENTRY_BYTE_ALLOWANCE} the byte budget itself is derived
|
|
82
|
+
* from, so the warning band and the cap can no more contradict each other than
|
|
83
|
+
* `maxTokens` and `maxEntries` can. A hand-picked 90% would drift the moment
|
|
84
|
+
* either cap moved.
|
|
85
|
+
*
|
|
86
|
+
* Two independent ways to run out, because a ledger can hit either first:
|
|
87
|
+
* every slot taken, or fewer than one average entry's bytes remaining.
|
|
88
|
+
*
|
|
89
|
+
* ## What happens if the warning is ignored
|
|
90
|
+
*
|
|
91
|
+
* Nothing is lost — the writer's overflow path (`learnings-overflow`) preserves
|
|
92
|
+
* a rejected capture in a tracked `.overflow.md` beside the ledger and files a
|
|
93
|
+
* `[lisa-ledger-saturated]` signal, so content survives a full ledger. That
|
|
94
|
+
* path is reactive by construction: it runs only once a write has already
|
|
95
|
+
* failed. This verdict is the same fact, said before anyone pays for it.
|
|
96
|
+
* @param entryCount - Entries the document holds
|
|
97
|
+
* @param measuredTokens - Measured document size under the contract's measure
|
|
98
|
+
* @returns Single-line saturation clause, or undefined when room remains
|
|
99
|
+
*/
|
|
100
|
+
export declare function describeLearningsSaturation(entryCount: number, measuredTokens: number): string | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Render the one operator-facing verdict line for a within-budget document.
|
|
103
|
+
*
|
|
104
|
+
* Shared by the package script and the shipped CLI subcommand so the two
|
|
105
|
+
* cannot report the same ledger differently — they previously carried the same
|
|
106
|
+
* template string twice, which is how one of them would have kept saying
|
|
107
|
+
* `passed` for a full ledger after the other stopped.
|
|
108
|
+
* @param file - Absolute learnings file path
|
|
109
|
+
* @param result - Successful budget-check result
|
|
110
|
+
* @returns Single-line, terminal-safe verdict
|
|
111
|
+
*/
|
|
112
|
+
export declare function formatBudgetVerdict(file: string, result: LearningsBudgetOk): string;
|
|
29
113
|
/**
|
|
30
114
|
* Render a caught failure without allowing filesystem paths or control bytes
|
|
31
115
|
* embedded in an Error message to forge additional terminal/CI output.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-budget-check.d.ts","sourceRoot":"","sources":["../../src/core/learnings-budget-check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"learnings-budget-check.d.ts","sourceRoot":"","sources":["../../src/core/learnings-budget-check.ts"],"names":[],"mappings":"AAgCA,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,gFAAgF;AAChF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,8EAA8E;AAC9E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,8CAA8C;AAC9C,MAAM,MAAM,qBAAqB,GAC7B,iBAAiB,GACjB,sBAAsB,GACtB,wBAAwB,CAAC;AAE7B;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,qBAAqB,CAAC,CAiChC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACrB,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,iBAAiB,GACxB,MAAM,CAKR;AAiDD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAYxD;AAoCD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD"}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { constants } from "node:fs";
|
|
18
18
|
import { open } from "node:fs/promises";
|
|
19
|
-
import { LEARNINGS_CONTRACT, estimateLearningTokens, } from "./learnings-contract.js";
|
|
19
|
+
import { LEARNINGS_CONTRACT, PER_ENTRY_BYTE_ALLOWANCE, estimateLearningTokens, } from "./learnings-contract.js";
|
|
20
20
|
import { CONFLICT_MARKER_DIAGNOSIS, conflictMarkerError, findConflictMarkerInBytes, parseLearningsFile, renderLearningsFile, } from "./learnings-document.js";
|
|
21
21
|
import { validateLearningEntry } from "./learnings-entry.js";
|
|
22
22
|
/**
|
|
@@ -46,6 +46,7 @@ export async function checkLearningsBudget(file) {
|
|
|
46
46
|
maxEntries: LEARNINGS_CONTRACT.maxEntries,
|
|
47
47
|
measuredTokens,
|
|
48
48
|
maxTokens: LEARNINGS_CONTRACT.maxTokens,
|
|
49
|
+
saturation: describeLearningsSaturation(entries.length, measuredTokens),
|
|
49
50
|
};
|
|
50
51
|
}
|
|
51
52
|
catch (error) {
|
|
@@ -55,6 +56,92 @@ export async function checkLearningsBudget(file) {
|
|
|
55
56
|
: { kind: "violation", detail: withRemediation(detail, file) };
|
|
56
57
|
}
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Describe a ledger that is inside its hard budget but has no room left for a
|
|
61
|
+
* further learning, or `undefined` when room remains.
|
|
62
|
+
*
|
|
63
|
+
* ## Why saturation is a verdict at all
|
|
64
|
+
*
|
|
65
|
+
* Before this, the budget had exactly two states: `passed` up to the cap and
|
|
66
|
+
* `exceeded` past it. This repository's own ledger sat at 20/20 entries and
|
|
67
|
+
* 11924/12000 bytes and the check called it `passed`
|
|
68
|
+
* (CodySwannGT/lisa#3089) — a control reporting health right up to the moment
|
|
69
|
+
* it could no longer do its job. A gate that reads green at 100% gives an
|
|
70
|
+
* operator no warning at all; the next agent to capture a learning is the one
|
|
71
|
+
* who finds out, and the message they get tells them to shorten THEIR entry.
|
|
72
|
+
*
|
|
73
|
+
* The 20/20 `passed` was considered and rejected as the correct output. So was
|
|
74
|
+
* the reflex fix of failing at the cap — see below — and so was raising the
|
|
75
|
+
* cap, which silences the signal without doing the work the signal asks for and
|
|
76
|
+
* puts the ledger back here with a higher ceiling.
|
|
77
|
+
*
|
|
78
|
+
* ## Why this is a warning and not a failure
|
|
79
|
+
*
|
|
80
|
+
* At exactly the cap nothing has overflowed yet: the document is valid, every
|
|
81
|
+
* entry is serveable, and the projection works. Failing there converts a
|
|
82
|
+
* working state into a red build.
|
|
83
|
+
*
|
|
84
|
+
* More importantly it fails the WRONG PERSON. The learnings ledger is a shared
|
|
85
|
+
* document that fills up over weeks; the gate runs on every pull request. A
|
|
86
|
+
* failure would stop whoever happens to be mid-change for a corpus their change
|
|
87
|
+
* never touched, and retirement is not theirs to do — it is the gardener's
|
|
88
|
+
* human-gated call (`/lisa:learnings:audit`). Blaming an unrelated change is
|
|
89
|
+
* the CURRENT failure mode moved one step earlier, and it is the shape that
|
|
90
|
+
* gets a guard disabled rather than obeyed. So saturation is loud in the output
|
|
91
|
+
* and exit code 0.
|
|
92
|
+
*
|
|
93
|
+
* The hard caps still fail, unchanged. Nothing here weakens them.
|
|
94
|
+
*
|
|
95
|
+
* ## Why this boundary
|
|
96
|
+
*
|
|
97
|
+
* Not a percentage. Saturation is "the next capture does not fit", derived from
|
|
98
|
+
* the same {@link PER_ENTRY_BYTE_ALLOWANCE} the byte budget itself is derived
|
|
99
|
+
* from, so the warning band and the cap can no more contradict each other than
|
|
100
|
+
* `maxTokens` and `maxEntries` can. A hand-picked 90% would drift the moment
|
|
101
|
+
* either cap moved.
|
|
102
|
+
*
|
|
103
|
+
* Two independent ways to run out, because a ledger can hit either first:
|
|
104
|
+
* every slot taken, or fewer than one average entry's bytes remaining.
|
|
105
|
+
*
|
|
106
|
+
* ## What happens if the warning is ignored
|
|
107
|
+
*
|
|
108
|
+
* Nothing is lost — the writer's overflow path (`learnings-overflow`) preserves
|
|
109
|
+
* a rejected capture in a tracked `.overflow.md` beside the ledger and files a
|
|
110
|
+
* `[lisa-ledger-saturated]` signal, so content survives a full ledger. That
|
|
111
|
+
* path is reactive by construction: it runs only once a write has already
|
|
112
|
+
* failed. This verdict is the same fact, said before anyone pays for it.
|
|
113
|
+
* @param entryCount - Entries the document holds
|
|
114
|
+
* @param measuredTokens - Measured document size under the contract's measure
|
|
115
|
+
* @returns Single-line saturation clause, or undefined when room remains
|
|
116
|
+
*/
|
|
117
|
+
export function describeLearningsSaturation(entryCount, measuredTokens) {
|
|
118
|
+
const entriesFull = entryCount >= LEARNINGS_CONTRACT.maxEntries;
|
|
119
|
+
const bytesFull = measuredTokens + PER_ENTRY_BYTE_ALLOWANCE > LEARNINGS_CONTRACT.maxTokens;
|
|
120
|
+
if (!entriesFull && !bytesFull) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const reason = entriesFull
|
|
124
|
+
? `every one of the ${LEARNINGS_CONTRACT.maxEntries} entry slots is taken`
|
|
125
|
+
: `fewer than ${PER_ENTRY_BYTE_ALLOWANCE} bytes remain, less than one average entry`;
|
|
126
|
+
return `${reason}, so the next learning captured here will be rejected. Retire or promote an entry with the gardener (\`/lisa:learnings:audit\`); raising the cap is not the remedy`;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Render the one operator-facing verdict line for a within-budget document.
|
|
130
|
+
*
|
|
131
|
+
* Shared by the package script and the shipped CLI subcommand so the two
|
|
132
|
+
* cannot report the same ledger differently — they previously carried the same
|
|
133
|
+
* template string twice, which is how one of them would have kept saying
|
|
134
|
+
* `passed` for a full ledger after the other stopped.
|
|
135
|
+
* @param file - Absolute learnings file path
|
|
136
|
+
* @param result - Successful budget-check result
|
|
137
|
+
* @returns Single-line, terminal-safe verdict
|
|
138
|
+
*/
|
|
139
|
+
export function formatBudgetVerdict(file, result) {
|
|
140
|
+
const counts = `(${result.entryCount}/${result.maxEntries} entries, ${result.measuredTokens}/${result.maxTokens} maxTokens)`;
|
|
141
|
+
return result.saturation === undefined
|
|
142
|
+
? `${formatDiagnosticPath(file)}: learnings budget passed ${counts}`
|
|
143
|
+
: `${formatDiagnosticPath(file)}: learnings budget saturated ${counts} — ${result.saturation}`;
|
|
144
|
+
}
|
|
58
145
|
/**
|
|
59
146
|
* Append a terse, actionable remediation clause to a file-level budget breach
|
|
60
147
|
* so an operator reading CI output learns the fix, not just the number. Only
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings-budget-check.js","sourceRoot":"","sources":["../../src/core/learnings-budget-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAmB,MAAM,kBAAkB,CAAC;AACzD,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"learnings-budget-check.js","sourceRoot":"","sources":["../../src/core/learnings-budget-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -1076,7 +1076,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
1076
1076
|
"scripts/check-delivery-deletion-conflicts.mjs": "77eed58c9ff076c4438a5fe01c343f25c1a1c8f29a8f5861d1e1081b1739d300",
|
|
1077
1077
|
"scripts/check-derived-artifacts.mjs": "2911e2153f6accceacec81fa0255afe9b75cc58c69476db1505eb08878f6672d",
|
|
1078
1078
|
"scripts/check-duplicate-versions.mjs": "26b26351dd2735dfd8d9a2436b89e876ce2ed93871d0b264f611215dd03d70ae",
|
|
1079
|
-
"scripts/check-learnings-budget.ts": "
|
|
1079
|
+
"scripts/check-learnings-budget.ts": "2945574099642da37dc88c784a065a75db74f2084302bc0762fea3d8d6522ba3",
|
|
1080
1080
|
"scripts/check-orphan-test-processes.mjs": "123822f43b53a84b619ed97d5c18069feb5964b8216248968a7ab165e345106a",
|
|
1081
1081
|
"scripts/check-pipeline-status-reads.mjs": "a84a24ff386cdb16bf1c05c7728d5266a4b32c4c46abc227303620ca5b49ddfe",
|
|
1082
1082
|
"scripts/check-plugins-sync.sh": "77ce9db178da0f32e16e353bcf3d7bd0531aed2e699c18d030a7e90a9de5abd9",
|
package/package.json
CHANGED
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"zod-validation-error": "^4.0.0"
|
|
148
148
|
},
|
|
149
149
|
"name": "@codyswann/lisa",
|
|
150
|
-
"version": "4.6.
|
|
150
|
+
"version": "4.6.4",
|
|
151
151
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
152
152
|
"main": "dist/index.js",
|
|
153
153
|
"exports": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.4",
|
|
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": "4.6.
|
|
3
|
+
"version": "4.6.4",
|
|
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": "4.6.
|
|
3
|
+
"version": "4.6.4",
|
|
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": "4.6.
|
|
3
|
+
"version": "4.6.4",
|
|
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": "4.6.
|
|
3
|
+
"version": "4.6.4",
|
|
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"
|
|
@@ -16,9 +16,16 @@
|
|
|
16
16
|
*
|
|
17
17
|
* The two surfaces are genuinely different and both matter: the template is
|
|
18
18
|
* what every adopting project starts from, and the ledger is what this
|
|
19
|
-
* repository's agents actually read.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* repository's agents actually read. Both are committed in a source checkout,
|
|
20
|
+
* so a missing one there is a failure — see `checkDefaultSurfaces` for why the
|
|
21
|
+
* ledger's absence used to be a pass and no longer is. Running from the
|
|
22
|
+
* published package, where no tarball carries a ledger, its absence stays the
|
|
23
|
+
* ordinary quiet pass.
|
|
24
|
+
*
|
|
25
|
+
* A within-budget ledger reports one of TWO verdicts, not one: `learnings
|
|
26
|
+
* budget passed` while room remains, and `learnings budget saturated` once the
|
|
27
|
+
* next capture would not fit (#3089). Both exit 0. The reasoning for warning
|
|
28
|
+
* rather than failing lives on `describeLearningsSaturation` in the core.
|
|
22
29
|
* @module scripts/check-learnings-budget
|
|
23
30
|
*/
|
|
24
31
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -28,7 +35,7 @@ import type * as BudgetCheckModule from "../src/core/learnings-budget-check.js";
|
|
|
28
35
|
|
|
29
36
|
type BudgetChecker = Pick<
|
|
30
37
|
typeof BudgetCheckModule,
|
|
31
|
-
"checkLearningsBudget" | "formatDiagnosticPath"
|
|
38
|
+
"checkLearningsBudget" | "formatBudgetVerdict" | "formatDiagnosticPath"
|
|
32
39
|
>;
|
|
33
40
|
|
|
34
41
|
const REPO_ROOT = path.resolve(import.meta.dir, "..");
|
|
@@ -69,6 +76,22 @@ function resolveLedger(): string {
|
|
|
69
76
|
return path.resolve(REPO_ROOT, relative);
|
|
70
77
|
}
|
|
71
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Whether this script is running from a source checkout rather than from the
|
|
81
|
+
* published package, decided by the presence of the TypeScript core the
|
|
82
|
+
* published tarball deliberately excludes.
|
|
83
|
+
*
|
|
84
|
+
* The same discriminator the quality workflow uses to choose between running
|
|
85
|
+
* this script and running the shipped CLI subcommand, so the two agree on what
|
|
86
|
+
* "Lisa's own repository" means by construction rather than by convention.
|
|
87
|
+
* @returns True when the in-tree TypeScript core is present
|
|
88
|
+
*/
|
|
89
|
+
function isSourceCheckout(): boolean {
|
|
90
|
+
return existsSync(
|
|
91
|
+
path.join(REPO_ROOT, "src", "core", "learnings-budget-check.ts")
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
72
95
|
/** Run the package-facing checker with zero or one explicit file path. */
|
|
73
96
|
async function main(): Promise<void> {
|
|
74
97
|
const arguments_ = process.argv.slice(2);
|
|
@@ -77,48 +100,87 @@ async function main(): Promise<void> {
|
|
|
77
100
|
}
|
|
78
101
|
|
|
79
102
|
const checker = await loadBudgetChecker();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
103
|
+
const inspected =
|
|
104
|
+
arguments_.length === 1
|
|
105
|
+
? await checkExplicitSurface(checker, arguments_[0] as string)
|
|
106
|
+
: await checkDefaultSurfaces(checker);
|
|
107
|
+
|
|
108
|
+
// VACUITY GUARD. Every path above either judges a document or exits, so this
|
|
109
|
+
// should be unreachable — which is the point. A run that inspected nothing
|
|
110
|
+
// and a run that inspected a healthy ledger produce identical output and an
|
|
111
|
+
// identical exit code, and that ambiguity is how this gate spent a release
|
|
112
|
+
// checking only a 0-entry template while looking like a gate on the ledger
|
|
113
|
+
// (#2932). Counting what was actually judged makes "nothing" say so instead
|
|
114
|
+
// of reporting all-clear.
|
|
115
|
+
if (inspected === 0) {
|
|
116
|
+
fail(
|
|
117
|
+
"inspected no learnings surface — an empty inspection is indistinguishable from a healthy ledger, so it fails rather than reporting all-clear"
|
|
118
|
+
);
|
|
85
119
|
}
|
|
120
|
+
}
|
|
86
121
|
|
|
87
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Check the one document named on the command line.
|
|
124
|
+
* @param checker - The loaded budget checker
|
|
125
|
+
* @param argument - Caller-supplied learnings path
|
|
126
|
+
* @returns How many documents were judged
|
|
127
|
+
*/
|
|
128
|
+
async function checkExplicitSurface(
|
|
129
|
+
checker: BudgetChecker,
|
|
130
|
+
argument: string
|
|
131
|
+
): Promise<number> {
|
|
132
|
+
await check(checker, path.resolve(process.cwd(), argument));
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Check the two default surfaces: the shipped template and this repository's
|
|
138
|
+
* own ledger.
|
|
139
|
+
* @param checker - The loaded budget checker
|
|
140
|
+
* @returns How many documents were judged
|
|
141
|
+
*/
|
|
142
|
+
async function checkDefaultSurfaces(checker: BudgetChecker): Promise<number> {
|
|
143
|
+
await check(checker, TEMPLATE_LEARNINGS_FILE);
|
|
88
144
|
const ledger = resolveLedger();
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
return;
|
|
145
|
+
if (existsSync(ledger)) {
|
|
146
|
+
await check(checker, ledger);
|
|
147
|
+
return 2;
|
|
92
148
|
}
|
|
93
|
-
|
|
149
|
+
// In a source checkout the ledger is a committed file, so its absence means
|
|
150
|
+
// the resolver drifted off it — and "no learnings file" is a verdict the CI
|
|
151
|
+
// marker grep accepts as green, which turns that drift into a gate on the
|
|
152
|
+
// template alone. Fail instead. From the published package the same absence
|
|
153
|
+
// is the ordinary case (no tarball carries a ledger) and stays a quiet pass,
|
|
154
|
+
// exactly as it does for host projects on the CLI subcommand.
|
|
155
|
+
if (isSourceCheckout()) {
|
|
156
|
+
fail(
|
|
157
|
+
`${checker.formatDiagnosticPath(ledger)}: resolved ledger does not exist, and this is a source checkout where the ledger is committed — the configured \`learnings.file\` no longer resolves to a document, so this run would have gated the shipped template alone`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
console.log(`${checker.formatDiagnosticPath(ledger)}: no learnings file`);
|
|
161
|
+
return 1;
|
|
94
162
|
}
|
|
95
163
|
|
|
96
164
|
/**
|
|
97
165
|
* Check one file and report, failing the process on any violation.
|
|
166
|
+
*
|
|
167
|
+
* Every document this script reaches must exist — an explicit argument names
|
|
168
|
+
* one, and both defaults are committed here — so a missing file is as much a
|
|
169
|
+
* failure as any other violation. Host projects use the
|
|
170
|
+
* `lisa check-learnings-budget` CLI subcommand instead, which treats a missing
|
|
171
|
+
* file as an expected pass.
|
|
98
172
|
* @param checker - The loaded budget checker
|
|
99
173
|
* @param file - Absolute path to the document to check
|
|
100
|
-
* @param options - Whether a missing file is a violation
|
|
101
|
-
* @param options.absenceIsFailure - True when the file must exist
|
|
102
174
|
*/
|
|
103
|
-
async function check(
|
|
104
|
-
checker: BudgetChecker,
|
|
105
|
-
file: string,
|
|
106
|
-
options: { absenceIsFailure: boolean }
|
|
107
|
-
): Promise<void> {
|
|
175
|
+
async function check(checker: BudgetChecker, file: string): Promise<void> {
|
|
108
176
|
const result = await checker.checkLearningsBudget(file);
|
|
109
177
|
if (result.kind === "ok") {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
);
|
|
178
|
+
// Prints `learnings budget saturated` for a full-but-valid ledger and exits
|
|
179
|
+
// 0 all the same; the reasoning lives on describeLearningsSaturation.
|
|
180
|
+
console.log(checker.formatBudgetVerdict(file, result));
|
|
113
181
|
return;
|
|
114
182
|
}
|
|
115
|
-
|
|
116
|
-
// much a failure as any other violation. Host projects use the
|
|
117
|
-
// `lisa check-learnings-budget` CLI subcommand instead, which treats a
|
|
118
|
-
// missing file as an expected pass.
|
|
119
|
-
if (options.absenceIsFailure) {
|
|
120
|
-
fail(`${checker.formatDiagnosticPath(file)}: ${result.detail}`);
|
|
121
|
-
}
|
|
183
|
+
fail(`${checker.formatDiagnosticPath(file)}: ${result.detail}`);
|
|
122
184
|
}
|
|
123
185
|
|
|
124
186
|
/**
|
|
@@ -146,6 +208,7 @@ async function loadBudgetChecker(): Promise<BudgetChecker> {
|
|
|
146
208
|
);
|
|
147
209
|
return {
|
|
148
210
|
checkLearningsBudget: module_.checkLearningsBudget,
|
|
211
|
+
formatBudgetVerdict: module_.formatBudgetVerdict,
|
|
149
212
|
formatDiagnosticPath: module_.formatDiagnosticPath,
|
|
150
213
|
} as BudgetChecker;
|
|
151
214
|
}
|