@@ -155,6 +155,11 @@ class CoderWorktreeCommitResult:
155155 parent_commit_sha : str | None = None
156156 effect_id : str | None = None
157157 alias_evidence_path : str | None = None
158+ source_coder_commit_decision : str | None = None
159+ source_coder_commit_decision_md : str | None = None
160+ source_commit_decision_sha256 : str | None = None
161+ source_commit_decision_md_sha256 : str | None = None
162+ source_coder_commit_decision_markdown_consumed : bool = False
158163
159164
160165def request_coder_worktree_approval (
@@ -1062,6 +1067,7 @@ def promote_coder_worktree_commit(
10621067 raise CoderWorktreeCommitError (f"commit approval not found: { approval_id } " )
10631068 if approval .status == "committed" :
10641069 _ensure_recorded_commit_exists (approval )
1070+ local_commit_payload = _load_coder_local_commit_payload (root , approval )
10651071 return CoderWorktreeCommitResult (
10661072 approval = approval ,
10671073 status = "already_committed" ,
@@ -1072,9 +1078,39 @@ def promote_coder_worktree_commit(
10721078 alias_evidence_path = str (
10731079 (_coder_commit_dir (root , approval ) / "commit.json" ).relative_to (root )
10741080 ),
1081+ source_coder_commit_decision = local_commit_payload .get (
1082+ "source_coder_commit_decision"
1083+ ),
1084+ source_coder_commit_decision_md = local_commit_payload .get (
1085+ "source_coder_commit_decision_md"
1086+ ),
1087+ source_commit_decision_sha256 = local_commit_payload .get (
1088+ "source_commit_decision_sha256"
1089+ ),
1090+ source_commit_decision_md_sha256 = local_commit_payload .get (
1091+ "source_commit_decision_md_sha256"
1092+ ),
1093+ source_coder_commit_decision_markdown_consumed = (
1094+ local_commit_payload .get (
1095+ "source_coder_commit_decision_markdown_consumed"
1096+ )
1097+ is True
1098+ ),
10751099 )
10761100 if approval .status != "approved" :
10771101 raise CoderWorktreeCommitError ("approval is not approved" )
1102+ try :
1103+ decision_proof = _load_commit_decision_proof (root , approval )
1104+ except CoderWorktreeCommitError as error :
1105+ _block_commit_approval (
1106+ root ,
1107+ storage ,
1108+ approval ,
1109+ failure_class = "missing_commit_decision_proof" ,
1110+ detail = str (error ),
1111+ verification_exit_code = None ,
1112+ )
1113+ raise
10781114
10791115 run = get_coder_worktree_run (storage , approval .run_id )
10801116 if run is None :
@@ -1385,6 +1421,22 @@ def promote_coder_worktree_commit(
13851421 "changed_files" : approval .changed_files ,
13861422 "committed_files" : committed_files ,
13871423 "commit_message" : commit_message ,
1424+ "source_coder_commit_decision" : decision_proof [
1425+ "source_coder_commit_decision"
1426+ ],
1427+ "source_coder_commit_decision_md" : decision_proof [
1428+ "source_coder_commit_decision_md"
1429+ ],
1430+ "source_commit_decision_sha256" : decision_proof [
1431+ "source_commit_decision_sha256"
1432+ ],
1433+ "source_commit_decision_md_sha256" : decision_proof [
1434+ "source_commit_decision_md_sha256"
1435+ ],
1436+ "source_coder_commit_decision_markdown_consumed" : True ,
1437+ "source_coder_commit_decision_markdown_excerpt" : decision_proof [
1438+ "markdown_excerpt"
1439+ ],
13881440 "source_coder_worktree_run_sha256" : approval .source_coder_worktree_run_sha256 ,
13891441 "source_diff_sha256" : approval .source_diff_sha256 ,
13901442 "verification_command" : verification_command ,
@@ -1415,6 +1467,22 @@ def promote_coder_worktree_commit(
14151467 "branch_name" : approval .branch_name ,
14161468 "commit_request_id" : approval .id ,
14171469 "commit_approval_id" : approval .id ,
1470+ "source_coder_commit_decision" : decision_proof [
1471+ "source_coder_commit_decision"
1472+ ],
1473+ "source_coder_commit_decision_md" : decision_proof [
1474+ "source_coder_commit_decision_md"
1475+ ],
1476+ "source_commit_decision_sha256" : decision_proof [
1477+ "source_commit_decision_sha256"
1478+ ],
1479+ "source_commit_decision_md_sha256" : decision_proof [
1480+ "source_commit_decision_md_sha256"
1481+ ],
1482+ "source_coder_commit_decision_markdown_consumed" : True ,
1483+ "source_coder_commit_decision_markdown_excerpt" : decision_proof [
1484+ "markdown_excerpt"
1485+ ],
14181486 "commit_sha" : commit_sha ,
14191487 "parent_commit_sha" : parent_commit_sha ,
14201488 "commit_message" : commit_message ,
@@ -1471,6 +1539,17 @@ def promote_coder_worktree_commit(
14711539 parent_commit_sha = parent_commit_sha ,
14721540 effect_id = effect .id ,
14731541 alias_evidence_path = str ((coder_commit_dir / "commit.json" ).relative_to (root )),
1542+ source_coder_commit_decision = decision_proof ["source_coder_commit_decision" ],
1543+ source_coder_commit_decision_md = decision_proof [
1544+ "source_coder_commit_decision_md"
1545+ ],
1546+ source_commit_decision_sha256 = decision_proof [
1547+ "source_commit_decision_sha256"
1548+ ],
1549+ source_commit_decision_md_sha256 = decision_proof [
1550+ "source_commit_decision_md_sha256"
1551+ ],
1552+ source_coder_commit_decision_markdown_consumed = True ,
14741553 )
14751554
14761555
@@ -1906,6 +1985,7 @@ def render_commit_coder_worktree_cli_lines(
19061985 evidence_path = result .alias_evidence_path or str (
19071986 (_coder_commit_dir (root .resolve (), approval ) / "commit.json" ).relative_to (root .resolve ())
19081987 )
1988+ payload = _load_coder_local_commit_payload (root .resolve (), approval )
19091989 return [
19101990 f"commit_coder_worktree: { result .status } " ,
19111991 f"commit_request_id: { approval .id } " ,
@@ -1920,6 +2000,16 @@ def render_commit_coder_worktree_cli_lines(
19202000 f"worktree_path: { approval .worktree_path } " ,
19212001 f"branch_name: { approval .branch_name } " ,
19222002 f"committed_files: { ',' .join (approval .changed_files ) or 'none' } " ,
2003+ "source_coder_commit_decision: "
2004+ f"{ payload .get ('source_coder_commit_decision' , result .source_coder_commit_decision or 'missing' )} " ,
2005+ "source_coder_commit_decision_md: "
2006+ f"{ payload .get ('source_coder_commit_decision_md' , result .source_coder_commit_decision_md or 'missing' )} " ,
2007+ "source_commit_decision_sha256: "
2008+ f"{ payload .get ('source_commit_decision_sha256' , result .source_commit_decision_sha256 or 'missing' )} " ,
2009+ "source_commit_decision_md_sha256: "
2010+ f"{ payload .get ('source_commit_decision_md_sha256' , result .source_commit_decision_md_sha256 or 'missing' )} " ,
2011+ "source_coder_commit_decision_markdown_consumed: "
2012+ f"{ _bool (payload .get ('source_coder_commit_decision_markdown_consumed' ) is True or result .source_coder_commit_decision_markdown_consumed )} " ,
19232013 f"evidence: { evidence_path } " ,
19242014 "commit_created: true" ,
19252015 "push_created: false" ,
@@ -2071,12 +2161,19 @@ def render_coder_local_commit_dashboard_lines(root: Path) -> list[str]:
20712161 lines : list [str ] = []
20722162 for approval in list_coder_worktree_commit_approvals (root , status = "committed" , limit = 10 ):
20732163 artifact = _coder_commit_dir (root .resolve (), approval ) / "commit.json"
2164+ payload = _load_coder_local_commit_payload (root .resolve (), approval )
20742165 lines .append (
20752166 f"- { approval .id } : delegation={ approval .delegation_id } project={ approval .project_id } "
20762167 f"coder_worktree_run={ approval .run_id } commit={ approval .commit_sha or 'none' } "
20772168 f"parent={ approval .pre_commit_head } effect={ approval .effect_id or 'none' } "
20782169 f"github_handoff_available={ _bool (bool (approval .effect_id ))} "
20792170 f"committed_files={ ',' .join (approval .changed_files ) or 'none' } "
2171+ "source_commit_decision_md="
2172+ f"{ payload .get ('source_coder_commit_decision_md' , 'missing' )} "
2173+ "source_commit_decision_md_sha256="
2174+ f"{ payload .get ('source_commit_decision_md_sha256' , 'missing' )} "
2175+ "source_commit_decision_markdown_consumed="
2176+ f"{ _bool (payload .get ('source_coder_commit_decision_markdown_consumed' ) is True )} "
20802177 f"artifact={ artifact .relative_to (root .resolve ())} "
20812178 "push_created=false pr_created=false deploy_created=false"
20822179 )
@@ -3238,6 +3335,58 @@ def _load_commit_request_proof(
32383335 }
32393336
32403337
3338+ def _load_commit_decision_proof (
3339+ root : Path ,
3340+ approval : CoderWorktreeCommitApprovalRecord ,
3341+ ) -> dict [str , Any ]:
3342+ decision_path = _coder_commit_dir (root , approval ) / "coder_commit_decision.json"
3343+ decision_markdown_path = decision_path .with_suffix (".md" )
3344+ try :
3345+ payload = json .loads (decision_path .read_text (encoding = "utf-8" ))
3346+ markdown_text = decision_markdown_path .read_text (encoding = "utf-8" )
3347+ except (OSError , json .JSONDecodeError ) as error :
3348+ raise CoderWorktreeCommitError ("coder commit decision is not readable" ) from error
3349+ if payload .get ("kind" ) != COMMIT_APPROVAL_DECISION_KIND :
3350+ raise CoderWorktreeCommitError ("coder commit decision has unexpected kind" )
3351+ if payload .get ("commit_request_id" ) != approval .id :
3352+ raise CoderWorktreeCommitError ("coder commit decision does not match approval" )
3353+ if payload .get ("coder_worktree_run_id" ) != approval .run_id :
3354+ raise CoderWorktreeCommitError ("coder commit decision does not match run" )
3355+ if payload .get ("status" ) != "approved" :
3356+ raise CoderWorktreeCommitError ("coder commit decision is not approved" )
3357+ if payload .get ("source_coder_commit_request_markdown_consumed" ) is not True :
3358+ raise CoderWorktreeCommitError (
3359+ "coder commit decision is missing request markdown proof"
3360+ )
3361+ if f"- commit_request_id: { approval .id } " not in markdown_text :
3362+ raise CoderWorktreeCommitError ("coder commit decision markdown does not match approval" )
3363+ if "- status: approved" not in markdown_text :
3364+ raise CoderWorktreeCommitError ("coder commit decision markdown is not approved" )
3365+ return {
3366+ "payload" : payload ,
3367+ "markdown_text" : markdown_text ,
3368+ "markdown_excerpt" : markdown_text [:2000 ],
3369+ "source_coder_commit_decision" : str (decision_path .relative_to (root )),
3370+ "source_coder_commit_decision_md" : str (decision_markdown_path .relative_to (root )),
3371+ "source_commit_decision_sha256" : _sha256_path (decision_path ),
3372+ "source_commit_decision_md_sha256" : hashlib .sha256 (
3373+ markdown_text .encode ("utf-8" )
3374+ ).hexdigest (),
3375+ }
3376+
3377+
3378+ def _load_coder_local_commit_payload (
3379+ root : Path ,
3380+ approval : CoderWorktreeCommitApprovalRecord ,
3381+ ) -> dict [str , Any ]:
3382+ artifact = _coder_commit_dir (root , approval ) / "commit.json"
3383+ try :
3384+ payload = json .loads (artifact .read_text (encoding = "utf-8" ))
3385+ except (OSError , json .JSONDecodeError ):
3386+ return {}
3387+ return payload if isinstance (payload , dict ) else {}
3388+
3389+
32413390def _record_coder_worktree_incident (
32423391 storage : Storage ,
32433392 * ,
@@ -3278,6 +3427,7 @@ def _commit_failure_class_from_error(error_text: str) -> str:
32783427 ("worktree does not exist" , "missing_worktree" ),
32793428 ("unsafe_git_state" , "unsafe_git_state" ),
32803429 ("approved commit request is missing" , "missing_commit_request" ),
3430+ ("coder commit decision" , "missing_commit_decision_proof" ),
32813431 ("approval is not approved" , "commit_request_not_approved" ),
32823432 ("approval is not pending" , "commit_request_not_approved" ),
32833433 ("source_hash_mismatch" , "source_hash_mismatch" ),
@@ -3309,6 +3459,7 @@ def _commit_failure_next_action(failure_class: str) -> str:
33093459 return "review_coder_worktree_run"
33103460 if failure_class in {
33113461 "missing_commit_request" ,
3462+ "missing_commit_decision_proof" ,
33123463 "commit_request_not_approved" ,
33133464 "source_hash_mismatch" ,
33143465 "changed_files_mismatch" ,
@@ -4105,6 +4256,13 @@ def _render_coder_local_commit_markdown(payload: dict[str, Any]) -> str:
41054256 f"- parent_commit_sha: { payload ['parent_commit_sha' ]} " ,
41064257 f"- branch_name: { payload ['branch_name' ]} " ,
41074258 f"- worktree_path: { payload ['worktree_path' ]} " ,
4259+ f"- source_coder_commit_decision: { payload ['source_coder_commit_decision' ]} " ,
4260+ f"- source_coder_commit_decision_md: { payload ['source_coder_commit_decision_md' ]} " ,
4261+ f"- source_commit_decision_sha256: { payload ['source_commit_decision_sha256' ]} " ,
4262+ "- source_commit_decision_md_sha256: "
4263+ f"{ payload ['source_commit_decision_md_sha256' ]} " ,
4264+ "- source_coder_commit_decision_markdown_consumed: "
4265+ f"{ _bool (payload ['source_coder_commit_decision_markdown_consumed' ] is True )} " ,
41084266 f"- next_recommended_action: { payload ['next_recommended_action' ]} " ,
41094267 "" ,
41104268 "## Committed Files" ,
0 commit comments