# Implementation Layer

# CTH Business Objects

# CTH Business Objects

The discrete entities the CTH agentic workflows operate on.

## Post
Field: `caption`, `image_path`, `country`, `milestone`, `platforms`, `supporters`.

## Image
Generated by Ideogram. Must be >=1080x1080, JPG or PNG, brand-compliant.

## Country audience
Target audience per country (CO, PE, SV, GT, CR). Drives copy + supporter set.

## Milestone
Campaign milestone (launch, midpoint, deadline, winners, bootcamp).

## Supporter
Organisation credited in a post -- varies per country.

## Workflow Run
A single execution of a workflow. Has run_id, eval_score, status, audit URL.

> TODO: expand with worked examples per object.

---

## Opportunity (Grants)
Funder, call/RFP, deadline, budget ceiling + currency, CTH role (lead / co-applicant / implementing / subcontractor), required partners, funder type (multilateral / bilateral / climate-innovation / philanthropic / corporate / bid-cp).

## Fit Scorecard (Grants)
The 9 weighted criteria from cth-grant section 1a. Produces a 0-45 score + GO / CONDITIONAL / NO-GO verdict.

## Scope Brief (Grants)
In/out of scope, dependencies. Activities sized to budget (3-5 for <50K EUR, 8-12 for >150K EUR).

## Theory of Change (Grants)
Master ToC adapted to funder type and language register per section 3b.

## Budget (Grants)
The section 5b structure. Carries salary_pct, overhead_pct, cofinance_pct, total. Hard gate: salary must be 40 percent or less.

## Narrative (Grants)
Universal narrative sections per section 4b: exec summary, context, methodology, results, org capacity, budget summary, annexes.

## Pre-Submission Checklist (Grants)
13-line checklist (section 4d). Each line: yes / no / waived-by-Gideon. All must be YES or waived before submission.

## Submission (Grants)
Record of final package + human-performed submission + reporting schedule. The pod never auto-submits.

# Authority Matrix

# Authority Matrix

| Action | Tier | Requires HITL? | Notes |
|---|---|---|---|
| notion.read | read | No | scoped to CLP26 DB |
| bookstack.read | read | No | |
| ideogram.generate | write_reversible | No | spend-capped |
| notion.create_draft | write_reversible | No | |
| monday.create_item | write_reversible | No | |
| buffer.publish | write_irreversible | Yes | first 20 always HITL |
| gmail.send | write_irreversible | Yes | |
| davivienda.submit | write_irreversible | Yes | Gideon only |

> TODO: keep aligned with `/opt/cth/client_authority.yaml`.

## Grants Pipeline Actions

| Action | Tier | Requires HITL? | Approver | Notes |
|---|---|---|---|---|
| monday.read_opportunities | read | No | -- | scan board |
| fit_score.compute | read | No | -- | auto + partial |
| scope_toc.generate | write_reversible | No | -- | |
| budget.build | write_reversible | No | -- | |
| narrative.draft | write_reversible | No | -- | |
| go_no_go.decide | write_reversible | Yes if conditional | Gideon | auto GO if >=35, auto NO-GO if <25 |
| budget.review | write_reversible | Yes on red flags | Delegate | blocking if salary >40 pct |
| pre_submission.approve | write_irreversible | Always | Delegate | every submission |
| submission.perform | write_irreversible | Always | Human manual | pod stops at ready_to_submit |

# CLP26 Runbook

# CLP26 Runbook

How to operate the CLP26 workflow.

## Triggering a run
The systemd timer fires every 15 minutes. To force a run:
```bash
sudo systemctl start cth-runner@clp26.service
```

## Approving HITL
You will see a Telegram message in `#hitl-approvals` with Approve / Reject buttons. Tap one. Decision logged automatically.

## Inspecting a run
- Monday board `CLP26 Workflow Runs`
- `journalctl -u cth-runner@clp26.service -n 200`
- `jq 'select(.workflow_run_id=="<id>")' /opt/cth/audit.jsonl`

## Pausing the workflow
```bash
sudo systemctl stop cth-runner-clp26.timer
```

> TODO: add screenshots after first run.

# Recovery Playbook

# Recovery Playbook

## Eval below threshold
HITL prompt fires automatically. Reject + add reason -> run terminates, recovery row on Monday.

