feat(voyage)!: rename produced_by field values + validator comments [skip-docs]

- commands/trekexecute.md: produced_by literals -> trekexecute (4 occurrences)
- commands/trekendsession.md: produced_by literals -> trekendsession (2 occurrences)
- tests/validators/next-session-prompt-validator.test.mjs: 11 'ultraexecute-local' refs -> 'trekexecute'
- tests/commands/trekcontinue.test.mjs: 3 fixture strings updated
- tests/lib/cleanup.test.mjs: 1 fixture string updated
- lib/validators/next-session-prompt-validator.mjs: producer-list comment
- docs/HANDOVER-CONTRACTS.md line 432: example producer names updated

Part of voyage-rebrand session 2 (W3.4 / Step 6).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-05 14:42:21 +02:00
commit 5f74a670ab
7 changed files with 24 additions and 24 deletions

View file

@ -114,7 +114,7 @@ Under `node --input-type=module -e "<script>" arg1 arg2 arg3`, Node sets
`process.argv[1]`. Adjust the destructure if your Node version differs.
This phase ALSO writes a sibling `NEXT-SESSION-PROMPT.local.md` in the
project directory with YAML frontmatter (`produced_by: ultraplan-end-session-local`,
project directory with YAML frontmatter (`produced_by: trekendsession`,
`produced_at: <ISO-8601>`, `project: <project-dir>`). Both files are written
in a single ESM block so the writes succeed or fail together:
@ -129,7 +129,7 @@ const stateObj = { schema_version: 1, project: dir, next_session_brief_path: bri
const stateFile = path.join(dir, '.session-state.local.json');
atomicWriteJson(stateFile, stateObj);
const promptFile = path.join(dir, 'NEXT-SESSION-PROMPT.local.md');
const promptBody = '---\\nproduced_by: ultraplan-end-session-local\\nproduced_at: ' + now + '\\nproject: ' + dir + '\\n---\\n\\n# ' + label + '\\n\\nResume via /ultracontinue.\\n';
const promptBody = '---\\nproduced_by: trekendsession\\nproduced_at: ' + now + '\\nproject: ' + dir + '\\n---\\n\\n# ' + label + '\\n\\nResume via /ultracontinue.\\n';
writeFileSync(promptFile, promptBody);
console.log(stateFile);
console.log(promptFile);

View file

@ -415,7 +415,7 @@ Verify with `node lib/validators/session-state-validator.mjs --json
to stderr but do NOT block the stop; `progress.json` is still authoritative.
**Also write sibling `NEXT-SESSION-PROMPT.local.md`** with frontmatter
(`produced_by: ultraexecute-local`, `produced_at: <ISO-8601>`,
(`produced_by: trekexecute`, `produced_at: <ISO-8601>`,
`status: stopped`) so the next-session producer-mismatch check has both
candidates available. Use the same combined ESM block pattern as Phase 8.
@ -904,7 +904,7 @@ write pattern + validator check as Phase 2.55. On validator failure, warn
but do not block.
**Also write sibling `NEXT-SESSION-PROMPT.local.md`** with frontmatter
(`produced_by: ultraexecute-local`, `produced_at: <ISO-8601>`,
(`produced_by: trekexecute`, `produced_at: <ISO-8601>`,
`status: stopped`) — same combined ESM pattern as Phase 8 — so Phase 1.5
of `/ultracontinue` can compare project-dir and plugin-root candidates.
@ -1352,7 +1352,7 @@ to stderr but do NOT block — Phase 8 must always reach the final report.
**Also write sibling `NEXT-SESSION-PROMPT.local.md`** (Bug 3 frontmatter
contract — see `docs/HANDOVER-CONTRACTS.md` § Handover 7 Lifecycle) in the
project directory. The frontmatter MUST contain `produced_by: ultraexecute-local`
project directory. The frontmatter MUST contain `produced_by: trekexecute`
and `produced_at: <ISO-8601>` so `/ultracontinue` Phase 1.5 can detect
producer drift between project-dir and plugin-root candidates. Use a single
ESM inline block so state-file + prompt-file writes succeed or fail together:
@ -1366,7 +1366,7 @@ const [, dir, briefPath, label, status] = process.argv;
const now = new Date().toISOString();
const stateObj = { schema_version: 1, project: dir, next_session_brief_path: briefPath, next_session_label: label, status, updated_at: now };
atomicWriteJson(path.join(dir, '.session-state.local.json'), stateObj);
const promptBody = '---\\nproduced_by: ultraexecute-local\\nproduced_at: ' + now + '\\nproject: ' + dir + '\\nstatus: ' + status + '\\n---\\n\\n# ' + label + '\\n\\nResume via /ultracontinue.\\n';
const promptBody = '---\\nproduced_by: trekexecute\\nproduced_at: ' + now + '\\nproject: ' + dir + '\\nstatus: ' + status + '\\n---\\n\\n# ' + label + '\\n\\nResume via /ultracontinue.\\n';
writeFileSync(path.join(dir, 'NEXT-SESSION-PROMPT.local.md'), promptBody);
" '{project_dir}' '{next_session_brief_path}' '{next_session_label}' '{status}'`
```

View file

@ -429,7 +429,7 @@ The state file follows a producer/consumer separation that keeps responsibilitie
**Frontmatter contract for `NEXT-SESSION-PROMPT.local.md`:** Producers MUST write a YAML frontmatter block on the prompt file with at minimum:
- `produced_by:` — string identifying the producer (e.g. `ultraplan-local-A4-session`, `ultraexecute-local-phase-8`, `ultraplan-end-session-local`)
- `produced_by:` — string identifying the producer (e.g. `trekplan-A4-session`, `trekexecute-phase-8`, `trekendsession`)
- `produced_at:` — ISO-8601 timestamp of when the file was written
The `next-session-prompt-validator` (`lib/validators/next-session-prompt-validator.mjs`) cross-checks `produced_at` against the sibling state file's `updated_at` and emits a `NEXT_SESSION_PROMPT_INCONSISTENT` error when the prompt is older than the state — that means the prompt has not been refreshed for the current session and is stale. Files **without** any frontmatter are tolerated (warning, not error) for backwards compatibility with v3.3.x and earlier hand-rolled prompt files; this is consistent with Handover 3's drift-WARN posture.

View file

@ -1,8 +1,8 @@
// lib/validators/next-session-prompt-validator.mjs
// Validate NEXT-SESSION-PROMPT.local.md frontmatter (Bug 3 contract).
//
// Producers (ultraexecute-local Phase 8/2.55/4, ultraplan-end-session-local
// Phase 3) MUST write `produced_by:` and `produced_at:` (ISO-8601) frontmatter.
// Producers (trekexecute Phase 8/2.55/4, trekendsession Phase 3) MUST write
// `produced_by:` and `produced_at:` (ISO-8601) frontmatter.
// Consumers (/ultracontinue Phase 1.5) compare two candidate files and refuse
// when producers disagree on a non-stale pair.
//

View file

@ -210,7 +210,7 @@ test('ultracontinue Bug 3 (e) — CLI consistency mode flags producer mismatch i
// Project-dir prompt: produced_by ultraexecute-local at T-1
const projectPrompt = join(projectDir, 'NEXT-SESSION-PROMPT.local.md');
writeFileSync(projectPrompt,
'---\nproduced_by: ultraexecute-local\nproduced_at: 2026-05-04T15:30:00.000Z\n---\n\n# Session 2\n');
'---\nproduced_by: trekexecute\nproduced_at: 2026-05-04T15:30:00.000Z\n---\n\n# Session 2\n');
// Plugin-root prompt: produced_by graceful-handoff at T-0 (newer)
const pluginPrompt = join(root, 'NEXT-SESSION-PROMPT.local.md');
@ -303,7 +303,7 @@ test('ultracontinue Bug 4 (f-1) dry-run lists candidates without deleting', asyn
updated_at: '2026-05-04T16:00:00.000Z',
}, null, 2));
writeFileSync(join(dir, 'NEXT-SESSION-PROMPT.local.md'),
'---\nproduced_by: ultraexecute-local\nproduced_at: 2026-05-04T16:00:00.000Z\n---\n\n# Done\n');
'---\nproduced_by: trekexecute\nproduced_at: 2026-05-04T16:00:00.000Z\n---\n\n# Done\n');
const r = cleanupProject(dir, { dryRun: true });
assert.equal(r.valid, true, JSON.stringify(r.errors));
assert.equal(r.parsed.wouldDelete.length, 2);
@ -330,7 +330,7 @@ test('ultracontinue Bug 4 (f-2) confirm deletes and (f-3) idempotent re-run hand
updated_at: '2026-05-04T16:00:00.000Z',
}, null, 2));
writeFileSync(join(dir, 'NEXT-SESSION-PROMPT.local.md'),
'---\nproduced_by: ultraexecute-local\nproduced_at: 2026-05-04T16:00:00.000Z\n---\n\n# Done\n');
'---\nproduced_by: trekexecute\nproduced_at: 2026-05-04T16:00:00.000Z\n---\n\n# Done\n');
// f-2: confirm deletes
const r2 = cleanupProject(dir, { dryRun: false, confirm: true });

View file

@ -20,7 +20,7 @@ function buildProject(dir, status) {
};
writeFileSync(join(dir, '.session-state.local.json'), JSON.stringify(stateObj, null, 2));
writeFileSync(join(dir, 'NEXT-SESSION-PROMPT.local.md'),
`---\nproduced_by: ultraexecute-local\nproduced_at: 2026-05-04T16:00:00.000Z\n---\n\n# Done\n`);
`---\nproduced_by: trekexecute\nproduced_at: 2026-05-04T16:00:00.000Z\n---\n\n# Done\n`);
return dir;
}

