fix(mosaic): preserve measurable brain git state

This commit is contained in:
2026-08-05 17:19:50 -05:00
parent 518c4185ee
commit bad53564ed
5 changed files with 217 additions and 12 deletions
@@ -361,6 +361,72 @@ describe('doctor runtime observation', (): void => {
}
});
it.each(['remote', 'branch', 'status'] as const)(
'reports %s measurement failure as indeterminate rather than healthy or mismatched',
async (failedMeasurement): Promise<void> => {
const runtime = await loadRuntime('MB-REQ-08 three-state git measurements');
const root = join(tempRoot(), 'brain');
mkdirSync(join(root, '.git'), { recursive: true });
const runner: CommandRunner = (request): CommandResult => {
if (request.program === 'mosaic') {
return {
status: 0,
stdout: validateResult('ok', 'validation-verified').replaceAll(
'synthetic-no-token',
'seat-a',
),
stderr: '',
};
}
const command = request.args.join(' ');
if (command.includes('rev-parse --is-inside-work-tree')) {
return { status: 0, stdout: 'true\n', stderr: '' };
}
if (command.includes('remote get-url origin')) {
return failedMeasurement === 'remote'
? { status: 1, stdout: '', stderr: 'measurement failed' }
: {
status: 0,
stdout: 'https://git.mosaicstack.dev/mosaicstack/mosaic-brain.git\n',
stderr: '',
};
}
if (command.includes('branch --show-current')) {
return failedMeasurement === 'branch'
? { status: 1, stdout: '', stderr: 'measurement failed' }
: { status: 0, stdout: 'main\n', stderr: '' };
}
if (command.includes('status --porcelain')) {
return failedMeasurement === 'status'
? { status: 1, stdout: '', stderr: 'measurement failed' }
: { status: 0, stdout: '', stderr: '' };
}
return { status: 99, stdout: '', stderr: 'unexpected command' };
};
const report = runtime.collectBrainDoctorReport(
{
registrySource: registry(),
targetGitUrl: 'https://git.mosaicstack.dev/mosaicstack/stack.git',
brainNamespace: 'mosaicstack',
identity: 'seat-a',
root,
},
runner,
);
expect(report.findings).toEqual(
expect.arrayContaining([
expect.objectContaining({
code: 'brain-git-state-indeterminate',
reasonCode: `${failedMeasurement}-unmeasurable`,
}),
]),
);
expect(report.findings.some((finding) => finding.code.endsWith('-mismatch'))).toBe(false);
},
);
it('repairs write refusal through mosaic cred, revalidates, then clones and verifies the resulting object', async (): Promise<void> => {
const runtime = await loadRuntime('MB-REQ-08 broker-only doctor repair');
const root = join(tempRoot(), 'brain');
@@ -612,6 +678,105 @@ describe('push-on-write publication', (): void => {
expect(evidence.reachable).toBe(true);
});
it('leaves a genuinely clean checkout clean after normal publication', async (): Promise<void> => {
const runtime = await loadRuntime('MB-REQ-07 normal publication index reconciliation');
const root = tempRoot();
const remote = join(root, 'remote.git');
const checkout = join(root, 'brain');
execFileSync('git', ['init', '--bare', '--initial-branch=main', remote]);
execFileSync('git', ['init', '--initial-branch=main', checkout]);
writeFileSync(join(checkout, 'README.md'), 'brain\n');
execFileSync('git', ['-C', checkout, 'add', 'README.md']);
execFileSync('git', [
'-C',
checkout,
'-c',
'user.name=fixture',
'-c',
'[email protected]',
'commit',
'-m',
'seed',
]);
execFileSync('git', ['-C', checkout, 'remote', 'add', 'origin', remote]);
execFileSync('git', ['-C', checkout, 'push', '-u', 'origin', 'main']);
const finding = join(checkout, 'finding.md');
writeFileSync(finding, 'approved finding\n');
runtime.publishBrainPaths(
{
root: checkout,
identity: 'seat-a',
entries: [{ path: finding, content: new TextEncoder().encode('approved finding\n') }],
message: 'append approved finding',
},
runtime.systemCommandRunner,
);
expect(execFileSync('git', ['-C', checkout, 'status', '--porcelain']).toString()).toBe('');
});
it('rebases a clean concurrent append-only push and leaves the checkout clean', async (): Promise<void> => {
const runtime = await loadRuntime('MB-REQ-07 real concurrent publication reconciliation');
const root = tempRoot();
const remote = join(root, 'remote.git');
const checkout = join(root, 'brain-a');
const concurrent = join(root, 'brain-b');
execFileSync('git', ['init', '--bare', '--initial-branch=main', remote]);
execFileSync('git', ['init', '--initial-branch=main', checkout]);
writeFileSync(join(checkout, 'README.md'), 'brain\n');
execFileSync('git', ['-C', checkout, 'add', 'README.md']);
execFileSync('git', [
'-C',
checkout,
'-c',
'user.name=fixture',
'-c',
'[email protected]',
'commit',
'-m',
'seed',
]);
execFileSync('git', ['-C', checkout, 'remote', 'add', 'origin', remote]);
execFileSync('git', ['-C', checkout, 'push', '-u', 'origin', 'main']);
execFileSync('git', ['clone', remote, concurrent]);
writeFileSync(join(concurrent, 'remote-finding.md'), 'concurrent finding\n');
execFileSync('git', ['-C', concurrent, 'add', 'remote-finding.md']);
execFileSync('git', [
'-C',
concurrent,
'-c',
'user.name=other-seat',
'-c',
'[email protected]',
'commit',
'-m',
'append concurrent finding',
]);
execFileSync('git', ['-C', concurrent, 'push', 'origin', 'main']);
const finding = join(checkout, 'local-finding.md');
writeFileSync(finding, 'local finding\n');
const evidence = runtime.publishBrainPaths(
{
root: checkout,
identity: 'seat-a',
entries: [{ path: finding, content: new TextEncoder().encode('local finding\n') }],
message: 'append local finding',
},
runtime.systemCommandRunner,
);
expect(evidence.reachable).toBe(true);
expect(execFileSync('git', ['-C', checkout, 'status', '--porcelain']).toString()).toBe('');
expect(execFileSync('git', ['-C', checkout, 'show', 'HEAD:remote-finding.md']).toString()).toBe(
'concurrent finding\n',
);
expect(execFileSync('git', ['-C', checkout, 'show', 'HEAD:local-finding.md']).toString()).toBe(
'local finding\n',
);
});
it('commits with command-scoped identity, pushes immediately, and proves reachability from origin/main', async (): Promise<void> => {
const runtime = await loadRuntime('MB-REQ-07 publish-on-write reachability');
const root = tempRoot();
@@ -140,7 +140,7 @@ export function collectBrainDoctorReport(
let gitRepository = false;
let remote: string | null = null;
let branch: string | null = null;
let dirty: boolean | null = null;
let worktreeState: BrainDoctorObservation['worktreeState'] = 'unmeasurable';
if (rootExists) {
const repository = runGit(run, input.identity, [
'-C',
@@ -166,7 +166,9 @@ export function collectBrainDoctorReport(
const statusResult = runGit(run, input.identity, ['-C', input.root, 'status', '--porcelain']);
if (remoteResult.status === 0) remote = remoteResult.stdout.trim();
if (branchResult.status === 0) branch = branchResult.stdout.trim();
if (statusResult.status === 0) dirty = statusResult.stdout.trim().length > 0;
if (statusResult.status === 0) {
worktreeState = statusResult.stdout.trim().length > 0 ? 'dirty' : 'clean';
}
}
}
@@ -175,7 +177,7 @@ export function collectBrainDoctorReport(
gitRepository,
remote,
branch,
dirty,
worktreeState,
access,
};
const refusalMarker = `refused reason=${access.reasonCode}`;
@@ -385,6 +387,23 @@ export function publishBrainPaths(
if (result.stdout.trim() !== expected) throw new Error('brain-git-commit-content-mismatch');
}
};
const reconcileRealIndex = (): void => {
for (const [path, objectId] of expectedObjects) {
requireSuccess(
runGit(run, input.identity, [
'-C',
input.root,
'update-index',
'--add',
'--cacheinfo',
'100644',
objectId,
path,
]),
'brain-git-reconcile-checkout-index',
);
}
};
const verifyCommitPaths = (commit: string): void => {
const changed = runGit(run, input.identity, [
'-C',
@@ -476,6 +495,7 @@ export function publishBrainPaths(
verifyCommitPaths(commit);
verifyCommitObjects(commit);
verifyCommitIdentity(commit);
reconcileRealIndex();
createdCommit = true;
} else if (difference.status !== 0) {
throw new Error('brain-git-isolated-diff-failed');
@@ -93,7 +93,7 @@ interface BrainDoctorObservation {
readonly gitRepository: boolean;
readonly remote: string | null;
readonly branch: string | null;
readonly dirty: boolean | null;
readonly worktreeState: 'clean' | 'dirty' | 'unmeasurable';
readonly access: CredentialAssessment | null;
}
@@ -991,7 +991,7 @@ describe('R8 — doctor diagnoses defects and fixes only through approved seams'
gitRepository: false,
remote: null,
branch: null,
dirty: null,
worktreeState: 'unmeasurable',
access: sut.assessCredentialResult(credentialResult('refused', 'no-token-for-identity')),
},
expected,
@@ -1006,7 +1006,7 @@ describe('R8 — doctor diagnoses defects and fixes only through approved seams'
gitRepository: true,
remote: 'https://git.uscllc.com/usc/mosaic-brain.git',
branch: 'main',
dirty: true,
worktreeState: 'dirty',
access: sut.assessCredentialResult(
credentialResult('indeterminate', 'credential-rejected'),
),
+22 -4
View File
@@ -178,7 +178,7 @@ export interface BrainDoctorObservation {
readonly gitRepository: boolean;
readonly remote: string | null;
readonly branch: string | null;
readonly dirty: boolean | null;
readonly worktreeState: 'clean' | 'dirty' | 'unmeasurable';
readonly access: CredentialAssessment | null;
}
@@ -1079,13 +1079,31 @@ export function evaluateBrainDoctor(
findings.push({ code: 'brain-not-git-repository', repairable: true, reasonCode: null });
return findings;
}
if (observation.remote !== expectedRemote) {
if (observation.remote === null) {
findings.push({
code: 'brain-git-state-indeterminate',
repairable: false,
reasonCode: 'remote-unmeasurable',
});
} else if (observation.remote !== expectedRemote) {
findings.push({ code: 'brain-remote-mismatch', repairable: true, reasonCode: null });
}
if (observation.branch !== 'main') {
if (observation.branch === null) {
findings.push({
code: 'brain-git-state-indeterminate',
repairable: false,
reasonCode: 'branch-unmeasurable',
});
} else if (observation.branch !== 'main') {
findings.push({ code: 'brain-branch-mismatch', repairable: false, reasonCode: null });
}
if (observation.dirty === true) {
if (observation.worktreeState === 'unmeasurable') {
findings.push({
code: 'brain-git-state-indeterminate',
repairable: false,
reasonCode: 'status-unmeasurable',
});
} else if (observation.worktreeState === 'dirty') {
findings.push({ code: 'brain-uncommitted-state', repairable: false, reasonCode: null });
}
if (access !== null) findings.push(access);