docs(voyage): S5 — formalize Handover 1 brief-schema as public contract (v5.4)
Elevate Handover 1 (brief.md → research) from an internal pipeline handover to an explicit PUBLIC CONTRACT — the only public producer↔Voyage integration boundary (Trinity asymmetry invariant: Voyage stays unaware of upstream tiers; any compatible producer may feed it; no producer privileged). Scope = freeze + document (operator-gated, option A). No schema change, no plugin version bump (that is S10 RELEASE). Per S3, phase_signals stays optional and brief_version 2.1 is the frozen public-contract baseline. - docs/HANDOVER-CONTRACTS.md: PUBLIC CONTRACT label + callout on Handover 1 (asymmetry, breaking-for-downstream, additive-vs-breaking, frozen 2.1 baseline); resolve the speculative "v5.4 may promote phase_signals to required → 3.0" line to the S3 freeze decision; fix stale schema-table baseline 2.0 → 2.1; annotate the Stability summary row (symmetric with Handover 3's "external" flag). - CLAUDE.md: Trinity note now points at docs/HANDOVER-CONTRACTS.md §Handover 1. - tests/lib/doc-consistency.test.mjs: +4 failing-first doc-truth pins (Iron Law) — PUBLIC CONTRACT label, callout + breaking-for-downstream guarantee, frozen 2.1 baseline (no stale 2.0), freeze-not-promote. 586/584 pass/0 fail/2 skip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
This commit is contained in:
parent
fdd3ad80d7
commit
fa23b16443
3 changed files with 43 additions and 5 deletions
|
|
@ -6,7 +6,7 @@ Voyage — a contract-driven Claude Code pipeline: brief, research, plan, execut
|
|||
|
||||
> **v3.0.0 — architect step extracted from this plugin.** The plan command still auto-discovers `architecture/overview.md` if present, so any compatible producer (architect plugin no longer publicly distributed; the architecture/overview.md slot remains available for any compatible producer) plugs into the same slot. See [CHANGELOG.md](CHANGELOG.md) for migration history.
|
||||
|
||||
> **Trinity context (2026-05-13, informational).** Voyage is Tier 1 (per-task) of a three-tier architecture in active design under the author's private marketplace: Tier 2 `app-creator` (per-app — "what does the app need, what's the next brief?") produces briefs Voyage consumes; Tier 3 `app-factory` (per-portfolio — "which app needs me now?") aggregates state across multiple app-creator instances. Both are pre-implementation and will ship to Forgejo when ready. **Asymmetry is a hard invariant:** Voyage stays unaware of Tier 2/3. Handover 1 (brief format) is the only integration point — any compatible producer can feed Voyage, app-creator is not privileged. Brief-schema changes are therefore breaking changes for downstream consumers, formalized as a public contract in v5.4.
|
||||
> **Trinity context (2026-05-13, informational).** Voyage is Tier 1 (per-task) of a three-tier architecture in active design under the author's private marketplace: Tier 2 `app-creator` (per-app — "what does the app need, what's the next brief?") produces briefs Voyage consumes; Tier 3 `app-factory` (per-portfolio — "which app needs me now?") aggregates state across multiple app-creator instances. Both are pre-implementation and will ship to Forgejo when ready. **Asymmetry is a hard invariant:** Voyage stays unaware of Tier 2/3. Handover 1 (brief format) is the only integration point — any compatible producer can feed Voyage, app-creator is not privileged. Brief-schema changes are therefore breaking changes for downstream consumers, formalized as a public contract in v5.4 — see `docs/HANDOVER-CONTRACTS.md` §Handover 1 (PUBLIC CONTRACT).
|
||||
|
||||
> **Cross-cutting invariant: brief framing must match operator intent (2026-05-15).** Etablert etter residiv. Briefen er pipelinens source of truth; operatørens intent lever i hodet + i memory-filer (`feedback_*`, `project_*`); pipelinen tvinger ikke alignment. Høyere reasoning-kraft polerer feil premiss istedenfor å utfordre det. **Tre lag av forsvar (input-siden), alle BLOCKER ved brudd når v5.5 shipper:** (1) eksplisitt `framing: preserve|refine|replace|new-direction` i brief-frontmatter, `AskUserQuestion`-validert før brief-prosa skrives; (2) memory-alignment check som ny dimensjon i `brief-reviewer` — sammenlikner brief-prosa mot relevante memory-filer og rapporterer eksplisitte motsigelser; (3) obligatorisk `## TL;DR`-seksjon (≤ 5 linjer) øverst i `brief.md`. Implementeres i v5.5 (tracket i `STATE.md` § NESTE STEG når aktivt). Inntil shipping: operatør må manuelt sjekke at briefens framingord ikke motsier intent, særlig etter avvist iterasjon hvor "delta fra forrige" er en farlig default-ankring.
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ Every validator exposes a CLI: `node lib/validators/<name>.mjs --json <path>` re
|
|||
|
||||
---
|
||||
|
||||
## Handover 1 — `brief.md` → research/
|
||||
## Handover 1 — `brief.md` → research/ (PUBLIC CONTRACT)
|
||||
|
||||
**Stability tier: PUBLIC CONTRACT.** Handover 1 is the *only* public integration boundary of the pipeline: `brief.md` is what an upstream producer hands to Voyage, and Voyage consumes it without any knowledge of who produced it. This asymmetry is a hard invariant (see `CLAUDE.md` §Trinity context) — the interactive `/trekbrief` interview is just one producer; a `manual` brief, or an external per-app / per-portfolio producer, is equally valid as long as the artifact conforms to the schema below. No producer is privileged. The consequence: changing this schema — renaming or removing a field, narrowing an enum, or promoting an optional field to required — is a **breaking change for every downstream consumer** and MUST follow the [breaking-change protocol](#breaking-change-protocol) (version bump + N-1 compatibility window). Additive *optional* fields are non-breaking by design: the validator tolerates unknown frontmatter keys silently (forward-compat), so a newer brief still validates against an older consumer. As of the v5.4 contract formalization, `brief_version` **2.1** is the frozen public-contract baseline.
|
||||
|
||||
**Producer:** `/trekbrief` Phase 4g (after `brief-reviewer` stop-gate passes or iteration cap is hit).
|
||||
|
||||
|
|
@ -56,7 +58,7 @@ Every validator exposes a CLI: `node lib/validators/<name>.mjs --json <path>` re
|
|||
| Field | Type | Required | Allowed values | Notes |
|
||||
|---|---|---|---|---|
|
||||
| `type` | string | yes | `trekbrief` | Hard-coded discriminator |
|
||||
| `brief_version` | string | yes | `"2.0"` (current) | Bump on schema change |
|
||||
| `brief_version` | string | yes | `"2.1"` (current) | Bump on schema change |
|
||||
| `created` | date | yes | YYYY-MM-DD | |
|
||||
| `task` | string | yes | one-line description | |
|
||||
| `slug` | string | yes | URL-safe slug | Used in project_dir |
|
||||
|
|
@ -91,7 +93,7 @@ Optional but standard sections: `## Non-Goals`, `## Constraints`, `## Preference
|
|||
|
||||
**State machine** detail: a brief that says it has research topics but skipped them must explicitly admit it (via `brief_quality: partial`). This is the most common failure mode the validator catches.
|
||||
|
||||
**Versioning:** current is `2.1` (v5.1 — adds optional `phase_signals` + `phase_signals_partial`). The forward-compat policy in `brief-validator.mjs` header still applies: unknown frontmatter keys flow through silently, so a `2.1` brief still validates against pre-v5.1 consumers. The version bump exists because v2.1 activates the **version-conditional sequencing gate** (above) — the only check in the validator that triggers on `brief_version` rather than field-presence. There are no live `1.x` briefs; remove legacy paths in next major. v5.4 may promote `phase_signals` from optional to required (breaking change → `3.0`).
|
||||
**Versioning:** current is `2.1` (v5.1 — adds optional `phase_signals` + `phase_signals_partial`). The forward-compat policy in `brief-validator.mjs` header still applies: unknown frontmatter keys flow through silently, so a `2.1` brief still validates against pre-v5.1 consumers. The version bump exists because v2.1 activates the **version-conditional sequencing gate** (above) — the only check in the validator that triggers on `brief_version` rather than field-presence. There are no live `1.x` briefs; remove legacy paths in next major. The v5.4 contract formalization **freezes this schema as the public-contract baseline** (see the PUBLIC CONTRACT callout under the Handover 1 heading): per the S3 effort-axis decision, `phase_signals` stays **optional**, and the v2.1 sequencing gate (`phase_signals` **or** `phase_signals_partial`) is the stability mechanism. Promoting `phase_signals` to required would be a future breaking change (→ `3.0`) under the protocol above — explicitly *not* part of v5.4.
|
||||
|
||||
**Failure modes:**
|
||||
- `BRIEF_NOT_FOUND` → consumer halts with a usage message
|
||||
|
|
@ -451,7 +453,7 @@ The `next-session-prompt-validator` (`lib/validators/next-session-prompt-validat
|
|||
|
||||
| Handover | Validation strength | Owner | Risk |
|
||||
|---|---|---|---|
|
||||
| 1. brief → research | strict at write, soft at read | this plugin | low |
|
||||
| 1. brief → research | strict at write, soft at read | this plugin (**PUBLIC CONTRACT** — producer-facing) | low |
|
||||
| 2. research → plan | soft, drift-warn | this plugin | low |
|
||||
| 3. architecture → plan | discovery-only, drift-WARN | **external** (opt-in architect plugin, not bundled) | low — by design we tolerate drift |
|
||||
| 4. plan → execute | **strict, both ends** | this plugin | medium — Opus 4.7 narrative drift requires constant vigilance |
|
||||
|
|
|
|||
|
|
@ -620,3 +620,39 @@ test('v5.1.1 — commands/trekexecute.md contains ### High-effort behavior (v5.1
|
|||
assert.match(t, /^### High-effort behavior \(v5\.1\.1\)$/m,
|
||||
'trekexecute.md must contain ### High-effort behavior (v5.1.1) sub-section under Composition rule (gates_mode = closed)');
|
||||
});
|
||||
|
||||
// --- v5.4 — brief.md formalized as PUBLIC CONTRACT (Handover 1) ---
|
||||
// S5: the brief schema is the only public producer↔Voyage integration boundary
|
||||
// (Trinity asymmetry invariant). These pin the formalization as enforced doc-truth,
|
||||
// not prose — same pattern as the v5.1 Handover-1 pins above. Freeze, not promote:
|
||||
// phase_signals stays optional; brief_version 2.1 is the frozen baseline (S3 decision).
|
||||
|
||||
test('v5.4 — HANDOVER-CONTRACTS.md Handover 1 heading is labeled (PUBLIC CONTRACT)', () => {
|
||||
const t = read('docs/HANDOVER-CONTRACTS.md');
|
||||
assert.match(t, /^## Handover 1 —.*\(PUBLIC CONTRACT\)\s*$/m,
|
||||
'Handover 1 heading must carry the (PUBLIC CONTRACT) label — symmetric with Handover 3 (EXTERNAL CONTRACT)');
|
||||
});
|
||||
|
||||
test('v5.4 — Handover 1 declares the PUBLIC CONTRACT callout + breaking-for-downstream guarantee', () => {
|
||||
const t = read('docs/HANDOVER-CONTRACTS.md');
|
||||
assert.ok(t.includes('Stability tier: PUBLIC CONTRACT'),
|
||||
'Handover 1 must open with a "Stability tier: PUBLIC CONTRACT" callout');
|
||||
assert.ok(t.includes('breaking change for every downstream consumer'),
|
||||
'the callout must state that a brief-schema change is a breaking change for every downstream consumer');
|
||||
});
|
||||
|
||||
test('v5.4 — brief_version 2.1 is the frozen public-contract baseline (no stale 2.0)', () => {
|
||||
const t = read('docs/HANDOVER-CONTRACTS.md');
|
||||
assert.ok(!t.includes('`"2.0"` (current)'),
|
||||
'Handover 1 schema table must not still mark brief_version "2.0" as current (stale)');
|
||||
assert.ok(t.includes('`"2.1"` (current)'),
|
||||
'Handover 1 schema table must mark brief_version "2.1" as current');
|
||||
});
|
||||
|
||||
test('v5.4 — phase_signals stays optional: v5.4 freezes, does not promote to required', () => {
|
||||
const t = read('docs/HANDOVER-CONTRACTS.md');
|
||||
assert.ok(!t.includes('v5.4 may promote'),
|
||||
'the speculative "v5.4 may promote phase_signals to required" line must be resolved (S3 froze the shape)');
|
||||
assert.ok(t.includes('freezes this schema as the public-contract baseline'),
|
||||
'the Versioning note must record that v5.4 freezes the schema as the public-contract baseline');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue