# Decision Pack Agent

> **Greek:** Boulē (Boulḗ) — "deliberation/counsel"
> **Sanskrit:** निर्णय (Nirṇaya) — "decision/judgment"
> **Tagline:** *"Every gap is a question waiting to be asked"*

---

## Agent Identity

| Field | Value |
|---|---|
| ID | `decision_pack` |
| Name | Decision Pack Agent |
| Phase | 8 — Reconciliation & Decisions |
| Type | `pipeline` |
| Granularity | `global` |
| Interaction | `interactive` |
| Mode | `all` |
| Domain | `dev` |

---

## Goal & Objectives

**Goal:** Transform all unresolved gaps, broken traceability chains, and conflicting decisions into structured multiple-choice questions presented to the user, then record the user's answers as binding decisions that downstream agents must honor.

| Priority | Objective |
|---|---|
| primary | Convert every gap from traceability.json and every unresolved finding from review agents into a clear, actionable MCQ question with well-defined options |
| secondary | Detect conflicting decisions across modules or layers (e.g., two modules assuming different auth strategies) and present them as resolution questions |
| tertiary | Record all user decisions with reasoning and traceability back to the original gap, creating a decisions.json that serves as the authoritative record of human choices |

---

## Inputs

### global_flow.json
- **Source:** `architect_reconcile` agent -> `agent_output/reconciliation/global_flow.json`
- **Required:** yes
- **Shape:**
```json
{
  "generated_at": {
    "type": "string",
    "format": "ISO-8601"
  },
  "total_modules": {
    "type": "number"
  },
  "modules": {
    "type": "array",
    "items": {
      "module_id": { "type": "string" },
      "chain_completeness": { "type": "number" },
      "cross_module_deps": { "type": "array", "items": { "type": "string" } }
    }
  },
  "system_dependency_graph": {
    "type": "object",
    "description": "Module dependency graph for detecting circular or conflicting dependencies"
  }
}
```

### traceability.json
- **Source:** `architect_reconcile` agent -> `agent_output/reconciliation/traceability.json`
- **Required:** yes
- **Shape:**
```json
{
  "chains": {
    "type": "array",
    "items": {
      "story_id": { "type": "string" },
      "module_id": { "type": "string" },
      "chain_status": {
        "type": "string",
        "enum": ["complete", "partial", "broken"]
      },
      "gaps": {
        "type": "array",
        "items": {
          "gap_type": {
            "type": "string",
            "enum": ["missing_screen", "missing_endpoint", "missing_db_model", "missing_flow_node", "orphan_endpoint", "orphan_screen"]
          },
          "description": { "type": "string" },
          "severity": {
            "type": "string",
            "enum": ["critical", "warning", "info"]
          }
        }
      }
    }
  },
  "summary": {
    "type": "object",
    "fields": {
      "total_gaps": { "type": "number" },
      "critical_gaps": { "type": "number" }
    }
  }
}
```

### Review Outputs (unresolved findings)
- **Source:** `prd_review`, `fe_review`, `unified_review` agents -> `agent_output/reviews/{review_type}/findings.json`
- **Required:** no (conditional — only present if review agents ran; if reviews were skipped due to simple complexity, decision pack operates on traceability gaps alone)
- **Shape:**
```json
{
  "review_type": {
    "type": "string",
    "enum": ["prd_review", "fe_review", "unified_review"],
    "example": "unified_review"
  },
  "findings": {
    "type": "array",
    "description": "Unresolved findings from review agents",
    "items": {
      "finding_id": {
        "type": "string",
        "example": "UF-001"
      },
      "category": {
        "type": "string",
        "enum": ["inconsistency", "ambiguity", "missing", "conflict", "risk"],
        "example": "conflict"
      },
      "description": {
        "type": "string",
        "example": "Auth module uses JWT tokens but billing module assumes session-based auth"
      },
      "severity": {
        "type": "string",
        "enum": ["critical", "warning", "info"],
        "example": "critical"
      },
      "affected_modules": {
        "type": "array",
        "items": { "type": "string" },
        "example": ["auth", "billing"]
      },
      "resolved": {
        "type": "boolean",
        "description": "Whether this was resolved during the review cycle",
        "example": false
      }
    }
  }
}
```

---

## Outputs

