process: derived artifacts are accepted on dev once per beta (#697)

The screenshot fingerprint and golden baselines stop being a tax on every
task branch:

- Task branches no longer commit docs/images/** or golden baselines. On a
  branch the screenshot freshness stays a preflight warning; the review
  prompt, REVIEWER.md and AUTHOR.md drop check-docs as a per-task gate.
- beta-derived.yml refreshes them on dev in one bot commit before the beta
  candidate: canonical docs capture + docs:accept --reviewed, golden from
  the golden-images artifact of a completed Validate on dev +
  golden:accept --reviewed. A changed frame or scene is accepted only when
  named in the inputs; undeclared differences refuse. Baseline commits carry
  Release: and Baseline-Reviewed:; the subject is not a candidate subject.
- classify-changes: the Release: trailer on an issue/* branch no longer
  switches on the heavy set. ci:full / ci:golden do: process-track emits
  full=true, the review gate dispatches Validate with full=true and does not
  accept a light proof.

Canon: PROCESS.md §3 п.13, §5.1, §8, §11.4; CONTRIBUTING.md.

Issue: #697
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
This commit is contained in:
Claude
2026-09-28 23:38:50 +03:00
parent c716bb0f63
commit 2a62ad5b95
15 changed files with 490 additions and 63 deletions
+18 -2
View File
@@ -21,8 +21,8 @@ test('пакет задачи и конвейер читают трек одно
test('явная трековая метка главнее признака инфраструктуры (#696)', () => {
const infra = ['scripts/x.mjs', '.github/workflows/y.yml'];
assert.deepEqual(resolveTrack({ labels: ['track:ask'], files: infra }), { track: 'ask', mutants: true, infrastructure: true });
assert.deepEqual(resolveTrack({ labels: ['track:ship'], files: ['src/a.ts'] }), { track: 'ship', mutants: false, infrastructure: false });
assert.deepEqual(resolveTrack({ labels: ['track:ask'], files: infra }), { track: 'ask', mutants: true, full: false, infrastructure: true });
assert.deepEqual(resolveTrack({ labels: ['track:ship'], files: ['src/a.ts'] }), { track: 'ship', mutants: false, full: false, infrastructure: false });
assert.equal(resolveTrack({ labels: ['small'], files: ['src/a.ts'] }).track, 'show');
});
@@ -168,3 +168,19 @@ test('конвейер: ship в рамках сливается без моде
assert.match(env, /if: steps\.env_needs\.outputs\.deps == 'true'\n\s+run: npm ci/);
assert.match(env, /if: steps\.env_needs\.outputs\.browser == 'true' && steps\.pw\.outputs\.cache-hit != 'true'/);
});
test('#697: полный набор на ветке задачи — только по меткам ci:full и ci:golden', () => {
assert.equal(resolveTrack({ labels: ['track:show'], files: ['src/a.ts'] }).full, false);
assert.equal(resolveTrack({ labels: ['track:show', 'ci:golden'], files: ['src/a.ts'] }).full, true);
assert.equal(resolveTrack({ labels: ['track:ask', 'ci:full'], files: ['src/a.ts'] }).full, true);
assert.equal(resolveTrack({ labels: ['ci:mutants'], files: ['src/a.ts'] }).full, false, 'мутанты полного набора не заказывают');
});
test('#697: конвейер передаёт полный набор гейту материала', async () => {
const { readFileSync } = await import('node:fs');
const workflow = readFileSync(WORKFLOW, 'utf8');
const gate = workflow.slice(workflow.indexOf(' - name: Validate на материале\n'), workflow.indexOf(' - name: Validate идёт — раунд продолжит событие\n'));
assert.match(gate, /FULL: \$\{\{ steps\.track\.outputs\.full \}\}/);
assert.match(gate, /--full="\$\{FULL:-false\}"/);
assert.match(workflow, /full=\$\(printf '%s\\n' "\$out" \| sed -n 's\/\^full=\/\/p'\)/);
});