export const meta = {
  name: 'security-sweep',
  description: "Map a repo's attack surface, then run an isolated adversarial security-guard review per high-risk unit with cross-model verification. Depth-per-unit, never whole-repo-at-once — the structure that catches what a converged self-audit misses.",
  phases: [
    { title: 'Map', detail: 'enumerate + risk-tier the attack surface (read-only Explore)' },
    { title: 'Review', detail: 'one isolated security-guard pass per unit (opus, xhigh)' },
    { title: 'Verify', detail: 'cross-model refute + exploit per finding (different model)' },
    { title: 'Report', detail: 'dedup, triage, block-ship list + honest residuals' },
  ],
}

// ---- args (all optional) ----
// path:        repo root or a SUBDIR to scope the sweep (test small by pointing here)
// tiers:       which risk tiers to review, e.g. ['T0'] or ['T0','T1']
// maxUnits:    hard cap on fan-out (cost ceiling); overflow is logged, never silently dropped
// verifyModel: the cross-model verifier (must differ from the opus finder) — default 'sonnet'
const path = (args && args.path) || '.'
const tiers = (args && args.tiers) || ['T0']
const maxUnits = (args && args.maxUnits) || 12
const verifyModel = (args && args.verifyModel) || 'sonnet'

const UNIT_SCHEMA = {
  type: 'object',
  properties: {
    units: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'short stable id, e.g. returns-complete' },
          tier: { type: 'string', enum: ['T0', 'T1', 'T2'] },
          entry: { type: 'string', description: 'primary entry-point / handler / command file path' },
          files: {
            type: 'array', items: { type: 'string' },
            description: 'entry PLUS the auth/ownership/data helper files it directly calls (one hop only)',
          },
          surface: { type: 'string', description: 'what it exposes: authz | auth | secret | PII | money/value | mutation | upload | webhook | admin | parse | ipc | read' },
          why: { type: 'string', description: 'one line: why this tier' },
        },
        required: ['id', 'tier', 'entry', 'files', 'surface'],
      },
    },
  },
  required: ['units'],
}

const FINDINGS_SCHEMA = {
  type: 'object',
  properties: {
    findings: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          title: { type: 'string' },
          location: { type: 'string', description: 'file:line or function' },
          severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },
          trigger: { type: 'string', description: 'concrete attacker steps / input' },
          fix: { type: 'string' },
        },
        required: ['title', 'location', 'severity', 'trigger', 'fix'],
      },
    },
  },
  required: ['findings'],
}

const VERDICT_SCHEMA = {
  type: 'object',
  properties: {
    real: { type: 'boolean' },
    confidence: { type: 'string', enum: ['high', 'medium', 'low'] },
    exploit: { type: 'string', description: 'concrete exploit if real; else why it is refuted/safe' },
  },
  required: ['real', 'confidence', 'exploit'],
}

// ---- Phase 1: MAP the attack surface (read-only) ----
phase('Map')
log(`Mapping attack surface under ${path} (tiers: ${tiers.join(', ')})`)
const map = await agent(
  `Map the attack surface of a codebase for a security sweep. Repo/scope root: ${path}. The project may be of ANY kind — web/API service, CLI, library/SDK, mobile or desktop backend, infra/IaC, data pipeline, smart contract. First infer what it is from its structure, then enumerate accordingly.

Enumerate the security-relevant UNITS to review. A unit = one entry point / trust boundary PLUS the auth/validation/data helper files it DIRECTLY calls (one hop only — enough to judge whether an authorization/validation check exists; do NOT pull the whole import graph). Entry points include, depending on the project: HTTP/RPC/GraphQL handlers, CLI commands, message/queue/cron/event consumers, auth/session flows, deserialization/parse boundaries, file/IO and FFI boundaries, public SDK functions, privileged/admin operations.

Risk-tier each unit:
- T0 = authorization & access control, authentication/session, secret/credential handling, sensitive data (PII), and value/state of consequence (money, balances, permissions, ledger).
- T1 = other state mutations or side effects (writes, webhooks, admin actions, queue/cron consumers, external calls).
- T2 = read/display/pure-compute only.

Only enumerate these tiers: ${tiers.join(', ')}. For each unit resolve the entry's directly-imported auth/validation/data helpers to real file paths so the reviewer can read them.

Be EXHAUSTIVE for the requested tiers — completeness is the goal; a missed entry point is the failure mode. Return the unit list.`,
  { label: 'map-surface', phase: 'Map', agentType: 'Explore', schema: UNIT_SCHEMA }
)

let units = ((map && map.units) || []).filter(u => tiers.includes(u.tier))
units.sort((a, b) => a.tier.localeCompare(b.tier)) // T0 first
const totalFound = units.length
if (totalFound > maxUnits) {
  log(`⚠️ COST CAP: ${totalFound} units found, reviewing first ${maxUnits} by tier. DROPPED ${totalFound - maxUnits} — re-run with higher maxUnits or narrower scope/tiers to cover them.`)
  units = units.slice(0, maxUnits)
}
log(`${units.length} units queued for review`)

// ---- Phase 2+3: REVIEW each unit in isolation, then VERIFY each finding cross-model (pipelined, no barrier) ----
const reviewed = await pipeline(
  units,
  (u) => agent(
    `Security review this unit IN ISOLATION. Read ONLY these files: ${u.files.join(', ')}.
Entry handler: ${u.entry}. Exposed surface: ${u.surface}. Risk tier: ${u.tier}.
Apply your full hunt checklist and the adversarial self-check before reporting. Output only findings that survive your own refutation.`,
    { label: `review:${u.id}`, phase: 'Review', agentType: 'security-guard', schema: FINDINGS_SCHEMA }
  ),
  (rev, u) => parallel(((rev && rev.findings) || []).map(f => () =>
    agent(
      `Adversarially verify this security finding as an INDEPENDENT skeptic on a different model than the finder. Re-read the cited code and try to REFUTE it. Default real=false unless you can construct a concrete, specific exploit.

Finding: ${String(f.severity).toUpperCase()} — ${f.title}
Location: ${f.location}
Claimed trigger: ${f.trigger}
Proposed fix: ${f.fix}
Unit files (read these): ${u.files.join(', ')}`,
      { label: `verify:${u.id}`, phase: 'Verify', model: verifyModel, schema: VERDICT_SCHEMA }
    ).then(v => ({ unit: u.id, tier: u.tier, ...f, verdict: v }))
  ))
)

const allFindings = reviewed.flat().filter(Boolean)
const confirmed = allFindings.filter(x => x.verdict && x.verdict.real)
log(`${confirmed.length}/${allFindings.length} findings survived cross-model verification`)

// ---- Phase 4: REPORT (dedup, triage, honest residuals) ----
phase('Report')
const report = await agent(
  `Produce a pre-ship security report from these CROSS-MODEL-VERIFIED findings. Dedupe overlapping findings across units, order by severity, and name the 1-2 that should BLOCK ship.

Verified findings (JSON):
${JSON.stringify(confirmed, null, 2)}

Then write a RESIDUAL RISK section, honestly: tiers reviewed = ${tiers.join(', ')}; units reviewed = ${units.length}${totalFound > maxUnits ? `; ${totalFound - maxUnits} units dropped by the cost cap (NOT reviewed)` : ''}. Do not claim "clean" for any scope that was not reviewed. List the top assumptions a deeper pass should test.`,
  { label: 'report', phase: 'Report' }
)

return {
  scope: path,
  tiers,
  unitsFound: totalFound,
  unitsReviewed: units.length,
  findingsRaw: allFindings.length,
  findingsConfirmed: confirmed.length,
  confirmed,
  report,
}
