#!/usr/bin/env node

import { createPublicKey, verify as verifySignature } from 'node:crypto'
import { lstatSync, readFileSync, readdirSync, realpathSync, rmSync } from 'node:fs'
import { dirname, join, relative, resolve, sep } from 'node:path'
import { spawnSync } from 'node:child_process'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { canonical, parseJsonStrict, sha256, verifyPacket } from './verify-packet.mjs'

export const PROFILE = 'glyph.compute-contract-drill/0.1-experimental'
export const REPORT_PROFILE = 'glyph.compute-contract-drill-report/0.1-experimental'
const DIMENSIONS = ['authority', 'custody', 'evidence', 'exclusivity', 'lineage', 'promise']
const STATES = new Set(['CONTRADICTED', 'ESTABLISHED', 'NOT_ESTABLISHED', 'UNCHECKABLE'])
const PYTHON = process.env.COMPUTE_CONTRACT_PYTHON || 'python3'
const BASELINE_REASONS = {
  authority: 'PRECOMMITTED_TYPED_AUTHORITIES_BOUND',
  custody: 'PROJECT_OPERATED_TRANSACTION_MAPPING_AND_HISTORY_BOUND',
  evidence: 'PROJECT_FIXTURE_EVENT_BINDING_CLOSES_DECLARED_RELATION',
  exclusivity: 'EXCLUSIVELY_BOUND_INSIDE_ACCEPTED_MECHANISM',
  lineage: 'DECLARED_DEPENDENCY_NODE_AND_GRAPH_BOUND',
  promise: 'ACTION_RECEIPT_BOUND_TO_CONSTRUCTED_RELATION',
}
const MUTATION_RULES = {
  allocation_without_exclusivity: { dimension: 'exclusivity', input_name: 'allocation_stage', state: 'NOT_ESTABLISHED', reason_code: 'ALLOCATION_STAGE_INPUT_NOT_EXCLUSIVE' },
  correction_without_authority: { dimension: 'authority', input_name: 'correction_authority', state: 'CONTRADICTED', reason_code: 'CORRECTION_AUTHORITY_INPUT_ABSENT' },
  double_pledged_capacity: { dimension: 'exclusivity', input_name: 'portfolio_total_allocated', state: 'CONTRADICTED', reason_code: 'PORTFOLIO_TOTAL_INPUT_EXCEEDS_CAPACITY' },
  hardware_without_execution_binding: { dimension: 'evidence', input_name: 'shared_event_binding', state: 'NOT_ESTABLISHED', reason_code: 'SHARED_EVENT_BINDING_INPUT_ABSENT' },
  output_substitution: { dimension: 'evidence', input_name: 'response_commitment', state: 'CONTRADICTED', reason_code: 'RESPONSE_COMMITMENT_INPUT_DISAGREES' },
  post_reliance_forum: { dimension: 'authority', input_name: 'forum_commitment_order', state: 'CONTRADICTED', reason_code: 'FORUM_COMMITMENT_INPUT_AT_OR_AFTER_RELIANCE' },
  prompt_replay: { dimension: 'evidence', input_name: 'request_occurrences', state: 'CONTRADICTED', reason_code: 'REQUEST_OCCURRENCE_INPUT_EXCEEDS_ONE' },
  recourse_without_authorization: { dimension: 'authority', input_name: 'recourse_authorization', state: 'CONTRADICTED', reason_code: 'RECOURSE_AUTHORIZATION_INPUT_ABSENT' },
  stale_nonce: { dimension: 'evidence', input_name: 'nonce_freshness', state: 'CONTRADICTED', reason_code: 'NONCE_FRESHNESS_INPUT_IS_STALE' },
  witness_equivocation: { dimension: 'custody', input_name: 'custody_history_status', state: 'CONTRADICTED', reason_code: 'CUSTODY_HISTORY_INPUT_REPORTS_SAME_SIZE_EQUIVOCATION' },
  wrong_device_class: { dimension: 'evidence', input_name: 'device_class_comparison', state: 'CONTRADICTED', reason_code: 'PROJECT_FIXTURE_DEVICE_CLASS_INPUT_DISAGREES' },
  wrong_model: { dimension: 'evidence', input_name: 'model_commitment', state: 'CONTRADICTED', reason_code: 'MODEL_COMMITMENT_INPUT_DISAGREES' },
}