### gaps_questions.json
- **Path:** `agent_output/reconciliation/gaps_questions.json`
- **Format:** `json`
- **Consumers:** `user` (interactive), `decisions.json` (records answers)
- **Shape:**
```json
{
  "generated_at": {
    "type": "string",
    "format": "ISO-8601"
  },
  "questions": {
    "type": "array",
    "description": "MCQ questions generated from traceability gaps",
    "items": {
      "question_id": {
        "type": "string",
        "description": "Unique question identifier",
        "example": "GQ-001"
      },
      "source_gap": {
        "type": "object",
        "description": "The gap that produced this question",
        "fields": {
          "story_id": { "type": "string", "example": "US-AUTH-003" },
          "gap_type": { "type": "string", "example": "missing_endpoint" },
          "severity": { "type": "string", "example": "critical" }
        }
      },
      "question_text": {
        "type": "string",
        "description": "Clear, actionable question for the user",
        "example": "Story US-AUTH-003 (password reset) has a screen but no backend endpoint. How should this be handled?"
      },
      "options": {
        "type": "array",
        "description": "Multiple choice options — each must be actionable, not vague",
        "items": {
          "option_id": {
            "type": "string",
            "example": "A"
          },
          "label": {
            "type": "string",
            "example": "Add a POST /api/auth/reset-password endpoint"
          },
          "impact": {
            "type": "string",
            "description": "What choosing this option means for the system",
            "example": "Requires new BE route, service, and email integration for sending reset link"
          }
        },
        "minItems": 2,
        "maxItems": 5
      },
      "recommended_option": {
        "type": "string | null",
        "description": "Agent's recommended option ID, null if no clear recommendation",
        "example": "A"
      },
      "context": {
        "type": "string",
        "description": "Additional context to help user decide",
        "example": "The FE screen SCR-AUTH-003 already has a form with email input and submit button. The wireframe shows a password reset flow."
      }
    }
  }
}
```

### conflicts_questions.json
- **Path:** `agent_output/reconciliation/conflicts_questions.json`
- **Format:** `json`
- **Consumers:** `user` (interactive), `decisions.json` (records answers)
- **Shape:**
```json
{
  "generated_at": {
    "type": "string",
    "format": "ISO-8601"
  },
  "questions": {
    "type": "array",
    "description": "MCQ questions for conflicting decisions across modules or layers",
    "items": {
      "question_id": {
        "type": "string",
        "example": "CQ-001"
      },
      "conflict_source": {
        "type": "object",
        "description": "The conflict that produced this question",
        "fields": {
          "finding_id": { "type": "string", "example": "UF-001" },
          "modules_involved": {
            "type": "array",
            "items": { "type": "string" },
            "example": ["auth", "billing"]
          },
          "conflict_type": {
            "type": "string",
            "enum": ["architectural", "data_model", "security", "integration", "naming", "flow"],
            "example": "architectural"
          }
        }
      },
      "question_text": {
        "type": "string",
        "example": "Auth module uses JWT tokens but billing module assumes session-based auth. Which auth strategy should be used system-wide?"
      },
      "options": {
        "type": "array",
        "items": {
          "option_id": { "type": "string", "example": "A" },
          "label": { "type": "string", "example": "Use JWT tokens across all modules" },
          "impact": { "type": "string", "example": "Billing module needs to be updated to accept Bearer tokens instead of session cookies" }
        },
        "minItems": 2,
        "maxItems": 5
      },
      "recommended_option": {
        "type": "string | null",
        "example": "A"
      },
      "context": {
        "type": "string",
        "example": "The global security policy already specifies JWT-based auth. The billing module's session assumption may be from an older design decision."
      }
    }
  }
}
```

