docs(fleet): tier the north star and declare the tier-0 operator surface (#1337)
ci/woodpecker/push/publish Pipeline was canceled

This commit was merged in pull request #1337.
This commit is contained in:
2026-08-20 23:05:34 +00:00
parent ca97b885b0
commit af43a7a63e
27 changed files with 307 additions and 71 deletions
@@ -147,11 +147,11 @@ describe('renderNorthStarMarkdown', () => {
'standing_objectives:',
' - { id: NS-1, text: t }',
'success_criteria:',
' - { id: AC-NS-1, text: t }',
' - { id: AC-NS-1, text: t, tier: 0 }',
'workstreams:',
' - { id: A, title: t }',
'goals:',
' - { id: A1, title: t, phase: 1, priority: must-have, depends_on: [] }',
' - { id: A1, title: t, phase: 1, tier: 0, priority: must-have, depends_on: [] }',
'assumptions:',
' - { id: ASM-1, vetoable: true, text: t }',
'spend:',
+24 -8
View File
@@ -191,6 +191,10 @@ export interface NorthStarIdText {
text: string;
}
export interface NorthStarCriterion extends NorthStarIdText {
tier: number;
}
export interface NorthStarWorkstream {
id: string;
title: string;
@@ -200,6 +204,8 @@ export interface NorthStarGoal {
id: string;
title: string;
phase: number;
/** Capability tier this goal serves: 0 dogfood, 1 MVP, 2 full vision. Orthogonal to phase, which is build order. */
tier: number;
priority: string;
depends_on: string[];
}
@@ -220,7 +226,7 @@ export interface NorthStar {
mission: string;
substrate: { note: string };
standing_objectives: NorthStarIdText[];
success_criteria: NorthStarIdText[];
success_criteria: NorthStarCriterion[];
workstreams: NorthStarWorkstream[];
goals: NorthStarGoal[];
assumptions: NorthStarAssumption[];
@@ -280,9 +286,13 @@ export function parseNorthStar(rawText: string): NorthStar {
standing_objectives: requireArray(parsed.standing_objectives, 'standing_objectives').map(
(row, i) => idText(row, 'standing_objectives', i),
),
success_criteria: requireArray(parsed.success_criteria, 'success_criteria').map((row, i) =>
idText(row, 'success_criteria', i),
),
success_criteria: requireArray(parsed.success_criteria, 'success_criteria').map((row, i) => {
const tier = (row as Record<string, unknown>)?.tier;
if (typeof tier !== 'number') {
throw new Error(`NORTH_STAR.yaml: success_criteria[${i}].tier must be a number.`);
}
return { ...idText(row, 'success_criteria', i), tier };
}),
workstreams: requireArray(parsed.workstreams, 'workstreams').map((row, i) => {
const ws = row as Record<string, unknown>;
return {
@@ -300,10 +310,15 @@ export function parseNorthStar(rawText: string): NorthStar {
if (typeof phase !== 'number') {
throw new Error(`NORTH_STAR.yaml: goals[${i}].phase must be a number.`);
}
const tier = goal?.tier;
if (typeof tier !== 'number') {
throw new Error(`NORTH_STAR.yaml: goals[${i}].tier must be a number.`);
}
return {
id: requireString(goal?.id, `goals[${i}].id`),
title: requireString(goal?.title, `goals[${i}].title`),
phase,
tier,
priority: requireString(goal?.priority, `goals[${i}].priority`),
depends_on: dependsRaw.map((dep, j) => requireString(dep, `goals[${i}].depends_on[${j}]`)),
};
@@ -349,7 +364,7 @@ function renderMarkdownTable(headers: string[], rows: string[][]): string[] {
* Pure function of its input — same input always yields byte-identical output,
* so the round-trip (YAML → render → write) is stable across runs. No clock, no
* network, no CLI. Layout follows the repo's existing doctrine-doc convention
* (heading, blockquote banner, then sections + tables, e.g. north-star.md /
* (heading, blockquote banner, then sections + tables, e.g. FLEET-DOCTRINE.md /
* mission-control/BOARD.md).
*/
export function renderNorthStarMarkdown(ns: NorthStar): string {
@@ -362,7 +377,7 @@ export function renderNorthStarMarkdown(ns: NorthStar): string {
'> Projected deterministically from [`NORTH_STAR.yaml`](./NORTH_STAR.yaml) by the pure',
);
lines.push('> generator in `packages/mosaic/src/commands/fleet.ts` (`renderNorthStarMarkdown`).');
lines.push('> Edit the YAML, then regenerate. Self-contained Mosaic — no Hermes dependency.');
lines.push('> Edit the YAML, then regenerate. Self-contained Mosaic.');
lines.push('');
lines.push('## Mission');
@@ -385,7 +400,7 @@ export function renderNorthStarMarkdown(ns: NorthStar): string {
lines.push('## Success criteria');
lines.push('');
for (const ac of ns.success_criteria) {
lines.push(`- **${ac.id}** — ${ac.text}`);
lines.push(`- **${ac.id}** (tier ${ac.tier})${ac.text}`);
}
lines.push('');
@@ -403,10 +418,11 @@ export function renderNorthStarMarkdown(ns: NorthStar): string {
lines.push('');
lines.push(
...renderMarkdownTable(
['id', 'title', 'phase', 'priority', 'depends_on'],
['id', 'title', 'tier', 'phase', 'priority', 'depends_on'],
ns.goals.map((goal) => [
goal.id,
goal.title,
String(goal.tier),
String(goal.phase),
goal.priority,
goal.depends_on.length > 0 ? goal.depends_on.join(', ') : '—',
@@ -922,8 +922,8 @@ describe('fleet operator documentation', (): void => {
);
expect(
surfaces.filter((surface): boolean => surface.category === 'InlineLiteral'),
).toHaveLength(863);
expect(surfaces).toHaveLength(887);
).toHaveLength(882);
expect(surfaces).toHaveLength(906);
const rosterSource = await readFile(join(fleetDocs, 'examples', 'roster-v2.yaml'), 'utf8');
const auxiliary: CodeSurface = {