@fledge/workflow 0.6.3 → 0.7.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.
@@ -554,7 +554,6 @@ const string$1 = (params) => {
554
554
  const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
555
555
  return new RegExp(`^${regex}$`);
556
556
  };
557
- const boolean$1 = /^(?:true|false)$/i;
558
557
  const lowercase = /^[^A-Z]*$/;
559
558
  const uppercase = /^[^a-z]*$/;
560
559
  //#endregion
@@ -1166,24 +1165,6 @@ const $ZodJWT = /* @__PURE__ */ $constructor("$ZodJWT", (inst, def) => {
1166
1165
  });
1167
1166
  };
1168
1167
  });
1169
- const $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
1170
- $ZodType.init(inst, def);
1171
- inst._zod.pattern = boolean$1;
1172
- inst._zod.parse = (payload, _ctx) => {
1173
- if (def.coerce) try {
1174
- payload.value = Boolean(payload.value);
1175
- } catch (_) {}
1176
- const input = payload.value;
1177
- if (typeof input === "boolean") return payload;
1178
- payload.issues.push({
1179
- expected: "boolean",
1180
- code: "invalid_type",
1181
- input,
1182
- inst
1183
- });
1184
- return payload;
1185
- };
1186
- });
1187
1168
  const $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
1188
1169
  $ZodType.init(inst, def);
1189
1170
  inst._zod.parse = (payload) => payload;
@@ -2146,13 +2127,6 @@ function _isoDuration(Class, params) {
2146
2127
  });
2147
2128
  }
2148
2129
  /* @__NO_SIDE_EFFECTS__ */
2149
- function _boolean(Class, params) {
2150
- return new Class({
2151
- type: "boolean",
2152
- ...normalizeParams(params)
2153
- });
2154
- }
2155
- /* @__NO_SIDE_EFFECTS__ */
2156
2130
  function _unknown(Class) {
2157
2131
  return new Class({ type: "unknown" });
2158
2132
  }
@@ -3336,14 +3310,6 @@ const ZodJWT = /* @__PURE__ */ $constructor("ZodJWT", (inst, def) => {
3336
3310
  $ZodJWT.init(inst, def);
3337
3311
  ZodStringFormat.init(inst, def);
3338
3312
  });
3339
- const ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
3340
- $ZodBoolean.init(inst, def);
3341
- ZodType.init(inst, def);
3342
- inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params);
3343
- });
3344
- function boolean(params) {
3345
- return /* @__PURE__ */ _boolean(ZodBoolean, params);
3346
- }
3347
3313
  const ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
3348
3314
  $ZodUnknown.init(inst, def);
3349
3315
  ZodType.init(inst, def);
