You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: enforce non-empty FR in check, drop stale SRD.md, note tech cap
Found and fixed by exercising the skill end-to-end against real product
ideas (privacy analytics, meal-planning, password manager) plus hostile
and degenerate briefs:
- check: an SRD with zero functional requirements now fails the hard
structural gate instead of only warning. This matches the gate already
failing when a single FR is missing acceptance criteria, and stops the
SKILL.md "loop until check passes" flow from terminating on an empty
scaffold ("nothing to build" is not a complete, buildable SRD).
- render: remove a stale SRD.md left behind by a prior `--merge` run when
re-rendering without `--merge`, so `check` no longer validates outdated
merged content (e.g. an already-resolved decision callout). Same hygiene
the decisions/ directory already gets.
- research/tech: surface an honest note when candidateTech is capped to
the first 3 technologies, instead of silently dropping the rest.
Adds a regression test per fix and rebuilds the zero-dep bundle.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: scripts/construct.mjs
+12-2Lines changed: 12 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1092,10 +1092,16 @@ ${body || "(no body)"}`,
1092
1092
1093
1093
// src/research/tech.ts
1094
1094
asyncfunctiontechAngle(ctx){
1095
-
consttechs=ctx.brief.candidateTech.slice(0,3);
1095
+
constallTechs=ctx.brief.candidateTech;
1096
+
consttechs=allTechs.slice(0,3);
1096
1097
constideaKw=ctx.query||ctx.brief.idea;
1097
1098
constdocItems=[];
1098
1099
constdocNotes=[];
1100
+
if(allTechs.length>techs.length){
1101
+
docNotes.push(
1102
+
`Only the first ${techs.length} of ${allTechs.length} candidate technologies were grounded; skipped: ${allTechs.slice(techs.length).join(", ")}. Drill them with \`construct tech --out <run> --q "<tech>"\`.`
warnings.push(`${noTrace} functional requirement(s) have no data/interface traceability \u2014 fill DATA-MODEL.md / INTERFACES.md and set FR.entities/interfaces.`);
// Bound the run to the first few technologies; surface the cap honestly rather
12
+
// than silently dropping the rest of the user's candidateTech list.
13
+
constallTechs=ctx.brief.candidateTech;
14
+
consttechs=allTechs.slice(0,3);
12
15
constideaKw=ctx.query||ctx.brief.idea;
13
16
14
17
// --- docs: official documentation of each candidate technology. ----------
15
18
constdocItems: RawItem[]=[];
16
19
constdocNotes: string[]=[];
20
+
if(allTechs.length>techs.length){
21
+
docNotes.push(
22
+
`Only the first ${techs.length} of ${allTechs.length} candidate technologies were grounded; skipped: ${allTechs.slice(techs.length).join(", ")}. Drill them with \`construct tech --out <run> --q "<tech>"\`.`,
0 commit comments