diff --git a/docs/workflow/develop-workflow-record.md b/docs/workflow/develop-workflow-record.md index e0da76d..43cd536 100644 --- a/docs/workflow/develop-workflow-record.md +++ b/docs/workflow/develop-workflow-record.md @@ -3,8 +3,8 @@ ## Status - Status: active -- Current phase: approved cooperative-lock contract revision -- Next safe action: document the cooperative serialization boundary, use `lstat` for best-effort replacement detection, correct the regression timing, then reverify and review. +- Current phase: checkpoint simplification +- Next safe action: remove the adversarial replacement guard/tests, retain practical cooperative `wx` serialization, then run verification and one final review. ## Request and scope @@ -53,7 +53,7 @@ Owned paths: - `skills/develop/develop-workflow/scripts/checkpoint-record.mjs` - `skills/develop/develop-workflow/tests/checkpoint-record.test.mjs` -Implement a Node 22 ESM helper with an exported injectable API and a strict CLI. Validate one H1 and the ten required H2 sections used by this record. For creation, require an absent destination; for replacement, require the current SHA-256 digest. Acquire a fixed exclusive per-record lock among cooperating helper invocations, re-read and hash under that lock, write a unique same-directory mode-0600 temporary file, flush it, close it, atomically rename it, and flush the containing directory. Preserve unrelated stale temporary files for recovery and fail closed on a pre-existing lock. Cleanup invocation-created paths without masking the primary failure. External mutation of lock pathnames is outside the serialization boundary; use `lstat` as best-effort detection and preserve replacements visible before unlink, without claiming atomic defense against concurrent out-of-protocol mutation. +Implement a Node 22 ESM helper with an exported injectable API and a strict CLI. Validate one H1 and the ten required H2 sections used by this record. For creation, require an absent destination; for replacement, require the current SHA-256 digest. Acquire a fixed exclusive per-record lock among cooperating helper invocations, re-read and hash under that lock, write a unique same-directory mode-0600 temporary file, flush it, close it, atomically rename it, and flush the containing directory. Preserve unrelated stale temporary files for recovery and fail closed on a pre-existing lock. Cleanup invocation-created paths without masking the primary failure. External lock-path mutation is outside the cooperative serialization boundary. Cover valid create/replace, missing/malformed/duplicate sections, replacement without a digest, stale digest, concurrent writers, interrupted write/flush, rename failure, directory-flush failure, stale temporary artifacts, stale lock, and cleanup behavior that preserves the last valid target byte-for-byte. @@ -202,7 +202,8 @@ Before integration, abandon only by preserving evidence and obtaining cleanup ap - Exceptional remediation standards reviewer: `develop-workflow-exception-standards` / `precedent-locator` / child `f28de7de` / session `01a06ceb-bd79-7050-86d5-693b50a01fe7`; digest confirmed; CHANGES REQUESTED. - Exceptional remediation specification reviewer: `develop-workflow-exception-spec` / `claim-verifier` / child `4d059ea9` / session `01a06ceb-eace-7afb-afdd-df094bb66f6a`; digest confirmed; CHANGES REQUESTED. - Remaining medium finding: `stat(lock)` followed by `unlink(lock)` is still a check-then-act race, and `stat` follows symlinks. An external replacement in that gap could be deleted. The regression replaced the lock after closing the original handle and did not model the exact scenario. -- Approved architecture revision: the user selected a cooperative lock contract. Conforming helper invocations serialize through exclusive `wx` acquisition and never replace an existing lock. Concurrent out-of-protocol pathname mutation is not a supported safety boundary. `lstat` remains a best-effort guard for replacements observable before cleanup. +- Approved architecture revision: the user selected a cooperative lock contract. Conforming helper invocations serialize through exclusive `wx` acquisition and never replace an existing lock. Concurrent out-of-protocol pathname mutation is not a supported safety boundary. +- Simplification decision: the user directed the parent to remove the disproportionate adversarial lock machinery and move on. Keep only practical cooperative lock behavior and its existing concurrency/stale-lock tests. - This review-brief checkpoint is necessarily a metadata-only commit after the pinned product HEAD because a record cannot contain the digest of bytes that include its own digest. Prove it touches only this record. ## Integration and rollback @@ -236,5 +237,5 @@ Rebase the feature branch onto the latest remote/local `main` when available, re - Review result: both axes rejected the remediation because identity verification and pathname deletion are not atomic; reviewers remained read-only with unchanged clean state. - Architecture constraint: another conforming helper invocation cannot replace an existing lock because acquisition uses `open(..., "wx")`; the disputed race requires out-of-protocol filesystem mutation. Portable Node filesystem APIs provide no atomic compare-and-delete primitive for defending a path lock against that mutation. - Architecture decision: the user approved narrowing the contract to cooperative helper invocations rather than broadening Slice 1–2 with a broker or platform-specific native primitive. -- Approved follow-up: replace path `stat` with `lstat`, make the replacement test mutate the pathname while the original handle is open, synchronize documentation, reverify, and obtain fresh review. -- Next safe action: commit this revised plan gate before dependent production mutation. +- Approved follow-up: remove inode/device identity tracking and adversarial replacement tests, retain exclusive `wx` acquisition plus ordinary owned-lock cleanup, reverify once, and complete final review/integration without further hardening scope. +- Next safe action: commit this simplification gate before dependent production mutation.