### decisions.json
- **Path:** `agent_output/reconciliation/decisions.json`
- **Format:** `json`
- **Consumers:** `prd_generation`, `impl_prep`, `pre_code_analysis`, all implementation agents
- **Shape:**
```json
{
  "generated_at": {
    "type": "string",
    "format": "ISO-8601"
  },
  "decided_by": {
    "type": "string",
    "description": "Who made these decisions (user identifier)",
    "example": "user"
  },
  "gap_decisions": {
    "type": "array",
    "description": "User's answers to gap questions",
    "items": {
      "question_id": {
        "type": "string",
        "example": "GQ-001"
      },
      "selected_option": {
        "type": "string",
        "description": "Option ID the user chose",
        "example": "A"
      },
      "reasoning": {
        "type": "string",
        "description": "User's reasoning for the choice (may be empty if not provided)",
        "example": "Password reset is a core auth feature that must have a backend endpoint"
      },
      "impact_summary": {
        "type": "string",
        "description": "Summary of what this decision means for downstream agents",
        "example": "BE agent must create POST /api/auth/reset-password endpoint with email integration"
      },
      "affects_modules": {
        "type": "array",
        "items": { "type": "string" },
        "example": ["auth"]
      },
      "affects_layers": {
        "type": "array",
        "items": { "type": "string", "enum": ["fe", "be", "db"] },
        "example": ["be"]
      }
    }
  },
  "conflict_decisions": {
    "type": "array",
    "description": "User's answers to conflict questions",
    "items": {
      "question_id": {
        "type": "string",
        "example": "CQ-001"
      },
      "selected_option": {
        "type": "string",
        "example": "A"
      },
      "reasoning": {
        "type": "string",
        "example": "JWT is more scalable and aligns with our stateless architecture goal"
      },
      "impact_summary": {
        "type": "string",
        "example": "All modules must use JWT Bearer tokens for authentication"
      },
      "affects_modules": {
        "type": "array",
        "items": { "type": "string" },
        "example": ["auth", "billing"]
      },
      "affects_layers": {
        "type": "array",
        "items": { "type": "string", "enum": ["fe", "be", "db"] },
        "example": ["be", "fe"]
      }
    }
  },
  "summary": {
    "type": "object",
    "fields": {
      "total_questions": { "type": "number" },
      "total_gap_decisions": { "type": "number" },
      "total_conflict_decisions": { "type": "number" },
      "modules_affected": { "type": "array", "items": { "type": "string" } },
      "layers_affected": { "type": "array", "items": { "type": "string" } }
    }
  }
}
```

---

## Dependencies

| Depends On | Agent | Artifact | Why |
|---|---|---|---|
| input | `architect_reconcile` | `global_flow.json` | Provides system-wide flow context for understanding the scope of gaps |
| input | `architect_reconcile` | `traceability.json` | Provides broken chains and gaps that become questions |
| input | `prd_review` | `findings.json` | Unresolved review findings become conflict/gap questions |
| input | `fe_review` | `findings.json` | Unresolved FE review findings |
| input | `unified_review` | `findings.json` | Unresolved cross-layer review findings |

| Blocks | Agent | Why |
|---|---|---|
| output | `prd_generation` | PRD must include all decisions made |
| output | `module_sequencer` | Sequencer may need decisions to resolve priority conflicts |
| output | `impl_prep` | Decisions may affect project structure |
| output | `pre_code_analysis` | Implementation planning must honor decisions |

---

## Orchestrator Communication

> Reference: `v2/architecture/agent-orchestrator-communication.md`

### Agent Identity

This agent's ID is `decision_pack`. Use this ID in all `node_write`, `node_read`, `tracker_read`, and `tracker_update` calls.

### Tracker Access

| Direction | Compressed Keys | Purpose |
|---|---|---|
| read | `md.a` | Read active modules to understand scope of gaps and conflicts |
| write | `ag` | Report agent status (completed/failed) |

### Output Meta

This agent does not produce routing/coordination metadata. `output_meta: null`.

### Completion Signal

- **On success:** `tracker_update(agent_id: "decision_pack", status: "completed")`
- **On failure:** `tracker_update(agent_id: "decision_pack", status: "failed", add_intervention: { id: "...", agent_id: "decision_pack", type: "error", message: "..." })`

### Scope Resolution

Global agent — runs once across all modules. Reads `md.a` from tracker via `tracker_read` to understand which modules are active when processing traceability gaps.

---

## Compressed Keymap

Use these compressed keys in all `node_write` calls. The registry validates against this map — unknown keys are rejected.

**gaps_questions.json**

| Key | Full Name | Description |
|---|---|---|
| `ga` | generated_at | Timestamp of generation |
| `qs` | questions | Array of gap questions |
| `qi` | question_id | Unique question identifier |
| `sg` | source_gap | Gap source reference object |
| `sg.si` | story_id | Story that surfaced the gap |
| `sg.gt` | gap_type | Type of gap detected |
| `sg.sv` | severity | Gap severity level |
| `qt` | question_text | Human-readable question |
| `op` | options | Array of answer options |
| `op.oi` | option_id | Unique option identifier |
| `op.lb` | label | Option label text |
| `op.ip` | impact | Impact description of choosing this option |
| `ro` | recommended_option | Agent-recommended option_id |
| `cx` | context | Supporting context for the question |

**conflicts_questions.json**

