3535sys .dont_write_bytecode = True
3636try :
3737 try :
38- from ticket_activity import ActivityError , delivery_landed , resolve as resolve_ticket_activity
38+ from ticket_activity import (ActivityError , delivery_landed ,
39+ parse_ticket_state_text as _shared_ticket_state ,
40+ resolve as resolve_ticket_activity )
3941 except ModuleNotFoundError :
4042 _activity_spec = importlib .util .spec_from_file_location (
4143 "ticket_activity" , Path (__file__ ).with_name ("ticket_activity.py" )
4850 ActivityError = _activity_module .ActivityError
4951 delivery_landed = _activity_module .delivery_landed
5052 resolve_ticket_activity = _activity_module .resolve
53+ _shared_ticket_state = _activity_module .parse_ticket_state_text
5154finally :
5255 sys .dont_write_bytecode = _previous_bytecode_policy
5356
@@ -981,12 +984,12 @@ def placement_error(value: Any) -> str | None:
981984 allowed = required | {"runtimeOwner" , "adopt" }
982985 if not isinstance (value , dict ) or not required <= set (value ) <= allowed :
983986 return "placement must contain home and shape"
984- if value ["home" ] not in PLACEMENT_HOMES :
987+ if not isinstance ( value . get ( "home" ), str ) or value ["home" ] not in PLACEMENT_HOMES :
985988 return "placement home is invalid"
986- if value ["shape" ] not in PLACEMENT_SHAPES :
989+ if not isinstance ( value . get ( "shape" ), str ) or value ["shape" ] not in PLACEMENT_SHAPES :
987990 return "placement shape is invalid"
988991 runtime_owner = value .get ("runtimeOwner" )
989- if runtime_owner is not None and runtime_owner not in PLACEMENT_HOMES :
992+ if runtime_owner is not None and ( not isinstance ( runtime_owner , str ) or runtime_owner not in PLACEMENT_HOMES ) :
990993 return "placement runtimeOwner is invalid"
991994 if value ["home" ] == "wellmanifest" and value ["shape" ] == "runtime_service" :
992995 return "runtime_service must not HOME wellmanifest; ADOPT packs from a product organization"
@@ -1417,14 +1420,12 @@ def check_history_order(
14171420 _ , commit = first_implementation
14181421 ticket_intent = f"{ ticket_root .rstrip ('/' )} /{ ticket_name } /{ intent_path } "
14191422 try :
1420- subprocess .run (
1421- ["git" , "cat-file" , "-e" , f"{ commit } :{ ticket_intent } " ], cwd = root ,
1422- check = True , stdout = subprocess .DEVNULL , stderr = subprocess .DEVNULL ,
1423- )
1424- except subprocess .CalledProcessError :
1423+ raw_blob = git_output (root , ["cat-file" , "-p" , f"{ commit } :{ ticket_intent } " ])
1424+ json .loads (raw_blob .decode ("utf-8" ))
1425+ except (subprocess .CalledProcessError , ValueError , UnicodeDecodeError ):
14251426 report .add (
14261427 "GOV-INTENT-003" ,
1427- f"{ ticket_intent } was absent from the first material implementation commit." ,
1428+ f"{ ticket_intent } was absent or invalid in the first material implementation commit." ,
14281429 "Include the validated intent atomically with the first material commit; do not create a separate plan-only commit." ,
14291430 [ticket_intent ], {"firstImplementationCommit" : commit },
14301431 )
@@ -1774,12 +1775,7 @@ def parse_ticket_state(readme: Path) -> tuple[str | None, str | None]:
17741775
17751776
17761777def parse_ticket_state_text (text : str ) -> tuple [str | None , str | None ]:
1777- status_match = re .search (r"(?mi)^-[ \t]+\*\*Status\*\*:[ \t]*([A-Z_]+)[ \t]*$" , text )
1778- state_match = re .search (r"(?mi)^-[ \t]+\*\*Workflow state\*\*:[ \t]*([A-Z_]+)[ \t]*$" , text )
1779- return (
1780- status_match .group (1 ).upper () if status_match else None ,
1781- state_match .group (1 ).upper () if state_match else None ,
1782- )
1778+ return _shared_ticket_state (text )
17831779
17841780
17851781def ticket_directories (root : Path , config : dict [str , Any ]) -> list [Path ]:
@@ -1946,8 +1942,9 @@ def load_repository_policy_ticket(
19461942 "integrationTicket" : None ,
19471943 "classification" : {"kind" : "SERVICE" , "priority" : "P2" , "origin" : "requested" },
19481944 }
1945+ ticket_root = policy .get ("tickets" , {}).get ("root" , "project" )
19491946 return TicketRecord (
1950- root / str (raw_path ) ,
1947+ root / str (ticket_root ) / adapter [ "ticket" ] ,
19511948 adapter ["status" ],
19521949 adapter ["workflow" ],
19531950 intent ,
@@ -2854,12 +2851,19 @@ def validate_domain_errors(root: Path, errors: dict[str, Any], domain: str, comm
28542851 {"code" , "documentation" , "retryability" , "status" , "rejectionEvent" },
28552852 "errors" ,
28562853 )
2854+ command_for_code = {
2855+ code : [cmd_name for cmd_name , cmd in commands .items () if code in cmd ["rejects" ]]
2856+ for code in error_index
2857+ }
28572858 for error in error_index .values ():
28582859 contract_document (
28592860 root , error ["documentation" ], f"error/{ error ['code' ]} .md" , "error" ,
28602861 )
28612862 if error ["rejectionEvent" ] not in event_index :
28622863 raise ValueError ("error rejection event is unknown" )
2864+ emitter = event_index [error ["rejectionEvent" ]]["emittedBy" ]
2865+ if emitter not in command_for_code .get (error ["code" ], []):
2866+ raise ValueError ("error rejection event emitter does not match rejecting command" )
28632867 if error ["retryability" ] not in {
28642868 "never" , "after-correction" , "after-new-evidence" ,
28652869 }:
@@ -2937,6 +2941,22 @@ def first_repo_file(names: list[str]) -> str | None:
29372941 )
29382942
29392943
2944+ def _section_aware_toml_version (content : str , section_names : tuple [str , ...]) -> str | None :
2945+ current_section = None
2946+ for line in content .splitlines ():
2947+ line = line .strip ()
2948+ if not line or line .startswith ("#" ):
2949+ continue
2950+ if line .startswith ("[" ) and line .endswith ("]" ):
2951+ current_section = line .strip ("[]" ).strip ()
2952+ continue
2953+ if current_section in section_names :
2954+ m = re .match (r'^version\s*=\s*["\']([^"\']+)["\']' , line )
2955+ if m :
2956+ return m .group (1 ).strip ()
2957+ return None
2958+
2959+
29402960def _extract_pyproject_version (content : str ) -> str | None :
29412961 if tomllib is not None :
29422962 try :
@@ -2952,8 +2972,7 @@ def _extract_pyproject_version(content: str) -> str | None:
29522972 return flit ["version" ].strip ()
29532973 except Exception :
29542974 pass
2955- m = re .search (r'^\s*version\s*=\s*["\']([^"\']+)["\']' , content , re .MULTILINE )
2956- return m .group (1 ).strip () if m else None
2975+ return _section_aware_toml_version (content , ("project" , "tool.poetry" , "tool.flit.metadata" ))
29572976
29582977
29592978def _extract_setup_py_version (content : str ) -> str | None :
@@ -2973,8 +2992,7 @@ def _extract_cargo_version(content: str) -> str | None:
29732992 return pkg ["version" ].strip ()
29742993 except Exception :
29752994 pass
2976- m = re .search (r'^\s*version\s*=\s*["\']([^"\']+)["\']' , content , re .MULTILINE )
2977- return m .group (1 ).strip () if m else None
2995+ return _section_aware_toml_version (content , ("package" ,))
29782996
29792997
29802998def check_version_parity (root : Path , manifest : dict [str , Any ], report : Report ) -> None :
0 commit comments