@alex.botez/elaborate 1.0.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 +21 -0
- package/README.md +114 -0
- package/dist/durable/index.d.ts +10 -0
- package/dist/durable/index.d.ts.map +1 -0
- package/dist/durable/index.js +9 -0
- package/dist/durable/index.js.map +1 -0
- package/dist/durable/workflow.d.ts +165 -0
- package/dist/durable/workflow.d.ts.map +1 -0
- package/dist/durable/workflow.js +224 -0
- package/dist/durable/workflow.js.map +1 -0
- package/dist/interview/classification.d.ts +16 -0
- package/dist/interview/classification.d.ts.map +1 -0
- package/dist/interview/classification.js +25 -0
- package/dist/interview/classification.js.map +1 -0
- package/dist/interview/composition.d.ts +12 -0
- package/dist/interview/composition.d.ts.map +1 -0
- package/dist/interview/composition.js +19 -0
- package/dist/interview/composition.js.map +1 -0
- package/dist/interview/describe.d.ts +41 -0
- package/dist/interview/describe.d.ts.map +1 -0
- package/dist/interview/describe.js +80 -0
- package/dist/interview/describe.js.map +1 -0
- package/dist/interview/deviation.d.ts +91 -0
- package/dist/interview/deviation.d.ts.map +1 -0
- package/dist/interview/deviation.js +137 -0
- package/dist/interview/deviation.js.map +1 -0
- package/dist/interview/extraction.d.ts +32 -0
- package/dist/interview/extraction.d.ts.map +1 -0
- package/dist/interview/extraction.js +102 -0
- package/dist/interview/extraction.js.map +1 -0
- package/dist/interview/index.d.ts +25 -0
- package/dist/interview/index.d.ts.map +1 -0
- package/dist/interview/index.js +22 -0
- package/dist/interview/index.js.map +1 -0
- package/dist/interview/macros.d.ts +91 -0
- package/dist/interview/macros.d.ts.map +1 -0
- package/dist/interview/macros.js +138 -0
- package/dist/interview/macros.js.map +1 -0
- package/dist/interview/preambles.d.ts +18 -0
- package/dist/interview/preambles.d.ts.map +1 -0
- package/dist/interview/preambles.js +93 -0
- package/dist/interview/preambles.js.map +1 -0
- package/dist/interview/progress.d.ts +31 -0
- package/dist/interview/progress.d.ts.map +1 -0
- package/dist/interview/progress.js +51 -0
- package/dist/interview/progress.js.map +1 -0
- package/dist/interview/prompt.d.ts +20 -0
- package/dist/interview/prompt.d.ts.map +1 -0
- package/dist/interview/prompt.js +58 -0
- package/dist/interview/prompt.js.map +1 -0
- package/dist/phases/aggregate/assumptions.d.ts +14 -0
- package/dist/phases/aggregate/assumptions.d.ts.map +1 -0
- package/dist/phases/aggregate/assumptions.js +33 -0
- package/dist/phases/aggregate/assumptions.js.map +1 -0
- package/dist/phases/aggregate/findings.d.ts +10 -0
- package/dist/phases/aggregate/findings.d.ts.map +1 -0
- package/dist/phases/aggregate/findings.js +20 -0
- package/dist/phases/aggregate/findings.js.map +1 -0
- package/dist/phases/aggregate/goals.d.ts +28 -0
- package/dist/phases/aggregate/goals.d.ts.map +1 -0
- package/dist/phases/aggregate/goals.js +74 -0
- package/dist/phases/aggregate/goals.js.map +1 -0
- package/dist/phases/aggregate/index.d.ts +128 -0
- package/dist/phases/aggregate/index.d.ts.map +1 -0
- package/dist/phases/aggregate/index.js +165 -0
- package/dist/phases/aggregate/index.js.map +1 -0
- package/dist/phases/aggregate/pam.d.ts +19 -0
- package/dist/phases/aggregate/pam.d.ts.map +1 -0
- package/dist/phases/aggregate/pam.js +37 -0
- package/dist/phases/aggregate/pam.js.map +1 -0
- package/dist/phases/aggregate/scope.d.ts +24 -0
- package/dist/phases/aggregate/scope.d.ts.map +1 -0
- package/dist/phases/aggregate/scope.js +67 -0
- package/dist/phases/aggregate/scope.js.map +1 -0
- package/dist/phases/aggregate/shared.d.ts +16 -0
- package/dist/phases/aggregate/shared.d.ts.map +1 -0
- package/dist/phases/aggregate/shared.js +26 -0
- package/dist/phases/aggregate/shared.js.map +1 -0
- package/dist/phases/aggregate/stakeholders.d.ts +27 -0
- package/dist/phases/aggregate/stakeholders.d.ts.map +1 -0
- package/dist/phases/aggregate/stakeholders.js +90 -0
- package/dist/phases/aggregate/stakeholders.js.map +1 -0
- package/dist/phases/aggregate/waitingRoom.d.ts +16 -0
- package/dist/phases/aggregate/waitingRoom.d.ts.map +1 -0
- package/dist/phases/aggregate/waitingRoom.js +32 -0
- package/dist/phases/aggregate/waitingRoom.js.map +1 -0
- package/dist/phases/assumptions.d.ts +19 -0
- package/dist/phases/assumptions.d.ts.map +1 -0
- package/dist/phases/assumptions.js +224 -0
- package/dist/phases/assumptions.js.map +1 -0
- package/dist/phases/configuration.d.ts +8 -0
- package/dist/phases/configuration.d.ts.map +1 -0
- package/dist/phases/configuration.js +14 -0
- package/dist/phases/configuration.js.map +1 -0
- package/dist/phases/goals.d.ts +15 -0
- package/dist/phases/goals.d.ts.map +1 -0
- package/dist/phases/goals.js +297 -0
- package/dist/phases/goals.js.map +1 -0
- package/dist/phases/index.d.ts +21 -0
- package/dist/phases/index.d.ts.map +1 -0
- package/dist/phases/index.js +56 -0
- package/dist/phases/index.js.map +1 -0
- package/dist/phases/opening.d.ts +12 -0
- package/dist/phases/opening.d.ts.map +1 -0
- package/dist/phases/opening.js +99 -0
- package/dist/phases/opening.js.map +1 -0
- package/dist/phases/purpose.d.ts +17 -0
- package/dist/phases/purpose.d.ts.map +1 -0
- package/dist/phases/purpose.js +207 -0
- package/dist/phases/purpose.js.map +1 -0
- package/dist/phases/schema.d.ts +861 -0
- package/dist/phases/schema.d.ts.map +1 -0
- package/dist/phases/schema.js +157 -0
- package/dist/phases/schema.js.map +1 -0
- package/dist/phases/scope.d.ts +18 -0
- package/dist/phases/scope.d.ts.map +1 -0
- package/dist/phases/scope.js +440 -0
- package/dist/phases/scope.js.map +1 -0
- package/dist/phases/session/archive.d.ts +19 -0
- package/dist/phases/session/archive.d.ts.map +1 -0
- package/dist/phases/session/archive.js +49 -0
- package/dist/phases/session/archive.js.map +1 -0
- package/dist/phases/session/file.d.ts +31 -0
- package/dist/phases/session/file.d.ts.map +1 -0
- package/dist/phases/session/file.js +113 -0
- package/dist/phases/session/file.js.map +1 -0
- package/dist/phases/session/index.d.ts +8 -0
- package/dist/phases/session/index.d.ts.map +1 -0
- package/dist/phases/session/index.js +8 -0
- package/dist/phases/session/index.js.map +1 -0
- package/dist/phases/session/persistence.d.ts +30 -0
- package/dist/phases/session/persistence.d.ts.map +1 -0
- package/dist/phases/session/persistence.js +91 -0
- package/dist/phases/session/persistence.js.map +1 -0
- package/dist/phases/shared.d.ts +64 -0
- package/dist/phases/shared.d.ts.map +1 -0
- package/dist/phases/shared.js +100 -0
- package/dist/phases/shared.js.map +1 -0
- package/dist/phases/stakeholders.d.ts +17 -0
- package/dist/phases/stakeholders.d.ts.map +1 -0
- package/dist/phases/stakeholders.js +370 -0
- package/dist/phases/stakeholders.js.map +1 -0
- package/dist/phases/validation.d.ts +13 -0
- package/dist/phases/validation.d.ts.map +1 -0
- package/dist/phases/validation.js +130 -0
- package/dist/phases/validation.js.map +1 -0
- package/dist/skill/adapter.d.ts +16 -0
- package/dist/skill/adapter.d.ts.map +1 -0
- package/dist/skill/adapter.js +278 -0
- package/dist/skill/adapter.js.map +1 -0
- package/dist/skill/index.d.ts +12 -0
- package/dist/skill/index.d.ts.map +1 -0
- package/dist/skill/index.js +11 -0
- package/dist/skill/index.js.map +1 -0
- package/dist/skill/log.d.ts +18 -0
- package/dist/skill/log.d.ts.map +1 -0
- package/dist/skill/log.js +53 -0
- package/dist/skill/log.js.map +1 -0
- package/package.json +83 -0
- package/skills/elaborate/SKILL.md +97 -0
- package/skills/elaborate/scripts/elaborate.cjs +589 -0
- package/skills/project-brief/SKILL.md +45 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/phases/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MVP artifact schema using Zod
|
|
3
|
+
*/
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
/** Provenance — which prompt surfaced this artifact */
|
|
6
|
+
export const SourceSchema = z.object({
|
|
7
|
+
promptId: z.string(),
|
|
8
|
+
});
|
|
9
|
+
/** Goal status progression: fuzzy → elaborated → confirmed */
|
|
10
|
+
export const GoalStatus = z.enum(["fuzzy", "elaborated", "confirmed"]);
|
|
11
|
+
/** Deterministic confidence from goal status */
|
|
12
|
+
export const GOAL_CONFIDENCE = {
|
|
13
|
+
fuzzy: 0.5,
|
|
14
|
+
elaborated: 0.7,
|
|
15
|
+
confirmed: 0.9,
|
|
16
|
+
};
|
|
17
|
+
/** In-scope item — no status progression, boundary decisions are binary */
|
|
18
|
+
export const InScopeItemSchema = z.object({
|
|
19
|
+
id: z.string(),
|
|
20
|
+
description: z.string().min(1),
|
|
21
|
+
relatedGoals: z.array(z.string()).default([]),
|
|
22
|
+
confidence: z.number().min(0).max(1),
|
|
23
|
+
source: SourceSchema.optional(),
|
|
24
|
+
});
|
|
25
|
+
/** Out-of-scope item */
|
|
26
|
+
export const OutOfScopeItemSchema = z.object({
|
|
27
|
+
id: z.string(),
|
|
28
|
+
description: z.string().min(1),
|
|
29
|
+
reason: z.string().default(""),
|
|
30
|
+
relatedGoals: z.array(z.string()).default([]),
|
|
31
|
+
confidence: z.number().min(0).max(1),
|
|
32
|
+
source: SourceSchema.optional(),
|
|
33
|
+
});
|
|
34
|
+
/** Constraint — external non-negotiable reality */
|
|
35
|
+
export const ConstraintSchema = z.object({
|
|
36
|
+
id: z.string(),
|
|
37
|
+
description: z.string().min(1),
|
|
38
|
+
source: SourceSchema.optional(),
|
|
39
|
+
});
|
|
40
|
+
/** Stakeholder type */
|
|
41
|
+
export const StakeholderType = z.enum(["primary", "secondary", "external"]);
|
|
42
|
+
/** Stakeholder status progression: identified → elaborated → confirmed */
|
|
43
|
+
export const StakeholderStatus = z.enum(["identified", "elaborated", "confirmed"]);
|
|
44
|
+
/** Deterministic confidence from stakeholder status */
|
|
45
|
+
export const STAKEHOLDER_CONFIDENCE = {
|
|
46
|
+
identified: 0.5,
|
|
47
|
+
elaborated: 0.7,
|
|
48
|
+
confirmed: 0.9,
|
|
49
|
+
};
|
|
50
|
+
/** Purpose statement with confidence */
|
|
51
|
+
export const PurposeSchema = z.object({
|
|
52
|
+
statement: z.string().min(1),
|
|
53
|
+
confidence: z.number().min(0).max(1),
|
|
54
|
+
source: SourceSchema.optional(),
|
|
55
|
+
});
|
|
56
|
+
/** Goal */
|
|
57
|
+
export const GoalSchema = z.object({
|
|
58
|
+
id: z.string(),
|
|
59
|
+
title: z.string().min(1),
|
|
60
|
+
description: z.string(),
|
|
61
|
+
rationale: z.string().optional(),
|
|
62
|
+
status: GoalStatus,
|
|
63
|
+
confidence: z.number().min(0).max(1),
|
|
64
|
+
source: SourceSchema.optional(),
|
|
65
|
+
});
|
|
66
|
+
/** Stakeholder */
|
|
67
|
+
export const StakeholderSchema = z.object({
|
|
68
|
+
id: z.string(),
|
|
69
|
+
name: z.string().min(1),
|
|
70
|
+
type: StakeholderType,
|
|
71
|
+
role: z.string().default(""),
|
|
72
|
+
concerns: z.array(z.string()).default([]),
|
|
73
|
+
isRespondent: z.boolean().default(false),
|
|
74
|
+
status: StakeholderStatus.default("identified"),
|
|
75
|
+
confidence: z.number().min(0).max(1).default(0.5),
|
|
76
|
+
source: SourceSchema.optional(),
|
|
77
|
+
});
|
|
78
|
+
/** Advantage statement with confidence */
|
|
79
|
+
export const AdvantageSchema = z.object({
|
|
80
|
+
statement: z.string().min(1),
|
|
81
|
+
confidence: z.number().min(0).max(1),
|
|
82
|
+
source: SourceSchema.optional(),
|
|
83
|
+
});
|
|
84
|
+
/** Measurement criteria with confidence */
|
|
85
|
+
export const MeasurementSchema = z.object({
|
|
86
|
+
statement: z.string().min(1),
|
|
87
|
+
confidence: z.number().min(0).max(1),
|
|
88
|
+
source: SourceSchema.optional(),
|
|
89
|
+
});
|
|
90
|
+
/** Assumption status: no progression — binary validation with explicit "can't verify" */
|
|
91
|
+
export const AssumptionStatus = z.enum(["unvalidated", "validated", "flagged"]);
|
|
92
|
+
/** Deterministic confidence from assumption status */
|
|
93
|
+
export const ASSUMPTION_CONFIDENCE = {
|
|
94
|
+
unvalidated: 0.5,
|
|
95
|
+
validated: 0.9,
|
|
96
|
+
flagged: 0.7,
|
|
97
|
+
};
|
|
98
|
+
export const AssumptionType = z.enum(["hypothesis", "invariant"]);
|
|
99
|
+
/** Assumption — believed-but-unverified domain property (KAOS) */
|
|
100
|
+
export const AssumptionSchema = z.object({
|
|
101
|
+
id: z.string(),
|
|
102
|
+
statement: z.string().min(1),
|
|
103
|
+
type: AssumptionType,
|
|
104
|
+
status: AssumptionStatus.default("unvalidated"),
|
|
105
|
+
relatedGoals: z.array(z.string()).default([]),
|
|
106
|
+
confidence: z.number().min(0).max(1),
|
|
107
|
+
source: SourceSchema.optional(),
|
|
108
|
+
});
|
|
109
|
+
/** Waiting room item */
|
|
110
|
+
export const WaitingItemSchema = z.object({
|
|
111
|
+
id: z.string(),
|
|
112
|
+
content: z.string().min(1),
|
|
113
|
+
});
|
|
114
|
+
/** A finding — gap or observation captured during the session */
|
|
115
|
+
export const FindingSchema = z.object({
|
|
116
|
+
id: z.string(),
|
|
117
|
+
content: z.string().min(1),
|
|
118
|
+
phase: z.string(),
|
|
119
|
+
});
|
|
120
|
+
/** Residual item — WR content that survived classify-and-route in validation */
|
|
121
|
+
export const ResidualItemSchema = z.object({
|
|
122
|
+
id: z.string(),
|
|
123
|
+
content: z.string().min(1),
|
|
124
|
+
reason: z.string().min(1),
|
|
125
|
+
});
|
|
126
|
+
/** Complete artifacts structure (MVP) */
|
|
127
|
+
export const ArtifactsSchema = z.object({
|
|
128
|
+
purpose: PurposeSchema.optional(),
|
|
129
|
+
advantage: AdvantageSchema.optional(),
|
|
130
|
+
measurement: MeasurementSchema.optional(),
|
|
131
|
+
goals: z.array(GoalSchema).default([]),
|
|
132
|
+
stakeholders: z.array(StakeholderSchema).default([]),
|
|
133
|
+
inScope: z.array(InScopeItemSchema).default([]),
|
|
134
|
+
outOfScope: z.array(OutOfScopeItemSchema).default([]),
|
|
135
|
+
constraints: z.array(ConstraintSchema).default([]),
|
|
136
|
+
assumptions: z.array(AssumptionSchema).default([]),
|
|
137
|
+
domainHints: z.array(z.string()).default([]),
|
|
138
|
+
waitingRoom: z.array(WaitingItemSchema).default([]),
|
|
139
|
+
findings: z.array(FindingSchema).default([]),
|
|
140
|
+
residual: z.array(ResidualItemSchema).default([]),
|
|
141
|
+
});
|
|
142
|
+
/** Create empty artifacts structure */
|
|
143
|
+
export function createEmptyArtifacts() {
|
|
144
|
+
return {
|
|
145
|
+
goals: [],
|
|
146
|
+
stakeholders: [],
|
|
147
|
+
inScope: [],
|
|
148
|
+
outOfScope: [],
|
|
149
|
+
constraints: [],
|
|
150
|
+
assumptions: [],
|
|
151
|
+
domainHints: [],
|
|
152
|
+
waitingRoom: [],
|
|
153
|
+
findings: [],
|
|
154
|
+
residual: [],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/phases/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope definition phase — boundary classification via contrast questioning.
|
|
3
|
+
*
|
|
4
|
+
* Captures scope through:
|
|
5
|
+
* 1. Seed extraction + waiting room drain
|
|
6
|
+
* 2. Constraint discovery
|
|
7
|
+
* 3. Contrast questions for ambiguous items (in/out/deferred)
|
|
8
|
+
* 4. Contradiction check (scope vs goals alignment)
|
|
9
|
+
* 5. Quality check (nudge if empty)
|
|
10
|
+
* 6. Confirmation with revision loop
|
|
11
|
+
*
|
|
12
|
+
* Novel schema — no RE framework defines scope items for structured dialog.
|
|
13
|
+
* No status progression: boundary decisions are binary. Confidence without status.
|
|
14
|
+
*/
|
|
15
|
+
import type { WorkflowContext } from "../durable/index.js";
|
|
16
|
+
import type { ArtifactAggregate } from "./aggregate/index.js";
|
|
17
|
+
export declare function runScope(ctx: WorkflowContext, agg: ArtifactAggregate): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/phases/scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AA+Q9D,wBAAsB,QAAQ,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuN1F"}
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope definition phase — boundary classification via contrast questioning.
|
|
3
|
+
*
|
|
4
|
+
* Captures scope through:
|
|
5
|
+
* 1. Seed extraction + waiting room drain
|
|
6
|
+
* 2. Constraint discovery
|
|
7
|
+
* 3. Contrast questions for ambiguous items (in/out/deferred)
|
|
8
|
+
* 4. Contradiction check (scope vs goals alignment)
|
|
9
|
+
* 5. Quality check (nudge if empty)
|
|
10
|
+
* 6. Confirmation with revision loop
|
|
11
|
+
*
|
|
12
|
+
* Novel schema — no RE framework defines scope items for structured dialog.
|
|
13
|
+
* No status progression: boundary decisions are binary. Confidence without status.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
import { inferStep, inferCompositionStep } from "../interview/index.js";
|
|
17
|
+
import { buildFullContext, confirmationCloser, confirmPhase } from "./shared.js";
|
|
18
|
+
import { SCOPE_CONTRAST_CAP } from "./configuration.js";
|
|
19
|
+
const SeedExtractionSchema = z.object({
|
|
20
|
+
inScope: z.array(z.object({
|
|
21
|
+
description: z.string().describe("what is in scope"),
|
|
22
|
+
relatedGoals: z.array(z.string()).optional().describe("goal IDs this supports"),
|
|
23
|
+
})).optional().describe("items clearly in scope from the conversation, empty if none"),
|
|
24
|
+
outOfScope: z.array(z.object({
|
|
25
|
+
description: z.string().describe("what is excluded"),
|
|
26
|
+
reason: z.string().optional().describe("why it's excluded"),
|
|
27
|
+
relatedGoals: z.array(z.string()).optional().describe("goal IDs this relates to"),
|
|
28
|
+
})).optional().describe("items clearly excluded, empty if none"),
|
|
29
|
+
ambiguous: z.array(z.object({
|
|
30
|
+
description: z.string().describe("the ambiguous item"),
|
|
31
|
+
relatedGoals: z.array(z.string()).optional().describe("goal IDs this relates to"),
|
|
32
|
+
})).optional().describe("items mentioned but unclear if in or out, empty if none"),
|
|
33
|
+
drainedWaitingRoomIds: z.array(z.string()).optional()
|
|
34
|
+
.describe('IDs of waiting room items classified into scope (e.g. ["waiting_001"]), empty if none'),
|
|
35
|
+
});
|
|
36
|
+
const ScopeSeedResponseSchema = z.object({
|
|
37
|
+
responseInterpretation: z.string().describe("what the respondent meant"),
|
|
38
|
+
confirmedInScope: z.array(z.string()).optional().describe("IDs the user confirmed as in-scope (or all if confirmed)"),
|
|
39
|
+
confirmedOutOfScope: z.array(z.string()).optional().describe("IDs the user confirmed as out-of-scope"),
|
|
40
|
+
removedIds: z.array(z.string()).optional().describe("IDs to remove entirely"),
|
|
41
|
+
newItems: z.array(z.object({ description: z.string().describe("the scope item"), classification: z.string().optional().describe("'in', 'out', or 'ambiguous'") })).optional().describe("new items mentioned, empty if none"),
|
|
42
|
+
waitingRoomItems: z.array(z.object({ content: z.string().describe("the item text") })).optional().describe("items that sound like assumptions rather than scope, empty if none"),
|
|
43
|
+
});
|
|
44
|
+
const ConstraintExtractionSchema = z.object({
|
|
45
|
+
responseInterpretation: z.string().describe("what the respondent meant, resolving any suggestion references"),
|
|
46
|
+
constraints: z.array(z.object({ description: z.string().describe("the constraint") })).optional().describe("constraints extracted from the response, empty if none"),
|
|
47
|
+
waitingRoomItems: z.array(z.object({ content: z.string().describe("the item text") })).optional().describe("items that sound like assumptions rather than constraints, empty if none"),
|
|
48
|
+
});
|
|
49
|
+
const ContrastExtractionSchema = z.object({
|
|
50
|
+
responseInterpretation: z.string().describe("what the respondent meant, resolving any suggestion references"),
|
|
51
|
+
classification: z.enum(["in", "out", "deferred"]).optional().describe("where this item belongs"),
|
|
52
|
+
reason: z.string().optional().describe("why it's excluded (only if classification is 'out'), empty otherwise"),
|
|
53
|
+
relatedGoals: z.array(z.string()).optional().describe("goal IDs this item relates to, empty if none"),
|
|
54
|
+
waitingRoomItems: z.array(z.object({ content: z.string().describe("the item text") })).optional().describe("items that sound like assumptions, empty if none"),
|
|
55
|
+
});
|
|
56
|
+
const AmbiguousSortSchema = z.object({
|
|
57
|
+
rankedAmbiguousIds: z.array(z.string()).describe("ambiguous item indices (as strings) ordered from highest to lowest priority for contrast questions"),
|
|
58
|
+
autoClassifications: z.array(z.object({
|
|
59
|
+
index: z.string().describe("the ambiguous item index (as string)"),
|
|
60
|
+
classification: z.enum(["in", "out"]).describe("best-guess classification"),
|
|
61
|
+
relatedGoals: z.array(z.string()).optional().describe("goal IDs this item relates to"),
|
|
62
|
+
reason: z.string().optional().describe("why classified out (only if 'out')"),
|
|
63
|
+
})).describe("default in/out classification for items that won't get contrast questions"),
|
|
64
|
+
});
|
|
65
|
+
function ambiguousSort(ambiguousItems, artifacts) {
|
|
66
|
+
const itemRef = ambiguousItems.map((item, i) => {
|
|
67
|
+
const goals = item.relatedGoals?.length ? ` (goals: ${item.relatedGoals.join(", ")})` : "";
|
|
68
|
+
return `[${i}] "${item.description}"${goals}`;
|
|
69
|
+
}).join("; ");
|
|
70
|
+
const goalRef = artifacts.goals.map((g) => `[${g.id}] "${g.title}" — ${g.description}`).join("; ");
|
|
71
|
+
const scopeRef = [
|
|
72
|
+
...artifacts.inScope.map((s) => `IN: "${s.description}"`),
|
|
73
|
+
...artifacts.outOfScope.map((s) => `OUT: "${s.description}"`),
|
|
74
|
+
].join("; ");
|
|
75
|
+
return inferStep({
|
|
76
|
+
id: "scope-ambiguous-sort",
|
|
77
|
+
schema: AmbiguousSortSchema,
|
|
78
|
+
message: `
|
|
79
|
+
Rank these ambiguous scope items by priority for boundary clarification, and provide default in/out classifications for lower-priority items.
|
|
80
|
+
|
|
81
|
+
Ambiguous items: ${itemRef}
|
|
82
|
+
Goals: ${goalRef}
|
|
83
|
+
Existing scope: ${scopeRef}
|
|
84
|
+
|
|
85
|
+
Ranking criteria (in order):
|
|
86
|
+
1. Connected to more goals: items touching multiple goals affect more downstream requirements.
|
|
87
|
+
2. Higher ambiguity: items where the in/out decision is genuinely unclear rank above items that are almost certainly one way.
|
|
88
|
+
|
|
89
|
+
Return ALL indices in rankedAmbiguousIds (highest priority first).
|
|
90
|
+
For items beyond the top ${SCOPE_CONTRAST_CAP}, provide autoClassifications with your best-guess in/out.
|
|
91
|
+
`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const ContradictionCheckSchema = z.object({
|
|
95
|
+
contradictions: z.array(z.object({
|
|
96
|
+
description: z.string().describe("what the contradiction is"),
|
|
97
|
+
scopeItemId: z.string().describe("the scope item ID"),
|
|
98
|
+
goalId: z.string().describe("the conflicting goal ID"),
|
|
99
|
+
})).optional().describe("scope items that make a confirmed/elaborated goal infeasible — the goal CANNOT be achieved without this item. NOT: soft tensions where a goal is merely weakened, less efficient, or harder to achieve. Empty array if none"),
|
|
100
|
+
orphans: z.array(z.object({
|
|
101
|
+
scopeItemId: z.string().describe("the scope item ID"),
|
|
102
|
+
description: z.string().describe("what the orphan item is"),
|
|
103
|
+
})).optional().describe("in-scope items with no goal connection"),
|
|
104
|
+
});
|
|
105
|
+
const ScopeDedupSchema = z.object({
|
|
106
|
+
duplicateGroups: z.array(z.object({
|
|
107
|
+
keepId: z.string().describe("the scope item ID to keep"),
|
|
108
|
+
removeIds: z.array(z.string()).describe("scope item IDs that are semantically duplicate of keepId"),
|
|
109
|
+
})).describe("groups of semantically duplicate scope items — only flag items you are CERTAIN describe the same thing with different wording"),
|
|
110
|
+
});
|
|
111
|
+
const ScopeRevisionSchema = z.object({
|
|
112
|
+
responseInterpretation: z.string().describe("what the respondent meant, resolving any suggestion references"),
|
|
113
|
+
inScope: z.array(z.object({ description: z.string().describe("what is in scope"), relatedGoals: z.array(z.string()).optional().describe("goal IDs this supports") })).optional().describe("new or updated in-scope items, empty if none"),
|
|
114
|
+
outOfScope: z.array(z.object({ description: z.string().describe("what is excluded"), reason: z.string().optional().describe("why it's excluded"), relatedGoals: z.array(z.string()).optional().describe("goal IDs this relates to") })).optional().describe("new or updated out-of-scope items, empty if none"),
|
|
115
|
+
removedIds: z.array(z.string()).optional().describe("scope item IDs to remove, empty if none"),
|
|
116
|
+
reclassifiedItems: z.array(z.object({
|
|
117
|
+
id: z.string().describe("scope item ID to reclassify"),
|
|
118
|
+
newClassification: z.enum(["in", "out"]).describe("new classification"),
|
|
119
|
+
})).optional().describe("existing scope items to move between in-scope and out-of-scope, empty if none"),
|
|
120
|
+
waitingRoomItems: z.array(z.object({ content: z.string().describe("the item text") })).optional().describe("items that sound like assumptions, empty if none"),
|
|
121
|
+
});
|
|
122
|
+
function seedPresent(artifacts, ambiguousDescriptions) {
|
|
123
|
+
const letters = "abcdefghijklmnopqrstuvwxyz";
|
|
124
|
+
const inStart = 0;
|
|
125
|
+
const outStart = artifacts.inScope.length;
|
|
126
|
+
const ambStart = outStart + artifacts.outOfScope.length;
|
|
127
|
+
const total = ambStart + ambiguousDescriptions.length;
|
|
128
|
+
if (total === 0) {
|
|
129
|
+
return {
|
|
130
|
+
id: "scope-seed-present",
|
|
131
|
+
message: `I haven't identified specific **scope boundaries** from our conversation yet.\n\nWhat are the main things your project will definitely include or exclude?`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const inSection = artifacts.inScope.length > 0
|
|
135
|
+
? `**In scope:**\n${artifacts.inScope.map((item, i) => `${letters[inStart + i]}) ${item.description}`).join("\n")}\n\n`
|
|
136
|
+
: "";
|
|
137
|
+
const outSection = artifacts.outOfScope.length > 0
|
|
138
|
+
? `**Out of scope:**\n${artifacts.outOfScope.map((item, i) => {
|
|
139
|
+
const reason = item.reason ? ` — ${item.reason}` : "";
|
|
140
|
+
return `${letters[outStart + i]}) ${item.description}${reason}`;
|
|
141
|
+
}).join("\n")}\n\n`
|
|
142
|
+
: "";
|
|
143
|
+
const ambSection = ambiguousDescriptions.length > 0
|
|
144
|
+
? `**Unclear (we'll sort these out):**\n${ambiguousDescriptions.map((desc, i) => `${letters[ambStart + i]}) ${desc}`).join("\n")}\n\n`
|
|
145
|
+
: "";
|
|
146
|
+
return {
|
|
147
|
+
id: "scope-seed-present",
|
|
148
|
+
message: `
|
|
149
|
+
Based on our conversation, here's what I see for your project scope:
|
|
150
|
+
${inSection}${outSection}${ambSection}
|
|
151
|
+
Does this look right? You can confirm, add items, remove items, or reclassify.
|
|
152
|
+
`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function constraintComposition(artifacts) {
|
|
156
|
+
return inferCompositionStep({
|
|
157
|
+
id: "",
|
|
158
|
+
fallback: "Are there any constraints your project must work within? Think about technical limits, budget, timeline, or regulations.",
|
|
159
|
+
message: `
|
|
160
|
+
Compose a question about project constraints — non-negotiable realities the project must work within.
|
|
161
|
+
Ask about technical, budget, timeline, regulatory, or organizational constraints.
|
|
162
|
+
Include 2-3 suggested constraints relevant to the project domain.
|
|
163
|
+
|
|
164
|
+
Context:
|
|
165
|
+
${buildFullContext(artifacts)}
|
|
166
|
+
`,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function contrastComposition(description, artifacts) {
|
|
170
|
+
return inferCompositionStep({
|
|
171
|
+
id: "",
|
|
172
|
+
fallback: `Is "${description}" in scope or out of scope for this project?`,
|
|
173
|
+
message: `
|
|
174
|
+
Compose a contrast question about: "${description}"
|
|
175
|
+
Ask whether this item is in scope or out of scope for the project.
|
|
176
|
+
Frame it as a clear choice. Include 2-3 suggested answers that clarify the boundary.
|
|
177
|
+
|
|
178
|
+
Context:
|
|
179
|
+
${buildFullContext(artifacts)}
|
|
180
|
+
`,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function nudge() {
|
|
184
|
+
return {
|
|
185
|
+
id: "scope-nudge",
|
|
186
|
+
message: `
|
|
187
|
+
We haven't defined any scope boundaries yet.
|
|
188
|
+
Could you tell me at least one thing that's definitely part of this project, or one thing that's explicitly NOT part of it?`,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function contradictionCheck(artifacts) {
|
|
192
|
+
const goalRef = artifacts.goals.map((g) => `[${g.id}] "${g.title}" (${g.status})`).join("; ");
|
|
193
|
+
const scopeRef = [
|
|
194
|
+
...artifacts.inScope.map((s) => `IN [${s.id}]: "${s.description}" (goals: ${s.relatedGoals.join(", ") || "none"})`),
|
|
195
|
+
...artifacts.outOfScope.map((s) => `OUT [${s.id}]: "${s.description}" (goals: ${s.relatedGoals.join(", ") || "none"})`),
|
|
196
|
+
...artifacts.constraints.map((c) => `CONSTRAINT [${c.id}]: "${c.description}"`),
|
|
197
|
+
].join("; ");
|
|
198
|
+
return inferStep({
|
|
199
|
+
id: "scope-contradiction-check",
|
|
200
|
+
message: `
|
|
201
|
+
Check for contradictions between scope decisions and goals.
|
|
202
|
+
|
|
203
|
+
Goals: ${goalRef}
|
|
204
|
+
Scope: ${scopeRef}
|
|
205
|
+
|
|
206
|
+
Find:
|
|
207
|
+
1. Out-of-scope items needed by a confirmed/elaborated goal → contradiction
|
|
208
|
+
2. Constraints that make a goal infeasible → contradiction
|
|
209
|
+
3. In-scope items with no connection to any goal → orphan (not contradiction, just a note)
|
|
210
|
+
`,
|
|
211
|
+
schema: ContradictionCheckSchema,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function scopeDedup(artifacts, suffix) {
|
|
215
|
+
const allItems = [
|
|
216
|
+
...artifacts.inScope.map((s) => `IN [${s.id}]: "${s.description}"`),
|
|
217
|
+
...artifacts.outOfScope.map((s) => `OUT [${s.id}]: "${s.description}"`),
|
|
218
|
+
].join("; ");
|
|
219
|
+
return inferStep({
|
|
220
|
+
id: suffix ? `scope-dedup-${suffix}` : "scope-dedup",
|
|
221
|
+
schema: ScopeDedupSchema,
|
|
222
|
+
message: `
|
|
223
|
+
Identify semantically duplicate scope items — items that describe the same concept with different wording.
|
|
224
|
+
|
|
225
|
+
Scope items: ${allItems}
|
|
226
|
+
|
|
227
|
+
Rules:
|
|
228
|
+
1. Only group items you are CERTAIN are duplicates (same concept, different words). Related but distinct items are NOT duplicates.
|
|
229
|
+
2. For each group, pick the clearest/most specific description as keepId.
|
|
230
|
+
3. Items in different classifications (IN vs OUT) are never duplicates — they represent a conflict, not a duplicate.
|
|
231
|
+
4. Return an empty array if there are no duplicates.
|
|
232
|
+
`,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function confirmation(artifacts, findings) {
|
|
236
|
+
const inSection = artifacts.inScope.length > 0
|
|
237
|
+
? `**In scope:**\n${artifacts.inScope.map((s) => {
|
|
238
|
+
const goals = s.relatedGoals.length > 0 ? ` (supports: ${s.relatedGoals.join(", ")})` : "";
|
|
239
|
+
return `- ${s.description}${goals}`;
|
|
240
|
+
}).join("\n")}\n\n`
|
|
241
|
+
: "";
|
|
242
|
+
const outSection = artifacts.outOfScope.length > 0
|
|
243
|
+
? `**Out of scope:**\n${artifacts.outOfScope.map((s) => {
|
|
244
|
+
const reason = s.reason ? ` — ${s.reason}` : "";
|
|
245
|
+
return `- ${s.description}${reason}`;
|
|
246
|
+
}).join("\n")}\n\n`
|
|
247
|
+
: "";
|
|
248
|
+
const constSection = artifacts.constraints.length > 0
|
|
249
|
+
? `**Constraints:**\n${artifacts.constraints.map((c) => `- ${c.description}`).join("\n")}\n\n`
|
|
250
|
+
: "";
|
|
251
|
+
const scopeFindings = findings.filter((f) => f.phase === "scope");
|
|
252
|
+
const findingsSection = scopeFindings.length > 0
|
|
253
|
+
? `**Notes:**\n${scopeFindings.map((f) => `- ${f.content}`).join("\n")}\n\n`
|
|
254
|
+
: "";
|
|
255
|
+
return {
|
|
256
|
+
id: "scope-confirmation",
|
|
257
|
+
message: `
|
|
258
|
+
Here's what I've captured for your project scope:
|
|
259
|
+
${inSection}${outSection}${constSection}${findingsSection}
|
|
260
|
+
${confirmationCloser()}`,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
export async function runScope(ctx, agg) {
|
|
264
|
+
const artifacts = agg.data;
|
|
265
|
+
// Track waiting room IDs before seeding so we only drain pre-existing items
|
|
266
|
+
const preWaitingRoomIds = new Set(artifacts.waitingRoom.map((w) => w.id));
|
|
267
|
+
// Step 1: Seed extraction + waiting room drain
|
|
268
|
+
const seeds = await ctx.seed({
|
|
269
|
+
id: "scope-seed-extraction",
|
|
270
|
+
artifactsContext: buildFullContext(artifacts, { includeWaitingRoom: true }),
|
|
271
|
+
schema: SeedExtractionSchema,
|
|
272
|
+
guidance: "Extract scope candidates. Classify each as clearly in-scope, out-of-scope, or ambiguous. Link to goal IDs. Pull hints from the waitingRoom items in the context; return drainedWaitingRoomIds for the items you consumed.",
|
|
273
|
+
});
|
|
274
|
+
const ambiguousItems = seeds.ambiguous ?? [];
|
|
275
|
+
const src = ctx.currentSource;
|
|
276
|
+
agg.addInScopeItems(seeds.inScope ?? [], undefined, src);
|
|
277
|
+
agg.addOutOfScopeItems(seeds.outOfScope ?? [], undefined, src);
|
|
278
|
+
// Drain waiting room items the LLM reported as consumed (by ID)
|
|
279
|
+
const drainedIds = new Set((seeds.drainedWaitingRoomIds ?? []).filter((id) => preWaitingRoomIds.has(id)));
|
|
280
|
+
agg.drainWaitingRoom(drainedIds);
|
|
281
|
+
// Present seed list
|
|
282
|
+
const ambiguousDescriptions = ambiguousItems.map((a) => a.description);
|
|
283
|
+
// Classify seed response
|
|
284
|
+
const allItems = [...artifacts.inScope, ...artifacts.outOfScope];
|
|
285
|
+
const itemRef = allItems.map((s) => `${s.id}: "${s.description}"`).join(", ");
|
|
286
|
+
const seedClass = await ctx.promptReview(seedPresent(artifacts, ambiguousDescriptions), "scope-seed-classification", itemRef, buildFullContext(artifacts), ScopeSeedResponseSchema, { defaults: { responseInterpretation: "", confirmedInScope: [], confirmedOutOfScope: [], removedIds: [], newItems: [], waitingRoomItems: [] } });
|
|
287
|
+
// Remove rejected items
|
|
288
|
+
const removedIds = new Set(seedClass.removedIds ?? []);
|
|
289
|
+
if (removedIds.size > 0) {
|
|
290
|
+
agg.removeScopeItems(removedIds);
|
|
291
|
+
}
|
|
292
|
+
// Add new items from response
|
|
293
|
+
const reviewSrc = ctx.currentSource;
|
|
294
|
+
for (const item of seedClass.newItems ?? []) {
|
|
295
|
+
if (item.classification === "out") {
|
|
296
|
+
agg.addOutOfScopeItems([item], undefined, reviewSrc);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
agg.addInScopeItems([item], undefined, reviewSrc);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
agg.addWaitingRoomItems(seedClass.waitingRoomItems ?? []);
|
|
303
|
+
// Step 2: Constraints (with deviation resilience)
|
|
304
|
+
const constExtraction = await ctx.composePromptExtract("scope-constraint", () => constraintComposition(artifacts), { artifactsContext: buildFullContext(artifacts), schema: ConstraintExtractionSchema, guidance: "Constraints are non-negotiable external realities (technical limits, budget, timeline, regulations)." }, { park: (items) => agg.addWaitingRoomItems(items), maxRetries: 2, defaults: { responseInterpretation: "", constraints: [], waitingRoomItems: [] } });
|
|
305
|
+
agg.addConstraints(constExtraction.constraints ?? [], ctx.currentSource);
|
|
306
|
+
agg.addWaitingRoomItems(constExtraction.waitingRoomItems ?? []);
|
|
307
|
+
// Steps 3-4: Sort + cap ambiguous items, then contrast questions for top items
|
|
308
|
+
let contrastItems;
|
|
309
|
+
if (ambiguousItems.length > SCOPE_CONTRAST_CAP) {
|
|
310
|
+
const sortResult = await ctx.infer(ambiguousSort(ambiguousItems, artifacts));
|
|
311
|
+
const validIndices = new Set(ambiguousItems.map((_, i) => String(i)));
|
|
312
|
+
const ranked = sortResult.rankedAmbiguousIds.filter((id) => validIndices.has(id));
|
|
313
|
+
const keepIndices = ranked.length >= SCOPE_CONTRAST_CAP
|
|
314
|
+
? ranked.slice(0, SCOPE_CONTRAST_CAP)
|
|
315
|
+
: ambiguousItems.slice(0, SCOPE_CONTRAST_CAP).map((_, i) => String(i));
|
|
316
|
+
const keepSet = new Set(keepIndices);
|
|
317
|
+
contrastItems = keepIndices.map((idx) => ambiguousItems[Number(idx)]);
|
|
318
|
+
// Auto-classify excess items
|
|
319
|
+
const autoMap = new Map(sortResult.autoClassifications.map((ac) => [ac.index, ac]));
|
|
320
|
+
for (let i = 0; i < ambiguousItems.length; i++) {
|
|
321
|
+
if (keepSet.has(String(i)))
|
|
322
|
+
continue;
|
|
323
|
+
const auto = autoMap.get(String(i));
|
|
324
|
+
const item = ambiguousItems[i];
|
|
325
|
+
if (auto?.classification === "out") {
|
|
326
|
+
agg.addOutOfScopeItems([{ description: item.description, reason: auto.reason, relatedGoals: auto.relatedGoals }], undefined, src);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
agg.addInScopeItems([{ description: item.description, relatedGoals: auto?.relatedGoals ?? item.relatedGoals }], undefined, src);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
contrastItems = ambiguousItems;
|
|
335
|
+
}
|
|
336
|
+
for (let i = 0; i < contrastItems.length; i++) {
|
|
337
|
+
const item = contrastItems[i];
|
|
338
|
+
const contrastResult = await ctx.composePromptExtract(`scope-contrast-${i}`, () => contrastComposition(item.description, artifacts), { artifactsContext: buildFullContext(artifacts), schema: ContrastExtractionSchema, focus: `"${item.description}"` }, { defaults: { responseInterpretation: "", classification: "deferred", reason: "", relatedGoals: [], waitingRoomItems: [] } });
|
|
339
|
+
const contrastSrc = ctx.currentSource;
|
|
340
|
+
const resolvedDescription = contrastResult.responseInterpretation || item.description;
|
|
341
|
+
if (contrastResult.classification === "in") {
|
|
342
|
+
agg.addInScopeItems([{
|
|
343
|
+
description: resolvedDescription,
|
|
344
|
+
relatedGoals: contrastResult.relatedGoals,
|
|
345
|
+
}], undefined, contrastSrc);
|
|
346
|
+
}
|
|
347
|
+
else if (contrastResult.classification === "out") {
|
|
348
|
+
agg.addOutOfScopeItems([{
|
|
349
|
+
description: resolvedDescription,
|
|
350
|
+
reason: contrastResult.reason,
|
|
351
|
+
relatedGoals: contrastResult.relatedGoals,
|
|
352
|
+
}], undefined, contrastSrc);
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
agg.addWaitingRoomItems([{ content: item.description }]);
|
|
356
|
+
}
|
|
357
|
+
agg.addWaitingRoomItems(contrastResult.waitingRoomItems ?? []);
|
|
358
|
+
}
|
|
359
|
+
// Step 5: Contradiction check
|
|
360
|
+
if (artifacts.goals.length > 0 && (artifacts.inScope.length > 0 || artifacts.outOfScope.length > 0)) {
|
|
361
|
+
const checkResult = await ctx.infer(contradictionCheck(artifacts));
|
|
362
|
+
// Surface contradictions
|
|
363
|
+
if (checkResult.contradictions && checkResult.contradictions.length > 0) {
|
|
364
|
+
const contradictionDescs = checkResult.contradictions.map((c) => c.description);
|
|
365
|
+
await ctx.promptReextract("scope-contradiction-clarification", contradictionDescs, buildFullContext(artifacts), z.object({}), { defaults: {} });
|
|
366
|
+
}
|
|
367
|
+
// Record orphans as findings
|
|
368
|
+
if (checkResult.orphans && checkResult.orphans.length > 0) {
|
|
369
|
+
for (const orphan of checkResult.orphans) {
|
|
370
|
+
agg.addFinding(`In-scope item "${orphan.description}" has no connection to any stated goal`, "scope");
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Step 6: Quality check
|
|
375
|
+
if (artifacts.inScope.length === 0 && artifacts.outOfScope.length === 0) {
|
|
376
|
+
// One nudge
|
|
377
|
+
const nudgeClass = await ctx.promptExtract(nudge(), { artifactsContext: buildFullContext(artifacts), schema: SeedExtractionSchema }, { defaults: { inScope: [], outOfScope: [], ambiguous: [], drainedWaitingRoomIds: [] } });
|
|
378
|
+
const nudgeSrc = ctx.currentSource;
|
|
379
|
+
agg.addInScopeItems(nudgeClass.inScope ?? [], undefined, nudgeSrc);
|
|
380
|
+
agg.addOutOfScopeItems(nudgeClass.outOfScope ?? [], undefined, nudgeSrc);
|
|
381
|
+
// If still empty after nudge, finding
|
|
382
|
+
if (artifacts.inScope.length === 0 && artifacts.outOfScope.length === 0) {
|
|
383
|
+
agg.addFinding("No scope boundaries defined — downstream requirements may lack focus", "scope");
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// Step 6b: Semantic deduplication
|
|
387
|
+
if (artifacts.inScope.length + artifacts.outOfScope.length >= 2) {
|
|
388
|
+
const dedupResult = await ctx.infer(scopeDedup(artifacts));
|
|
389
|
+
for (const group of dedupResult.duplicateGroups) {
|
|
390
|
+
const validRemoveIds = group.removeIds.filter((id) => artifacts.inScope.some((s) => s.id === id) || artifacts.outOfScope.some((s) => s.id === id));
|
|
391
|
+
if (validRemoveIds.length > 0) {
|
|
392
|
+
agg.removeScopeItems(new Set(validRemoveIds));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// Step 7: Single-pass confirmation
|
|
397
|
+
const { response, approved } = await confirmPhase(ctx, confirmation(artifacts, artifacts.findings), artifacts, "scope", 0);
|
|
398
|
+
if (!approved) {
|
|
399
|
+
const extraction = await ctx.extract({
|
|
400
|
+
id: "scope-revision",
|
|
401
|
+
response,
|
|
402
|
+
artifactsContext: buildFullContext(artifacts),
|
|
403
|
+
schema: ScopeRevisionSchema,
|
|
404
|
+
});
|
|
405
|
+
// Reclassify items first (before adds, so exact-match guard doesn't block re-adds)
|
|
406
|
+
for (const item of extraction.reclassifiedItems ?? []) {
|
|
407
|
+
const existing = artifacts.inScope.find((s) => s.id === item.id)
|
|
408
|
+
?? artifacts.outOfScope.find((s) => s.id === item.id);
|
|
409
|
+
if (!existing)
|
|
410
|
+
continue;
|
|
411
|
+
agg.removeScopeItems(new Set([item.id]));
|
|
412
|
+
if (item.newClassification === "in") {
|
|
413
|
+
agg.addInScopeItems([{ description: existing.description, relatedGoals: existing.relatedGoals }], undefined, existing.source);
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
agg.addOutOfScopeItems([{ description: existing.description, relatedGoals: existing.relatedGoals }], undefined, existing.source);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
const revSrc = ctx.currentSource;
|
|
420
|
+
agg.addInScopeItems(extraction.inScope ?? [], undefined, revSrc);
|
|
421
|
+
agg.addOutOfScopeItems(extraction.outOfScope ?? [], undefined, revSrc);
|
|
422
|
+
const revRemovedIds = new Set(extraction.removedIds ?? []);
|
|
423
|
+
if (revRemovedIds.size > 0) {
|
|
424
|
+
agg.removeScopeItems(revRemovedIds);
|
|
425
|
+
}
|
|
426
|
+
agg.addWaitingRoomItems(extraction.waitingRoomItems ?? []);
|
|
427
|
+
// Post-revision dedup: revision may add items that overlap existing ones
|
|
428
|
+
if (artifacts.inScope.length + artifacts.outOfScope.length >= 2) {
|
|
429
|
+
const dedupResult = await ctx.infer(scopeDedup(artifacts, "post-revision"));
|
|
430
|
+
for (const group of dedupResult.duplicateGroups ?? []) {
|
|
431
|
+
const validRemoveIds = group.removeIds.filter((id) => artifacts.inScope.some((s) => s.id === id) || artifacts.outOfScope.some((s) => s.id === id));
|
|
432
|
+
if (validRemoveIds.length > 0) {
|
|
433
|
+
agg.removeScopeItems(new Set(validRemoveIds));
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
agg.confirmScope();
|
|
439
|
+
}
|
|
440
|
+
//# sourceMappingURL=scope.js.map
|