create-pmos 0.38.4 → 0.38.6
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/package.json +1 -1
- package/payload/AGENTS.md +1 -1
- package/payload/KIT-VERSION +2 -2
- package/payload/okf/core/templates/requirements-brief-template.md +61 -0
- package/payload/planning/evals/eval-calibration.md +1 -1
- package/payload/planning/okrs/health-budgets.md +1 -1
- package/payload/scripts/lane-defs.js +226 -0
- package/payload/scripts/workflow-state.js +108 -24
- package/payload/scripts/workflow-sweep.js +155 -3
- package/payload/skills/design-brief.skill +5 -6
- package/payload/skills/discovery.skill +1 -2
- package/payload/skills/eval-rubric.skill +2 -5
- package/payload/skills/pmos-router.skill +3 -2
- package/payload/skills/prd.skill +7 -13
- package/payload/skills/requirements-elicitation.skill +231 -0
- package/payload/skills-native/design-brief/SKILL.md +5 -6
- package/payload/skills-native/discovery/SKILL.md +1 -2
- package/payload/skills-native/eval-rubric/SKILL.md +2 -5
- package/payload/skills-native/pmos-router/SKILL.md +3 -2
- package/payload/skills-native/prd/SKILL.md +7 -13
- package/payload/skills-native/requirements-elicitation/SKILL.md +233 -0
- package/payload/state/discoveries.md +1 -1
- package/payload/state/log.md +1 -1
- package/workspace/lib/audit.js +54 -0
- package/workspace/lib/engine/lane-defs.js +226 -0
- package/workspace/lib/engine/workflow-state.js +108 -24
- package/workspace/lib/engine/workflow-sweep.js +934 -0
- package/workspace/package-lock.json +1 -1
- package/workspace/package.json +2 -2
- package/workspace/public/pm/data.js +67 -24
- package/workspace/public/pm/panel-detail.js +12 -2
- package/workspace/public/pm/panel-repos.js +36 -5
- package/workspace/public/pm/tab-task.js +4 -1
- package/workspace/server.js +22 -1
- package/workspace/skills/gather-requirements.skill +13 -1
|
@@ -32,22 +32,17 @@ agreed.
|
|
|
32
32
|
|
|
33
33
|
## Procedure
|
|
34
34
|
|
|
35
|
-
0a. **Existing surface? Understand it first — before
|
|
35
|
+
0a. **Existing surface? Understand it first — before asking.** If specifying this honestly
|
|
36
36
|
requires reading code that already exists, an [explain-surface](/skills/explain-surface.skill)
|
|
37
37
|
pass runs on that region **first**, in a fresh context and **not by you**. Its *Open questions*
|
|
38
|
-
section is a declared input to the
|
|
38
|
+
section is a declared input to the questions in step 0: those are the things that could not be
|
|
39
39
|
determined from the code, and they must be resolved with the PM or carried explicitly into the
|
|
40
40
|
PRD's risks — never silently answered by assumption. Greenfield → skip. This exists because step 0b's
|
|
41
41
|
boundary rule, on its own, gives the **agent** the understanding and the PM none.
|
|
42
|
-
0. **
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
question is a quality bug, not a quantity bug). A batch questionnaire is **not** compliant with
|
|
47
|
-
this step. Boundary rule, near-verbatim from AGENTS.md: *if a fact can be found by exploring the
|
|
48
|
-
environment, look it up rather than asking — the decisions, though, are the PM's* (D12 at
|
|
49
|
-
optimal altitude). A stated requirement that later goes unhonored in a build (the recorded
|
|
50
|
-
"too many navigations" class) is exactly what this step exists to pin down in writing.
|
|
42
|
+
0. **Ask before you write.** Follow the [requirements-elicitation skill](/skills/requirements-elicitation.skill):
|
|
43
|
+
its asking rule holds here, and no authoring starts until the PM confirms the shared understanding.
|
|
44
|
+
A stated requirement that later goes unhonored in a build (the recorded "too many navigations"
|
|
45
|
+
class) is what this step pins down in writing.
|
|
51
46
|
1. **Anchor to strategy first.** Identify the parent KR in the
|
|
52
47
|
[OKR tree](/okf/core/concepts/okr-tree.md) — or, for maintenance work with no honest KR, the
|
|
53
48
|
declared [health budget](/okf/core/concepts/health-anchors.md) (`health:<id>`, D59). If the
|
|
@@ -109,8 +104,7 @@ its situating sentence (D58); the eval rubric is queued to be written first.
|
|
|
109
104
|
|
|
110
105
|
## Level 3 sub-cases
|
|
111
106
|
|
|
112
|
-
-
|
|
113
|
-
(author on first need).
|
|
107
|
+
- None yet.
|
|
114
108
|
- Spike / discovery work where the deliverable is a learning, not a feature, is **not a PRD
|
|
115
109
|
case** — take the discovery lane ([D56](/okf/products/pmos/adr/d56-initiative-lanes.md)):
|
|
116
110
|
[discovery skill](/skills/discovery.skill) +
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: requirements-elicitation
|
|
3
|
+
description: Turn a vague ask, or notes the PM gathered, into a requirements brief by asking the PM questions one at a time. Use when the PM wants to gather, clarify or sharpen requirements, or before any lane writes its first artifact (PRD, spike brief, fix specification, content brief).
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
pmos-version: 1.0.0
|
|
7
|
+
pmos-owner: wawan
|
|
8
|
+
pmos-risk: low
|
|
9
|
+
pmos-category: planning
|
|
10
|
+
pmos-scope: read:okf, read:planning, read:state, write:planning/briefs
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# requirements-elicitation — Ask until the requirement is sharp
|
|
14
|
+
|
|
15
|
+
This skill is the one place where PMOS states how an agent asks the PM questions. It also
|
|
16
|
+
holds the questions each lane needs. Its output is a requirements brief that a PRD, a spike
|
|
17
|
+
brief or a fix specification starts from. It does not write those documents.
|
|
18
|
+
|
|
19
|
+
> **Format note:** this skill follows [SKILL-FORMAT](/skills/SKILL-FORMAT.md). The text is
|
|
20
|
+
> instructional (class A of [technical-writing-ste](/skills/technical-writing-ste.skill)).
|
|
21
|
+
|
|
22
|
+
## When to use vs. not
|
|
23
|
+
|
|
24
|
+
- **Use** when the PM asks to gather, clarify or sharpen requirements.
|
|
25
|
+
- **Use** before the first artifact of any lane, when the intent is not yet unambiguous.
|
|
26
|
+
- **Do not use** to decide the lane. That is the [pmos-router](/skills/pmos-router.skill).
|
|
27
|
+
- **Do not use** to judge whether to build at all. That is the
|
|
28
|
+
[strategic-brief](/skills/strategic-brief.skill).
|
|
29
|
+
- **Do not use** when an instance of the idea is needed before the PM can judge it. Route to the
|
|
30
|
+
prototype lane first.
|
|
31
|
+
|
|
32
|
+
## The asking rule
|
|
33
|
+
|
|
34
|
+
This rule holds in every step below. Other skills point here and do not repeat it.
|
|
35
|
+
|
|
36
|
+
1. Ask one question at a time.
|
|
37
|
+
2. Give a recommended answer with each question.
|
|
38
|
+
3. Do not set a limit on the number of questions. Stop when the intent is unambiguous.
|
|
39
|
+
4. Do not send a batch questionnaire. A batch does not satisfy this rule.
|
|
40
|
+
5. Look up each fact that the repository or the record can answer. Do not ask the PM for it.
|
|
41
|
+
6. Leave each decision to the PM.
|
|
42
|
+
7. Write nothing until the PM confirms the shared understanding.
|
|
43
|
+
|
|
44
|
+
## Procedure
|
|
45
|
+
|
|
46
|
+
1. **Find the lane.** Read the initiative record and its `type`. Run
|
|
47
|
+
`node scripts/workflow-state.js --lanes --json` (in a kit repository the script is
|
|
48
|
+
`pmos/scripts/workflow-state.js`). Find the lane in `defs`.
|
|
49
|
+
State the lane's `input`, `output` and `done` in plain words before the first question.
|
|
50
|
+
*Done when:* the PM has seen the lane's input, output and done-rule.
|
|
51
|
+
|
|
52
|
+
If the script is missing or the lane is not in `defs`, say so. Ask the PM which lane applies.
|
|
53
|
+
Do not guess a question set.
|
|
54
|
+
|
|
55
|
+
2. **Look up what exists.** Read the record, the PRD or brief if one exists, the OKR the
|
|
56
|
+
record names, and the explainer if the surface exists. Collect the facts you found.
|
|
57
|
+
*Done when:* every fact you will use has a source, and none of them is a question for the PM.
|
|
58
|
+
|
|
59
|
+
3. **Read the gathered notes.** List `<state>/requirements/*.md`. `<state>` is `pmos/state/`
|
|
60
|
+
if it exists, and `planning/` if not. Select each item whose `initiative` names this
|
|
61
|
+
initiative. Show each item to the PM with its pointer and its `confidence`. Ask for one
|
|
62
|
+
answer per item: confirmed, rejected or deferred. Record the answer.
|
|
63
|
+
- A confirmed item goes in the brief under *Decisions*, with its pointer.
|
|
64
|
+
- A rejected item is dropped. Name it in *Gathered notes used* as rejected.
|
|
65
|
+
- A deferred item goes in *Open questions*.
|
|
66
|
+
- An item with `confidence: unconfirmed` stays unconfirmed until the PM answers. Never write
|
|
67
|
+
it as a fact.
|
|
68
|
+
- Name a note that does not parse. Skip it.
|
|
69
|
+
- If no notes exist, say so and continue.
|
|
70
|
+
|
|
71
|
+
Never edit a note. The notes are read-only drafts (D71).
|
|
72
|
+
*Done when:* every selected item has an answer, or the PM has said to skip the notes.
|
|
73
|
+
|
|
74
|
+
4. **Ask the topic questions.** Work through the [question inventory](#question-inventory).
|
|
75
|
+
Skip a topic the lane's input does not need, and say that you skipped it.
|
|
76
|
+
Skip a question that step 2 or step 3 already answered.
|
|
77
|
+
*Done when:* each topic is answered, skipped with a reason, or listed in *Open questions*.
|
|
78
|
+
|
|
79
|
+
5. **Ask the lane questions.** Find the lane in [Question sets by lane](#question-sets-by-lane).
|
|
80
|
+
Ask each question there that the earlier steps did not answer.
|
|
81
|
+
*Done when:* every element of the lane's `input` has an answer or an *Open questions* entry.
|
|
82
|
+
|
|
83
|
+
6. **Confirm.** Say the shared understanding back to the PM in one short list. Ask the PM to
|
|
84
|
+
confirm or correct it.
|
|
85
|
+
*Done when:* the PM has confirmed. If the PM corrects it, go back to step 4.
|
|
86
|
+
|
|
87
|
+
7. **Write the brief.** Copy the
|
|
88
|
+
[requirements-brief-template](/okf/core/templates/requirements-brief-template.md). Fill every
|
|
89
|
+
section from the confirmed answers, in the PM's words where the PM gave words. Write it to
|
|
90
|
+
`planning/briefs/<id>-requirements.md`. Set `brief_path` on the initiative record. If the lane
|
|
91
|
+
uses `prd_path` for its first artifact and that file does not exist yet, tell the PM that the
|
|
92
|
+
brief is the input and that the lane's own skill writes `prd_path`.
|
|
93
|
+
*Done when:* the file exists, no section is empty, and `brief_path` is set.
|
|
94
|
+
|
|
95
|
+
8. **Hand over.** Name the next skill for the lane: [prd](/skills/prd.skill) for
|
|
96
|
+
feature and new-feature, [discovery](/skills/discovery.skill) for discovery,
|
|
97
|
+
[copywriting](/skills/copywriting.skill) for content, and the lane's own
|
|
98
|
+
template for the others. State the open questions that remain.
|
|
99
|
+
*Done when:* the PM knows what comes next and what is still open.
|
|
100
|
+
|
|
101
|
+
## Question inventory
|
|
102
|
+
|
|
103
|
+
Each topic has an opening question. Add follow-up questions when the answer is vague.
|
|
104
|
+
|
|
105
|
+
| Topic | Opening question |
|
|
106
|
+
|---|---|
|
|
107
|
+
| Problem and user | Who has this problem, and what do they do today instead? |
|
|
108
|
+
| Evidence | What shows that the problem is real: a number, a ticket, a quote, an incident? |
|
|
109
|
+
| Constraints | What is fixed: a date, a budget, a technology, a rule or a promise already made? |
|
|
110
|
+
| Stakeholders and decision owner | Who is affected, who must agree, and who decides if they disagree? |
|
|
111
|
+
| Dependencies | What must exist, or be done by someone else, before this can work? |
|
|
112
|
+
| Data | What data does this read or change, and who owns it? |
|
|
113
|
+
| Non-functional needs | What must hold about speed, security, privacy, access or cost? |
|
|
114
|
+
| Risks | What is the worst way this fails, and how would we notice? |
|
|
115
|
+
| Success measure | Which measure moves if this works, from what value to what value, by when? |
|
|
116
|
+
| Out of scope | What will this not do, even though someone might expect it to? |
|
|
117
|
+
|
|
118
|
+
## Question sets by lane
|
|
119
|
+
|
|
120
|
+
Each lane has its own heading. The headings use the lane names in `scripts/lane-defs.js`.
|
|
121
|
+
A lane name that both profiles use (discovery, chore) has one set.
|
|
122
|
+
|
|
123
|
+
### Lane `feature`
|
|
124
|
+
|
|
125
|
+
1. What behaviour changes for the user, in one sentence?
|
|
126
|
+
2. Does the surface exist today? If yes, what does it do now?
|
|
127
|
+
3. Which KR or health budget does this serve?
|
|
128
|
+
4. Can the PM judge this from a description, or must the PM see an instance first?
|
|
129
|
+
5. What would the PM check by hand to accept it?
|
|
130
|
+
|
|
131
|
+
### Lane `new-feature`
|
|
132
|
+
|
|
133
|
+
1. Who has the problem, and how often does it happen?
|
|
134
|
+
2. What shows that it is real?
|
|
135
|
+
3. What do users do today?
|
|
136
|
+
4. What must a first version do, and what can wait?
|
|
137
|
+
5. What would make the PM drop it?
|
|
138
|
+
|
|
139
|
+
### Lane `improvement`
|
|
140
|
+
|
|
141
|
+
1. What does the feature do now? Look it up first.
|
|
142
|
+
2. What is wrong or missing, and for whom?
|
|
143
|
+
3. Which measure should the change move, and by how much?
|
|
144
|
+
4. What must stay the same?
|
|
145
|
+
5. How will we tell that it worked?
|
|
146
|
+
|
|
147
|
+
### Lane `bug-fix`
|
|
148
|
+
|
|
149
|
+
1. What are the steps that reproduce it?
|
|
150
|
+
2. What is the expected result?
|
|
151
|
+
3. What is the actual result?
|
|
152
|
+
4. How severe is it, and who is affected?
|
|
153
|
+
5. Is there a workaround?
|
|
154
|
+
|
|
155
|
+
### Lane `discovery`
|
|
156
|
+
|
|
157
|
+
1. What is the question, in one sentence?
|
|
158
|
+
2. What is unknown, and what is already known?
|
|
159
|
+
3. What evidence would end the spike?
|
|
160
|
+
4. What would make this worth picking up, and what would make it worth dropping?
|
|
161
|
+
5. How long may it take?
|
|
162
|
+
|
|
163
|
+
### Lane `chore`
|
|
164
|
+
|
|
165
|
+
1. What is the intent, in one paragraph?
|
|
166
|
+
2. Which health budget does it serve?
|
|
167
|
+
3. What must not change?
|
|
168
|
+
4. How will the PM see that it is done?
|
|
169
|
+
|
|
170
|
+
### Lane `incident`
|
|
171
|
+
|
|
172
|
+
1. What broke, and who noticed?
|
|
173
|
+
2. What is the cause?
|
|
174
|
+
3. What was the repair, and is it permanent?
|
|
175
|
+
4. What stops it from happening again?
|
|
176
|
+
5. When was it fixed? The record is due within 48 hours.
|
|
177
|
+
|
|
178
|
+
### Lane `content`
|
|
179
|
+
|
|
180
|
+
1. Who reads it, and what should they do after?
|
|
181
|
+
2. What is the one message?
|
|
182
|
+
3. What tone and length does the reader expect?
|
|
183
|
+
4. What facts must it contain, and where are they?
|
|
184
|
+
5. Does the PM want a rubric?
|
|
185
|
+
|
|
186
|
+
### Lane `prototype`
|
|
187
|
+
|
|
188
|
+
1. What judgement does the PM need to make?
|
|
189
|
+
2. Which format fits the specimens: a screen, a sample output, a transcript or a schema?
|
|
190
|
+
3. What should the 2–3 specimens differ on?
|
|
191
|
+
4. Which conventions does the class need before the specimens (design system, skill format)?
|
|
192
|
+
|
|
193
|
+
### Lane `prd`
|
|
194
|
+
|
|
195
|
+
1. What is the question the document answers?
|
|
196
|
+
2. Who reads it?
|
|
197
|
+
3. Which decision does it inform?
|
|
198
|
+
4. What do the readers already know?
|
|
199
|
+
|
|
200
|
+
### Lane `strategy`
|
|
201
|
+
|
|
202
|
+
1. What is the question the document answers?
|
|
203
|
+
2. Who reads it?
|
|
204
|
+
3. Which decision does it inform?
|
|
205
|
+
4. Over what period?
|
|
206
|
+
|
|
207
|
+
### Lane `project-plan`
|
|
208
|
+
|
|
209
|
+
1. What is in scope, and what is out?
|
|
210
|
+
2. Who is on it, and for how much of their time?
|
|
211
|
+
3. Which dates are fixed, and who fixed them?
|
|
212
|
+
4. What does it depend on?
|
|
213
|
+
|
|
214
|
+
### Lane `decision-record`
|
|
215
|
+
|
|
216
|
+
1. What are the options?
|
|
217
|
+
2. Which one was chosen, and by whom?
|
|
218
|
+
3. What is the reason?
|
|
219
|
+
4. What would reverse the choice?
|
|
220
|
+
|
|
221
|
+
### Lane `report`
|
|
222
|
+
|
|
223
|
+
1. What period or subject does it cover?
|
|
224
|
+
2. Who reads it?
|
|
225
|
+
3. What should the reader do after reading?
|
|
226
|
+
4. Which sources does it use, and which can it not reach?
|
|
227
|
+
|
|
228
|
+
## Failure behaviour
|
|
229
|
+
|
|
230
|
+
- The lane definition cannot be read: say so, and ask the PM which lane applies.
|
|
231
|
+
- No gathered notes exist: say so, and continue.
|
|
232
|
+
- A note does not parse: name it, and skip it.
|
|
233
|
+
- The PM leaves a question open: write it under *Open questions*. Do not answer it.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
type: Reference
|
|
3
3
|
title: "Discoveries and friction log"
|
|
4
4
|
description: "Append-only record of what runs discovered and where the process rubbed."
|
|
5
|
-
generated: {by: process:create-pmos, at: "2026-10-
|
|
5
|
+
generated: {by: process:create-pmos, at: "2026-10-03T00:48:37Z"}
|
|
6
6
|
status: stable
|
|
7
7
|
---
|
|
8
8
|
|
package/payload/state/log.md
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/* audit.js — the workspace's door to the workflow sweep (D77).
|
|
3
|
+
*
|
|
4
|
+
* The sweep is ONE file, scripts/workflow-sweep.js, shared with the CLI an agent runs. It is loaded the
|
|
5
|
+
* way the workflow engine is: from the checkout two directories up, or from the copy the packaging step
|
|
6
|
+
* vendors into lib/engine/. This door only READS: it runs the sweep and reports. Repairs are made by
|
|
7
|
+
* `node scripts/workflow-sweep.js --fix`, on the PM's word, because they write the repository.
|
|
8
|
+
*/
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
const PATHS = [
|
|
13
|
+
path.join(__dirname, '..', '..', 'scripts', 'workflow-sweep.js'),
|
|
14
|
+
path.join(__dirname, 'engine', 'workflow-sweep.js'),
|
|
15
|
+
];
|
|
16
|
+
function core() {
|
|
17
|
+
for (const p of PATHS) {
|
|
18
|
+
if (!fs.existsSync(p)) continue;
|
|
19
|
+
try { return { ok: true, core: require(p) }; }
|
|
20
|
+
catch (e) { return { ok: false, error: `the workflow sweep at ${p} failed to load — ${String((e && e.message) || e).slice(0, 160)}` }; }
|
|
21
|
+
}
|
|
22
|
+
return { ok: false, error: 'the workflow sweep is not present in this install' };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const DEFECT_CAP = 40;
|
|
26
|
+
const OWED_CAP = 12;
|
|
27
|
+
|
|
28
|
+
/* Run the sweep on `root` and return a compact report. Defects are listed in full up to a cap, owed work as
|
|
29
|
+
* counts per class plus the first few, because a defect is the board lying and owed work is an open loop. */
|
|
30
|
+
function run(root) {
|
|
31
|
+
const c = core(); if (!c.ok) return c;
|
|
32
|
+
let res;
|
|
33
|
+
try { res = c.core.sweep({ root }); }
|
|
34
|
+
catch (e) { return { ok: false, error: 'the sweep could not run — ' + String((e && e.message) || e).slice(0, 160) }; }
|
|
35
|
+
if (!res || res.ok === false) return { ok: false, error: (res && res.error) || 'the sweep could not read this repository' };
|
|
36
|
+
const pick = (f) => ({
|
|
37
|
+
class: f.class, id: f.id || null, file: f.file || null, what: f.what, evidence: f.evidence || null,
|
|
38
|
+
repair: f.repair ? { key: f.repair.key || null, to: f.repair.to || null } : null,
|
|
39
|
+
hand: f.hand || null,
|
|
40
|
+
command: f.repair ? 'node scripts/workflow-sweep.js --fix' : null,
|
|
41
|
+
});
|
|
42
|
+
const owedBy = {};
|
|
43
|
+
for (const f of res.owed || []) owedBy[f.class] = (owedBy[f.class] || 0) + 1;
|
|
44
|
+
return {
|
|
45
|
+
ok: true, root, initiatives: res.initiatives,
|
|
46
|
+
counts: { defects: (res.defects || []).length, owed: (res.owed || []).length, repairable: res.repairable || 0 },
|
|
47
|
+
defects: (res.defects || []).slice(0, DEFECT_CAP).map(pick),
|
|
48
|
+
owed_by_class: owedBy,
|
|
49
|
+
owed: (res.owed || []).slice(0, OWED_CAP).map(pick),
|
|
50
|
+
notes: res.notes || [],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = { run, core, PATHS };
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* Lane definitions — the one place a workflow is defined (D77).
|
|
4
|
+
*
|
|
5
|
+
* A lane is a kind of work. This file says, for each lane: what it is for, what goes in, which
|
|
6
|
+
* rungs the work passes, what comes out, and when it is done. The workflow engine, the lane
|
|
7
|
+
* picker, the lane write and the workspace detail pane all read THIS file. Change a lane here and
|
|
8
|
+
* every one of them changes; there is no second list to keep in step.
|
|
9
|
+
*
|
|
10
|
+
* Two kinds of field:
|
|
11
|
+
* · prose (label, when, input, output, done) — shown to the PM, never read by the engine's rules;
|
|
12
|
+
* · rules (track, rungs, labels) — read by the engine, so a change here changes the ladder.
|
|
13
|
+
*
|
|
14
|
+
* The engine runs under stock Node with no dependencies, and the kit vendors it by walking its
|
|
15
|
+
* relative requires, so this is a plain CommonJS module rather than a JSON file.
|
|
16
|
+
*
|
|
17
|
+
* `rungs` lists the pm-artifacts rungs a lane passes through. A rung left out reads `n/a` with the
|
|
18
|
+
* lane named as the reason, so a lane that skips a rung says so instead of showing it pending.
|
|
19
|
+
* The code profile's ladder is fixed by D56/D58/D60; its definitions here are descriptive.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const PM_ALL_RUNGS = ['brief', 'draft', 'review', 'approved', 'handoff'];
|
|
23
|
+
const PM_NO_HANDOFF = ['brief', 'draft', 'review', 'approved'];
|
|
24
|
+
|
|
25
|
+
const PM_ARTIFACTS = {
|
|
26
|
+
'new-feature': {
|
|
27
|
+
label: 'New feature',
|
|
28
|
+
group: 'work',
|
|
29
|
+
when: 'A capability that does not exist yet.',
|
|
30
|
+
input: 'The problem, who has it, and the evidence that it is real.',
|
|
31
|
+
output: 'A product requirements document (PRD).',
|
|
32
|
+
done: 'The PRD exists, a reviewer has judged it, the PM has accepted it, and it is handed to the team or tracker.',
|
|
33
|
+
track: 'governed', rungs: PM_ALL_RUNGS, brief_label: 'problem brief', draft_label: 'PRD',
|
|
34
|
+
},
|
|
35
|
+
improvement: {
|
|
36
|
+
label: 'Feature improvement',
|
|
37
|
+
group: 'work',
|
|
38
|
+
when: 'A change to a feature that already exists.',
|
|
39
|
+
input: 'The feature as it is now, what is wrong or missing, and the measure the change should move.',
|
|
40
|
+
output: 'A change specification: what changes, what stays the same, and how to tell it worked.',
|
|
41
|
+
done: 'The change specification exists, a reviewer has judged it, the PM has accepted it, and it is handed off.',
|
|
42
|
+
track: 'governed', rungs: PM_ALL_RUNGS, brief_label: 'change brief', draft_label: 'change specification',
|
|
43
|
+
},
|
|
44
|
+
'bug-fix': {
|
|
45
|
+
label: 'Bug fix',
|
|
46
|
+
group: 'work',
|
|
47
|
+
when: 'Behaviour that is wrong against what was promised.',
|
|
48
|
+
input: 'A bug report: steps to reproduce, expected result, actual result, severity.',
|
|
49
|
+
output: 'A fix specification: the cause, the behaviour after the fix, and the check that proves it.',
|
|
50
|
+
done: 'The fix specification exists, a reviewer has judged it, the PM has accepted it, and it is handed off.',
|
|
51
|
+
track: 'light', rungs: PM_ALL_RUNGS, brief_label: 'bug report', draft_label: 'fix specification',
|
|
52
|
+
},
|
|
53
|
+
discovery: {
|
|
54
|
+
label: 'New product discovery',
|
|
55
|
+
group: 'work',
|
|
56
|
+
when: 'A question that must be answered before anyone commits to build.',
|
|
57
|
+
input: 'The question, what is unknown, and the evidence that would make this worth picking up or dropping.',
|
|
58
|
+
output: 'Findings and a recommendation: go, drop, or learn more.',
|
|
59
|
+
done: 'The findings exist, a reviewer has judged them, the PM has accepted them, and the recommendation is handed off.',
|
|
60
|
+
track: 'governed', rungs: PM_ALL_RUNGS, brief_label: 'question brief', draft_label: 'findings',
|
|
61
|
+
},
|
|
62
|
+
chore: {
|
|
63
|
+
label: 'Chore',
|
|
64
|
+
group: 'work',
|
|
65
|
+
when: 'Upkeep that needs no requirements document.',
|
|
66
|
+
input: 'One paragraph that states the intent.',
|
|
67
|
+
output: 'The change itself, with the paragraph in the record.',
|
|
68
|
+
done: 'The change is made and the PM has accepted it. Nothing is handed off.',
|
|
69
|
+
track: 'light', rungs: PM_NO_HANDOFF, brief_label: 'intent', draft_label: 'change',
|
|
70
|
+
},
|
|
71
|
+
prd: {
|
|
72
|
+
label: 'PRD (document)',
|
|
73
|
+
group: 'document',
|
|
74
|
+
when: 'A standalone requirements document that is not a new feature, an improvement or a bug fix.',
|
|
75
|
+
input: 'The brief: the question, the reader, the decision it informs.',
|
|
76
|
+
output: 'A product requirements document.',
|
|
77
|
+
done: 'The PRD exists, a reviewer has judged it, the PM has accepted it, and it is handed off.',
|
|
78
|
+
track: 'governed', rungs: PM_ALL_RUNGS, brief_label: 'brief', draft_label: 'PRD',
|
|
79
|
+
},
|
|
80
|
+
strategy: {
|
|
81
|
+
label: 'Strategy (document)',
|
|
82
|
+
group: 'document',
|
|
83
|
+
when: 'A statement of direction: where to play, how to win, what not to do.',
|
|
84
|
+
input: 'The brief: the question, the reader, the decision it informs.',
|
|
85
|
+
output: 'A strategy document.',
|
|
86
|
+
done: 'The document exists, a reviewer has judged it, the PM has accepted it, and it is handed off.',
|
|
87
|
+
track: 'governed', rungs: PM_ALL_RUNGS, brief_label: 'brief', draft_label: 'strategy document',
|
|
88
|
+
},
|
|
89
|
+
'project-plan': {
|
|
90
|
+
label: 'Project plan (document)',
|
|
91
|
+
group: 'document',
|
|
92
|
+
when: 'Who does what, by when, in what order.',
|
|
93
|
+
input: 'The scope, the people and the dates that are fixed.',
|
|
94
|
+
output: 'A project plan.',
|
|
95
|
+
done: 'The plan exists, a reviewer has judged it, the PM has accepted it, and it is handed off.',
|
|
96
|
+
track: 'governed', rungs: PM_ALL_RUNGS, brief_label: 'brief', draft_label: 'project plan',
|
|
97
|
+
},
|
|
98
|
+
'decision-record': {
|
|
99
|
+
label: 'Decision record (document)',
|
|
100
|
+
group: 'document',
|
|
101
|
+
when: 'A decision that was made and must not be re-argued.',
|
|
102
|
+
input: 'The options, the choice, and the reason.',
|
|
103
|
+
output: 'A decision record.',
|
|
104
|
+
done: 'The record exists, a reviewer has judged it, and the PM has accepted it. Nothing is handed off.',
|
|
105
|
+
track: 'light', rungs: PM_NO_HANDOFF, brief_label: 'brief', draft_label: 'decision record',
|
|
106
|
+
},
|
|
107
|
+
report: {
|
|
108
|
+
label: 'Report (document)',
|
|
109
|
+
group: 'document',
|
|
110
|
+
when: 'An account of what happened or where things stand.',
|
|
111
|
+
input: 'The period or subject, and the reader.',
|
|
112
|
+
output: 'A report.',
|
|
113
|
+
done: 'The report exists, a reviewer has judged it, and the PM has accepted it. Nothing is handed off.',
|
|
114
|
+
track: 'light', rungs: PM_NO_HANDOFF, brief_label: 'brief', draft_label: 'report',
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/*
|
|
119
|
+
* The code profile's lanes. They share ONE ladder; a lane changes only the artifact the spec rung
|
|
120
|
+
* requires (`requires`), whether a rubric is needed, the prototype rule, and the build-path rule. Those
|
|
121
|
+
* rules are fixed by D56/D58/D60 and live in workflow-state.js; what is here is what the PM reads.
|
|
122
|
+
*/
|
|
123
|
+
const PRODUCT_CODE = {
|
|
124
|
+
feature: {
|
|
125
|
+
label: 'Feature',
|
|
126
|
+
group: 'work',
|
|
127
|
+
when: 'New or changed behaviour in the product.',
|
|
128
|
+
input: 'A product requirements document and an evaluation rubric, written before the build.',
|
|
129
|
+
requires: 'A PRD and a rubric, both written before the build.',
|
|
130
|
+
output: 'A pull request that satisfies the rubric.',
|
|
131
|
+
done: 'The build passes the rubric, an explainer is written, and the PM has accepted it.',
|
|
132
|
+
},
|
|
133
|
+
discovery: {
|
|
134
|
+
label: 'Discovery',
|
|
135
|
+
group: 'work',
|
|
136
|
+
when: 'A question to answer before building.',
|
|
137
|
+
input: 'A spike brief: the question and the evidence that would end the spike.',
|
|
138
|
+
requires: 'A spike brief.',
|
|
139
|
+
output: 'Findings that answer the question.',
|
|
140
|
+
done: 'The findings answer the brief and the PM has accepted them.',
|
|
141
|
+
},
|
|
142
|
+
chore: {
|
|
143
|
+
label: 'Chore',
|
|
144
|
+
group: 'work',
|
|
145
|
+
when: 'Upkeep that needs no requirements document.',
|
|
146
|
+
input: 'One paragraph that states the intent.',
|
|
147
|
+
requires: 'One paragraph of intent, written in the record\'s status.',
|
|
148
|
+
output: 'The change.',
|
|
149
|
+
done: 'The change is made and the PM has accepted it.',
|
|
150
|
+
},
|
|
151
|
+
incident: {
|
|
152
|
+
label: 'Incident',
|
|
153
|
+
group: 'work',
|
|
154
|
+
when: 'Something broke and was fixed first.',
|
|
155
|
+
input: 'A record written after the fix: what broke, the cause, the repair.',
|
|
156
|
+
requires: 'An incident record.',
|
|
157
|
+
output: 'The fix and its post-hoc record.',
|
|
158
|
+
done: 'The record states the cause and the repair, and the PM has accepted it.',
|
|
159
|
+
},
|
|
160
|
+
content: {
|
|
161
|
+
label: 'Content',
|
|
162
|
+
group: 'work',
|
|
163
|
+
when: 'Writing or media that ships with the product.',
|
|
164
|
+
input: 'A content brief. A rubric is recommended.',
|
|
165
|
+
requires: 'A content brief. A rubric is optional.',
|
|
166
|
+
output: 'The content.',
|
|
167
|
+
done: 'The content meets the brief and the PM has accepted it.',
|
|
168
|
+
},
|
|
169
|
+
prototype: {
|
|
170
|
+
label: 'Prototype',
|
|
171
|
+
group: 'work',
|
|
172
|
+
when: 'An idea the PM cannot judge from a description.',
|
|
173
|
+
input: 'A quick brief.',
|
|
174
|
+
requires: 'A quick prototype brief.',
|
|
175
|
+
output: '2–3 specimens the PM can look at. A prototype is never scored.',
|
|
176
|
+
done: 'The PM has looked at the specimens and chosen what to do with them.',
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/*
|
|
181
|
+
* What decides each rung. This is the answer to "how does PMOS know this step is done" — one
|
|
182
|
+
* sentence per rung, shown beside the evidence in the detail pane. It restates the engine's test;
|
|
183
|
+
* the engine remains the authority, and the suite checks that every rung the engine emits has a
|
|
184
|
+
* sentence here.
|
|
185
|
+
*/
|
|
186
|
+
const RUNG_RULES = {
|
|
187
|
+
'pm-artifacts': {
|
|
188
|
+
route: 'The lane named in the record is one this repository offers.',
|
|
189
|
+
anchor: 'parent_kr names a KR, a declared health budget, or a domain goal that resolves.',
|
|
190
|
+
brief: 'The file named in brief_path (or prd_path) exists.',
|
|
191
|
+
draft: 'The file named in doc_path exists. On the governed track it did not first appear before the brief.',
|
|
192
|
+
review: 'evals.jsonl holds a verdict for this initiative, or the record names a reviewer in reviewed_by.',
|
|
193
|
+
approved: 'acceptances.jsonl holds an accepted line for this initiative. The PM records it; it is never automatic.',
|
|
194
|
+
handoff: 'handed_off in the record names where the work went.',
|
|
195
|
+
},
|
|
196
|
+
'product-code': {
|
|
197
|
+
route: 'The lane is one this repository offers, and its specimen and surface questions are answered.',
|
|
198
|
+
anchor: 'parent_kr names a KR, a declared health budget, or a domain goal that resolves.',
|
|
199
|
+
prototype: 'A prototype brief first appeared before the PRD, where the specimen test calls for one.',
|
|
200
|
+
understand: 'An explainer for the existing surface first appeared before the PRD.',
|
|
201
|
+
spec: 'The PRD and rubric named in the record exist and first appeared at or before the first build commit.',
|
|
202
|
+
priors: 'The record cites a prior run or states that none applies.',
|
|
203
|
+
contract: 'A run in agent-runs.jsonl holds done criteria and a test method with PM_approved set.',
|
|
204
|
+
build: 'Commits attributed to this initiative change a build path.',
|
|
205
|
+
quality: 'CI decides on the pull request. The engine never claims a test result it did not run.',
|
|
206
|
+
review: 'evals.jsonl holds a Review-Gate verdict for this initiative, or a skip.',
|
|
207
|
+
explain: 'An explainer exists for the run.',
|
|
208
|
+
accept: 'acceptances.jsonl holds an accepted line for this initiative. The PM records it.',
|
|
209
|
+
outcome: 'outcome_checks holds a validated, refuted or inconclusive disposition with evidence.',
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
function defsFor(profile) {
|
|
214
|
+
return profile === 'pm-artifacts' ? PM_ARTIFACTS : PRODUCT_CODE;
|
|
215
|
+
}
|
|
216
|
+
function laneNames(profile) {
|
|
217
|
+
return Object.keys(defsFor(profile));
|
|
218
|
+
}
|
|
219
|
+
function laneDef(profile, lane) {
|
|
220
|
+
return defsFor(profile)[lane] || null;
|
|
221
|
+
}
|
|
222
|
+
function rungRule(profile, key) {
|
|
223
|
+
return (RUNG_RULES[profile] || {})[key] || null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = { PM_ARTIFACTS, PRODUCT_CODE, RUNG_RULES, defsFor, laneNames, laneDef, rungRule };
|