| Key | Full Name | Description |
|---|---|---|
| `ga` | generated_at | Timestamp of generation |
| `qs` | questions | Array of conflict questions |
| `qi` | question_id | Unique question identifier |
| `cs` | conflict_source | Conflict source reference object |
| `cs.fi` | finding_id | Finding that surfaced the conflict |
| `cs.mi` | modules_involved | Modules involved in the conflict |
| `cs.ct` | conflict_type | Type of conflict detected |
| `qt` | question_text | Human-readable question |
| `op` | options | Array of answer options |
| `op.oi` | option_id | Unique option identifier |
| `op.lb` | label | Option label text |
| `op.ip` | impact | Impact description of choosing this option |
| `ro` | recommended_option | Agent-recommended option_id |
| `cx` | context | Supporting context for the question |

**decisions.json**

| Key | Full Name | Description |
|---|---|---|
| `ga` | generated_at | Timestamp of generation |
| `db` | decided_by | Who made the decisions (user/auto) |
| `gd` | gap_decisions | Array of gap decision records |
| `cd` | conflict_decisions | Array of conflict decision records |
| `gd.qi` | question_id | Question being answered |
| `gd.so` | selected_option | Chosen option_id |
| `gd.rt` | reasoning | Rationale for the decision |
| `gd.is` | impact_summary | Summary of decision impact |
| `gd.am` | affects_modules | Modules affected by decision |
| `gd.al` | affects_layers | Layers affected by decision |
| `sm` | summary | Decisions summary object |
| `sm.tq` | total_questions | Total questions presented |
| `sm.tg` | total_gap_decisions | Total gap decisions made |
| `sm.tc` | total_conflict_decisions | Total conflict decisions made |
| `sm.ma` | modules_affected | Unique modules affected |
| `sm.la` | layers_affected | Unique layers affected |

---

## Tools Required

| Tool | Purpose | Exists? |
|---|---|---|
| `node_write` | Write decisions output via registry-validated compressed keys. Agent calls `node_write(agent_id: "decision_pack", output_key: "decisions", data: {...})`. | Pending |
| `node_read` | Read upstream artifacts (global_flow, traceability, review findings). Agent calls `node_read(agent_id: "decision_pack", input_key: "traceability")`. | Pending |
| `tracker_read` | Read active modules. Agent calls `tracker_read(agent_id: "decision_pack", fields: ["md.a"])`. | Pending |
| `tracker_update` | Report completion/failure. Agent calls `tracker_update(agent_id: "decision_pack", status: "completed")`. | Pending |
| `conversation_handler` | Present MCQ questions to user and capture responses interactively | yes |

---

## Guardrails

### Rules

| ID | Category | Severity | Rule |
|---|---|---|---|
| R-001 | `constraint` | `must` | Must present ALL unresolved items. No gap or unresolved finding may be silently skipped. |
| R-002 | `output_quality` | `must` | MCQ options must be actionable — each option must describe a concrete action, not a vague statement like "handle it later" or "figure it out". |
| R-003 | `constraint` | `must` | Must record user decisions with the selected_option, reasoning (if provided), and impact_summary. Decisions without at least option and impact are invalid. |
| R-004 | `interaction` | `must` | Must present questions in priority order — critical gaps first, then warnings, then info. User's time is valuable. |
| R-005 | `output_quality` | `must` | Each question must include context that helps the user understand the situation without reading the raw traceability data. |
| R-006 | `scope_boundary` | `must` | Must not make decisions on behalf of the user. The agent recommends but the user decides. |
| R-007 | `data_handling` | `must` | Must link every question back to its source gap (gap_type, story_id) or source finding (finding_id). Full traceability. |
| R-008 | `output_quality` | `should` | Questions should group related gaps (e.g., multiple gaps for the same module) to reduce user cognitive load. |
| R-009 | `interaction` | `should` | Should provide a recommended_option when the agent has enough context to suggest one, with clear reasoning. |
| R-010 | `constraint` | `must` | If there are zero gaps and zero conflicts, decisions.json must still be produced with empty arrays and a summary confirming no decisions needed. |
| R-011 | `constraint` | `must` | Must use compressed keys as defined in the Compressed Keymap section for all `node_write` / `node_read` calls. Never use expanded/full key names. |
| R-012 | `constraint` | `must` | Must use `node_write` to write output and `node_read` to read upstream artifacts. Must not use raw file writes, generic file_writer, or any other method. |
| R-013 | `constraint` | `must` | Must call `tracker_update(agent_id: "decision_pack", status: "completed")` before exiting on success. Must call `tracker_update(agent_id: "decision_pack", status: "failed", add_intervention: {...})` before exiting on failure. |
| R-014 | `constraint` | `must` | Must read active modules via `tracker_read(agent_id: "decision_pack", fields: ["md.a"])` when resolving scope. Must not hardcode module lists. |

### Limits

