auto-sync: tudo-para-ia-mais-humana 2026-05-02 07:28:45

This commit is contained in:
2026-05-02 07:28:46 -03:00
parent 89e69ff7bd
commit e392a2c255
14 changed files with 45153 additions and 18 deletions

Binary file not shown.

View File

@@ -6,6 +6,6 @@
"path": "G:\\_codex-git\\nucleo-gestao-operacional\\central-de-ordem-de-servico\\projects\\15_repo_tudo-para-ia-mais-humana-platform\\reports\\EXECUTADO__workspace-hygiene.md"
}
],
"generatedAt": "2026-05-02T09:27:04+00:00",
"generatedAt": "2026-05-02T10:25:29+00:00",
"ok": false
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,10 +4,10 @@
"action": "delete_directory",
"applied": true,
"deleted": false,
"error": "PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpnk6r4sdb'",
"error": "PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpnk6r4sdb'; PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpu13bzfhr'; OSError: [WinError 145] A pasta não está vazia: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp'",
"footprint_after": {
"byte_count": 0,
"child_count": 1042,
"child_count": 2,
"errors": [
"PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpnk6r4sdb'",
"PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpu13bzfhr'"
@@ -17,8 +17,8 @@
"is_file": false
},
"footprint_before": {
"byte_count": 68130347,
"child_count": 3052,
"byte_count": 10279,
"child_count": 1186,
"errors": [
"PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpnk6r4sdb'",
"PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpu13bzfhr'"
@@ -61,13 +61,13 @@
],
"apply": true,
"blockers": [
"python-test-temp:PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpnk6r4sdb'"
"python-test-temp:PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpnk6r4sdb'; PermissionError: [WinError 5] Acesso negado: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp\\\\tmpu13bzfhr'; OSError: [WinError 145] A pasta não está vazia: 'G:\\\\_codex-git\\\\tudo-para-ia-mais-humana\\\\.test-tmp'"
],
"central_platform_folder": "G:\\_codex-git\\nucleo-gestao-operacional\\central-de-ordem-de-servico\\projects\\15_repo_tudo-para-ia-mais-humana-platform",
"clean": false,
"generated_at": "2026-05-02T09:27:04+00:00",
"generated_at": "2026-05-02T10:25:29+00:00",
"project_root": "G:\\_codex-git\\tudo-para-ia-mais-humana",
"report_id": "workspace-hygiene-389155382838",
"report_id": "workspace-hygiene-441283210879",
"status": "blocked",
"summary": [
"Targets evaluated: 2.",

View File

@@ -0,0 +1,104 @@
# Politica de higiene de workspace
- report_id: `workspace-hygiene-policy-9147f326520c9100`
- generated_at: `2026-05-02T10:28:39+00:00`
- cases: `1536`
- owner_action_cases: `288`
- unsafe_block_cases: `192`
## Resumo
- Policy cases: 1536.
- Owner action cases: 288.
- Unsafe path blocks: 192.
- Best-effort cleanup must continue after child ACL errors and retain only inaccessible paths.
## Casos amostrais
- `workspace-hygiene-policy-5d2027200080cdc46bb65f26` `.test-tmp` `windows_primary` `inspect` `none` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-228473216bb503bc783a215c` `.test-tmp` `windows_primary` `inspect` `not_found` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-cb761d2f71e849f1c149b488` `.test-tmp` `windows_primary` `inspect` `permission_denied` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-4582db63a0bb51ede7108d29` `.test-tmp` `windows_primary` `inspect` `directory_not_empty` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-fb0ee31aef29fc1e827f9a6a` `.test-tmp` `windows_primary` `inspect` `file_locked` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-4aa82262a3f3e58f587663a6` `.test-tmp` `windows_primary` `inspect` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-4c516245ec963722a3dc7ee8` `.test-tmp` `windows_primary` `inspect` `central_write_denied` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-dabc8c8df47232d77d5e1541` `.test-tmp` `windows_primary` `inspect` `unknown` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-a0a5fba1d3767fe3c2d63f33` `.test-tmp` `windows_primary` `apply` `none` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-3e31009425a0230ecef0ccd8` `.test-tmp` `windows_primary` `apply` `not_found` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-c23bb01b6d9294f0ebfdd9fc` `.test-tmp` `windows_primary` `apply` `permission_denied` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-7cce0df320947bdf44a99a25` `.test-tmp` `windows_primary` `apply` `directory_not_empty` -> `retain_with_evidence` actions `best_effort_delete, continue_after_child_error, write_status_artifact`
- `workspace-hygiene-policy-7d3c3344e63eb8e867ee5bfe` `.test-tmp` `windows_primary` `apply` `file_locked` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-f3675147f70d13633cb09512` `.test-tmp` `windows_primary` `apply` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-ac1bd6962d0b5a4526fdd10a` `.test-tmp` `windows_primary` `apply` `central_write_denied` -> `retain_with_evidence` actions `write_status_artifact, update_semantic_sql`
- `workspace-hygiene-policy-5aef47da6b565cd6dcabe957` `.test-tmp` `windows_primary` `apply` `unknown` -> `retain_with_evidence` actions `write_status_artifact`
- `workspace-hygiene-policy-f9d8c5f22f456ec593c6f211` `.test-tmp` `windows_primary` `closeout` `none` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-66c57ea342cf242a5393be0d` `.test-tmp` `windows_primary` `closeout` `not_found` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-32e3856c59c82f31b106ac99` `.test-tmp` `windows_primary` `closeout` `permission_denied` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-b1638bc1c123df15e80227d2` `.test-tmp` `windows_primary` `closeout` `directory_not_empty` -> `retain_with_evidence` actions `best_effort_delete, continue_after_child_error, write_status_artifact`
- `workspace-hygiene-policy-45895efc199646bc41cdf9e0` `.test-tmp` `windows_primary` `closeout` `file_locked` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-7a53c08cceab0e41c3359ed8` `.test-tmp` `windows_primary` `closeout` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-46699cee9bdfd53b87e78c36` `.test-tmp` `windows_primary` `closeout` `central_write_denied` -> `retain_with_evidence` actions `write_status_artifact, update_semantic_sql`
- `workspace-hygiene-policy-36d8f0af32e85b3e0b279e05` `.test-tmp` `windows_primary` `closeout` `unknown` -> `retain_with_evidence` actions `write_status_artifact`
- `workspace-hygiene-policy-5a1b22bdcb58bbcc237f14ac` `.test-tmp` `windows_primary` `central_record` `none` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-0a88ddf3c1c8b14321813c32` `.test-tmp` `windows_primary` `central_record` `not_found` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-606b442e56149662192ac879` `.test-tmp` `windows_primary` `central_record` `permission_denied` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-89a9c0752f0b51866217bf84` `.test-tmp` `windows_primary` `central_record` `directory_not_empty` -> `retain_with_evidence` actions `best_effort_delete, continue_after_child_error, write_status_artifact`
- `workspace-hygiene-policy-1f3ffab2223eeaecbbdbed62` `.test-tmp` `windows_primary` `central_record` `file_locked` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-1c441a1661159cb6f7187ce1` `.test-tmp` `windows_primary` `central_record` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-aad100963e7d8379a24f2b57` `.test-tmp` `windows_primary` `central_record` `central_write_denied` -> `retain_with_evidence` actions `write_status_artifact, update_semantic_sql`
- `workspace-hygiene-policy-e3eb826734091137b31cc07b` `.test-tmp` `windows_primary` `central_record` `unknown` -> `retain_with_evidence` actions `write_status_artifact`
- `workspace-hygiene-policy-f8242138d8161a66bdd2d7cb` `.test-tmp` `windows_secondary` `inspect` `none` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-8f0f0dfa2a0a0cd0be6b658e` `.test-tmp` `windows_secondary` `inspect` `not_found` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-f9c3fc1327e3c1391868b696` `.test-tmp` `windows_secondary` `inspect` `permission_denied` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-0baf6ba10316a0cfd87f80ad` `.test-tmp` `windows_secondary` `inspect` `directory_not_empty` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-806a326c17d88486df9359d2` `.test-tmp` `windows_secondary` `inspect` `file_locked` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-c992717a0c0a8d1f38b29b08` `.test-tmp` `windows_secondary` `inspect` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-53a6aee1dc74bbd57220d67e` `.test-tmp` `windows_secondary` `inspect` `central_write_denied` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-9c152223f8242817a79971bc` `.test-tmp` `windows_secondary` `inspect` `unknown` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-87c3f9c9b4e74cbc737cbda2` `.test-tmp` `windows_secondary` `apply` `none` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-206da35bc71c92f44cfee34f` `.test-tmp` `windows_secondary` `apply` `not_found` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-51957806f136b8a3e39c1b58` `.test-tmp` `windows_secondary` `apply` `permission_denied` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-0ff808e4688a92886ff70527` `.test-tmp` `windows_secondary` `apply` `directory_not_empty` -> `retain_with_evidence` actions `best_effort_delete, continue_after_child_error, write_status_artifact`
- `workspace-hygiene-policy-d0ad8569490cf7d3fbf0fa6c` `.test-tmp` `windows_secondary` `apply` `file_locked` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-9cc8d387da8cc335efd68e3a` `.test-tmp` `windows_secondary` `apply` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-769cb1efd5f31fa84616585f` `.test-tmp` `windows_secondary` `apply` `central_write_denied` -> `retain_with_evidence` actions `write_status_artifact, update_semantic_sql`
- `workspace-hygiene-policy-bf728d1d9afc76b2627a662a` `.test-tmp` `windows_secondary` `apply` `unknown` -> `retain_with_evidence` actions `write_status_artifact`
- `workspace-hygiene-policy-049c398e0663b27fb5609985` `.test-tmp` `windows_secondary` `closeout` `none` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-0ff76ce14fffe9fe665251e1` `.test-tmp` `windows_secondary` `closeout` `not_found` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-1451df7001a804cc3ee552dc` `.test-tmp` `windows_secondary` `closeout` `permission_denied` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-2cc605680ae873c818865b33` `.test-tmp` `windows_secondary` `closeout` `directory_not_empty` -> `retain_with_evidence` actions `best_effort_delete, continue_after_child_error, write_status_artifact`
- `workspace-hygiene-policy-cb226b7380849e26aa4d76c7` `.test-tmp` `windows_secondary` `closeout` `file_locked` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-63a68ccc0d018e2fe1546090` `.test-tmp` `windows_secondary` `closeout` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-20906dab1c11fbb4cebf2b62` `.test-tmp` `windows_secondary` `closeout` `central_write_denied` -> `retain_with_evidence` actions `write_status_artifact, update_semantic_sql`
- `workspace-hygiene-policy-2221a710356ed9e7607ef7f3` `.test-tmp` `windows_secondary` `closeout` `unknown` -> `retain_with_evidence` actions `write_status_artifact`
- `workspace-hygiene-policy-714c981b7e3ac0583c2a9b9f` `.test-tmp` `windows_secondary` `central_record` `none` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-c99a74dc347c76b2b57bb2e1` `.test-tmp` `windows_secondary` `central_record` `not_found` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-eb582edade7af46be10eea64` `.test-tmp` `windows_secondary` `central_record` `permission_denied` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-2acae1058db81e26fe74bf74` `.test-tmp` `windows_secondary` `central_record` `directory_not_empty` -> `retain_with_evidence` actions `best_effort_delete, continue_after_child_error, write_status_artifact`
- `workspace-hygiene-policy-00a57f8e2a5229b50f48463f` `.test-tmp` `windows_secondary` `central_record` `file_locked` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-2d76fae86d19d0550d374952` `.test-tmp` `windows_secondary` `central_record` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-20ab0f83d53c3cd4c8a67f08` `.test-tmp` `windows_secondary` `central_record` `central_write_denied` -> `retain_with_evidence` actions `write_status_artifact, update_semantic_sql`
- `workspace-hygiene-policy-83f282f1d7fe2cca0bd27934` `.test-tmp` `windows_secondary` `central_record` `unknown` -> `retain_with_evidence` actions `write_status_artifact`
- `workspace-hygiene-policy-90f58c90392bba2d16c0dbd8` `.test-tmp` `codex_server` `inspect` `none` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-7694790458af6a1d5b93d85b` `.test-tmp` `codex_server` `inspect` `not_found` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-e830494add59daf1410a11a6` `.test-tmp` `codex_server` `inspect` `permission_denied` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-b120f9fd5fa901c522ef7d14` `.test-tmp` `codex_server` `inspect` `directory_not_empty` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-ebe8bd703ba081cef5c7d379` `.test-tmp` `codex_server` `inspect` `file_locked` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-7fe73882bbf81c6c267106d0` `.test-tmp` `codex_server` `inspect` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-b65b014821b311f4c5991681` `.test-tmp` `codex_server` `inspect` `central_write_denied` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-8049cd78fdda5b4b748f5074` `.test-tmp` `codex_server` `inspect` `unknown` -> `record_only` actions `verify_absent, write_status_artifact`
- `workspace-hygiene-policy-584d53c3180c3596cb9021f0` `.test-tmp` `codex_server` `apply` `none` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-ab6e1d396d8421f67657dcf1` `.test-tmp` `codex_server` `apply` `not_found` -> `pass` actions `verify_absent`
- `workspace-hygiene-policy-af6f8916bf733c4a553d50e3` `.test-tmp` `codex_server` `apply` `permission_denied` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-3b75f906ae19b7cac43af2f6` `.test-tmp` `codex_server` `apply` `directory_not_empty` -> `retain_with_evidence` actions `best_effort_delete, continue_after_child_error, write_status_artifact`
- `workspace-hygiene-policy-6372da5f33fc0af7df08e000` `.test-tmp` `codex_server` `apply` `file_locked` -> `owner_action_required` actions `best_effort_delete, continue_after_child_error, escalate_owner, record_acl_exception`
- `workspace-hygiene-policy-d95aca64f3bee2b9921624be` `.test-tmp` `codex_server` `apply` `unsafe_path` -> `block_unsafe` actions `block_before_write, write_status_artifact`
- `workspace-hygiene-policy-d71b3e6ba8346080dd3288e2` `.test-tmp` `codex_server` `apply` `central_write_denied` -> `retain_with_evidence` actions `write_status_artifact, update_semantic_sql`
- `workspace-hygiene-policy-0bcdd168427902e850455395` `.test-tmp` `codex_server` `apply` `unknown` -> `retain_with_evidence` actions `write_status_artifact`
## Regra operacional
- Remover somente artefatos locais aprovados.
- Continuar a limpeza depois de erro de filho quando o caminho ainda estiver dentro do projeto.
- Registrar WinError 5, arquivo em uso ou pasta nao vazia como pendencia de owner quando persistirem.
- Nao apagar paths fora do project_root.

View File

@@ -1,7 +1,7 @@
# Workspace Hygiene Report
- report_id: `workspace-hygiene-389155382838`
- generated_at: `2026-05-02T09:27:04+00:00`
- report_id: `workspace-hygiene-441283210879`
- generated_at: `2026-05-02T10:25:29+00:00`
- project_root: `G:\_codex-git\tudo-para-ia-mais-humana`
- central_platform_folder: `G:\_codex-git\nucleo-gestao-operacional\central-de-ordem-de-servico\projects\15_repo_tudo-para-ia-mais-humana-platform`
- status: `blocked`
@@ -27,10 +27,10 @@
- applied: `True`
- deleted: `False`
- exists_after: `True`
- children_before: `3052`
- bytes_before: `68130347`
- children_before: `1186`
- bytes_before: `10279`
- note: artifact retained by ACL or filesystem lock
- error: `PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb'`
- error: `PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb'; PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpu13bzfhr'; OSError: [WinError 145] A pasta não está vazia: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp'`
- footprint_errors:
- `PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb'`
- `PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpu13bzfhr'`
@@ -49,4 +49,4 @@
## Blockers
- `python-test-temp:PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb'`
- `python-test-temp:PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb'; PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpu13bzfhr'; OSError: [WinError 145] A pasta não está vazia: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp'`

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,3 @@
target_id,path,action,status,applied,deleted,exists_after,children_before,bytes_before,error,note
python-test-temp,G:\_codex-git\tudo-para-ia-mais-humana\.test-tmp,delete_directory,blocked,yes,no,yes,3052,68130347,PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb',artifact retained by ACL or filesystem lock
python-test-temp,G:\_codex-git\tudo-para-ia-mais-humana\.test-tmp,delete_directory,blocked,yes,no,yes,1186,10279,PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb'; PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpu13bzfhr'; OSError: [WinError 145] A pasta não está vazia: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp',artifact retained by ACL or filesystem lock
node-dependencies,G:\_codex-git\tudo-para-ia-mais-humana\node_modules,verify_absent,not_found,no,no,no,0,0,,target already absent
1 target_id path action status applied deleted exists_after children_before bytes_before error note
2 python-test-temp G:\_codex-git\tudo-para-ia-mais-humana\.test-tmp delete_directory blocked yes no yes 3052 1186 68130347 10279 PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb' PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpnk6r4sdb'; PermissionError: [WinError 5] Acesso negado: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp\\tmpu13bzfhr'; OSError: [WinError 145] A pasta não está vazia: 'G:\\_codex-git\\tudo-para-ia-mais-humana\\.test-tmp' artifact retained by ACL or filesystem lock
3 node-dependencies G:\_codex-git\tudo-para-ia-mais-humana\node_modules verify_absent not_found no no no 0 0 target already absent

View File

@@ -52,6 +52,7 @@ from .scanner import environment_summary, scan_ecosystem
from .storage import table_counts
from .targeted_sync_audit import run_targeted_sync_audit
from .workspace_hygiene import run_workspace_hygiene
from .workspace_hygiene_policy import policy_payload, run_hygiene_policy
def build_parser() -> argparse.ArgumentParser:
@@ -126,6 +127,10 @@ def build_parser() -> argparse.ArgumentParser:
hygiene.add_argument("--project-root", default="G:/_codex-git/tudo-para-ia-mais-humana")
hygiene.add_argument("--central-platform-folder", default="")
hygiene.add_argument("--apply", action="store_true")
hygiene_policy = sub.add_parser("workspace-hygiene-policy", help="Write executable workspace cleanup and ACL retention policy.")
hygiene_policy.add_argument("--project-root", default="G:/_codex-git/tudo-para-ia-mais-humana")
hygiene_policy.add_argument("--no-generated", action="store_true")
hygiene_policy.add_argument("--limit", type=int, default=40)
sync_audit = sub.add_parser("targeted-sync-audit", help="Write safe Git synchronization audit for the active round repos.")
sync_audit.add_argument("--project-root", default="G:/_codex-git/tudo-para-ia-mais-humana")
sync_audit.add_argument("--mcp-repo-root", default="G:/_codex-git/tudo-para-ia-mcps-internos-plataform")
@@ -557,6 +562,19 @@ def command_workspace_hygiene(args: argparse.Namespace) -> int:
return 0
def command_workspace_hygiene_policy(args: argparse.Namespace) -> int:
report, records = run_hygiene_policy(
project_root=Path(args.project_root),
use_generated=not bool(args.no_generated),
)
payload = {
"report": policy_payload(report, limit_cases=int(args.limit)),
"generatedFiles": [record.path for record in records],
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
return 0
def command_targeted_sync_audit(args: argparse.Namespace) -> int:
central_platform_folder = Path(args.central_platform_folder) if args.central_platform_folder else None
report, records = run_targeted_sync_audit(
@@ -666,6 +684,8 @@ def main(argv: list[str] | None = None) -> int:
return command_mcp_access_policy(args)
if args.command == "workspace-hygiene":
return command_workspace_hygiene(args)
if args.command == "workspace-hygiene-policy":
return command_workspace_hygiene_policy(args)
if args.command == "targeted-sync-audit":
return command_targeted_sync_audit(args)
if args.command == "mcp-admin-route-acceptance":

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,6 @@ import csv
import io
import json
import os
import shutil
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
@@ -196,13 +195,61 @@ def _footprint(path: Path, *, max_errors: int = 8) -> PathFootprint:
return PathFootprint(True, True, False, child_count, byte_count, tuple(errors[:max_errors]))
def _delete_file(path: Path, errors: list[str], *, max_errors: int = 12) -> None:
try:
if not path.exists():
return
path.unlink()
except OSError as exc:
if len(errors) < max_errors:
errors.append(f"{type(exc).__name__}: {exc}")
def _delete_empty_dir(path: Path, errors: list[str], *, max_errors: int = 12) -> None:
try:
if path.exists():
path.rmdir()
except OSError as exc:
if len(errors) < max_errors:
errors.append(f"{type(exc).__name__}: {exc}")
def _delete_directory_best_effort(path: Path) -> tuple[bool, str]:
"""Delete a directory while continuing after ACL errors.
``shutil.rmtree`` stops at the first inaccessible child on Windows. The
closeout hygiene needs a better operational behavior: remove every
accessible file/directory, retain only the ACL-blocked paths, and report the
retained evidence.
"""
errors: list[str] = []
def on_walk_error(exc: OSError) -> None:
if len(errors) < 12:
errors.append(f"{type(exc).__name__}: {exc}")
for current_root, dirnames, filenames in os.walk(path, topdown=False, onerror=on_walk_error):
current = Path(current_root)
for filename in filenames:
_delete_file(current / filename, errors)
for dirname in dirnames:
_delete_empty_dir(current / dirname, errors)
_delete_empty_dir(path, errors)
if not path.exists():
return True, ""
message = "; ".join(merge_unique(errors))
if not message:
message = "path retained after best-effort cleanup"
return False, message
def _delete_path(path: Path) -> tuple[bool, str]:
try:
if not path.exists():
return False, ""
if path.is_dir():
shutil.rmtree(path)
return True, ""
return _delete_directory_best_effort(path)
path.unlink()
return True, ""
except OSError as exc:

View File

@@ -0,0 +1,470 @@
"""Workspace hygiene retention policy.
The closeout rule is simple to say and surprisingly easy to get wrong on
Windows mirrors: remove local build/test artifacts, but keep going when ACLs
retain a child path and record exactly what still needs an authorized owner.
This module turns that rule into executable policy cases that can be exposed to
MCP, tested by Codex, and attached to the service-order closeout.
"""
from __future__ import annotations
import csv
import io
import json
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
from typing import Any, Iterable, Sequence
from .models import GeneratedFile, as_plain_data, merge_unique, utc_now
from .repository_mesh import stable_digest
from .storage import connect, upsert_files
class HygieneArtifactKind(str, Enum):
"""Artifacts governed by the cleanup policy."""
PYTHON_TEST_TEMP = "python_test_temp"
NODE_DEPENDENCIES = "node_dependencies"
PYTHON_CACHE = "python_cache"
WRANGLER_CACHE = "wrangler_cache"
FRONTEND_CACHE = "frontend_cache"
COVERAGE_OUTPUT = "coverage_output"
TEST_REPORT = "test_report"
LOG_OUTPUT = "log_output"
class HygieneErrorKind(str, Enum):
"""Filesystem or operational issue observed during cleanup."""
NONE = "none"
NOT_FOUND = "not_found"
PERMISSION_DENIED = "permission_denied"
DIRECTORY_NOT_EMPTY = "directory_not_empty"
FILE_LOCKED = "file_locked"
UNSAFE_PATH = "unsafe_path"
CENTRAL_WRITE_DENIED = "central_write_denied"
UNKNOWN = "unknown"
class HygieneExecutionMode(str, Enum):
"""Execution mode for a cleanup case."""
INSPECT = "inspect"
APPLY = "apply"
CLOSEOUT = "closeout"
CENTRAL_RECORD = "central_record"
class HygieneEnvironment(str, Enum):
"""Environment where a cleanup case can run."""
WINDOWS_PRIMARY = "windows_primary"
WINDOWS_SECONDARY = "windows_secondary"
CODEX_SERVER = "codex_server"
GITLAB_SERVER = "gitlab_server"
class HygienePolicyStatus(str, Enum):
"""Decision for one hygiene policy case."""
PASS = "pass"
RETAIN_WITH_EVIDENCE = "retain_with_evidence"
OWNER_ACTION_REQUIRED = "owner_action_required"
BLOCK_UNSAFE = "block_unsafe"
RECORD_ONLY = "record_only"
class HygieneRemediationAction(str, Enum):
"""Action recommended by a policy case."""
VERIFY_ABSENT = "verify_absent"
BEST_EFFORT_DELETE = "best_effort_delete"
CONTINUE_AFTER_CHILD_ERROR = "continue_after_child_error"
ESCALATE_OWNER = "escalate_owner"
RECORD_ACL_EXCEPTION = "record_acl_exception"
BLOCK_BEFORE_WRITE = "block_before_write"
WRITE_STATUS_ARTIFACT = "write_status_artifact"
UPDATE_SEMANTIC_SQL = "update_semantic_sql"
ARTIFACT_TARGETS: tuple[tuple[HygieneArtifactKind, str, str], ...] = (
(HygieneArtifactKind.PYTHON_TEST_TEMP, ".test-tmp", "scratch criado por testes Python e comandos de validacao"),
(HygieneArtifactKind.NODE_DEPENDENCIES, "node_modules", "dependencias Node locais que nao devem sobreviver ao fechamento"),
(HygieneArtifactKind.PYTHON_CACHE, "__pycache__", "cache Python recompilavel"),
(HygieneArtifactKind.PYTHON_CACHE, ".pytest_cache", "cache pytest local"),
(HygieneArtifactKind.WRANGLER_CACHE, ".wrangler", "cache local do Wrangler"),
(HygieneArtifactKind.FRONTEND_CACHE, ".next", "build cache frontend"),
(HygieneArtifactKind.FRONTEND_CACHE, ".vite", "build cache frontend"),
(HygieneArtifactKind.COVERAGE_OUTPUT, "coverage", "saida local de cobertura"),
(HygieneArtifactKind.TEST_REPORT, "test-results", "saida local de testes"),
(HygieneArtifactKind.TEST_REPORT, "playwright-report", "relatorio local de browser tests"),
(HygieneArtifactKind.TEST_REPORT, "blob-report", "artefato local de browser tests"),
(HygieneArtifactKind.LOG_OUTPUT, "logs", "logs locais de execucao"),
)
POLICY_TRANSIT_FIELDS: tuple[str, ...] = (
"origin",
"destination",
"tool",
"payload",
"actor",
"permission",
"result",
"traceId",
"auditId",
"timestamp",
)
@dataclass(frozen=True, slots=True)
class HygienePolicyCase:
"""One policy case for local artifact cleanup."""
case_id: str
artifact_kind: HygieneArtifactKind
relative_path: str
environment: HygieneEnvironment
execution_mode: HygieneExecutionMode
error_kind: HygieneErrorKind
status: HygienePolicyStatus
remediation_actions: tuple[HygieneRemediationAction, ...]
required_evidence: tuple[str, ...]
mcp_transit_required: bool
direct_delete_allowed: bool
reason: str
next_action: str
def to_dict(self) -> dict[str, Any]:
return as_plain_data(self)
@dataclass(frozen=True, slots=True)
class HygienePolicyReport:
"""Policy report used by CLI, Markdown, CSV, and tests."""
report_id: str
generated_at: str
cases: tuple[HygienePolicyCase, ...]
summary: tuple[str, ...]
@property
def cases_count(self) -> int:
return len(self.cases)
@property
def owner_action_count(self) -> int:
return sum(1 for case in self.cases if case.status == HygienePolicyStatus.OWNER_ACTION_REQUIRED)
@property
def unsafe_block_count(self) -> int:
return sum(1 for case in self.cases if case.status == HygienePolicyStatus.BLOCK_UNSAFE)
def to_dict(self) -> dict[str, Any]:
data = as_plain_data(self)
data["cases_count"] = self.cases_count
data["owner_action_count"] = self.owner_action_count
data["unsafe_block_count"] = self.unsafe_block_count
return data
def classify_policy_case(
*,
artifact_kind: HygieneArtifactKind,
relative_path: str,
environment: HygieneEnvironment,
execution_mode: HygieneExecutionMode,
error_kind: HygieneErrorKind,
) -> tuple[HygienePolicyStatus, tuple[HygieneRemediationAction, ...], bool, str, str]:
"""Classify one cleanup situation into an auditable policy decision."""
if error_kind == HygieneErrorKind.UNSAFE_PATH:
return (
HygienePolicyStatus.BLOCK_UNSAFE,
(HygieneRemediationAction.BLOCK_BEFORE_WRITE, HygieneRemediationAction.WRITE_STATUS_ARTIFACT),
False,
"path calculado sai do project_root ou cruza boundary de volume",
"bloquear antes de qualquer escrita e registrar evidencia",
)
if execution_mode == HygieneExecutionMode.INSPECT:
return (
HygienePolicyStatus.RECORD_ONLY,
(HygieneRemediationAction.VERIFY_ABSENT, HygieneRemediationAction.WRITE_STATUS_ARTIFACT),
False,
"modo inspecao nunca apaga artefato",
"registrar footprint e executar apply apenas no fechamento",
)
if error_kind in {HygieneErrorKind.NONE, HygieneErrorKind.NOT_FOUND}:
return (
HygienePolicyStatus.PASS,
(HygieneRemediationAction.VERIFY_ABSENT,),
True,
"artefato ausente ou removivel por limpeza local aprovada",
"manter ausente e registrar status",
)
if error_kind in {HygieneErrorKind.PERMISSION_DENIED, HygieneErrorKind.FILE_LOCKED}:
return (
HygienePolicyStatus.OWNER_ACTION_REQUIRED,
(
HygieneRemediationAction.BEST_EFFORT_DELETE,
HygieneRemediationAction.CONTINUE_AFTER_CHILD_ERROR,
HygieneRemediationAction.ESCALATE_OWNER,
HygieneRemediationAction.RECORD_ACL_EXCEPTION,
),
True,
"ACL ou processo externo reteve caminho depois de remover filhos acessiveis",
"registrar caminho retido e solicitar owner autorizado",
)
if error_kind == HygieneErrorKind.DIRECTORY_NOT_EMPTY:
return (
HygienePolicyStatus.RETAIN_WITH_EVIDENCE,
(
HygieneRemediationAction.BEST_EFFORT_DELETE,
HygieneRemediationAction.CONTINUE_AFTER_CHILD_ERROR,
HygieneRemediationAction.WRITE_STATUS_ARTIFACT,
),
True,
"diretorio ainda contem filho retido por erro anterior",
"reduzir conteudo acessivel e registrar filhos retidos",
)
if error_kind == HygieneErrorKind.CENTRAL_WRITE_DENIED:
return (
HygienePolicyStatus.RETAIN_WITH_EVIDENCE,
(HygieneRemediationAction.WRITE_STATUS_ARTIFACT, HygieneRemediationAction.UPDATE_SEMANTIC_SQL),
False,
"pasta central recusou escrita, mas projeto real deve registrar status",
"manter fallback no projeto real e registrar pendencia central",
)
return (
HygienePolicyStatus.RETAIN_WITH_EVIDENCE,
(HygieneRemediationAction.WRITE_STATUS_ARTIFACT,),
False,
"erro desconhecido deve ser evidenciado antes de nova tentativa",
"registrar erro bruto redigido e reavaliar proxima rodada",
)
def build_policy_cases() -> tuple[HygienePolicyCase, ...]:
"""Build the deterministic matrix of hygiene policy cases."""
cases: list[HygienePolicyCase] = []
for artifact_kind, relative_path, description in ARTIFACT_TARGETS:
for environment in HygieneEnvironment:
for execution_mode in HygieneExecutionMode:
for error_kind in HygieneErrorKind:
status, actions, direct_delete_allowed, reason, next_action = classify_policy_case(
artifact_kind=artifact_kind,
relative_path=relative_path,
environment=environment,
execution_mode=execution_mode,
error_kind=error_kind,
)
seed = {
"artifact": artifact_kind.value,
"path": relative_path,
"environment": environment.value,
"mode": execution_mode.value,
"error": error_kind.value,
}
evidence = (
"footprint_before",
"footprint_after",
"git_status_short",
"node_modules_absent",
"acl_error_excerpt" if error_kind != HygieneErrorKind.NONE else "no_error",
description,
)
cases.append(
HygienePolicyCase(
case_id=f"workspace-hygiene-policy-{stable_digest(seed, 24)}",
artifact_kind=artifact_kind,
relative_path=relative_path,
environment=environment,
execution_mode=execution_mode,
error_kind=error_kind,
status=status,
remediation_actions=actions,
required_evidence=evidence,
mcp_transit_required=True,
direct_delete_allowed=direct_delete_allowed,
reason=reason,
next_action=next_action,
)
)
return tuple(cases)
def build_hygiene_policy_cases(*, use_generated: bool = True) -> tuple[HygienePolicyCase, ...]:
"""Return generated policy cases when available, otherwise build runtime cases."""
if use_generated:
try:
from .generated_workspace_hygiene_policy import iter_policy_cases
return tuple(iter_policy_cases())
except (ImportError, AttributeError):
pass
return build_policy_cases()
def build_hygiene_policy_report(*, use_generated: bool = True) -> HygienePolicyReport:
"""Build a compact policy report."""
cases = build_hygiene_policy_cases(use_generated=use_generated)
summary = (
f"Policy cases: {len(cases)}.",
f"Owner action cases: {sum(1 for case in cases if case.status == HygienePolicyStatus.OWNER_ACTION_REQUIRED)}.",
f"Unsafe path blocks: {sum(1 for case in cases if case.status == HygienePolicyStatus.BLOCK_UNSAFE)}.",
"Best-effort cleanup must continue after child ACL errors and retain only inaccessible paths.",
)
return HygienePolicyReport(
report_id=f"workspace-hygiene-policy-{stable_digest([case.case_id for case in cases], 16)}",
generated_at=utc_now(),
cases=cases,
summary=summary,
)
def policy_payload(report: HygienePolicyReport, *, limit_cases: int = 80) -> dict[str, Any]:
"""Return compact JSON payload for the policy report."""
payload = report.to_dict()
payload["transit_fields"] = list(POLICY_TRANSIT_FIELDS)
payload["cases"] = [case.to_dict() for case in report.cases[: max(0, limit_cases)]]
payload["cases_total"] = len(report.cases)
return payload
def policy_case_rows(cases: Sequence[HygienePolicyCase]) -> list[list[str]]:
"""Return CSV rows for policy cases."""
rows = [
[
"case_id",
"artifact_kind",
"relative_path",
"environment",
"execution_mode",
"error_kind",
"status",
"remediation_actions",
"direct_delete_allowed",
"reason",
"next_action",
]
]
for case in cases:
rows.append(
[
case.case_id,
case.artifact_kind.value,
case.relative_path,
case.environment.value,
case.execution_mode.value,
case.error_kind.value,
case.status.value,
" | ".join(action.value for action in case.remediation_actions),
"yes" if case.direct_delete_allowed else "no",
case.reason,
case.next_action,
]
)
return rows
def rows_to_csv(rows: Sequence[Sequence[str]]) -> str:
"""Serialize rows to CSV text."""
buffer = io.StringIO()
writer = csv.writer(buffer, lineterminator="\n")
writer.writerows(rows)
return buffer.getvalue()
def policy_markdown(report: HygienePolicyReport, *, limit_cases: int = 40) -> str:
"""Render the policy report in Markdown."""
lines = [
"# Politica de higiene de workspace",
"",
f"- report_id: `{report.report_id}`",
f"- generated_at: `{report.generated_at}`",
f"- cases: `{report.cases_count}`",
f"- owner_action_cases: `{report.owner_action_count}`",
f"- unsafe_block_cases: `{report.unsafe_block_count}`",
"",
"## Resumo",
"",
]
lines.extend(f"- {item}" for item in report.summary)
lines.extend(["", "## Casos amostrais", ""])
for case in report.cases[: max(0, limit_cases)]:
actions = ", ".join(action.value for action in case.remediation_actions)
lines.append(
f"- `{case.case_id}` `{case.relative_path}` `{case.environment.value}` `{case.execution_mode.value}` "
f"`{case.error_kind.value}` -> `{case.status.value}` actions `{actions}`"
)
lines.extend(
[
"",
"## Regra operacional",
"",
"- Remover somente artefatos locais aprovados.",
"- Continuar a limpeza depois de erro de filho quando o caminho ainda estiver dentro do projeto.",
"- Registrar WinError 5, arquivo em uso ou pasta nao vazia como pendencia de owner quando persistirem.",
"- Nao apagar paths fora do project_root.",
"",
]
)
return "\n".join(lines)
def generated_files(project_root: Path) -> tuple[GeneratedFile, ...]:
"""Return semantic records for policy artifacts."""
relation = "0041_EXECUTIVA__resolver-test-tmp-bloqueado-por-acl"
specs = (
("dados/workspace-hygiene-policy.json", "Politica JSON de retencao e limpeza de workspace.", "workspace hygiene policy", "json"),
("matrizes/workspace-hygiene-policy-cases.csv", "Matriz de casos de higiene e ACL.", "workspace hygiene policy cases", "csv"),
("ecossistema/WORKSPACE-HYGIENE-POLICY.md", "Relatorio humano da politica de higiene.", "workspace hygiene policy report", "markdown"),
)
return tuple(
GeneratedFile(
path=str(project_root / relative),
description=description,
function=function,
file_type=file_type,
changed_by="mais_humana.workspace_hygiene_policy",
change_summary="Criada politica executavel para limpeza parcial, ACL, owner action e evidencia de fechamento.",
relation_to_order=relation,
)
for relative, description, function, file_type in specs
)
def write_policy_artifacts(report: HygienePolicyReport, project_root: Path) -> tuple[GeneratedFile, ...]:
"""Write policy JSON, CSV, Markdown, and semantic file records."""
targets = (
(project_root / "dados" / "workspace-hygiene-policy.json", json.dumps(policy_payload(report, limit_cases=160), ensure_ascii=False, indent=2, sort_keys=True)),
(project_root / "matrizes" / "workspace-hygiene-policy-cases.csv", rows_to_csv(policy_case_rows(report.cases))),
(project_root / "ecossistema" / "WORKSPACE-HYGIENE-POLICY.md", policy_markdown(report, limit_cases=80)),
)
for path, text in targets:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding="utf-8")
records = generated_files(project_root)
with connect(project_root / "controle-semantico.sqlite") as conn:
upsert_files(conn, records)
conn.commit()
return records
def run_hygiene_policy(project_root: Path, *, use_generated: bool = True) -> tuple[HygienePolicyReport, tuple[GeneratedFile, ...]]:
"""Build and persist the workspace hygiene policy artifacts."""
report = build_hygiene_policy_report(use_generated=use_generated)
records = write_policy_artifacts(report, project_root)
return report, records

View File

@@ -0,0 +1,64 @@
from __future__ import annotations
import json
import unittest
from mais_humana.cli import main
from mais_humana.storage import table_counts
from mais_humana.workspace_hygiene_policy import (
HygieneErrorKind,
HygieneExecutionMode,
HygienePolicyStatus,
build_hygiene_policy_report,
build_policy_cases,
policy_payload,
)
from tests.helpers import make_tmp
class WorkspaceHygienePolicyTests(unittest.TestCase):
def test_runtime_policy_contains_acl_owner_cases(self) -> None:
report = build_hygiene_policy_report(use_generated=False)
self.assertGreaterEqual(report.cases_count, 1000)
self.assertGreater(report.owner_action_count, 0)
self.assertGreater(report.unsafe_block_count, 0)
self.assertTrue(
any(
case.error_kind == HygieneErrorKind.PERMISSION_DENIED
and case.execution_mode == HygieneExecutionMode.APPLY
and case.status == HygienePolicyStatus.OWNER_ACTION_REQUIRED
for case in report.cases
)
)
def test_payload_is_limited_but_keeps_totals(self) -> None:
report = build_hygiene_policy_report(use_generated=False)
payload = policy_payload(report, limit_cases=7)
self.assertEqual(len(payload["cases"]), 7)
self.assertEqual(payload["cases_total"], report.cases_count)
self.assertIn("traceId", payload["transit_fields"])
def test_generated_policy_matches_runtime_case_count(self) -> None:
runtime_count = len(build_policy_cases())
generated = build_hygiene_policy_report(use_generated=True)
self.assertEqual(generated.cases_count, runtime_count)
def test_cli_writes_policy_artifacts_and_sql(self) -> None:
project = make_tmp()
code = main(["workspace-hygiene-policy", "--project-root", str(project), "--no-generated", "--limit", "5"])
self.assertEqual(code, 0)
self.assertTrue((project / "dados" / "workspace-hygiene-policy.json").exists())
self.assertTrue((project / "matrizes" / "workspace-hygiene-policy-cases.csv").exists())
self.assertTrue((project / "ecossistema" / "WORKSPACE-HYGIENE-POLICY.md").exists())
payload = json.loads((project / "dados" / "workspace-hygiene-policy.json").read_text(encoding="utf-8"))
self.assertGreaterEqual(payload["cases_total"], 1000)
self.assertGreaterEqual(table_counts(project / "controle-semantico.sqlite").get("files", 0), 3)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,120 @@
"""Generate importable workspace hygiene policy cases."""
from __future__ import annotations
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src"
OUTPUT = SRC / "mais_humana" / "generated_workspace_hygiene_policy.py"
def ensure_import_path() -> None:
import sys
src = str(SRC)
if src not in sys.path:
sys.path.insert(0, src)
def q(value: object) -> str:
return repr(str(value))
def bool_literal(value: bool) -> str:
return "True" if value else "False"
def tuple_enum(values: object) -> str:
items = list(values)
if not items:
return "()"
lines = ["("]
for item in items:
lines.append(f" HygieneRemediationAction.{getattr(item, 'name')},")
lines.append(" )")
return "\n".join(lines)
def tuple_str(values: object) -> str:
items = [str(value) for value in values]
if not items:
return "()"
lines = ["("]
for item in items:
lines.append(f" {q(item)},")
lines.append(" )")
return "\n".join(lines)
def case_block(case: object) -> str:
return "\n".join(
[
" HygienePolicyCase(",
f" case_id={q(getattr(case, 'case_id'))},",
f" artifact_kind=HygieneArtifactKind.{getattr(case, 'artifact_kind').name},",
f" relative_path={q(getattr(case, 'relative_path'))},",
f" environment=HygieneEnvironment.{getattr(case, 'environment').name},",
f" execution_mode=HygieneExecutionMode.{getattr(case, 'execution_mode').name},",
f" error_kind=HygieneErrorKind.{getattr(case, 'error_kind').name},",
f" status=HygienePolicyStatus.{getattr(case, 'status').name},",
" remediation_actions=" + tuple_enum(getattr(case, "remediation_actions")) + ",",
" required_evidence=" + tuple_str(getattr(case, "required_evidence")) + ",",
f" mcp_transit_required={bool_literal(getattr(case, 'mcp_transit_required'))},",
f" direct_delete_allowed={bool_literal(getattr(case, 'direct_delete_allowed'))},",
f" reason={q(getattr(case, 'reason'))},",
f" next_action={q(getattr(case, 'next_action'))},",
" ),",
]
)
def main() -> int:
ensure_import_path()
from mais_humana.workspace_hygiene_policy import build_policy_cases
cases = build_policy_cases()
lines = [
'"""Generated workspace hygiene policy cases.',
"",
"Do not edit this file by hand. Regenerate with:",
"",
" python tools/generate_workspace_hygiene_policy.py",
'"""',
"",
"from __future__ import annotations",
"",
"from .workspace_hygiene_policy import (",
" HygieneArtifactKind,",
" HygieneEnvironment,",
" HygieneErrorKind,",
" HygieneExecutionMode,",
" HygienePolicyCase,",
" HygienePolicyStatus,",
" HygieneRemediationAction,",
")",
"",
f"GENERATED_POLICY_CASES_COUNT = {len(cases)}",
"",
"POLICY_CASES = (",
]
lines.extend(case_block(case) for case in cases)
lines.extend(
[
")",
"",
"",
"def iter_policy_cases():",
" return POLICY_CASES",
"",
]
)
OUTPUT.write_text("\n".join(lines), encoding="utf-8")
print(f"generated {OUTPUT} cases={len(cases)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())