function exact(value, fields, label) {
  if (value === null || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${label} must be an object`)
  const actual = Object.keys(value).sort()
  const expected = [...fields].sort()
  if (canonical(actual) !== canonical(expected)) throw new Error(`${label} fields changed`)
  return value
}

function readJson(path, label) { return parseJsonStrict(readFileSync(path), label) }
function digestFile(path) { return sha256(readFileSync(path)) }

function decodeBase64Canonical(value, label) {
  if (typeof value !== 'string' || value.length === 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) throw new Error(`${label} is not canonical base64`)
  const raw = Buffer.from(value, 'base64')
  if (raw.toString('base64') !== value) throw new Error(`${label} is not canonical base64`)
  return raw
}

function loadDirectory(root) {
  const base = realpathSync(root)
  const bundle = new Map()
  function visit(directory) {
    for (const name of readdirSync(directory).sort()) {
      const path = join(directory, name)
      const stat = lstatSync(path)
      if (stat.isSymbolicLink()) throw new Error('verifier dossier contains a symlink')
      if (stat.isDirectory()) visit(path)
      else if (stat.isFile()) bundle.set(relative(base, path).split(sep).join('/'), new Uint8Array(readFileSync(path)))
      else throw new Error('verifier dossier contains a non-regular member')
    }
  }
  visit(base)
  return bundle
}

function run(command, args, options = {}) {
  const result = spawnSync(command, args, { encoding: 'utf8', maxBuffer: 32 * 1024 * 1024, ...options })
  if (result.status !== 0) throw new Error(result.stderr || result.stdout || `${command} failed`)
  return result.stdout
}

function dimension(state, reasons, evidence) {
  if (!STATES.has(state) || !Array.isArray(reasons) || reasons.some((item) => typeof item !== 'string') || !Array.isArray(evidence)) throw new Error('invalid dimension result')
  return { evidence_sha256: [...evidence].sort(), reason_codes: [...reasons].sort(), state }
}

function isDigest(value) { return typeof value === 'string' && /^sha256:[0-9a-f]{64}$/.test(value) }

function validateHostileValue(mutation, supplied, baseline) {
  if (canonical(supplied) === canonical(baseline)) throw new Error(`${mutation} hostile input did not change`)
  if (mutation === 'wrong_model' || mutation === 'output_substitution') {
    if (!isDigest(supplied)) throw new Error(`${mutation} hostile input must be a digest`)
    return
  }
  if (mutation === 'wrong_device_class') {
    exact(supplied, ['expected_device_class', 'jurisdiction', 'observed_device_class'], 'wrong-device fixture input')
    if (supplied.expected_device_class !== 'HOPPER' || supplied.observed_device_class !== 'BLACKWELL' || supplied.jurisdiction !== 'PROJECT_FIXTURE_INPUT_NOT_SIGNED_NVIDIA_CLAIM') throw new Error('wrong-device fixture input changed')
    return
  }
  if (mutation === 'prompt_replay') {
    if (!Number.isSafeInteger(supplied) || supplied <= 1) throw new Error('prompt replay count must exceed one')
    return
  }
  if (mutation === 'double_pledged_capacity') {
    if (!Number.isSafeInteger(supplied) || supplied <= 1_000_000) throw new Error('double-pledged total must exceed capacity')
    return
  }
  const expected = {
    allocation_without_exclusivity: 'WITNESSED',
    correction_without_authority: 'ABSENT',
    hardware_without_execution_binding: false,
    post_reliance_forum: 'AT_OR_AFTER_RELIANCE',
    recourse_without_authorization: 'ABSENT',
    stale_nonce: 'STALE',
    witness_equivocation: 'SAME_SIZE_EQUIVOCATION',
  }[mutation]
  if (canonical(supplied) !== canonical(expected)) throw new Error(`${mutation} hostile input value changed`)
}

function disposition(dimensions, bindingPresent) {
  const values = Object.values(dimensions)
  if (values.some((item) => item.state === 'CONTRADICTED')) return 'REFUSE'
  if (!bindingPresent || values.some((item) => item.state === 'UNCHECKABLE' || item.state === 'NOT_ESTABLISHED')) return 'ESCALATE'
  return 'RELY'
}

function verifyEventBinding(record, acceptedKey, expected) {
  exact(record, ['signature_b64', 'statement'], 'event binding')
  const statement = exact(record.statement, [
    'allocation_id', 'authority_id', 'authority_result', 'beneficiary', 'binding_id',
    'covenant_id', 'custody_result', 'custody_source_transaction_id',
    'device_report_sha256', 'evidence_result', 'exclusivity_result',
    'lineage_artifact_digest', 'lineage_node_id', 'lineage_result',
    'model_commitment', 'notional_amount', 'profile', 'promise_attestation',
    'request_commitment', 'response_commitment', 'transaction_id', 'unit',
  ], 'event binding statement')
  if (statement.profile !== 'glyph.compute-contract-event-binding/1' || statement.authority_id !== acceptedKey.authority_id) throw new Error('event binding authority or profile changed')
  for (const field of Object.keys(expected)) if (statement[field] !== expected[field]) throw new Error(`event binding ${field} changed`)
  if (statement.transaction_id !== expected.transaction_id || statement.notional_amount !== 50000 || statement.unit !== 'TEST_USD') throw new Error('event binding relationship changed')
  exact(acceptedKey, ['authority_id', 'public_key_spki_b64'], 'accepted event authority')
  const key = createPublicKey({ key: decodeBase64Canonical(acceptedKey.public_key_spki_b64, 'accepted event key'), format: 'der', type: 'spki' })
  if (key.asymmetricKeyType !== 'ed25519' || !verifySignature(null, Buffer.from(canonical(statement)), key, decodeBase64Canonical(record.signature_b64, 'event binding signature'))) throw new Error('event binding signature failed')
  return sha256(Buffer.from(canonical(record)))
}

function verifyHostileInputs(record, acceptedKey, eventBindingDigest, baselineInputs) {
  exact(record, ['signature_b64', 'statement'], 'hostile input bundle')
  const statement = exact(record.statement, ['authority_id', 'baseline_event_binding_digest', 'inputs', 'profile'], 'hostile input statement')
  if (statement.profile !== 'glyph.compute-contract-hostile-inputs/1' || statement.authority_id !== acceptedKey.authority_id || statement.baseline_event_binding_digest !== eventBindingDigest) throw new Error('hostile input bundle jurisdiction changed')
  if (!Array.isArray(statement.inputs) || statement.inputs.length !== Object.keys(MUTATION_RULES).length) throw new Error('hostile input member set changed')
  const inputs = new Map()
  for (const input of statement.inputs) {
    exact(input, ['input_name', 'mutation_id', 'supplied_value'], 'hostile input')
    const rule = MUTATION_RULES[input.mutation_id]
    if (!rule || rule.input_name !== input.input_name || inputs.has(input.mutation_id)) throw new Error('hostile input identity changed')
    validateHostileValue(input.mutation_id, input.supplied_value, baselineInputs[input.input_name])
    inputs.set(input.mutation_id, input)
  }
  if (canonical([...inputs.keys()].sort()) !== canonical(Object.keys(MUTATION_RULES).sort())) throw new Error('hostile input set changed')
  exact(acceptedKey, ['authority_id', 'public_key_spki_b64'], 'accepted event authority')
  const key = createPublicKey({ key: decodeBase64Canonical(acceptedKey.public_key_spki_b64, 'accepted event key'), format: 'der', type: 'spki' })
  if (key.asymmetricKeyType !== 'ed25519' || !verifySignature(null, Buffer.from(canonical(statement)), key, decodeBase64Canonical(record.signature_b64, 'hostile input signature'))) throw new Error('hostile input signature failed')
  return { bundle_digest: sha256(Buffer.from(canonical(record))), inputs }
}

function applyHostileInput(dimensions, mutation, verifiedHostiles) {
  if (!mutation) return
  const rule = MUTATION_RULES[mutation]
  const input = verifiedHostiles.inputs.get(mutation)
  if (!rule || !input) throw new Error(`unknown hostile mutation: ${mutation}`)
  const inputDigest = sha256(Buffer.from(canonical(input)))
  dimensions[rule.dimension] = dimension(rule.state, [rule.reason_code], [...dimensions[rule.dimension].evidence_sha256, verifiedHostiles.bundle_digest, inputDigest])
}

function checkDimension(value, label) {
  exact(value, ['evidence_sha256', 'reason_codes', 'state'], label)
  if (!STATES.has(value.state) || !Array.isArray(value.reason_codes) || value.reason_codes.length === 0 || value.reason_codes.some((item) => typeof item !== 'string' || !/^[A-Z0-9_]+$/.test(item))) throw new Error(`${label} reason or state changed`)
  if (!Array.isArray(value.evidence_sha256) || value.evidence_sha256.length === 0 || value.evidence_sha256.some((item) => !isDigest(item))) throw new Error(`${label} evidence changed`)
  if (canonical([...value.reason_codes].sort()) !== canonical(value.reason_codes) || new Set(value.evidence_sha256).size !== value.evidence_sha256.length) throw new Error(`${label} arrays are not canonical`)
}

export function checkReport(report) {
  exact(report, ['cases', 'external_counter_increment', 'mutation', 'notional_relationship', 'policy', 'profile', 'source_profiles'], 'report')
  if (report.profile !== REPORT_PROFILE || (report.mutation !== 'NONE' && !MUTATION_RULES[report.mutation])) throw new Error('report profile or mutation changed')
  exact(report.external_counter_increment, ['D', 'I', 'W', 'r'], 'counter increment')
  if (Object.values(report.external_counter_increment).some((value) => value !== 0)) throw new Error('external counter increment changed')
  exact(report.notional_relationship, ['amount', 'transaction_id', 'unit'], 'notional relationship')
  if (report.notional_relationship.amount !== 50000 || report.notional_relationship.transaction_id !== 'compute-contract-001' || report.notional_relationship.unit !== 'TEST_USD') throw new Error('notional relationship changed')
  exact(report.policy, ['profile', 'required_dimensions', 'rules'], 'report policy')
  exact(report.policy.rules, ['contradiction', 'missing_or_uncheckable', 'satisfied'], 'report policy rules')
  if (report.policy.profile !== 'glyph.compute-contract-receiver-policy/1' || canonical(report.policy.required_dimensions) !== canonical(DIMENSIONS) || canonical(report.policy.rules) !== canonical({ contradiction: 'REFUSE', missing_or_uncheckable: 'ESCALATE', satisfied: 'RELY' })) throw new Error('report policy changed')
  exact(report.source_profiles, ['attestation', 'custody', 'exclusivity', 'lineage', 'promise'], 'source profiles')
  if (canonical(report.source_profiles) !== canonical({ attestation: 'bulla.attestation-boundary/0.1-experimental', custody: 'bulla.answerability-network/0.1-experimental', exclusivity: 'glyph.assurance-exclusivity/0.1-experimental', lineage: 'bulla.reliance-map/0.1-experimental', promise: 'bulla.action-receipt/0.2' })) throw new Error('source profiles changed')
  if (!Array.isArray(report.cases) || report.cases.length !== 2) throw new Error('report cases changed')
  for (const entry of report.cases) {
    exact(entry, ['case_id', 'dimensions', 'execution_relation', 'externality', 'funds_moved', 'receiver_disposition', 'scope'], 'report case')
    exact(entry.dimensions, DIMENSIONS, 'report dimensions')
    for (const name of DIMENSIONS) checkDimension(entry.dimensions[name], `${entry.case_id} ${name}`)
  }
  const [unbound, constructed] = report.cases
  if (unbound.case_id !== 'unbound_public_evidence' || unbound.scope !== 'PUBLIC_FIXTURES_WITHOUT_AUTHENTICATED_SHARED_EVENT_BINDING' || unbound.execution_relation !== 'NOT_ESTABLISHED' || unbound.externality !== 'NOT_ESTABLISHED' || unbound.funds_moved !== false || unbound.receiver_disposition !== disposition(unbound.dimensions, false)) throw new Error('unbound case changed')
  const unboundExpected = {
    authority: ['NOT_ESTABLISHED', ['NO_SHARED_EVENT_AUTHORITY']], custody: ['NOT_ESTABLISHED', ['PROJECT_HISTORY_NOT_BOUND_TO_RELATIONSHIP']], evidence: ['NOT_ESTABLISHED', ['NO_AUTHENTICATED_SHARED_EVENT_BINDING', 'NO_VERIFIED_INFERENCE_RELATION']], exclusivity: ['NOT_ESTABLISHED', ['BINDING_NOT_LINKED_TO_PUBLIC_EVENT']], lineage: ['NOT_ESTABLISHED', ['DECLARED_GRAPH_NOT_BOUND_TO_RELATIONSHIP']], promise: ['ESTABLISHED', ['ACTION_RECEIPT_INTEGRITY_VERIFIED_TO_DIGEST']],
  }
  for (const [name, [state, reasons]] of Object.entries(unboundExpected)) if (unbound.dimensions[name].state !== state || canonical(unbound.dimensions[name].reason_codes) !== canonical(reasons)) throw new Error(`unbound ${name} conclusion changed`)
  if (constructed.case_id !== 'constructed_closed_control' || constructed.scope !== 'PROJECT_OPERATED' || constructed.externality !== 'NOT_ESTABLISHED' || constructed.funds_moved !== false) throw new Error('constructed case changed')
  const mutationRule = report.mutation === 'NONE' ? null : MUTATION_RULES[report.mutation]
  for (const name of DIMENSIONS) {
    const expectedState = mutationRule?.dimension === name ? mutationRule.state : 'ESTABLISHED'
    const expectedReason = mutationRule?.dimension === name ? mutationRule.reason_code : BASELINE_REASONS[name]
    if (constructed.dimensions[name].state !== expectedState || canonical(constructed.dimensions[name].reason_codes) !== canonical([expectedReason])) throw new Error(`constructed ${name} conclusion disagrees with mutation`)
  }
  const expectedExecution = constructed.dimensions.evidence.state === 'ESTABLISHED' ? 'ESTABLISHED_INSIDE_PROJECT_FIXTURE' : 'NOT_ESTABLISHED'
  if (constructed.execution_relation !== expectedExecution || constructed.receiver_disposition !== disposition(constructed.dimensions, true)) throw new Error('constructed disposition disagrees with policy')
  return report
}

export async function computeReport(packetRoot, mutation = null) {
  const verified = verifyPacket(packetRoot)
  const root = verified.root
  const policy = exact(readJson(join(root, 'receiver-policy.json'), 'receiver policy'), ['accepted_event_authority', 'profile', 'required_dimensions', 'rules'], 'receiver policy')
  if (policy.profile !== 'glyph.compute-contract-receiver-policy/1' || canonical(policy.required_dimensions) !== canonical(DIMENSIONS)) throw new Error('receiver policy changed')
  exact(policy.rules, ['contradiction', 'missing_or_uncheckable', 'satisfied'], 'receiver policy rules')
  if (policy.rules.contradiction !== 'REFUSE' || policy.rules.missing_or_uncheckable !== 'ESCALATE' || policy.rules.satisfied !== 'RELY') throw new Error('receiver policy disposition rules changed')

  const pythonEnvironment = { ...process.env, PYTHONDONTWRITEBYTECODE: '1' }
  const promiseOutput = run(PYTHON, ['-B', '-I', join(root, 'verify-promise.py'), root, join(root, 'inputs', 'promise', 'action-receipt.json')], { env: pythonEnvironment })
  const promise = JSON.parse(promiseOutput)
  if (promise.amount !== 50000 || promise.unit !== 'TEST_USD' || promise.transaction_id !== 'compute-contract-001' || promise.model_commitment !== `sha256:${'55'.repeat(32)}` || promise.request_commitment !== `sha256:${'66'.repeat(32)}`) throw new Error('promise relationship changed')

  const attestationRoot = join(root, 'inputs', 'attestation')
  try { run(PYTHON, ['-B', '-I', join(attestationRoot, 'check.py')], { cwd: attestationRoot, env: pythonEnvironment }) }
  finally { rmSync(join(attestationRoot, 'verifier.log'), { force: true }) }
  const attestation = readJson(join(root, 'inputs', 'attestation', 'generated', 'report.json'), 'attestation report')
  if (attestation.profile !== 'bulla.attestation-boundary-report/0.1-experimental') throw new Error('attestation report profile changed')

  const { verifyAnswerabilityNetwork } = await import(pathToFileURL(join(root, 'verifiers', 'answerability-network', 'kernel.mjs')).href)
  const custody = await verifyAnswerabilityNetwork(loadDirectory(join(root, 'inputs', 'custody', 'dossier')), new Uint8Array(readFileSync(join(root, 'inputs', 'custody', 'context.json'))))
  if (custody.profile !== 'bulla.answerability-network-report/0.1-experimental' || custody.exit_code !== 0 || custody.receipt_inclusion !== 'VERIFIED' || custody.history_consistency !== 'CONSISTENT_AT_COMPARED_SIZE') throw new Error('custody fixture did not verify')
  const custodyPromise = readJson(join(root, 'inputs', 'custody', 'dossier', 'procurement', 'promise.json'), 'custody promise')
  const custodySourceTransactionId = custodyPromise?.action?.subject?.transaction_id
  if (custodySourceTransactionId !== 'inference-job-001') throw new Error('custody source transaction changed')

  const { evaluateContext } = await import(pathToFileURL(join(root, 'verifiers', 'assurance-exclusivity', 'kernel.mjs')).href)
  const assurance = evaluateContext(readJson(join(root, 'inputs', 'exclusivity', 'fixture.json'), 'assurance fixture'))
  if (assurance.profile !== 'glyph.assurance-exclusivity-report/0.1-experimental') throw new Error('assurance report profile changed')
  const binding = assurance.binding_cases.find((item) => item.accepted_mechanism === 'BANK_ESCROW')
  if (!binding || binding.amount !== 50000 || binding.unit !== 'TEST_USD' || binding.stage !== 'EXCLUSIVELY_BOUND' || binding.allocation_id !== 'allocation-1' || binding.binding_id !== 'binding-1' || binding.beneficiary !== 'buyer-1' || binding.covenant_id !== 'covenant-1') throw new Error('exclusive binding fixture changed')

  const { computeRelianceMap } = await import(pathToFileURL(join(root, 'verifiers', 'reliance-map', 'kernel.mjs')).href)
  const lineage = await computeRelianceMap(readFileSync(join(root, 'inputs', 'lineage', 'graph.json')), readFileSync(join(root, 'inputs', 'lineage', 'correction-ledger.json')), readFileSync(join(root, 'inputs', 'lineage', 'context.json')))
  if (lineage.profile !== 'bulla.reliance-map-report/0.1-experimental' || lineage.summary.affected !== 2500 || lineage.summary.not_affected !== 5000 || lineage.summary.undetermined !== 2500) throw new Error('lineage fixture changed')
  const lineageNode = lineage.results.find((item) => item.node_id === 'decision-00000')
  if (!lineageNode || lineageNode.status !== 'AFFECTED' || lineageNode.conditional_action !== 'RECHECK_REQUIRED') throw new Error('lineage selected node changed')

  const sourceDigests = {
    attestation: attestation.report_sha256,
    authority: assurance.pre_reliance_forum.commitment_digest,
    custody: custody.report_digest,
    exclusivity: sha256(Buffer.from(canonical(binding))),
    lineage: lineage.report_digest,
    promise: promise.attestation,
  }
  const unboundDimensions = {
    authority: dimension('NOT_ESTABLISHED', ['NO_SHARED_EVENT_AUTHORITY'], [sourceDigests.authority]),
    custody: dimension('NOT_ESTABLISHED', ['PROJECT_HISTORY_NOT_BOUND_TO_RELATIONSHIP'], [sourceDigests.custody]),
    evidence: dimension(attestation.combined_execution_relation.state, attestation.combined_execution_relation.reason_codes, [sourceDigests.attestation]),
    exclusivity: dimension('NOT_ESTABLISHED', ['BINDING_NOT_LINKED_TO_PUBLIC_EVENT'], [sourceDigests.exclusivity]),
    lineage: dimension('NOT_ESTABLISHED', ['DECLARED_GRAPH_NOT_BOUND_TO_RELATIONSHIP'], [sourceDigests.lineage]),
    promise: dimension('ESTABLISHED', ['ACTION_RECEIPT_INTEGRITY_VERIFIED_TO_DIGEST'], [sourceDigests.promise]),
  }
  const unbound = {
    case_id: 'unbound_public_evidence',
    dimensions: unboundDimensions,
    execution_relation: 'NOT_ESTABLISHED',
    externality: 'NOT_ESTABLISHED',
    funds_moved: false,
    receiver_disposition: disposition(unboundDimensions, false),
    scope: 'PUBLIC_FIXTURES_WITHOUT_AUTHENTICATED_SHARED_EVENT_BINDING',
  }

  const expectedBinding = {
    allocation_id: binding.allocation_id,
    authority_result: sourceDigests.authority,
    beneficiary: binding.beneficiary,
    binding_id: binding.binding_id,
    covenant_id: binding.covenant_id,
    custody_result: sourceDigests.custody,
    custody_source_transaction_id: custodySourceTransactionId,
    device_report_sha256: attestation.artifacts.nvidia.details.report_sha256,
    evidence_result: sourceDigests.attestation,
    exclusivity_result: sourceDigests.exclusivity,
    lineage_artifact_digest: lineageNode.artifact_digest,
    lineage_node_id: lineageNode.node_id,
    lineage_result: sourceDigests.lineage,
    model_commitment: promise.model_commitment,
    promise_attestation: sourceDigests.promise,
    request_commitment: promise.request_commitment,
    response_commitment: `sha256:${attestation.artifacts.air.details.response_hash_hex}`,
    transaction_id: promise.transaction_id,
  }
  const eventBinding = readJson(join(root, 'constructed-event-binding.json'), 'constructed event binding')
  const eventBindingDigest = verifyEventBinding(eventBinding, policy.accepted_event_authority, expectedBinding)
  const baselineInputs = {
    allocation_stage: binding.stage,
    correction_authority: 'PRECOMMITTED',
    custody_history_status: custody.history_consistency,
    device_class_comparison: { expected_device_class: 'HOPPER', jurisdiction: 'PROJECT_FIXTURE_INPUT_NOT_SIGNED_NVIDIA_CLAIM', observed_device_class: 'HOPPER' },
    forum_commitment_order: 'BEFORE_RELIANCE',
    model_commitment: promise.model_commitment,
    nonce_freshness: 'FRESH_AT_PINNED_EVALUATION',
    portfolio_total_allocated: binding.amount,
    recourse_authorization: 'AUTHORIZED',
    request_occurrences: 1,
    response_commitment: expectedBinding.response_commitment,
    shared_event_binding: true,
  }
  const verifiedHostiles = verifyHostileInputs(readJson(join(root, 'hostile-inputs.json'), 'hostile inputs'), policy.accepted_event_authority, eventBindingDigest, baselineInputs)
  const constructedDimensions = {
    authority: dimension('ESTABLISHED', ['PRECOMMITTED_TYPED_AUTHORITIES_BOUND'], [sourceDigests.authority, eventBindingDigest]),
    custody: dimension('ESTABLISHED', ['PROJECT_OPERATED_TRANSACTION_MAPPING_AND_HISTORY_BOUND'], [sourceDigests.custody, eventBindingDigest]),
    evidence: dimension('ESTABLISHED', ['PROJECT_FIXTURE_EVENT_BINDING_CLOSES_DECLARED_RELATION'], [sourceDigests.attestation, eventBindingDigest]),
    exclusivity: dimension('ESTABLISHED', ['EXCLUSIVELY_BOUND_INSIDE_ACCEPTED_MECHANISM'], [sourceDigests.exclusivity, eventBindingDigest]),
    lineage: dimension('ESTABLISHED', ['DECLARED_DEPENDENCY_NODE_AND_GRAPH_BOUND'], [sourceDigests.lineage, eventBindingDigest]),
    promise: dimension('ESTABLISHED', ['ACTION_RECEIPT_BOUND_TO_CONSTRUCTED_RELATION'], [sourceDigests.promise, eventBindingDigest]),
  }
  applyHostileInput(constructedDimensions, mutation, verifiedHostiles)
  const constructed = {
    case_id: 'constructed_closed_control',
    dimensions: constructedDimensions,
    execution_relation: constructedDimensions.evidence.state === 'ESTABLISHED' ? 'ESTABLISHED_INSIDE_PROJECT_FIXTURE' : 'NOT_ESTABLISHED',
    externality: 'NOT_ESTABLISHED',
    funds_moved: false,
    receiver_disposition: disposition(constructedDimensions, true),
    scope: 'PROJECT_OPERATED',
  }
  return checkReport({
    cases: [unbound, constructed],
    external_counter_increment: { D: 0, I: 0, W: 0, r: 0 },
    mutation: mutation ?? 'NONE',
    notional_relationship: { amount: 50000, transaction_id: 'compute-contract-001', unit: 'TEST_USD' },
    policy: { profile: policy.profile, required_dimensions: policy.required_dimensions, rules: policy.rules },
    profile: REPORT_PROFILE,
    source_profiles: {
      attestation: 'bulla.attestation-boundary/0.1-experimental',
      custody: 'bulla.answerability-network/0.1-experimental',
      exclusivity: 'glyph.assurance-exclusivity/0.1-experimental',
      lineage: 'bulla.reliance-map/0.1-experimental',
      promise: 'bulla.action-receipt/0.2',
    },
  })
}

export async function main(argv = process.argv.slice(2)) {
  if (argv.length !== 1) throw new Error('usage: node run.mjs PACKET_ROOT')
  const report = await computeReport(argv[0])
  const expected = readJson(join(resolve(argv[0]), 'expected-report.json'), 'expected report')
  if (canonical(report) !== canonical(expected)) throw new Error('computed report differs from expected report')
  process.stdout.write(`${JSON.stringify(report, null, 2)}\n`)
}

if (process.argv[1] && realpathSync(fileURLToPath(import.meta.url)) === realpathSync(resolve(process.argv[1]))) {
  main().catch((error) => { process.stderr.write(`${error.message}\n`); process.exitCode = 1 })
}