@@ -3650,8 +3616,10 @@ function superRefine(fn) {
3650
3616
  //#region ../cli/dist/schemas/brief.js
3651
3617
  const briefStatus = _enum([
3652
3618
  "draft",
3619
+ "ready",
3653
3620
  "active",
3654
- "completed"
3621
+ "completed",
3622
+ "cancelled"
3655
3623
  ]);
3656
3624
  const briefFrontmatter = object({
3657
3625
  name: string().min(1),
@@ -3663,20 +3631,42 @@ const briefFrontmatter = object({
3663
3631
  /**
3664
3632
  * Valid state transitions for a brief.
3665
3633
  * Each key maps to the set of states it can transition to.
3634
+ *
3635
+ * draft → ready: brief skill marks the brief as designed and enriched
3636
+ * ready → active: build skill begins building
3637
+ * ready → draft: brief needs rework
3638
+ * active → completed: build skill finishes all tasks
3639
+ * draft/ready/active → cancelled: feature is dropped
3666
3640
  */
3667
3641
  const briefTransitions = {
3668
- draft: ["active"],
3669
- active: ["completed", "draft"],
3670
- completed: []
3642
+ draft: ["ready", "cancelled"],
3643
+ ready: [
3644
+ "active",
3645
+ "draft",
3646
+ "cancelled"
3647
+ ],
3648
+ active: ["completed", "cancelled"],
3649
+ completed: [],
3650
+ cancelled: []
3671
3651
  };
3652
+ //#endregion
3653
+ //#region ../cli/dist/schemas/tasks.js
3654
+ const taskStatus = _enum([
3655
+ "pending",
3656
+ "active",
3657
+ "completed",
3658
+ "skipped"
3659
+ ]);
3672
3660
  const tasksFrontmatter = object({ tasks: array(object({
3673
3661
  name: string().min(1),
3674
3662
  group: string().min(1).optional(),
3675
- done: boolean().default(false)
3663
+ status: taskStatus.default("pending")
3676
3664
  })) });
3677
3665
  //#endregion
3678
3666
  //#region ../cli/dist/brief.js
3679
- const BRIEFS_DIRECTORY = path.join(".fledge", "briefs");
3667
+ const FLEDGE_DIRECTORY = ".fledge";
3668
+ const BRIEFS_DIRECTORY = path.join(FLEDGE_DIRECTORY, "briefs");
3669
+ path.join(FLEDGE_DIRECTORY, "project.md");
3680
3670
  /**
3681
3671
  * Creates a BriefContext from a project directory path or falls back to `cwd()`.
3682
3672
  *
@@ -3726,6 +3716,16 @@ function getTasksFile(context, name) {
3726
3716
  return path.join(getBriefDirectory(context, name), "tasks.md");
3727
3717
  }
3728
3718
  /**
3719
+ * Returns the absolute path to a brief's `spec.md` file.
3720
+ *
3721
+ * @param context - The brief context.
3722
+ * @param name - The brief name.
3723
+ * @returns The absolute path to `spec.md`.
3724
+ */
3725
+ function getSpecFile(context, name) {
3726
+ return path.join(getBriefDirectory(context, name), "spec.md");
3727
+ }
3728
+ /**
3729
3729
  * Checks whether a brief directory exists.
3730
3730
  *
3731
3731
  * @param context - The brief context.
@@ -3815,6 +3815,35 @@ const projectDirectory = {
3815
3815
  description: "Project root directory. Overrides cwd() for locating .fledge/briefs/."
3816
3816
  };
3817
3817
  //#endregion
3818
+ //#region ../cli/dist/commands/brief/cancel.js
3819
+ var cancel_default = defineCommand({
3820
+ meta: {
3821
+ name: "cancel",
3822
+ description: "Cancel a brief"
3823
+ },
3824
+ args: {
3825
+ name: {
3826
+ type: "positional",
3827
+ required: true,
3828
+ description: "The name of the brief to cancel"
3829
+ },
3830
+ projectDirectory
3831
+ },
3832
+ run(context) {
3833
+ const ctx = createBriefContext(context.args.projectDirectory);
3834
+ const { name } = context.args;
3835
+ if (!briefExists(ctx, name)) throw new Error(`Brief "${name}" does not exist at "${getBriefDirectory(ctx, name)}"`);
3836
+ const brief = readBriefFrontmatter(ctx, name);
3837
+ validateTransition(brief.status, "cancelled");
3838
+ updateBriefFrontmatter(ctx, name, {
3839
+ ...brief,
3840
+ status: "cancelled",
3841
+ updated: formatDate()
3842
+ });
3843
+ stdout.write(`Brief "${name}" has been cancelled\n`);
3844
+ }
3845
+ });
3846
+ //#endregion
3818
3847
  //#region ../cli/dist/commands/brief/complete.js
3819
3848
  var complete_default = defineCommand({
3820
3849
  meta: {
@@ -3836,10 +3865,10 @@ var complete_default = defineCommand({
3836
3865
  const brief = readBriefFrontmatter(ctx, name);
3837
3866
  validateTransition(brief.status, "completed");
3838
3867
  if (!brief.summary) throw new Error("Brief must have a summary before completing. Add a \"summary\" field to the brief.md frontmatter.");
3839
- const incomplete = readTasksFrontmatter(ctx, name).tasks.filter((task) => !task.done);
3868
+ const incomplete = readTasksFrontmatter(ctx, name).tasks.filter((task) => task.status !== "completed" && task.status !== "skipped");
3840
3869
  if (incomplete.length > 0) {
3841
- const names = incomplete.map((task) => ` - ${task.name}`).join("\n");
3842
- throw new Error(`Cannot complete brief with ${incomplete.length} incomplete task(s):\n${names}`);
3870
+ const names = incomplete.map((task) => ` - ${task.name} [${task.status}]`).join("\n");
3871
+ throw new Error(`Cannot complete brief with ${incomplete.length} unfinished task(s):\n${names}`);
3843
3872
  }
3844
3873
  updateBriefFrontmatter(ctx, name, {
3845
3874
  ...brief,
@@ -3878,6 +3907,7 @@ var create_default = defineCommand({
3878
3907
  updated: date
3879
3908
  }));
3880
3909
  fs.writeFileSync(getTasksFile(ctx, name), writeFrontmatter({ tasks: [] }));
3910
+ fs.writeFileSync(getSpecFile(ctx, name), "");
3881
3911
  stdout.write(`Created brief "${name}" at "${directory}"\n`);
3882
3912
  }
3883
3913
  });
@@ -3892,7 +3922,7 @@ var list_default = defineCommand({
3892
3922
  status: {
3893
3923
  type: "string",
3894
3924
  required: false,
3895
- description: "Filter by brief status (draft, active, completed)"
3925
+ description: "Filter by brief status (draft, ready, active, completed, cancelled)"
3896
3926
  },
3897
3927
  projectDirectory
3898
3928
  },
@@ -3906,7 +3936,7 @@ var list_default = defineCommand({
3906
3936
  let briefs = names.map((name) => {
3907
3937
  const brief = readBriefFrontmatter(ctx, name);
3908
3938
  const { tasks } = readTasksFrontmatter(ctx, name);
3909
- const done = tasks.filter((task) => task.done).length;
3939
+ const done = tasks.filter((task) => task.status === "completed" || task.status === "skipped").length;
3910
3940
  return {
3911
3941
  ...brief,
3912
3942
  tasksDone: done,
@@ -3934,6 +3964,35 @@ var list_default = defineCommand({
3934
3964
  }
3935
3965
  });
3936
3966
  //#endregion
3967
+ //#region ../cli/dist/commands/brief/ready.js
3968
+ var ready_default = defineCommand({
3969
+ meta: {
3970
+ name: "ready",
3971
+ description: "Transition a brief from draft to ready"
3972
+ },
3973
+ args: {
3974
+ name: {
3975
+ type: "positional",
3976
+ required: true,
3977
+ description: "The name of the brief to mark as ready"
3978
+ },
3979
+ projectDirectory
3980
+ },
3981
+ run(context) {
3982
+ const ctx = createBriefContext(context.args.projectDirectory);
3983
+ const { name } = context.args;
3984
+ if (!briefExists(ctx, name)) throw new Error(`Brief "${name}" does not exist at "${getBriefDirectory(ctx, name)}"`);
3985
+ const brief = readBriefFrontmatter(ctx, name);
3986
+ validateTransition(brief.status, "ready");
3987
+ updateBriefFrontmatter(ctx, name, {
3988
+ ...brief,
3989
+ status: "ready",
3990
+ updated: formatDate()
3991
+ });
3992
+ stdout.write(`Brief "${name}" is ready for implementation\n`);
3993
+ }
3994
+ });
3995
+ //#endregion
3937
3996
  //#region ../cli/dist/commands/brief/schema.js
3938
3997
  var schema_default = defineCommand({
3939
3998
  meta: {
@@ -3953,7 +4012,7 @@ var schema_default = defineCommand({
3953
4012
  var start_default = defineCommand({
3954
4013
  meta: {
3955
4014
  name: "start",
3956
- description: "Transition a brief from draft to active"
4015
+ description: "Transition a brief from ready to active"
3957
4016
  },
3958
4017
  args: {
3959
4018
  name: {
@@ -3969,7 +4028,6 @@ var start_default = defineCommand({
3969
4028
  if (!briefExists(ctx, name)) throw new Error(`Brief "${name}" does not exist at "${getBriefDirectory(ctx, name)}"`);
3970
4029
  const brief = readBriefFrontmatter(ctx, name);
3971
4030
  validateTransition(brief.status, "active");
3972
- if (readTasksFrontmatter(ctx, name).tasks.length === 0) throw new Error("Brief must have at least one task before starting");
3973
4031
  updateBriefFrontmatter(ctx, name, {
3974
4032
  ...brief,
3975
4033
  status: "active",
@@ -3997,13 +4055,18 @@ function groupTasks(tasks) {
3997
4055
  return groups;
3998
4056
  }
3999
4057
  /**
4000
- * Formats a task as a line with a checkbox indicator.
4058
+ * Maps a task status to a display indicator.
4001
4059
  *
4002
4060
  * @param task - The task to format.
4003
- * @returns The formatted task string.
4061
+ * @returns The formatted task string with status indicator.
4004
4062
  */
4005
4063
  function formatTask(task) {
4006
- return ` ${task.done ? "[x]" : "[ ]"} ${task.name}`;
4064
+ return ` ${{
4065
+ pending: "[ ]",
4066
+ active: "[~]",
4067
+ completed: "[x]",
4068
+ skipped: "[-]"
4069
+ }[task.status] ?? "[ ]"} ${task.name}`;
4007
4070
  }
4008
4071
  //#endregion
4009
4072
  //#region ../cli/dist/run-brief.js
@@ -4013,9 +4076,11 @@ runMain(defineCommand({
4013
4076
  description: "Manage feature briefs"
4014
4077
  },
4015
4078
  subCommands: {
4079
+ cancel: cancel_default,
4016
4080
  complete: complete_default,
4017
4081
  create: create_default,
4018
4082
  list: list_default,
4083
+ ready: ready_default,
4019
4084
  schema: schema_default,
4020
4085
  start: start_default,
4021
4086
  status: defineCommand({
@@ -4037,7 +4102,7 @@ runMain(defineCommand({
4037
4102
  if (!briefExists(ctx, name)) throw new Error(`Brief "${name}" does not exist at "${getBriefDirectory(ctx, name)}"`);
4038
4103
  const brief = readBriefFrontmatter(ctx, name);
4039
4104
  const { tasks } = readTasksFrontmatter(ctx, name);
4040
- const done = tasks.filter((task) => task.done).length;
4105
+ const done = tasks.filter((task) => task.status === "completed" || task.status === "skipped").length;
4041
4106
  const lines = [];
4042
4107
  lines.push(`${name} [${brief.status}] ${done}/${tasks.length} tasks done`);
4043
4108
  lines.push("");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fledge/workflow",
3
3
  "type": "module",
4
- "version": "0.6.3",
4
+ "version": "0.7.1",
5
5
  "author": "René Schapka",
6
6
  "license": "MIT",
7
7
  "files": [
@@ -15,7 +15,7 @@
15
15
  "node": ">=24"
16
16
  },
17
17
  "dependencies": {
18
- "@fledge/cli": "^0.9.1"
18
+ "@fledge/cli": "^0.11.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@antfu/eslint-config": "7.7.3",
@@ -1,20 +1,43 @@
1
1
  ---
2
2
  name: fledge-brief
3
3
  description: >-
4
- Guide feature brief creation and lifecycle. Plan new features, create or update feature briefs, break down work into tasks, or complete a feature.
4
+ Guide feature brief creation and lifecycle. Plan new features, create or update feature briefs, enrich with project knowledge, or complete a feature.
5
5
  Invoked directly via /fledge-brief, not auto-triggered.
6
6
  metadata:
7
7
  type: workflow
8
- allowed-tools: Bash(node *scripts/brief.js *)
8
+ allowed-tools: Bash(node *scripts/brief.js*)
9
9
  ---
10
10
 
11
+ ## Lifecycle overview
12
+
13
+ The brief skill owns two workflow phases: **Brief** (capture what to build) and **Enrich** (connect to project knowledge). See [docs/workflow.md](../../docs/workflow.md) for the full workflow.
14
+
15
+ ```
16
+ Brief → Enrich → [Build] → [Verify] → [Complete]
17
+ └── this skill ──┘ └── build skill (future) ──────────┘
18
+ ```
19
+
20
+ **States this skill manages:** `draft → ready`
21
+ **States managed by the build skill:** `ready → active → completed`
22
+
23
+ A brief directory contains three files:
24
+
25
+ ```
26
+ .fledge/briefs/<name>/
27
+ brief.md what, why, scope, design decisions (product-level)
28
+ spec.md data models, APIs, external services (technical context)
29
+ tasks.md tasks (empty until build phase)
30
+ ```
31
+
11
32
  ## Available scripts
12
33
 
13
34
  **Important:** Run all scripts with `node` (e.g. `node scripts/brief.js list`). Always pass `--project-dir` pointing to the project root.
14
35
 
15
36
  - **`node scripts/brief.js create <name> --project-dir <path>`** -- Create a new brief with stub files
16
- - **`node scripts/brief.js start <name> --project-dir <path>`** -- Transition a brief from draft to active
37
+ - **`node scripts/brief.js ready <name> --project-dir <path>`** -- Transition a brief from draft to ready
38
+ - **`node scripts/brief.js start <name> --project-dir <path>`** -- Transition a brief from ready to active
17
39
  - **`node scripts/brief.js complete <name> --project-dir <path>`** -- Transition a brief from active to completed
40
+ - **`node scripts/brief.js cancel <name> --project-dir <path>`** -- Cancel a brief
18
41
  - **`node scripts/brief.js status <name> --project-dir <path>`** -- Show status and task progress
19
42
  - **`node scripts/brief.js list [--status <status>] --project-dir <path>`** -- List all briefs with progress and summary
20
43
  - **`node scripts/brief.js validate <name> --project-dir <path>`** -- Validate brief files against schemas
@@ -25,8 +48,8 @@ allowed-tools: Bash(node *scripts/brief.js *)
25
48
  Ask what the user wants to do, or infer from context. Present these options:
26
49
 
27
50
  1. **New brief** -- plan a new feature from scratch. Proceed to Step 1.
28
- 2. **Continue a brief** -- pick up an existing brief. Proceed to Step 4.
29
- 3. **Complete a brief** -- wrap up a finished feature. Proceed to Step 5.
51
+ 2. **Continue a brief** -- pick up an existing brief. Proceed to Step 5.
52
+ 3. **Complete a brief** -- wrap up a finished feature. Proceed to Step 6.
30
53
 
31
54
  If unclear, run `node scripts/brief.js list --project-dir <path>` to show current briefs and ask.
32
55
 
@@ -60,65 +83,70 @@ Write the brief content into `brief.md`. The frontmatter is managed by the scrip
60
83
  - **Scope**: what is included and what is explicitly excluded
61
84
  - **Design decisions**: key choices made during this conversation, with reasoning
62
85
 
63
- Keep it concise. The brief is a reference for implementation, not a specification document. If something is obvious from the code, do not repeat it here.
86
+ Keep it concise. The brief is a reference for building, not a specification document. If something is obvious from the code, do not repeat it here.
64
87
 
65
88
  Proceed to Step 3.
66
89
 
67
90
  ---
68
91
 
69
- ## Step 3: Break down into tasks
92
+ ## Step 3: Enrich with project knowledge
70
93
 
71
- Define the implementation tasks in `tasks.md`. Each task should be:
94
+ Connect the brief to the technical reality of the project. Start by reading `.fledge/project.md` to understand the project landscape. If this file does not exist, suggest running `fledge init` first.
72
95
 
73
- - **Small enough** to be a single focused unit of work
74
- - **Specific enough** that someone (or an agent) can start without further clarification
75
- - **Grouped** by concern when the feature spans multiple areas (e.g. backend, frontend, data)
96
+ Walk through each section of `project.md` with the brief in mind:
76
97
 
77
- Write the tasks into the `tasks.md` frontmatter:
98
+ 1. **Domain**: which concepts from the glossary does this feature involve? Are there new domain terms that need defining?
99
+ 2. **Data models**: which existing models does the feature interact with? Are new models or fields needed?
100
+ 3. **APIs**: which existing endpoints are relevant? Are new endpoints needed? Do they follow the documented conventions?
101
+ 4. **External services**: does this feature involve any third-party integrations?
102
+ 5. **Conventions**: are there project-specific patterns the build should follow?
103
+ 6. **Stack**: which technology skills are available to guide the build?
104
+
105
+ Write the relevant findings into `spec.md`. The spec grounds the product-level brief in the project's actual structure. It does **not** include tasks or technology-specific guidance (those come from the build skill and technology skills).
106
+
107
+ **Gap detection**: if you discover aspects of the project that are not reflected in `project.md` (an undocumented endpoint, a model that is missing, a domain concept that should be in the glossary), note these gaps and suggest updates to `project.md`. Keeping project knowledge current is part of enrichment.
108
+
109
+ Proceed to Step 4.
78
110
 
79
- ```yaml
80
- ---
81
- tasks:
82
- - name: <clear, actionable task name>
83
- group: <area>
84
- done: false
85
111
  ---
86
- ```
87
112
 
88
- Order tasks by dependency: tasks that others depend on come first within their group.
113
+ ## Step 4: Mark as ready
114
+
115
+ Run `node scripts/brief.js validate <name> --project-dir <path>` to confirm the brief is valid.
89
116
 
90
- After writing tasks, run `node scripts/brief.js validate <name> --project-dir <path>` to confirm the brief is valid, then run `node scripts/brief.js start <name> --project-dir <path>` to transition to active.
117
+ Present the complete brief (`brief.md`) and spec (`spec.md`) to the user for review.
91
118
 
92
- Present the complete brief and task list to the user for review before starting.
119
+ Once approved, run `node scripts/brief.js ready <name> --project-dir <path>` to transition to ready. The brief is now ready for the build skill to pick up.
93
120
 
94
121
  ---
95
122
 
96
- ## Step 4: Continue a brief
123
+ ## Step 5: Continue a brief
97
124
 
98
125
  Run `node scripts/brief.js list --project-dir <path>` to show all briefs. If the user does not specify which brief, ask them to pick one.
99
126
 
100
- Run `node scripts/brief.js status <name> --project-dir <path>` to show progress. Read the brief and tasks files to understand the full context.
127
+ Run `node scripts/brief.js status <name> --project-dir <path>` to show progress. Read the brief, spec, and tasks files to understand the full context.
101
128
 
102
129
  From here, the user may want to:
103
- - **Discuss a task** -- talk through approach before implementing
104
- - **Update tasks** -- mark tasks as done, add new tasks, reorder
105
- - **Revise the brief** -- update scope or design decisions based on what was learned during implementation
130
+ - **Discuss the brief** -- talk through scope or design decisions
131
+ - **Update the spec** -- add or revise technical context
132
+ - **Revise the brief** -- update scope or design decisions based on what was learned
133
+ - **Send back to draft** -- if a ready brief needs significant rework, update the status back to draft
106
134
 
107
- When updating task status, modify the `tasks.md` frontmatter directly, then run `node scripts/brief.js status <name> --project-dir <path>` to confirm the update.
135
+ When updating files, run `node scripts/brief.js validate <name> --project-dir <path>` afterward to confirm validity.
108
136
 
109
137
  ---
110
138
 
111
- ## Step 5: Complete a brief
139
+ ## Step 6: Complete a brief
112
140
 
113
141
  Run `node scripts/brief.js status <name> --project-dir <path>` to verify all tasks are done.
114
142
 
115
143
  If there are incomplete tasks, ask the user whether to:
116
- 1. Mark remaining tasks as done (if they were completed outside this conversation)
117
- 2. Remove tasks that are no longer needed
144
+ 1. Mark remaining tasks as completed (if they were completed outside this conversation)
145
+ 2. Mark tasks as skipped (if they are no longer needed)
118
146
  3. Continue working on them first
119
147
 
120
148
  Write a summary into the `brief.md` frontmatter `summary` field. The summary should be one to two sentences capturing:
121
149
  - What was built
122
150
  - Key decisions or patterns established that future features should know about
123
151
 
124
- Run `node scripts/brief.js complete <name> --project-dir <path>` to transition to completed. The script validates that all tasks are done and the summary is present.
152
+ Run `node scripts/brief.js complete <name> --project-dir <path>` to transition to completed. The script validates that all tasks are done or skipped and the summary is present.