Compare commits

..
Author SHA1 Message Date
fargo 68279d61a1 feat(verify-release): wire quality-rails evaluator stage into canonical verification (#1275)
ci/woodpecker/pr/ci Pipeline was successful
- new canonical-only quality-rails stage (after build) invokes the evaluator
  CLI on the repo root — QC-19 monorepo subject — instead of duplicating
  presence logic; no ci.yml mirror (same shape as the build stage)
- parity spec updated: stage-name list, evaluator-delegation assertions, and
  negative controls for inline duplication / dropped command
- quality-rails README points at the probe inventory (input doc)
2026-08-18 12:35:03 -05:00
fargo 771127d3cd test(quality-rails): evaluator contract, parity oracle, and negative-control specs (#1275)
- CLI evaluate/check --json vs programmatic evaluateSubject: same subject,
  same typed report
- QC-19 parity vs a verbatim copy of the absorbed presence loop (positive and
  negative fixtures, all scaffold kinds) and QC-20 parity vs the real
  framework verify.sh output contract
- negative controls: unknown check id, absent subject, missing probePath,
  spawn error, timeout, nonzero/unexpected exit, malformed output, throwing
  check, unqualified skip — all never passed
2026-08-18 11:17:25 -05:00
fargo ae95e7b853 feat(quality-rails): absorb QC-19 presence loop into evaluator; add typed evaluate/check/doctor (#1275)
- check (QC-19) is now implemented by the evaluator's typed
  qc-19-rails-files-present definition; keeps fail-closed exit and gains --json
- doctor stays advisory but reports typed states
- new evaluate subcommand is the canonical CLI entry point (--probe-path feeds
  QC-20; shell probes remain thin adapters with TS-owned verdict parsing)
2026-08-18 11:17:23 -05:00
fargo 367cb27591 feat(quality-rails): typed evaluator core — statuses, digested definitions, per-subject sets (#1275) 2026-08-18 11:17:15 -05:00
fargo 18905d69e6 docs(ri-050): RI-3-001 done — review 187 + merge evidence recorded (#1275) 2026-08-18 11:01:20 -05:00
2 changed files with 3 additions and 183 deletions
@@ -244,115 +244,12 @@ describe('[email protected]', (): void => {
* absent env — either of which turns the condition into decoration while the
* literal-string assertion above still passes.
*/
/**
* The condition an installed unit actually presents to systemd: the shipped
* unit's values with drop-ins applied in lexical order, honouring the list
* reset an empty assignment performs.
*
* Reading the *installed* tree rather than the template is the point. The
* template alone cannot show what `install` produced, and #1310 lived in that
* gap: the template was correct for the install it was written for, and wrong
* for the one the operator had.
*/
async function effectiveConditionPaths(systemdUserDir: string): Promise<string[]> {
const dropInDir = join(systemdUserDir, '[email protected]');
const dropIns = (
await readdir(dropInDir).catch((error: NodeJS.ErrnoException): string[] => {
if (error.code === 'ENOENT') return [];
throw error;
})
)
.filter((name): boolean => name.endsWith('.conf'))
.sort();
const sources = [
join(systemdUserDir, '[email protected]'),
...dropIns.map((name): string => join(dropInDir, name)),
];
const conditions: string[] = [];
for (const source of sources) {
for (const line of (await readFile(source, 'utf8')).split('\n')) {
const match = line.match(/^ConditionPathExists=(.*)$/);
if (!match) continue;
const value = match[1]!.trim();
if (value === '') conditions.length = 0;
else conditions.push(value);
}
}
return conditions;
}
/** Makes `~/.mosaic` adoptable — the shape that puts a real box in split mode. */
async function adoptableBrainHome(): Promise<string> {
const brainHome = join(tempHome!, '.mosaic');
await mkdir(join(brainHome, 'fleet', 'agents'), { recursive: true, mode: 0o700 });
return brainHome;
}
it('guards exactly the file the fleet writes, so the two cannot drift apart', async (): Promise<void> => {
const mosaicHome = await v2Home();
const systemdUserDir = join(tempHome!, '.config', 'systemd', 'user');
await program().parseAsync(['node', 'mosaic', 'fleet', 'install', '--no-enable']);
const rendered = (await effectiveConditionPaths(systemdUserDir)).map((value): string =>
value.replace('%h', tempHome!).replace('%i', 'coder0'),
);
const rendered = (await conditionPath()).replace('%h', tempHome!).replace('%i', 'coder0');
// The path an installed fleet actually places for this agent.
expect(rendered).toEqual([join(mosaicHome, 'fleet', 'agents', 'coder0.env.generated')]);
});
/**
* #1310. The test above passed throughout the bug, because its fixture never
* creates `~/.mosaic/fleet/agents` and so can only ever reach legacy mode,
* where brain home and config home are the same directory and the drift it
* names is unobservable. A guard that cannot reach the state it guards is
* decoration; this is the arm that reaches it.
*
* Measured consequence on a real box (mosaic-sbx-dev 1124, 0.0.50-next.2507):
* the config-home condition can never be met, systemd reports every seat
* `ConditionResult=no` with `Result=success` and `ExecMainStatus=0`, and
* `fleet start` exits 0 having started nothing.
*/
it('follows the brain home when one is active, not the config home', async (): Promise<void> => {
const mosaicHome = await v2Home();
const brainHome = await adoptableBrainHome();
const systemdUserDir = join(tempHome!, '.config', 'systemd', 'user');
await program().parseAsync(['node', 'mosaic', 'fleet', 'install', '--no-enable']);
const rendered = (await effectiveConditionPaths(systemdUserDir)).map((value): string =>
value.replace('%h', tempHome!).replace('%i', 'coder0'),
);
// Exactly one condition: the drop-in must reset the shipped value, not join
// it. Two conditions would both have to pass and the seat would stay skipped.
expect(rendered).toEqual([join(brainHome, 'fleet', 'agents', 'coder0.env.generated')]);
expect(rendered[0]).not.toContain(mosaicHome);
});
/**
* The other direction, which fails the same silent way: a box that had a
* brain home and no longer does would keep a condition pointing at a path the
* reconciler has stopped writing.
*/
it('drops a stale brain-home override when the brain home goes away', async (): Promise<void> => {
const mosaicHome = await v2Home();
const systemdUserDir = join(tempHome!, '.config', 'systemd', 'user');
await adoptableBrainHome();
await program().parseAsync(['node', 'mosaic', 'fleet', 'install', '--no-enable']);
// Control: the override is present before the brain home is removed, so a
// passing assertion below cannot come from it never having been written.
expect(await effectiveConditionPaths(systemdUserDir)).toHaveLength(1);
expect((await effectiveConditionPaths(systemdUserDir))[0]).toContain('.mosaic/fleet/agents');
await rm(join(tempHome!, '.mosaic'), { recursive: true, force: true });
await program().parseAsync(['node', 'mosaic', 'fleet', 'install', '--no-enable']);
const rendered = (await effectiveConditionPaths(systemdUserDir)).map((value): string =>
value.replace('%h', tempHome!).replace('%i', 'coder0'),
);
expect(rendered).toEqual([join(mosaicHome, 'fleet', 'agents', 'coder0.env.generated')]);
expect(rendered).toBe(join(mosaicHome, 'fleet', 'agents', 'coder0.env.generated'));
});
it('guards a real failure — the launcher rejects an absent generated env', async (): Promise<void> => {
+1 -78
View File
@@ -13,7 +13,7 @@ import {
import { randomUUID } from 'node:crypto';
import { homedir, hostname, userInfo } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { brainHomeIsActive, fleetAgentEnvDir } from '../fleet/brain-home.js';
import { fleetAgentEnvDir } from '../fleet/brain-home.js';
import { fileURLToPath } from 'node:url';
import { spawn } from 'node:child_process';
import * as readline from 'node:readline';
@@ -2350,80 +2350,6 @@ export function registerFleetAgentCommands(
});
}
/** Directory holding the install-managed drop-ins for `[email protected]`. */
export function agentUnitDropInDir(systemdUserDir: string): string {
return join(systemdUserDir, '[email protected]');
}
/** The one drop-in `mosaic fleet install` owns: the brain-home env condition. */
export function agentUnitBrainHomeDropInPath(systemdUserDir: string): string {
return join(agentUnitDropInDir(systemdUserDir), '10-brain-home.conf');
}
/**
* Drop-in re-pointing the agent unit's env condition at the resolved brain home.
*
* The shipped unit gates on `%h/.config/mosaic/fleet/agents/%i.env.generated`,
* which is right for a legacy single-tree install. When a brain home is active
* (canon `docs/STRUCTURE-CANON.md` §2) the reconciler writes seat env under the
* brain home instead, so that condition can never be met — and an unmet
* condition is reported as success (`ConditionResult=no`, `Result=success`,
* `ExecMainStatus=0`). `fleet start` therefore returns 0, prints nothing, and
* starts no seat, with every status surface agreeing the fleet is healthy
* (#1310, measured on mosaic-sbx-dev 1124 against 0.0.50-next.2507).
*
* An empty `ConditionPathExists=` resets the inherited list before the correct
* path is added, so the shipped condition is replaced rather than joined — two
* conditions would both have to pass and the seat would stay skipped.
*
* The boot-window behaviour the shipped unit documents is deliberately kept:
* this still gates on the generated env existing, only at the path that
* actually receives it. The launcher already resolves the brain home itself,
* so nothing downstream of the condition needs to change.
*/
export function renderAgentUnitBrainHomeDropIn(agentEnvDir: string): string {
return [
'# Managed by `mosaic fleet install`. Do not edit; re-run install to update.',
'#',
'# Re-points the seat env condition at the active brain home. Without this the',
'# shipped config-home condition can never be met on a split install and every',
'# seat is silently skipped while `fleet start` reports success (#1310).',
'[Unit]',
'ConditionPathExists=',
`ConditionPathExists=${join(agentEnvDir, '%i.env.generated')}`,
'',
].join('\n');
}
/**
* Write the brain-home drop-in when a brain is active, and remove a stale one
* when it is not.
*
* The removal arm is load-bearing, not tidiness: a host that had a brain home
* and no longer does would otherwise keep a condition pointing at a path the
* reconciler has stopped writing, which fails in exactly the same silent
* direction as the bug this fixes.
*/
export async function syncAgentUnitBrainHomeDropIn(
systemdUserDir: string,
mosaicHome: string,
): Promise<void> {
const dropInPath = agentUnitBrainHomeDropInPath(systemdUserDir);
if (!brainHomeIsActive(mosaicHome)) {
try {
await unlink(dropInPath);
} catch (error) {
// Absent is the expected state on a legacy install; anything else is real.
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
throw error;
}
}
return;
}
await mkdir(agentUnitDropInDir(systemdUserDir), { recursive: true });
await writeFile(dropInPath, renderAgentUnitBrainHomeDropIn(fleetAgentEnvDir(mosaicHome)), 'utf8');
}
async function installFleet(cmd: Command, frameworkRoot: string): Promise<void> {
const activePaths = resolveFleetPaths(cmd.opts<{ mosaicHome: string }>().mosaicHome);
assertDefaultMosaicHomeForSystemd(activePaths.mosaicHome);
@@ -2484,9 +2410,6 @@ async function installFleet(cmd: Command, frameworkRoot: string): Promise<void>
join(frameworkRoot, 'systemd', 'user', '[email protected]'),
join(activePaths.systemdUserDir, '[email protected]'),
);
// Must follow the copy: the drop-in overrides the unit just written, and on a
// split install the unit alone gates every seat on a path nothing writes.
await syncAgentUnitBrainHomeDropIn(activePaths.systemdUserDir, activePaths.mosaicHome);
await copyFile(
join(frameworkRoot, 'systemd', 'user', '[email protected]'),
join(activePaths.systemdUserDir, '[email protected]'),