pmp-gywd 3.3.0
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/LICENSE +27 -0
- package/README.md +567 -0
- package/bin/install.js +348 -0
- package/commands/gywd/add-phase.md +207 -0
- package/commands/gywd/anticipate.md +271 -0
- package/commands/gywd/bootstrap.md +336 -0
- package/commands/gywd/challenge.md +344 -0
- package/commands/gywd/check-drift.md +144 -0
- package/commands/gywd/complete-milestone.md +106 -0
- package/commands/gywd/consider-issues.md +202 -0
- package/commands/gywd/context.md +93 -0
- package/commands/gywd/create-roadmap.md +115 -0
- package/commands/gywd/deps.md +169 -0
- package/commands/gywd/digest.md +138 -0
- package/commands/gywd/discuss-milestone.md +47 -0
- package/commands/gywd/discuss-phase.md +60 -0
- package/commands/gywd/execute-plan.md +161 -0
- package/commands/gywd/extract-decisions.md +325 -0
- package/commands/gywd/health.md +150 -0
- package/commands/gywd/help.md +556 -0
- package/commands/gywd/history.md +278 -0
- package/commands/gywd/impact.md +317 -0
- package/commands/gywd/init.md +95 -0
- package/commands/gywd/insert-phase.md +227 -0
- package/commands/gywd/list-phase-assumptions.md +50 -0
- package/commands/gywd/map-codebase.md +84 -0
- package/commands/gywd/memory.md +159 -0
- package/commands/gywd/new-milestone.md +59 -0
- package/commands/gywd/new-project.md +315 -0
- package/commands/gywd/pause-work.md +123 -0
- package/commands/gywd/plan-fix.md +205 -0
- package/commands/gywd/plan-phase.md +93 -0
- package/commands/gywd/preview-plan.md +139 -0
- package/commands/gywd/profile.md +363 -0
- package/commands/gywd/progress.md +317 -0
- package/commands/gywd/remove-phase.md +338 -0
- package/commands/gywd/research-phase.md +91 -0
- package/commands/gywd/resume-work.md +40 -0
- package/commands/gywd/rollback.md +179 -0
- package/commands/gywd/status.md +42 -0
- package/commands/gywd/sync-github.md +234 -0
- package/commands/gywd/verify-work.md +71 -0
- package/commands/gywd/why.md +251 -0
- package/docs/COMMANDS.md +722 -0
- package/docs/CONTRIBUTING.md +342 -0
- package/docs/EXAMPLES.md +535 -0
- package/docs/GETTING-STARTED.md +262 -0
- package/docs/README.md +55 -0
- package/docs/RELEASING.md +159 -0
- package/get-your-work-done/core/agent-patterns.md +331 -0
- package/get-your-work-done/core/architecture.md +334 -0
- package/get-your-work-done/core/context-model-schema.json +154 -0
- package/get-your-work-done/core/decisions-schema.json +193 -0
- package/get-your-work-done/core/learning-state-schema.json +133 -0
- package/get-your-work-done/core/profile-schema.json +257 -0
- package/get-your-work-done/references/adaptive-decomposition.md +175 -0
- package/get-your-work-done/references/checkpoints.md +287 -0
- package/get-your-work-done/references/confidence-scoring.md +169 -0
- package/get-your-work-done/references/continuation-format.md +255 -0
- package/get-your-work-done/references/git-integration.md +254 -0
- package/get-your-work-done/references/plan-format.md +428 -0
- package/get-your-work-done/references/principles.md +157 -0
- package/get-your-work-done/references/questioning.md +162 -0
- package/get-your-work-done/references/research-pitfalls.md +215 -0
- package/get-your-work-done/references/scope-estimation.md +172 -0
- package/get-your-work-done/references/tdd.md +263 -0
- package/get-your-work-done/templates/codebase/architecture.md +255 -0
- package/get-your-work-done/templates/codebase/concerns.md +310 -0
- package/get-your-work-done/templates/codebase/conventions.md +307 -0
- package/get-your-work-done/templates/codebase/integrations.md +280 -0
- package/get-your-work-done/templates/codebase/stack.md +186 -0
- package/get-your-work-done/templates/codebase/structure.md +285 -0
- package/get-your-work-done/templates/codebase/testing.md +480 -0
- package/get-your-work-done/templates/config.json +18 -0
- package/get-your-work-done/templates/context.md +161 -0
- package/get-your-work-done/templates/continue-here.md +78 -0
- package/get-your-work-done/templates/discovery.md +146 -0
- package/get-your-work-done/templates/issues.md +32 -0
- package/get-your-work-done/templates/milestone-archive.md +123 -0
- package/get-your-work-done/templates/milestone-context.md +93 -0
- package/get-your-work-done/templates/milestone.md +115 -0
- package/get-your-work-done/templates/phase-prompt.md +303 -0
- package/get-your-work-done/templates/project.md +184 -0
- package/get-your-work-done/templates/research.md +529 -0
- package/get-your-work-done/templates/roadmap.md +196 -0
- package/get-your-work-done/templates/state.md +210 -0
- package/get-your-work-done/templates/summary.md +273 -0
- package/get-your-work-done/templates/uat-issues.md +143 -0
- package/get-your-work-done/workflows/complete-milestone.md +643 -0
- package/get-your-work-done/workflows/create-milestone.md +416 -0
- package/get-your-work-done/workflows/create-roadmap.md +481 -0
- package/get-your-work-done/workflows/discovery-phase.md +293 -0
- package/get-your-work-done/workflows/discuss-milestone.md +236 -0
- package/get-your-work-done/workflows/discuss-phase.md +247 -0
- package/get-your-work-done/workflows/execute-phase.md +1625 -0
- package/get-your-work-done/workflows/list-phase-assumptions.md +178 -0
- package/get-your-work-done/workflows/map-codebase.md +434 -0
- package/get-your-work-done/workflows/plan-phase.md +488 -0
- package/get-your-work-done/workflows/research-phase.md +436 -0
- package/get-your-work-done/workflows/resume-project.md +287 -0
- package/get-your-work-done/workflows/transition.md +580 -0
- package/get-your-work-done/workflows/verify-work.md +202 -0
- package/lib/automation/dependency-analyzer.js +635 -0
- package/lib/automation/doc-generator.js +643 -0
- package/lib/automation/index.js +42 -0
- package/lib/automation/test-generator.js +628 -0
- package/lib/context/context-analyzer.js +554 -0
- package/lib/context/context-cache.js +426 -0
- package/lib/context/context-predictor.js +622 -0
- package/lib/context/index.js +44 -0
- package/lib/memory/confidence-calibrator.js +484 -0
- package/lib/memory/feedback-collector.js +551 -0
- package/lib/memory/global-memory.js +465 -0
- package/lib/memory/index.js +75 -0
- package/lib/memory/pattern-aggregator.js +487 -0
- package/lib/memory/team-sync.js +501 -0
- package/lib/profile/index.js +24 -0
- package/lib/profile/pattern-learner.js +303 -0
- package/lib/profile/profile-manager.js +445 -0
- package/lib/questioning/index.js +49 -0
- package/lib/questioning/question-engine.js +311 -0
- package/lib/questioning/question-templates.js +315 -0
- package/lib/validators/command-validator.js +188 -0
- package/lib/validators/index.js +29 -0
- package/lib/validators/schema-validator.js +183 -0
- package/package.json +61 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Calibration storage location
|
|
9
|
+
*/
|
|
10
|
+
const CALIBRATION_DIR = path.join(os.homedir(), '.gywd', 'calibration');
|
|
11
|
+
const CALIBRATION_FILE = path.join(CALIBRATION_DIR, 'calibration.json');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Default prior parameters (Beta distribution)
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_PRIOR = {
|
|
17
|
+
alpha: 2, // Prior successes + 1
|
|
18
|
+
beta: 2, // Prior failures + 1
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* ConfidenceCalibrator - Bayesian confidence scoring
|
|
23
|
+
*
|
|
24
|
+
* Uses Bayesian updating with Beta-Binomial model to:
|
|
25
|
+
* - Maintain calibrated confidence estimates
|
|
26
|
+
* - Update beliefs based on observed outcomes
|
|
27
|
+
* - Track prediction accuracy over time
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const calibrator = new ConfidenceCalibrator();
|
|
31
|
+
* calibrator.init();
|
|
32
|
+
*
|
|
33
|
+
* // Record outcomes
|
|
34
|
+
* calibrator.recordOutcome('pattern:naming', true); // success
|
|
35
|
+
* calibrator.recordOutcome('pattern:naming', false); // failure
|
|
36
|
+
*
|
|
37
|
+
* // Get calibrated confidence
|
|
38
|
+
* const conf = calibrator.getCalibratedConfidence('pattern:naming', 0.8);
|
|
39
|
+
*/
|
|
40
|
+
class ConfidenceCalibrator {
|
|
41
|
+
constructor() {
|
|
42
|
+
this.calibrationData = {};
|
|
43
|
+
this.predictionHistory = [];
|
|
44
|
+
this.initialized = false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize the calibrator
|
|
49
|
+
* @returns {ConfidenceCalibrator} this for chaining
|
|
50
|
+
*/
|
|
51
|
+
init() {
|
|
52
|
+
this._ensureDirectories();
|
|
53
|
+
this._loadData();
|
|
54
|
+
this.initialized = true;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Ensure directories exist
|
|
60
|
+
* @private
|
|
61
|
+
*/
|
|
62
|
+
_ensureDirectories() {
|
|
63
|
+
if (!fs.existsSync(CALIBRATION_DIR)) {
|
|
64
|
+
fs.mkdirSync(CALIBRATION_DIR, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Load calibration data
|
|
70
|
+
* @private
|
|
71
|
+
*/
|
|
72
|
+
_loadData() {
|
|
73
|
+
try {
|
|
74
|
+
if (fs.existsSync(CALIBRATION_FILE)) {
|
|
75
|
+
const data = JSON.parse(fs.readFileSync(CALIBRATION_FILE, 'utf8'));
|
|
76
|
+
this.calibrationData = data.calibrationData || {};
|
|
77
|
+
this.predictionHistory = data.predictionHistory || [];
|
|
78
|
+
}
|
|
79
|
+
} catch (err) {
|
|
80
|
+
this.calibrationData = {};
|
|
81
|
+
this.predictionHistory = [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Save calibration data
|
|
87
|
+
*/
|
|
88
|
+
save() {
|
|
89
|
+
this._ensureDirectories();
|
|
90
|
+
fs.writeFileSync(CALIBRATION_FILE, JSON.stringify({
|
|
91
|
+
calibrationData: this.calibrationData,
|
|
92
|
+
predictionHistory: this.predictionHistory,
|
|
93
|
+
}, null, 2), 'utf8');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ==================== BAYESIAN UPDATING ====================
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get or create calibration data for a key
|
|
100
|
+
* @private
|
|
101
|
+
* @param {string} key - Calibration key
|
|
102
|
+
* @returns {object} Calibration data with alpha, beta
|
|
103
|
+
*/
|
|
104
|
+
_getCalibrationData(key) {
|
|
105
|
+
if (!this.calibrationData[key]) {
|
|
106
|
+
this.calibrationData[key] = {
|
|
107
|
+
alpha: DEFAULT_PRIOR.alpha,
|
|
108
|
+
beta: DEFAULT_PRIOR.beta,
|
|
109
|
+
totalOutcomes: 0,
|
|
110
|
+
successes: 0,
|
|
111
|
+
failures: 0,
|
|
112
|
+
lastUpdated: null,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return this.calibrationData[key];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Record an outcome for Bayesian updating
|
|
120
|
+
* @param {string} key - Calibration key (e.g., 'pattern:naming')
|
|
121
|
+
* @param {boolean} success - Whether the prediction was successful
|
|
122
|
+
* @param {number} [predictedConfidence] - The confidence that was predicted
|
|
123
|
+
*/
|
|
124
|
+
recordOutcome(key, success, predictedConfidence = null) {
|
|
125
|
+
if (!this.initialized) this.init();
|
|
126
|
+
|
|
127
|
+
const data = this._getCalibrationData(key);
|
|
128
|
+
|
|
129
|
+
// Bayesian update: add to alpha for success, beta for failure
|
|
130
|
+
if (success) {
|
|
131
|
+
data.alpha += 1;
|
|
132
|
+
data.successes += 1;
|
|
133
|
+
} else {
|
|
134
|
+
data.beta += 1;
|
|
135
|
+
data.failures += 1;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
data.totalOutcomes += 1;
|
|
139
|
+
data.lastUpdated = new Date().toISOString();
|
|
140
|
+
|
|
141
|
+
// Record in prediction history for calibration analysis
|
|
142
|
+
if (predictedConfidence !== null) {
|
|
143
|
+
this.predictionHistory.push({
|
|
144
|
+
key,
|
|
145
|
+
predictedConfidence,
|
|
146
|
+
actualOutcome: success,
|
|
147
|
+
timestamp: new Date().toISOString(),
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Keep history manageable
|
|
151
|
+
if (this.predictionHistory.length > 1000) {
|
|
152
|
+
this.predictionHistory = this.predictionHistory.slice(-1000);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this.save();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get the posterior mean (expected probability of success)
|
|
161
|
+
* @param {string} key - Calibration key
|
|
162
|
+
* @returns {number} Posterior mean 0-1
|
|
163
|
+
*/
|
|
164
|
+
getPosteriorMean(key) {
|
|
165
|
+
if (!this.initialized) this.init();
|
|
166
|
+
|
|
167
|
+
const data = this._getCalibrationData(key);
|
|
168
|
+
// Beta distribution mean = alpha / (alpha + beta)
|
|
169
|
+
return data.alpha / (data.alpha + data.beta);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get the posterior variance (uncertainty)
|
|
174
|
+
* @param {string} key - Calibration key
|
|
175
|
+
* @returns {number} Posterior variance
|
|
176
|
+
*/
|
|
177
|
+
getPosteriorVariance(key) {
|
|
178
|
+
if (!this.initialized) this.init();
|
|
179
|
+
|
|
180
|
+
const data = this._getCalibrationData(key);
|
|
181
|
+
const a = data.alpha;
|
|
182
|
+
const b = data.beta;
|
|
183
|
+
// Beta distribution variance
|
|
184
|
+
return (a * b) / ((a + b) ** 2 * (a + b + 1));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get calibrated confidence using Bayesian shrinkage
|
|
189
|
+
* @param {string} key - Calibration key
|
|
190
|
+
* @param {number} rawConfidence - Original confidence 0-1
|
|
191
|
+
* @returns {number} Calibrated confidence 0-1
|
|
192
|
+
*/
|
|
193
|
+
getCalibratedConfidence(key, rawConfidence) {
|
|
194
|
+
if (!this.initialized) this.init();
|
|
195
|
+
|
|
196
|
+
const data = this._getCalibrationData(key);
|
|
197
|
+
const posteriorMean = this.getPosteriorMean(key);
|
|
198
|
+
|
|
199
|
+
// Calculate shrinkage factor based on sample size
|
|
200
|
+
// More data = more weight on observed rate, less on prior
|
|
201
|
+
const n = data.totalOutcomes;
|
|
202
|
+
const priorWeight = (DEFAULT_PRIOR.alpha + DEFAULT_PRIOR.beta) / (n + DEFAULT_PRIOR.alpha + DEFAULT_PRIOR.beta);
|
|
203
|
+
const dataWeight = 1 - priorWeight;
|
|
204
|
+
|
|
205
|
+
// Blend raw confidence with posterior mean
|
|
206
|
+
// If we have lots of data, trust the observed rate more
|
|
207
|
+
// If we have little data, trust the raw confidence more
|
|
208
|
+
const calibrated = rawConfidence * priorWeight + posteriorMean * dataWeight;
|
|
209
|
+
|
|
210
|
+
// Ensure bounds
|
|
211
|
+
return Math.max(0.01, Math.min(0.99, calibrated));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get credible interval for confidence
|
|
216
|
+
* @param {string} key - Calibration key
|
|
217
|
+
* @param {number} [level=0.95] - Credible level (e.g., 0.95 for 95%)
|
|
218
|
+
* @returns {object} { lower, upper } bounds
|
|
219
|
+
*/
|
|
220
|
+
getCredibleInterval(key, level = 0.95) {
|
|
221
|
+
if (!this.initialized) this.init();
|
|
222
|
+
|
|
223
|
+
// Ensure key exists (side effect)
|
|
224
|
+
this._getCalibrationData(key);
|
|
225
|
+
|
|
226
|
+
// Approximation using normal distribution for large samples
|
|
227
|
+
// For small samples, this is a rough estimate
|
|
228
|
+
const mean = this.getPosteriorMean(key);
|
|
229
|
+
const variance = this.getPosteriorVariance(key);
|
|
230
|
+
const std = Math.sqrt(variance);
|
|
231
|
+
|
|
232
|
+
// Z-score for credible level
|
|
233
|
+
const z = this._getZScore(level);
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
lower: Math.max(0, mean - z * std),
|
|
237
|
+
upper: Math.min(1, mean + z * std),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get Z-score for a given confidence level
|
|
243
|
+
* @private
|
|
244
|
+
*/
|
|
245
|
+
_getZScore(level) {
|
|
246
|
+
// Common values
|
|
247
|
+
const zScores = {
|
|
248
|
+
0.90: 1.645,
|
|
249
|
+
0.95: 1.96,
|
|
250
|
+
0.99: 2.576,
|
|
251
|
+
};
|
|
252
|
+
return zScores[level] || 1.96;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ==================== CALIBRATION ANALYSIS ====================
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Analyze calibration accuracy
|
|
259
|
+
* Groups predictions by confidence bin and compares to actual outcomes
|
|
260
|
+
* @returns {object} Calibration analysis
|
|
261
|
+
*/
|
|
262
|
+
analyzeCalibration() {
|
|
263
|
+
if (!this.initialized) this.init();
|
|
264
|
+
|
|
265
|
+
if (this.predictionHistory.length < 10) {
|
|
266
|
+
return { error: 'Insufficient data for calibration analysis' };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Group by confidence bins
|
|
270
|
+
const bins = [
|
|
271
|
+
{ min: 0.0, max: 0.2, predictions: [], outcomes: [] },
|
|
272
|
+
{ min: 0.2, max: 0.4, predictions: [], outcomes: [] },
|
|
273
|
+
{ min: 0.4, max: 0.6, predictions: [], outcomes: [] },
|
|
274
|
+
{ min: 0.6, max: 0.8, predictions: [], outcomes: [] },
|
|
275
|
+
{ min: 0.8, max: 1.0, predictions: [], outcomes: [] },
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
for (const entry of this.predictionHistory) {
|
|
279
|
+
for (const bin of bins) {
|
|
280
|
+
if (entry.predictedConfidence >= bin.min && entry.predictedConfidence < bin.max) {
|
|
281
|
+
bin.predictions.push(entry.predictedConfidence);
|
|
282
|
+
bin.outcomes.push(entry.actualOutcome ? 1 : 0);
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Calculate calibration metrics
|
|
289
|
+
const analysis = {
|
|
290
|
+
bins: bins.map(bin => ({
|
|
291
|
+
range: `${bin.min.toFixed(1)}-${bin.max.toFixed(1)}`,
|
|
292
|
+
count: bin.predictions.length,
|
|
293
|
+
meanPredicted: bin.predictions.length > 0
|
|
294
|
+
? bin.predictions.reduce((a, b) => a + b, 0) / bin.predictions.length
|
|
295
|
+
: 0,
|
|
296
|
+
actualRate: bin.outcomes.length > 0
|
|
297
|
+
? bin.outcomes.reduce((a, b) => a + b, 0) / bin.outcomes.length
|
|
298
|
+
: 0,
|
|
299
|
+
})),
|
|
300
|
+
totalPredictions: this.predictionHistory.length,
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// Calculate calibration error (mean absolute error between predicted and actual)
|
|
304
|
+
let totalError = 0;
|
|
305
|
+
let countWithData = 0;
|
|
306
|
+
for (const bin of analysis.bins) {
|
|
307
|
+
if (bin.count >= 3) {
|
|
308
|
+
totalError += Math.abs(bin.meanPredicted - bin.actualRate);
|
|
309
|
+
countWithData++;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
analysis.calibrationError = countWithData > 0 ? totalError / countWithData : 0;
|
|
313
|
+
|
|
314
|
+
// Brier score (lower is better)
|
|
315
|
+
let brierSum = 0;
|
|
316
|
+
for (const entry of this.predictionHistory) {
|
|
317
|
+
const outcome = entry.actualOutcome ? 1 : 0;
|
|
318
|
+
brierSum += (entry.predictedConfidence - outcome) ** 2;
|
|
319
|
+
}
|
|
320
|
+
analysis.brierScore = brierSum / this.predictionHistory.length;
|
|
321
|
+
|
|
322
|
+
return analysis;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Check if predictions are well-calibrated
|
|
327
|
+
* @returns {boolean} Whether calibration is acceptable
|
|
328
|
+
*/
|
|
329
|
+
isWellCalibrated() {
|
|
330
|
+
const analysis = this.analyzeCalibration();
|
|
331
|
+
if (analysis.error) return true; // Assume well-calibrated with insufficient data
|
|
332
|
+
|
|
333
|
+
// Calibration error < 0.1 is considered good
|
|
334
|
+
return analysis.calibrationError < 0.1;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Get calibration adjustment factor
|
|
339
|
+
* @param {string} key - Calibration key
|
|
340
|
+
* @returns {number} Adjustment factor (multiply raw confidence by this)
|
|
341
|
+
*/
|
|
342
|
+
getAdjustmentFactor(key) {
|
|
343
|
+
if (!this.initialized) this.init();
|
|
344
|
+
|
|
345
|
+
const data = this._getCalibrationData(key);
|
|
346
|
+
if (data.totalOutcomes < 3) return 1.0; // Not enough data
|
|
347
|
+
|
|
348
|
+
const observedRate = data.successes / data.totalOutcomes;
|
|
349
|
+
const expectedRate = 0.5; // Assume predictions claim 50% average
|
|
350
|
+
|
|
351
|
+
// Adjustment to bring predictions closer to observed reality
|
|
352
|
+
return Math.max(0.5, Math.min(2.0, observedRate / expectedRate));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ==================== UTILITIES ====================
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Get statistics for a key
|
|
359
|
+
* @param {string} key - Calibration key
|
|
360
|
+
* @returns {object} Statistics
|
|
361
|
+
*/
|
|
362
|
+
getKeyStats(key) {
|
|
363
|
+
if (!this.initialized) this.init();
|
|
364
|
+
|
|
365
|
+
const data = this._getCalibrationData(key);
|
|
366
|
+
const interval = this.getCredibleInterval(key);
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
key,
|
|
370
|
+
posteriorMean: this.getPosteriorMean(key),
|
|
371
|
+
posteriorVariance: this.getPosteriorVariance(key),
|
|
372
|
+
credibleInterval: interval,
|
|
373
|
+
totalOutcomes: data.totalOutcomes,
|
|
374
|
+
successRate: data.totalOutcomes > 0
|
|
375
|
+
? data.successes / data.totalOutcomes
|
|
376
|
+
: 0.5,
|
|
377
|
+
lastUpdated: data.lastUpdated,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Get all calibration keys
|
|
383
|
+
* @returns {Array} List of keys
|
|
384
|
+
*/
|
|
385
|
+
getKeys() {
|
|
386
|
+
if (!this.initialized) this.init();
|
|
387
|
+
return Object.keys(this.calibrationData);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Get overall statistics
|
|
392
|
+
* @returns {object} Statistics
|
|
393
|
+
*/
|
|
394
|
+
getStats() {
|
|
395
|
+
if (!this.initialized) this.init();
|
|
396
|
+
|
|
397
|
+
const keys = this.getKeys();
|
|
398
|
+
let totalOutcomes = 0;
|
|
399
|
+
let totalSuccesses = 0;
|
|
400
|
+
|
|
401
|
+
for (const key of keys) {
|
|
402
|
+
const data = this.calibrationData[key];
|
|
403
|
+
totalOutcomes += data.totalOutcomes;
|
|
404
|
+
totalSuccesses += data.successes;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
keysTracked: keys.length,
|
|
409
|
+
totalOutcomes,
|
|
410
|
+
overallSuccessRate: totalOutcomes > 0 ? totalSuccesses / totalOutcomes : 0.5,
|
|
411
|
+
predictionHistorySize: this.predictionHistory.length,
|
|
412
|
+
isWellCalibrated: this.isWellCalibrated(),
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Clear calibration data for a key
|
|
418
|
+
* @param {string} key - Key to clear
|
|
419
|
+
*/
|
|
420
|
+
clearKey(key) {
|
|
421
|
+
if (!this.initialized) this.init();
|
|
422
|
+
delete this.calibrationData[key];
|
|
423
|
+
this.save();
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Clear all calibration data
|
|
428
|
+
*/
|
|
429
|
+
clear() {
|
|
430
|
+
this.calibrationData = {};
|
|
431
|
+
this.predictionHistory = [];
|
|
432
|
+
this.save();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Export calibration data
|
|
437
|
+
* @returns {object} Exportable data
|
|
438
|
+
*/
|
|
439
|
+
export() {
|
|
440
|
+
if (!this.initialized) this.init();
|
|
441
|
+
|
|
442
|
+
return {
|
|
443
|
+
version: '1.0.0',
|
|
444
|
+
exportedAt: new Date().toISOString(),
|
|
445
|
+
calibrationData: this.calibrationData,
|
|
446
|
+
predictionHistory: this.predictionHistory,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Import calibration data
|
|
452
|
+
* @param {object} data - Data to import
|
|
453
|
+
*/
|
|
454
|
+
import(data) {
|
|
455
|
+
if (!this.initialized) this.init();
|
|
456
|
+
|
|
457
|
+
if (data.calibrationData) {
|
|
458
|
+
this.calibrationData = { ...this.calibrationData, ...data.calibrationData };
|
|
459
|
+
}
|
|
460
|
+
if (data.predictionHistory) {
|
|
461
|
+
this.predictionHistory = [
|
|
462
|
+
...this.predictionHistory,
|
|
463
|
+
...data.predictionHistory,
|
|
464
|
+
].slice(-1000);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
this.save();
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Get calibration directory path
|
|
472
|
+
* @returns {string} Directory path
|
|
473
|
+
*/
|
|
474
|
+
static getCalibrationDir() {
|
|
475
|
+
return CALIBRATION_DIR;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
module.exports = {
|
|
480
|
+
ConfidenceCalibrator,
|
|
481
|
+
DEFAULT_PRIOR,
|
|
482
|
+
CALIBRATION_DIR,
|
|
483
|
+
CALIBRATION_FILE,
|
|
484
|
+
};
|