valent-pipeline 0.19.61 → 0.19.63

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valent-pipeline",
3
- "version": "0.19.61",
3
+ "version": "0.19.63",
4
4
  "description": "v3 multi-agent AI pipeline for software development lifecycle",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1951,7 +1951,7 @@ async function runStory(story) {
1951
1951
  // reworks via the QA-B re-execution alone, then falls through to JUDGE at the cap as usual.
1952
1952
  const evGate = await runEvidenceGate(storyId, [])
1953
1953
  recordStage('evidence', evGate)
1954
- const visual = await runVisualGate(storyId, profiles)
1954
+ const visual = await runVisualGate(storyId, profiles, itemType)
1955
1955
  recordStage('visual', visual)
1956
1956
  phase('Judge')
1957
1957
  const decision = await runJudgeGate(storyId, visual, evGate)
@@ -2234,8 +2234,9 @@ async function runStory(story) {
2234
2234
  recordStage('evidence', evGate)
2235
2235
 
2236
2236
  // Visual validation (revived PMCP): for ui-profile stories, produce pmcp-evidence.md so JUDGE's
2237
- // evidence pass has the visual artifact it requires. No-op (returns null) for non-ui stories.
2238
- const visual = await runVisualGate(storyId, profiles)
2237
+ // evidence pass has the visual artifact it requires. No-op (returns null) for non-ui stories, and a
2238
+ // non-blocking N/A for itemType:bug (the QA-A-less bug-fix path mints no checklist — M-192).
2239
+ const visual = await runVisualGate(storyId, profiles, itemType)
2239
2240
  recordStage('visual', visual)
2240
2241
 
2241
2242
  phase('Judge')
@@ -2826,11 +2827,23 @@ async function runStory(story) {
2826
2827
  // exact trigger QA-A uses to produce the checklist (qa-a/write-spec.md Step 9: `ui` in profiles).
2827
2828
  // The agent starts its own dev server: unlike the old always-on topology where QA-B triggered an
2828
2829
  // idle PMCP while QA-B's server was up, here the stages are sequential, so PMCP owns its server.
2829
- async function runVisualGate(sid, storyProfiles) {
2830
+ async function runVisualGate(sid, storyProfiles, sidItemType = 'story') {
2830
2831
  if (!storyProfiles.includes('ui')) {
2831
2832
  log(`${sid}: no ui profile — visual validation N/A (QA-A wrote no checklist; nothing for PMCP to run)`)
2832
2833
  return null
2833
2834
  }
2835
+ // QA-A-less bug-fix path (owner-ruled M-192): a bug-fix item runs bug-intake -> Build -> CRITIC ->
2836
+ // QA-B -> Judge and STRUCTURALLY SKIPS the Spec phase, so QA-A never mints a
2837
+ // visual-validation-checklist.md. Running PMCP against a checklist that can NEVER exist yields a
2838
+ // 0/0 block-fail (onMissingMcp inherited from the parent story) on a path with no checklist to
2839
+ // drive — a config contradiction, not a real visual defect. Treat it as a non-blocking N/A: no
2840
+ // visual coverage is lost because the parent story's `revalidate` re-drives the FULL visual gate
2841
+ // on the merged fix (its checklist exists). A FULL story always runs QA-A, so a missing checklist
2842
+ // THERE stays a real, blocking fault — this scopes the gate down ONLY for itemType:bug.
2843
+ if (sidItemType === 'bug') {
2844
+ log(`${sid}: ui profile but itemType:bug — the QA-A-less bug-fix path mints no visual-validation-checklist.md; visual validation N/A (owner-ruled M-192). The parent story's revalidate re-drives the full visual gate on the merged fix.`)
2845
+ return { schema: 1, agent: 'pmcp', story: sid, verdict: 'na', skipped: true, mcpAvailable: null, totalCheckpoints: 0, passed: 0, failed: 0, naCheckpoints: 0, files: [], notes: 'QA-A-less bug-fix path: no visual-validation-checklist.md minted (Spec phase skipped for itemType:bug); visual gate N/A (owner-ruled M-192). The parent story revalidate re-drives the full visual gate on the merged fix.' }
2846
+ }
2834
2847
  phase('Visual')
2835
2848
  const naMode = visualOnMissingMcp === 'na'
2836
2849
  const result = await spawn('PMCP', 'pmcp.md',
@@ -2920,7 +2933,13 @@ async function runStory(story) {
2920
2933
  : ''
2921
2934
  // A ui story has a PMCP visual pass; tell the evidence agent the result so Step 9 (Verify PMCP
2922
2935
  // Evidence) is grounded rather than guessing whether visual evidence should exist.
2923
- const visualNote = visual
2936
+ const visualNote = visual && visual.skipped
2937
+ ? `\n\nThis is a UI-profile BUG-FIX item: the QA-A-less bug-fix path mints no ` +
2938
+ `visual-validation-checklist.md, so PMCP did NOT run and there is NO pmcp-evidence.md. Treat ` +
2939
+ `PMCP evidence as N/A in Step 9 (no checklist ⟹ visual N/A) — do NOT flag its absence as a ` +
2940
+ `missing required file (owner-ruled M-192). The parent story's revalidate re-drives the full ` +
2941
+ `visual gate on the merged fix.`
2942
+ : visual
2924
2943
  ? `\n\nThis is a UI story: a visual-validation (PMCP) pass already ran and wrote ` +
2925
2944
  `pmcp-evidence.md (verdict: ${visual.verdict}, ${visual.passed || 0}/${visual.totalCheckpoints || 0} ` +
2926
2945
  `checkpoint(s) passed${visual.mcpAvailable === false ? `, browser MCP unavailable` : ''}). ` +
@@ -63,7 +63,25 @@ Follow the on-missing-MCP behavior the orchestrator passed in your trigger:
63
63
  `mcpAvailable: false`, and return — the story proceeds without visual evidence.
64
64
 
65
65
  ### Step 3: Execute checkpoints (MCP available)
66
- Start the dev server. For each checkpoint: navigate to its route, establish the required state (seed
66
+ Start the dev server.
67
+
68
+ **Pre-flight — assert an INTEGER `devicePixelRatio` before driving any interaction.** Once the server
69
+ is up and you have navigated to the app, evaluate `window.devicePixelRatio`. If it is NOT an integer
70
+ (commonly `1.5` when the host display runs Windows/macOS scaling at 150%), the browser's
71
+ coordinate-based `click()`/`fill()` land OFF-TARGET: Playwright reports the click succeeded but the
72
+ app's `onClick`/`onInput` handlers never fire, so you can screenshot STATIC renders yet can NEVER
73
+ drive an interaction or a multi-step / WS flow. **Do NOT misread this as "the browser MCP cannot drive
74
+ WS events," and do NOT FAIL or `na` the interaction checkpoints** — it is an infrastructure config
75
+ bug, not an app or reachability defect (the e2e test runner pins the scale factor, which is why an
76
+ acceptance e2e can drive the same flow the MCP cannot). STOP and record an **infrastructure blocker**
77
+ in `pmcp-evidence.md` (`verdict: fail`, `mcpAvailable: true`) naming the cause and the fix: the
78
+ browser MCP must launch with **`deviceScaleFactor: 1`** (passing a fixed `--viewport-size` defaults
79
+ the scale factor to 1), a project `.mcp.json` / browser-MCP-config change that needs an MCP/session
80
+ **RESTART** to take effect. Static render-only checkpoints may still be captured; mark every
81
+ interaction-dependent checkpoint blocked-by-DPR, not FAIL. A non-integer DPR is the single most common
82
+ cause of "PMCP can render but can't drive."
83
+
84
+ For each checkpoint: navigate to its route, establish the required state (seed
67
85
  data, auth, form values), wait for the expected state using element/network conditions — **never hard
68
86
  waits** — capture a screenshot into `{story_output_dir}` using the checklist's filename convention,
69
87
  and evaluate it against the pass criteria. Record PASS or FAIL per checkpoint. Stop the server when done.
@@ -6,7 +6,7 @@ Runs after bug review (Steps 1-4) approves with no P4->P1-P3 escalations.
6
6
 
7
7
  Read all inputs, record in `inputsRead`. If any REQUIRED file missing, set blocker and STOP.
8
8
 
9
- Required: `execution-report.md`, `traceability-matrix.md`, `bugs.md`, `qa-test-spec.md` — all in `{story_output_dir}/`. Also `pmcp-evidence.md` **if this is a UI story** — i.e. `ui` is in `{testing_profiles}` (equivalently, `visual-validation-checklist.md` exists). If there is no `ui` profile, PMCP evidence is N/A — do NOT treat its absence as a missing required file.
9
+ Required: `execution-report.md`, `traceability-matrix.md`, `bugs.md`, `qa-test-spec.md` — all in `{story_output_dir}/`. Also `pmcp-evidence.md` **if this is a UI story** — i.e. `ui` is in `{testing_profiles}` **AND** `visual-validation-checklist.md` exists. The checklist's existence is the operative trigger: a `ui`-profile item with **no** `visual-validation-checklist.md` has PMCP **N/A** — do NOT treat the absence of `pmcp-evidence.md` as a missing required file. This is exactly the **QA-A-less bug-fix path** (an `itemType:bug` fix runs bug-intake → Build → CRITIC → QA-B → Judge and structurally skips the Spec phase, so QA-A mints no checklist); its visual coverage is re-driven in full by the parent story's `revalidate` on the merged fix (owner-ruled M-192). If there is no `ui` profile at all, PMCP evidence is likewise N/A.
10
10
 
11
11
  **Machine evidence (when `stories/{story_id}/evidence/` exists — required in that case):** the newest JSON under `evidence/asserts/` (the deterministic green-gate's verdict), `evidence/pins.jsonl` (which commit each gate reviewed), and the run records under `evidence/runs/` (frozen junit reports + hashes, written only by the CLI). **ATDD stories add** `evidence/atdd-red.json` (the pre-implementation failing run: per-case statuses, the pre-dev SHA, the acceptance-source snapshot hashes) and — for a proven story — `evidence/proof.json` (red run + green run + the CLI-hashed diff between: the story's headline evidence). These are the authoritative numbers — the markdown artifacts are the human-readable companion. If the evidence directory does not exist, this is a LEGACY story: apply the legacy fallbacks below and flag every count as self-reported.
12
12