mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-11-04 11:51:53 +00:00
TASK-pilot-brief-sandbox tolerate vanished sibling worktree
This commit is contained in:
1 parent
84227151b4
commit
15a8b70ebf
3 files changed
+135
-3
No files matched your search
@@ -3454,3 +3454,34 @@ test_integrity_note:
|
||||
did_relax_any_assertion: false
|
||||
if_true_explain_spec_basis: ""
|
||||
```
|
||||
|
||||
# Release brief resolver tolerates unrelated vanished Git sibling
|
||||
|
||||
```yaml
|
||||
test_integrity_note:
|
||||
change_type: ["new_tests"]
|
||||
scenarios:
|
||||
- id: SCN-setup-unrelated-vanished-sibling-tolerated
|
||||
given: "A real installed Git fixture has a selected registered worktree and a separate Git-registered sibling whose directory is renamed away but whose fixture data and registration remain"
|
||||
when: "The installed-project resolver reads the selected worktree, and strict refusal cases exercise missing selected root, foreign/unregistered checkout, stale or absent installation identity, registered common-Git mismatch, and registered branch mismatch"
|
||||
then: "The resolver returns the canonical root while local-state inputs, Git worktree-admin bytes and refs, install manifest, and moved sibling bytes remain unchanged; every strict refusal retains its existing error code"
|
||||
observable_outcomes:
|
||||
- "The selected same-installation registered branch resolves to its canonical project root despite an unrelated missing Git sibling"
|
||||
- "The sibling remains absent; the full relevant Git worktree-admin entry and exact ref listing remain present and byte-identical"
|
||||
- "Every file, directory inventory, and mode under declared local project state remains identical, including state.db and WAL/SHM files when present"
|
||||
- "The moved sibling fixture, including its .git administration file, remains byte-identical"
|
||||
- "The install manifest remains byte-identical; the resolver performs no prune, unregister, or fixture cleanup"
|
||||
- "A missing selected root retains ENOENT; foreign/unregistered, stale or absent install identity, registered common-Git mismatch, and registered branch mismatch retain UNREGISTERED_PROJECT_WORKTREE"
|
||||
determinism_controls:
|
||||
- "Fixed fixture inputs and branch names, real local Git worktrees, temporary project and state roots, and no network or provider calls"
|
||||
- "A filesystem rename makes one registered sibling path absent without pruning or changing Git's registration; deterministic recursive SHA-256/mode/inventory snapshots cover local state, Git worktree administration, and moved fixture data"
|
||||
anti_cheat_rationale:
|
||||
prevents:
|
||||
- "Treating an unregistered or copied checkout as canonical after a lookup error"
|
||||
- "Swallowing current-root or non-absence filesystem failures"
|
||||
- "Pruning, unregistering, or rewriting the missing sibling to make resolution pass"
|
||||
- "Relying only on porcelain output while silently changing SQLite, Git admin/ref, or moved-sibling bytes"
|
||||
relaxation:
|
||||
did_relax_any_assertion: false
|
||||
if_true_explain_spec_basis: ""
|
||||
```
|
||||
@@ -28,7 +28,17 @@ export function resolveInstalledProjectRoot(root, env = process.env) {
|
||||
const current = read(join(canonical, '.torch', 'install-manifest.json'));
|
||||
const registered = current.external?.find(entry => entry.type === 'worktree' && existsSync(entry.path) && realpathSync(entry.path) === root);
|
||||
const common = directory => realpathSync(resolve(directory, git(directory, ['rev-parse', '--git-common-dir'])));
|
||||
const members = git(canonical, ['worktree', 'list', '--porcelain']).split('\n').filter(line => line.startsWith('worktree ')).map(line => realpathSync(line.slice(9)));
|
||||
const members = [];
|
||||
for (const line of git(canonical, ['worktree', 'list', '--porcelain']).split('\n').filter(value => value.startsWith('worktree '))) {
|
||||
const memberPath = line.slice(9);
|
||||
try {
|
||||
members.push(realpathSync(memberPath));
|
||||
} catch (error) {
|
||||
// A vanished unrelated worktree must not block this checkout's lookup.
|
||||
// Keep errors for the selected root and non-absence failures fail-closed.
|
||||
if (resolve(memberPath) === root || !['ENOENT', 'ENOTDIR'].includes(error.code)) throw error;
|
||||
}
|
||||
}
|
||||
if (current.projectId !== manifest.projectId || current.installationId !== manifest.installationId
|
||||
|| !registered || common(root) !== common(canonical) || !members.includes(root)
|
||||
|| git(root, ['branch', '--show-current']) !== registered.branch) {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { mkdtempSync, readFileSync, writeFileSync, cpSync } from 'node:fs';
|
||||
import { existsSync, lstatSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, renameSync, writeFileSync, cpSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { join, resolve } from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { analyzeRepository } from '../../src/kernel/analyze.mjs';
|
||||
import { proposeDomains } from '../../src/kernel/domains.mjs';
|
||||
@@ -30,6 +31,33 @@ function fixture() {
|
||||
installProject({ repository, proposal, env });
|
||||
return { root, env, parentOverride: join(root, 'worktrees') };
|
||||
}
|
||||
function snapshotTree(root) {
|
||||
const records = [];
|
||||
const visit = (path, relativePath) => {
|
||||
const stat = lstatSync(path);
|
||||
const record = { path: relativePath || '.', mode: stat.mode & 0o7777 };
|
||||
if (stat.isDirectory()) {
|
||||
record.type = 'directory';
|
||||
records.push(record);
|
||||
for (const name of readdirSync(path).sort()) visit(join(path, name), relativePath ? join(relativePath, name) : name);
|
||||
} else if (stat.isSymbolicLink()) {
|
||||
record.type = 'symlink';
|
||||
record.target = readlinkSync(path);
|
||||
records.push(record);
|
||||
} else if (stat.isFile()) {
|
||||
const bytes = readFileSync(path);
|
||||
record.type = 'file';
|
||||
record.size = bytes.length;
|
||||
record.sha256 = createHash('sha256').update(bytes).digest('hex');
|
||||
records.push(record);
|
||||
} else {
|
||||
record.type = 'other';
|
||||
records.push(record);
|
||||
}
|
||||
};
|
||||
visit(root, '');
|
||||
return records;
|
||||
}
|
||||
|
||||
test('SCN-guided-setup: approved setup checkpoints owned files and provisions without agents', () => {
|
||||
const f = fixture();
|
||||
@@ -79,6 +107,69 @@ test('SCN-worktree-canonical-brief: current instructions win and unregistered or
|
||||
assert.throws(() => resolveInstalledProjectRoot(entry.path, f.env), { code: 'UNREGISTERED_PROJECT_WORKTREE' });
|
||||
});
|
||||
|
||||
test('SCN-setup-unrelated-vanished-sibling-tolerated: registered checkout resolves while an absent Git sibling remains registered', () => {
|
||||
const f = fixture();
|
||||
setupProject({ ...f, repository: inspectRepository(f.root), authorized: true });
|
||||
const entry = readInstallManifest(f.root).external.find(item => item.type === 'worktree');
|
||||
const missingSibling = join(f.parentOverride, 'vanished-sibling');
|
||||
const movedSibling = join(f.parentOverride, 'moved-sibling-fixture');
|
||||
git(f.root, ['worktree', 'add', '-b', 'vanished-sibling', missingSibling]);
|
||||
const siblingAdminPath = resolve(missingSibling, git(missingSibling, ['rev-parse', '--git-dir']));
|
||||
renameSync(missingSibling, movedSibling);
|
||||
assert.equal(existsSync(missingSibling), false);
|
||||
|
||||
const manifestPath = join(f.root, '.torch/install-manifest.json');
|
||||
const stateRoot = readInstallManifest(f.root).external.find(item => item.type === 'local-state').path;
|
||||
const manifestBefore = readFileSync(manifestPath, 'utf8');
|
||||
const stateBefore = snapshotTree(stateRoot);
|
||||
const siblingAdminBefore = snapshotTree(siblingAdminPath);
|
||||
const movedSiblingBefore = snapshotTree(movedSibling);
|
||||
const worktreesBefore = git(f.root, ['worktree', 'list', '--porcelain']);
|
||||
const refsBefore = git(f.root, ['for-each-ref', '--format=%(refname) %(objectname)']);
|
||||
assert.ok(worktreesBefore.includes(`worktree ${missingSibling}`));
|
||||
assert.ok(refsBefore.split('\n').includes(`refs/heads/vanished-sibling ${git(f.root, ['rev-parse', 'refs/heads/vanished-sibling'])}`));
|
||||
|
||||
assert.equal(resolveInstalledProjectRoot(entry.path, f.env), f.root);
|
||||
|
||||
assert.equal(existsSync(missingSibling), false);
|
||||
assert.equal(readFileSync(manifestPath, 'utf8'), manifestBefore);
|
||||
assert.deepEqual(snapshotTree(stateRoot), stateBefore);
|
||||
assert.deepEqual(snapshotTree(siblingAdminPath), siblingAdminBefore);
|
||||
assert.deepEqual(snapshotTree(movedSibling), movedSiblingBefore);
|
||||
assert.equal(git(f.root, ['worktree', 'list', '--porcelain']), worktreesBefore);
|
||||
assert.equal(git(f.root, ['for-each-ref', '--format=%(refname) %(objectname)']), refsBefore);
|
||||
|
||||
assert.throws(() => resolveInstalledProjectRoot(join(f.parentOverride, 'missing-selected-root'), f.env), { code: 'ENOENT' });
|
||||
|
||||
const foreignRoot = mkdtempSync(join(tmpdir(), 'torch-foreign-worktree-'));
|
||||
cpSync(join(entry.path, '.torch'), join(foreignRoot, '.torch'), { recursive: true });
|
||||
git(foreignRoot, ['init', '-b', entry.branch]);
|
||||
const foreignManifestPath = join(foreignRoot, '.torch/install-manifest.json');
|
||||
const canonicalManifest = JSON.parse(manifestBefore);
|
||||
const foreignManifest = JSON.parse(readFileSync(foreignManifestPath, 'utf8'));
|
||||
foreignManifest.installationId = 'stale-installation';
|
||||
writeFileSync(foreignManifestPath, JSON.stringify(foreignManifest));
|
||||
assert.throws(() => resolveInstalledProjectRoot(foreignRoot, f.env), { code: 'UNREGISTERED_PROJECT_WORKTREE' });
|
||||
delete foreignManifest.installationId;
|
||||
writeFileSync(foreignManifestPath, JSON.stringify(foreignManifest));
|
||||
assert.throws(() => resolveInstalledProjectRoot(foreignRoot, f.env), { code: 'UNREGISTERED_PROJECT_WORKTREE' });
|
||||
foreignManifest.installationId = canonicalManifest.installationId;
|
||||
writeFileSync(foreignManifestPath, JSON.stringify(foreignManifest));
|
||||
assert.throws(() => resolveInstalledProjectRoot(foreignRoot, f.env), { code: 'UNREGISTERED_PROJECT_WORKTREE' });
|
||||
|
||||
const foreignRegistration = { ...entry, path: foreignRoot };
|
||||
canonicalManifest.external.push(foreignRegistration);
|
||||
writeFileSync(manifestPath, JSON.stringify(canonicalManifest));
|
||||
try {
|
||||
assert.throws(() => resolveInstalledProjectRoot(foreignRoot, f.env), { code: 'UNREGISTERED_PROJECT_WORKTREE' });
|
||||
} finally {
|
||||
writeFileSync(manifestPath, manifestBefore);
|
||||
}
|
||||
|
||||
git(entry.path, ['switch', '-c', 'registered-branch-mismatch']);
|
||||
assert.throws(() => resolveInstalledProjectRoot(entry.path, f.env), { code: 'UNREGISTERED_PROJECT_WORKTREE' });
|
||||
});
|
||||
|
||||
test('SCN-install-restore: detach and explicit restore preserve configuration and worktree history without starting sessions', () => {
|
||||
const f = fixture();
|
||||
setupProject({ ...f, repository: inspectRepository(f.root), authorized: true });
|
||||
|
||||
Reference in new issue
Block a user