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.
Files changed (49) hide show
  1. package/config/skills/agent/core/project-tickets/SKILL.md +21 -0
  2. package/config/skills/agent/core/project-tickets/execute.sh +15 -5
  3. package/config/skills/agent/core/record-learning/SKILL.md +12 -1
  4. package/config/skills/agent/core/record-learning/execute.sh +24 -2
  5. package/config/skills/team-leader/decide-correction/SKILL.md +65 -0
  6. package/config/skills/team-leader/decide-correction/execute.sh +63 -0
  7. package/config/skills/team-leader/handle-failure/SKILL.md +2 -0
  8. package/config/skills/team-leader/handle-failure/execute.sh +18 -0
  9. package/dist/backend/backend/src/constants.d.ts +35 -0
  10. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  11. package/dist/backend/backend/src/constants.js +36 -0
  12. package/dist/backend/backend/src/constants.js.map +1 -1
  13. package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts +42 -2
  14. package/dist/backend/backend/src/controllers/memory/memory.controller.d.ts.map +1 -1
  15. package/dist/backend/backend/src/controllers/memory/memory.controller.js +111 -4
  16. package/dist/backend/backend/src/controllers/memory/memory.controller.js.map +1 -1
  17. package/dist/backend/backend/src/controllers/memory/memory.routes.d.ts +3 -0
  18. package/dist/backend/backend/src/controllers/memory/memory.routes.d.ts.map +1 -1
  19. package/dist/backend/backend/src/controllers/memory/memory.routes.js +7 -1
  20. package/dist/backend/backend/src/controllers/memory/memory.routes.js.map +1 -1
  21. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +8 -0
  22. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
  23. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +28 -0
  24. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
  25. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +1 -0
  26. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts.map +1 -1
  27. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +4 -1
  28. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js.map +1 -1
  29. package/dist/backend/backend/src/index.d.ts.map +1 -1
  30. package/dist/backend/backend/src/index.js +25 -0
  31. package/dist/backend/backend/src/index.js.map +1 -1
  32. package/dist/backend/backend/src/services/memory/correction-ladder.service.d.ts +225 -0
  33. package/dist/backend/backend/src/services/memory/correction-ladder.service.d.ts.map +1 -0
  34. package/dist/backend/backend/src/services/memory/correction-ladder.service.js +335 -0
  35. package/dist/backend/backend/src/services/memory/correction-ladder.service.js.map +1 -0
  36. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-retro.d.ts +99 -1
  37. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-retro.d.ts.map +1 -1
  38. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-retro.js +188 -16
  39. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-retro.js.map +1 -1
  40. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +53 -4
  41. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
  42. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +226 -27
  43. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
  44. package/dist/backend/build-info.json +2 -2
  45. package/dist/cli/backend/src/constants.d.ts +35 -0
  46. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  47. package/dist/cli/backend/src/constants.js +36 -0
  48. package/dist/cli/backend/src/constants.js.map +1 -1
  49. 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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"}