Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ keys/
*.pem
.env
.DS_Store
deploy/complete-tech/.coven-github-private-key.pem
deploy/complete-tech/coven-github-policy.json
deploy/complete-tech/coven-github-state/
83 changes: 82 additions & 1 deletion crates/github/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub const DEFAULT_API_BASE_URL: &str = "https://api.github.com";

/// Major version of the coven-code headless execution contract this adapter
/// speaks. See `docs/headless-contract.md`. Bump only on breaking changes.
pub const HEADLESS_CONTRACT_VERSION: &str = "1";
pub const HEADLESS_CONTRACT_VERSION: &str = "2";

fn default_contract_version() -> String {
HEADLESS_CONTRACT_VERSION.to_string()
Expand Down Expand Up @@ -187,6 +187,7 @@ pub struct SessionResult {
pub files_changed: Vec<String>,
pub summary: String,
pub pr_body: String,
pub review: ReviewResult,
pub exit_reason: Option<ExitReason>,
}

Expand All @@ -205,6 +206,86 @@ pub struct CommitInfo {
pub message: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ReviewResult {
pub mode: ReviewMode,
pub evidence_status: ReviewEvidenceStatus,
pub reviewed_files: Vec<String>,
pub supporting_files: Vec<String>,
pub findings: Vec<ReviewFinding>,
pub tests_run: Vec<ReviewTestRun>,
pub no_findings_reason: Option<String>,
pub limitations: Vec<String>,
}

impl ReviewResult {
pub fn none() -> Self {
Self {
mode: ReviewMode::None,
evidence_status: ReviewEvidenceStatus::NotApplicable,
reviewed_files: Vec::new(),
supporting_files: Vec::new(),
findings: Vec::new(),
tests_run: Vec::new(),
no_findings_reason: None,
limitations: Vec::new(),
}
}
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReviewMode {
None,
PullRequest,
ReviewComment,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReviewEvidenceStatus {
NotApplicable,
Complete,
Partial,
Missing,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ReviewFinding {
pub severity: ReviewSeverity,
pub file: String,
pub line: Option<u64>,
pub title: String,
pub body: String,
pub recommendation: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReviewSeverity {
Info,
Low,
Medium,
High,
Critical,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ReviewTestRun {
pub command: String,
pub status: ReviewTestStatus,
pub output_summary: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ReviewTestStatus {
Passed,
Failed,
NotRun,
Unknown,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ExitReason {
Expand Down
1 change: 1 addition & 0 deletions crates/github/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ mod tests {
files_changed: vec![],
summary: "Done".to_string(),
pr_body: "Body".to_string(),
review: crate::ReviewResult::none(),
exit_reason: None,
},
Some(9),
Expand Down
5 changes: 3 additions & 2 deletions crates/worker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ fn task_issue_number(kind: &TaskKind) -> Option<u64> {
#[cfg(test)]
mod disposition_tests {
use super::*;
use coven_github_api::{CommitInfo, HEADLESS_CONTRACT_VERSION};
use coven_github_api::{CommitInfo, ReviewResult, HEADLESS_CONTRACT_VERSION};
use coven_github_config::{GitHubAppConfig, ServerConfig, WorkerConfig};
use std::path::PathBuf;

Expand All @@ -643,6 +643,7 @@ mod disposition_tests {
files_changed: vec![],
summary: "summary".to_string(),
pr_body: "body".to_string(),
review: ReviewResult::none(),
exit_reason: None,
}
}
Expand Down Expand Up @@ -828,7 +829,7 @@ mod process_tests {
/// A minimal contract-valid result.json with the given status/exit_reason.
fn result_json(status: &str, exit_reason: &str) -> String {
format!(
r#"{{"contract_version":"1","status":"{status}","branch":null,"commits":[],"files_changed":[],"summary":"s","pr_body":"","exit_reason":{exit_reason}}}"#
r#"{{"contract_version":"2","status":"{status}","branch":null,"commits":[],"files_changed":[],"summary":"s","pr_body":"","review":{{"mode":"none","evidence_status":"not_applicable","reviewed_files":[],"supporting_files":[],"findings":[],"tests_run":[],"no_findings_reason":null,"limitations":[]}},"exit_reason":{exit_reason}}}"#
)
}

Expand Down
20 changes: 19 additions & 1 deletion crates/worker/tests/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
//! If these fail, either the runtime contract drifted or the docs are stale —
//! fix one of them, do not just bless the test.

use coven_github_api::{ExitReason, SessionResult, SessionStatus, HEADLESS_CONTRACT_VERSION};
use coven_github_api::{
ExitReason, ReviewEvidenceStatus, ReviewMode, SessionResult, SessionStatus,
HEADLESS_CONTRACT_VERSION,
};
use coven_github_worker::brief::SessionBrief;

fn fixture(name: &str) -> String {
Expand Down Expand Up @@ -43,6 +46,11 @@ fn golden_result_deserializes_into_adapter_type() {

assert_eq!(result.contract_version, HEADLESS_CONTRACT_VERSION);
assert_eq!(result.status, SessionStatus::Success);
assert_eq!(result.review.mode, ReviewMode::None);
assert_eq!(
result.review.evidence_status,
ReviewEvidenceStatus::NotApplicable
);
assert_eq!(result.branch.as_deref(), Some("cody/fix-issue-42"));
assert_eq!(result.commits.len(), 1);
assert_eq!(
Expand All @@ -63,6 +71,16 @@ fn result_without_contract_version_defaults_to_current() {
"files_changed": [],
"summary": "Could not reproduce.",
"pr_body": "",
"review": {
"mode": "none",
"evidence_status": "not_applicable",
"reviewed_files": [],
"supporting_files": [],
"findings": [],
"tests_run": [],
"no_findings_reason": null,
"limitations": []
},
"exit_reason": "ambiguous_spec"
}"#;
let result: SessionResult = serde_json::from_str(raw).expect("legacy result must parse");
Expand Down
36 changes: 36 additions & 0 deletions deploy/complete-tech/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# CompleteTech hosted dogfood adapter

This directory tracks the Python adapter currently deployed for the
CompleteTech-hosted dogfood GitHub App at `webhook.complete.tech`.

The adapter is intentionally deployment-specific. It is not the canonical Rust
worker implementation; it exists so hosted dogfood behavior can be reviewed,
reproduced, and changed through PRs instead of invisible server edits.

## Files

- `coven_github_adapter.py` - webhook handler, task runner, PR evidence capture,
Codex-backed headless runtime invocation, and dogfood comment publisher.

## Runtime inputs

The deployment expects secrets and mutable state to be supplied outside git:

- `GITHUB_APP_PRIVATE_KEY_PATH` or `.coven-github-private-key.pem`
- `GITHUB_APP_ID`
- `COVEN_GITHUB_STATE_DIR`
- `COVEN_GITHUB_POLICY_PATH`
- `COVEN_CODE_BIN`
- Codex OAuth tokens under the deployed account's `.coven-code` directory

Do not commit private keys, webhook secrets, OAuth tokens, generated task state,
workspaces, or attempt artifacts.

## Current dogfood behavior

- Emits headless contract v2 session briefs.
- Captures PR checkout metadata and changed-file patches before invoking
`coven-code`.
- Publishes visible structured review evidence, including `reviewed_files`,
`supporting_files`, findings, test evidence, no-findings rationale, and
limitations.
Loading