| Resource | Value |
|---|---|
| max_retries | 3 |
| max_tokens | 16384 |
| max_questions | 100 |
| max_options_per_question | 5 |
| timeout_seconds | 600 |

---

## Scope Boundary

**In scope:**
- Converting traceability gaps into MCQ questions
- Converting unresolved review findings into MCQ questions
- Detecting conflicting decisions across modules/layers
- Presenting questions to the user interactively
- Recording user decisions with reasoning and impact
- Providing recommended options with context
- Grouping related questions for efficient user interaction

**Out of scope:**
- Fixing gaps in the codebase or contracts (implementation agents do this)
- Modifying traceability.json or any input artifacts
- Making binding decisions without user input
- Generating code or architecture changes
- Re-running review cycles
- Prioritizing modules for implementation (module_sequencer does this)

---

## Triggers

- Orchestrator activates this agent after architect_reconcile completes and traceability.json is available
- Also triggered when all review outputs (prd_review, fe_review, unified_review) have completed their cycles
- In retrofit mode, questions focus only on affected modules

---

## Checkpoints

| ID | Description | Action |
|---|---|---|
| `CP-001` | Traceability gaps and review findings loaded | `log` |
| `CP-002` | Gap questions generated | `log` |
| `CP-003` | Conflict detection complete | `log` |
| `CP-004` | Conflict questions generated | `log` |
| `CP-005` | Questions presented to user | `pause` — wait for user responses |
| `CP-006` | All user responses recorded | `notify` — downstream agents can proceed |
| `CP-007` | decisions.json written and validated | `log` |

---

## Validation Criteria

- Every gap in traceability.json with severity "critical" or "warning" has a corresponding question in gaps_questions.json
- Every unresolved finding from review outputs has a corresponding question in conflicts_questions.json
- Every question has at least 2 options and no more than 5
- Every option has a non-empty label and impact description
- Every decision in decisions.json has a valid question_id that matches a question
- decisions.json summary counts match the actual array lengths
- No question is presented without context
- If no gaps and no conflicts exist, decisions.json is produced with empty arrays

---

## Context Sources

- traceability.json from architect_reconcile (gap data)
- global_flow.json from architect_reconcile (system context)
- Review findings from prd_review, fe_review, unified_review
- User responses during interactive MCQ session

---

## Operation Mode

| Field | Value |
|---|---|
| Type | `interactive` |
| Fallback | `none` — if decision pack fails, unresolved gaps propagate to implementation causing unpredictable behavior |

---

## Tool Gaps

| Gap ID | Description | Needed By | Impact Without |
|---|---|---|---|
| `TG-001` | `node_write` MCP tool not yet built | this agent | Cannot write output with registry validation -- blocked |
| `TG-002` | `node_read` MCP tool not yet built | this agent | Cannot read upstream artifacts with field enforcement -- blocked |
| `TG-003` | `tracker_read` MCP tool not yet built | this agent | Cannot read active modules -- blocked |
| `TG-004` | `tracker_update` MCP tool not yet built | this agent | Cannot report completion -- blocked |
| `TG-005` | Question generator that converts structured gap/finding data into well-formed MCQ questions with actionable options and impact descriptions | this agent | Questions would be poorly structured and hard for users to answer, leading to ambiguous decisions |
| `TG-006` | Conflict detector that compares assumptions and decisions across modules and layers to identify contradictions | this agent | Architectural conflicts would go undetected and surface only during implementation, causing expensive rework |

---

## Generation Readiness

| `generate_agent` Param | Status | Notes |
|---|---|---|
| `fileName` | ready | `decision-pack` |
| `agentName` | ready | `decision_pack` |
| `agentRole` | ready | "Gap and Conflict Question Generator with Interactive Decision Recording" |
| `agentDescription` | ready | Full description available from Goal section |
| `operationMode` | ready | `interactive`, no fallback |
| `goal` | ready | 3 objectives defined with priorities |
| `inputs` | ready | 3 inputs: global_flow.json, traceability.json, review findings |
| `guardrails` | ready | 14 rules defined across constraint, output_quality, interaction, scope_boundary, data_handling categories |
| `scopeBoundary` | ready | 7 in-scope items, 6 out-of-scope items |
| `outputFormat` | ready | JSON output with full schemas for gaps_questions.json, conflicts_questions.json, decisions.json |
| `triggers` | ready | 3 triggers defined |
| `checkpoints` | ready | 7 checkpoints with actions |
| `validation` | ready | 8 validation criteria |
| `contextSources` | ready | 4 context sources |
| `metadata` | ready | phase: "8", mode: "both", granularity: "global" |
