import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import test from "node:test";
import {
  EXPECTED,
  PROTECTED_DECISIONS,
  PROTECTED_INPUT_CLASSES,
  decodeBase58,
  readManifest,
  root,
  supportedPrograms,
  verifyCanonicalManifest,
} from "../scripts/release-policy.mjs";
import {
  assertGeneratedOutputAllowed,
  assertGeneratedPathAllowed,
  assertNotSymlink,
  assertProgramIsolation,
  assertLockfileScope,
  assertNoExcludedJsonActivation,
  assertNoExcludedReleaseClaims,
  assertNoKeyMaterial,
  assertReadinessCommitProvenance,
  workspaceMembers,
} from "../scripts/verify-release-scope.mjs";
import {
  assertIdlInterface,
  assertNoProtectedInterfaceDrift,
  extractSourceInterface,
  sourceInterfaceDigest,
} from "../scripts/interface-policy.mjs";

const manifest = verifyCanonicalManifest(readManifest());
const byName = new Map(manifest.programs.map((program) => [program.name, program]));
const dispositionByName = Object.fromEntries(
  Object.entries(EXPECTED).flatMap(([disposition, names]) =>
    names.map((name) => [name, disposition]),
  ),
);

const camelCase = (name) => name.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
const toIdlType = (type) => {
  if (type === "String") return "string";
  if (type === "Pubkey") return "pubkey";
  if (/^[ui]\d+$/.test(type) || type === "bool") return type;
  const vector = type.match(/^Vec<(.+)>$/);
  if (vector) return { vec: toIdlType(vector[1]) };
  return { defined: { name: type } };
};
const canonicalIdlFixture = (program, sourceInterface) => {
  const records = new Map(sourceInterface.records.map((record) => [record.name, record]));
  return {
    address: program.programId,
    instructions: sourceInterface.instructions.map((instruction) => {
      const contextName = instruction.context.match(/^Context<(\w+)>$/)[1];
      const context = records.get(contextName);
      return {
        name: camelCase(instruction.name),
        args: instruction.args.map(([name, type]) => ({
          name: camelCase(name),
          type: toIdlType(type),
        })),
        accounts: context.fields.map(([name], index) => {
          const metadata = context.accountMetadata[index];
          return {
            name: camelCase(name),
            writable: metadata.writable,
            signer: metadata.signer,
            ...(metadata.pda
              ? {
                  pda: {
                    seeds: structuredClone(metadata.pda.seeds),
                    ...(metadata.pda.program
                      ? { program: structuredClone(metadata.pda.program) }
                      : {}),
                  },
                }
              : {}),
            ...(metadata.relations.length
              ? { relations: metadata.relations.map(camelCase) }
              : {}),
          };
        }),
      };
    }),
    accounts: sourceInterface.records
      .filter((record) => record.kind === "account")
      .map((record) => ({
        name: record.name,
        type: {
          kind: "struct",
          fields: record.fields.map(([name, type]) => ({
            name: camelCase(name),
            type: toIdlType(type),
          })),
        },
      })),
    events: sourceInterface.records
      .filter((record) => record.kind === "event")
      .map((record) => ({
        name: record.name,
        fields: record.fields.map(([name, type]) => ({
          name: camelCase(name),
          type: toIdlType(type),
        })),
      })),
    errors: (sourceInterface.errors ?? []).map((name, index) => ({
      code: 6000 + index,
      name,
      msg: name,
    })),
    types: (sourceInterface.definedTypes ?? []).map((definition) => ({
      name: definition.name,
      type: {
        kind: "enum",
        variants: definition.variants.map((name) => ({ name })),
      },
    })),
  };
};

