Files
healer-man/scripts/playtest-stockade-spell-blocking.cjs
T
2026-10-06 22:25:34 -04:00

392 lines
32 KiB
JavaScript

const { spawnSync } = require('node:child_process');
const fs = require('node:fs');
const path = require('node:path');
const projectRoot = path.resolve(__dirname, '..');
const sourceWrapperPath = path.join(__dirname, 'playtest-stockade-stances-blocking.cjs');
const sourceWrapper = fs.readFileSync(sourceWrapperPath, 'utf8');
const runtimeWrapperPath = path.join(__dirname, `.playtest-stockade-spell-blocking-${process.pid}.cjs`);
function replaceExactlyOnce(source, marker, replacement, label) {
const count = source.split(marker).length - 1;
if (count !== 1) throw new Error(`${label} must occur exactly once; found ${count}.`);
return source.replace(marker, replacement);
}
function transformSpellCampaignHarness(source) {
const replaceOnce = (marker, replacement, label) => {
const count = source.split(marker).length - 1;
if (count !== 1) throw new Error(`${label} must occur exactly once in the campaign source; found ${count}.`);
source = source.replace(marker, replacement);
};
const replaceEvery = (marker, replacement, label) => {
const count = source.split(marker).length - 1;
if (!count) throw new Error(`${label} marker was not found in the campaign source.`);
source = source.replaceAll(marker, replacement);
};
replaceOnce(
`async function runCampaignBossRoute(page, route, entryState, profile) {
const guidance = readNavigationGuidance(route.id);`,
`async function runCampaignBossRoute(page, route, entryState, profile) {
if (!entryState.dungeonRun?.id && !entryState.dungeonRun?.biteSizedSelection) {
const selectionDeadline = Date.now() + 8_000;
while (Date.now() < selectionDeadline
&& !entryState.dungeonRun?.id && !entryState.dungeonRun?.biteSizedSelection) {
await page.waitForTimeout(250);
entryState = await readLiveState(page, true);
}
}
const fullStockadeGuidance = readNavigationGuidance(FULL_STOCKADE_DUNGEON_ID);
const sourceBossObjectives = fullStockadeGuidance.objectives;
const observedBossesAtEntry = entryState.mobs.filter((mob) => mob.boss && !mob.dead
&& sourceBossObjectives.some((objective) => objective.name === mob.name));
if (observedBossesAtEntry.length > 1) {
throw new Error(\`Bite-Sized Stockade exposed multiple source bosses at entry: \${JSON.stringify(observedBossesAtEntry.map((mob) => ({ id: mob.id, name: mob.name, serverEntry: mob.serverEntry })))}.\`);
}
const selectedRunBoss = entryState.dungeonRun?.biteSizedSelection?.boss ?? null;
const runId = entryState.dungeonRun?.id ?? null;
const observedSelectedBoss = observedBossesAtEntry[0] ?? null;
const runIdSelectedObjective = runId ? (() => {
let hash = 2_166_136_261;
for (let index = 0; index < runId.length; index += 1) {
hash ^= runId.charCodeAt(index);
hash = Math.imul(hash, 16_777_619);
}
return sourceBossObjectives[(hash >>> 0) % sourceBossObjectives.length];
})() : null;
const selectedSourceObjective = selectedRunBoss
? sourceBossObjectives.find((objective) => objective.name === selectedRunBoss.name
&& objective.id === selectedRunBoss.objectiveId)
: runIdSelectedObjective ?? sourceBossObjectives.find((objective) => objective.name === observedSelectedBoss?.name);
if (!selectedSourceObjective) {
throw new Error(\`Bite-Sized Stockade selected boss was not present in run selection or a live entry mob: selection=\${JSON.stringify(selectedRunBoss)}, observed=\${JSON.stringify(observedBossesAtEntry.map((mob) => ({ id: mob.id, name: mob.name, serverEntry: mob.serverEntry })))}.\`);
}
if (observedSelectedBoss && observedSelectedBoss.name !== selectedSourceObjective.name) {
throw new Error('The live entry boss name disagrees with the seeded dungeon-run selection.');
}
const cellblockAnchor = sourceBossObjectives.find((objective) => objective.name === 'Targorr the Dread');
if (!selectedSourceObjective || !cellblockAnchor) {
throw new Error('The observed seeded boss or reviewed central-cell navigation anchor is missing from the source guide.');
}
const expectedBiteSizedBossRoom = [-159.582, -25.6062, 1.2531];
if (!Array.isArray(cellblockAnchor.position)
|| cellblockAnchor.position.some((coordinate, index) => coordinate !== expectedBiteSizedBossRoom[index])) {
throw new Error(\`Targorr guide anchor \${JSON.stringify(cellblockAnchor.position)} does not exactly match the Bite-Sized boss room \${JSON.stringify(expectedBiteSizedBossRoom)}.\`);
}
const biteWaypoints = fullStockadeGuidance.waypoints.slice(0, cellblockAnchor.waypointIndex + 1);
const biteDistance = biteWaypoints.slice(1).reduce((sum, waypoint, index) =>
sum + distance3(biteWaypoints[index], waypoint), 0);
const selectedObjective = { ...selectedSourceObjective,
position: cellblockAnchor.position, waypointIndex: cellblockAnchor.waypointIndex };
const selectedBossIdentity = {
name: selectedSourceObjective.name,
sourceSpawnId: selectedSourceObjective.id,
entityId: selectedRunBoss?.entityId ?? null,
sourceDungeonId: selectedRunBoss?.sourceDungeonId ?? null,
runId,
liveActorId: observedSelectedBoss?.id ?? null,
serverEntry: observedSelectedBoss?.serverEntry ?? null,
selectionEvidence: selectedRunBoss
? 'read-only biteSizedSelection.boss from normal dungeon-run progress'
: runIdSelectedObjective
? 'source seededBossIndex FNV-1a selection reconstructed from read-only dungeon-run id'
: 'the one live source boss mob observed at normal Bite-Sized Stockade entry',
};
const guidance = {
...fullStockadeGuidance,
dungeonId: route.id,
objective: selectedObjective.name,
objectiveId: selectedObjective.id,
objectivePosition: selectedObjective.position,
objectives: [selectedObjective],
waypoints: biteWaypoints,
waypointCount: biteWaypoints.length,
expectedNavigationDistance: Number(biteDistance.toFixed(2)),
};`,
'dynamic seeded one-boss navigation guide',
);
replaceOnce(
' objective: { name: guidance.objective, position: guidance.objectivePosition },',
' objective: { name: guidance.objective, position: guidance.objectivePosition },\n selectedBossIdentity,',
'selected boss identity in campaign result',
);
replaceOnce(
' dungeonRun: dungeonRunProgress ? {\n dungeonId: dungeonRunProgress.dungeonId,',
' dungeonRun: dungeonRunProgress ? {\n id: dungeonRunProgress.id ?? null,\n biteSizedSelection: dungeonRunProgress.biteSizedSelection ?? null,\n dungeonId: dungeonRunProgress.dungeonId,',
'read-only seeded boss run selection',
);
replaceOnce(
' const playerToBoss = liveBoss ? distance3(current.player.position, liveBoss.position) : bossDistance;',
' if (liveBoss) {\n selectedBossIdentity.liveActorId = liveBoss.id;\n selectedBossIdentity.serverEntry = liveBoss.serverEntry ?? selectedBossIdentity.serverEntry;\n }\n const playerToBoss = liveBoss ? distance3(current.player.position, liveBoss.position) : bossDistance;',
'late live seeded boss identity confirmation',
);
replaceOnce(
' result.pageErrors = [];\n result.consoleErrors = [];\n result.frozenBuildAssetUrls = moduleUrls.map((url) => new URL(url, page.url()).href);',
' const selectedBossMobObservation = [...entryState.mobs, ...current.mobs,\n ...result.samples.flatMap((sample) => sample.mobs ?? [])]\n .find((mob) => mob.name === selectedBossIdentity.name && mob.id);\n const selectedBossDeathObservation = [...observedDeadMobs].find(([, name]) => name === selectedBossIdentity.name);\n if (selectedBossMobObservation) {\n selectedBossIdentity.liveActorId = selectedBossMobObservation.id;\n selectedBossIdentity.serverEntry = selectedBossMobObservation.serverEntry ?? selectedBossIdentity.serverEntry;\n } else if (selectedBossDeathObservation) selectedBossIdentity.liveActorId = selectedBossDeathObservation[0];\n result.pageErrors = [];\n result.consoleErrors = [];\n result.frozenBuildAssetUrls = moduleUrls.map((url) => new URL(url, page.url()).href);',
'final selected live boss actor identity',
);
replaceOnce(
` const initialEventKeys = new Set(entryState.events.map((event) => [event.occurredAt, event.sourceActorId,
event.targetActorId, event.abilityId, event.kind, event.effectiveAmount].join('|')));
const seenEventKeys = initialEventKeys;`,
` const eventKey = (event) => event.id != null ? \`event:\${event.id}\` : JSON.stringify(event);
const initialEventKeys = new Set(entryState.events.map(eventKey));
const seenEventKeys = initialEventKeys;`,
'stable source event identity key',
);
replaceEvery(
` const key = [event.occurredAt, event.sourceActorId, event.targetActorId,
event.abilityId, event.kind, event.effectiveAmount].join('|');`,
' const key = eventKey(event);',
'stable sampled-event deduplication key',
);
replaceOnce(
" if (lastCombatResult?.outcome === 'block') {\n const latestDamageEvent = [...snapshot.events].reverse().find((event) => event.kind === 'damage');\n const matchedLatestBlockEvent = latestDamageEvent?.outcome === 'block'\n && Number(latestDamageEvent.rawAmount) === Number(lastCombatResult.rawDamage)\n ? latestDamageEvent : null;",
" if (lastCombatResult?.blocked === true || lastCombatResult?.outcome === 'block') {\n const latestDamageEvent = [...snapshot.events].reverse().find((event) => event.kind === 'damage'\n && (event.blocked === true || Number(event.blockedAmount) > 0 || event.outcome === 'block'));\n const matchedLatestBlockEvent = latestDamageEvent\n && Number(latestDamageEvent.rawAmount) === Number(lastCombatResult.rawDamage)\n ? latestDamageEvent : null;",
'crit-with-block last result sampling',
);
replaceOnce(
' school: attack.school ?? null, castTimeMs: attack.castTimeMs ?? 0,',
' school: attack.school ?? null, wowSpellDefense: attack.wowSpellDefense ?? null,\n effects: attack.effects ?? [], castTimeMs: attack.castTimeMs ?? 0,',
'source NPC spell metadata projection',
);
replaceOnce(
' playerAtEntry: entryState.player, partyAtEntry: entryState.party,',
' playerAtEntry: entryState.player, partyAtEntry: entryState.party,\n sourceSpellAbilityMetadata: (entryState.abilities ?? [])\n .filter((ability) => ability.wowSpellDefense || ability.ranks?.some((rank) => rank.wowSpellDefense))\n .map((ability) => ({ ...ability, ranks: (ability.ranks ?? []).filter((rank) => rank.wowSpellDefense) })),',
'read-only ability source metadata',
);
return source;
}
function summarizeSpellBlockingEvidence(route) {
const events = route.observedCombatEvents ?? [];
const partyActorIds = new Set(['__player__', ...(route.partyAtEntry ?? []).map((actor) => actor.id)]);
for (const sample of route.samples ?? []) {
for (const member of sample.party ?? []) partyActorIds.add(member.id);
}
const hostileActorIds = new Set((route.samples ?? []).flatMap((sample) => (sample.mobs ?? [])
.map((mob) => mob.id).filter(Boolean)));
const resultByEventId = new Map((route.observedBlockResultObservations ?? [])
.filter((observation) => observation.event?.id != null)
.map((observation) => [observation.event.id, observation]));
const blockedDamageEvents = events.filter((event) => event.kind === 'damage'
&& (event.blocked === true || Number(event.blockedAmount) > 0 || event.outcome === 'block'))
.map((event) => {
const result = resultByEventId.get(event.id)?.combatResult ?? null;
return {
...event,
blockDirection: hostileActorIds.has(event.sourceActorId) && partyActorIds.has(event.targetActorId)
? 'hostile-attack-blocked-by-party'
: partyActorIds.has(event.sourceActorId) && hostileActorIds.has(event.targetActorId)
? 'party-attack-blocked-by-hostile' : 'actor-team-unresolved',
blocked: event.blocked ?? result?.blocked ?? (event.outcome === 'block'),
blockedAmount: event.blockedAmount ?? result?.blockedAmount ?? null,
sampledCombatResult: result,
};
});
const mobSamples = (route.samples ?? []).flatMap((sample) => (sample.mobs ?? []).map((mob) => ({
observedAt: sample.at ?? sample.now ?? null,
id: mob.id ?? null,
name: mob.name ?? null,
serverEntry: mob.serverEntry ?? null,
attacks: mob.attacks ?? [],
auras: mob.auras ?? [],
combatAuraTelemetry: mob.combatAuraTelemetry ?? [],
})));
return {
definitions: {
blockedDamageEvents: 'Read-only StructuredCombatEvent values retained verbatim from sampled combatEvents snapshots when blocked is true, blockedAmount is positive, or outcome is block; crit outcomes remain crit.',
eventSampling: 'The source snapshots take the latest 200 events from the store ring; polling plus ID deduplication can miss events that age out between snapshots.',
blockDirection: 'Party and hostile sides are determined only from sampled party/mob actor IDs; unresolved IDs retain an explicit unresolved direction.',
blockedAmount: 'Prefers the event field; otherwise uses a sampled lastCombatResult only when correlated by event id.',
npcSources: 'Mob attack definitions, source aura lists, and combatStore aura telemetry copied from read-only campaign snapshots.',
abilityMetadata: 'Source spell metadata is recorded only when the entry ability or rank supplied wowSpellDefense.',
negativeEvidence: 'No observed blocked event is not evidence that a spell cannot be blocked; this route samples ordinary live UI snapshots.',
},
counts: {
rawCombatEvents: events.length,
blockedDamageEvents: blockedDamageEvents.length,
blockedDamageEventsWithAmount: blockedDamageEvents.filter((event) => event.blockedAmount !== null).length,
critAndBlockedDamageEvents: blockedDamageEvents.filter((event) => event.outcome === 'crit'
&& (event.blocked === true || Number(event.blockedAmount) > 0)).length,
hostileAttacksBlockedByParty: blockedDamageEvents.filter((event) => event.blockDirection === 'hostile-attack-blocked-by-party').length,
partyAttacksBlockedByHostile: blockedDamageEvents.filter((event) => event.blockDirection === 'party-attack-blocked-by-hostile').length,
actorTeamUnresolvedBlockEvents: blockedDamageEvents.filter((event) => event.blockDirection === 'actor-team-unresolved').length,
sourceNpcSamples: mobSamples.length,
sourceNpcAuraSamples: mobSamples.filter((mob) => mob.auras.length || mob.combatAuraTelemetry.length).length,
sourceSpellAbilityMetadata: route.sourceSpellAbilityMetadata?.length ?? 0,
},
selectedBossIdentity: route.selectedBossIdentity ?? null,
blockedDamageEvents,
sourceNpcSamples: mobSamples,
sourceSpellAbilityMetadata: route.sourceSpellAbilityMetadata ?? [],
rawCombatEvents: events,
};
}
function makeBiteSizedWrapper() {
let source = sourceWrapper;
source = replaceExactlyOnce(source,
'const {\n FULL_STOCKADE_DUNGEON_ID,',
'const {\n DEFAULT_TEST_DUNGEON_ID,\n DEFAULT_TEST_DUNGEON_TITLE,\n FULL_STOCKADE_DUNGEON_ID,',
'bite-sized defaults import');
source = source.replaceAll('stockade-stances-blocking', 'stockade-spell-blocking');
source = replaceExactlyOnce(source,
'function main() {\n const instrumentedHarness = createInstrumentedHarness();',
`${transformSpellCampaignHarness.toString()}\n\n${summarizeSpellBlockingEvidence.toString()}\n\nfunction main() {\n const instrumentedHarness = transformSpellCampaignHarness(createInstrumentedHarness());`,
'spell-specific campaign transformation');
source = replaceExactlyOnce(source,
" if (!process.argv.includes('--full-stockade')) {\n throw new Error('This source-specific full-campaign harness requires explicit --full-stockade opt-in.');\n }",
" if (!process.argv.includes('--bite-sized-stockade')) {\n throw new Error('This source-specific Bite-Sized Stockade harness requires explicit --bite-sized-stockade opt-in.');\n }",
'explicit Bite-Sized route opt-in');
source = replaceExactlyOnce(source,
' dungeon: { id: FULL_STOCKADE_DUNGEON_ID, title: FULL_STOCKADE_DUNGEON_TITLE },',
" dungeon: { id: DEFAULT_TEST_DUNGEON_ID, title: DEFAULT_TEST_DUNGEON_TITLE },\n routeScope: 'Bite-Sized Cellblock Rush; one seeded source boss, ordinary UI traversal, 900-second hard bound',",
'Bite-Sized route record');
source = replaceExactlyOnce(source,
' entryAndPlay: \'normal full Stockade picker and Discipline healer-role entry; campaign harness ordinary WASD, target selection, attack/support healing/party commands; no Boss Testing, teleport, collision bypass, enemy/damage/aura/health/cast seeding, or combat store writes\',',
" entryAndPlay: 'normal Bite-Sized Stockade picker and Discipline healer-role entry; ordinary WASD, target selection, attack/support healing/party commands; no Boss Testing, teleport, collision bypass, enemy/damage/aura/health/cast seeding, or combat store writes',",
'normal Bite-Sized entry description');
source = replaceExactlyOnce(source,
" instrumentation: ['active enemy-source aura applications for spells 7164/7165/3419 with owner, target, apply/expiry, and stack fields',\n 'raw observed combat events with block outcomes and actor direction',\n 'read-only lastCombatResult block amount snapshots correlated to matching damage events',\n 'read-only live-state progress.json snapshots at 30-second intervals'],\n requestedMaximumCampaignSeconds: 1800,",
" instrumentation: ['sampled read-only StructuredCombatEvent ring snapshots (latest 200), retaining blocked and blockedAmount fields; crit-plus-block stays visible',\n 'read-only source NPC attacks, auras, and combatAuraTelemetry',\n 'source spell metadata only where wowSpellDefense is present on an entry ability/rank',\n 'actual seeded boss identity plus one-objective native clear result',\n 'complete content manifest JSON before and after and hash-addressed objects actually served'],\n requestedMaximumCampaignSeconds: 900,",
'spell run instrumentation record');
source = replaceExactlyOnce(source,
" const contentManifestBefore = collectContentManifestSnapshot();",
" const contentManifestBefore = collectContentManifestSnapshot();",
'baseline content manifest location');
source = replaceExactlyOnce(source,
" const child = spawnSync(process.execPath, [runtimeHarnessPath,\n '--campaign-boss-route', `--route=${FULL_STOCKADE_DUNGEON_ID}`, '--max-campaign-seconds=1800'], {",
" const child = spawnSync(process.execPath, [runtimeHarnessPath,\n '--campaign-boss-route', `--route=${DEFAULT_TEST_DUNGEON_ID}`, '--max-campaign-seconds=900'], {",
'bounded Bite-Sized campaign route');
source = replaceExactlyOnce(source,
' timeout: 2_100_000,',
' timeout: 900_000,',
'900-second child hard bound');
source = replaceExactlyOnce(source,
' ? path.join(campaignDirectory, `${FULL_STOCKADE_DUNGEON_ID}-campaign-boss-route.json`) : null;',
' ? path.join(campaignDirectory, `${DEFAULT_TEST_DUNGEON_ID}-campaign-boss-route.json`) : null;',
'Bite-Sized route result path');
source = replaceExactlyOnce(source,
' ? path.join(campaignDirectory, `${FULL_STOCKADE_DUNGEON_ID}-route.json`) : null;',
' ? path.join(campaignDirectory, `${DEFAULT_TEST_DUNGEON_ID}-route.json`) : null;',
'Bite-Sized summary result path');
source = replaceExactlyOnce(source,
" const evidence = route ? summarizeStanceBlockingEvidence(route) : null;\n if (evidence) writeJson(path.join(outputDirectory, 'stances-blocking-evidence.json'), evidence);",
" const evidence = route ? summarizeSpellBlockingEvidence(route) : null;\n if (route && evidence?.selectedBossIdentity) {\n const selectedBossSample = evidence.sourceNpcSamples.find((mob) => mob.name === evidence.selectedBossIdentity.name && mob.id);\n if (selectedBossSample) {\n const observedIdentity = { ...route.selectedBossIdentity, liveActorId: selectedBossSample.id,\n serverEntry: selectedBossSample.serverEntry ?? null };\n route.selectedBossIdentity = observedIdentity;\n evidence.selectedBossIdentity = observedIdentity;\n writeJson(routePath, route);\n }\n }\n if (evidence) writeJson(path.join(outputDirectory, 'spell-blocking-evidence.json'), evidence);",
'spell-blocking evidence output');
source = replaceExactlyOnce(source,
' runRecord.stanceBlockingEvidenceCounts = evidence?.counts ?? null;',
' runRecord.spellBlockingEvidenceCounts = evidence?.counts ?? null;',
'spell-blocking evidence count field');
source = replaceExactlyOnce(source,
"specializationId: 'priest:discipline', role: 'healer', level: 30,",
"specializationId: 'priest:discipline', role: 'healer', level: 30,\n preEntryLevelPreparation: 'UI-created profile advanced through isolated shell.saveActiveProgression(30, 0, talentRanks) before dungeon entry; no combat-state writes during play',",
'explicit isolated pre-entry progression setup');
source = replaceExactlyOnce(source,
" if (route && !evidence?.counts.stanceAuraApplications) {\n runRecord.statusNotes.push('No live application of Defensive Stance 7164 or Battle Stance 7165 was captured; aura outcomes are not observed in this run.');\n }\n if (route && !evidence?.counts.improvedBlockingAuraApplications) {\n runRecord.statusNotes.push('No live Improved Blocking 3419 application was captured; aura outcomes are not observed in this run.');\n }\n if (route && !evidence?.counts.rawBlockEvents) {\n runRecord.statusNotes.push('No damage event with outcome=block was captured; intermittent live sampling limits negative conclusions.');\n } else if (route && evidence?.counts.matchedBlockedAmountEvents < evidence?.counts.rawBlockEvents) {\n runRecord.statusNotes.push(`${evidence.counts.rawBlockEvents - evidence.counts.matchedBlockedAmountEvents} block outcome event(s) had no matching sampled lastCombatResult amount; the outcome is retained without inferring a blocked amount.`);\n }\n if (route && evidence?.counts.actorTeamUnresolvedBlockEvents) {\n runRecord.statusNotes.push(`${evidence.counts.actorTeamUnresolvedBlockEvents} block event(s) could not be assigned to party-versus-hostile direction from sampled actor IDs.`);\n }",
" if (route && !evidence?.counts.blockedDamageEvents) {\n runRecord.statusNotes.push('No block-indicated damage event was captured in sampled combat-event snapshots; this does not establish that a spell cannot be blocked.');\n } else if (route && evidence?.counts.blockedDamageEventsWithAmount < evidence?.counts.blockedDamageEvents) {\n runRecord.statusNotes.push(`${evidence.counts.blockedDamageEvents - evidence.counts.blockedDamageEventsWithAmount} block-indicated event(s) had no correlated numeric blocked amount; missing amounts remain unknown.`);\n }\n if (route && evidence?.counts.actorTeamUnresolvedBlockEvents) {\n runRecord.statusNotes.push(`${evidence.counts.actorTeamUnresolvedBlockEvents} block-indicated event(s) could not be assigned to party-versus-hostile direction from sampled actor IDs.`);\n }",
'spell-appropriate sampled block status notes');
source = replaceExactlyOnce(source,
' const fiveRequiredBossesVerified = expectedBossIds.length === 5\n && expectedBossIds.every((bossId) => killedBossIds.has(bossId));',
" const selectedBossIdentity = route?.selectedBossIdentity ?? null;\n const supportedSeededBossNames = new Set(['Targorr the Dread', 'Kam Deepfury', 'Hamhock', 'Bazil Thredd', 'Dextren Ward']);\n const oneSelectedBossVerified = expectedBossIds.length === 1\n && killedBossIds.has(expectedBossIds[0])\n && selectedBossIdentity?.sourceSpawnId === expectedBossIds[0]\n && supportedSeededBossNames.has(selectedBossIdentity?.name);",
'single selected boss result verification');
source = replaceExactlyOnce(source,
' && fiveRequiredBossesVerified);',
' && oneSelectedBossVerified);',
'single boss native clear assertion');
source = replaceExactlyOnce(source,
' runRecord.requiredBossIds = expectedBossIds;\n runRecord.killedBossIds = [...killedBossIds];',
' runRecord.requiredBossIds = expectedBossIds;\n runRecord.killedBossIds = [...killedBossIds];\n runRecord.selectedBossIdentity = selectedBossIdentity;',
'actual boss identity in run record');
source = replaceExactlyOnce(source,
' runRecord.contentSourceResponseCounts = contentSourceEvidence.counts;',
' runRecord.contentSourceResponseCounts = contentSourceEvidence.counts;\n runRecord.contentObjectsActuallyLoaded = contentSourceEvidence.counts.successfulManifestResponses > 0\n && contentSourceEvidence.counts.verifiedHashAddressedObjects > 0\n && contentSourceEvidence.counts.objectIntegrityFailures === 0;\n runRecord.contentObjectsActuallyLoadedRequirement = \'At least one successful manifest response and one served hash-addressed content object whose bytes match its address; zero integrity failures.\';',
'loaded hash-addressed content verification');
source = replaceExactlyOnce(source,
" if (!runRecord.fullClearVerified && runRecord.executionStatus === 'complete' && route) {\n runRecord.statusNotes.push('Campaign process exited successfully, but results UI plus all five required boss IDs were not verified; this remains a partial live attempt.');\n }",
" if (!runRecord.fullClearVerified && runRecord.executionStatus === 'complete' && route) {\n runRecord.statusNotes.push('Campaign process exited successfully, but the native result UI plus the one seeded boss ID were not verified; this remains a partial live attempt.');\n }\n if (!runRecord.contentObjectsActuallyLoaded && runRecord.executionStatus === 'complete') {\n runRecord.statusNotes.push('The run did not prove that hash-addressed content objects were served from the recorded manifest; content provenance remains unverified.');\n }",
'single boss and content-provenance notes');
source = replaceExactlyOnce(source,
" runRecord.status = runRecord.executionStatus === 'complete' && route\n ? runRecord.fullClearVerified ? 'complete' : 'partial-full-clear-unverified' : 'failed';",
" runRecord.status = runRecord.executionStatus === 'complete' && route\n ? runRecord.fullClearVerified && runRecord.contentObjectsActuallyLoaded ? 'complete'\n : 'partial-spell-blocking-run-unverified' : 'failed';",
'final route status requires content provenance');
source = source.replaceAll('Stockade stance/blocking QA', 'Stockade spell-blocking QA');
source = source.replaceAll('Prepared scoped Stockade stance/blocking harness', 'Prepared scoped Bite-Sized Stockade spell-blocking harness');
source = source.replaceAll('all five required boss IDs', 'the one seeded boss ID');
source = source.replaceAll('contentManifestSha256: contentManifestBefore.manifestSha256,',
'contentManifestSha256: contentManifestBefore.manifestSha256,\n contentManifestJsonIncluded: true,');
source = replaceExactlyOnce(source,
' manifestVersion: manifest.version ?? null,',
' manifest,\n manifestVersion: manifest.version ?? null,',
'full source content manifest JSON');
source = replaceExactlyOnce(source,
'function collectLoadedContentObjectEvidence(responses) {',
'function collectLoadedContentObjectEvidence(responses, manifest) {',
'manifest-backed content object evidence');
source = replaceExactlyOnce(source,
" return uniqueObjects.map((response) => {\n const relativeObjectPath = decodeURIComponent(response.pathname.slice('/content/'.length));",
" return uniqueObjects.map((response) => {\n const manifestReferences = Object.entries(manifest?.files ?? {})\n .filter(([, entry]) => [entry.url, entry.download?.url].includes(response.pathname))\n .map(([logicalPath, entry]) => ({ logicalPath, sha256: entry.download?.sha256 ?? entry.sha256 ?? null }));\n const manifestReferencedLogicalPaths = manifestReferences.map((entry) => entry.logicalPath);\n const relativeObjectPath = decodeURIComponent(response.pathname.slice('/content/'.length));",
'content object manifest membership');
source = replaceExactlyOnce(source,
'return { ...response, localObjectPath: null, localBytes: null, localSha256: null,\n objectIntegrity:',
'return { ...response, manifestReferencedLogicalPaths, manifestReferenceCount: manifestReferences.length,\n localObjectPath: null, localBytes: null, localSha256: null,\n objectIntegrity:',
'unsafe content object manifest telemetry');
source = replaceExactlyOnce(source,
'return { ...response, localObjectPath: path.relative(projectRoot, absoluteObjectPath),\n localBytes: null, localSha256: null, objectIntegrity:',
'return { ...response, manifestReferencedLogicalPaths, manifestReferenceCount: manifestReferences.length,\n localObjectPath: path.relative(projectRoot, absoluteObjectPath),\n localBytes: null, localSha256: null, objectIntegrity:',
'missing content object manifest telemetry');
source = replaceExactlyOnce(source,
' return {\n ...response,\n localObjectPath: path.relative(projectRoot, absoluteObjectPath),',
' return {\n ...response,\n manifestReferencedLogicalPaths,\n manifestReferenceCount: manifestReferences.length,\n localObjectPath: path.relative(projectRoot, absoluteObjectPath),',
'verified content object manifest telemetry');
source = replaceExactlyOnce(source,
' const loadedContentObjects = collectLoadedContentObjectEvidence(contentSourceResponses);',
' const loadedContentObjects = collectLoadedContentObjectEvidence(contentSourceResponses, contentManifestBefore.manifest);',
'captured-manifest object verification');
source = replaceExactlyOnce(source,
" verifiedHashAddressedObjects: loadedContentObjects.filter((object) => object.objectIntegrity === 'served-file-matches-hash-address').length,",
" verifiedHashAddressedObjects: loadedContentObjects.filter((object) => object.objectIntegrity === 'served-file-matches-hash-address').length,\n verifiedManifestReferencedHashAddressedObjects: loadedContentObjects.filter((object) => object.objectIntegrity === 'served-file-matches-hash-address'\n && object.manifestReferenceCount > 0).length,",
'manifest reference match count');
source = replaceExactlyOnce(source,
' && contentSourceEvidence.counts.verifiedHashAddressedObjects > 0\n && contentSourceEvidence.counts.objectIntegrityFailures === 0;',
' && contentSourceEvidence.counts.verifiedHashAddressedObjects > 0\n && contentSourceEvidence.counts.verifiedManifestReferencedHashAddressedObjects > 0\n && contentSourceEvidence.counts.objectIntegrityFailures === 0;',
'manifest-backed object success gate');
return source;
}
function main() {
const wrapper = makeBiteSizedWrapper();
fs.writeFileSync(runtimeWrapperPath, wrapper, 'utf8');
try {
const syntax = spawnSync(process.execPath, ['--check', runtimeWrapperPath], {
cwd: projectRoot,
encoding: 'utf8',
windowsHide: true,
});
if (syntax.status !== 0) throw new Error(`Generated Stockade wrapper syntax check failed: ${syntax.stderr || syntax.error}`);
const args = process.argv.slice(2);
const run = spawnSync(process.execPath, [runtimeWrapperPath, ...args], {
cwd: projectRoot,
stdio: 'inherit',
windowsHide: true,
});
if (run.error) throw run.error;
process.exitCode = run.status ?? 1;
} finally {
fs.rmSync(runtimeWrapperPath, { force: true });
}
}
try {
main();
} catch (error) {
fs.rmSync(runtimeWrapperPath, { force: true });
console.error(error.stack ?? error.message);
process.exitCode = 1;
}