@sentropic/track 0.10.11 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +103 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/events/types.d.ts +2 -2
- package/dist/events/types.d.ts.map +1 -1
- package/dist/events/types.js +15 -1
- package/dist/events/types.js.map +1 -1
- package/dist/ingest/contract.d.ts +3 -2
- package/dist/ingest/contract.d.ts.map +1 -1
- package/dist/ingest/contract.js +32 -2
- package/dist/ingest/contract.js.map +1 -1
- package/dist/ingest/ingest.d.ts.map +1 -1
- package/dist/ingest/ingest.js +26 -0
- package/dist/ingest/ingest.js.map +1 -1
- package/dist/ingest/map.d.ts.map +1 -1
- package/dist/ingest/map.js +12 -0
- package/dist/ingest/map.js.map +1 -1
- package/dist/mcp/server.d.ts +68 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +64 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/index.d.ts +2 -1
- package/dist/model/index.d.ts.map +1 -1
- package/dist/model/index.js +3 -1
- package/dist/model/index.js.map +1 -1
- package/dist/model/item.d.ts +43 -5
- package/dist/model/item.d.ts.map +1 -1
- package/dist/model/item.js +53 -0
- package/dist/model/item.js.map +1 -1
- package/dist/model/verification.d.ts +38 -0
- package/dist/model/verification.d.ts.map +1 -0
- package/dist/model/verification.js +52 -0
- package/dist/model/verification.js.map +1 -0
- package/dist/read/commands.d.ts +7 -0
- package/dist/read/commands.d.ts.map +1 -1
- package/dist/read/commands.js +18 -0
- package/dist/read/commands.js.map +1 -1
- package/dist/read/contract.d.ts +38 -3
- package/dist/read/contract.d.ts.map +1 -1
- package/dist/read/contract.js +64 -3
- package/dist/read/contract.js.map +1 -1
- package/dist/read/index.d.ts +3 -0
- package/dist/read/index.d.ts.map +1 -1
- package/dist/read/index.js +5 -0
- package/dist/read/index.js.map +1 -1
- package/dist/read/scope-validate.d.ts +44 -0
- package/dist/read/scope-validate.d.ts.map +1 -0
- package/dist/read/scope-validate.js +204 -0
- package/dist/read/scope-validate.js.map +1 -0
- package/dist/report/build.d.ts +1 -1
- package/dist/report/build.d.ts.map +1 -1
- package/dist/report/build.js +5 -4
- package/dist/report/build.js.map +1 -1
- package/dist/report/index.d.ts +2 -1
- package/dist/report/index.d.ts.map +1 -1
- package/dist/report/index.js +3 -1
- package/dist/report/index.js.map +1 -1
- package/dist/report/rollup.d.ts +11 -1
- package/dist/report/rollup.d.ts.map +1 -1
- package/dist/report/rollup.js +26 -20
- package/dist/report/rollup.js.map +1 -1
- package/dist/report/status-by-level.d.ts +27 -0
- package/dist/report/status-by-level.d.ts.map +1 -0
- package/dist/report/status-by-level.js +151 -0
- package/dist/report/status-by-level.js.map +1 -0
- package/dist/state/fold.d.ts +7 -0
- package/dist/state/fold.d.ts.map +1 -1
- package/dist/state/fold.js +28 -0
- package/dist/state/fold.js.map +1 -1
- package/dist/state/snapshot.d.ts +2 -0
- package/dist/state/snapshot.d.ts.map +1 -1
- package/dist/state/snapshot.js +2 -0
- package/dist/state/snapshot.js.map +1 -1
- package/dist/track.d.ts +25 -1
- package/dist/track.d.ts.map +1 -1
- package/dist/track.js +61 -17
- package/dist/track.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// Scope §B(b) — `track scope validate`: a PURE, read-only, fail-closed, ADVISORY validation over the
|
|
2
|
+
// folded track state. It NEVER glob-matches (string-level set logic only), NEVER ingests, NEVER appends,
|
|
3
|
+
// and is NEVER a commit gate — it RENDERS a verdict the harness owns the path side of. The fail-closed
|
|
4
|
+
// staleness gate (requireFresh/StaleSidecarError) is handled by the caller (TrackReader.scopeValidate),
|
|
5
|
+
// which runs it FIRST; this module is reached only on a fresh (or no-sidecar) read.
|
|
6
|
+
import { computeHash } from '../events/canonical.js';
|
|
7
|
+
import { isRoleContainer } from '../model/item.js';
|
|
8
|
+
import { bucketOf } from '../report/buckets.js';
|
|
9
|
+
/**
|
|
10
|
+
* Is a container (WP/spec-phase) "realization-active" — does it have at least one ACTIVE (non-dropped,
|
|
11
|
+
* non-`done`) descendant leaf? An undeclared scope is only flagged for an active container (a finished
|
|
12
|
+
* or empty one has no work the harness would verify). Reuses `bucketOf` (no new bucket logic).
|
|
13
|
+
*/
|
|
14
|
+
function isRealizationActive(state, containerId, childrenOf, config) {
|
|
15
|
+
let found = false;
|
|
16
|
+
const walk = (parentId) => {
|
|
17
|
+
if (found)
|
|
18
|
+
return;
|
|
19
|
+
for (const child of childrenOf.get(parentId) ?? []) {
|
|
20
|
+
if (found)
|
|
21
|
+
return;
|
|
22
|
+
if (isRoleContainer(child)) {
|
|
23
|
+
walk(child.id); // descend through a nested container
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const grandkids = childrenOf.get(child.id) ?? [];
|
|
27
|
+
if (grandkids.length === 0) {
|
|
28
|
+
const bucket = bucketOf(state, child, config);
|
|
29
|
+
if (bucket === 'TO-DO' || bucket === 'AWAITED')
|
|
30
|
+
found = true;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
walk(child.id); // non-container container — descend
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
walk(containerId);
|
|
38
|
+
return found;
|
|
39
|
+
}
|
|
40
|
+
/** True iff the container's latest run (or all leaves) is `done` and none active — for the opt-in inference. */
|
|
41
|
+
function allLeavesDone(state, containerId, childrenOf, config) {
|
|
42
|
+
let any = false;
|
|
43
|
+
let allDone = true;
|
|
44
|
+
const walk = (parentId) => {
|
|
45
|
+
for (const child of childrenOf.get(parentId) ?? []) {
|
|
46
|
+
if (isRoleContainer(child)) {
|
|
47
|
+
walk(child.id);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const grandkids = childrenOf.get(child.id) ?? [];
|
|
51
|
+
if (grandkids.length === 0) {
|
|
52
|
+
any = true;
|
|
53
|
+
if (bucketOf(state, child, config) !== 'DONE')
|
|
54
|
+
allDone = false;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
walk(child.id);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
walk(containerId);
|
|
62
|
+
return any && allDone;
|
|
63
|
+
}
|
|
64
|
+
/** Is `itemId` a (transitive) descendant of `ancestorId`? */
|
|
65
|
+
function isDescendant(state, itemId, ancestorId) {
|
|
66
|
+
for (let cursor = state.items.get(itemId)?.parentId; cursor !== undefined;) {
|
|
67
|
+
if (cursor === ancestorId)
|
|
68
|
+
return true;
|
|
69
|
+
cursor = state.items.get(cursor)?.parentId;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validate scope declarations over the folded `state`, scoped to `workspace`. PURE: no glob-matching
|
|
75
|
+
* (allowed∩forbidden is a string-level set overlap), no ingest, no append. The caller guarantees freshness.
|
|
76
|
+
*/
|
|
77
|
+
export function scopeValidate(state, input) {
|
|
78
|
+
const config = { baselineCommit: input.baselineCommit, requireAccepted: false };
|
|
79
|
+
const items = [...state.items.values()];
|
|
80
|
+
// children index: parentId → direct children (id-sorted for deterministic labels — same as the rollup).
|
|
81
|
+
const childrenOf = new Map();
|
|
82
|
+
for (const item of items) {
|
|
83
|
+
const list = childrenOf.get(item.parentId) ?? [];
|
|
84
|
+
list.push(item);
|
|
85
|
+
childrenOf.set(item.parentId, list);
|
|
86
|
+
}
|
|
87
|
+
for (const list of childrenOf.values())
|
|
88
|
+
list.sort((a, b) => a.id.localeCompare(b.id));
|
|
89
|
+
// Derive the dotted WP-forest label per container (same walk as status-by-level). Roots = containers
|
|
90
|
+
// whose parent is not itself a container.
|
|
91
|
+
const isContainerById = new Map(items.map((i) => [i.id, isRoleContainer(i)]));
|
|
92
|
+
const roots = items.filter((i) => isRoleContainer(i) && !(i.parentId !== undefined && isContainerById.get(i.parentId)));
|
|
93
|
+
roots.sort((a, b) => a.id.localeCompare(b.id));
|
|
94
|
+
const labelOf = new Map();
|
|
95
|
+
const visit = (c, label) => {
|
|
96
|
+
labelOf.set(c.id, label);
|
|
97
|
+
let ordinal = 0;
|
|
98
|
+
const collect = (parentId) => {
|
|
99
|
+
for (const child of childrenOf.get(parentId) ?? []) {
|
|
100
|
+
if (isRoleContainer(child)) {
|
|
101
|
+
ordinal++;
|
|
102
|
+
visit(child, `${label}.${ordinal}`);
|
|
103
|
+
}
|
|
104
|
+
else
|
|
105
|
+
collect(child.id);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
collect(c.id);
|
|
109
|
+
};
|
|
110
|
+
roots.forEach((c, idx) => visit(c, `WP${idx + 1}`));
|
|
111
|
+
// Latest VerificationRun per wpRef (read, never recomputed): latest by `at` then `runId`.
|
|
112
|
+
const latestRunByWp = new Map();
|
|
113
|
+
for (const run of state.verificationRuns.values()) {
|
|
114
|
+
if (run.wpRef === undefined)
|
|
115
|
+
continue;
|
|
116
|
+
const prev = latestRunByWp.get(run.wpRef);
|
|
117
|
+
if (prev === undefined || run.at > prev.at || (run.at === prev.at && run.runId > prev.runId)) {
|
|
118
|
+
latestRunByWp.set(run.wpRef, run);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const containers = items
|
|
122
|
+
.filter((i) => isRoleContainer(i) && i.workspace === input.workspace)
|
|
123
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
124
|
+
const findings = [];
|
|
125
|
+
const perWp = [];
|
|
126
|
+
const declaredScopes = [];
|
|
127
|
+
for (const c of containers) {
|
|
128
|
+
const declared = c.scope !== undefined;
|
|
129
|
+
let semanticStatus = 'ok';
|
|
130
|
+
// illegal-nesting: a spec-phase whose parent is neither a WP nor a spec-phase (a folded-state anomaly;
|
|
131
|
+
// the write path forbids this, so it only fires on a hand-edited/foreign log — fail-closed surfacing).
|
|
132
|
+
if (c.role === 'spec-phase' && c.parentId !== undefined) {
|
|
133
|
+
const parent = state.items.get(c.parentId);
|
|
134
|
+
if (parent === undefined || !isRoleContainer(parent)) {
|
|
135
|
+
semanticStatus = 'illegal-nesting';
|
|
136
|
+
findings.push({ code: 'illegal-nesting', wpId: c.id, message: `spec-phase ${c.id} is not nested under a workpackage or spec-phase` });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (declared) {
|
|
140
|
+
declaredScopes.push({ wpId: c.id, scope: c.scope });
|
|
141
|
+
// incoherent: a glob present in BOTH allowed and forbidden (string-level set overlap, NOT a path match).
|
|
142
|
+
const allowed = new Set(c.scope.allowed ?? []);
|
|
143
|
+
const overlap = (c.scope.forbidden ?? []).filter((g) => allowed.has(g));
|
|
144
|
+
if (overlap.length > 0 && semanticStatus === 'ok') {
|
|
145
|
+
semanticStatus = 'incoherent';
|
|
146
|
+
findings.push({
|
|
147
|
+
code: 'incoherent',
|
|
148
|
+
wpId: c.id,
|
|
149
|
+
message: `scope on ${c.id} lists ${overlap.length} glob(s) as both allowed and forbidden: ${overlap.join(', ')}`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (isRealizationActive(state, c.id, childrenOf, config) && semanticStatus === 'ok') {
|
|
154
|
+
// scope-undeclared: a realization-active container with no scope declaration.
|
|
155
|
+
semanticStatus = 'scope-undeclared';
|
|
156
|
+
findings.push({ code: 'scope-undeclared', wpId: c.id, message: `${c.role} ${c.id} is realization-active but has no scope declaration` });
|
|
157
|
+
}
|
|
158
|
+
const latest = latestRunByWp.get(c.id);
|
|
159
|
+
perWp.push({
|
|
160
|
+
wpId: c.id,
|
|
161
|
+
label: labelOf.get(c.id) ?? c.id,
|
|
162
|
+
declared,
|
|
163
|
+
semanticStatus,
|
|
164
|
+
...(latest !== undefined ? { latestVerification: latest, evidenceStatus: latest.verdict } : {}),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// claim-out-of-phase: an explicit claimed item must be a descendant of a DECLARED phase/WP it belongs to.
|
|
168
|
+
if (input.claimedItemId !== undefined) {
|
|
169
|
+
const claimed = state.items.get(input.claimedItemId);
|
|
170
|
+
if (claimed !== undefined && claimed.workspace === input.workspace) {
|
|
171
|
+
const ownerDeclared = containers.some((c) => c.scope !== undefined && (c.id === claimed.parentId || isDescendant(state, claimed.id, c.id)));
|
|
172
|
+
if (!ownerDeclared) {
|
|
173
|
+
findings.push({
|
|
174
|
+
code: 'claim-out-of-phase',
|
|
175
|
+
message: `claimed item ${claimed.id} is not a descendant of any declared scope phase`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Opt-in delivered-out-of-scope inference: a container whose leaves are all done but whose latest
|
|
181
|
+
// VerificationRun is a violation. A READ flag — never a write, OFF by default.
|
|
182
|
+
if (input.inferDeliveredOutOfScope === true) {
|
|
183
|
+
for (const c of containers) {
|
|
184
|
+
const latest = latestRunByWp.get(c.id);
|
|
185
|
+
if (latest?.verdict === 'violation' && allLeavesDone(state, c.id, childrenOf, config)) {
|
|
186
|
+
findings.push({
|
|
187
|
+
code: 'delivered-out-of-scope',
|
|
188
|
+
wpId: c.id,
|
|
189
|
+
message: `${c.role} ${c.id} is delivered (all leaves done) but its latest verification is a violation`,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const status = containers.length === 0 ? 'missing' : findings.length > 0 ? 'fail' : 'pass';
|
|
195
|
+
return {
|
|
196
|
+
status,
|
|
197
|
+
findings,
|
|
198
|
+
perWp,
|
|
199
|
+
...(declaredScopes.length > 0
|
|
200
|
+
? { scopeRevisionHash: computeHash(declaredScopes.sort((a, b) => a.wpId.localeCompare(b.wpId))) }
|
|
201
|
+
: {}),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=scope-validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-validate.js","sourceRoot":"","sources":["../../src/read/scope-validate.ts"],"names":[],"mappings":"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"}
|
package/dist/report/build.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ActorId } from '../events/types.js';
|
|
2
2
|
import type { AcceptanceStatus } from '../model/acceptance.js';
|
|
3
3
|
import type { DecisionKind, DossierArtifact, Outcome } from '../model/decision.js';
|
|
4
|
-
import type
|
|
4
|
+
import { type ItemId, type ItemKind, type ItemRole, type Realization } from '../model/item.js';
|
|
5
5
|
import type { State } from '../state/fold.js';
|
|
6
6
|
import { type Bucket } from './buckets.js';
|
|
7
7
|
import { type WpNode } from './rollup.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/report/build.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAClF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/report/build.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAClF,OAAO,EAAmB,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAE,KAAK,QAAQ,EAAkB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC/H,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAqB,KAAK,MAAM,EAAqB,MAAM,cAAc,CAAA;AAChF,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAExD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,QAAQ,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,WAAW,CAAA;IACxB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,IAAI,CAAC,EAAE,QAAQ,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,YAAY,CAAA;IAC1B,WAAW,EAAE,WAAW,CAAA;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IAGrB,SAAS,CAAC,EAAE,eAAe,EAAE,CAAA;CAC9B;AAED,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAA;IACpC,SAAS,CAAC,EAAE,WAAW,EAAE,CAAA;IACzB,0GAA0G;IAC1G,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sGAAsG;IACtG,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AA4BD,4GAA4G;AAC5G,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CA+BxE;AAED,MAAM,WAAW,WAAW;IAG1B,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IACpC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,UAAU,CAAC,EAAE,gBAAgB,CAAA;IAC7B,yGAAyG;IACzG,IAAI,CAAC,EAAE,QAAQ,CAAA;CAChB;AAED,kEAAkE;AAClE,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,SAAS,EAAE,CA0B5F"}
|
package/dist/report/build.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { acceptanceStatus } from '../accept/status.js';
|
|
2
|
+
import { isRoleContainer } from '../model/item.js';
|
|
2
3
|
import { BUCKETS, bucketOf } from './buckets.js';
|
|
3
4
|
import { computeWpTree } from './rollup.js';
|
|
4
5
|
function toRow(state, item, config) {
|
|
@@ -35,10 +36,10 @@ export function buildReport(state, options) {
|
|
|
35
36
|
};
|
|
36
37
|
const buckets = { AWAITED: [], DROPPED: [], DONE: [], 'TO-DO': [] };
|
|
37
38
|
for (const item of state.items.values()) {
|
|
38
|
-
// Workpackages §2 — a WP is a container, not a leaf: keep it out of the
|
|
39
|
-
// it can never be mis-counted as a TO-DO leaf (the false-% bug the design
|
|
40
|
-
// forest is surfaced separately on `report.wpTree`.
|
|
41
|
-
if (item
|
|
39
|
+
// Workpackages §2 / Scope §B(a) — a WP or spec-phase is a container, not a leaf: keep it out of the
|
|
40
|
+
// flat buckets entirely so it can never be mis-counted as a TO-DO leaf (the false-% bug the design
|
|
41
|
+
// warns about). The container forest is surfaced separately on `report.wpTree`.
|
|
42
|
+
if (isRoleContainer(item))
|
|
42
43
|
continue;
|
|
43
44
|
const row = toRow(state, item, config);
|
|
44
45
|
buckets[row.bucket].push(row);
|
package/dist/report/build.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/report/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/report/build.ts"],"names":[],"mappings":"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"}
|
package/dist/report/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { BUCKETS, bucketOf, type Bucket, type ReportConfig } from './buckets.js';
|
|
2
2
|
export { buildReport, query, type DecisionRow, type QueryFilter, type Report, type ReportOptions, type ReportRow, } from './build.js';
|
|
3
3
|
export { formatReport, formatRows, formatWpConductor, formatWpTree, wpTotals, type Format, type WpTotals, } from './format.js';
|
|
4
|
-
export { computeWpTree, type WpLeaf, type WpNode } from './rollup.js';
|
|
4
|
+
export { computeWpTree, tally, type WpLeaf, type WpNode } from './rollup.js';
|
|
5
|
+
export { statusByLevel, STATUS_LEVELS, type GroupStatus, type StatusGroup, type StatusLevel, } from './status-by-level.js';
|
|
5
6
|
export { effectiveBlockerOpen, effectiveOpenBlockersForItem } from './blocker-status.js';
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EACL,WAAW,EACX,KAAK,EACL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,QAAQ,EACR,KAAK,MAAM,EACX,KAAK,QAAQ,GACd,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,aAAa,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EACL,WAAW,EACX,KAAK,EACL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,SAAS,GACf,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,QAAQ,EACR,KAAK,MAAM,EACX,KAAK,QAAQ,GACd,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAE5E,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAA"}
|
package/dist/report/index.js
CHANGED
|
@@ -3,7 +3,9 @@ export { BUCKETS, bucketOf } from './buckets.js';
|
|
|
3
3
|
export { buildReport, query, } from './build.js';
|
|
4
4
|
export { formatReport, formatRows, formatWpConductor, formatWpTree, wpTotals, } from './format.js';
|
|
5
5
|
// Workpackages §2 — the %-by-WP rollup forest (pure).
|
|
6
|
-
export { computeWpTree } from './rollup.js';
|
|
6
|
+
export { computeWpTree, tally } from './rollup.js';
|
|
7
|
+
// Scope §A/§B — status(level) projection (spec|plan|wp|lot|task), additive read-only.
|
|
8
|
+
export { statusByLevel, STATUS_LEVELS, } from './status-by-level.js';
|
|
7
9
|
// Commit-relative blocker openness (v2.2a hybrid-A) — `linked-accepted` derived at projection time.
|
|
8
10
|
export { effectiveBlockerOpen, effectiveOpenBlockersForItem } from './blocker-status.js';
|
|
9
11
|
//# sourceMappingURL=index.js.map
|
package/dist/report/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAkC,MAAM,cAAc,CAAA;AAChF,OAAO,EACL,WAAW,EACX,KAAK,GAMN,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,QAAQ,GAGT,MAAM,aAAa,CAAA;AACpB,sDAAsD;AACtD,OAAO,EAAE,aAAa,EAA4B,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/report/index.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAkC,MAAM,cAAc,CAAA;AAChF,OAAO,EACL,WAAW,EACX,KAAK,GAMN,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,QAAQ,GAGT,MAAM,aAAa,CAAA;AACpB,sDAAsD;AACtD,OAAO,EAAE,aAAa,EAAE,KAAK,EAA4B,MAAM,aAAa,CAAA;AAC5E,sFAAsF;AACtF,OAAO,EACL,aAAa,EACb,aAAa,GAId,MAAM,sBAAsB,CAAA;AAC7B,oGAAoG;AACpG,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAA"}
|
package/dist/report/rollup.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ItemId, type ItemKind } from '../model/item.js';
|
|
2
2
|
import type { State } from '../state/fold.js';
|
|
3
3
|
import { type Bucket, type ReportConfig } from './buckets.js';
|
|
4
4
|
/** A rolled-up leaf under a WP — its bucket drives both the % counts and the `[x]/[ ]` checkbox. */
|
|
@@ -30,6 +30,16 @@ export interface WpNode {
|
|
|
30
30
|
leaves: WpLeaf[];
|
|
31
31
|
children: WpNode[];
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Tally leaf buckets into done/active/dropped counts (the % numerator/denominator). DONE counts in both
|
|
35
|
+
* done and active; TO-DO/AWAITED count active only; DROPPED is shown but EXCLUDED from the denominator.
|
|
36
|
+
* Exported so `statusByLevel` rolls up tiers with the SAME arithmetic (no Simpson mean-of-pcts trap).
|
|
37
|
+
*/
|
|
38
|
+
export declare function tally(leaves: readonly WpLeaf[]): {
|
|
39
|
+
done: number;
|
|
40
|
+
active: number;
|
|
41
|
+
dropped: number;
|
|
42
|
+
};
|
|
33
43
|
/**
|
|
34
44
|
* Build the WP forest and roll leaf buckets up. A WP's transitive NON-WP descendants are its leaves;
|
|
35
45
|
* a nested WP is a sub-node, not a leaf, so its leaves count once at every ancestor (SUM, not mean).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rollup.d.ts","sourceRoot":"","sources":["../../src/report/rollup.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"rollup.d.ts","sourceRoot":"","sources":["../../src/report/rollup.ts"],"names":[],"mappings":"AAUA,OAAO,EAAmB,KAAK,MAAM,EAAE,KAAK,QAAQ,EAAkB,MAAM,kBAAkB,CAAA;AAC9F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAY,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAGvE,oGAAoG;AACpG,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,QAAQ,CAAA;IACd,gGAAgG;IAChG,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mGAAmG;IACnG,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED,wGAAwG;AACxG,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAA;IACb,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;IACZ,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAA;IACd,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAA;IACf,mEAAmE;IACnE,GAAG,EAAE,MAAM,GAAG,KAAK,CAAA;IACnB,8GAA8G;IAC9G,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAOD;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAelG;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAsF1E"}
|
package/dist/report/rollup.js
CHANGED
|
@@ -7,11 +7,35 @@
|
|
|
7
7
|
// pct = round(done / active * 100), with 0/0 ⇒ 'n/a' (never 100%)
|
|
8
8
|
// Parent counts are the SUM of descendant leaves, NEVER the mean of child percentages (Simpson trap).
|
|
9
9
|
// Each node's dotted display label (`WP1`, `WP1.1`) is DERIVED from tree position, never stored.
|
|
10
|
+
import { isRoleContainer } from '../model/item.js';
|
|
10
11
|
import { bucketOf } from './buckets.js';
|
|
11
12
|
import { effectiveOpenBlockersForItem } from './blocker-status.js';
|
|
12
|
-
/** A
|
|
13
|
+
/** A CONTAINER node (workpackage OR spec-phase) — descended through, never a leaf (Scope §B(a)). */
|
|
13
14
|
function isWp(item) {
|
|
14
|
-
return item
|
|
15
|
+
return isRoleContainer(item);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Tally leaf buckets into done/active/dropped counts (the % numerator/denominator). DONE counts in both
|
|
19
|
+
* done and active; TO-DO/AWAITED count active only; DROPPED is shown but EXCLUDED from the denominator.
|
|
20
|
+
* Exported so `statusByLevel` rolls up tiers with the SAME arithmetic (no Simpson mean-of-pcts trap).
|
|
21
|
+
*/
|
|
22
|
+
export function tally(leaves) {
|
|
23
|
+
let done = 0;
|
|
24
|
+
let active = 0;
|
|
25
|
+
let dropped = 0;
|
|
26
|
+
for (const l of leaves) {
|
|
27
|
+
if (l.bucket === 'DONE') {
|
|
28
|
+
done++;
|
|
29
|
+
active++;
|
|
30
|
+
}
|
|
31
|
+
else if (l.bucket === 'TO-DO' || l.bucket === 'AWAITED') {
|
|
32
|
+
active++;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
dropped++; // DROPPED — shown, excluded from %
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return { done, active, dropped };
|
|
15
39
|
}
|
|
16
40
|
/**
|
|
17
41
|
* Build the WP forest and roll leaf buckets up. A WP's transitive NON-WP descendants are its leaves;
|
|
@@ -29,24 +53,6 @@ export function computeWpTree(state, config) {
|
|
|
29
53
|
}
|
|
30
54
|
for (const list of childrenOf.values())
|
|
31
55
|
list.sort((a, b) => a.id.localeCompare(b.id));
|
|
32
|
-
const tally = (leaves) => {
|
|
33
|
-
let done = 0;
|
|
34
|
-
let active = 0;
|
|
35
|
-
let dropped = 0;
|
|
36
|
-
for (const l of leaves) {
|
|
37
|
-
if (l.bucket === 'DONE') {
|
|
38
|
-
done++;
|
|
39
|
-
active++;
|
|
40
|
-
}
|
|
41
|
-
else if (l.bucket === 'TO-DO' || l.bucket === 'AWAITED') {
|
|
42
|
-
active++;
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
dropped++; // DROPPED — shown, excluded from %
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return { done, active, dropped };
|
|
49
|
-
};
|
|
50
56
|
// Collect every NON-WP leaf descendant of `node`, but STOP at a nested sub-WP boundary (those leaves
|
|
51
57
|
// belong to the sub-WP's own node). A non-WP container (e.g. a feature with chore children) is descended
|
|
52
58
|
// through — it is not itself a leaf. This is the set "directly attached" at `node`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rollup.js","sourceRoot":"","sources":["../../src/report/rollup.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,oGAAoG;AACpG,cAAc;AACd,0BAA0B;AAC1B,uEAAuE;AACvE,+EAA+E;AAC/E,wEAAwE;AACxE,sGAAsG;AACtG,iGAAiG;
|
|
1
|
+
{"version":3,"file":"rollup.js","sourceRoot":"","sources":["../../src/report/rollup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ItemId } from '../model/item.js';
|
|
2
|
+
import type { State } from '../state/fold.js';
|
|
3
|
+
import { type Bucket, type ReportConfig } from './buckets.js';
|
|
4
|
+
export type StatusLevel = 'spec' | 'plan' | 'wp' | 'lot' | 'task';
|
|
5
|
+
export declare const STATUS_LEVELS: readonly StatusLevel[];
|
|
6
|
+
/** The rolled-up status of a tier/leaf group — the group analogue of a leaf `Bucket`. */
|
|
7
|
+
export type GroupStatus = Bucket;
|
|
8
|
+
/** One status group at the requested level — a tier WP (or a single leaf for `task`). */
|
|
9
|
+
export interface StatusGroup {
|
|
10
|
+
id: ItemId;
|
|
11
|
+
title: string;
|
|
12
|
+
/** Derived dotted label from WP-forest position (e.g. "WP1", "WP1.2"); the leaf id for `task`. */
|
|
13
|
+
label: string;
|
|
14
|
+
/** The WP-nesting depth (root WP = 0); `task` groups carry the depth of their nearest WP ancestor + 1. */
|
|
15
|
+
depth: number;
|
|
16
|
+
status: GroupStatus;
|
|
17
|
+
done: number;
|
|
18
|
+
active: number;
|
|
19
|
+
dropped: number;
|
|
20
|
+
pct: number | 'n/a';
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Project the folded state into status groups at `level`. Pure; the same `config.baselineCommit` that
|
|
24
|
+
* drives `bucketOf`/AWAITED governs here (no new boundary).
|
|
25
|
+
*/
|
|
26
|
+
export declare function statusByLevel(state: State, level: StatusLevel, config: ReportConfig): StatusGroup[];
|
|
27
|
+
//# sourceMappingURL=status-by-level.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-by-level.d.ts","sourceRoot":"","sources":["../../src/report/status-by-level.ts"],"names":[],"mappings":"AAcA,OAAO,EAAmB,KAAK,MAAM,EAAkB,MAAM,kBAAkB,CAAA;AAC/E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAY,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAGvE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,KAAK,GAAG,MAAM,CAAA;AACjE,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAA0C,CAAA;AAE1F,yFAAyF;AACzF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAA;AAEhC,yFAAyF;AACzF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,kGAAkG;IAClG,KAAK,EAAE,MAAM,CAAA;IACb,0GAA0G;IAC1G,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,WAAW,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,GAAG,KAAK,CAAA;CACpB;AAcD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,WAAW,EAAE,CAuHnG"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Scope §A/§B — `status(level)` projection: a generalization of `computeWpTree`+`bucketOf` over the
|
|
2
|
+
// scope tiers {spec, plan, wp, lot, task}. ADDITIVE + READ-ONLY: it adds NO aggregate and NO stored
|
|
3
|
+
// status axis — it is a pure re-grouping of the SAME leaf buckets the report already computes.
|
|
4
|
+
//
|
|
5
|
+
// task = the leaf bucket (each non-WP leaf is its own group).
|
|
6
|
+
// wp = the existing role:'workpackage'+parentId rollup (≡ every computeWpTree node).
|
|
7
|
+
// lot|plan|spec = the SAME rollup over tiers derived from WP-NESTING DEPTH: a ROOT WP is the
|
|
8
|
+
// plan/spec tier; a nested sub-WP is the wp/lot tier.
|
|
9
|
+
//
|
|
10
|
+
// Group rollup (over a tier node's TRANSITIVE non-WP leaves): AWAITED if any ACTIVE descendant is
|
|
11
|
+
// awaited; else DONE if all active are done; else DROPPED if only dropped remain; else TO-DO. Counts
|
|
12
|
+
// done/active/dropped/pct via the shared `tally()` (SUM of leaves, never mean-of-pcts); dropped excluded
|
|
13
|
+
// from the denominator; 0/0 ⇒ 'n/a'. Reuses `bucketOf`/`tally`/the WP-forest shape verbatim.
|
|
14
|
+
import { isRoleContainer } from '../model/item.js';
|
|
15
|
+
import { bucketOf } from './buckets.js';
|
|
16
|
+
import { tally } from './rollup.js';
|
|
17
|
+
export const STATUS_LEVELS = ['spec', 'plan', 'wp', 'lot', 'task'];
|
|
18
|
+
// A CONTAINER node (workpackage OR spec-phase) — descended through, never a leaf (Scope §B(a)).
|
|
19
|
+
const isWp = (item) => isRoleContainer(item);
|
|
20
|
+
/** Roll a set of leaf buckets up to a group status (first match wins, mirroring `bucketOf` precedence). */
|
|
21
|
+
function rollupStatus(leaves) {
|
|
22
|
+
if (leaves.some((l) => l.bucket === 'AWAITED'))
|
|
23
|
+
return 'AWAITED';
|
|
24
|
+
const active = leaves.filter((l) => l.bucket !== 'DROPPED');
|
|
25
|
+
if (active.length === 0)
|
|
26
|
+
return 'DROPPED'; // only dropped (or empty) remain
|
|
27
|
+
if (active.every((l) => l.bucket === 'DONE'))
|
|
28
|
+
return 'DONE';
|
|
29
|
+
return 'TO-DO';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Project the folded state into status groups at `level`. Pure; the same `config.baselineCommit` that
|
|
33
|
+
* drives `bucketOf`/AWAITED governs here (no new boundary).
|
|
34
|
+
*/
|
|
35
|
+
export function statusByLevel(state, level, config) {
|
|
36
|
+
const items = [...state.items.values()];
|
|
37
|
+
// children index: parentId → direct children (id-sorted for deterministic labels/order — same as rollup).
|
|
38
|
+
const childrenOf = new Map();
|
|
39
|
+
for (const item of items) {
|
|
40
|
+
const list = childrenOf.get(item.parentId) ?? [];
|
|
41
|
+
list.push(item);
|
|
42
|
+
childrenOf.set(item.parentId, list);
|
|
43
|
+
}
|
|
44
|
+
for (const list of childrenOf.values())
|
|
45
|
+
list.sort((a, b) => a.id.localeCompare(b.id));
|
|
46
|
+
// Every NON-WP leaf TRANSITIVELY under `node` (descending THROUGH nested sub-WPs — a tier node owns all
|
|
47
|
+
// its descendants' leaves; SUM, not mean). A non-WP container (a feature with chore children) is descended.
|
|
48
|
+
const transitiveLeaves = (node) => {
|
|
49
|
+
const out = [];
|
|
50
|
+
const walk = (parentId) => {
|
|
51
|
+
for (const child of childrenOf.get(parentId) ?? []) {
|
|
52
|
+
if (isWp(child)) {
|
|
53
|
+
walk(child.id); // descend INTO the sub-WP — its leaves still count at this ancestor tier
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const grandkids = childrenOf.get(child.id) ?? [];
|
|
57
|
+
if (grandkids.length === 0) {
|
|
58
|
+
out.push({ id: child.id, title: child.title, bucket: bucketOf(state, child, config), kind: child.kind });
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
walk(child.id); // non-WP container — descend
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
walk(node);
|
|
66
|
+
return out;
|
|
67
|
+
};
|
|
68
|
+
const groupOf = (wp, label, depth) => {
|
|
69
|
+
const leaves = transitiveLeaves(wp.id);
|
|
70
|
+
const { done, active, dropped } = tally(leaves);
|
|
71
|
+
return {
|
|
72
|
+
id: wp.id,
|
|
73
|
+
title: wp.title,
|
|
74
|
+
label,
|
|
75
|
+
depth,
|
|
76
|
+
status: rollupStatus(leaves),
|
|
77
|
+
done,
|
|
78
|
+
active,
|
|
79
|
+
dropped,
|
|
80
|
+
pct: active === 0 ? 'n/a' : Math.round((done / active) * 100),
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
// ---- task: every non-WP leaf is its own group (the leaf bucket as a 1-leaf rollup). ----
|
|
84
|
+
if (level === 'task') {
|
|
85
|
+
const out = [];
|
|
86
|
+
const walkLeaves = (parentId, depth) => {
|
|
87
|
+
for (const child of childrenOf.get(parentId) ?? []) {
|
|
88
|
+
if (isWp(child)) {
|
|
89
|
+
walkLeaves(child.id, depth + 1);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const grandkids = childrenOf.get(child.id) ?? [];
|
|
93
|
+
if (grandkids.length === 0) {
|
|
94
|
+
const leaf = { id: child.id, title: child.title, bucket: bucketOf(state, child, config), kind: child.kind };
|
|
95
|
+
const { done, active, dropped } = tally([leaf]);
|
|
96
|
+
out.push({
|
|
97
|
+
id: child.id,
|
|
98
|
+
title: child.title,
|
|
99
|
+
label: child.id,
|
|
100
|
+
depth,
|
|
101
|
+
status: leaf.bucket,
|
|
102
|
+
done,
|
|
103
|
+
active,
|
|
104
|
+
dropped,
|
|
105
|
+
pct: active === 0 ? 'n/a' : Math.round((done / active) * 100),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
walkLeaves(child.id, depth);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
walkLeaves(undefined, 0);
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
// ---- WP-tier levels: collect every WP with its forest depth, then pick the tier the level names. ----
|
|
117
|
+
// Roots = WPs whose parent is not itself a WP (top-level WP, or a WP under a plain item) — same as rollup.
|
|
118
|
+
const isWpById = new Map(items.map((i) => [i.id, isWp(i)]));
|
|
119
|
+
const roots = items.filter((i) => isWp(i) && !(i.parentId !== undefined && isWpById.get(i.parentId)));
|
|
120
|
+
roots.sort((a, b) => a.id.localeCompare(b.id));
|
|
121
|
+
// Walk the WP forest, assigning the derived dotted label + depth (root WP = depth 0).
|
|
122
|
+
const all = [];
|
|
123
|
+
const visit = (wp, label, depth) => {
|
|
124
|
+
all.push({ wp, label, depth });
|
|
125
|
+
// Direct sub-WPs (a sub-WP nested under a non-WP container still counts as a child tier) — id-ordered.
|
|
126
|
+
let ordinal = 0;
|
|
127
|
+
const collectSubWps = (parentId) => {
|
|
128
|
+
for (const child of childrenOf.get(parentId) ?? []) {
|
|
129
|
+
if (isWp(child)) {
|
|
130
|
+
ordinal++;
|
|
131
|
+
visit(child, `${label}.${ordinal}`, depth + 1);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
collectSubWps(child.id);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
collectSubWps(wp.id);
|
|
139
|
+
};
|
|
140
|
+
roots.forEach((wp, idx) => visit(wp, `WP${idx + 1}`, 0));
|
|
141
|
+
// Level → which depth tier. `wp` = ALL WP nodes (≡ computeWpTree). `spec`/`plan` = the ROOT tier
|
|
142
|
+
// (depth 0). `lot` = the next nested tier (depth 1); deeper sub-WPs also surface as their own `lot`
|
|
143
|
+
// groups (a lot may nest), matching the rollup's "every nested sub-WP is a node".
|
|
144
|
+
const selected = level === 'wp'
|
|
145
|
+
? all
|
|
146
|
+
: level === 'spec' || level === 'plan'
|
|
147
|
+
? all.filter((n) => n.depth === 0)
|
|
148
|
+
: all.filter((n) => n.depth >= 1); // 'lot' — the nested-WP tier(s)
|
|
149
|
+
return selected.map((n) => groupOf(n.wp, n.label, n.depth));
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=status-by-level.js.map
|