mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-02 17:40:02 +02:00
fix(ship,qa,document-release): repair proof-run regressions and fixture gaps
- ship-docsync-completion: yesterday's audit-scope result dropped the section's status, so /ship spliced one in; the section now opens with **Status:**. - ship-docsync-missing-asset: a missing section or old Ship-owned mode blocks before launch. - ship-docsync-late-result: the invocation record says prepare already saves the candidate selection (no extra Read; budget unchanged). - qa exploratory: await the method Reads before the first probe. - qa-callers fixture: quote the real review-log record template; allow the git log command plan-completion prescribes. - qa functional observer: a receipt caught mid-link(2) is checked at stop instead of failing with ENOENT (reproduced from CI). Each repaired case passed a focused paid run.
This commit is contained in:
1 parent
4a87fa9d59
commit
77cce3bec4
16 files changed
+136
-21
No files matched your search
@@ -95,6 +95,7 @@ export async function observeQAWrites(root: string, options: { reportDirectory?:
|
||||
const events: QAWriteObservation['events'] = [];
|
||||
const failures: string[] = [];
|
||||
const publications = new Map<string, { temporary: string; dev: number; ino: number; bytes: string; parentDev: number; parentIno: number; mode: number }>();
|
||||
const pendingLinks = new Map<string, { target: string; dev: number; ino: number; mode: number; bytes: string }>();
|
||||
let stopped = false;
|
||||
const observedPath = (relative: string, knownPair = false): string => {
|
||||
try {
|
||||
@@ -150,6 +151,18 @@ export async function observeQAWrites(root: string, options: { reportDirectory?:
|
||||
publications.set(relativeTarget, publication);
|
||||
return target;
|
||||
} catch (publicationError) {
|
||||
if (receipt === undefined && (publicationError as NodeJS.ErrnoException).code === 'ENOENT' && temporaryName.test(basename)) {
|
||||
let linking: number | undefined;
|
||||
try { linking = fs.openSync(path.join(parent, basename), fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK); }
|
||||
catch (openError) { if ((openError as NodeJS.ErrnoException).code === 'ENOENT') return path.join(parent, basename); }
|
||||
if (linking !== undefined) try {
|
||||
const entry = fs.fstatSync(linking);
|
||||
if (entry.isFile() && entry.nlink === 2 && entry.uid === parentStat.uid && (entry.mode & 0o777) === mode) {
|
||||
pendingLinks.set(relative, { target: path.relative(root, target), dev: entry.dev, ino: entry.ino, mode, bytes: fs.readFileSync(linking, 'utf8') });
|
||||
return path.join(parent, basename);
|
||||
}
|
||||
} finally { fs.closeSync(linking); }
|
||||
}
|
||||
try { return ownedPath(root, relative); } catch { throw publicationError; }
|
||||
} finally { if (receipt !== undefined) fs.closeSync(receipt); }
|
||||
}
|
||||
@@ -241,6 +254,13 @@ export async function observeQAWrites(root: string, options: { reportDirectory?:
|
||||
|| fs.readFileSync(target, 'utf8') !== publication.bytes) throw new Error('Evidence publication did not settle unchanged');
|
||||
} catch (error) { failures.push(String(pathFailure(root, relative, error))); }
|
||||
}
|
||||
for (const [temporary, pending] of pendingLinks) {
|
||||
try {
|
||||
const entry = fs.lstatSync(ownedPath(root, pending.target));
|
||||
if (fs.existsSync(ownedPath(root, temporary)) || entry.dev !== pending.dev || entry.ino !== pending.ino || entry.nlink !== 1
|
||||
|| (entry.mode & 0o777) !== pending.mode || fs.readFileSync(ownedPath(root, pending.target), 'utf8') !== pending.bytes) throw new Error('Evidence publication did not settle unchanged');
|
||||
} catch (error) { failures.push(String(pathFailure(root, temporary, error))); }
|
||||
}
|
||||
let after: Record<string, string> = {};
|
||||
try { after = qaTreeSnapshot(root); } catch (error) { failures.push(String(error)); }
|
||||
fs.closeSync(fd);
|
||||
|
||||
Reference in new issue
Block a user