crewly 1.20.419 → 1.20.421
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/config/skills/agent/core/project-tickets/SKILL.md +21 -0
- package/config/skills/agent/core/project-tickets/execute.sh +15 -5
- package/config/skills/agent/core/record-learning/SKILL.md +12 -1
- package/config/skills/agent/core/record-learning/execute.sh +24 -2
- package/config/skills/team-leader/decide-correction/SKILL.md +65 -0
- package/config/skills/team-leader/decide-correction/execute.sh +63 -0
- package/config/skills/team-leader/handle-failure/SKILL.md +2 -0
- package/config/skills/team-leader/handle-failure/execute.sh +18 -0
- package/dist/backend/backend/src/constants.d.ts +35 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +36 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts +42 -2
- package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.controller.js +111 -4
- package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.d.ts +3 -0
- package/dist/backend/backend/src/controllers/memory/memory.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.js +7 -1
- package/dist/backend/backend/src/controllers/memory/memory.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +8 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +28 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +1 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +4 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +25 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/memory/correction-ladder.service.d.ts +225 -0
- package/dist/backend/backend/src/services/memory/correction-ladder.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/memory/correction-ladder.service.js +335 -0
- package/dist/backend/backend/src/services/memory/correction-ladder.service.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-retro.d.ts +99 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-retro.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-retro.js +188 -16
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-retro.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +53 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +226 -27
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +35 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +36 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correction ladder (#810, specs/2026-10-25-correction-ladder.md).
|
|
3
|
+
*
|
|
4
|
+
* When an agent is corrected, the correction lands in memory, an SOP or a
|
|
5
|
+
* prompt: prose that is read every turn and still lets the same mistake
|
|
6
|
+
* back in. This service keeps a per-project tally of corrections by
|
|
7
|
+
* **class** (a short slug the recorder chooses, e.g. `git-add-all`) and,
|
|
8
|
+
* the second time a class is recorded, hands the project's team lead one
|
|
9
|
+
* WorkItem: "can this be made impossible or checked in code?" with the
|
|
10
|
+
* ladder as options —
|
|
11
|
+
*
|
|
12
|
+
* (a) structural / API change — the mistake can no longer be expressed
|
|
13
|
+
* (b) lint / test / CI check — it is caught before merge
|
|
14
|
+
* (c) state-triggered hook — it is caught when it happens
|
|
15
|
+
* (d) keep as prose, with a stated reason
|
|
16
|
+
*
|
|
17
|
+
* The WorkItem is deduplicated: one open item per class. The lead records
|
|
18
|
+
* the rung with `decide`; until then a third occurrence does not raise a
|
|
19
|
+
* second item. A decision of (d) is not final: when the prose did not
|
|
20
|
+
* stick (two more occurrences after it), the class is raised again. No LLM;
|
|
21
|
+
* a plain JSON store under the project's `.crewly/`.
|
|
22
|
+
*
|
|
23
|
+
* @module services/memory/correction-ladder.service
|
|
24
|
+
*/
|
|
25
|
+
import { CORRECTION_LADDER_CONSTANTS } from '../../constants.js';
|
|
26
|
+
import { type WorkItem } from '../../types/v2/work-item.types.js';
|
|
27
|
+
/** Where a correction came from. */
|
|
28
|
+
export type CorrectionSource = 'learning' | 'failure' | 'manual';
|
|
29
|
+
/** The rungs of the ladder, from "cannot happen" to "we tell them again". */
|
|
30
|
+
export type CorrectionRung = (typeof CORRECTION_LADDER_CONSTANTS.RUNGS)[number];
|
|
31
|
+
/** One time a class was recorded. */
|
|
32
|
+
export interface CorrectionOccurrence {
|
|
33
|
+
/** ISO timestamp */
|
|
34
|
+
at: string;
|
|
35
|
+
/** Who recorded it (session name or agent id) */
|
|
36
|
+
agentId: string;
|
|
37
|
+
/** Learning, TL failure handling, or a direct call */
|
|
38
|
+
source: CorrectionSource;
|
|
39
|
+
/** The correction text as recorded (trimmed to `OCCURRENCE_TEXT_MAX_CHARS`) */
|
|
40
|
+
text: string;
|
|
41
|
+
/** Ticket / WorkItem the correction came from */
|
|
42
|
+
relatedTask?: string;
|
|
43
|
+
}
|
|
44
|
+
/** The lead's answer for a class. */
|
|
45
|
+
export interface CorrectionDecision {
|
|
46
|
+
rung: CorrectionRung;
|
|
47
|
+
/** Why this rung — required for every rung, and the whole point of (d) */
|
|
48
|
+
reason: string;
|
|
49
|
+
/** PR, file, rule or hook that implements it */
|
|
50
|
+
link?: string;
|
|
51
|
+
decidedBy: string;
|
|
52
|
+
decidedAt: string;
|
|
53
|
+
}
|
|
54
|
+
/** Everything known about one correction class in one project. */
|
|
55
|
+
export interface CorrectionClassRecord {
|
|
56
|
+
class: string;
|
|
57
|
+
/** Times recorded, all time */
|
|
58
|
+
count: number;
|
|
59
|
+
firstAt: string;
|
|
60
|
+
lastAt: string;
|
|
61
|
+
/** Newest last; capped at `MAX_OCCURRENCES_KEPT` */
|
|
62
|
+
occurrences: CorrectionOccurrence[];
|
|
63
|
+
/** The open ladder WorkItem, if one was raised and not yet decided */
|
|
64
|
+
workItemId: string | null;
|
|
65
|
+
workItemAt: string | null;
|
|
66
|
+
/** The current decision; `null` while undecided or after a re-raise */
|
|
67
|
+
decision: CorrectionDecision | null;
|
|
68
|
+
/** Earlier decisions that did not hold (a (d) that was raised again) */
|
|
69
|
+
previousDecisions: CorrectionDecision[];
|
|
70
|
+
}
|
|
71
|
+
/** The per-project store. */
|
|
72
|
+
export interface CorrectionLadderStore {
|
|
73
|
+
version: 1;
|
|
74
|
+
classes: Record<string, CorrectionClassRecord>;
|
|
75
|
+
}
|
|
76
|
+
/** Input of {@link CorrectionLadderService.record}. */
|
|
77
|
+
export interface RecordCorrectionInput {
|
|
78
|
+
projectPath: string;
|
|
79
|
+
/** Free text; normalised with {@link normalizeCorrectionClass} */
|
|
80
|
+
correctionClass: string;
|
|
81
|
+
agentId: string;
|
|
82
|
+
text: string;
|
|
83
|
+
source: CorrectionSource;
|
|
84
|
+
relatedTask?: string;
|
|
85
|
+
}
|
|
86
|
+
/** Why a second occurrence did not raise a WorkItem. */
|
|
87
|
+
export type CorrectionRaiseSkip = 'below_threshold' | 'already_raised' | 'decided' | 'no_pool' | 'target_dormant';
|
|
88
|
+
/** Result of {@link CorrectionLadderService.record}. */
|
|
89
|
+
export interface RecordCorrectionResult {
|
|
90
|
+
record: CorrectionClassRecord;
|
|
91
|
+
/** Whether this call raised the lead's WorkItem */
|
|
92
|
+
raised: boolean;
|
|
93
|
+
workItemId?: string;
|
|
94
|
+
target?: string;
|
|
95
|
+
skipped?: CorrectionRaiseSkip;
|
|
96
|
+
}
|
|
97
|
+
/** Input of {@link CorrectionLadderService.decide}. */
|
|
98
|
+
export interface DecideCorrectionInput {
|
|
99
|
+
projectPath: string;
|
|
100
|
+
correctionClass: string;
|
|
101
|
+
rung: string;
|
|
102
|
+
reason: string;
|
|
103
|
+
link?: string;
|
|
104
|
+
decidedBy: string;
|
|
105
|
+
}
|
|
106
|
+
/** The pool slice this service needs. */
|
|
107
|
+
export interface CorrectionLadderPool {
|
|
108
|
+
addToPool(workItem: WorkItem): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
/** Wiring. */
|
|
111
|
+
export interface CorrectionLadderOptions {
|
|
112
|
+
pool?: CorrectionLadderPool;
|
|
113
|
+
/** The team-lead session for a project root; `null` falls back to the orchestrator */
|
|
114
|
+
resolveTarget?: (projectPath: string) => Promise<string | null>;
|
|
115
|
+
/** Whether a session is awake; a dormant lead is not woken for a chore */
|
|
116
|
+
isTargetAwake?: (sessionName: string) => Promise<boolean>;
|
|
117
|
+
/** Target when no lead resolves (default: the orchestrator) */
|
|
118
|
+
fallbackTarget?: string;
|
|
119
|
+
/** Clock (tests) */
|
|
120
|
+
now?: () => number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Normalise a class to a slug: lower case, `a-z0-9-`, no leading/trailing
|
|
124
|
+
* or doubled dashes, at most `CLASS_MAX_CHARS`. Returns `null` when nothing
|
|
125
|
+
* usable is left.
|
|
126
|
+
*
|
|
127
|
+
* @param raw - What the recorder typed
|
|
128
|
+
* @returns The slug, or null
|
|
129
|
+
*/
|
|
130
|
+
export declare function normalizeCorrectionClass(raw: unknown): string | null;
|
|
131
|
+
/**
|
|
132
|
+
* Whether a string names a rung of the ladder.
|
|
133
|
+
*
|
|
134
|
+
* @param rung - Candidate
|
|
135
|
+
* @returns True for one of `RUNGS`
|
|
136
|
+
*/
|
|
137
|
+
export declare function isCorrectionRung(rung: unknown): rung is CorrectionRung;
|
|
138
|
+
/**
|
|
139
|
+
* Where a project's ladder store lives.
|
|
140
|
+
*
|
|
141
|
+
* @param projectPath - Project root
|
|
142
|
+
* @returns `<project data dir>/correction-ladder.json`
|
|
143
|
+
*/
|
|
144
|
+
export declare function correctionLadderPath(projectPath: string): string;
|
|
145
|
+
/**
|
|
146
|
+
* Occurrences recorded after the current decision (or all, when undecided).
|
|
147
|
+
*
|
|
148
|
+
* @param record - Class record
|
|
149
|
+
* @returns Count
|
|
150
|
+
*/
|
|
151
|
+
export declare function occurrencesSinceDecision(record: CorrectionClassRecord): number;
|
|
152
|
+
/**
|
|
153
|
+
* The lead's WorkItem for a class: the tally, the recorded texts, the four
|
|
154
|
+
* rungs, and how to record the choice.
|
|
155
|
+
*
|
|
156
|
+
* @param record - Class record (after the occurrence that raised it)
|
|
157
|
+
* @param projectPath - Project root
|
|
158
|
+
* @param target - Lead (or orchestrator) session
|
|
159
|
+
* @param again - Whether an earlier (d) did not hold
|
|
160
|
+
* @returns The WorkItem to add to the pool
|
|
161
|
+
*/
|
|
162
|
+
export declare function buildCorrectionWorkItem(record: CorrectionClassRecord, projectPath: string, target: string, again: boolean): WorkItem;
|
|
163
|
+
/**
|
|
164
|
+
* Per-project tally of correction classes with one ladder WorkItem per
|
|
165
|
+
* class for the team lead.
|
|
166
|
+
*/
|
|
167
|
+
export declare class CorrectionLadderService {
|
|
168
|
+
private static instance;
|
|
169
|
+
private readonly logger;
|
|
170
|
+
private readonly pool?;
|
|
171
|
+
private readonly resolveTarget?;
|
|
172
|
+
private readonly isTargetAwake?;
|
|
173
|
+
private readonly fallbackTarget;
|
|
174
|
+
private readonly now;
|
|
175
|
+
/** Serialises writes per store file */
|
|
176
|
+
private readonly locks;
|
|
177
|
+
/**
|
|
178
|
+
* @param options - Wiring (pool, lead resolver, wake check)
|
|
179
|
+
*/
|
|
180
|
+
constructor(options?: CorrectionLadderOptions);
|
|
181
|
+
/** The wired instance (an unwired one records and never raises). */
|
|
182
|
+
static getInstance(): CorrectionLadderService;
|
|
183
|
+
/** Install the wired instance (boot) or reset (tests). */
|
|
184
|
+
static setInstance(instance: CorrectionLadderService | null): void;
|
|
185
|
+
/**
|
|
186
|
+
* Record one correction of a class and, on the second occurrence (or the
|
|
187
|
+
* second after a (d) that did not hold), raise the lead's WorkItem.
|
|
188
|
+
*
|
|
189
|
+
* @param input - Class, who, what, where
|
|
190
|
+
* @returns The class record and whether a WorkItem was raised
|
|
191
|
+
* @throws Error when the class normalises to nothing or the text is empty
|
|
192
|
+
*/
|
|
193
|
+
record(input: RecordCorrectionInput): Promise<RecordCorrectionResult>;
|
|
194
|
+
/**
|
|
195
|
+
* Record the lead's choice for a class and close the ladder for it.
|
|
196
|
+
*
|
|
197
|
+
* @param input - Class, rung, reason, who
|
|
198
|
+
* @returns The updated record
|
|
199
|
+
* @throws Error for an unknown class, an unknown rung or an empty reason
|
|
200
|
+
*/
|
|
201
|
+
decide(input: DecideCorrectionInput): Promise<CorrectionClassRecord>;
|
|
202
|
+
/**
|
|
203
|
+
* Every class of a project, most recorded first.
|
|
204
|
+
*
|
|
205
|
+
* @param projectPath - Project root
|
|
206
|
+
* @returns Records
|
|
207
|
+
*/
|
|
208
|
+
list(projectPath: string): Promise<CorrectionClassRecord[]>;
|
|
209
|
+
/**
|
|
210
|
+
* Raise the lead's WorkItem when the class has earned it: `THRESHOLD`
|
|
211
|
+
* occurrences with no decision and no open item, or `THRESHOLD`
|
|
212
|
+
* occurrences after a (d) decision. An open item older than
|
|
213
|
+
* `REOPEN_AFTER_MS` with no decision counts as abandoned and is replaced.
|
|
214
|
+
*/
|
|
215
|
+
private maybeRaise;
|
|
216
|
+
/** The lead for a project; errors count as "no lead". */
|
|
217
|
+
private targetFor;
|
|
218
|
+
/** Errors count as dormant: a chore is never worth risking a wake. */
|
|
219
|
+
private targetAwake;
|
|
220
|
+
private read;
|
|
221
|
+
private write;
|
|
222
|
+
/** Run `fn` after every earlier operation on the same project's store. */
|
|
223
|
+
private withLock;
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=correction-ladder.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correction-ladder.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/memory/correction-ladder.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correction ladder (#810, specs/2026-10-25-correction-ladder.md).
|
|
3
|
+
*
|
|
4
|
+
* When an agent is corrected, the correction lands in memory, an SOP or a
|
|
5
|
+
* prompt: prose that is read every turn and still lets the same mistake
|
|
6
|
+
* back in. This service keeps a per-project tally of corrections by
|
|
7
|
+
* **class** (a short slug the recorder chooses, e.g. `git-add-all`) and,
|
|
8
|
+
* the second time a class is recorded, hands the project's team lead one
|
|
9
|
+
* WorkItem: "can this be made impossible or checked in code?" with the
|
|
10
|
+
* ladder as options —
|
|
11
|
+
*
|
|
12
|
+
* (a) structural / API change — the mistake can no longer be expressed
|
|
13
|
+
* (b) lint / test / CI check — it is caught before merge
|
|
14
|
+
* (c) state-triggered hook — it is caught when it happens
|
|
15
|
+
* (d) keep as prose, with a stated reason
|
|
16
|
+
*
|
|
17
|
+
* The WorkItem is deduplicated: one open item per class. The lead records
|
|
18
|
+
* the rung with `decide`; until then a third occurrence does not raise a
|
|
19
|
+
* second item. A decision of (d) is not final: when the prose did not
|
|
20
|
+
* stick (two more occurrences after it), the class is raised again. No LLM;
|
|
21
|
+
* a plain JSON store under the project's `.crewly/`.
|
|
22
|
+
*
|
|
23
|
+
* @module services/memory/correction-ladder.service
|
|
24
|
+
*/
|
|
25
|
+
import * as fs from 'fs/promises';
|
|
26
|
+
import * as path from 'path';
|
|
27
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
28
|
+
import { CORRECTION_LADDER_CONSTANTS, ORCHESTRATOR_SESSION_NAME } from '../../constants.js';
|
|
29
|
+
import { atomicWriteJson, safeReadJson } from '../../utils/file-io.utils.js';
|
|
30
|
+
import { resolveProjectDataDir } from '../core/crewly-home.utils.js';
|
|
31
|
+
import { createWorkItem } from '../../types/v2/work-item.types.js';
|
|
32
|
+
// =============================================================================
|
|
33
|
+
// Helpers
|
|
34
|
+
// =============================================================================
|
|
35
|
+
/**
|
|
36
|
+
* Normalise a class to a slug: lower case, `a-z0-9-`, no leading/trailing
|
|
37
|
+
* or doubled dashes, at most `CLASS_MAX_CHARS`. Returns `null` when nothing
|
|
38
|
+
* usable is left.
|
|
39
|
+
*
|
|
40
|
+
* @param raw - What the recorder typed
|
|
41
|
+
* @returns The slug, or null
|
|
42
|
+
*/
|
|
43
|
+
export function normalizeCorrectionClass(raw) {
|
|
44
|
+
if (typeof raw !== 'string')
|
|
45
|
+
return null;
|
|
46
|
+
const slug = raw
|
|
47
|
+
.trim()
|
|
48
|
+
.toLowerCase()
|
|
49
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
50
|
+
.replace(/^-+|-+$/g, '')
|
|
51
|
+
.replace(/-{2,}/g, '-')
|
|
52
|
+
.slice(0, CORRECTION_LADDER_CONSTANTS.CLASS_MAX_CHARS)
|
|
53
|
+
.replace(/-+$/g, '');
|
|
54
|
+
return slug.length >= CORRECTION_LADDER_CONSTANTS.CLASS_MIN_CHARS ? slug : null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether a string names a rung of the ladder.
|
|
58
|
+
*
|
|
59
|
+
* @param rung - Candidate
|
|
60
|
+
* @returns True for one of `RUNGS`
|
|
61
|
+
*/
|
|
62
|
+
export function isCorrectionRung(rung) {
|
|
63
|
+
return typeof rung === 'string' && CORRECTION_LADDER_CONSTANTS.RUNGS.includes(rung);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Where a project's ladder store lives.
|
|
67
|
+
*
|
|
68
|
+
* @param projectPath - Project root
|
|
69
|
+
* @returns `<project data dir>/correction-ladder.json`
|
|
70
|
+
*/
|
|
71
|
+
export function correctionLadderPath(projectPath) {
|
|
72
|
+
return path.join(resolveProjectDataDir(projectPath), CORRECTION_LADDER_CONSTANTS.STORE_FILE);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Occurrences recorded after the current decision (or all, when undecided).
|
|
76
|
+
*
|
|
77
|
+
* @param record - Class record
|
|
78
|
+
* @returns Count
|
|
79
|
+
*/
|
|
80
|
+
export function occurrencesSinceDecision(record) {
|
|
81
|
+
if (!record.decision)
|
|
82
|
+
return record.count;
|
|
83
|
+
const since = record.decision.decidedAt;
|
|
84
|
+
return record.occurrences.filter((o) => o.at > since).length;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The lead's WorkItem for a class: the tally, the recorded texts, the four
|
|
88
|
+
* rungs, and how to record the choice.
|
|
89
|
+
*
|
|
90
|
+
* @param record - Class record (after the occurrence that raised it)
|
|
91
|
+
* @param projectPath - Project root
|
|
92
|
+
* @param target - Lead (or orchestrator) session
|
|
93
|
+
* @param again - Whether an earlier (d) did not hold
|
|
94
|
+
* @returns The WorkItem to add to the pool
|
|
95
|
+
*/
|
|
96
|
+
export function buildCorrectionWorkItem(record, projectPath, target, again) {
|
|
97
|
+
const c = record.class;
|
|
98
|
+
const recent = record.occurrences.slice(-CORRECTION_LADDER_CONSTANTS.OCCURRENCES_IN_BRIEF);
|
|
99
|
+
const lines = [
|
|
100
|
+
`# Correction ladder — \`${c}\`${again ? ' (again)' : ''}`,
|
|
101
|
+
'',
|
|
102
|
+
`Project: \`${projectPath}\``,
|
|
103
|
+
`Recorded ${record.count} time${record.count === 1 ? '' : 's'}; first ${record.firstAt.slice(0, 10)}, last ${record.lastAt.slice(0, 10)}.`,
|
|
104
|
+
'',
|
|
105
|
+
];
|
|
106
|
+
if (again && record.previousDecisions.length) {
|
|
107
|
+
const prev = record.previousDecisions[record.previousDecisions.length - 1];
|
|
108
|
+
lines.push(`An earlier decision kept this as prose (${prev.decidedAt.slice(0, 10)}: "${prev.reason}") and the mistake came back ${occurrencesSinceDecision({ ...record, decision: prev })} more times. Prose did not hold; pick a higher rung or say why prose is still right.`, '');
|
|
109
|
+
}
|
|
110
|
+
lines.push('## What was recorded', '');
|
|
111
|
+
for (const o of recent)
|
|
112
|
+
lines.push(`- ${o.at.slice(0, 10)} · ${o.agentId} · ${o.source}${o.relatedTask ? ` · ${o.relatedTask}` : ''}: ${o.text}`);
|
|
113
|
+
lines.push('', '## The question', '', 'The same class of mistake has come back. Prose (memory, SOP, prompt) is read every turn and still let it through. Decide which rung makes it stop, highest feasible first:', '', '- **structural** — change the API, type or file layout so the mistake can no longer be expressed.', '- **check** — a lint rule, test or CI step that fails before merge.', '- **hook** — a state-triggered hook or skill guard that catches it the moment it happens.', '- **prose** — keep it as memory/SOP text, with the reason why nothing above is worth it.', '', 'Do the work for the rung you pick (or open the PR / ticket for it), then record the choice:', '', '```bash', `bash {{SKILLS_PATH}}/team-leader/decide-correction/execute.sh --project "${projectPath}" --class ${c} --rung <structural|check|hook|prose> --reason "<why this rung>" [--link <PR, file or rule>]`, '```', '', 'This WorkItem counts as done only when the choice is recorded. The owner is not involved; never post this in the owner\'s thread.');
|
|
114
|
+
return createWorkItem({
|
|
115
|
+
type: 'delegate',
|
|
116
|
+
owner: target === ORCHESTRATOR_SESSION_NAME ? 'orchestrator' : 'team_lead',
|
|
117
|
+
target,
|
|
118
|
+
title: `Correction ladder: "${c}" came back (${record.count}×)${again ? ' — prose did not hold' : ''}`,
|
|
119
|
+
description: `The correction class "${c}" was recorded ${record.count} times in ${projectPath}. Decide whether it can be made impossible (structural), caught by a check, caught by a hook, or must stay prose — and record the choice with decide-correction.`,
|
|
120
|
+
briefMarkdown: lines.join('\n'),
|
|
121
|
+
maxRetries: 1,
|
|
122
|
+
metadata: {
|
|
123
|
+
kind: CORRECTION_LADDER_CONSTANTS.WORKITEM_KIND,
|
|
124
|
+
correctionClass: c,
|
|
125
|
+
projectPath,
|
|
126
|
+
count: record.count,
|
|
127
|
+
again,
|
|
128
|
+
autoCreated: true,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
// =============================================================================
|
|
133
|
+
// Service
|
|
134
|
+
// =============================================================================
|
|
135
|
+
/**
|
|
136
|
+
* Per-project tally of correction classes with one ladder WorkItem per
|
|
137
|
+
* class for the team lead.
|
|
138
|
+
*/
|
|
139
|
+
export class CorrectionLadderService {
|
|
140
|
+
static instance = null;
|
|
141
|
+
logger;
|
|
142
|
+
pool;
|
|
143
|
+
resolveTarget;
|
|
144
|
+
isTargetAwake;
|
|
145
|
+
fallbackTarget;
|
|
146
|
+
now;
|
|
147
|
+
/** Serialises writes per store file */
|
|
148
|
+
locks = new Map();
|
|
149
|
+
/**
|
|
150
|
+
* @param options - Wiring (pool, lead resolver, wake check)
|
|
151
|
+
*/
|
|
152
|
+
constructor(options = {}) {
|
|
153
|
+
this.logger = LoggerService.getInstance().createComponentLogger('CorrectionLadder');
|
|
154
|
+
this.pool = options.pool;
|
|
155
|
+
this.resolveTarget = options.resolveTarget;
|
|
156
|
+
this.isTargetAwake = options.isTargetAwake;
|
|
157
|
+
this.fallbackTarget = options.fallbackTarget ?? ORCHESTRATOR_SESSION_NAME;
|
|
158
|
+
this.now = options.now ?? (() => Date.now());
|
|
159
|
+
}
|
|
160
|
+
/** The wired instance (an unwired one records and never raises). */
|
|
161
|
+
static getInstance() {
|
|
162
|
+
if (!this.instance)
|
|
163
|
+
this.instance = new CorrectionLadderService();
|
|
164
|
+
return this.instance;
|
|
165
|
+
}
|
|
166
|
+
/** Install the wired instance (boot) or reset (tests). */
|
|
167
|
+
static setInstance(instance) {
|
|
168
|
+
this.instance = instance;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Record one correction of a class and, on the second occurrence (or the
|
|
172
|
+
* second after a (d) that did not hold), raise the lead's WorkItem.
|
|
173
|
+
*
|
|
174
|
+
* @param input - Class, who, what, where
|
|
175
|
+
* @returns The class record and whether a WorkItem was raised
|
|
176
|
+
* @throws Error when the class normalises to nothing or the text is empty
|
|
177
|
+
*/
|
|
178
|
+
async record(input) {
|
|
179
|
+
const cls = normalizeCorrectionClass(input.correctionClass);
|
|
180
|
+
if (!cls)
|
|
181
|
+
throw new Error(`Correction class "${String(input.correctionClass)}" has no letters or digits to make a slug from`);
|
|
182
|
+
const text = (input.text ?? '').trim();
|
|
183
|
+
if (!text)
|
|
184
|
+
throw new Error('A correction needs the text that was recorded');
|
|
185
|
+
return this.withLock(input.projectPath, async () => {
|
|
186
|
+
const store = await this.read(input.projectPath);
|
|
187
|
+
const at = new Date(this.now()).toISOString();
|
|
188
|
+
const existing = store.classes[cls];
|
|
189
|
+
const occurrence = {
|
|
190
|
+
at,
|
|
191
|
+
agentId: input.agentId,
|
|
192
|
+
source: input.source,
|
|
193
|
+
text: text.slice(0, CORRECTION_LADDER_CONSTANTS.OCCURRENCE_TEXT_MAX_CHARS),
|
|
194
|
+
...(input.relatedTask ? { relatedTask: input.relatedTask } : {}),
|
|
195
|
+
};
|
|
196
|
+
const record = existing
|
|
197
|
+
? {
|
|
198
|
+
...existing,
|
|
199
|
+
count: existing.count + 1,
|
|
200
|
+
lastAt: at,
|
|
201
|
+
occurrences: [...existing.occurrences, occurrence].slice(-CORRECTION_LADDER_CONSTANTS.MAX_OCCURRENCES_KEPT),
|
|
202
|
+
}
|
|
203
|
+
: { class: cls, count: 1, firstAt: at, lastAt: at, occurrences: [occurrence], workItemId: null, workItemAt: null, decision: null, previousDecisions: [] };
|
|
204
|
+
store.classes[cls] = record;
|
|
205
|
+
const raise = await this.maybeRaise(record, input.projectPath);
|
|
206
|
+
await this.write(input.projectPath, store);
|
|
207
|
+
if (raise.raised) {
|
|
208
|
+
this.logger.info('Correction class raised to the team lead', { projectPath: input.projectPath, class: cls, count: record.count, target: raise.target, workItemId: raise.workItemId });
|
|
209
|
+
}
|
|
210
|
+
return { record, ...raise };
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Record the lead's choice for a class and close the ladder for it.
|
|
215
|
+
*
|
|
216
|
+
* @param input - Class, rung, reason, who
|
|
217
|
+
* @returns The updated record
|
|
218
|
+
* @throws Error for an unknown class, an unknown rung or an empty reason
|
|
219
|
+
*/
|
|
220
|
+
async decide(input) {
|
|
221
|
+
const cls = normalizeCorrectionClass(input.correctionClass);
|
|
222
|
+
if (!cls)
|
|
223
|
+
throw new Error(`Correction class "${String(input.correctionClass)}" is not a slug`);
|
|
224
|
+
const rung = input.rung;
|
|
225
|
+
if (!isCorrectionRung(rung))
|
|
226
|
+
throw new Error(`Unknown rung "${String(rung)}" — one of ${CORRECTION_LADDER_CONSTANTS.RUNGS.join(', ')}`);
|
|
227
|
+
const reason = (input.reason ?? '').trim();
|
|
228
|
+
if (!reason)
|
|
229
|
+
throw new Error('A decision needs a reason, for every rung');
|
|
230
|
+
return this.withLock(input.projectPath, async () => {
|
|
231
|
+
const store = await this.read(input.projectPath);
|
|
232
|
+
const record = store.classes[cls];
|
|
233
|
+
if (!record)
|
|
234
|
+
throw new Error(`No correction class "${cls}" recorded in ${input.projectPath}`);
|
|
235
|
+
const decision = {
|
|
236
|
+
rung,
|
|
237
|
+
reason,
|
|
238
|
+
...(input.link?.trim() ? { link: input.link.trim() } : {}),
|
|
239
|
+
decidedBy: input.decidedBy,
|
|
240
|
+
decidedAt: new Date(this.now()).toISOString(),
|
|
241
|
+
};
|
|
242
|
+
const updated = { ...record, decision, workItemId: null, workItemAt: null };
|
|
243
|
+
store.classes[cls] = updated;
|
|
244
|
+
await this.write(input.projectPath, store);
|
|
245
|
+
this.logger.info('Correction class decided', { projectPath: input.projectPath, class: cls, rung: decision.rung, decidedBy: input.decidedBy });
|
|
246
|
+
return updated;
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Every class of a project, most recorded first.
|
|
251
|
+
*
|
|
252
|
+
* @param projectPath - Project root
|
|
253
|
+
* @returns Records
|
|
254
|
+
*/
|
|
255
|
+
async list(projectPath) {
|
|
256
|
+
const store = await this.read(projectPath);
|
|
257
|
+
return Object.values(store.classes).sort((a, b) => b.count - a.count || a.class.localeCompare(b.class));
|
|
258
|
+
}
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
/**
|
|
261
|
+
* Raise the lead's WorkItem when the class has earned it: `THRESHOLD`
|
|
262
|
+
* occurrences with no decision and no open item, or `THRESHOLD`
|
|
263
|
+
* occurrences after a (d) decision. An open item older than
|
|
264
|
+
* `REOPEN_AFTER_MS` with no decision counts as abandoned and is replaced.
|
|
265
|
+
*/
|
|
266
|
+
async maybeRaise(record, projectPath) {
|
|
267
|
+
const since = occurrencesSinceDecision(record);
|
|
268
|
+
const again = record.decision?.rung === 'prose';
|
|
269
|
+
if (record.decision && !again)
|
|
270
|
+
return { raised: false, skipped: 'decided' };
|
|
271
|
+
if (since < CORRECTION_LADDER_CONSTANTS.THRESHOLD)
|
|
272
|
+
return { raised: false, skipped: 'below_threshold' };
|
|
273
|
+
if (record.workItemId) {
|
|
274
|
+
const age = record.workItemAt ? this.now() - Date.parse(record.workItemAt) : 0;
|
|
275
|
+
if (age < CORRECTION_LADDER_CONSTANTS.REOPEN_AFTER_MS)
|
|
276
|
+
return { raised: false, skipped: 'already_raised', workItemId: record.workItemId };
|
|
277
|
+
this.logger.warn('Correction ladder WorkItem never decided; raising again', { projectPath, class: record.class, workItemId: record.workItemId });
|
|
278
|
+
}
|
|
279
|
+
if (!this.pool)
|
|
280
|
+
return { raised: false, skipped: 'no_pool' };
|
|
281
|
+
const target = (await this.targetFor(projectPath)) ?? this.fallbackTarget;
|
|
282
|
+
if (!(await this.targetAwake(target)))
|
|
283
|
+
return { raised: false, skipped: 'target_dormant', target };
|
|
284
|
+
if (again && record.decision) {
|
|
285
|
+
record.previousDecisions = [...record.previousDecisions, record.decision];
|
|
286
|
+
record.decision = null;
|
|
287
|
+
}
|
|
288
|
+
const wi = buildCorrectionWorkItem(record, projectPath, target, again);
|
|
289
|
+
await this.pool.addToPool(wi);
|
|
290
|
+
record.workItemId = wi.id;
|
|
291
|
+
record.workItemAt = new Date(this.now()).toISOString();
|
|
292
|
+
return { raised: true, workItemId: wi.id, target };
|
|
293
|
+
}
|
|
294
|
+
/** The lead for a project; errors count as "no lead". */
|
|
295
|
+
async targetFor(projectPath) {
|
|
296
|
+
if (!this.resolveTarget)
|
|
297
|
+
return null;
|
|
298
|
+
try {
|
|
299
|
+
return await this.resolveTarget(projectPath);
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/** Errors count as dormant: a chore is never worth risking a wake. */
|
|
306
|
+
async targetAwake(target) {
|
|
307
|
+
if (!this.isTargetAwake)
|
|
308
|
+
return true;
|
|
309
|
+
try {
|
|
310
|
+
return await this.isTargetAwake(target);
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async read(projectPath) {
|
|
317
|
+
const data = await safeReadJson(correctionLadderPath(projectPath), null);
|
|
318
|
+
const classes = data && typeof data.classes === 'object' && data.classes ? data.classes : {};
|
|
319
|
+
return { version: 1, classes: { ...classes } };
|
|
320
|
+
}
|
|
321
|
+
async write(projectPath, store) {
|
|
322
|
+
const file = correctionLadderPath(projectPath);
|
|
323
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
324
|
+
await atomicWriteJson(file, store);
|
|
325
|
+
}
|
|
326
|
+
/** Run `fn` after every earlier operation on the same project's store. */
|
|
327
|
+
withLock(projectPath, fn) {
|
|
328
|
+
const key = path.resolve(projectPath);
|
|
329
|
+
const prev = this.locks.get(key) ?? Promise.resolve();
|
|
330
|
+
const next = prev.then(fn, fn);
|
|
331
|
+
this.locks.set(key, next.catch(() => undefined));
|
|
332
|
+
return next;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
//# sourceMappingURL=correction-ladder.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correction-ladder.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/memory/correction-ladder.service.ts"],"names":[],"mappings":"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"}
|