docs(fleet): add operator configuration guide #789

Open
jason.woltje wants to merge 12 commits from docs/758-fleet-config-operator-docs into main
3 changed files with 44 additions and 9 deletions
Showing only changes of commit a39bafb8e3 - Show all commits

View File

@@ -97,7 +97,7 @@ success_criteria:
- id: AC-NS-7 - id: AC-NS-7
text: >- text: >-
A user-customized persona (edited or added via the orchestrator) survives A user-customized persona (edited or added via the orchestrator) survives
`mosaic update`: baseline reseed never clobbers user overrides. mosaic update: baseline reseed never clobbers user overrides.
workstreams: workstreams:
- id: A - id: A

View File

@@ -97,8 +97,8 @@ observability and no safe way to watch a session.
is an intentional fail-closed design (FR-5). is an intentional fail-closed design (FR-5).
- **agent watch uses a grouped viewer session:** tmux attach -r directly against the - **agent watch uses a grouped viewer session:** tmux attach -r directly against the
agent session lets the viewer terminal shrink the agent's window. agent watch instead agent session lets the viewer terminal shrink the agent's window. agent watch instead
creates a throwaway grouped session (`tmux new-session -d -t '=<agent>' -s creates a throwaway grouped session (tmux new-session -d -t '=<agent>' -s
'<agent>-watch-<pid>'`), attaches read-only to that session, and kills it on detach. '<agent>-watch-<pid>'), attaches read-only to that session, and kills it on detach.
The grouped session shares the agent's windows but has independent sizing, so the The grouped session shares the agent's windows but has independent sizing, so the
agent's window is never affected. tmux attach is still interactive and requires agent's window is never affected. tmux attach is still interactive and requires
inherited stdio; the `interactiveRunner` handles TTY passthrough. inherited stdio; the `interactiveRunner` handles TTY passthrough.

View File

@@ -483,15 +483,11 @@ function codeSurfaceDiagnostics(path: string, source: string): SurfaceDiagnostic
diagnostics.push({ path, line: lineNumber, code: 'indented-code' }); diagnostics.push({ path, line: lineNumber, code: 'indented-code' });
continue; continue;
} }
if (/`{2,}/.test(line) && !/^```[a-z-]+$/.test(line)) {
diagnostics.push({ path, line: lineNumber, code: 'inline-delimiter' });
continue;
}
const marker = line.match(/^(`{3,}|~{3,})(.*)$/); const marker = line.match(/^(`{3,}|~{3,})(.*)$/);
if (marker !== null) { if (marker !== null) {
block += 1; block += 1;
const info = marker[2] ?? ''; const info = marker[2] ?? '';
if (marker[1] !== '```') { if (marker[1] !== '```' || /[`~]/.test(info)) {
diagnostics.push({ path, line: lineNumber, block, code: 'fence-marker' }); diagnostics.push({ path, line: lineNumber, block, code: 'fence-marker' });
continue; continue;
} }
@@ -507,6 +503,15 @@ function codeSurfaceDiagnostics(path: string, source: string): SurfaceDiagnostic
inFence = true; inFence = true;
continue; continue;
} }
if (/`{2,}/.test(line)) {
diagnostics.push({ path, line: lineNumber, code: 'inline-delimiter' });
continue;
}
const withoutClosedInlineSpans = line.replace(/`[^`\n]+`/g, '');
if (withoutClosedInlineSpans.includes('`')) {
diagnostics.push({ path, line: lineNumber, code: 'inline-delimiter' });
continue;
}
if (/<\/?(?:pre|code|script|style|xmp|listing)(?=$|\s|[>/])/i.test(line)) { if (/<\/?(?:pre|code|script|style|xmp|listing)(?=$|\s|[>/])/i.test(line)) {
diagnostics.push({ path, line: lineNumber, code: 'raw-code-container' }); diagnostics.push({ path, line: lineNumber, code: 'raw-code-container' });
} }
@@ -702,8 +707,38 @@ describe('closed documentation publication grammar', (): void => {
} }
}); });
it('rejects unmatched single-backtick delimiters on either side', (): void => {
for (const source of ['`literal', 'literal`', 'text `literal', 'literal` text']) {
expect(codeSurfaceDiagnostics('fixture.md', source)).toContainEqual({
path: 'fixture.md',
line: 1,
code: 'inline-delimiter',
});
}
});
it('counts every invalid column-one fence candidate before later profile selection', (): void => {
for (const firstCandidate of [
'````fleet-synopsis',
'```fleet-synopsis```',
'~~~fleet-synopsis~~~',
]) {
expect(
codeSurfaceDiagnostics(
'reference/cli.md',
`${firstCandidate}\n\`\`\`unknown\n\`\`\`fleet-synopsis\nmosaic fleet verify\n\`\`\``,
),
).toEqual([
{ path: 'reference/cli.md', line: 1, block: 1, code: 'fence-marker' },
{ path: 'reference/cli.md', line: 2, block: 2, code: 'fence-info' },
{ path: 'reference/cli.md', line: 3, block: 3, code: 'profile-unknown' },
{ path: 'reference/cli.md', line: 5, block: 4, code: 'fence-info' },
]);
}
});
it('rejects inline delimiter runs instead of silently omitting them', (): void => { it('rejects inline delimiter runs instead of silently omitting them', (): void => {
for (const source of ['``literal``', '```literal```', 'text ``literal`` text']) { for (const source of ['``literal``', 'text ```literal```', 'text ``literal`` text']) {
expect(codeSurfaceDiagnostics('fixture.md', source)).toContainEqual({ expect(codeSurfaceDiagnostics('fixture.md', source)).toContainEqual({
path: 'fixture.md', path: 'fixture.md',
line: 1, line: 1,