amsd-pipeline-workflow 0.1.29 → 0.1.31

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/driver/run.js CHANGED
@@ -469,8 +469,17 @@ async function phaseRunner(ctx, lane, laneEnv, { prd, phase, args, tag, lineSlug
469
469
  // reviewed, locked (operator, 2026-10-20); an approved one is locked and not touched
470
470
  const toReview = env.EPAM_RESUME_RUN ? ((p.implementationOrder || {})[phase] || []).map((id) => p.stories.find((s) => s.id === id))
471
471
  .filter((s) => s && s.completed === true && s.status !== 'deprecated' && s.agentRole !== 'review-agent')
472
- .filter((s) => { const rec = reviewRecord(ctx, lane, env, s.id, lineSlug); return !(rec && rec.verdict === 'approved'); }) : [];
473
- for (const s of toReview) log(`[driver] ${s.id}: committed but never reviewed — its review judges the committed change; nothing is rewritten`);
472
+ .filter((s) => {
473
+ const rec = reviewRecord(ctx, lane, env, s.id, lineSlug); if (!(rec && rec.verdict === 'approved')) return true;
474
+ // THE OPERATOR LIFTS THE LOCK (2026-10-21: "yes rewrite it is not good code"): approved work is judged again by the current
475
+ // reviewer; a rejection sends it back to the writer with the findings, as any rejection does
476
+ if (env.EPAM_REREVIEW_APPROVED === '1') { s.rereview = rec.from; return true; }
477
+ return false;
478
+ }) : [];
479
+ for (const s of toReview) {
480
+ log(s.rereview ? `[driver] ${s.id}: approved earlier — judged again by the current reviewer (EPAM_REREVIEW_APPROVED=1, ${s.rereview}); a rejection goes back to the writer`
481
+ : `[driver] ${s.id}: committed but never reviewed — its review judges the committed change; nothing is rewritten`);
482
+ }
474
483
  if (order.length && env.EPAM_BROWNFIELD === '1') bash(env, 'ensure_story_branch', [lane.wt, order[0].id, env.JIRA_BASELINE_BRANCH || ''], { log });
475
484
  // RAO:2653–2654 — THE LANE'S PHASE BASELINE (lib/qa-gate-evidence.sh qa_record_phase_baseline: the fork point from the
476
485
  // base branch) in the lane's log, where the release lines read the main line's change from (lib/release-lines.sh:69–74)
@@ -313,6 +313,16 @@ function main(a) {
313
313
  // retry budget plus one more per review cycle (lib/review-cycle.sh), each on every model the ladder can reach — has its
314
314
  // own copy of the writer, the failure analyst and the rung-entry step runner, identical but for the values their hooks
315
315
  // are given (the copy's retry; the writer's model; the model the previous attempt ran on).
316
+ // THE MODEL THE REVIEW RUNS ON: the shared policy (config/reviewer-policy.json), read by the SAME reader the bash reviewer calls (lib/reviewer-model.js in the install —
317
+ // team-lead-review.sh reviewer_model_for), so the two pipelines cannot differ. null = the writer's rung model (policy 'writer-rung', or an install without the policy).
318
+ // Run 11 (2026-10-21): on the writer's Sonnet rung the reviewer rated a thin and a rich delivery alike (9, 9); on Opus it separated them (6, 7.5).
319
+ const reviewerModel = (() => {
320
+ const lib = path.join(a.install, 'orchestrations', 'scripts', 'lib', 'reviewer-model.js');
321
+ if (!fs.existsSync(lib)) return null;
322
+ const r = spawnSync(process.execPath, [lib, ''], { encoding: 'utf8', env: { ...process.env, ...launchValues(a.launchEnv || {}), EPAM_PROVIDER_SET: a.set || 'claude' } });
323
+ if (r.status !== 0) { process.stderr.write(`[generate] the reviewer's model policy could not be read — reviewing on the writer's model: ${(r.stderr || '').trim()}\n`); return null; }
324
+ return r.stdout.trim() || null;
325
+ })();
316
326
  const reviewMaxCycles = maxRetries + 3;
317
327
  const lastAttempt = maxRetries + reviewMaxCycles;
318
328
  const models = [...new Set([lad.start.model, ...Object.values(lad.steps).map((v) => v.model)])];
@@ -562,6 +572,7 @@ function main(a) {
562
572
  where: "this workflow run's journal (it records the full prompt of every attempt)" },
563
573
  // lib/review-cycle.sh: REVIEW_MAX_CYCLES defaults to EPAM_MAX_RETRIES + 3.
564
574
  reviewMaxCycles,
575
+ reviewerModel,
565
576
  prompts: {
566
577
  'writer.first': fs.readFileSync(path.join(a.out, 'prompts', 'writer.first.md'), 'utf8'),
567
578
  'writer.retry': fs.readFileSync(path.join(a.out, 'prompts', 'writer.retry.md'), 'utf8'),
@@ -972,8 +972,8 @@ for (; attempt <= budget; attempt++) {
972
972
  for (;;) {
973
973
  r = await agentCall(fill(PLAN.prompts.reviewer, { ...base, story_acs: noTrail(criteriaBlock(state.acs, 'ACCEPTANCE CRITERIA:')),
974
974
  prior_review: priorReviews(), story_diff: checks.storyDiff, test_files: checks.testFiles, uncovered_vc_block: uncoveredVc !== null ? uncoveredVc : checks.uncoveredVc }),
975
- // team-lead-review.sh: on the writer's model (the rung that produced this work); effort stays the reviewer's own.
976
- { agentType: PLAN.agents.reviewer, model: rung.model, schema: SCHEMAS.review, label: \`review #\${reviews.length + 1}\`, phase: 'Review' })
975
+ // team-lead-review.sh reviewer_model_for: the shared policy's model (PLAN.reviewerModel — the reader the bash reviewer calls), else the writer's model (the rung that produced this work); effort stays the reviewer's own.
976
+ { agentType: PLAN.agents.reviewer, model: PLAN.reviewerModel || rung.model, schema: SCHEMAS.review, label: \`review #\${reviews.length + 1}\`, phase: 'Review' })
977
977
  if (r !== null) { noVerdict = 0; reviews.push({ verdict: r.verdict, issues: r.issues || [] }); break }
978
978
  reviews.push({ reviewIncomplete: true })
979
979
  noVerdict++
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amsd-pipeline-workflow",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "description": "The AMSD pipeline as Claude workflows. Installed by the amsd-pipeline installer: install.sh --workflows",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {