mandrel 1.80.0 → 1.82.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/.agents/README.md +5 -5
- package/.agents/docs/SDLC.md +93 -80
- package/.agents/docs/configuration.md +11 -1
- package/.agents/docs/quality-gates.md +61 -0
- package/.agents/docs/workflows.md +1 -1
- package/.agents/instructions.md +9 -7
- package/.agents/personas/architect.md +8 -5
- package/.agents/personas/engineer-mobile.md +3 -2
- package/.agents/personas/engineer-web.md +3 -2
- package/.agents/personas/engineer.md +6 -5
- package/.agents/personas/product.md +19 -13
- package/.agents/personas/project-manager.md +9 -8
- package/.agents/personas/qa-engineer.md +10 -6
- package/.agents/personas/refactorer.md +3 -2
- package/.agents/personas/technical-writer.md +2 -1
- package/.agents/personas/ux-designer.md +2 -2
- package/.agents/schemas/agentrc.schema.json +10 -0
- package/.agents/scripts/acceptance-spec-reconciler.js +143 -59
- package/.agents/scripts/epic-deliver-prepare.js +0 -31
- package/.agents/scripts/epic-plan-decompose.js +2 -5
- package/.agents/scripts/epic-plan-spec.js +16 -19
- package/.agents/scripts/hierarchy-gate.js +11 -11
- package/.agents/scripts/lib/ITicketingProvider.js +4 -3
- package/.agents/scripts/lib/baselines/env-overrides.js +35 -0
- package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-scanner.js +1 -1
- package/.agents/scripts/lib/cli-args.js +1 -5
- package/.agents/scripts/lib/codebase-snapshot.js +1 -1
- package/.agents/scripts/lib/config/temp-paths.js +1 -4
- package/.agents/scripts/lib/config-settings-schema.js +5 -0
- package/.agents/scripts/lib/epic-body-sections.js +222 -0
- package/.agents/scripts/lib/epic-plan-clarity.js +38 -1
- package/.agents/scripts/lib/epic-plan-ideation.js +15 -3
- package/.agents/scripts/lib/label-constants.js +7 -17
- package/.agents/scripts/lib/label-taxonomy.js +4 -21
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +47 -1
- package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +7 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +1 -1
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +2 -1
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +19 -8
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +23 -22
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +7 -10
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +4 -38
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +8 -9
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +11 -5
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/cli-args.js +26 -5
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +102 -304
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +32 -29
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +19 -20
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +6 -9
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +3 -4
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +20 -27
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +11 -5
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +22 -59
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
- package/.agents/scripts/lib/orchestration/planning-context-budget.js +1 -1
- package/.agents/scripts/lib/orchestration/preflight-cache.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-freshness.js +3 -3
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +122 -1
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +5 -8
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +2 -2
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -2
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +6 -85
- package/.agents/scripts/lib/templates/decomposer-prompts.js +14 -8
- package/.agents/scripts/lifecycle-emit.js +1 -1
- package/.agents/scripts/lint-label-vocabulary.js +2 -3
- package/.agents/scripts/providers/github/mappers.js +0 -3
- package/.agents/scripts/providers/github/tickets.js +7 -18
- package/.agents/scripts/single-story-init.js +0 -1
- package/.agents/scripts/story-init.js +1 -29
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +37 -18
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -18
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +7 -6
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +161 -109
- package/.agents/skills/core/hydrate-context/SKILL.md +10 -5
- package/.agents/skills/core/knowledge-transfer/SKILL.md +3 -2
- package/.agents/skills/core/scope-triage/SKILL.md +2 -1
- package/.agents/skills/skills.index.json +6 -6
- package/.agents/templates/epic-from-idea.md +4 -0
- package/.agents/workflows/audit-to-stories.md +2 -2
- package/.agents/workflows/helpers/code-review.md +11 -9
- package/.agents/workflows/helpers/deliver-epic.md +32 -44
- package/.agents/workflows/helpers/epic-audit.md +11 -8
- package/.agents/workflows/helpers/epic-deliver-story.md +10 -16
- package/.agents/workflows/helpers/epic-plan-decompose.md +17 -12
- package/.agents/workflows/helpers/epic-plan-spec.md +68 -68
- package/.agents/workflows/helpers/parallel-tooling.md +2 -1
- package/.agents/workflows/helpers/plan-epic.md +114 -99
- package/.agents/workflows/helpers/single-story-deliver.md +1 -1
- package/.agents/workflows/helpers/worktree-lifecycle.md +1 -1
- package/.agents/workflows/plan.md +8 -8
- package/.agents/workflows/qa-assist.md +2 -1
- package/docs/CHANGELOG.md +28 -0
- package/package.json +1 -1
- package/.agents/scripts/lib/issue-link-parser.js +0 -74
- package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +0 -116
- package/.agents/scripts/lib/orchestration/planning-state-manager.js +0 -318
- package/.agents/scripts/lib/story-init/hierarchy-tracer.js +0 -57
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description:
|
|
3
|
-
Orchestrates end-to-end Epic planning (
|
|
3
|
+
Orchestrates end-to-end Epic planning (Tech Spec, Acceptance Spec, and
|
|
4
4
|
Work Breakdown) for a GitHub Epic.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ phase helpers — [`helpers/epic-plan-spec.md`](epic-plan-spec.md) and
|
|
|
22
22
|
both phases sequentially with a human confirmation gate between them. The Epic
|
|
23
23
|
ID is the single positional argument.
|
|
24
24
|
|
|
25
|
-
As of v5.6, planning artifacts (
|
|
25
|
+
As of v5.6, planning artifacts (Tech Spec, ticket decomposition) are
|
|
26
26
|
authored **directly by you, the host LLM** — no external Gemini / Anthropic /
|
|
27
27
|
OpenAI API is called. The Node scripts are deterministic GitHub I/O wrappers
|
|
28
28
|
that (a) emit the authoring context you need and (b) validate and persist the
|
|
@@ -207,7 +207,7 @@ new Epic is genuinely distinct).
|
|
|
207
207
|
|
|
208
208
|
2. **Label discipline**: The Issue is opened with **only** the
|
|
209
209
|
`type::epic` label. **Do not** add any `state::*` label at creation
|
|
210
|
-
time — the Epic carries only `type::epic` until
|
|
210
|
+
time — the Epic carries only `type::epic` until spec authoring
|
|
211
211
|
advances it to `agent::review-spec` in Phase 7. The
|
|
212
212
|
`openEpicFromOnePager` helper already enforces this; the workflow
|
|
213
213
|
prose codifies the intent so future label-set tweaks don't silently
|
|
@@ -215,30 +215,36 @@ new Epic is genuinely distinct).
|
|
|
215
215
|
|
|
216
216
|
3. **Continue to Phase 5**: The captured Epic ID becomes the new
|
|
217
217
|
`[Epic_ID]` for the rest of the planning pipeline. Re-Plan Detection
|
|
218
|
-
(Phase 5) will short-circuit because
|
|
219
|
-
so the run flows naturally into Phase 6
|
|
220
|
-
Phase 7.
|
|
218
|
+
(Phase 5) will short-circuit because the fresh Epic body carries no
|
|
219
|
+
Tech Spec sections yet, so the run flows naturally into Phase 6
|
|
220
|
+
(Epic Clarity Gate) and then Phase 7.
|
|
221
221
|
|
|
222
222
|
## Phase 5: Re-Plan Detection
|
|
223
223
|
|
|
224
224
|
Before generating any artifacts, check whether the Epic has already been
|
|
225
225
|
planned.
|
|
226
226
|
|
|
227
|
-
1. **Fetch Epic**: Read the Epic issue body and check for
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
227
|
+
1. **Fetch Epic**: Read the Epic issue body and check for Tech Spec
|
|
228
|
+
content — the managed `<!-- mandrel:tech-spec:start/end -->` section or
|
|
229
|
+
a bare `## Delivery Slicing` heading (`hasTechSpecContent` in
|
|
230
|
+
[`lib/epic-body-sections.js`](../../scripts/lib/epic-body-sections.js)).
|
|
231
|
+
The Tech Spec sections alone are the already-planned signal. Historical
|
|
232
|
+
Epics may still carry a legacy `## Planning Artifacts` section linking
|
|
233
|
+
retired `context::*` tickets — those links are **ignored** (never
|
|
234
|
+
fetched); only the body sections count.
|
|
235
|
+
2. **If already planned**: Inform the user that this Epic already carries
|
|
236
|
+
planning sections. Ask:
|
|
237
|
+
|
|
238
|
+
> "Epic #[ID] already carries a Tech Spec (`## Delivery Slicing`) with
|
|
239
|
+
> YY decomposed tickets. Do you want to **re-plan**? This will
|
|
240
|
+
> **overwrite the Tech Spec and Acceptance Table sections of the Epic
|
|
241
|
+
> body in place** (comment history preserved) and **close-and-recreate**
|
|
242
|
+
> all child Story tickets."
|
|
237
243
|
|
|
238
244
|
3. **If user confirms re-plan**: Pass `--force` to all subsequent script
|
|
239
|
-
invocations. Under `--force`, the
|
|
240
|
-
Acceptance
|
|
241
|
-
|
|
245
|
+
invocations. Under `--force`, the Epic body's managed sections (Tech
|
|
246
|
+
Spec, Acceptance Table) are overwritten in place — the Epic's issue
|
|
247
|
+
number and prior discussion are preserved, and the Epic receives a
|
|
242
248
|
one-line regeneration audit comment. Child Story tickets are still
|
|
243
249
|
closed and recreated, because a re-decomposition can legitimately produce a
|
|
244
250
|
different ticket set.
|
|
@@ -257,16 +263,16 @@ clarity gate does not make.
|
|
|
257
263
|
|
|
258
264
|
The advisory runs **only** when **both** hold:
|
|
259
265
|
|
|
260
|
-
1. **Phase 5 found no planning
|
|
261
|
-
|
|
262
|
-
did **not** enter its re-plan branch).
|
|
266
|
+
1. **Phase 5 found no planning sections** — the Epic body carries no Tech
|
|
267
|
+
Spec content (no managed section, no `## Delivery Slicing` heading —
|
|
268
|
+
i.e. Phase 5 did **not** enter its re-plan branch).
|
|
263
269
|
2. **The Epic has no open Story children** — no open `type::story`
|
|
264
270
|
sub-issues are linked to this Epic.
|
|
265
271
|
|
|
266
272
|
If **either** condition fails, **skip this phase silently** and continue to
|
|
267
273
|
Phase 6. It must **never** fire on the re-plan path: recommending a "downgrade
|
|
268
|
-
to a Story" on an Epic that already carries
|
|
269
|
-
nonsense and would collide with the `--force` re-plan flow. The advisory also
|
|
274
|
+
to a Story" on an Epic that already carries folded Tech Spec sections and a
|
|
275
|
+
ticket tree is nonsense and would collide with the `--force` re-plan flow. The advisory also
|
|
270
276
|
does not fire on the ideation path — that path already ran the Phase 1.5 scope
|
|
271
277
|
triage on the one-pager before the Epic existed.
|
|
272
278
|
|
|
@@ -352,11 +358,13 @@ via [`/single-story-deliver`](single-story-deliver.md) or
|
|
|
352
358
|
|
|
353
359
|
Runs on every existing-Epic invocation, after Phase 5 (Re-Plan
|
|
354
360
|
Detection) and the Phase 5.5 story-sized advisory, and before Phase 7
|
|
355
|
-
(
|
|
356
|
-
against the five canonical
|
|
361
|
+
(Tech Spec & Acceptance Spec). The gate scores the Epic body
|
|
362
|
+
against the five clarity-scored canonical
|
|
357
363
|
sections from
|
|
358
364
|
[`.agents/templates/epic-from-idea.md`](../../templates/epic-from-idea.md)
|
|
359
|
-
(Context, Goal, Non-Goals, Scope, Acceptance Criteria
|
|
365
|
+
(Context, Goal, Non-Goals, Scope, Acceptance Criteria — the template
|
|
366
|
+
also carries a `## User Stories` section, which the clarity rubric does
|
|
367
|
+
not score) and either
|
|
360
368
|
skips fast (when the Epic body is already clear) or drops into a
|
|
361
369
|
refinement loop seeded from the current Epic body. The scorer also
|
|
362
370
|
accepts common heading variants for back-compat (e.g. `## Problem`,
|
|
@@ -406,8 +414,8 @@ for the scoring logic.
|
|
|
406
414
|
5. **HITL stop — confirm the diff**: Display the diff between the
|
|
407
415
|
current Epic body and the sharpened body and **STOP**. Operator
|
|
408
416
|
approves, edits, or aborts. Flag the blast radius in the
|
|
409
|
-
confirmation prompt: an approved body change feeds **
|
|
410
|
-
downstream artifacts (
|
|
417
|
+
confirmation prompt: an approved body change feeds **two**
|
|
418
|
+
downstream artifacts (Tech Spec, Acceptance Spec) — treat
|
|
411
419
|
this gate as a one-shot rewrite, not an iterative draft. The
|
|
412
420
|
Constraint ("Do not modify existing issues without explicit
|
|
413
421
|
permission") is honored — no `gh issue edit` call until the
|
|
@@ -443,7 +451,7 @@ for the scoring logic.
|
|
|
443
451
|
remediation hint to the operator. Do not loop — one refinement
|
|
444
452
|
pass per invocation, matching the `--force` re-plan pattern.
|
|
445
453
|
|
|
446
|
-
## Phase 7: Epic Planning (
|
|
454
|
+
## Phase 7: Epic Planning (Tech Spec & Acceptance Spec)
|
|
447
455
|
|
|
448
456
|
> **Epic-lease preflight (workflow guard).** Before any Phase 7 mutation,
|
|
449
457
|
> `epic-plan-spec.js` acquires the Epic-lease via the assignee-as-lease
|
|
@@ -464,28 +472,36 @@ for the scoring logic.
|
|
|
464
472
|
|
|
465
473
|
<!-- separator: adjacent blockquotes -->
|
|
466
474
|
|
|
467
|
-
> **Idempotent
|
|
468
|
-
> the Epic
|
|
469
|
-
>
|
|
470
|
-
>
|
|
471
|
-
>
|
|
475
|
+
> **Idempotent managed sections.** The persist half is section-scoped and
|
|
476
|
+
> keyed on the Epic body: a re-run that finds the requested sections already
|
|
477
|
+
> present (`<!-- mandrel:tech-spec:start/end -->` /
|
|
478
|
+
> `<!-- mandrel:acceptance-table:start/end -->`) short-circuits as
|
|
479
|
+
> `already-planned` instead of duplicating content. Pass `--force` to
|
|
480
|
+
> overwrite the managed sections in place (same Epic issue, refreshed
|
|
481
|
+
> section bodies).
|
|
472
482
|
|
|
473
483
|
<!-- separator: adjacent blockquotes -->
|
|
474
484
|
|
|
475
|
-
> **
|
|
476
|
-
>
|
|
477
|
-
>
|
|
478
|
-
>
|
|
479
|
-
>
|
|
480
|
-
>
|
|
481
|
-
>
|
|
482
|
-
>
|
|
483
|
-
>
|
|
484
|
-
> `
|
|
485
|
-
>
|
|
486
|
-
>
|
|
487
|
-
>
|
|
488
|
-
>
|
|
485
|
+
> **One planning document.** A `/plan` Epic run creates exactly **one**
|
|
486
|
+
> issue — the Epic. The planning artifacts land as marker-delimited
|
|
487
|
+
> managed sections of the Epic body: the Tech Spec (opening with
|
|
488
|
+
> `## Delivery Slicing`) inside `<!-- mandrel:tech-spec:start/end -->`,
|
|
489
|
+
> and the Acceptance Spec's AC-ID table (headed `## Acceptance Table`)
|
|
490
|
+
> inside `<!-- mandrel:acceptance-table:start/end -->`. The PRD artifact
|
|
491
|
+
> class was retired (Story #4314) — its one novel section, **User
|
|
492
|
+
> Stories**, lives inline in the Epic body as a `## User Stories`
|
|
493
|
+
> section — and Story #4324 retired the `context::tech-spec` /
|
|
494
|
+
> `context::acceptance-spec` ticket classes the same way. The
|
|
495
|
+
> `## Acceptance Table` section captures the stable-ID acceptance
|
|
496
|
+
> criteria table (`| AC ID | Outcome | Feature File | Scenario |
|
|
497
|
+
> Disposition |`) that drives close-time reconciliation during
|
|
498
|
+
> `/deliver` Phase 6. Operators may opt out for refactor-only or
|
|
499
|
+
> docs-only Epics by applying the `acceptance::n-a` label to the Epic
|
|
500
|
+
> ticket — when present, the `epic-plan-spec-author` skill skips the
|
|
501
|
+
> Acceptance Table output and the runtime gates (start gate, finalize
|
|
502
|
+
> reconciler) honour the waiver — the section need not be authored when
|
|
503
|
+
> the waiver is set. See [SDLC § Acceptance Table — the second folded
|
|
504
|
+
> planning section](../../docs/SDLC.md#acceptance-table--the-second-folded-planning-section)
|
|
489
505
|
> for the full lifecycle.
|
|
490
506
|
|
|
491
507
|
<!-- separator: adjacent blockquotes -->
|
|
@@ -495,11 +511,11 @@ for the scoring logic.
|
|
|
495
511
|
> workflow lives under the per-Epic tree
|
|
496
512
|
> (`temp/epic-[Epic_ID]/<artifact>`) — e.g.
|
|
497
513
|
> `temp/epic-[Epic_ID]/planner-context.json`,
|
|
498
|
-
> `temp/epic-[Epic_ID]/
|
|
514
|
+
> `temp/epic-[Epic_ID]/techspec.md`,
|
|
499
515
|
> `temp/epic-[Epic_ID]/decomposer-context.json`,
|
|
500
516
|
> `temp/epic-[Epic_ID]/tickets.json`. The directory namespace is the
|
|
501
517
|
> isolation boundary; basenames inside it are stable. Do **not** reuse
|
|
502
|
-
> bare flat names like `temp/
|
|
518
|
+
> bare flat names like `temp/techspec.md` or the legacy
|
|
503
519
|
> `temp/<artifact>-epic-<id>.<ext>` shape — both have been retired.
|
|
504
520
|
>
|
|
505
521
|
> **Durability.** The per-Epic tree is durable across runs: only the
|
|
@@ -523,18 +539,18 @@ for the scoring logic.
|
|
|
523
539
|
via the `Read` tool (resolve `<agentRoot>` from
|
|
524
540
|
`project.paths.agentRoot` — default `.agents`) and execute its
|
|
525
541
|
procedure with `[Epic_ID]` as input. The skill reads
|
|
526
|
-
`temp/epic-[Epic_ID]/planner-context.json`, authors the
|
|
542
|
+
`temp/epic-[Epic_ID]/planner-context.json`, authors the Tech
|
|
527
543
|
Spec, **risk verdict**, and **Acceptance Spec** against the embedded
|
|
528
|
-
system prompts, and writes them to
|
|
544
|
+
system prompts, and writes them to
|
|
529
545
|
`temp/epic-[Epic_ID]/techspec.md`,
|
|
530
546
|
`temp/epic-[Epic_ID]/risk-verdict.json`, and
|
|
531
547
|
`temp/epic-[Epic_ID]/acceptance-spec.md`. The skill is the
|
|
532
|
-
authoritative authoring step — do **not** inline the
|
|
548
|
+
authoritative authoring step — do **not** inline the Tech
|
|
533
549
|
Spec / risk-verdict / Acceptance Spec drafting in the workflow
|
|
534
550
|
body. The skill front-matter declares
|
|
535
551
|
`allowed_tools: [Read, Write, Bash]`; it never calls GitHub.
|
|
536
552
|
|
|
537
|
-
The skill body carries the authoritative
|
|
553
|
+
The skill body carries the authoritative Tech Spec and
|
|
538
554
|
Acceptance Spec system prompts. The `systemPrompts` field on the
|
|
539
555
|
`--emit-context` envelope is a backstop for legacy callers; the
|
|
540
556
|
skill body wins when the two surfaces diverge.
|
|
@@ -546,59 +562,55 @@ for the scoring logic.
|
|
|
546
562
|
(`deriveRiskEnvelope`), records a `risk-verdict` structured comment
|
|
547
563
|
on the Epic, flips the Epic to `agent::review-spec`, and writes the
|
|
548
564
|
`epic-plan-state` checkpoint (including the `riskVerdict` field).
|
|
549
|
-
The `--acceptance-
|
|
550
|
-
|
|
551
|
-
persist half fails loudly if any file is missing or
|
|
552
|
-
`--acceptance-
|
|
553
|
-
waiver label.
|
|
565
|
+
The `--acceptance-table` flag persists the AC-ID table as the Epic
|
|
566
|
+
body's `## Acceptance Table` managed section alongside the Tech Spec
|
|
567
|
+
sections; the persist half fails loudly if any file is missing or
|
|
568
|
+
empty. Omit `--acceptance-table` only when the Epic carries the
|
|
569
|
+
`acceptance::n-a` waiver label.
|
|
554
570
|
|
|
555
571
|
```bash
|
|
556
|
-
# Normal planning (
|
|
572
|
+
# Normal planning (both managed sections)
|
|
557
573
|
node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
|
|
558
|
-
--
|
|
559
|
-
--techspec temp/epic-[Epic_ID]/techspec.md \
|
|
574
|
+
--tech-spec temp/epic-[Epic_ID]/techspec.md \
|
|
560
575
|
--risk-verdict temp/epic-[Epic_ID]/risk-verdict.json \
|
|
561
|
-
--acceptance-
|
|
576
|
+
--acceptance-table temp/epic-[Epic_ID]/acceptance-spec.md
|
|
562
577
|
|
|
563
|
-
# Re-planning (--force overwrites the
|
|
564
|
-
#
|
|
565
|
-
#
|
|
566
|
-
#
|
|
578
|
+
# Re-planning (--force overwrites the Epic body's managed sections
|
|
579
|
+
# IN PLACE — same Epic issue, refreshed section bodies, one
|
|
580
|
+
# regeneration audit comment on the Epic. Child Story tickets are
|
|
581
|
+
# still close-and-recreate at decomposition time.)
|
|
567
582
|
node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
|
|
568
|
-
--
|
|
569
|
-
--techspec temp/epic-[Epic_ID]/techspec.md \
|
|
583
|
+
--tech-spec temp/epic-[Epic_ID]/techspec.md \
|
|
570
584
|
--risk-verdict temp/epic-[Epic_ID]/risk-verdict.json \
|
|
571
|
-
--acceptance-
|
|
585
|
+
--acceptance-table temp/epic-[Epic_ID]/acceptance-spec.md --force
|
|
572
586
|
|
|
573
|
-
# Waived (acceptance::n-a label on Epic — no
|
|
587
|
+
# Waived (acceptance::n-a label on Epic — no acceptance table authored)
|
|
574
588
|
node .agents/scripts/epic-plan-spec.js --epic [Epic_ID] \
|
|
575
|
-
--
|
|
576
|
-
--techspec temp/epic-[Epic_ID]/techspec.md \
|
|
589
|
+
--tech-spec temp/epic-[Epic_ID]/techspec.md \
|
|
577
590
|
--risk-verdict temp/epic-[Epic_ID]/risk-verdict.json
|
|
578
591
|
```
|
|
579
592
|
|
|
580
593
|
4. **Verification and review routing**:
|
|
581
|
-
- Verify that the
|
|
582
|
-
Acceptance
|
|
583
|
-
the Epic.
|
|
594
|
+
- Verify that the Technical Specification sections and (when not
|
|
595
|
+
waived) the `## Acceptance Table` section have landed as managed
|
|
596
|
+
sections of the Epic body.
|
|
584
597
|
- Read `planningRisk` from the persist stdout JSON (or the
|
|
585
598
|
`epic-plan-state` checkpoint). Branch on
|
|
586
599
|
`planningRisk.requiresReview` unless the operator passed
|
|
587
600
|
`--force-review`:
|
|
588
601
|
- **High risk** (`requiresReview === true`) or **operator override**
|
|
589
602
|
(`--force-review`) — **gate #2**: **STOP**. Ask the USER to review the
|
|
590
|
-
|
|
591
|
-
the user's verbal OK in this
|
|
592
|
-
|
|
593
|
-
|
|
603
|
+
updated Epic body (its Tech Spec sections and `## Acceptance
|
|
604
|
+
Table`) on GitHub. Approval is the user's verbal OK in this
|
|
605
|
+
session — the sections live on the Epic itself, so there is
|
|
606
|
+
nothing to close at delivery time. Do NOT proceed
|
|
594
607
|
to decomposition until the user confirms the plan is accurate.
|
|
595
608
|
|
|
596
609
|
> **`--yes` (headless) auto-proceed.** When `/plan` was invoked with
|
|
597
610
|
> `--yes`, this review gate does **not** STOP, even when
|
|
598
611
|
> `requiresReview === true` or `--force-review` was also passed: the
|
|
599
612
|
> review resolves as **approved** and the run **continues directly to
|
|
600
|
-
> Phase 8**, exactly as the low-risk auto-proceed branch below
|
|
601
|
-
> three context tickets stay **open** through delivery as usual; only
|
|
613
|
+
> Phase 8**, exactly as the low-risk auto-proceed branch below; only
|
|
602
614
|
> the operator *wait* is suppressed. This is `/plan`'s **gate #2** —
|
|
603
615
|
> the second and last HITL STOP `--yes` suppresses. `--yes` does
|
|
604
616
|
> **not** alter risk routing or the review criteria themselves; it
|
|
@@ -612,8 +624,8 @@ for the scoring logic.
|
|
|
612
624
|
decision is recorded in the `epic-plan-state` checkpoint. (`--yes` is
|
|
613
625
|
a no-op on this branch — there is no STOP to suppress.)
|
|
614
626
|
|
|
615
|
-
5. **Tech Spec freshness check (advisory)**: After the Tech Spec
|
|
616
|
-
|
|
627
|
+
5. **Tech Spec freshness check (advisory)**: After the Tech Spec sections
|
|
628
|
+
are persisted, `epic-plan-spec.js` runs
|
|
617
629
|
[`validateSpecFreshness`](../../scripts/lib/orchestration/spec-freshness.js)
|
|
618
630
|
against the authored Tech Spec body, probing every cited path-shape
|
|
619
631
|
reference (backticked paths, `// header` lines in code blocks, and
|
|
@@ -628,14 +640,14 @@ for the scoring logic.
|
|
|
628
640
|
reference the Architect inherited from drift-stale docs.
|
|
629
641
|
|
|
630
642
|
When ≥1 stale reference is detected, a `spec-freshness` structured
|
|
631
|
-
comment is upserted on the
|
|
643
|
+
comment is upserted on the **Epic** listing each citation
|
|
632
644
|
with its line number. The full report is also written to
|
|
633
645
|
`<tempRoot>/epic-<id>-spec-freshness.json` for downstream tooling.
|
|
634
646
|
The check is **advisory and non-blocking** — Phase 7 completes even
|
|
635
647
|
when stale references are present, so the operator retains final
|
|
636
648
|
judgment on edge cases. If the run summary shows
|
|
637
|
-
`⚠️ Spec freshness: N stale / M ambiguous`, review the
|
|
638
|
-
|
|
649
|
+
`⚠️ Spec freshness: N stale / M ambiguous`, review the Epic's
|
|
650
|
+
`spec-freshness` comment and correct the cited spec sections
|
|
639
651
|
before approving the plan for Phase 8.
|
|
640
652
|
|
|
641
653
|
6. **BDD scenario cross-reference (advisory)**: When the project has
|
|
@@ -716,8 +728,8 @@ node .agents/scripts/epic-plan-spec-validate.js \
|
|
|
716
728
|
|
|
717
729
|
**STOP** on a non-zero exit: do not advance to Phase 8. Re-author the Tech
|
|
718
730
|
Spec (re-run the Phase 7 spec-author step) or add a `## Delivery Slicing`
|
|
719
|
-
section to the
|
|
720
|
-
exits 0.
|
|
731
|
+
section by hand (to the temp spec file and the Epic body's tech-spec
|
|
732
|
+
section), then re-run the gate until it exits 0.
|
|
721
733
|
|
|
722
734
|
## Phase 8: Work Breakdown Decomposition
|
|
723
735
|
|
|
@@ -735,7 +747,7 @@ node .agents/scripts/epic-plan-spec-validate.js \
|
|
|
735
747
|
> **Hierarchy.** The decomposer emits a flat Story backlog under the Epic.
|
|
736
748
|
> Acceptance criteria and verification steps are inlined on each Story
|
|
737
749
|
> body (`acceptance[]` / `verify[]` fields) and resolved against the
|
|
738
|
-
> Acceptance
|
|
750
|
+
> Epic body's `## Acceptance Table` section at close time. See
|
|
739
751
|
> [`.agents/instructions.md` § 5.D](../../instructions.md) for the full
|
|
740
752
|
> contract.
|
|
741
753
|
|
|
@@ -750,8 +762,9 @@ node .agents/scripts/epic-plan-spec-validate.js \
|
|
|
750
762
|
via the `Read` tool (resolve `<agentRoot>` from
|
|
751
763
|
`project.paths.agentRoot` — default `.agents`) and execute its
|
|
752
764
|
procedure with `[Epic_ID]` as input. The skill reads
|
|
753
|
-
`temp/epic-[Epic_ID]/decomposer-context.json` (
|
|
754
|
-
|
|
765
|
+
`temp/epic-[Epic_ID]/decomposer-context.json` (`epicBody` — carrying
|
|
766
|
+
the folded Tech Spec sections and Acceptance Table — risk
|
|
767
|
+
heuristics, `maxTickets` cap, `contextMode`), applies its
|
|
755
768
|
embedded decomposer system prompt + ticket schema, and writes the
|
|
756
769
|
ticket array to `temp/epic-[Epic_ID]/tickets.json`. Do **not** inline
|
|
757
770
|
the JSON authoring in the workflow body.
|
|
@@ -781,8 +794,9 @@ node .agents/scripts/epic-plan-spec-validate.js \
|
|
|
781
794
|
[`epic-plan-consolidate`](../../skills/core/epic-plan-consolidate/SKILL.md)
|
|
782
795
|
skill with `[Epic_ID]` as input. This is a **separate critic pass with
|
|
783
796
|
fresh context** (not a self-review appended to the author skill): it reads
|
|
784
|
-
the draft array plus the
|
|
785
|
-
|
|
797
|
+
the draft array plus the Epic body (which carries the Tech Spec
|
|
798
|
+
sections), reconciles the draft against
|
|
799
|
+
the Tech Spec `## Delivery Slicing` target, and emits a **consolidated**
|
|
786
800
|
`tickets.json` plus a human-readable
|
|
787
801
|
`temp/epic-[Epic_ID]/consolidation-report.md`. Its operations are
|
|
788
802
|
scope-preserving only — **merge sibling Stories and rewire
|
|
@@ -838,8 +852,9 @@ node .agents/scripts/epic-plan-spec-validate.js \
|
|
|
838
852
|
reachability critic (8.4) and **before** the persist call below, activate the
|
|
839
853
|
[`epic-plan-premortem`](../../skills/core/epic-plan-premortem/SKILL.md)
|
|
840
854
|
skill with `[Epic_ID]` as input. This is a **fresh-context critic** sibling
|
|
841
|
-
to `epic-plan-consolidate`: it reads the drafted `tickets.json`, the
|
|
842
|
-
Tech Spec, **and the actual cited code
|
|
855
|
+
to `epic-plan-consolidate`: it reads the drafted `tickets.json`, the Epic
|
|
856
|
+
body (with its folded Tech Spec sections), **and the actual cited code
|
|
857
|
+
surfaces** (the files each Story's
|
|
843
858
|
`changes[]` / `references[]` name), then emits predicted-rework findings —
|
|
844
859
|
unverifiable acceptance criteria, over- or under-specified Stories, and
|
|
845
860
|
semantically-wrong assumptions the structural file-assumption gate (step 7)
|
|
@@ -1032,8 +1047,8 @@ forcing the walkthrough.
|
|
|
1032
1047
|
|
|
1033
1048
|
Activate the
|
|
1034
1049
|
[`core/knowledge-transfer`](../../skills/core/knowledge-transfer/SKILL.md) skill
|
|
1035
|
-
with the **plan** as the subject — the Epic body
|
|
1036
|
-
|
|
1050
|
+
with the **plan** as the subject — the Epic body (whose managed sections
|
|
1051
|
+
carry the Tech Spec), the decomposition (Stories with inline
|
|
1037
1052
|
`acceptance[]` / `verify[]`), and the Phase 9 wave roadmap. The skill owns the
|
|
1038
1053
|
method (restate-first, the why-ladder, mastery gates, depth levels, optional
|
|
1039
1054
|
quizzing, the persistent `temp/comprehension-*.md` checklist).
|
|
@@ -13,7 +13,7 @@ description:
|
|
|
13
13
|
[`/deliver`](deliver-stories.md). Use it for a Story that is **not**
|
|
14
14
|
attached to an Epic — refactors carved out of closed Epics, framework
|
|
15
15
|
maintenance, or any work small enough that the Epic-Centric ceremony
|
|
16
|
-
(
|
|
16
|
+
(sectioned Epic body + decomposition + dispatch manifest + cascade) would be
|
|
17
17
|
overhead rather than help.
|
|
18
18
|
|
|
19
19
|
```text
|
|
@@ -353,7 +353,7 @@ Human reviewers should **keep using the main checkout** — not a worktree:
|
|
|
353
353
|
the main checkout, not in any per-story worktree.
|
|
354
354
|
- Opening a worktree in an IDE can mislead: the working directory looks like the
|
|
355
355
|
main repo but carries a different HEAD. The main checkout is the canonical
|
|
356
|
-
place to read
|
|
356
|
+
place to read Epic planning bodies and run the `helpers/code-review.md`
|
|
357
357
|
procedure.
|
|
358
358
|
- `git worktree list --porcelain` on the main checkout enumerates any still
|
|
359
359
|
in-flight story worktrees if you need to inspect one — prefer read-only
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
description:
|
|
3
3
|
Unified planning entry point. Routes a seed idea (via scope triage) or an
|
|
4
4
|
existing Epic ID to the right planning path — the full Epic pipeline
|
|
5
|
-
(
|
|
6
|
-
authoring path — and absorbs every planning flag.
|
|
5
|
+
(sectioned Epic body: Tech Spec + Acceptance Table, then decomposition)
|
|
6
|
+
or the standalone-Story authoring path — and absorbs every planning flag.
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# /plan [Epic ID] | --idea "<seed>" | --from-notes <path>
|
|
@@ -14,8 +14,8 @@ Router. `/plan` owns argument parsing and path selection only — all phase
|
|
|
14
14
|
content lives in the two path helpers:
|
|
15
15
|
|
|
16
16
|
- [`helpers/plan-epic.md`](helpers/plan-epic.md) — the full Epic planning
|
|
17
|
-
pipeline (
|
|
18
|
-
handoff).
|
|
17
|
+
pipeline (Tech Spec + Acceptance Table folded into the Epic body, work
|
|
18
|
+
breakdown, healthcheck, handoff).
|
|
19
19
|
- [`helpers/plan-story.md`](helpers/plan-story.md) — the standalone-Story
|
|
20
20
|
authoring path (context envelope → host-LLM draft → HITL → issue create).
|
|
21
21
|
|
|
@@ -93,10 +93,10 @@ without waiting for operator input:
|
|
|
93
93
|
forces a review (`planningRisk.requiresReview === true`, or the operator
|
|
94
94
|
also passed `--force-review`),
|
|
95
95
|
[`helpers/plan-epic.md`](helpers/plan-epic.md) Phase 7 STOPs for operator
|
|
96
|
-
approval of the
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
auto-proceed path.
|
|
96
|
+
approval of the updated Epic body (its Tech Spec sections and
|
|
97
|
+
`## Acceptance Table`) before decomposition.
|
|
98
|
+
Under `--yes` this review auto-proceeds straight to Phase 8 exactly as
|
|
99
|
+
on the low-risk auto-proceed path.
|
|
100
100
|
|
|
101
101
|
**Composition.** `--yes` is orthogonal to the other planning flags and
|
|
102
102
|
composes cleanly:
|
|
@@ -226,7 +226,8 @@ every decision to the shared core helpers; never re-derive them in prose.
|
|
|
226
226
|
|
|
227
227
|
3. **Hydrate the QA context** to locate code precisely, via
|
|
228
228
|
[`qa-context-hydrator.js`](../scripts/lib/qa/qa-context-hydrator.js) — it
|
|
229
|
-
resolves the Epic
|
|
229
|
+
resolves the Epic (whose body carries the planning sections), the
|
|
230
|
+
feature-file set, the surface
|
|
230
231
|
map, and recent git log:
|
|
231
232
|
|
|
232
233
|
```js
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.82.0](https://github.com/dsj1984/mandrel/compare/mandrel-v1.81.0...mandrel-v1.82.0) (2026-07-04)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
* **decomposer:** add soft envelope-floor guidance to sizing prompt (refs [#4313](https://github.com/dsj1984/mandrel/issues/4313)) ([#4321](https://github.com/dsj1984/mandrel/issues/4321)) ([e95c9e4](https://github.com/dsj1984/mandrel/commit/e95c9e4b39b7549f2f83ee104e19a9824f9bab00))
|
|
11
|
+
* **epic-plan-spec:** key Acceptance Spec Outcomes to Epic AC bullets (refs [#4315](https://github.com/dsj1984/mandrel/issues/4315)) ([#4323](https://github.com/dsj1984/mandrel/issues/4323)) ([4d4103c](https://github.com/dsj1984/mandrel/commit/4d4103c79500e5704b1fa79e70f6efb985e06994))
|
|
12
|
+
* **plan:** recalibrate Delivery Slicing to a ceiling, not a target (refs [#4311](https://github.com/dsj1984/mandrel/issues/4311)) ([#4317](https://github.com/dsj1984/mandrel/issues/4317)) ([b37596b](https://github.com/dsj1984/mandrel/commit/b37596b8f739da52f568cb025b84ada84ce90355))
|
|
13
|
+
* **ticket-validator-sizing:** add merge-candidate under-size soft finding (refs [#4312](https://github.com/dsj1984/mandrel/issues/4312)) ([#4319](https://github.com/dsj1984/mandrel/issues/4319)) ([2b84e49](https://github.com/dsj1984/mandrel/commit/2b84e49022f9745549cb02a1237d24ab194af92c))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
* retire the context-ticket classes: fold Tech Spec and Acceptance Spec into the sectioned Epic body ([#4324](https://github.com/dsj1984/mandrel/issues/4324)) ([#4325](https://github.com/dsj1984/mandrel/issues/4325)) ([f8cfec7](https://github.com/dsj1984/mandrel/commit/f8cfec79f1aa59fc86c51e9ced6dda2bd06f2cb3))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
* **epic-plan-spec:** open Tech Spec with Delivery Slicing, drop Epic-context restatement (refs [#4316](https://github.com/dsj1984/mandrel/issues/4316)) ([#4320](https://github.com/dsj1984/mandrel/issues/4320)) ([b20d10a](https://github.com/dsj1984/mandrel/commit/b20d10a2e61b1940ebffe0bc595d3b6bfedec604))
|
|
24
|
+
* fold the PRD into the Epic body and retire the context::prd artifact class ([#4314](https://github.com/dsj1984/mandrel/issues/4314)) ([#4322](https://github.com/dsj1984/mandrel/issues/4322)) ([9c9bc7d](https://github.com/dsj1984/mandrel/commit/9c9bc7deb19ce04de1aebcaefb2eeebf949f61d5))
|
|
25
|
+
|
|
26
|
+
## [1.81.0](https://github.com/dsj1984/mandrel/compare/mandrel-v1.80.0...mandrel-v1.81.0) (2026-07-01)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
* **baselines:** add one-shot BUNDLE_SIZE_REFRESH acknowledge for the bundle-size ratchet ([#4309](https://github.com/dsj1984/mandrel/issues/4309)) ([bc466b9](https://github.com/dsj1984/mandrel/commit/bc466b98f6c7521c3a24bbb4d93ee5169c163839))
|
|
32
|
+
|
|
5
33
|
## [1.80.0](https://github.com/dsj1984/mandrel/compare/mandrel-v1.79.0...mandrel-v1.80.0) (2026-07-01)
|
|
6
34
|
|
|
7
35
|
|
package/package.json
CHANGED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Parse PRD / Tech-Spec / Acceptance-Spec references from a GitHub epic body.
|
|
3
|
-
* Extracted from providers/github.js so link-parsing is not mixed with HTTP
|
|
4
|
-
* transport.
|
|
5
|
-
*
|
|
6
|
-
* Expected markdown conventions in an epic body (case-insensitive, tolerant
|
|
7
|
-
* of the `- [ ]` / `- [x]` checkbox prefix that `epic-plan-spec.js` emits in
|
|
8
|
-
* the `## Planning Artifacts` section):
|
|
9
|
-
* - "PRD: #42" or "prd #42"
|
|
10
|
-
* - "Tech Spec: #43" / "Technical Spec: #43" / "tech-spec: #43"
|
|
11
|
-
* - "Acceptance Spec: #44" / "acceptance-spec: #44" / "accept spec: #44"
|
|
12
|
-
*
|
|
13
|
-
* Story #2091 added the `acceptanceSpec` slot so the
|
|
14
|
-
* `closePlanningArtifacts()` cascade in `epic-deliver-finalize.js` can close
|
|
15
|
-
* the `context::acceptance-spec` ticket Epic #2001 introduces alongside the
|
|
16
|
-
* existing PRD / Tech-Spec pair.
|
|
17
|
-
*
|
|
18
|
-
* Story #3848: regexes are now scoped to the `## Planning Artifacts` section
|
|
19
|
-
* only. Prose elsewhere in the body (e.g. bundled-follow-up notes that
|
|
20
|
-
* mention a foreign Epic's spec ticket by number) can no longer collide with
|
|
21
|
-
* the machine-managed list items.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
const PRD_RE = /(?:PRD|prd)[:\s]+#(\d+)/;
|
|
25
|
-
const TECH_SPEC_RE = /(?:Tech Spec|tech.?spec|technical.?spec)[:\s]+#(\d+)/i;
|
|
26
|
-
const ACCEPTANCE_SPEC_RE =
|
|
27
|
-
/(?:Acceptance Spec|acceptance.?spec|accept.?spec)[:\s]+#(\d+)/i;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Extract the `## Planning Artifacts` section text from an Epic body.
|
|
31
|
-
* Returns the slice from just after the heading line to the next `##`-level
|
|
32
|
-
* heading (exclusive), or to end-of-string when no following heading is
|
|
33
|
-
* present. Returns an empty string when the section is absent.
|
|
34
|
-
*
|
|
35
|
-
* @param {string} body
|
|
36
|
-
* @returns {string}
|
|
37
|
-
*/
|
|
38
|
-
function extractPlanningArtifactsSection(body) {
|
|
39
|
-
// Step 1: locate the heading.
|
|
40
|
-
const startMatch = body.match(/^##\s+Planning Artifacts[^\n]*/m);
|
|
41
|
-
if (!startMatch) return '';
|
|
42
|
-
// Step 2: slice from just after the heading to the next ## heading (or EOB).
|
|
43
|
-
const afterHeading = body.slice(startMatch.index + startMatch[0].length);
|
|
44
|
-
const nextHeadingMatch = afterHeading.match(/\n##\s/);
|
|
45
|
-
return nextHeadingMatch
|
|
46
|
-
? afterHeading.slice(0, nextHeadingMatch.index)
|
|
47
|
-
: afterHeading;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @param {string|null|undefined} body
|
|
52
|
-
* @returns {{ prd: number|null, techSpec: number|null, acceptanceSpec: number|null }}
|
|
53
|
-
*/
|
|
54
|
-
export function parseLinkedIssues(body) {
|
|
55
|
-
const result = { prd: null, techSpec: null, acceptanceSpec: null };
|
|
56
|
-
if (typeof body !== 'string' || body.length === 0) return result;
|
|
57
|
-
|
|
58
|
-
// Scope all regex matching to the canonical Planning Artifacts section so
|
|
59
|
-
// prose references elsewhere in the body do not shadow the machine-managed
|
|
60
|
-
// list items. When the section is absent every slot stays null — the caller
|
|
61
|
-
// (plan-epic.js) treats null as "not yet linked" and creates fresh tickets.
|
|
62
|
-
const section = extractPlanningArtifactsSection(body);
|
|
63
|
-
if (section.length === 0) return result;
|
|
64
|
-
|
|
65
|
-
const prdMatch = section.match(PRD_RE);
|
|
66
|
-
if (prdMatch) result.prd = Number.parseInt(prdMatch[1], 10);
|
|
67
|
-
const specMatch = section.match(TECH_SPEC_RE);
|
|
68
|
-
if (specMatch) result.techSpec = Number.parseInt(specMatch[1], 10);
|
|
69
|
-
const acceptanceMatch = section.match(ACCEPTANCE_SPEC_RE);
|
|
70
|
-
if (acceptanceMatch) {
|
|
71
|
-
result.acceptanceSpec = Number.parseInt(acceptanceMatch[1], 10);
|
|
72
|
-
}
|
|
73
|
-
return result;
|
|
74
|
-
}
|