View file

@ -21,10 +21,10 @@ function frontmatter(producedBy, producedAt, extra = '') {
}
test('validateNextSessionPromptContent — both consistent producers (valid)', () => {
const text = frontmatter('ultraexecute-local', '2026-05-04T16:00:00.000Z');
const text = frontmatter('trekexecute', '2026-05-04T16:00:00.000Z');
const r = validateNextSessionPromptContent(text);
assert.equal(r.valid, true, JSON.stringify(r.errors));
assert.equal(r.parsed.produced_by, 'ultraexecute-local');
assert.equal(r.parsed.produced_by, 'trekexecute');
});
test('validateNextSessionPromptObject — missing produced_by is invalid', () => {
@ -34,7 +34,7 @@ test('validateNextSessionPromptObject — missing produced_by is invalid', () =>
});
test('validateNextSessionPromptObject — missing produced_at is invalid', () => {
const r = validateNextSessionPromptObject({ produced_by: 'ultraexecute-local' });
const r = validateNextSessionPromptObject({ produced_by: 'trekexecute' });
assert.equal(r.valid, false);
assert.ok(r.errors.find(e => e.code === 'NEXT_SESSION_PROMPT_MISSING_FIELD' && /produced_at/.test(e.message)));
});
@ -52,7 +52,7 @@ test('validateNextSessionPromptContent — no frontmatter downgrades to warning
});
test('validateNextSessionPromptConsistency — producer mismatch with both fresh fails', () => {
const a = { path: '/a', parsed: { produced_by: 'ultraexecute-local', produced_at: '2026-05-04T16:00:00.000Z' } };
const a = { path: '/a', parsed: { produced_by: 'trekexecute', produced_at: '2026-05-04T16:00:00.000Z' } };
const b = { path: '/b', parsed: { produced_by: 'graceful-handoff', produced_at: '2026-05-04T16:05:00.000Z' } };
const state = { updated_at: '2026-05-04T15:00:00.000Z' };
const r = validateNextSessionPromptConsistency(a, b, { state, now: Date.parse('2026-05-04T16:30:00.000Z') });
@ -62,7 +62,7 @@ test('validateNextSessionPromptConsistency — producer mismatch with both fresh
test('validateNextSessionPromptConsistency — state-anchored stale candidate ignored', () => {
const a = { path: '/a', parsed: { produced_by: 'graceful-handoff', produced_at: '2026-05-03T10:00:00.000Z' } };
const b = { path: '/b', parsed: { produced_by: 'ultraexecute-local', produced_at: '2026-05-04T16:05:00.000Z' } };
const b = { path: '/b', parsed: { produced_by: 'trekexecute', produced_at: '2026-05-04T16:05:00.000Z' } };
const state = { updated_at: '2026-05-04T16:00:00.000Z' };
const r = validateNextSessionPromptConsistency(a, b, { state, now: Date.parse('2026-05-04T16:30:00.000Z') });
assert.equal(r.valid, true, JSON.stringify(r.errors));
@ -70,16 +70,16 @@ test('validateNextSessionPromptConsistency — state-anchored stale candidate ig
});
test('validateNextSessionPromptConsistency — 24h wall-clock drift emits soft warning', () => {
const a = { path: '/a', parsed: { produced_by: 'ultraexecute-local', produced_at: '2026-05-01T16:00:00.000Z' } };
const b = { path: '/b', parsed: { produced_by: 'ultraexecute-local', produced_at: '2026-05-01T16:00:00.000Z' } };
const a = { path: '/a', parsed: { produced_by: 'trekexecute', produced_at: '2026-05-01T16:00:00.000Z' } };
const b = { path: '/b', parsed: { produced_by: 'trekexecute', produced_at: '2026-05-01T16:00:00.000Z' } };
const r = validateNextSessionPromptConsistency(a, b, { now: Date.parse('2026-05-04T16:30:00.000Z') });
assert.equal(r.valid, true);
assert.ok(r.warnings.find(w => w.code === 'NEXT_SESSION_PROMPT_WALL_CLOCK_DRIFT'));
});
test('validateNextSessionPromptConsistency — same producer, both fresh, no errors', () => {
const a = { path: '/a', parsed: { produced_by: 'ultraexecute-local', produced_at: '2026-05-04T16:00:00.000Z' } };
const b = { path: '/b', parsed: { produced_by: 'ultraexecute-local', produced_at: '2026-05-04T16:01:00.000Z' } };
const a = { path: '/a', parsed: { produced_by: 'trekexecute', produced_at: '2026-05-04T16:00:00.000Z' } };
const b = { path: '/b', parsed: { produced_by: 'trekexecute', produced_at: '2026-05-04T16:01:00.000Z' } };
const r = validateNextSessionPromptConsistency(a, b, { now: Date.parse('2026-05-04T16:30:00.000Z') });
assert.equal(r.valid, true);
assert.deepEqual(r.errors, []);
@ -91,7 +91,7 @@ test('CLI shim — single-file mode returns JSON for valid file', () => {
const dir = mkdtempSync(join(tmpdir(), 'nspv-cli-'));
try {
const file = join(dir, 'NEXT-SESSION-PROMPT.local.md');
writeFileSync(file, frontmatter('ultraexecute-local', '2026-05-04T16:00:00.000Z'));
writeFileSync(file, frontmatter('trekexecute', '2026-05-04T16:00:00.000Z'));
const out = execFileSync(process.execPath, [
'lib/validators/next-session-prompt-validator.mjs',
'--json',
@ -109,7 +109,7 @@ test('CLI shim — consistency mode flags producer mismatch', () => {
try {
const a = join(dir, 'a.md');
const b = join(dir, 'b.md');
writeFileSync(a, frontmatter('ultraexecute-local', '2026-05-04T16:00:00.000Z'));
writeFileSync(a, frontmatter('trekexecute', '2026-05-04T16:00:00.000Z'));
writeFileSync(b, frontmatter('graceful-handoff', '2026-05-04T16:01:00.000Z'));
let exitCode = 0;
let out = '';