let s = import "../reflection/schema.ncl" in

# ADR System — Operational reflection guide
# Covers: authoring, reading, validating, and superseding ADRs in the ontoref ecosystem.
# All content in English. Schema field names (actor, depends_on, verify) are API identifiers.

let AdrAction = [|
  'new_adr,
  'read_adr,
  'validate_decision,
  'supersede_adr,
  'export_adr,
|] in

{
  style = {
    format          = "Nickel ADR",
    schema          = "adrs/defaults.ncl",
    content_lang    = "English",
    field_names     = "API identifiers — do not translate",
    invariant_check = "Every ADR decision string must be validated against .ontology/core.ncl before writing",
  },

  agent = {
    rules = [
      "Read adrs/defaults.ncl and adrs/schema.ncl before generating any ADR content",
      "Run `nickel export adrs/adr-NNN-*.ncl` to verify the file exports cleanly after writing",
      "Check .ontology/core.ncl invariants_at_risk and ontology_check.verdict before marking status = 'Accepted",
      "If verdict is 'Risky or 'Unsafe, require explicit justification in InvariantJustification before accepting",
      "All string values in id, title, context, decision, rationale, constraints, consequences must be in English",
      "Schema field names (name, description, closing_condition) are defined by ontoref-ontology in English",
      "Never create an ADR without at least one Hard constraint with a check_hint",
      "Superseded ADRs keep status = 'Superseded — do not delete them",
    ],
  },

  modes = [

    {
      id            = "new_adr",
      trigger       = "A significant architectural decision has been made or is being considered",
      preconditions = [
        "Decision affects the ecosystem architecture, not a single project implementation detail",
        "No existing ADR covers this decision",
        "adrs/defaults.ncl and adrs/schema.ncl are readable",
      ],
      steps = [
        {
          id     = "check_ontology",
          action = 'validate_decision,
          actor  = 'Agent,
          cmd    = "nickel export .ontology/core.ncl | get nodes | where level == 'Axiom | get id",
          verify = "Output lists the invariant IDs that the decision may affect",
          note   = "Identify which invariants are at risk before writing the ADR",
        },
        {
          id         = "draft_adr",
          action     = 'new_adr,
          depends_on = [{ step = "check_ontology", kind = 'OnSuccess }],
          actor      = 'Both,
          note       = "Use the next sequential adr-NNN id. Title must be a declarative statement, not a question.",
        },
        {
          id         = "add_constraints",
          action     = 'new_adr,
          depends_on = [{ step = "draft_adr", kind = 'Always }],
          actor      = 'Both,
          note       = "Every ADR requires at least one Hard constraint. The check_hint must be an executable command.",
        },
        {
          id         = "verify_export",
          action     = 'export_adr,
          depends_on = [{ step = "add_constraints", kind = 'OnSuccess }],
          actor      = 'Agent,
          cmd        = "nickel export adrs/adr-NNN-*.ncl",
          verify     = "Command exits 0 and produces valid JSON",
          on_error   = { strategy = 'Stop },
        },
        {
          id         = "set_accepted",
          action     = 'new_adr,
          depends_on = [{ step = "verify_export", kind = 'OnSuccess }],
          actor      = 'Human,
          note       = "Only the project maintainer sets status = 'Accepted. An ADR in 'Proposed is not authoritative.",
        },
      ],
      postconditions = [
        "adrs/adr-NNN-*.ncl exports cleanly with status = 'Accepted",
        "ontology_check.verdict is 'Safe or has explicit InvariantJustification",
        "At least one constraint has severity = 'Hard and a non-empty check_hint",
      ],
    },

    {
      id            = "read_as_human",
      trigger       = "Understanding a past decision or exploring the ADR corpus",
      preconditions = [
        "adrs/ directory contains at least one .ncl file",
      ],
      steps = [
        {
          id     = "list_adrs",
          action = 'read_adr,
          actor  = 'Human,
          cmd    = "ls adrs/adr-*.ncl | sort",
          verify = "Files are listed in adr-NNN order",
        },
        {
          id         = "export_adr",
          action     = 'export_adr,
          depends_on = [{ step = "list_adrs", kind = 'OnSuccess }],
          actor      = 'Human,
          cmd        = "nickel export adrs/adr-NNN-*.ncl | jq '{title, status, decision, constraints}'",
          verify     = "decision and constraints.claim fields are in English",
        },
        {
          id         = "check_related",
          action     = 'read_adr,
          depends_on = [{ step = "export_adr", kind = 'Always }],
          actor      = 'Human,
          note       = "Follow related_adrs references to understand the decision chain",
        },
      ],
      postconditions = [
        "Decision chain is understood: context → decision → constraints → ontology_check",
      ],
    },

    {
      id            = "read_as_agent",
      trigger       = "AI agent needs to understand the current architectural position before proposing changes",
      preconditions = [
        "Task affects ontoref protocol architecture, crate scope, or schema definitions",
      ],
      steps = [
        {
          id     = "export_all_accepted",
          action = 'export_adr,
          actor  = 'Agent,
          cmd    = "ls adrs/adr-*.ncl | each { |f| nickel export $f } | where status == 'Accepted",
          verify = "Only Accepted ADRs are in the working set",
          note   = "Proposed and Superseded ADRs are not authoritative — do not use them to justify decisions",
        },
        {
          id         = "extract_constraints",
          action     = 'validate_decision,
          depends_on = [{ step = "export_all_accepted", kind = 'OnSuccess }],
          actor      = 'Agent,
          cmd        = "nickel export adrs/adr-*.ncl | get constraints | where severity == 'Hard | get check_hint",
          verify     = "Hard constraints are available as executable check_hints",
        },
        {
          id         = "cross_reference_ontology",
          action     = 'validate_decision,
          depends_on = [{ step = "extract_constraints", kind = 'Always }],
          actor      = 'Agent,
          cmd        = "nickel export .ontology/core.ncl | get nodes | where invariant == true | get id",
          verify     = "Invariant IDs match the invariants_at_risk fields across accepted ADRs",
          note       = "A proposed change that touches any invariant requires a new ADR, not a patch",
        },
      ],
      postconditions = [
        "Agent has the active constraint set and knows which invariants bound the decision space",
        "No change is proposed that violates a Hard constraint without a new ADR",
      ],
    },

    {
      id            = "validate_decision",
      trigger       = "A proposed code or architecture change needs validation against existing ADRs",
      preconditions = [
        "The change is described in concrete terms: what is being added, removed, or modified",
        "Accepted ADRs are available via `nickel export`",
      ],
      steps = [
        {
          id     = "run_check_hints",
          action = 'validate_decision,
          actor  = 'Agent,
          cmd    = "nickel export adrs/adr-*.ncl | get constraints | where severity == 'Hard | each { |c| nu -c $c.check_hint }",
          verify = "All Hard check_hints exit 0 or produce no output (no violation found)",
          on_error = { strategy = 'Stop },
          note   = "A non-zero exit or match output means a Hard constraint is violated — stop and document",
        },
        {
          id         = "check_protocol_invariants",
          action     = 'validate_decision,
          depends_on = [{ step = "run_check_hints", kind = 'OnSuccess }],
          actor      = 'Agent,
          cmd        = "nickel export .ontology/core.ncl | get nodes | where invariant == true | get id",
          verify     = "None of the invariant node IDs are affected by the proposed change",
          note       = "A change touching any invariant node requires a new ADR, not a patch",
        },
        {
          id         = "report_result",
          action     = 'validate_decision,
          depends_on = [{ step = "check_protocol_invariants", kind = 'Always }],
          actor      = 'Agent,
          note       = "Report: which constraints passed, which failed, which ADR is implicated for each failure",
        },
      ],
      postconditions = [
        "All Hard constraints pass or a blocking ADR violation is documented with the implicated constraint ID",
      ],
    },

    {
      id            = "query_constraints",
      trigger       = "Need to know the current active constraint set, or reconstruct constraints at a specific point in time",
      preconditions = [
        "adrs/ directory contains exported ADR files",
        "`nickel export` is available",
      ],
      steps = [
        {
          id     = "active_constraints",
          action = 'read_adr,
          actor  = 'Agent,
          cmd    = "ls adrs/adr-*.ncl | each { |f| nickel export $f } | where status == 'Accepted | each { |a| { adr: $a.id, title: $a.title, constraints: $a.constraints } }",
          verify = "Output contains only Accepted ADRs with their constraint sets",
          note   = "This is the authoritative current constraint set. Proposed and Superseded ADRs are excluded.",
        },
        {
          id     = "hard_constraints_only",
          action = 'validate_decision,
          depends_on = [{ step = "active_constraints", kind = 'Always }],
          actor  = 'Agent,
          cmd    = "ls adrs/adr-*.ncl | each { |f| nickel export $f } | where status == 'Accepted | get constraints | flatten | where severity == 'Hard | select id claim check_hint",
          verify = "Each Hard constraint has a non-empty check_hint",
          note   = "Hard constraints are non-negotiable. A change that violates one requires a new ADR, not a workaround.",
        },
        {
          id     = "point_in_time",
          action = 'read_adr,
          depends_on = [{ step = "active_constraints", kind = 'Always }],
          actor  = 'Agent,
          cmd    = "ls adrs/adr-*.ncl | each { |f| nickel export $f } | where (($it.status == 'Accepted or $it.status == 'Superseded) and $it.date <= \"YYYY-MM\") | where superseded_by? == null | get constraints | flatten",
          verify = "Returns the constraint set that was active at the given date",
          note   = "Replace YYYY-MM with target date. An ADR without superseded_by was still Accepted at that date.",
        },
        {
          id     = "supersession_chain",
          action = 'read_adr,
          depends_on = [{ step = "point_in_time", kind = 'Always }],
          actor  = 'Agent,
          cmd    = "ls adrs/adr-*.ncl | each { |f| nickel export $f } | select id status supersedes superseded_by date | sort-by date",
          verify = "Each superseded ADR has a superseded_by reference to the replacing ADR",
          note   = "Follow the chain: superseded_by → new ADR → check its supersedes field to confirm bidirectional link",
        },
      ],
      postconditions = [
        "Agent has the active Hard constraint set for validation",
        "Or: the historical constraint set at a specific date is reconstructed",
        "Supersession chain is traceable in both directions via supersedes / superseded_by",
      ],
    },

    {
      id            = "supersede_adr",
      trigger       = "An existing Accepted ADR must be replaced due to architectural evolution",
      preconditions = [
        "A new ADR (adr-NNN) has been drafted and exports cleanly",
        "The superseding ADR references the old ADR in related_adrs",
        "The old ADR ID and title are known",
      ],
      steps = [
        {
          id     = "set_superseded_status",
          action = 'supersede_adr,
          actor  = 'Human,
          note   = "Edit the old ADR file: set status = 'Superseded. Do not delete the file.",
        },
        {
          id         = "verify_new_exports",
          action     = 'export_adr,
          depends_on = [{ step = "set_superseded_status", kind = 'OnSuccess }],
          actor      = 'Agent,
          cmd        = "nickel export adrs/adr-NNN-*.ncl",
          verify     = "New ADR exports with status = 'Accepted",
          on_error   = { strategy = 'Stop },
        },
        {
          id         = "verify_old_exports",
          action     = 'export_adr,
          depends_on = [{ step = "set_superseded_status", kind = 'OnSuccess }],
          actor      = 'Agent,
          cmd        = "nickel export adrs/adr-OLD-*.ncl | get status",
          verify     = "Output is 'Superseded",
          on_error   = { strategy = 'Stop },
        },
        {
          id         = "update_references",
          action     = 'supersede_adr,
          depends_on = [
            { step = "verify_new_exports", kind = 'OnSuccess },
            { step = "verify_old_exports", kind = 'OnSuccess },
          ],
          actor      = 'Human,
          cmd        = "grep -r 'adr-OLD' adrs/ reflection/ .ontology/",
          note       = "Update any references to the old ADR ID in other files",
        },
      ],
      postconditions = [
        "Old ADR has status = 'Superseded and remains in adrs/",
        "New ADR has status = 'Accepted and references the old ADR in related_adrs",
        "No file references the old ADR as if it were still active",
      ],
    },

  ],
}
| {
    modes
      | Array (s.Mode AdrAction)
      | doc "ADR operational modes — validated against reflection/schema.ncl at eval time",
    ..
  }
