@dzhechkov/harness-core 0.7.2 → 0.7.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/.dz-manifest.json +121 -41
- package/README.md +1 -1
- package/dist/cli-flag-notice.d.ts +50 -0
- package/dist/cli-flag-notice.d.ts.map +1 -0
- package/dist/cli-flag-notice.js +106 -0
- package/dist/cli-flag-notice.js.map +1 -0
- package/dist/event-chain.d.ts +50 -0
- package/dist/event-chain.d.ts.map +1 -1
- package/dist/event-chain.js +31 -0
- package/dist/event-chain.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/name-check.d.ts +98 -0
- package/dist/name-check.d.ts.map +1 -0
- package/dist/name-check.js +333 -0
- package/dist/name-check.js.map +1 -0
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +33 -5
- package/dist/operations.js.map +1 -1
- package/dist/provenance.d.ts +100 -92
- package/dist/provenance.d.ts.map +1 -1
- package/dist/provenance.js +122 -122
- package/dist/provenance.js.map +1 -1
- package/dist/recall-domain-boost.d.ts +10 -3
- package/dist/recall-domain-boost.d.ts.map +1 -1
- package/dist/recall-domain-boost.js +7 -0
- package/dist/recall-domain-boost.js.map +1 -1
- package/dist/recall-hook-policy.d.ts +15 -0
- package/dist/recall-hook-policy.d.ts.map +1 -1
- package/dist/recall-hook-policy.js +59 -0
- package/dist/recall-hook-policy.js.map +1 -1
- package/dist/recap.d.ts +146 -0
- package/dist/recap.d.ts.map +1 -0
- package/dist/recap.js +346 -0
- package/dist/recap.js.map +1 -0
- package/dist/retro.d.ts +131 -0
- package/dist/retro.d.ts.map +1 -0
- package/dist/retro.js +207 -0
- package/dist/retro.js.map +1 -0
- package/dist/score.d.ts +21 -0
- package/dist/score.d.ts.map +1 -1
- package/dist/score.js +44 -3
- package/dist/score.js.map +1 -1
- package/dist/vector-tier.d.ts +54 -0
- package/dist/vector-tier.d.ts.map +1 -1
- package/dist/vector-tier.js +69 -8
- package/dist/vector-tier.js.map +1 -1
- package/package.json +8 -8
- package/sbom.json +240 -40
- package/src/cli-flag-notice.ts +114 -0
- package/src/event-chain.ts +64 -0
- package/src/index.ts +13 -0
- package/src/name-check.ts +331 -0
- package/src/operations.ts +34 -6
- package/src/provenance.ts +217 -0
- package/src/recall-domain-boost.ts +10 -3
- package/src/recall-hook-policy.ts +60 -0
- package/src/recap.ts +462 -0
- package/src/score.ts +53 -3
- package/src/vector-tier.ts +109 -10
package/dist/retro.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dz retro` — what was done over a day, a week or a month.
|
|
3
|
+
*
|
|
4
|
+
* This module is PURE: no filesystem, no network, and — load-bearing — no clock. The window arrives
|
|
5
|
+
* as a parameter, because a window you cannot pin in a test is a window whose arithmetic errors you
|
|
6
|
+
* cannot catch. MEASURED in this project 2026-08-22: an agent's timestamp was off by a YEAR, the
|
|
7
|
+
* query returned 15 530 "hits" for a "week", and nothing about the output looked wrong.
|
|
8
|
+
*
|
|
9
|
+
* Its second job is refusing. Half of an honest report is declining to answer what the data cannot
|
|
10
|
+
* support, and those refusals live here as behaviour — types that cannot express a quarter, a
|
|
11
|
+
* decision function that names the real span in days, and a three-state section verdict where
|
|
12
|
+
* "the source said nothing" and "the source was not read" can never collapse into one zero.
|
|
13
|
+
*
|
|
14
|
+
* See features/dz-retro/03_adr/ for the decisions and the measurements behind them.
|
|
15
|
+
*/
|
|
16
|
+
/** The only horizons this project has the data for. A quarter or a year is NOT SPELLABLE (ADR-001). */
|
|
17
|
+
export type RetroHorizon = 'day' | 'week' | 'month';
|
|
18
|
+
/** Horizons a user may ASK for — recognised so they are refused loudly, never swallowed. */
|
|
19
|
+
export type RefusedHorizon = 'quarter' | 'half-year' | 'year';
|
|
20
|
+
export declare const REFUSED_HORIZONS: readonly RefusedHorizon[];
|
|
21
|
+
export interface RetroWindow {
|
|
22
|
+
readonly horizon: RetroHorizon;
|
|
23
|
+
/** Inclusive ISO date (YYYY-MM-DD) of the first day in the window. */
|
|
24
|
+
readonly startIso: string;
|
|
25
|
+
/** Inclusive ISO date of the last day — the anchor. */
|
|
26
|
+
readonly endIso: string;
|
|
27
|
+
readonly days: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The window for a horizon, anchored on an EXPLICIT date. Never reads the clock.
|
|
31
|
+
* `atIso` may be a full timestamp; only its date part is used.
|
|
32
|
+
*/
|
|
33
|
+
export declare function retroWindow(horizon: RetroHorizon, atIso: string): RetroWindow;
|
|
34
|
+
/** Is this instant inside the window? Compared in UTC, never as strings (ADR/AM-5). */
|
|
35
|
+
export declare function withinWindow(w: RetroWindow, isoInstant: string): boolean;
|
|
36
|
+
export interface HorizonDecision {
|
|
37
|
+
readonly action: 'report' | 'refuse';
|
|
38
|
+
readonly reason: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* May we report over the requested horizon at all?
|
|
42
|
+
*
|
|
43
|
+
* `spanDays` is the age of the LONGEST record we actually hold. Asking for a year over 174 days of
|
|
44
|
+
* data is not a thin report — it is an invented one, so it is refused and the real span is named.
|
|
45
|
+
*/
|
|
46
|
+
export declare function decideHorizon(input: {
|
|
47
|
+
requested: string;
|
|
48
|
+
spanDays: number;
|
|
49
|
+
}): HorizonDecision;
|
|
50
|
+
export type SectionStatus = 'full' | 'partial' | 'unavailable';
|
|
51
|
+
export interface SectionVerdict {
|
|
52
|
+
readonly status: SectionStatus;
|
|
53
|
+
/** The date this source's records begin — computed from the source itself, never hardcoded. */
|
|
54
|
+
readonly dataStart: string | null;
|
|
55
|
+
readonly note: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Does this source cover the whole window?
|
|
59
|
+
*
|
|
60
|
+
* `dataStart: null` means the source was NOT READ — a different fact from "read, and empty".
|
|
61
|
+
* Collapsing the two is how a report says "nothing happened" about a week it could not see.
|
|
62
|
+
*/
|
|
63
|
+
export declare function sectionStatus(input: {
|
|
64
|
+
dataStart: string | null;
|
|
65
|
+
windowStart: string;
|
|
66
|
+
}): SectionVerdict;
|
|
67
|
+
export interface ForbiddenMetric {
|
|
68
|
+
readonly name: string;
|
|
69
|
+
/** The measurement that disqualifies it. A bare ban decays into a word list. */
|
|
70
|
+
readonly reason: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Measures of the INSTRUMENT, not of the work (ADR-003). Each will be proposed again precisely
|
|
74
|
+
* because each is a one-liner to compute, so each carries the measurement that refutes it.
|
|
75
|
+
*/
|
|
76
|
+
export declare const FORBIDDEN_METRICS: readonly ForbiddenMetric[];
|
|
77
|
+
export interface Delivery {
|
|
78
|
+
readonly slug: string;
|
|
79
|
+
readonly createdIso: string;
|
|
80
|
+
/** 'unique' carries a grade; 'ambiguous' and 'none' are facts about the report, not gaps. */
|
|
81
|
+
readonly gradeStatus: 'unique' | 'ambiguous' | 'none' | 'no-report';
|
|
82
|
+
readonly grade: string | null;
|
|
83
|
+
}
|
|
84
|
+
export interface Publish {
|
|
85
|
+
readonly pkg: string;
|
|
86
|
+
readonly version: string;
|
|
87
|
+
readonly iso: string;
|
|
88
|
+
}
|
|
89
|
+
export interface GuardRun {
|
|
90
|
+
readonly iso: string;
|
|
91
|
+
readonly verdict: string;
|
|
92
|
+
readonly rules: readonly string[];
|
|
93
|
+
}
|
|
94
|
+
export interface ReuseFacts {
|
|
95
|
+
readonly dataStart: string | null;
|
|
96
|
+
readonly eventsInWindow: number;
|
|
97
|
+
readonly lessonsEverRecalled: number;
|
|
98
|
+
readonly lessonsTotal: number;
|
|
99
|
+
}
|
|
100
|
+
export interface SourceFacts<T> {
|
|
101
|
+
readonly dataStart: string | null;
|
|
102
|
+
readonly items: readonly T[];
|
|
103
|
+
}
|
|
104
|
+
export interface RetroFacts {
|
|
105
|
+
readonly window: RetroWindow;
|
|
106
|
+
/** The longest record we hold, in days — what `decideHorizon` judges against. */
|
|
107
|
+
readonly spanDays: number;
|
|
108
|
+
/** `null` means NOT READ. An empty `items` means read-and-empty. The type keeps them apart. */
|
|
109
|
+
readonly deliveries: SourceFacts<Delivery> | null;
|
|
110
|
+
readonly publishes: SourceFacts<Publish> | null;
|
|
111
|
+
readonly guard: SourceFacts<GuardRun> | null;
|
|
112
|
+
readonly reuse: ReuseFacts | null;
|
|
113
|
+
/** Feature dirs on disk that git has never seen — the report is blind to them, and says so. */
|
|
114
|
+
readonly uncommittedSlugs: readonly string[];
|
|
115
|
+
}
|
|
116
|
+
export interface RetroSection {
|
|
117
|
+
readonly id: 'deliveries' | 'publishes' | 'discipline' | 'reuse';
|
|
118
|
+
readonly title: string;
|
|
119
|
+
readonly verdict: SectionVerdict;
|
|
120
|
+
readonly lines: readonly string[];
|
|
121
|
+
}
|
|
122
|
+
export interface RetroReport {
|
|
123
|
+
readonly window: RetroWindow;
|
|
124
|
+
readonly spanDays: number;
|
|
125
|
+
readonly sections: readonly RetroSection[];
|
|
126
|
+
readonly caveats: readonly string[];
|
|
127
|
+
}
|
|
128
|
+
export declare function buildRetro(facts: RetroFacts): RetroReport;
|
|
129
|
+
/** The human rendering. `--json` prints the SAME `RetroReport` — one structure, two spellings (FR-6). */
|
|
130
|
+
export declare function renderRetro(report: RetroReport): string[];
|
|
131
|
+
//# sourceMappingURL=retro.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retro.d.ts","sourceRoot":"","sources":["../src/retro.ts"],"names":[],"mappings":"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"}
|
package/dist/retro.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dz retro` — what was done over a day, a week or a month.
|
|
3
|
+
*
|
|
4
|
+
* This module is PURE: no filesystem, no network, and — load-bearing — no clock. The window arrives
|
|
5
|
+
* as a parameter, because a window you cannot pin in a test is a window whose arithmetic errors you
|
|
6
|
+
* cannot catch. MEASURED in this project 2026-08-22: an agent's timestamp was off by a YEAR, the
|
|
7
|
+
* query returned 15 530 "hits" for a "week", and nothing about the output looked wrong.
|
|
8
|
+
*
|
|
9
|
+
* Its second job is refusing. Half of an honest report is declining to answer what the data cannot
|
|
10
|
+
* support, and those refusals live here as behaviour — types that cannot express a quarter, a
|
|
11
|
+
* decision function that names the real span in days, and a three-state section verdict where
|
|
12
|
+
* "the source said nothing" and "the source was not read" can never collapse into one zero.
|
|
13
|
+
*
|
|
14
|
+
* See features/dz-retro/03_adr/ for the decisions and the measurements behind them.
|
|
15
|
+
*/
|
|
16
|
+
export const REFUSED_HORIZONS = ['quarter', 'half-year', 'year'];
|
|
17
|
+
const HORIZON_DAYS = { day: 1, week: 7, month: 30 };
|
|
18
|
+
const REFUSED_DAYS = { quarter: 90, 'half-year': 182, year: 365 };
|
|
19
|
+
const DAY_MS = 86_400_000;
|
|
20
|
+
function isoDay(value) {
|
|
21
|
+
return value.slice(0, 10);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The window for a horizon, anchored on an EXPLICIT date. Never reads the clock.
|
|
25
|
+
* `atIso` may be a full timestamp; only its date part is used.
|
|
26
|
+
*/
|
|
27
|
+
export function retroWindow(horizon, atIso) {
|
|
28
|
+
const end = isoDay(atIso);
|
|
29
|
+
const endMs = Date.parse(`${end}T00:00:00.000Z`);
|
|
30
|
+
if (Number.isNaN(endMs))
|
|
31
|
+
throw new Error(`retroWindow: not an ISO date: ${JSON.stringify(atIso)}`);
|
|
32
|
+
const days = HORIZON_DAYS[horizon];
|
|
33
|
+
const startMs = endMs - (days - 1) * DAY_MS;
|
|
34
|
+
return { horizon, startIso: new Date(startMs).toISOString().slice(0, 10), endIso: end, days };
|
|
35
|
+
}
|
|
36
|
+
/** Is this instant inside the window? Compared in UTC, never as strings (ADR/AM-5). */
|
|
37
|
+
export function withinWindow(w, isoInstant) {
|
|
38
|
+
const t = Date.parse(isoInstant);
|
|
39
|
+
if (Number.isNaN(t))
|
|
40
|
+
return false;
|
|
41
|
+
const from = Date.parse(`${w.startIso}T00:00:00.000Z`);
|
|
42
|
+
const to = Date.parse(`${w.endIso}T00:00:00.000Z`) + DAY_MS;
|
|
43
|
+
return t >= from && t < to;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* May we report over the requested horizon at all?
|
|
47
|
+
*
|
|
48
|
+
* `spanDays` is the age of the LONGEST record we actually hold. Asking for a year over 174 days of
|
|
49
|
+
* data is not a thin report — it is an invented one, so it is refused and the real span is named.
|
|
50
|
+
*/
|
|
51
|
+
export function decideHorizon(input) {
|
|
52
|
+
const req = input.requested.trim().toLowerCase();
|
|
53
|
+
const span = Number.isFinite(input.spanDays) ? Math.max(0, Math.floor(input.spanDays)) : 0;
|
|
54
|
+
if (req in HORIZON_DAYS) {
|
|
55
|
+
const need = HORIZON_DAYS[req];
|
|
56
|
+
if (span < need) {
|
|
57
|
+
return {
|
|
58
|
+
action: 'refuse',
|
|
59
|
+
reason: `a ${req} needs ${need} day(s) of records and we hold ${span} — reporting it would invent the difference`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return { action: 'report', reason: `${req}: ${need} day(s) against ${span} day(s) of records` };
|
|
63
|
+
}
|
|
64
|
+
if (REFUSED_HORIZONS.includes(req)) {
|
|
65
|
+
const need = REFUSED_DAYS[req];
|
|
66
|
+
return {
|
|
67
|
+
action: 'refuse',
|
|
68
|
+
reason: `a ${req} needs about ${need} days of records and the longest record here spans ${span} day(s) — there is exactly one complete quarter, so a quarter-over-quarter comparison is arithmetically impossible and a year would be fabrication`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return { action: 'refuse', reason: `unknown horizon ${JSON.stringify(input.requested)} — use --day, --week or --month` };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Does this source cover the whole window?
|
|
75
|
+
*
|
|
76
|
+
* `dataStart: null` means the source was NOT READ — a different fact from "read, and empty".
|
|
77
|
+
* Collapsing the two is how a report says "nothing happened" about a week it could not see.
|
|
78
|
+
*/
|
|
79
|
+
export function sectionStatus(input) {
|
|
80
|
+
if (input.dataStart === null) {
|
|
81
|
+
return { status: 'unavailable', dataStart: null, note: 'source not read — this section says nothing, which is not the same as zero' };
|
|
82
|
+
}
|
|
83
|
+
const start = isoDay(input.dataStart);
|
|
84
|
+
if (start <= isoDay(input.windowStart)) {
|
|
85
|
+
return { status: 'full', dataStart: start, note: `records cover the whole window (from ${start})` };
|
|
86
|
+
}
|
|
87
|
+
return { status: 'partial', dataStart: start, note: `records only begin ${start}, inside the window — everything before that is unknown, not absent` };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Measures of the INSTRUMENT, not of the work (ADR-003). Each will be proposed again precisely
|
|
91
|
+
* because each is a one-liner to compute, so each carries the measurement that refutes it.
|
|
92
|
+
*/
|
|
93
|
+
export const FORBIDDEN_METRICS = [
|
|
94
|
+
{ name: 'commit count', reason: 'this project mandates a commit per logical change; 1318 commits over 66 active days measures compliance with that rule, not output (MEASURED 2026-08-22)' },
|
|
95
|
+
{ name: 'lines changed', reason: 'generated artifacts dominate — 352 of 1318 commits are docs, and one pipeline run writes 8-10 files before a line of product code exists' },
|
|
96
|
+
{ name: 'token spend', reason: 'self-declared an estimate, once wrong sixfold, covers 17 days, and 20 of 86 ledger rows carry no number by construction' },
|
|
97
|
+
{ name: 'learning event volume', reason: '640 in May against 10454 in August, but the sources are post-edit and post-command hooks: the curve measures when hooks were installed' },
|
|
98
|
+
{ name: 'inventory counts', reason: 'skills, packages and tests only ever grow, so they can only ever flatter' },
|
|
99
|
+
{ name: 'learned lesson count', reason: 'already refuted by this project’s own dz compounding: 54% of the pool has never been read by anyone' },
|
|
100
|
+
];
|
|
101
|
+
function emptyOrUnavailable(v, emptyLine) {
|
|
102
|
+
return v.status === 'unavailable'
|
|
103
|
+
? ['not read — this section cannot say anything about this window']
|
|
104
|
+
: [emptyLine];
|
|
105
|
+
}
|
|
106
|
+
export function buildRetro(facts) {
|
|
107
|
+
const ws = facts.window.startIso;
|
|
108
|
+
const sections = [];
|
|
109
|
+
// 1. Deliveries
|
|
110
|
+
{
|
|
111
|
+
const v = sectionStatus({ dataStart: facts.deliveries?.dataStart ?? null, windowStart: ws });
|
|
112
|
+
const items = (facts.deliveries?.items ?? []).filter((d) => withinWindow(facts.window, d.createdIso));
|
|
113
|
+
const graded = items.filter((d) => d.gradeStatus === 'unique');
|
|
114
|
+
const ambiguous = items.filter((d) => d.gradeStatus === 'ambiguous');
|
|
115
|
+
const ungraded = items.filter((d) => d.gradeStatus === 'none' || d.gradeStatus === 'no-report');
|
|
116
|
+
const lines = items.length === 0
|
|
117
|
+
? emptyOrUnavailable(v, 'no feature directories were created in this window')
|
|
118
|
+
: [
|
|
119
|
+
`${items.length} feature director${items.length === 1 ? 'y' : 'ies'} created`,
|
|
120
|
+
`${graded.length} carry a grade an independent review stated unambiguously${graded.length > 0 ? `: ${tally(graded.map((d) => d.grade))}` : ''}`,
|
|
121
|
+
`${ambiguous.length} have a report that states MORE THAN ONE grade — reported as ambiguous, never guessed`,
|
|
122
|
+
`${ungraded.length} have no letter grade in their report, or no report at all`,
|
|
123
|
+
'cadence is not value: this counts deliveries, not what they were worth',
|
|
124
|
+
];
|
|
125
|
+
sections.push({ id: 'deliveries', title: 'Deliveries', verdict: v, lines });
|
|
126
|
+
}
|
|
127
|
+
// 2. Publishes
|
|
128
|
+
{
|
|
129
|
+
const v = sectionStatus({ dataStart: facts.publishes?.dataStart ?? null, windowStart: ws });
|
|
130
|
+
const items = (facts.publishes?.items ?? []).filter((p) => withinWindow(facts.window, p.iso));
|
|
131
|
+
const pkgs = new Set(items.map((p) => p.pkg));
|
|
132
|
+
const lines = items.length === 0
|
|
133
|
+
? emptyOrUnavailable(v, 'no versions were accepted by the registry in this window')
|
|
134
|
+
: [
|
|
135
|
+
`${items.length} version(s) accepted by the registry across ${pkgs.size} package(s)`,
|
|
136
|
+
'timestamps are the registry’s own — this is the one record here nobody local can backdate',
|
|
137
|
+
];
|
|
138
|
+
sections.push({ id: 'publishes', title: 'Publishes', verdict: v, lines });
|
|
139
|
+
}
|
|
140
|
+
// 3. Discipline — DESCRIBES, never compares (ADR-004)
|
|
141
|
+
{
|
|
142
|
+
const v = sectionStatus({ dataStart: facts.guard?.dataStart ?? null, windowStart: ws });
|
|
143
|
+
const runs = (facts.guard?.items ?? []).filter((g) => withinWindow(facts.window, g.iso));
|
|
144
|
+
const byVerdict = new Map();
|
|
145
|
+
const byRule = new Map();
|
|
146
|
+
for (const r of runs) {
|
|
147
|
+
byVerdict.set(r.verdict, (byVerdict.get(r.verdict) ?? 0) + 1);
|
|
148
|
+
for (const rule of r.rules)
|
|
149
|
+
byRule.set(rule, (byRule.get(rule) ?? 0) + 1);
|
|
150
|
+
}
|
|
151
|
+
const lines = runs.length === 0
|
|
152
|
+
? emptyOrUnavailable(v, 'no gate runs were recorded in this window')
|
|
153
|
+
: [
|
|
154
|
+
`${runs.length} gate run(s): ${[...byVerdict.entries()].map(([k, n]) => `${k} ${n}`).join(', ')}`,
|
|
155
|
+
byRule.size === 0
|
|
156
|
+
? 'no rule was violated in this window'
|
|
157
|
+
: `violations by rule: ${[...byRule.entries()].sort((a, b) => b[1] - a[1]).map(([k, n]) => `${k} ${n}`).join(', ')}`,
|
|
158
|
+
];
|
|
159
|
+
// The caveat is NOT optional and NOT conditional: it is the whole honesty of the section.
|
|
160
|
+
lines.push('a rule missing from this list was either never violated or did not yet exist — the log records a rule only when it fires, so it cannot tell those apart');
|
|
161
|
+
lines.push('this section describes the window; it deliberately computes no comparison between periods');
|
|
162
|
+
sections.push({ id: 'discipline', title: 'Discipline', verdict: v, lines });
|
|
163
|
+
}
|
|
164
|
+
// 4. Knowledge reuse
|
|
165
|
+
{
|
|
166
|
+
const v = sectionStatus({ dataStart: facts.reuse?.dataStart ?? null, windowStart: ws });
|
|
167
|
+
const r = facts.reuse;
|
|
168
|
+
const lines = r === null || r.lessonsTotal === 0
|
|
169
|
+
? emptyOrUnavailable(v, 'no lessons are stored, so there is nothing to reuse')
|
|
170
|
+
: [
|
|
171
|
+
`${r.eventsInWindow} recall event(s) in this window`,
|
|
172
|
+
`${r.lessonsEverRecalled} of ${r.lessonsTotal} stored lessons have ever been read (${Math.round((r.lessonsEverRecalled / r.lessonsTotal) * 100)}%)`,
|
|
173
|
+
'this is a ratio with a hostile denominator: storing more unread lessons makes it worse, not better',
|
|
174
|
+
];
|
|
175
|
+
sections.push({ id: 'reuse', title: 'Knowledge reuse', verdict: v, lines });
|
|
176
|
+
}
|
|
177
|
+
const caveats = [];
|
|
178
|
+
if (facts.uncommittedSlugs.length > 0) {
|
|
179
|
+
caveats.push(`${facts.uncommittedSlugs.length} feature director${facts.uncommittedSlugs.length === 1 ? 'y is' : 'ies are'} not committed yet and therefore invisible to this report: ${facts.uncommittedSlugs.join(', ')}`);
|
|
180
|
+
}
|
|
181
|
+
caveats.push('none of the following is computed here, and each carries the measurement that disqualifies it: ' + FORBIDDEN_METRICS.map((m) => m.name).join(', '));
|
|
182
|
+
return { window: facts.window, spanDays: facts.spanDays, sections, caveats };
|
|
183
|
+
}
|
|
184
|
+
function tally(values) {
|
|
185
|
+
const m = new Map();
|
|
186
|
+
for (const v of values)
|
|
187
|
+
m.set(v, (m.get(v) ?? 0) + 1);
|
|
188
|
+
return [...m.entries()].sort((a, b) => (a[0] < b[0] ? -1 : 1)).map(([k, n]) => `${k}×${n}`).join(' ');
|
|
189
|
+
}
|
|
190
|
+
/** The human rendering. `--json` prints the SAME `RetroReport` — one structure, two spellings (FR-6). */
|
|
191
|
+
export function renderRetro(report) {
|
|
192
|
+
const out = [];
|
|
193
|
+
out.push(`dz retro — ${report.window.horizon}: ${report.window.startIso} … ${report.window.endIso} (${report.window.days} day(s))`);
|
|
194
|
+
out.push(`records held: ${report.spanDays} day(s)`);
|
|
195
|
+
for (const s of report.sections) {
|
|
196
|
+
out.push('');
|
|
197
|
+
out.push(`${s.title} [${s.verdict.status}]${s.verdict.dataStart !== null ? ` · records from ${s.verdict.dataStart}` : ''}`);
|
|
198
|
+
out.push(` ${s.verdict.note}`);
|
|
199
|
+
for (const l of s.lines)
|
|
200
|
+
out.push(` · ${l}`);
|
|
201
|
+
}
|
|
202
|
+
out.push('');
|
|
203
|
+
for (const c of report.caveats)
|
|
204
|
+
out.push(`! ${c}`);
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=retro.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retro.js","sourceRoot":"","sources":["../src/retro.ts"],"names":[],"mappings":"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"}
|
package/dist/score.d.ts
CHANGED
|
@@ -38,6 +38,27 @@ export interface RunScorecard {
|
|
|
38
38
|
}
|
|
39
39
|
/** The artifact texts of one run, keyed by RELATIVE path under `features/<slug>/`. */
|
|
40
40
|
export type RunArtifacts = Readonly<Record<string, string>>;
|
|
41
|
+
export type GradeReadStatus = 'unique' | 'ambiguous' | 'none';
|
|
42
|
+
export interface GradeReading {
|
|
43
|
+
readonly status: GradeReadStatus;
|
|
44
|
+
/** The grade, ONLY when the report names one unambiguously. */
|
|
45
|
+
readonly grade: string | null;
|
|
46
|
+
/** Every distinct grade found, normalised — what makes an `ambiguous` verdict inspectable. */
|
|
47
|
+
readonly found: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Read the review grade a report states — and refuse to guess when it states more than one.
|
|
51
|
+
*
|
|
52
|
+
* The obvious rules are both WRONG, and both were measured before this was written (ADR-002):
|
|
53
|
+
* FIRST match returns the round-1 grade of a report that was later fixed; LAST match returns a
|
|
54
|
+
* section heading naming the pre-fix grade, or a sentence quoting a grade in prose. Across 154
|
|
55
|
+
* real reports the two disagree in 14 files, and in `crossrt-2-codex-hooks` NEITHER is right —
|
|
56
|
+
* its true verdict is an all-caps `GRADE A` the old regex could not see at all.
|
|
57
|
+
*
|
|
58
|
+
* So: a grade is reported only when every occurrence agrees. Otherwise the caller is told the
|
|
59
|
+
* report is ambiguous, which is a fact about the report, not a missing number.
|
|
60
|
+
*/
|
|
61
|
+
export declare function readQeGrade(qeText: string): GradeReading;
|
|
41
62
|
export declare function extractQeGrade(qeText: string): string | null;
|
|
42
63
|
export declare function scoreRun(slug: string, artifacts: RunArtifacts): RunScorecard;
|
|
43
64
|
export declare function renderScorecard(card: RunScorecard): string;
|
package/dist/score.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../src/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;IACjD,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,sFAAsF;AACtF,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../src/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,SAAS,eAAe,EAAE,CAAC;IACjD,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,sFAAsF;AACtF,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAwE5D,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8FAA8F;IAC9F,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CASxD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE5D;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,GAAG,YAAY,CA+I5E;AAID,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAW1D"}
|
package/dist/score.js
CHANGED
|
@@ -67,10 +67,51 @@ function evidenceLinePositive(text, re, negationRe = NEGATION_RE) {
|
|
|
67
67
|
}
|
|
68
68
|
// Word-bounded on BOTH sides: "upgrade B-tree" fabricated a B- (Codex QE #1). The lookahead also
|
|
69
69
|
// rejects "Grade B-tree" (letter after the dash) while keeping the real "Grade: A−" formats.
|
|
70
|
-
|
|
70
|
+
//
|
|
71
|
+
// CASE: the whole word is case-insensitive, not just its first letter. The previous `[Gg]rade`
|
|
72
|
+
// could never match an all-caps `GRADE A` — MEASURED 2026-08-22: 15 reports spell it that way, and
|
|
73
|
+
// for several of them it is the ONLY grade in the file, so the parser returned `null` about a
|
|
74
|
+
// report that plainly states its verdict (ADR-002, features/dz-recap).
|
|
75
|
+
// The trailing `(?![A-Za-z])` is NOT decoration. Making the word case-insensitive let `GRADED by
|
|
76
|
+
// an independent reviewer` match: the engine took `GRADE`, skipped the optional `d`, and read the
|
|
77
|
+
// word's own final `D` as the grade. The old lowercase-only pattern could never reach that state,
|
|
78
|
+
// so widening the alphabet shifted the threshold — caught by the regression half of the test,
|
|
79
|
+
// which is exactly why that half is mandatory (recalled lesson, Step 0).
|
|
80
|
+
// NOT global. `evidenceLine` calls `re.test(line)` in a loop, and a /g regex carries `lastIndex`
|
|
81
|
+
// between calls — it would skip matches on every other line. `readQeGrade` makes its own global
|
|
82
|
+
// copy instead. (Caught by the existing evidence-locator test when /g was added here.)
|
|
83
|
+
const GRADE_RE = /(?<![A-Za-z])[Gg][Rr][Aa][Dd][Ee][Dd]?(?![A-Za-z]):?\s*\*{0,2}\s*([A-F][+\u2212-]?)(?![A-Za-z-])/;
|
|
84
|
+
/** U+2212 and the ASCII hyphen spell the same grade; a tally must not count them twice. */
|
|
85
|
+
function normaliseGradeSign(grade) {
|
|
86
|
+
return grade.replace('\u2212', '-');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Read the review grade a report states — and refuse to guess when it states more than one.
|
|
90
|
+
*
|
|
91
|
+
* The obvious rules are both WRONG, and both were measured before this was written (ADR-002):
|
|
92
|
+
* FIRST match returns the round-1 grade of a report that was later fixed; LAST match returns a
|
|
93
|
+
* section heading naming the pre-fix grade, or a sentence quoting a grade in prose. Across 154
|
|
94
|
+
* real reports the two disagree in 14 files, and in `crossrt-2-codex-hooks` NEITHER is right —
|
|
95
|
+
* its true verdict is an all-caps `GRADE A` the old regex could not see at all.
|
|
96
|
+
*
|
|
97
|
+
* So: a grade is reported only when every occurrence agrees. Otherwise the caller is told the
|
|
98
|
+
* report is ambiguous, which is a fact about the report, not a missing number.
|
|
99
|
+
*/
|
|
100
|
+
export function readQeGrade(qeText) {
|
|
101
|
+
const found = [];
|
|
102
|
+
for (const m of qeText.matchAll(new RegExp(GRADE_RE.source, 'g'))) {
|
|
103
|
+
const g = normaliseGradeSign(m[1]);
|
|
104
|
+
if (!found.includes(g))
|
|
105
|
+
found.push(g);
|
|
106
|
+
}
|
|
107
|
+
if (found.length === 0)
|
|
108
|
+
return { status: 'none', grade: null, found: [] };
|
|
109
|
+
if (found.length === 1)
|
|
110
|
+
return { status: 'unique', grade: found[0], found };
|
|
111
|
+
return { status: 'ambiguous', grade: null, found };
|
|
112
|
+
}
|
|
71
113
|
export function extractQeGrade(qeText) {
|
|
72
|
-
|
|
73
|
-
return m?.[1] ?? null;
|
|
114
|
+
return readQeGrade(qeText).grade;
|
|
74
115
|
}
|
|
75
116
|
export function scoreRun(slug, artifacts) {
|
|
76
117
|
const adrText = collect(artifacts, (p) => p.startsWith('03_adr/'));
|
package/dist/score.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"score.js","sourceRoot":"","sources":["../src/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAyBH,SAAS,OAAO,CAAC,SAAuB,EAAE,SAAoC;IAC5E,OAAO,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;SAC7B,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;SAC7B,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;SACvB,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,4EAA4E;AAC5E,SAAS,YAAY,CAAC,IAAY,EAAE,EAAU;IAC5C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,qFAAqF;AACrF,MAAM,WAAW,GAAG,4CAA4C,CAAC;AAEjE;;;;;;;;GAQG;AACH,MAAM,sBAAsB,GAAG,4EAA4E,CAAC;AAE5G,SAAS,oBAAoB,CAAC,IAAY,EAAE,EAAU,EAAE,aAAqB,WAAW;IACtF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QAC7B,uFAAuF;QACvF,4FAA4F;QAC5F,4FAA4F;QAC5F,6CAA6C;QAC7C,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACpC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iGAAiG;AACjG,6FAA6F;AAC7F,MAAM,QAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"score.js","sourceRoot":"","sources":["../src/score.ts"],"names":[],"mappings":"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"}
|
package/dist/vector-tier.d.ts
CHANGED
|
@@ -80,8 +80,20 @@ export interface ImportVectorRow {
|
|
|
80
80
|
readonly metadata?: Record<string, unknown> | undefined;
|
|
81
81
|
}
|
|
82
82
|
/** The engine PORT — both adapters implement exactly this surface (04 §4.1). */
|
|
83
|
+
/**
|
|
84
|
+
* Is this engine's `similarity` a real cosine, or only good enough to RANK by?
|
|
85
|
+
*
|
|
86
|
+
* `agentdb` computes a magnitude-normalised cosine over the stored vectors, so its number is
|
|
87
|
+
* comparable and lives in the space the recall floors were calibrated in. The `rvf` adapter returns
|
|
88
|
+
* `-distance` — unbounded, and the metric is not established — so its number may only order rows.
|
|
89
|
+
* Printing it beside a 0.38 cosine floor would hand the reader a figure that looks calibrated and is
|
|
90
|
+
* not; that is the one lie this feature must not tell (ADR, features/recall-true-closeness).
|
|
91
|
+
*/
|
|
92
|
+
export type SimilarityKind = 'cosine' | 'rank-only';
|
|
83
93
|
export interface VectorEngine {
|
|
84
94
|
readonly kind: VectorEngineKind;
|
|
95
|
+
/** Absent means `rank-only`: an engine must SAY its number is a cosine to have it shown as one. */
|
|
96
|
+
readonly similarityKind?: SimilarityKind;
|
|
85
97
|
upsert(entries: readonly VectorEntry[]): Promise<{
|
|
86
98
|
indexed: number;
|
|
87
99
|
error?: string | undefined;
|
|
@@ -134,6 +146,14 @@ export interface HybridHit {
|
|
|
134
146
|
readonly score: number;
|
|
135
147
|
/** lesson-quarantine: set only for a quarantined hit — display marks ⚠q, ranking was damped. */
|
|
136
148
|
readonly quarantined?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Raw closeness from the semantic leg, when the engine reports a genuine cosine. ABSENT for a
|
|
151
|
+
* lexical-only hit and for an engine whose score is not a cosine — the honest display there is a
|
|
152
|
+
* dash, never a substitute number. On a `both` hit this is the SEMANTIC leg's cosine, which
|
|
153
|
+
* explains less of the ordering than it may appear to: the list is ranked by RRF plus learning
|
|
154
|
+
* signals, not by this.
|
|
155
|
+
*/
|
|
156
|
+
readonly similarity?: number;
|
|
137
157
|
}
|
|
138
158
|
/** Outcome of {@link recallHybrid}. With no engine this is content-identical to `recallPatterns`. */
|
|
139
159
|
export interface HybridRecall {
|
|
@@ -198,6 +218,8 @@ export interface VectorTierStatus {
|
|
|
198
218
|
* project print a fully-healthy status line over a dead writer (ADR-001).
|
|
199
219
|
*/
|
|
200
220
|
readonly mirrorWriterEnabled: boolean;
|
|
221
|
+
/** WHY it is on or off — so the surface printing it cannot invent a cause (see mirrorWriterReason). */
|
|
222
|
+
readonly mirrorWriterState: MirrorWriterState;
|
|
201
223
|
/**
|
|
202
224
|
* Vectors of OTHER dz-owned task types (today: `dz-backlog`). Reported separately so a store of N
|
|
203
225
|
* vectors can be fully accounted for, and never folded into `mirrored`, which must stay comparable
|
|
@@ -374,6 +396,31 @@ export declare function readHarmonizeThreshold(projectRoot: string): number;
|
|
|
374
396
|
* `false`, so its `dz teach` output stays byte-identical to the pre-feature baseline (AC-1).
|
|
375
397
|
*/
|
|
376
398
|
export declare function vectorMirrorEnabled(projectRoot: string): boolean;
|
|
399
|
+
/** Why the mirror writer is on or off — a CLOSED set, so a caller cannot invent a cause. */
|
|
400
|
+
export type MirrorWriterState = 'on'
|
|
401
|
+
/** No `.dz/config.json` at all — an unconfigured project, which is the normal quiet case. */
|
|
402
|
+
| 'no-config'
|
|
403
|
+
/** The config exists but could not be read or parsed. */
|
|
404
|
+
| 'config-unreadable'
|
|
405
|
+
/** The config is readable and simply does not enable a mirror. */
|
|
406
|
+
| 'not-enabled'
|
|
407
|
+
/** The config explicitly turns the vector tier off. */
|
|
408
|
+
| 'engine-off';
|
|
409
|
+
/**
|
|
410
|
+
* The mirror writer's state AND its real cause.
|
|
411
|
+
*
|
|
412
|
+
* Every failure used to collapse into `false`, and the one message printed above it named ONE
|
|
413
|
+
* specific cause: "no memory.backend=agentdb". MEASURED 2026-08-24 with a config that sets
|
|
414
|
+
* `memory.vector.engine: "off"` — the status line correctly said OFF and then blamed a setting the
|
|
415
|
+
* config did not mention. A diagnosis that names the wrong cause sends the reader to fix something
|
|
416
|
+
* that is not broken, which is worse than saying nothing.
|
|
417
|
+
*/
|
|
418
|
+
export declare function mirrorWriterReason(projectRoot: string): {
|
|
419
|
+
enabled: boolean;
|
|
420
|
+
state: MirrorWriterState;
|
|
421
|
+
};
|
|
422
|
+
/** The sentence a reader can act on, for each state. */
|
|
423
|
+
export declare function mirrorWriterExplanation(state: MirrorWriterState): string;
|
|
377
424
|
export declare function resolveVectorEngine(projectRoot: string): ResolvedVectorEngine;
|
|
378
425
|
/** Options shared by the mirror/recall services. `engine: null` force-disables (tests). */
|
|
379
426
|
export interface VectorServiceOptions {
|
|
@@ -410,6 +457,13 @@ export interface RankedPattern {
|
|
|
410
457
|
readonly id: string;
|
|
411
458
|
readonly pattern: PatternRecord;
|
|
412
459
|
readonly backend: RecallHit['backend'];
|
|
460
|
+
/**
|
|
461
|
+
* The semantic leg's raw closeness, when the engine reports a real cosine. Rides ALONGSIDE the RRF
|
|
462
|
+
* score and never enters the ranking maths — four things depend on RRF magnitude (the reinforce
|
|
463
|
+
* cap, quarantine damping, the learning uplift, and an ADR-level note in backlog.ts), so this is a
|
|
464
|
+
* sibling field, never a repurposing.
|
|
465
|
+
*/
|
|
466
|
+
readonly similarity?: number;
|
|
413
467
|
}
|
|
414
468
|
/**
|
|
415
469
|
* Reciprocal Rank Fusion merge: `score(p) = Σ 1/(60 + rank)` over the lists containing `p`
|