for (const [name, disposition] of Object.entries(dispositionByName)) {
  test(`${name} has canonical ${disposition} disposition`, () => {
    const entry = byName.get(name);
    assert.ok(entry);
    assert.equal(entry.disposition, disposition);
    assert.equal(entry.buildEligible, disposition === "supported-candidate");
    assert.equal(entry.rehearsalEligible, disposition === "supported-candidate");
    assert.equal(entry.protectedDecisionUse, "prohibited");
    assert.equal(entry.sourcePath, `programs/${name}/src/lib.rs`);
    assert.equal(entry.cargoManifestPath, `programs/${name}/Cargo.toml`);
    assert.equal(decodeBase58(entry.programId).length, 32);
    const source = readFileSync(resolve(root, entry.sourcePath), "utf8");
    assert.equal(source.match(/declare_id!\("([^"]+)"\)/)[1], entry.programId);
  });
}

test("all program IDs are pinned and globally unique", () => {
  assert.equal(new Set(manifest.programs.map((program) => program.programId)).size, 15);
});

test("the protected input and decision matrix is exact", () => {
  assert.deepEqual(manifest.policy.protectedInputClasses, PROTECTED_INPUT_CLASSES);
  assert.deepEqual(manifest.policy.protectedDecisions, PROTECTED_DECISIONS);
});

test("all supported source interfaces match exact canonical instruction and structural hashes", () => {
  for (const name of supportedPrograms(manifest)) {
    const program = byName.get(name);
    const source = readFileSync(resolve(root, program.sourcePath), "utf8");
    const sourceInterface = extractSourceInterface(source);
    assert.deepEqual(
      sourceInterface.instructions.map((instruction) => instruction.name),
      program.allowedInstructions,
    );
    assert.equal(sourceInterfaceDigest(source), program.sourceInterfaceSha256);
    assert.equal(createHash("sha256").update(source).digest("hex"), program.sourceSha256);
    assert.notEqual(
      createHash("sha256").update(`${source}\n// decision alias drift`).digest("hex"),
      program.sourceSha256,
    );
  }
});

test("all nine protected decisions are rejected as new instruction, field, or type drift", () => {
  const canonical = { instructions: [], records: [] };
  const fixtures = [
    "access",
    "custody",
    "dispute",
    "eligibility",
    "pricing",
    "routing",
    "settlement",
    "slashing",
    "value_transfer",
  ];
  for (const identifier of fixtures) {
    assert.throws(() =>
      assertNoProtectedInterfaceDrift(
        { instructions: [{ name: `set_${identifier}`, args: [] }], records: [] },
        canonical,
        "fixture",
      ),
    );
    assert.throws(() =>
      assertNoProtectedInterfaceDrift(
        {
          instructions: [],
          records: [{ kind: "account", name: "Record", fields: [[identifier, "bool"]] }],
        },
        canonical,
        "fixture",
      ),
    );
    assert.throws(() =>
      assertNoProtectedInterfaceDrift(
        {
          instructions: [],
          records: [{ kind: "account", name: "Record", fields: [["state", identifier]] }],
        },
        canonical,
        "fixture",
      ),
    );
  }
});

test("the release workspace exactly matches the supported-candidate allowlist", () => {
  const cargo = readFileSync(resolve(root, "Cargo.toml"), "utf8");
  assert.deepEqual(workspaceMembers(cargo), supportedPrograms(manifest));
  assert.doesNotMatch(cargo.match(/members\s*=\s*\[([\s\S]*?)\]/)[1], /\*/);
});

test("dependency and cross-program invocation policy fails closed", () => {
  const all = manifest.programs.map((program) => program.name);
  const dependency = '\nanchor-lang = "=0.32.1"\n';
  assert.throws(() =>
    assertProgramIsolation(
      "identity_registry",
      "pub fn route() { invoke(&ix); }",
      dependency,
      all,
    ),
  );
  assert.throws(() =>
    assertProgramIsolation(
      "identity_registry",
      "const TARGET: &str = \"trust_data_bridge\";",
      dependency,
      all,
    ),
  );
  assert.throws(() =>
    assertProgramIsolation(
      "identity_registry",
      "pub fn isolated() {}",
      `${dependency}other = { path = "../trust_data_bridge" }\n`,
      all,
    ),
  );
});

test("Cargo.lock contains supported candidates and no excluded source packages", () => {
  const allowed = supportedPrograms(manifest);
  const excluded = [...EXPECTED.retired, ...EXPECTED["redesign-required"]];
  const lockfile = readFileSync(resolve(root, "Cargo.lock"), "utf8");
  assert.doesNotThrow(() => assertLockfileScope(lockfile, allowed, excluded));
  assert.throws(() =>
    assertLockfileScope(
      `${lockfile}\n[[package]]\nname = "trust_data_bridge"\nversion = "0.1.0"\n`,
      allowed,
      excluded,
    ),
  );
});

test("excluded programs cannot acquire positive release claims in public docs", () => {
  const excluded = [...EXPECTED.retired, ...EXPECTED["redesign-required"]];
  assert.throws(() =>
    assertNoExcludedReleaseClaims(
      "production_belief_verifier is release eligible",
      excluded,
      "fixture.md",
    ),
  );
  assert.throws(() =>
    assertNoExcludedReleaseClaims(
      "production_belief_verifier was retired before but is release eligible now",
      excluded,
      "PARTNER_LOCAL_REHEARSAL.md",
    ),
  );
  assert.throws(() =>
    assertNoExcludedReleaseClaims(
      "Trust Data Bridge is production-ready",
      excluded,
      "partner-notes.txt",
    ),
  );
  assert.doesNotThrow(() =>
    assertNoExcludedReleaseClaims(
      "production_belief_verifier is retired and excluded",
      excluded,
      "fixture.md",
    ),
  );
  assert.throws(() =>
    assertNoExcludedReleaseClaims(
      "production_belief_verifier is release eligible",
      excluded,
      "PARTNER_LOCAL_REHEARSAL.md",
    ),
  );
  assert.throws(() =>
    assertNoExcludedJsonActivation(
      { supportedPrograms: ["production_belief_verifier"] },
      excluded,
      "release.json",
    ),
  );
  assert.throws(() =>
    assertNoExcludedJsonActivation(
      { name: "production_belief_verifier", status: "supported-candidate" },
      excluded,
      "release.json",
    ),
  );
  for (const key of ["state", "phase", "futureVocabulary"]) {
    assert.throws(() =>
      assertNoExcludedJsonActivation(
        { displayName: "Trust Data Bridge", [key]: "ready" },
        excluded,
        "release.json",
      ),
    );
  }
  assert.throws(() =>
    assertNoExcludedJsonActivation(
      ["Trust-Data-Bridge"],
      excluded,
      "top-level-list.json",
    ),
  );
});

test("every excluded program alias style is rejected without substring false positives", () => {
  const excluded = [...EXPECTED.retired, ...EXPECTED["redesign-required"]];
  for (const name of excluded) {
    const words = name.split("_");
    const pascal = words.map((word) => word[0].toUpperCase() + word.slice(1)).join("");
    const camel = words[0] + words.slice(1).map((word) => word[0].toUpperCase() + word.slice(1)).join("");
    const aliases = [
      name,
      words.join("-"),
      words.map((word) => word[0].toUpperCase() + word.slice(1)).join(" "),
      pascal,
      camel,
      words.join(""),
    ];
    for (const alias of aliases) {
      assert.throws(
        () =>
          assertNoExcludedReleaseClaims(
            `${alias} is production-ready.`,
            excluded,
            `auditor-${alias}.txt`,
          ),
        `${alias} must be rejected`,
      );
    }
  }
  assert.doesNotThrow(() =>
    assertNoExcludedReleaseClaims(
      "TrustDataBridgework is production-ready, and DistrustDataBridge is production-ready.",
      excluded,
      "substring-controls.txt",
    ),
  );
});

test("arbitrary wallet names and Solana secret-key JSON shapes fail closed", () => {
  const secret = Array.from({ length: 64 }, (_, index) => index);
  assert.throws(() => assertNoKeyMaterial("wallet.json", {}));
  assert.throws(() => assertNoKeyMaterial("candidate/authority.json", {}));
  assert.throws(() => assertNoKeyMaterial("innocent-name.json", secret));
  assert.throws(() =>
    assertNoKeyMaterial("innocent-name.json", { nested: { privateKey: [1, 2, 3] } }),
  );
  assert.throws(() =>
    assertNoKeyMaterial(
      "deep/nested/meeting-notes.dat",
      undefined,
      `[${secret.join(", ")}]`,
    ),
  );
  assert.throws(() =>
    assertNoKeyMaterial(
      "innocent-name.txt",
      undefined,
      ["-----BEGIN ", "PRIVATE KEY-----", "\nnot-real"].join(""),
    ),
  );
  assert.doesNotThrow(() =>
    assertNoKeyMaterial("v3-program-dispositions.json", { schemaVersion: 2 }),
  );
});

test("generated artifact and IDL policy rejects excluded programs and signers", () => {
  const allowed = supportedPrograms(manifest);
  const excluded = [...EXPECTED.retired, ...EXPECTED["redesign-required"]];
  assert.doesNotThrow(() =>
    assertGeneratedOutputAllowed(
      "identity_registry.so",
      "",
      allowed,
      excluded,
    ),
  );
  assert.throws(() =>
    assertGeneratedOutputAllowed(
      "trust_data_bridge.so",
      "",
      allowed,
      excluded,
    ),
  );
  const adapter = byName.get("vaultfire_adapter");
  const adapterSource = readFileSync(resolve(root, adapter.sourcePath), "utf8");
  const adapterInterface = extractSourceInterface(adapterSource);
  const adapterIdl = canonicalIdlFixture(adapter, adapterInterface);
  assert.doesNotThrow(() =>
    assertGeneratedPathAllowed(
      "target/idl/vaultfire_adapter.json",
      adapterIdl,
      manifest,
      allowed,
      excluded,
    ),
  );
  assert.throws(() =>
    assertIdlInterface(
      {
        ...adapterIdl,
        instructions: [...adapterIdl.instructions, { name: "setRouting" }],
      },
      adapter,
      adapterInterface,
    ),
  );
  const wrongArgumentType = structuredClone(adapterIdl);
  wrongArgumentType.instructions.find((instruction) => instruction.args.length).args[0].type =
    "u64";
  assert.throws(() => assertIdlInterface(wrongArgumentType, adapter, adapterInterface));

  const wrongPrivilege = structuredClone(adapterIdl);
  wrongPrivilege.instructions
    .find((instruction) => instruction.accounts.some((account) => account.signer))
    .accounts.find((account) => account.signer).signer = false;
  assert.throws(() => assertIdlInterface(wrongPrivilege, adapter, adapterInterface));

  const missingPda = structuredClone(adapterIdl);
  const pdaAccount = missingPda.instructions
    .flatMap((instruction) => instruction.accounts)
    .find((account) => account.pda);
  delete pdaAccount.pda;
  assert.throws(() => assertIdlInterface(missingPda, adapter, adapterInterface));

  const wrongRelation = structuredClone(adapterIdl);
  const relatedAccount = wrongRelation.instructions
    .flatMap((instruction) => instruction.accounts)
    .find((account) => account.relations?.length);
  relatedAccount.relations = [];
  assert.throws(() => assertIdlInterface(wrongRelation, adapter, adapterInterface));

  const wrongAccountLayout = structuredClone(adapterIdl);
  wrongAccountLayout.accounts[0].type.fields[0].type = "bool";
  assert.throws(() => assertIdlInterface(wrongAccountLayout, adapter, adapterInterface));

  const wrongEventLayout = structuredClone(adapterIdl);
  wrongEventLayout.events[0].fields[0].type = "u64";
  assert.throws(() => assertIdlInterface(wrongEventLayout, adapter, adapterInterface));
  assert.throws(() =>
    assertIdlInterface(
      {
        ...adapterIdl,
        types: [
          {
            name: "AgentProfile",
            type: { kind: "struct", fields: [{ name: "eligibility", type: "bool" }] },
          },
        ],
      },
      adapter,
      adapterInterface,
    ),
  );
  assert.throws(() =>
    assertGeneratedOutputAllowed(
      "identity_registry.json",
      '{"name":"reputation_registry"}',
      allowed,
      excluded,
    ),
  );
  assert.throws(() =>
    assertGeneratedOutputAllowed(
      "identity_registry-keypair.json",
      "[]",
      allowed,
      excluded,
    ),
  );
  assert.throws(() =>
    assertGeneratedPathAllowed(
      "artifacts/other/reputation_registry.so",
      undefined,
      manifest,
      allowed,
      excluded,
    ),
  );
  assert.throws(() =>
    assertGeneratedPathAllowed(
      "generated-idls/trust_data_bridge.json",
      { address: byName.get("trust_data_bridge").programId, instructions: [] },
      manifest,
      allowed,
      excluded,
    ),
  );
  assert.throws(() =>
    assertGeneratedPathAllowed(
      "target/idl/identity_registry.json",
      { address: byName.get("ai_partnership_bonds").programId, instructions: [] },
      manifest,
      allowed,
      excluded,
    ),
  );
  const seen = new Set();
  assert.doesNotThrow(() =>
    assertGeneratedPathAllowed(
      "artifacts/sbf/identity_registry.so",
      undefined,
      manifest,
      allowed,
      excluded,
      seen,
    ),
  );
  assert.throws(() =>
    assertGeneratedPathAllowed(
      "artifacts/sbf/identity_registry.so",
      undefined,
      manifest,
      allowed,
      excluded,
      seen,
    ),
  );
  assert.throws(() => assertNotSymlink(true, "artifacts/sbf/identity_registry.so"));
  assert.throws(() =>
    assertGeneratedPathAllowed(
      "artifacts/sbf/notes.txt",
      undefined,
      manifest,
      allowed,
      excluded,
    ),
  );
  assert.throws(() =>
    assertGeneratedPathAllowed(
      "checksums/extra-sha256.txt",
      undefined,
      manifest,
      allowed,
      excluded,
    ),
  );
  assert.throws(() =>
    assertGeneratedPathAllowed(
      "target/debug/build-output",
      undefined,
      manifest,
      allowed,
      excluded,
    ),
  );
});

test("generated IDL PDA metadata must exactly match source seed semantics", () => {
  const adapter = byName.get("vaultfire_adapter");
  const adapterInterface = extractSourceInterface(
    readFileSync(resolve(root, adapter.sourcePath), "utf8"),
  );
  const adapterIdl = canonicalIdlFixture(adapter, adapterInterface);
  assert.doesNotThrow(() => assertIdlInterface(adapterIdl, adapter, adapterInterface));

  const profilePda = (idl) =>
    idl.instructions
      .flatMap((instruction) => instruction.accounts)
      .find((account) => account.pda?.seeds?.length === 2).pda;

  const wrongValue = structuredClone(adapterIdl);
  profilePda(wrongValue).seeds[0].value[0] ^= 1;
  assert.throws(() => assertIdlInterface(wrongValue, adapter, adapterInterface));

  const wrongOrder = structuredClone(adapterIdl);
  profilePda(wrongOrder).seeds.reverse();
  assert.throws(() => assertIdlInterface(wrongOrder, adapter, adapterInterface));

  const wrongKind = structuredClone(adapterIdl);
  profilePda(wrongKind).seeds[1] = { kind: "const", value: [1] };
  assert.throws(() => assertIdlInterface(wrongKind, adapter, adapterInterface));

  const wrongPath = structuredClone(adapterIdl);
  profilePda(wrongPath).seeds[1].path = "authority";
  assert.throws(() => assertIdlInterface(wrongPath, adapter, adapterInterface));

  const unexpectedProgram = structuredClone(adapterIdl);
  profilePda(unexpectedProgram).program = { kind: "const", value: [1] };
  assert.throws(() => assertIdlInterface(unexpectedProgram, adapter, adapterInterface));

  const accountability = byName.get("ai_accountability_bonds");
  const accountabilityInterface = extractSourceInterface(
    readFileSync(resolve(root, accountability.sourcePath), "utf8"),
  );
  const accountabilityIdl = canonicalIdlFixture(accountability, accountabilityInterface);
  assert.doesNotThrow(() =>
    assertIdlInterface(accountabilityIdl, accountability, accountabilityInterface),
  );
  const wrongAccountReference = structuredClone(accountabilityIdl);
  const referencedSeed = wrongAccountReference.instructions
    .flatMap((instruction) => instruction.accounts)
    .flatMap((account) => account.pda?.seeds ?? [])
    .find((seed) => seed.account);
  referencedSeed.account = "PartnershipBond";
  assert.throws(() =>
    assertIdlInterface(wrongAccountReference, accountability, accountabilityInterface),
  );
});

test("generated IDL enum variants and defined argument types match canonical source", () => {
  const partnership = byName.get("ai_partnership_bonds");
  const sourceInterface = extractSourceInterface(
    readFileSync(resolve(root, partnership.sourcePath), "utf8"),
  );
  const idl = canonicalIdlFixture(partnership, sourceInterface);
  assert.doesNotThrow(() => assertIdlInterface(idl, partnership, sourceInterface));

  const wrongEnum = structuredClone(idl);
  wrongEnum.types[0].type.variants[0].name = "Routing";
  assert.throws(() => assertIdlInterface(wrongEnum, partnership, sourceInterface));

  const wrongDefinedType = structuredClone(idl);
  wrongDefinedType.instructions.find((instruction) => instruction.name === "createBond").args[0].type =
    "u64";
  assert.throws(() => assertIdlInterface(wrongDefinedType, partnership, sourceInterface));
});

test("rehearsal follows ProgramData and requires Agave's disabled-authority sentinel", () => {
  const localScript = readFileSync(
    resolve(root, "scripts", "local-validator-rehearsal.sh"),
    "utf8",
  );
  const verifier = readFileSync(
    resolve(root, "scripts", "verify-local-validator.mjs"),
    "utf8",
  );
  assert.match(localScript, /--bpf-program/);
  assert.doesNotMatch(localScript, /program deploy|program write-buffer|set-upgrade-authority/);
  assert.match(verifier, /BPFLoaderUpgradeab1e11111111111111111111111/);
  assert.match(verifier, /parseProgramAccount/);
  assert.match(verifier, /parseDisabledProgramData/);
  assert.match(verifier, /DISABLED_AUTHORITY_SENTINEL/);
  assert.match(verifier, /bytes\[12\]/);
  assert.match(verifier, /bytes\.subarray\(13, 45\)/);
  assert.match(verifier, /ProgramData must start with ELF magic/);
  assert.match(verifier, /upgradeAuthority: null/);
  assert.doesNotMatch(verifier, /allowedImmutableLoaders/);
});

test("adapter is passive, agent-owned, closable, and has no protected-decision fields", () => {
  const adapter = readFileSync(
    resolve(root, "programs", "vaultfire_adapter", "src", "lib.rs"),
    "utf8",
  );
  assert.doesNotMatch(adapter, /reputation_score|identity_verified/);
  assert.doesNotMatch(adapter, /has_one = authority/);
  assert.match(adapter, /pub fn close_profile/);
  assert.match(adapter, /close = agent/);
  assert.match(adapter, /has_one = agent/);
});

test("supported record lifecycles return rent and permit renewal", () => {
  const identity = readFileSync(
    resolve(root, "programs", "identity_registry", "src", "lib.rs"),
    "utf8",
  );
  const privacy = readFileSync(
    resolve(root, "programs", "privacy_guarantees", "src", "lib.rs"),
    "utf8",
  );
  const governance = readFileSync(
    resolve(root, "programs", "multisig_governance", "src", "lib.rs"),
    "utf8",
  );
  const updateAccounts = identity.match(
    /pub struct UpdateAgent<'info> \{([\s\S]*?)\n\}/,
  )[1];
  const deregisterAccounts = identity.match(
    /pub struct DeregisterAgent<'info> \{([\s\S]*?)\n\}/,
  )[1];
  assert.doesNotMatch(updateAccounts, /close = authority/);
  assert.match(deregisterAccounts, /close = authority/);
  assert.match(deregisterAccounts, /#\[account\(mut\)\]\s+pub authority: Signer/);
  assert.match(privacy, /pub fn close_commitment/);
  assert.match(privacy, /checked_sub\(1\)/);
  assert.match(privacy, /close = agent/);
  assert.match(governance, /pub fn close_expired_proposal/);
  assert.match(governance, /close = proposer/);
  assert.match(governance, /address = proposal\.proposer/);
});

test("build and validator scripts derive candidates from the canonical manifest", () => {
  const build = readFileSync(resolve(root, "scripts", "build-sbf.sh"), "utf8");
  const verifier = readFileSync(resolve(root, "scripts", "verify-artifacts.mjs"), "utf8");
  const local = readFileSync(resolve(root, "scripts", "local-validator-rehearsal.sh"), "utf8");
  assert.match(build, /verify-artifacts\.mjs/);
  assert.match(verifier, /supportedPrograms\(dispositionManifest\)/);
  assert.match(
    verifier,
    /"--sbf-out-dir",[\s\S]*?"--",\s*"--locked"/,
    "Agave 2.3 must receive Cargo's locked mode after the argument separator",
  );
  assert.match(local, /list-supported-programs\.mjs/);
  for (const script of [build, verifier, local]) {
    assert.doesNotMatch(script, /programs\/\*\/(?:Cargo\.toml|src\/lib\.rs)/);
  }
});

test("source readiness has no stale commit attribution", () => {
  const readiness = JSON.parse(readFileSync(resolve(root, "MAINNET_READINESS.json"), "utf8"));
  assert.doesNotThrow(() => assertReadinessCommitProvenance(readiness));
  assert.throws(() =>
    assertReadinessCommitProvenance({
      ...readiness,
      asOfCommit: "cf1975db9ff12b946695069e42059eed25b3ae3f",
    }),
  );
});

test("artifact provenance is verifier-owned and cannot be asserted by an environment flag", () => {
  const verifier = readFileSync(resolve(root, "scripts", "verify-artifacts.mjs"), "utf8");
  const build = readFileSync(resolve(root, "scripts", "build-sbf.sh"), "utf8");
  assert.doesNotMatch(`${verifier}\n${build}`, /REPRODUCIBLE_BUILD_VERIFIED/);
  assert.match(verifier, /runOwnedBuild\(1,/);
  assert.match(verifier, /runOwnedBuild\(2,/);
  assert.match(verifier, /first\.equals\(second\)/);
  assert.match(verifier, /ephemeralProgramKeypairs/);
  assert.match(verifier, /ephemeralProgramKeypairsDeletedBeforePublication: true/);
  assert.match(verifier, /reproducibilityMethod: "verifier-owned-two-clean-builds-byte-comparison"/);
});

test("deployment maps remain absent and the migration entry point fails closed", () => {
  const anchor = readFileSync(resolve(root, "Anchor.toml"), "utf8");
  const migration = readFileSync(resolve(root, "migrations", "deploy.ts"), "utf8");
  assert.doesNotMatch(anchor, /^\[programs\./m);
  assert.match(migration, /throw new Error/);
  assert.doesNotMatch(migration, /setProvider|\.rpc\s*\(/);
});

test("committed-candidate enforcement is wired into CI and executable-evidence paths", () => {
  const workflow = readFileSync(resolve(root, ".github", "workflows", "ci.yml"), "utf8");
  const build = readFileSync(resolve(root, "scripts", "build-sbf.sh"), "utf8");
  const local = readFileSync(
    resolve(root, "scripts", "local-validator-rehearsal.sh"),
    "utf8",
  );
  const container = readFileSync(
    resolve(root, "scripts", "container-rehearsal.sh"),
    "utf8",
  );
  const gate = readFileSync(resolve(root, "scripts", "verify-release-scope.mjs"), "utf8");
  assert.match(workflow, /REQUIRE_COMMITTED_CANDIDATE: "1"/);
  assert.match(workflow, /EXPECTED_CANDIDATE_COMMIT: \$\{\{ github\.sha \}\}/);
  assert.match(build, /--require-committed-candidate/);
  assert.match(local, /--require-committed-candidate/);
  assert.ok(
    container.indexOf("--require-committed-candidate") <
      container.indexOf("command -v docker"),
    "host tree must be scanned before entering the container",
  );
  assert.match(gate, /scripts\/interface-policy\.mjs/);
  assert.match(gate, /git", \["ls-files"/);
  assert.match(gate, /status", "--porcelain", "--untracked-files=all"/);
});

test("README describes the current source-ID and historical-evidence boundaries", () => {
  const readme = readFileSync(resolve(root, "README.md"), "utf8");
  assert.match(readme, /PROGRAM_IDS\.md\s+— Six supported-candidate source IDs only/);
  assert.match(readme, /TEST_RESULTS\.md\s+— Superseded, non-executable evidence tombstone/);
  assert.doesNotMatch(readme, /PROGRAM_IDS\.md\s+— All 15 program IDs/);
  assert.doesNotMatch(readme, /TEST_RESULTS\.md\s+— Full end-to-end test results/);
});

test("native rehearsal validates compiler-resolved workspace metadata", () => {
  const rehearsal = readFileSync(resolve(root, "scripts", "ci-rehearsal.sh"), "utf8");
  const verifier = readFileSync(
    resolve(root, "scripts", "verify-cargo-metadata.mjs"),
    "utf8",
  );
  assert.match(rehearsal, /cargo metadata --locked --format-version 1 --no-deps/);
  assert.match(rehearsal, /verify-cargo-metadata\.mjs/);
  assert.match(verifier, /workspace_members/);
  assert.match(verifier, /local path dependency/);
  assert.match(verifier, /=0\.32\.1/);
});

test("IDL verifier isolates Anchor program-ID synchronization from canonical source", () => {
  const verifier = readFileSync(resolve(root, "scripts/verify-idls.mjs"), "utf8");
  assert.match(verifier, /"git",[\s\S]{0,80}"archive"/);
  assert.match(verifier, /\[programs\.localnet\]/);
  assert.match(verifier, /--locked/);
  assert.match(verifier, /--offline/);
  assert.match(verifier, /supportedSourceHashes\(temporaryPackage\)/);
  assert.match(verifier, /verifyCommittedCandidate\(sourceCommit\)/);
  assert.doesNotMatch(verifier, /keys\s+sync/);
  assert.doesNotMatch(verifier, /"anchor",[\s\S]{0,80}"deploy"/);
});

test("source-derived has_one relationships use Anchor IDL direction", () => {
  const accountability = byName.get("ai_accountability_bonds");
  const source = readFileSync(resolve(root, accountability.sourcePath), "utf8");
  const canonical = extractSourceInterface(source);
  const slash = canonical.records.find((record) => record.name === "SlashBond");
  const metadata = Object.fromEntries(
    slash.accountMetadata.map((account) => [account.name, account]),
  );
  assert.deepEqual(metadata.bonds_state.relations, []);
  assert.deepEqual(metadata.authority.relations, ["bonds_state"]);
});

test("source-derived error allowlists admit only declared Anchor errors", () => {
  const accountability = byName.get("ai_accountability_bonds");
  const source = readFileSync(resolve(root, accountability.sourcePath), "utf8");
  const canonical = extractSourceInterface(source);
  assert.deepEqual(canonical.errors.slice(0, 4), [
    "ZeroStake",
    "AlreadySlashed",
    "AlreadyWithdrawn",
    "BondSlashed",
  ]);
  const idl = canonicalIdlFixture(accountability, canonical);
  assert.doesNotThrow(() => assertIdlInterface(idl, accountability, canonical));
  idl.errors.push({ code: 6999, name: "BehaviorScoreRejected", msg: "not declared" });
  assert.throws(() => assertIdlInterface(idl, accountability, canonical));
});

test("the locked macro dependency remains compatible with Agave SBF Cargo", () => {
  const cargoLock = readFileSync(resolve(root, "Cargo.lock"), "utf8");
  assert.match(
    cargoLock,
    /name = "proc-macro-crate"\nversion = "3\.4\.0"/,
  );
  assert.doesNotMatch(
    cargoLock,
    /name = "proc-macro-crate"\nversion = "3\.5\.0"/,
  );
  assert.match(
    cargoLock,
    /name = "toml_parser"\nversion = "1\.0\.10\+spec-1\.1\.0"/,
  );
  assert.doesNotMatch(
    cargoLock,
    /name = "toml_parser"\nversion = "1\.1\./,
  );
  assert.doesNotMatch(cargoLock, /toml_edit 0\.25\./);
  assert.match(
    cargoLock,
    /name = "unicode-segmentation"\nversion = "1\.12\.0"/,
  );
  assert.doesNotMatch(
    cargoLock,
    /name = "unicode-segmentation"\nversion = "1\.13\./,
  );
});
