fix(mosaic): preserve measurable brain git state
This commit is contained in:
@@ -83,14 +83,16 @@ No explicit token ceiling was supplied. Working cap: 55K tokens for implementati
|
|||||||
- [x] C1 P5→P7 seam receipt read; no brain implementation is in C1.
|
- [x] C1 P5→P7 seam receipt read; no brain implementation is in C1.
|
||||||
- [x] RED acceptance set committed at `cf11c6c86abae073d8b02b4014cd5447ba67f12a`; author and committer read back as `be-coder-07` and branch reachability was independently verified by `tl-mosaic`.
|
- [x] RED acceptance set committed at `cf11c6c86abae073d8b02b4014cd5447ba67f12a`; author and committer read back as `be-coder-07` and branch reachability was independently verified by `tl-mosaic`.
|
||||||
- [x] Moving-contract REDs observed independently for v1.4 mismatch, R8 prerequisite ordering, owner resolver seam/allowlist, tracked skeleton/no-follow behavior, runtime observation/publication, and provider owner resolution.
|
- [x] Moving-contract REDs observed independently for v1.4 mismatch, R8 prerequisite ordering, owner resolver seam/allowlist, tracked skeleton/no-follow behavior, runtime observation/publication, and provider owner resolution.
|
||||||
- [x] Focused implementation includes secure migration, v1.5 write-differential/subject binding, production Git+API refusal parity, provider-backed durable owner resolution that ignores non-admin `active`, required GLPI standing-process policy, P7 provision orchestration, an internal installer command, and installed `mosaic doctor` wiring. Latest focused result: 88/88 (secure config 4, store 43, runtime 13, owner resolver 16, provision 4, provision command 3, installed doctor 5).
|
- [x] Focused implementation includes secure migration, v1.5 write-differential/subject binding, production Git+API refusal parity, provider-backed durable owner resolution that ignores non-admin `active`, required GLPI standing-process policy, P7 provision orchestration, an internal installer command, and installed `mosaic doctor` wiring. Latest focused result: 93/93 (secure config 4, store 43, runtime 18, owner resolver 16, provision 4, provision command 3, installed doctor 5).
|
||||||
- [x] MC-CRED added the required canonical reverse registry seam `ParsedCredentialEstateRegistry.resolveByHost()` at dependency head `6ca8758f`; current local copies are temporary until dependency integration and the 32-line permissive shim has been removed.
|
- [x] MC-CRED added the required canonical reverse registry seam `ParsedCredentialEstateRegistry.resolveByHost()` at dependency head `6ca8758f`; current local copies are temporary until dependency integration and the 32-line permissive shim has been removed.
|
||||||
- [x] Identity gotcha measured: inline `MOSAIC_GIT_IDENTITY=be-coder-07` controls credential resolution but does not override `user.name`/`user.email` inherited from the linked worktree common-dir config (`coder-mos1`). The first local P7 RED commit was immediately amended before push with command-scoped `GIT_AUTHOR_*` + `GIT_COMMITTER_*`; resulting author and committer both read back as `be-coder-07`. Every subsequent authoring command must carry both identity sets and be verified.
|
- [x] Identity gotcha measured: inline `MOSAIC_GIT_IDENTITY=be-coder-07` controls credential resolution but does not override `user.name`/`user.email` inherited from the linked worktree common-dir config (`coder-mos1`). The first local P7 RED commit was immediately amended before push with command-scoped `GIT_AUTHOR_*` + `GIT_COMMITTER_*`; resulting author and committer both read back as `be-coder-07`. Every subsequent authoring command must carry both identity sets and be verified.
|
||||||
- [x] R6 migration reports filename- or content-secret-shaped files without copying them; arbitrary legacy content requires an approved scanner bound to the exact source snapshot, and production currently retains/reports when no approved scanner is configured. Symlinked `.gitignore`, layout directories, and nested migration destinations fail closed.
|
- [x] R6 migration reports filename- or content-secret-shaped files without copying them; arbitrary legacy content requires an approved scanner bound to the exact source snapshot, and production currently retains/reports when no approved scanner is configured. Symlinked `.gitignore`, layout directories, and nested migration destinations fail closed.
|
||||||
- [x] Provider owner lookup uses manual redirect handling, a five-second abort signal, strict JSON content type/shape, and an incrementally enforced 256 KiB response ceiling.
|
- [x] Provider owner lookup uses manual redirect handling, a five-second abort signal, strict JSON content type/shape, and an incrementally enforced 256 KiB response ceiling.
|
||||||
- [x] Security-critical owner policy/registry reads have direct controls for principal UID ownership, file/ancestor permissions, and descriptor-safe regular-file reads.
|
- [x] Security-critical owner policy/registry reads have direct controls for principal UID ownership, file/ancestor permissions, and descriptor-safe regular-file reads.
|
||||||
- [x] Automatic source deletion is parked per the shared-Git-identity governance ruling; remotely reachable snapshots still leave and report every source.
|
- [x] Automatic source deletion is parked per the shared-Git-identity governance ruling; remotely reachable snapshots still leave and report every source.
|
||||||
- [x] Multi-host push-on-write uses an isolated temporary Git index populated from approved in-memory blobs rather than pathname re-reads, verifies each committed blob ID, the exact changed-path allowlist, and both author/committer trailers before push, retries non-fast-forward races via identity-scoped fetch/rebase rather than LWW, and retains both sources and local copies when publication reachability is unknown. A real-repository abuse test proves destination-path substitution cannot change committed bytes and unrelated pre-staged secret-shaped content remains staged but never enters the published commit.
|
- [x] Multi-host push-on-write uses an isolated temporary Git index populated from approved in-memory blobs rather than pathname re-reads, verifies each committed blob ID, the exact changed-path allowlist, and both author/committer trailers before push, then reconciles only approved paths into the real checkout index. Real-repository controls prove a clean checkout remains clean, a concurrent non-fast-forward fetch/rebase/push remains clean and preserves both findings, destination-path substitution cannot change committed bytes, and unrelated pre-staged secret-shaped content remains staged but never enters the published commit.
|
||||||
|
- [x] Doctor Git observations preserve three states: `clean`, `dirty`, and `unmeasurable`; failed remote, branch, or status measurements emit hard `brain-git-state-indeterminate` findings rather than mismatch or ready. The boolean-literal guard sweep covered all MB-BRAIN production files in the 20-file PR population: its only remaining `=== false` guard is the non-nullable `isAbsolute()` predicate; no nullable boolean measurement guards remain.
|
||||||
|
- [x] Author-run Review 10 and focused 88/88 evidence were declared void when blocker fixes changed the head; neither is an independent gate pass.
|
||||||
- [ ] Installer shell P7 invocation after C1 + MC-CRED integration; production command is registered but the C1 shell has not yet called it.
|
- [ ] Installer shell P7 invocation after C1 + MC-CRED integration; production command is registered but the C1 shell has not yet called it.
|
||||||
- [ ] Implementation green on merged dependency base.
|
- [ ] Implementation green on merged dependency base.
|
||||||
- [ ] Independent code review.
|
- [ ] Independent code review.
|
||||||
|
|||||||
@@ -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> => {
|
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 runtime = await loadRuntime('MB-REQ-08 broker-only doctor repair');
|
||||||
const root = join(tempRoot(), 'brain');
|
const root = join(tempRoot(), 'brain');
|
||||||
@@ -612,6 +678,105 @@ describe('push-on-write publication', (): void => {
|
|||||||
expect(evidence.reachable).toBe(true);
|
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> => {
|
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 runtime = await loadRuntime('MB-REQ-07 publish-on-write reachability');
|
||||||
const root = tempRoot();
|
const root = tempRoot();
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export function collectBrainDoctorReport(
|
|||||||
let gitRepository = false;
|
let gitRepository = false;
|
||||||
let remote: string | null = null;
|
let remote: string | null = null;
|
||||||
let branch: string | null = null;
|
let branch: string | null = null;
|
||||||
let dirty: boolean | null = null;
|
let worktreeState: BrainDoctorObservation['worktreeState'] = 'unmeasurable';
|
||||||
if (rootExists) {
|
if (rootExists) {
|
||||||
const repository = runGit(run, input.identity, [
|
const repository = runGit(run, input.identity, [
|
||||||
'-C',
|
'-C',
|
||||||
@@ -166,7 +166,9 @@ export function collectBrainDoctorReport(
|
|||||||
const statusResult = runGit(run, input.identity, ['-C', input.root, 'status', '--porcelain']);
|
const statusResult = runGit(run, input.identity, ['-C', input.root, 'status', '--porcelain']);
|
||||||
if (remoteResult.status === 0) remote = remoteResult.stdout.trim();
|
if (remoteResult.status === 0) remote = remoteResult.stdout.trim();
|
||||||
if (branchResult.status === 0) branch = branchResult.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,
|
gitRepository,
|
||||||
remote,
|
remote,
|
||||||
branch,
|
branch,
|
||||||
dirty,
|
worktreeState,
|
||||||
access,
|
access,
|
||||||
};
|
};
|
||||||
const refusalMarker = `refused reason=${access.reasonCode}`;
|
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');
|
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 verifyCommitPaths = (commit: string): void => {
|
||||||
const changed = runGit(run, input.identity, [
|
const changed = runGit(run, input.identity, [
|
||||||
'-C',
|
'-C',
|
||||||
@@ -476,6 +495,7 @@ export function publishBrainPaths(
|
|||||||
verifyCommitPaths(commit);
|
verifyCommitPaths(commit);
|
||||||
verifyCommitObjects(commit);
|
verifyCommitObjects(commit);
|
||||||
verifyCommitIdentity(commit);
|
verifyCommitIdentity(commit);
|
||||||
|
reconcileRealIndex();
|
||||||
createdCommit = true;
|
createdCommit = true;
|
||||||
} else if (difference.status !== 0) {
|
} else if (difference.status !== 0) {
|
||||||
throw new Error('brain-git-isolated-diff-failed');
|
throw new Error('brain-git-isolated-diff-failed');
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ interface BrainDoctorObservation {
|
|||||||
readonly gitRepository: boolean;
|
readonly gitRepository: boolean;
|
||||||
readonly remote: string | null;
|
readonly remote: string | null;
|
||||||
readonly branch: string | null;
|
readonly branch: string | null;
|
||||||
readonly dirty: boolean | null;
|
readonly worktreeState: 'clean' | 'dirty' | 'unmeasurable';
|
||||||
readonly access: CredentialAssessment | null;
|
readonly access: CredentialAssessment | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,7 +991,7 @@ describe('R8 — doctor diagnoses defects and fixes only through approved seams'
|
|||||||
gitRepository: false,
|
gitRepository: false,
|
||||||
remote: null,
|
remote: null,
|
||||||
branch: null,
|
branch: null,
|
||||||
dirty: null,
|
worktreeState: 'unmeasurable',
|
||||||
access: sut.assessCredentialResult(credentialResult('refused', 'no-token-for-identity')),
|
access: sut.assessCredentialResult(credentialResult('refused', 'no-token-for-identity')),
|
||||||
},
|
},
|
||||||
expected,
|
expected,
|
||||||
@@ -1006,7 +1006,7 @@ describe('R8 — doctor diagnoses defects and fixes only through approved seams'
|
|||||||
gitRepository: true,
|
gitRepository: true,
|
||||||
remote: 'https://git.uscllc.com/usc/mosaic-brain.git',
|
remote: 'https://git.uscllc.com/usc/mosaic-brain.git',
|
||||||
branch: 'main',
|
branch: 'main',
|
||||||
dirty: true,
|
worktreeState: 'dirty',
|
||||||
access: sut.assessCredentialResult(
|
access: sut.assessCredentialResult(
|
||||||
credentialResult('indeterminate', 'credential-rejected'),
|
credentialResult('indeterminate', 'credential-rejected'),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ export interface BrainDoctorObservation {
|
|||||||
readonly gitRepository: boolean;
|
readonly gitRepository: boolean;
|
||||||
readonly remote: string | null;
|
readonly remote: string | null;
|
||||||
readonly branch: string | null;
|
readonly branch: string | null;
|
||||||
readonly dirty: boolean | null;
|
readonly worktreeState: 'clean' | 'dirty' | 'unmeasurable';
|
||||||
readonly access: CredentialAssessment | null;
|
readonly access: CredentialAssessment | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1079,13 +1079,31 @@ export function evaluateBrainDoctor(
|
|||||||
findings.push({ code: 'brain-not-git-repository', repairable: true, reasonCode: null });
|
findings.push({ code: 'brain-not-git-repository', repairable: true, reasonCode: null });
|
||||||
return findings;
|
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 });
|
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 });
|
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 });
|
findings.push({ code: 'brain-uncommitted-state', repairable: false, reasonCode: null });
|
||||||
}
|
}
|
||||||
if (access !== null) findings.push(access);
|
if (access !== null) findings.push(access);
|
||||||
|
|||||||
Reference in New Issue
Block a user