## Buffer publish failure
Automatic retry 3x (exponential). If still failing, alert in `#recovery`. Manual options:
1. Reschedule for later
2. Post a correction
3. Mark as cancelled

## Orphan run
`runner.py` detects stale state.json lock (>1h old) on next tick -> logs orphan, alerts.

## Image generation failure
Run marked failed with `image_unavailable`. Re-run from Step 03 manually.

## Wrong-country copy
Triggers country_copy_check failure -> HITL -> reject -> re-draft.

> TODO: add SOP for each failure mode after W6 simulation pass.

---

## Grants Pipeline Failure Modes

### Budget blocking gate fires -- salary above 40 pct
The 40 pct salary check is a hard gate. When fired:
1. Run is blocked and cannot reach pre-submission
2. Telegram alert in hitl-approvals with restructuring guidance
3. Options: restructure budget and re-run, or waive with explicit override

### Partner unresponsive -- more than 14 days
Automatically flagged during scan. Partner status downgraded to unresponsive. Alert in agent-ops. Consider replacing partner or dropping consortium component.

### Capacity guard -- 2 or more active drafts
New evaluating opportunities are deferred until an active draft completes. Logged as capacity_deferred in audit. No intervention needed; next tick retries.

### HITL gate timeout
If no response within timeout: run terminates cleanly. Opportunity stays at current stage. Next daily tick retries.

### Eval score below threshold
Routes through pre-submission HITL with the score and failing checks visible. Reviewer can approve despite low score.

### Subagent verify unavailable
Graceful degradation: check returns passed=True with weight=0 so it does not count. Other checks still score normally.

# Grants Runbook

# Grants Pipeline Runbook

Operator guide for the CTH Grants Pipeline -- a deadline-watcher state machine with 3 HITL gates.

## Architecture

The grants pipeline runs daily at 08:00 America/Bogota (13:00 UTC) via systemd timer.
It scans the Grants Opportunities Monday board for actionable rows and advances each
opportunity through an 8-step state machine.

Key principle: The pod NEVER auto-submits. It produces a ready-to-submit package;
a human performs the final submission.

## State Machine

```
evaluating -> fit_score -> go_no_go HITL1 -> scoping -> budgeting HITL2
-> drafting -> eval -> awaiting_HITL HITL3 -> ready_to_submit -> human submits
```

Terminal states: submitted, won, lost, no_go.

## HITL Gates

### Gate 1 -- GO / NO-GO (step 03)
- Approver: Gideon
- Auto GO: fit score >= 35/45
- Auto NO-GO: fit score < 25/45
- Conditional 25-34: requires explicit approval via Telegram inline keyboard
- Timeout: 30 minutes, run terminates cleanly, retries next tick

### Gate 2 -- Budget Review (step 05)
- Approver: Delegate
- Blocking gate: salary > 40 pct, run blocked until restructured or waived
- Red flags: overhead > cap, missing M&E line, routes to HITL for review
- Budget restructuring guidance provided in Telegram message

### Gate 3 -- Pre-Submission (step 07)
- Approver: Delegate
- Every pre-submission checklist line must be YES or explicitly waived
- Posts assembled package links + 24h deadline buffer reminder
- On approval: stage = ready_to_submit, pod STOPS

## How to Submit (Human)

After the pod marks an opportunity as ready_to_submit:
1. Review the package links posted in agent-ops
2. Verify all checklist items in the Grants HITL Approvals board
3. Submit via the funder portal or email as specified
4. Update the Grants Opportunities board: stage to submitted
5. Record submission details in Monday

## Manual Trigger

```bash
sudo systemctl start cth-runner@grants.service
```

## Logs

```bash
sudo journalctl -u cth-runner@grants.service -f
```

## Monday Boards

- Grants Opportunities: 18414094447 -- source/state board
- Grants Workflow Runs: 18414094534 -- per-tick run state
- Grants HITL Approvals: 18414094587 -- approval records
- Grants Audit Log: 18414094632 -- forensic trail for Advisory Board
- Grants Recovery Actions: 18414094675 -- failure tracking

## Planning Horizon

- Scan: 90 days before deadline, opportunities appear on radar
- Action required: 45 days before deadline, must be actively progressing
- Capacity guard: max 2 active drafts simultaneously