diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 333dc5a..57083a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,8 @@ name: Capability wall and standard-library suite on: push: + branches: [main] + tags: ["v*"] pull_request: permissions: diff --git a/ADOPTING.md b/ADOPTING.md index ae6f154..7b82809 100644 --- a/ADOPTING.md +++ b/ADOPTING.md @@ -42,12 +42,10 @@ locked session may deny the network request that would otherwise retrieve them. For a first adoption, the default is the day-zero coordinator: -Release candidate `v0.9.3` contains the terminal Architect handoff described -below but is not yet published. The tagged install command becomes valid only -after that release is published; until then, use the checked source-tree fallback. +Release `v0.9.3` is published and contains the terminal Architect handoff +described below. ```text -# After v0.9.3 is published, install that tagged release. python -m pip install "https://github.com/HLLMR/writwall/archive/refs/tags/v0.9.3.zip" # Installed command diff --git a/PROJECTION-MANIFEST.sha256 b/PROJECTION-MANIFEST.sha256 index 71b7ae6..e2da980 100644 --- a/PROJECTION-MANIFEST.sha256 +++ b/PROJECTION-MANIFEST.sha256 @@ -3,9 +3,9 @@ ad5c9e60c3e8512adbbe005585ab801cb58b44cb277ad2136fc0c2c42c5ad480 .github/ISSUE_ 97dd39f9b48f5eba205125b007204e6241088ad7a4b4e606132107f4b327f41a .github/ISSUE_TEMPLATE/feature_request.yml b2e36dfcfc6eb31570c9340640bcd73abc62f57c80b4794abf36e3d3e89ab34f .github/dependabot.yml 9e90d43615b02a265b08692ef7a1c00a37477a5c6b1e8233a8fc7bedefaedea6 .github/pull_request_template.md -40e5cddf710e4e6fa4984ac864fdb30a7031005ef1a80082ce0cc6a4f9bc115e .github/workflows/ci.yml +3c35b31bc2b80d101a3a549da68fec55587b6a6428ce6b32112670276490ce23 .github/workflows/ci.yml e544abe8ffd83c81c7b002cbd2e552f9d56f226ea20e1e0722c5d1bdec914fe0 .gitignore -3070e0fcfea3c39c621d323b586e108ee86e83f56d4300117bba45db0f49124b ADOPTING.md +4e610d391b2c3ba95a269ab1112464feca5263c648e78fc2aefc6b713d3fc817 ADOPTING.md 1179c999034f4ec1c1d44c1946bd2955c4625905e80767abe760c8c3ab01c493 CLAUDE.md 86f3193d5174d8bc5a594a2c5a065de97255e9f223da374632c8eb3f592ca6ab CONTRIBUTING.md 664196054cd98585105be457afa09c788a482416ccb48a87bb269b2156e49ae6 DOCTRINE.md @@ -16,13 +16,13 @@ c274f80372d90c012937370f0e1f15087d22e308ef98b27cea5dc0d2d088366c LICENSES/Apach a2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499 LICENSES/CC0-1.0.txt 59746d6285ffa44bfc7ecada352aa5d6a20dc8eab418a60ce091cc739012c135 LICENSES/MIT-0.txt 35e6d37b7c5fa0c1fc872315cbd362cd24bfa41e1b7dc3019fbcd31e99350f51 NAMING.md -61e2afa6304c7e1ba8f2cd9687d51d8bb9ab5f9c9b68bb6883b1f4252288ff51 PROJECTION-PROVENANCE.md +bd0e416ac56565c27fa3ab00d3248a04ef825f4cd3a6c1a815bb919f35816202 PROJECTION-PROVENANCE.md 9716fb18ddca4626791e17474cdba2fd343f47886080c6ff8b1e7c41f63830ec PUBLICATION.md -2bef9b65ca9ff3aec8dc8149f185f337c7f0e4d71c79c62661f37f9c1a543c82 README.md +d05596604edc06e5ac5c2502ecd61b945e0caa41fe63a39de66a3d58fa2e1e2b README.md 284a0862f3be77e8d867aa4d3ef92ed1a64ad4315d6d9074f6bb64771b6d1dd0 REUSE.toml ab75b39490b4db4e203f5b23b480a1c998d87cf07d760cb787cb260778b21d0a SECURITY.md 6a51c1211cc675599634d144ca24a705ec1696f84640a6464b14efb1d6c3a629 SELF-HOSTING.md -10d0bc5c620e4fb108869027cb69bd754e616927b9f9e6cec635a02b43abce1d START-HERE.md +b6a970033c7fb8d6976471216d68f8c961e2417657b655801f191319b9d3e702 START-HERE.md 75c7ae0f569148f489570d63df916a70b6ccf24b77db2076cdee29663f747428 adapters/claude-code/README.md aeb7f81d139e7ffa6de9a1782444b99eb6d549ac1c3a8b9c0f8bcb9c6addfa6d adapters/claude-code/SECURITY.md dd29af2a39d25e0270ad9acc23ee912f81e39c674e1179759f4a3010c6a0c1a0 adapters/claude-code/wo_capability_wall.py @@ -61,11 +61,11 @@ d2c5a8ca21edf842dfd17a83862024afa0a92349abf693a60e55ce454c8d78fa examples/name- 0d62666ddc07a4283309bcbc8f9501add4ecec052d26369d30ce232e17c17702 examples/plumbline-self-hosting-pilot.md 30cdb11fbeb2fd9bbf4048255331ccbbdd6e516fae5adfa5317af00ce53607c9 governance/ADOPTION-MAPPING.md 08b235351ab7799715b1e2df4fa3dd9fa88bb85084c8aade4d01039bf255b489 governance/LOG-denials-probes.md -50784b173c90c4fd22572306429187c8a7e22614f4b9ad649a3005647467c7fa governance/LOG-denials.jsonl -8f1ae9b4f005a31eed74e9f68429fed33fc6ffed2bd31e05de59327d4f9db220 governance/LOG.md -3b5645777ed304ce7205fbd797323320fd10ddd421bf4b9562c5bd3c28b4df9f governance/PLAN.md +72581985a0c16bcd2c2abe5e871a23918be3acc320e0529c94c4a0aa07207033 governance/LOG-denials.jsonl +8a27c2cda1dbbb3d38ca03f1745352abb0ab07290d691dd4f063d3e274da425f governance/LOG.md +0a1cfae5dcd8d475a599fff8bb8c07c745f4baae63adb8def5ddbcad6cfb13ea governance/PLAN.md dd445eb2994e0d9615bc61fe2ae157a6b14ba7b190c65b705d380b31c49fdfe0 governance/ROUTING.md -abd6676fd83bb1e7a480048ffc3e717fe9184a41e5c887ef223c40d3bed113a1 governance/STATE.md +4ad60876ac2ff78f8eb212e0c4b54a42dd5c1131780a2b1add58f9367bcd0ee7 governance/STATE.md e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 governance/archive/.gitkeep e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 governance/briefs/.gitkeep e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 governance/decisions/.gitkeep @@ -82,7 +82,7 @@ b567ce0c0867464328e81774d888f6491fa66b68ac73be01f993e5c4c66d3ed8 governance/tem d355e46f978f17de8824af805e05124e0f20b1c072523b518422044f88c6f079 governance/templates/D-adoption-record.md 2b586efadab716a59fcafb74312a45a05401a4787fee6ae18cb5c9dd14ef3a09 governance/templates/E-adoption-mapping.md e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 governance/work-orders/.gitkeep -2f0ce5496677f7a85b3bf49c22ebd16e8ece655bf1cc53a8714d1f148142bc0e identity/legacy-references.json +2bccff453a30dcc8556221b3552a2b3b58616c16b023e008478b912f10029fb0 identity/legacy-references.json 345b7e962731c085a95aea66a344eae000b27c9bde13b0d790c76b73273dbe7a init.sh 5c90584642f405534b2071f27396ff293ab01632e4dbb8ccb6b8ec043dca4cc9 migration-guides/0.1-to-0.6.md ba4eff258ca5b9a45f3f9f1cbf646ba5bc5521fae812adacac65cd2e78698c9d migration-guides/0.6-to-0.7.md @@ -92,7 +92,7 @@ cb875755a70e151f9ea75b11d88da8dff8f5e9732ff923c5d01156ecc392a445 pyproject.toml 455ca1ab3c9e7e78afbb9946e13b94497ba24003ab6f411ea96cce26d4ecc39e scripts/build_distribution.py bdbe47e8ea246ceafb874229d5582a9cc18db7c66250c9873d50a787bd5d9fe2 scripts/build_public_projection.py 3cf88f936599e0e84bc2368bc0503a39b9f96e47b473e09b26569e5c3c9edbd9 scripts/collect_name_clearance.py -8441030e9df498e9c2621d37d9bf77850599723c985b1d958b8d11638dcb1ae4 scripts/privacy_screen.py +c372f7f1736eb77bedaca43696ea0b060333733f912053479b363442022c4b24 scripts/privacy_screen.py fb793b5d08981e9a2f44f62c26d79d3652aa56f5d6db600fca4ce5546ba2c141 scripts/start_writwall.py 374f4e8a80b7b9e162b9360a3907b6ffe12ce94ba0ed827058c7b3c9c0658b2c skills/writwall-adopt/LICENSE-MAP.md 1c15f2a97cddf727f3173b8971e6ea3e05ab93f57664f8c3031eb0e634a87933 skills/writwall-adopt/SKILL.md @@ -121,12 +121,12 @@ d355e46f978f17de8824af805e05124e0f20b1c072523b518422044f88c6f079 templates/D-ad 9924816cbbeade6f88f79d3e06fe04d143d801783888210ac2325925d69e4bdb tests/test_check_distribution.py b046f2eea794070194294a33f2914e627eed384e63fccffc2ac46693db2a968c tests/test_check_licenses.py 9a106ff5182b4a15713575de42e90b0dc5cdeebcb17ba08d97522a4c9aa6b2fa tests/test_check_work_order_dispatch.py -61c0276a850b38c39c9a8fb355b71fae6f9fa228d8cb664cff8f8c9ca60b1173 tests/test_coordinator_release.py -e5e6df9ead5effa20ee48167f070aa43eb8716e4df66fd997df65d6c2edc7c69 tests/test_distribution.py +304066215be7c840888f9dc5afdd3e9b0470907ce18bb1f1157370c320743f16 tests/test_coordinator_release.py +6483f84819c08284b989252f4a40a42e8eca64fec5fda303cec62350c19328d0 tests/test_distribution.py e150a2f988a4b0beac5f70644f55f5e185a8aa575e988a19642bafabc0f07775 tests/test_identity_migration.py 11cd8090dbc53e8aa6a2f14cb181c8a11696335da8f40700eae5116798e49ba5 tests/test_init_sh.py 96c255d84e37b8884cde769897e763776b81027080c2308c33dc5e4b8df4a4bf tests/test_name_clearance.py -a8345b5da77a8b73dd0269110be89bc0ad85c253f2c76b1b075d494fa018a21f tests/test_privacy_screen.py +677d5b532450ace267be9c834269c081368697cd83defa5531ce673f6d0ca252 tests/test_privacy_screen.py ee771c239c0fc072675f88617dec7e330c1e19be90a8b22691d7049dbb5a4544 tests/test_public_projection.py 478a470078cfb0ac10a9e93c5d4c656830bf089f7b7a4999c7ce975b7dc0b08e tests/test_start_writwall.py 0684c04067eb95eadc9f72ab126d8662b4a5e2005c80b2dea174075a6140eebc tests/test_wo_capability_wall.py diff --git a/PROJECTION-PROVENANCE.md b/PROJECTION-PROVENANCE.md index 62a75e3..8b53ba8 100644 --- a/PROJECTION-PROVENANCE.md +++ b/PROJECTION-PROVENANCE.md @@ -5,8 +5,8 @@ Legacy commit identifiers in projected records refer to that private source and are intentionally not resolvable from fresh public history. No private remote URL is recorded here. -- Source commit: `9da1a2b34e787737837a9c857f002dc23ebfb277` -- Source commit time: `2026-09-02T12:10:32-05:00` +- Source commit: `ae6ca4e29493b7c33738756190dc1bbf1617388d` +- Source commit time: `2026-09-02T20:30:55-05:00` - Projection allowlist SHA-256: `fafcbf659c40d7260dddaa8a64b6b59c3b7de484f77d879a90323bb4b3e1a4a7` ## Legacy identifier inventory @@ -21,4 +21,5 @@ No private remote URL is recorded here. - `a905c87987f31094121c11a3b8163f97ef1abcf4` — `SELF-HOSTING.md`, `governance/STATE.md`, `governance/decisions/DR-001.md` - `ba3c0754e5019f1fa93779d110843562cfa07307` — `governance/STATE.md` - `d790a2b8d500a1c3a5e10af9f0a78d1c3c3f4e3a` — `governance/STATE.md` +- `e0cef360843dff38d6a02dd48be8f61b2d2d300e` — `governance/PLAN.md`, `governance/STATE.md` - `e270fd3235d170a28a21fd198b88857740b74acd` — `governance/STATE.md` diff --git a/README.md b/README.md index 7da7fa4..610c3c6 100644 --- a/README.md +++ b/README.md @@ -98,12 +98,10 @@ inspects the target before intake, assigns the correct fresh role, and changes target bytes only for clean/new bootstrap. It never installs the wall or claims adoption. This routing happens without installing the wall or claiming adoption: -Release candidate `v0.9.3` contains the terminal Architect handoff described -below but is not yet published. The tagged install command becomes valid only -after that release is published; until then, use the checked source-tree fallback. +Release `v0.9.3` is published and contains the terminal Architect handoff +described below. ```text -# After v0.9.3 is published, install that tagged release. python -m pip install "https://github.com/HLLMR/writwall/archive/refs/tags/v0.9.3.zip" # Installed command diff --git a/START-HERE.md b/START-HERE.md index 7f60ba8..86a8878 100644 --- a/START-HERE.md +++ b/START-HERE.md @@ -59,9 +59,8 @@ names, repository slugs, domains, logos, or launch copy. The coordinator may collect evidence, but the Owner chooses the identity; unavailable sources are not clear results. -1. Release candidate `v0.9.3` contains the terminal Architect handoff but is - not yet published. After publication, install it without unpacking it over - your project; until then, use the checked source-tree fallback below: +1. Release `v0.9.3` is published and contains the terminal Architect handoff. + Install it without unpacking it over your project: ```text python -m pip install "https://github.com/HLLMR/writwall/archive/refs/tags/v0.9.3.zip" @@ -69,7 +68,7 @@ not clear results. Release `v0.9.0` first introduced the coordinator. Release `v0.9.1` corrected first-use bytecode residue. Release `v0.9.2` corrects the bootstrap - expected-denial contract. Release candidate `v0.9.3` adds lifecycle-aware + expected-denial contract. Release `v0.9.3` adds lifecycle-aware routing and the terminal Architect handoff. If you are testing an unpublished release candidate, use its checked external candidate tree and the release gate in `PUBLICATION.md`. diff --git a/governance/LOG-denials.jsonl b/governance/LOG-denials.jsonl index 72fa2e7..6bd992e 100644 --- a/governance/LOG-denials.jsonl +++ b/governance/LOG-denials.jsonl @@ -308,3 +308,13 @@ {"schema":1,"timestamp":"2026-08-28T02:41:25Z","session_id":"3164b0b3-d9b8-44d3-8648-d2ce46ad618c","tool":"Glob","surface":"filesystem.read","work_order":"governance/work-orders/WO-PL-033-public-front-door-and-release-hygiene.md","decision":"deny","reason_code":"read_traversal_denied","reason":"Read traversal could reach a grant.filesystem.read.deny subtree."} {"schema":1,"timestamp":"2026-08-28T02:41:33Z","session_id":"3164b0b3-d9b8-44d3-8648-d2ce46ad618c","tool":"Edit","surface":"filesystem.write","work_order":"governance/work-orders/WO-PL-033-public-front-door-and-release-hygiene.md","decision":"deny","reason_code":"write_target_out_of_grant","reason":"Write target is outside grant.filesystem.write."} {"schema":1,"timestamp":"2026-08-29T13:46:40Z","session_id":"9d3e6df2-ec9b-4d50-b219-de48f8cf02b0","tool":"Write","surface":"filesystem.write","work_order":"governance/work-orders/WO-PL-037-controlled-identity-migration.md","decision":"deny","reason_code":"write_target_out_of_grant","reason":"Write target is outside grant.filesystem.write."} +{"schema":1,"timestamp":"2026-09-02T21:01:51Z","session_id":"6a6c7f41-8f77-4406-baf2-532011f7d5e6","tool":"Write","surface":"filesystem.write","work_order":"governance/work-orders/WO-WW-017-post-release-truth-and-ci-reliability.md","decision":"deny","reason_code":"write_target_out_of_grant","reason":"Write target is outside grant.filesystem.write."} +{"schema":1,"timestamp":"2026-09-02T21:01:54Z","session_id":"6a6c7f41-8f77-4406-baf2-532011f7d5e6","tool":"Glob","surface":"filesystem.read","work_order":"governance/work-orders/WO-WW-017-post-release-truth-and-ci-reliability.md","decision":"deny","reason_code":"read_traversal_denied","reason":"Read traversal could reach a grant.filesystem.read.deny subtree."} +{"schema":1,"timestamp":"2026-09-02T21:03:04Z","session_id":"6a6c7f41-8f77-4406-baf2-532011f7d5e6","tool":"Grep","surface":"filesystem.read","work_order":"governance/work-orders/WO-WW-017-post-release-truth-and-ci-reliability.md","decision":"deny","reason_code":"read_traversal_denied","reason":"Read traversal could reach a grant.filesystem.read.deny subtree."} +{"schema":1,"timestamp":"2026-09-02T21:05:35Z","session_id":"6a6c7f41-8f77-4406-baf2-532011f7d5e6","tool":"Bash","surface":"shell.execute","work_order":"governance/work-orders/WO-WW-017-post-release-truth-and-ci-reliability.md","decision":"deny","reason_code":"control_plane_channel_uninspectable","reason":"Mutation-capable channel cannot prove protected control-plane targets remain unchanged."} +{"schema":1,"timestamp":"2026-09-02T21:05:40Z","session_id":"6a6c7f41-8f77-4406-baf2-532011f7d5e6","tool":"PowerShell","surface":"shell.execute","work_order":"governance/work-orders/WO-WW-017-post-release-truth-and-ci-reliability.md","decision":"deny","reason_code":"control_plane_channel_uninspectable","reason":"Mutation-capable channel cannot prove protected control-plane targets remain unchanged."} +{"schema":1,"timestamp":"2026-09-02T21:06:40Z","session_id":"6a6c7f41-8f77-4406-baf2-532011f7d5e6","tool":"Bash","surface":"shell.execute","work_order":"governance/work-orders/WO-WW-017-post-release-truth-and-ci-reliability.md","decision":"deny","reason_code":"control_plane_channel_uninspectable","reason":"Mutation-capable channel cannot prove protected control-plane targets remain unchanged."} +{"schema":1,"timestamp":"2026-09-03T00:33:42Z","session_id":"a00059e2-867d-473d-a3e0-4ba015b2ec43","tool":"Bash","surface":"shell.execute","work_order":"governance/work-orders/WO-WW-018-python-314-contention-test-race.md","decision":"deny","reason_code":"control_plane_channel_uninspectable","reason":"Mutation-capable channel cannot prove protected control-plane targets remain unchanged."} +{"schema":1,"timestamp":"2026-09-03T00:33:46Z","session_id":"a00059e2-867d-473d-a3e0-4ba015b2ec43","tool":"Glob","surface":"filesystem.read","work_order":"governance/work-orders/WO-WW-018-python-314-contention-test-race.md","decision":"deny","reason_code":"read_traversal_denied","reason":"Read traversal could reach a grant.filesystem.read.deny subtree."} +{"schema":1,"timestamp":"2026-09-03T00:33:46Z","session_id":"a00059e2-867d-473d-a3e0-4ba015b2ec43","tool":"Glob","surface":"filesystem.read","work_order":"governance/work-orders/WO-WW-018-python-314-contention-test-race.md","decision":"deny","reason_code":"read_traversal_denied","reason":"Read traversal could reach a grant.filesystem.read.deny subtree."} +{"schema":1,"timestamp":"2026-09-03T00:33:56Z","session_id":"a00059e2-867d-473d-a3e0-4ba015b2ec43","tool":"Write","surface":"filesystem.write","work_order":"governance/work-orders/WO-WW-018-python-314-contention-test-race.md","decision":"deny","reason_code":"write_target_out_of_grant","reason":"Write target is outside grant.filesystem.write."} diff --git a/governance/LOG.md b/governance/LOG.md index b35608b..8e1efa3 100644 --- a/governance/LOG.md +++ b/governance/LOG.md @@ -937,6 +937,39 @@ branch, PR, issue closure, merge, tag, or release occurred before acceptance. Issue #24 proceeds only through the separately authorized post-closeout PR and protected-CI merge; tagging and releasing `v0.9.3` remain unauthorized. +### Post-pilot WO-WW-017 completed record + +WO-WW-017 is post-pilot and does not add an eleventh metrics row or change the +accepted ten-order aggregate. The Owner accepted it on 2026-09-02 and reported +active minutes **NOT REPORTED**. + +Current install guidance now truthfully identifies published `v0.9.3`. The +obsolete former-identity distribution archive was retired from private +governed source at closeout. Windows privacy-profile replacement contention +now receives a bounded retry only for WinError 5, 32, or 33 while atomicity, +locking, link protection, and nondisclosure remain intact. Pull-request heads +now execute one complete CI matrix without also matching the push trigger; +direct-main and version-tag coverage, all three operating systems, all five +Python versions, and `CI required` remain. + +The complete Windows suite passed 752 tests with two skips. The native Ubuntu +affected set passed with one Windows-only skip. The final synchronized +contention regression passed 20/20 repetitions and fails against the pre-edit +implementation. Fresh review returned **ACCEPT — HIGH confidence** after two +rework cycles: first for a malformed issued baseline hash and timing-based +test, then for a staging-file signal that did not prove replacement had been +attempted. The accepted test observes a real failed `os.replace` and verifies +recovery through the production CLI without a production test hook. + +Accepted environment diagnostics are preserved in the report: a Windows 3.14 +host lacked the declared build backend, and Ubuntu's old system setuptools +could not parse the modern SPDX license expression. Neither diagnostic is +acceptance evidence and no package was installed. No out-of-grant mutation +succeeded. Public issues #18 and #19 remain open pending the authorized +post-closeout projection, review, and protected-CI pull request. The separate +External Pilot B lifecycle-classification defect is queued after that merge; +hllmr-site remains untouched. + --- ## Column definitions diff --git a/governance/PLAN.md b/governance/PLAN.md index e77ad1e..a470d98 100644 --- a/governance/PLAN.md +++ b/governance/PLAN.md @@ -690,3 +690,66 @@ minutes were **NOT REPORTED**. After ordinary closeout, repeat two projections and fresh publication review, open the issue #24 PR, and merge only after required CI passes. Tagging and releasing `v0.9.3` remain separate, unauthorized actions. + +## 26. Post-v0.9.3 release truth and CI reliability — 2026-09-02 + +The Owner confirms that public `main` and release tag `v0.9.3` are both +`e0cef360843dff38d6a02dd48be8f61b2d2d300e`, the GitHub release is public, +its complete CI run passed, public issue #24 is closed, and no public pull +request remains open. The post-release governed-source record and current +install guidance must now be reconciled with those observed facts. + +**WO-WW-017 — COMPLETE, accepted 2026-09-02: post-release truth and CI +reliability.** Current guidance now truthfully identifies published v0.9.3; +the obsolete former-identity `dist/plumbline-0.6.zip` (private governed-source reference, not present in this candidate) was retired at Owner closeout; +Windows privacy-profile replacement contention has a bounded classified retry; +and pull-request heads execute one complete matrix without duplicate push +jobs. Windows passed 752 tests with two skips, the native Ubuntu affected set +passed with one platform skip, and fresh review returned **ACCEPT — HIGH +confidence** after two correction cycles. Public issues #18 and #19 proceed +through the authorized post-closeout projection, review, and protected-CI PR. +No release or external-project mutation is authorized. + +## 27. CI recovery and onboarding correction sequence — 2026-09-02 + +The first protected-CI run for the accepted WO-WW-017 public projection passed +fourteen of fifteen jobs and exposed a Python 3.14 race in the Windows +contention-test harness. Public issue #27 records the failure. The Owner +authorized correction rather than an unexplained rerun. + +1. **WO-WW-018 — COMPLETE, accepted 2026-09-02: Python 3.14 + contention-test race.** The observation handshake now publishes atomically, + tolerates present-but-incomplete state within a bounded wait, and guarantees + helper reaping and stream closure without weakening real Windows contention + or product assertions. Native Windows Python 3.14 focused tests and 20 stress + iterations passed; a clean prospective tree passed 753 tests with two skips + and every repository gate. Fresh independent execution returned **ACCEPT + WITH NON-BLOCKING POLISH / high confidence**. Resume PR #26 only after the + complete required matrix passes. +2. **WO-WW-019 — External Pilot B lifecycle classification.** A clean external + pilot with draft/unratified adoption records was classified as retired + lockout. Require evidence of ratification, preserve clean/new and recovery + compatibility, and fail closed on contradictory records before that pilot + resumes. +3. **WO-WW-020 — Canonical project-root enforcement.** Generated repository and + external-Operator packets must name the discovered canonical repository root, + prohibit durable project artifacts in user/temp/bootstrap locations, and + distinguish external evidence staging from project records. Correct every + route that can otherwise create dual-repository or synchronization drift. +4. **WO-WW-021 — Conversation-first inception and existing-project continuity.** + Preserve the current CLI and lifecycle routes while adding a low-friction + discovery stage. For an existing project, begin with a read-only high-level + inventory of current documents, code, history, and recorded reasoning; + summarize the apparent project and ask whether to explore that work or start + elsewhere. Do not make the Owner re-enter facts the repository already + supports. For a new or unnamed idea, begin with one open invitation and let + adaptive discovery continue as long as useful. Before governance mechanics, + return a concise project sketch, recommended topology, and provisional first + backlog. Nothing in discovery is ratified authority; adoption and the first + executable work order begin only after one explicit promotion decision. + +The conversational path is not capped at three questions or any fixed turn +count. Fast first value is the target; useful inquiry may continue. Existing +`writwall start --project-root ...` automation and lifecycle-aware behavior +remain backward-compatible. The public on-ramp must make the simple path +obvious without removing the detailed manual and recovery routes. diff --git a/governance/STATE.md b/governance/STATE.md index ada4e07..7ec486b 100644 --- a/governance/STATE.md +++ b/governance/STATE.md @@ -22,8 +22,12 @@ identity correction, accepted WO-WW-012 installed bootstrap-bundle completeness correction, accepted WO-WW-013 post-closeout projection-reference truth, accepted WO-WW-014 public current-record host-path privacy, accepted WO-WW-015 terminal Architect handoff and lifecycle-aware start routing, and accepted -WO-WW-016 release identity 0.9.3. -Release `v0.9.2` is public. External Pilot A successfully adopted Writwall, +WO-WW-016 release identity 0.9.3, and accepted WO-WW-017 post-release truth +and CI reliability. No work order is active during the closeout publication +tail. +Release `v0.9.3` is public at commit +`e0cef360843dff38d6a02dd48be8f61b2d2d300e`; its complete CI run passed, +public issue #24 is closed, and no public pull request is open. External Pilot A successfully adopted Writwall, completed its channel-local Windows birth test, and closed two genuine work orders with no successful forbidden mutation. Public issue #24 records the product lesson that onboarding did not terminate in an explicit fresh Project- @@ -34,14 +38,16 @@ WO-WW-015 corrected those product interactions without reclassifying the pilot as a failure: clean/new retains intake and create-only bootstrap; later valid states route without target-byte changes; adoption closeout stops at the fresh Architect boundary; and Architect requests use progressive disclosure plus one -combined disposition/action gate. No external media content, website, DNS, or -mail mutation is active. +combined disposition/action gate. Public issues #18 and #19 remain open +pending the authorized WO-WW-017 public projection and PR. The obsolete `dist/plumbline-0.6.zip` (private governed-source reference, not present in this candidate) was retired at Owner closeout. No external media content, +website, DNS, or mail mutation is active. -**Derived:** 2026-09-01 from the ten accepted pilot records, the Doctrine 9.3.1 +**Derived:** 2026-09-02 from the ten accepted pilot records, the Doctrine 9.3.1 fresh-agent evaluation, ratified DR-002 and project-migration DR-003, and accepted WO-PL-017 through WO-PL-023 and WO-PL-025 through WO-PL-033 records, the WO-PL-024 sequencing recovery, the verified public-release events, the -accepted WO-WW-001 through WO-WW-016 closeout records. +accepted WO-WW-001 through WO-WW-017 closeout records, plus the observed +v0.9.3 publication. **Boundary:** post-adoption, all 10 counted pilot work orders and their evaluation complete; WO-PL-017 remediation complete; DR-003 ratified; WO-PL-018 through WO-PL-023 complete; WO-PL-024 void before implementation; @@ -53,12 +59,12 @@ the current identity with the two-line wall glyph; WO-PL-039 complete and accepted, with public PR #5 merged after the required CI passed and issue #4 closed; WO-PL-040 complete and accepted; public PR #8 merged and issue #1 closed; the historical `WO-PL` series ends at 040; **WO-WW-001 through -WO-WW-016 are COMPLETE and accepted**; no work order is active; public PR #9, -#12, #13, and #17 merged with protected CI green; public issue #14 records the -coordinator release gate; release `v0.9.2` is published; External Pilot A -adopted successfully and closed two genuine work orders; public issue #24 -records the terminal-Architect handoff defect. No external media content, -website, DNS, or mail mutation is active. +WO-WW-017 are COMPLETE and accepted**; **no work order is active**; public PR #9, +#12, #13, #17, and #21 merged with protected CI green; public issue #14 records +the coordinator release gate; release `v0.9.3` is published; External Pilot A +adopted successfully and closed two genuine work orders; public issue #24 is +closed; public issues #18 and #19 remain open. No external media content, +website, DNS, or mail mutation is active from this repository. The hash of the commit containing this file is intentionally recorded only externally. @@ -129,7 +135,9 @@ externally. | WO-WW-014 | **COMPLETE**, accepted 2026-09-01; the earlier current-use Plan reference is host-neutral and the projection checker rejects concrete Windows, macOS, Linux-home, and mounted-drive paths in current public records without echoing values. Windows passed 743 tests with two skips; Windows and Ubuntu projection suites each passed 68 tests; two 136-file candidates were projection/release-clean and byte-identical; corrected fresh review returned **ACCEPT — HIGH confidence**. Owner active minutes **NOT REPORTED**. The authorized public release and External Pilot A tail resume | | WO-WW-015 | **COMPLETE**, accepted 2026-09-01; lifecycle-aware `writwall start` now preserves clean/new intake while routing recovery, adopted/retired lockout, and active-work-order states to the correct fresh role with zero target-byte change. Adoption closes at an explicit fresh Project-Architect handoff using progressive disclosure and one combined approval/action gate. Windows passed 750 tests with two skips; native Ubuntu affected and installed-wheel gates passed; two 136-file candidates were checker-clean and byte-identical; fresh final re-review returned **ACCEPT — HIGH confidence**. Owner active minutes **NOT REPORTED**. Records retained in `governance/history/`; public issue #24 remains open pending separately authorized public projection/PR work | | WO-WW-016 | **COMPLETE**, accepted 2026-09-02; current package metadata, conditional install guidance, and executable release checks agree on `0.9.3` / `v0.9.3` without claiming the tag is published. Historical release facts remain unchanged. Windows passed 750 tests with two skips; native Ubuntu passed 17 release tests and the installed gate; two 136-file candidates were projection/release-clean and byte-identical; fresh review returned **ACCEPT — HIGH confidence**. Owner active minutes **NOT REPORTED**. Records retained in `governance/history/`; issue #24 proceeds through the authorized post-closeout public PR while tag and release remain unauthorized | -| Post-pilot sequence | **WO-PL-017 through WO-PL-023 COMPLETE**; WO-PL-024 **VOID BEFORE IMPLEMENTATION**; WO-PL-025 through WO-PL-040 **COMPLETE**; historical `WO-PL` identifiers end at 040; **WO-WW-001 through WO-WW-016 COMPLETE and accepted**; no work order is active; public PR #9, #12, #13, #17, and #21 merged with protected CI green; public issues #1, #4, #10, #11, #16, and #20 closed; public issue #14 records the accepted release gate; `v0.9.2` is published; `v0.9.3` is not yet tagged or released; External Pilot A adopted and closed two genuine work orders; issue #24 remains open pending the authorized public PR; website, DNS, and mail pilots remain queued | +| WO-WW-017 | **COMPLETE**, accepted 2026-09-02; published-release truth, bounded Windows privacy-profile replacement retry, and non-duplicating CI triggers are implemented. Windows passed 752 tests with two skips; the native Ubuntu affected set passed with one platform skip; fresh review returned **ACCEPT — HIGH confidence** after two rework cycles. Owner active minutes **NOT REPORTED**. The obsolete `dist/plumbline-0.6.zip` (private governed-source reference, not present in this candidate) was retired at closeout. Public issues #18 and #19 remain open pending the authorized public PR | +| WO-WW-018 | **COMPLETE**, accepted 2026-09-02; Python 3.14 contention-test signal publication and helper cleanup repaired without product-code change. Native Windows Python 3.14 focused tests and 20 stress iterations passed; a clean prospective tree passed 753 tests with two skips and all gates; independent public-clone review returned **ACCEPT WITH NON-BLOCKING POLISH / high confidence**. Owner active minutes **NOT REPORTED**. Public issue #27 and PR #26 proceed through protected CI | +| Post-pilot sequence | **WO-PL-017 through WO-PL-023 COMPLETE**; WO-PL-024 **VOID BEFORE IMPLEMENTATION**; WO-PL-025 through WO-PL-040 **COMPLETE**; historical `WO-PL` identifiers end at 040; **WO-WW-001 through WO-WW-018 COMPLETE and accepted**; no active work order; public PR #9, #12, #13, #17, and #21 merged with protected CI green; public issues #1, #4, #10, #11, #16, #20, and #24 closed; public issue #14 records the accepted release gate; `v0.9.3` is published; External Pilot A adopted and closed two genuine work orders; public issues #18, #19, and #27 remain open behind PR #26; lifecycle classification, canonical-root enforcement, and conversation-first onboarding are queued as WO-WW-019 through WO-WW-021; website and infrastructure pilots proceed under their own repositories and authority | | Bootstrap history | Eleven completed work orders retained as uncounted pre-adoption evidence under `archive/pre-adoption-bootstrap/` | ### Verification accepted at WO-PL-016 closeout @@ -971,14 +979,14 @@ it on 2026-08-28 and reported active minutes **NOT REPORTED**. | RFI-28 | **RESOLVED** at WO-PL-014 closeout under the Owner-approved parser-free design. Frontmatter is sole grant authority; B.4 is generated and unmatched B.3/B.4 paths block dispatch | | RFI-25 / 27 / 28 routing | The records remain separate but were implemented and disposed together by WO-PL-014; their bounded residuals remain visible in each record | | RFI-03 / licensing | **RESOLVED by DR-003, 2026-08-20.** License map selected; mechanization and publication remain separate gates | -| Active work order | None; intentional between-work-order lockout | -| Queued work | No successor work order. The accepted external Writwall cutover packet remains pending a separate Owner authorization | +| Active work order | None | +| Queued work | Complete protected CI and merge PR #26; then WO-WW-019 lifecycle classification, WO-WW-020 canonical-root enforcement, and WO-WW-021 conversation-first inception/existing-project continuity; private pilots retain their own authority | | WO-PL-010 follow-up | **Complete.** The three adoption-recorder consistency findings from WO-PL-009 are closed | | Second-project boundary | Each adopting project maintains its own adoption and product state. No second-project source, private benchmark material, proprietary design detail, or trade-secret material is imported into Plumbline by this closeout | | Published / tagged / licensed | **Yes**: clean-history public repository `HLLMR/plumbline`, release tag `v0.8`; DR-003 path-based license map remains operative | | Push | WO-PL-034 private and public updates authorized; remote commit identities are recorded after the push completes | | Repository visibility | Private governed source remains private; clean-history `HLLMR/plumbline` is public | -| Stage | **Plumbline 0.8 remains the historical public release; Writwall migration is accepted in governed source; Tuesday promotion remains frozen pending the separately authorized external cutover** | +| Stage | **Writwall v0.9.3 is public; WO-WW-018 is accepted and closed; PR #26 awaits a complete green CI matrix; hllmr-site remains frozen pending WO-WW-019** | --- diff --git a/identity/legacy-references.json b/identity/legacy-references.json index 4acba2b..76859e6 100644 --- a/identity/legacy-references.json +++ b/identity/legacy-references.json @@ -16,7 +16,7 @@ { "path": "README.md", "context": "migration_provenance", - "sha256": "2bef9b65ca9ff3aec8dc8149f185f337c7f0e4d71c79c62661f37f9c1a543c82" + "sha256": "d05596604edc06e5ac5c2502ecd61b945e0caa41fe63a39de66a3d58fa2e1e2b" }, { "path": "SELF-HOSTING.md", @@ -94,19 +94,19 @@ { "path": "governance/LOG.md", "context": "historical_pilot_summary", - "sha256": "8f1ae9b4f005a31eed74e9f68429fed33fc6ffed2bd31e05de59327d4f9db220", + "sha256": "8a27c2cda1dbbb3d38ca03f1745352abb0ab07290d691dd4f063d3e274da425f", "projection_transform": "private_evidence_redaction" }, { "path": "governance/PLAN.md", "context": "ratified_historical_intent", - "sha256": "3b5645777ed304ce7205fbd797323320fd10ddd421bf4b9562c5bd3c28b4df9f" + "sha256": "0a1cfae5dcd8d475a599fff8bb8c07c745f4baae63adb8def5ddbcad6cfb13ea" }, { "path": "governance/STATE.md", "context": "mixed_current_state_and_history", - "sha256": "4939f44b509ce43e356f55d40f7ec506e29f3fb0a236096b8353729f59f68e3c", - "projection_sha256": "abd6676fd83bb1e7a480048ffc3e717fe9184a41e5c887ef223c40d3bed113a1" + "sha256": "87ed1be87ddf391439baddcb2a1aef588387e813a3e42dc05e297384da806f0c", + "projection_sha256": "4ad60876ac2ff78f8eb212e0c4b54a42dd5c1131780a2b1add58f9367bcd0ee7" }, { "path": "governance/decisions/DR-001.md", @@ -127,7 +127,7 @@ { "path": "tests/test_distribution.py", "context": "historical_evidence_fixture", - "sha256": "e5e6df9ead5effa20ee48167f070aa43eb8716e4df66fd997df65d6c2edc7c69" + "sha256": "6483f84819c08284b989252f4a40a42e8eca64fec5fda303cec62350c19328d0" }, { "path": "tests/test_identity_migration.py", diff --git a/scripts/privacy_screen.py b/scripts/privacy_screen.py index 8e2eaa5..28dc7a1 100644 --- a/scripts/privacy_screen.py +++ b/scripts/privacy_screen.py @@ -169,6 +169,28 @@ def _locked_profile(path: Path): os.close(descriptor) +_WINDOWS_REPLACE_CONTENTION_WINERRORS = frozenset({5, 32, 33}) +_WINDOWS_REPLACE_RETRY_DEADLINE_SECONDS = 2.0 +_WINDOWS_REPLACE_RETRY_INTERVAL_SECONDS = 0.05 + + +def _replace_with_windows_contention_retry(temporary: Path, path: Path) -> None: + if sys.platform != "win32": + os.replace(temporary, path) + return + deadline = time.monotonic() + _WINDOWS_REPLACE_RETRY_DEADLINE_SECONDS + while True: + try: + os.replace(temporary, path) + return + except OSError as exc: + if getattr(exc, "winerror", None) not in _WINDOWS_REPLACE_CONTENTION_WINERRORS: + raise + if time.monotonic() >= deadline: + raise + time.sleep(_WINDOWS_REPLACE_RETRY_INTERVAL_SECONDS) + + def _write_patterns(path: Path, patterns: list[str]) -> None: _assert_managed_components(path) temporary = path.with_name(f".{PROFILE_NAME}.{uuid.uuid4().hex}.tmp") @@ -181,7 +203,7 @@ def _write_patterns(path: Path, patterns: list[str]) -> None: os.fsync(stream.fileno()) if os.name != "nt": temporary.chmod(0o600) - os.replace(temporary, path) + _replace_with_windows_contention_retry(temporary, path) except OSError as exc: raise PrivacyScreenError("privacy screen could not be written") from exc finally: diff --git a/tests/test_coordinator_release.py b/tests/test_coordinator_release.py index fc4d4ef..6fde034 100644 --- a/tests/test_coordinator_release.py +++ b/tests/test_coordinator_release.py @@ -304,8 +304,12 @@ def test_release_identity_and_public_payload_are_coherent(self): self.assertIn("--expected-tag v0.9.3", publication) self.assertIn("--expected-tag v0.9.3", contributing) for document in (readme, adopting, start): - self.assertIn("not yet published", document) - self.assertIn("After", document) + self.assertNotIn("not yet published", document) + self.assertIn( + 'python -m pip install ' + '"https://github.com/HLLMR/writwall/archive/refs/tags/v0.9.3.zip"', + document, + ) self.assertIn("Release `v0.9.0` first introduced", start) self.assertIn("Release `v0.9.1` corrected", start) self.assertIn("Release `v0.9.2` corrects", start) diff --git a/tests/test_distribution.py b/tests/test_distribution.py index 41ffe22..c900aa2 100644 --- a/tests/test_distribution.py +++ b/tests/test_distribution.py @@ -331,6 +331,29 @@ def test_ci_provisions_declared_build_requirements_before_tests(self): with self.subTest(requirement=requirement): self.assertIn(f'"{requirement}"', provisioning) + def test_pull_request_heads_do_not_duplicate_the_push_matrix(self): + workflow = (self.repo / ".github" / "workflows" / "ci.yml").read_text( + encoding="utf-8" + ) + on_block_match = re.search(r"(?ms)^on:\n(.*?)\n(?=\S)", workflow) + self.assertIsNotNone(on_block_match, "workflow 'on:' block is missing") + on_block = on_block_match.group(1) + self.assertIn("push:", on_block) + self.assertIn("pull_request:", on_block) + push_index = on_block.index("push:") + pull_request_index = on_block.index("pull_request:") + self.assertLess(push_index, pull_request_index) + push_block = on_block[push_index:pull_request_index] + pull_request_block = on_block[pull_request_index:] + # A push-event filter narrowed to main and release tags means an + # ordinary feature-branch push, including the one behind a pull + # request, no longer independently triggers the push matrix; only + # the unrestricted pull_request trigger runs it for that head. + self.assertIn("branches: [main]", push_block) + self.assertIn('tags: ["v*"]', push_block) + self.assertNotIn("branches:", pull_request_block) + self.assertNotIn("tags:", pull_request_block) + class CurrentDocumentationSynchronizationTests(unittest.TestCase): def test_adapter_readme_lists_every_reason_code_and_surface(self): diff --git a/tests/test_privacy_screen.py b/tests/test_privacy_screen.py index ac3a0d7..4d4eb7e 100644 --- a/tests/test_privacy_screen.py +++ b/tests/test_privacy_screen.py @@ -8,6 +8,7 @@ import subprocess import sys import tempfile +import time import unittest from pathlib import Path @@ -235,6 +236,153 @@ def test_concurrent_additions_are_serialized_without_lost_updates(self) -> None: for identifier in identifiers: self.assertIn(identifier, stored) + def _reap_helper(self, process: subprocess.Popen[str]) -> None: + """Guarantee the helper process is terminated, reaped, and closed. + + Idempotent, so it is safe both as an immediate call on the timeout + path and as a deferred ``addCleanup`` safety net on every other + path (exception, assertion failure, or ordinary success where the + process already exited). + """ + if process.poll() is None: + process.terminate() + try: + process.wait(timeout=5) + except subprocess.TimeoutExpired: + process.kill() + process.wait(timeout=5) + else: + process.wait(timeout=5) + for stream in (process.stdin, process.stdout, process.stderr): + if stream is not None and not stream.closed: + stream.close() + + def _observe_contention_signal( + self, process: subprocess.Popen[str], signal: Path, timeout: float = 10 + ) -> int | None: + """Wait up to ``timeout`` seconds for a complete, parseable signal. + + A present-but-empty or otherwise unparseable signal is treated as + not-yet-published rather than raised, so a partially observed write + can never crash the parse; the wait is always bounded regardless of + whether a valid signal ever appears. If the deadline elapses without + the helper exiting on its own or publishing a valid signal, the + helper is terminated and reaped here before returning, so a + never-resolving wait can never leak it. On every other return path + the helper is left running for the caller to await naturally (for + example while it retries and finishes after a contended handle is + released). + """ + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + if signal.is_file(): + content = signal.read_text(encoding="ascii") + if content: + try: + return int(content) + except ValueError: + pass + if process.poll() is not None: + return None + time.sleep(0.01) + self._reap_helper(process) + return None + + def test_signal_race_present_but_incomplete_does_not_leak_helper(self) -> None: + signal = self.temp / "race-signal.txt" + process = subprocess.Popen( + [sys.executable, "-B", "-c", "import sys; sys.stdin.read()"], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + text=True, + ) + self.addCleanup(self._reap_helper, process) + # Present but never completed: reproduces the observed race + # deterministically, without depending on real filesystem timing. + signal.write_bytes(b"") + + self._observe_contention_signal(process, signal, timeout=1) + + self.assertIsNotNone( + process.poll(), + "a present-but-incomplete completion signal must not leak the " + "helper process", + ) + + @unittest.skipUnless( + sys.platform == "win32", "Windows atomic-replacement contention regression" + ) + def test_windows_replacement_contention_retries_until_handle_releases(self) -> None: + import ctypes + + initialized = self.run_cli( + "privacy", "init", "--project-root", str(self.project) + ) + self.assertEqual(initialized.returncode, 0, initialized.stderr) + profile = next(self.state.rglob("private-patterns.txt")) + + generic_read = 0x80000000 + file_share_read = 0x00000001 + file_share_write = 0x00000002 + open_existing = 3 + file_attribute_normal = 0x80 + invalid_handle_value = ctypes.c_void_p(-1).value + create_file = ctypes.windll.kernel32.CreateFileW + create_file.restype = ctypes.c_void_p + # Deny delete sharing only, reproducing real Windows replacement + # contention (for example from an indexer or antivirus scanner) + # without also blocking ordinary readers or writers. + handle = create_file( + str(profile), generic_read, file_share_read | file_share_write, + None, open_existing, file_attribute_normal, None, + ) + self.assertNotEqual(handle, invalid_handle_value, ctypes.WinError()) + + signal = self.temp / "replace-contention-observed.txt" + instrumented_cli = ( + "from pathlib import Path\n" + "from scripts import privacy_screen\n" + f"signal = Path({str(signal)!r})\n" + "real_replace = privacy_screen.os.replace\n" + "def observed_replace(source, target):\n" + " try:\n" + " return real_replace(source, target)\n" + " except OSError as exc:\n" + " content = str(getattr(exc, 'winerror', ''))\n" + " staging = signal.with_name(signal.name + '.tmp')\n" + " staging.write_text(content, encoding='ascii')\n" + " real_replace(staging, signal)\n" + " raise\n" + "privacy_screen.os.replace = observed_replace\n" + "from writwall_cli.__main__ import main\n" + f"raise SystemExit(main(['privacy', 'add', '--project-root', " + f"{str(self.project)!r}, '--identifier-stdin', " + "'--confirm-no-secrets']))\n" + ) + process = subprocess.Popen( + [sys.executable, "-B", "-c", instrumented_cli], + cwd=REPO_ROOT, env=self.managed_environment(), stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, + ) + self.addCleanup(self._reap_helper, process) + assert process.stdin is not None + process.stdin.write("PRIVATE-CONTENTION-MARKER\n") + process.stdin.close() + try: + contention_winerror = self._observe_contention_signal( + process, signal, timeout=10 + ) + finally: + ctypes.windll.kernel32.CloseHandle(handle) + + stdout, stderr = process.communicate(timeout=30) + self.assertIn( + contention_winerror, + {5, 32, 33}, + "privacy add did not encounter classified replacement contention", + ) + self.assertEqual(process.returncode, 0, stdout + stderr) + self.assertRegex(stdout, r"privacy screen: ready \([1-9][0-9]* entries\)") + if __name__ == "__main__": unittest.main()