From 7535c0865ec67fd6f3978872bbc695734dafee84 Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Wed, 21 Oct 2026 08:54:01 +0000 Subject: [PATCH 1/7] docs(memory-bank): record that #129 and #130 are merged The maintainer merged the tests-only round (#129, 2026-10-21 08:24Z) and the Memory Bank (#130, 08:47Z); master is d0cb57c. The new tests gave the same counts on the runner in three CI runs (the first PR head, the second PR head, and master after #129). The notes no longer list the merge as open. What is open before the stable pull request is the decision on #34 (2026-11-02), the check of the PSGALLERY_API_KEY, and the decision on the open items, among them the 10 rows (7 MaintainerDecision, 3 would-pin) that wait for the maintainer. last-verified moves to 2026-10-21 in the three files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- .memory-bank/activeContext.md | 40 +++++++++---------- .../0021-quality-gate-before-5.0.0.md | 16 ++++---- .memory-bank/progress.md | 29 +++++++------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/.memory-bank/activeContext.md b/.memory-bank/activeContext.md index 68e60ee..9b9d9e0 100644 --- a/.memory-bank/activeContext.md +++ b/.memory-bank/activeContext.md @@ -1,6 +1,6 @@ --- status: current -last-verified: 2026-10-20 +last-verified: 2026-10-21 owner: active-agent source: current task evidence --- @@ -21,15 +21,16 @@ six machine classes, the first lab 245/0/1 per edition, every end state CLEAN (record `Tests/Lab/Acceptance-2026-10-20-published-rc8.md`, #128). The boundary of the new error, a computer name of 32,718 characters, holds on Server 2019, 2022, 2025, and Windows 11 26H1. He merged the record, #128, on 2026-10-21 at -05:48Z (`master` `461015e`, CI green). The tests-only round for the plain gaps -ran on 2026-10-20 (Next step 6) and is #129, with this Memory Bank in #130; -their CI is green, and the runner's counts equal the local run in each test -file. Open before the stable pull request: the merge of both, the maintainer's -decision on #34 on 2026-11-02 (no reply to his follow-up of 2026-10-19), and -his check of `PSGALLERY_API_KEY`. The stable build is new bytes that no lab -ran; the procedure accepts the last prerelease, so the stable change touches -only the label, the CHANGELOG, and `$publishedVersions`. Any other product -change needs rc9 and the same acceptance (about 70 minutes with the script). +05:48Z, the tests-only round for the plain gaps (#129, 08:24Z; Next step 6), +and this Memory Bank (#130, 08:47Z); `master` is `d0cb57c`. The new tests gave +the same counts on the runner in three CI runs, equal to the local run in each +test file. Open before the stable pull request: the maintainer's decision +on #34 on 2026-11-02 (no reply to his follow-up of 2026-10-19), his check of +`PSGALLERY_API_KEY`, and his decision on the open items (Next steps 3 and 6). +The stable build is new bytes that no lab ran; the procedure accepts the last +prerelease, so the stable change touches only the label, the CHANGELOG, and +`$publishedVersions`. Any other product change needs rc9 and the same +acceptance (about 70 minutes with the script). State at 2026-10-10: the maintainer integrated the release-gate stack into `master` (#116, #120, #118, #119, #121; `fa0701b`, CI green; GitHub closed #117 @@ -185,14 +186,13 @@ Decisions 22 and 24 on 2026-10-19 and decides 23 on 2026-11-02. 21): the hard-link names under another root stay a known limit; the pages and the CHANGELOG say so since rc8. The tests-only round for the plain items (68 `budget` mentions) ran on 2026-10-20: four implementers, one - `ParameterSets.*` file each, integrated on `ai/tests-round-1` (#129): 89 `It` - blocks, 121 cases, the suite 1,494 to 1,615 per configuration, 0 failed; - 38 of 64 sets closed, 26 with a leftover (16 Limit, 7 MaintainerDecision, 3 - would-pin), no defect; report - `Tests/Coverage/Quality-Gate-Test-Round-2026-10-20.md`. On the runner (CI run - `39551726767`) the counts equal the local run in each test file. No plain - gap is left. A defect that a test finds needs his decision and rc9. Still - his: the 7 MaintainerDecision and 3 would-pin rows, the silent default scope - for a piped `AppliesTo` that PowerShell cannot convert (a design change), the - 8 getters of pipeline parameters, and the audit paths. + `ParameterSets.*` file each, merged as #129: 89 `It` blocks, 121 cases, the + suite 1,494 to 1,615 per configuration, 0 failed; 38 of 64 sets closed, 26 + with a leftover (16 Limit, 7 MaintainerDecision, 3 would-pin), no defect; + report `Tests/Coverage/Quality-Gate-Test-Round-2026-10-20.md`. The runner's + counts equal the local run in three CI runs. No plain gap is left. A defect + that a test finds needs his decision and rc9. Still his: the 7 + MaintainerDecision and 3 would-pin rows, the silent default scope for a + piped `AppliesTo` that PowerShell cannot convert (a design change), the 8 + getters of pipeline parameters, and the audit paths. 7. Do not release stable 5.0.0 or equate a percentage with gate closure. diff --git a/.memory-bank/decisions/0021-quality-gate-before-5.0.0.md b/.memory-bank/decisions/0021-quality-gate-before-5.0.0.md index ce4a81d..7557762 100644 --- a/.memory-bank/decisions/0021-quality-gate-before-5.0.0.md +++ b/.memory-bank/decisions/0021-quality-gate-before-5.0.0.md @@ -1,7 +1,7 @@ --- status: accepted date: 2026-10-08 -last-verified: 2026-10-20 +last-verified: 2026-10-21 owner: shared source: maintainer decision of 2026-10-08; closing choices of 2026-10-19; status of 2026-10-20 --- @@ -83,10 +83,10 @@ tests-only round ran the same afternoon (report `Tests/Coverage/Quality-Gate-Test-Round-2026-10-20.md`): 89 `It` blocks, 121 cases, the suite 1,494 to 1,615 per configuration with no failure, 38 of 64 parameter sets closed, 26 with a leftover (16 Limit, 7 MaintainerDecision, 3 -would-pin), no defect. It is #129; on the runner the counts equal the local -run in each test file. No plain gap is left. Open are the merge of #129, the -10 rows that wait for his decision (7 MaintainerDecision, 3 would-pin), #34 -(2026-11-02), and the key check. The stable build is new bytes: the stable -change may touch only the -label, the CHANGELOG, and `$publishedVersions`; any other product change needs -rc9 and the same acceptance. +would-pin), no defect. It is #129 (merged 2026-10-21); on the runner the +counts equal the local run in each test file. No plain gap is left. Open are +the 10 rows that wait for his decision (7 MaintainerDecision, 3 would-pin), +the decision on #34 (2026-11-02), and the key check. The stable build is new +bytes: the stable change may touch only the label, the CHANGELOG, and +`$publishedVersions`; any other product change needs rc9 and the same +acceptance. diff --git a/.memory-bank/progress.md b/.memory-bank/progress.md index 1d10c51..3baabd1 100644 --- a/.memory-bank/progress.md +++ b/.memory-bank/progress.md @@ -1,6 +1,6 @@ --- status: current -last-verified: 2026-10-20 +last-verified: 2026-10-21 owner: active-agent source: repository and validation evidence --- @@ -16,9 +16,10 @@ into `master` (CI green; the milestones have the details). On 2026-10-19 he merged #125 (Handoff 5) and #124 (Dependabot) and decided the path to stable (Decision 21, "Closing the gate"); on 2026-10-20 he merged #126 (the decisions) and #127 (the rc8 fix and label) and tagged rc8; on 2026-10-21 he merged #128 -(the rc8 record). The published rc7 and rc8 passed their lab acceptance in the -matrix and in the first lab. Stable Gallery version: 4.2.6. -After 5.0.0, archive in favor of WindowsAccessControl (Decision 18). +(the rc8 record), #129 (tests), and #130 (this file). The published rc7 and +rc8 passed their lab acceptance in the matrix and in the first lab. Stable +Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl +(Decision 18). ## Recent milestones @@ -129,13 +130,13 @@ After 5.0.0, archive in favor of WindowsAccessControl (Decision 18). of 32,718 characters). Record `Tests/Lab/Acceptance-2026-10-20-published-rc8.md` (#128). - 2026-10-20: tests-only round (Decision 21). Four implementers, one - `ParameterSets.*` test file each; integrated on `ai/tests-round-1` (#129): - 89 `It` blocks, 121 cases, the suite 1,494 to 1,615 per configuration, 0 - failed in four configurations; 38 of 64 sets closed (7 before), 26 with a - leftover (16 Limit, 7 MaintainerDecision, 3 would-pin); no defect. Report: - `Tests/Coverage/Quality-Gate-Test-Round-2026-10-20.md`. On 2026-10-21 the - CI of #129 and #130 passed; the runner's counts equal the local run in each - test file (run `39551726767`). + `ParameterSets.*` test file each (#129): 89 `It` blocks, 121 cases, the + suite 1,494 to 1,615 per configuration, 0 failed in four configurations; 38 + of 64 sets closed (7 before), 26 with a leftover (16 Limit, 7 + MaintainerDecision, 3 would-pin); no defect. Report: + `Tests/Coverage/Quality-Gate-Test-Round-2026-10-20.md`. On 2026-10-21 he + merged #129 (08:24Z) and #130 (08:47Z); the runner gave the local counts in + three CI runs (`39551726767` and two more). ## Stable capabilities @@ -150,9 +151,9 @@ After 5.0.0, archive in favor of WindowsAccessControl (Decision 18). 1. Decision 21 gate: the published rc7 and rc8 are accepted in the matrix and the first lab (records); stable follows rc8 (Decision 21, "Closing the - gate"). Do not release 5.0.0 until the other gates close: the merge of #129 - and #130 (no plain gap is left), #34 on 2026-11-02, and the key check. - Release steps: + gate"). Do not release 5.0.0 until the other gates close: the decision on + #34 on 2026-11-02, the key check, and the decision on the open items (no + plain test gap is left). Release steps: `Docs/Contributing/05-Releasing.md`; remove the prerelease label, date `[5.0.0]`, add the last prerelease (rc8) to `$publishedVersions` (never the version of the manifest), tag through CI. From f31c1c24652471e6014fccb6fa6e9b1dff009847 Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Wed, 21 Oct 2026 10:37:22 +0000 Subject: [PATCH 2/7] docs(memory-bank): record Decision 27, the scope of rc9 before 5.0.0 A probe on the published rc8 found that a piped optional enum parameter silently ignores a value that PowerShell cannot convert: a typo for Deny in AccessType creates an Allow entry, AuditFlags, the flags, and AppliesTo fall back to their defaults, and Get-FileHash2 runs SHA256. Named calls fail loudly. The maintainer decided on 2026-10-21 that rc9 fixes the family in the four access and audit cmdlets, changes the items 3 to 7 of the sheet, and gets an independent review. Decision 27 holds the probes, the options, the designs that five read-only research threads proposed, and the recommended defaults. The lab suite run of the new tests (24 runs on six machine classes, 0 failed) is recorded as the agent's flagged assumption. activeContext and progress follow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- .memory-bank/activeContext.md | 37 +++-- .../decisions/0027-open-items-before-5.0.0.md | 143 ++++++++++++++++++ .memory-bank/progress.md | 29 ++-- 3 files changed, 175 insertions(+), 34 deletions(-) create mode 100644 .memory-bank/decisions/0027-open-items-before-5.0.0.md diff --git a/.memory-bank/activeContext.md b/.memory-bank/activeContext.md index 9b9d9e0..574a9a8 100644 --- a/.memory-bank/activeContext.md +++ b/.memory-bank/activeContext.md @@ -23,14 +23,14 @@ of the new error, a computer name of 32,718 characters, holds on Server 2019, 2022, 2025, and Windows 11 26H1. He merged the record, #128, on 2026-10-21 at 05:48Z, the tests-only round for the plain gaps (#129, 08:24Z; Next step 6), and this Memory Bank (#130, 08:47Z); `master` is `d0cb57c`. The new tests gave -the same counts on the runner in three CI runs, equal to the local run in each -test file. Open before the stable pull request: the maintainer's decision -on #34 on 2026-11-02 (no reply to his follow-up of 2026-10-19), his check of -`PSGALLERY_API_KEY`, and his decision on the open items (Next steps 3 and 6). -The stable build is new bytes that no lab ran; the procedure accepts the last -prerelease, so the stable change touches only the label, the CHANGELOG, and -`$publishedVersions`. Any other product change needs rc9 and the same -acceptance (about 70 minutes with the script). +the same counts on the runner (three CI runs) and on six machine classes of the +labs (24 runs, 0 failed). A probe found that a typo in a piped `AccessType` +silently creates an Allow entry. He decided (Decision 27): rc9 fixes that +family and the items 3 to 7 of its sheet, with a review. Open before the +stable pull request: rc9 (designs, tests, review, acceptance of about 70 +minutes), his decision on #34 on 2026-11-02, and his check of +`PSGALLERY_API_KEY`. The stable change then touches only the label, the +CHANGELOG, and `$publishedVersions`. State at 2026-10-10: the maintainer integrated the release-gate stack into `master` (#116, #120, #118, #119, #121; `fa0701b`, CI green; GitHub closed #117 @@ -164,11 +164,10 @@ Decisions 22 and 24 on 2026-10-19 and decides 23 on 2026-11-02. `[Unreleased]` and the links, and `5.0.0-rc8` in `$publishedVersions` (the list ends at rc7 now). The maintainer checks the expiry of `PSGALLERY_API_KEY` first, merges, and tags. Every release step is his. -3. He decides the other open items of the paths report: `FileSecurity` - conversions, `RemoveAll` account filters, lazy path overloads, abandoned - `PrivilegeEnabler`, dot patterns of `Get-ChildItem2 -Filter`, the 17 - owner-restore handlers without the later-command check, unused classes - (Decisions 21/22). Decisions 22 and 24 are accepted (2026-10-19). +3. Decision 27 (2026-10-21): rc9 changes the library-only items, the dot + patterns of `Get-ChildItem2 -Filter`, the 17 owner-restore handlers, the + errors of the descriptor sets, and three inconsistencies; designs are being + researched. Decisions 22 and 24 are accepted (2026-10-19). 4. #34 waits for a tester until 2026-11-02 (Decision 23, option 3; the follow-up went up on 2026-10-19, no reply yet; checklist: `Tests/Lab/Non-Windows-File-Server-Test.md`). On that date the maintainer @@ -180,8 +179,8 @@ Decisions 22 and 24 on 2026-10-19 and decides 23 on 2026-11-02. only with a result. He still decides the other: the ACL of the stage folders under `C:\` in the lab kit (they inherit Authenticated Users: Modify; protecting them is a design change of the controller and needs a new - acceptance). The help could also say that a local standard user who asks - about a domain account still gets "Access is denied". + acceptance). rc9 adds to the help that a local standard user who asks about + a domain account still gets "Access is denied" (Decision 27). 6. Handoff 5 is done and merged (Evidence). Decided on 2026-10-19 (Decision 21): the hard-link names under another root stay a known limit; the pages and the CHANGELOG say so since rc8. The tests-only round for the plain items @@ -191,8 +190,8 @@ Decisions 22 and 24 on 2026-10-19 and decides 23 on 2026-11-02. with a leftover (16 Limit, 7 MaintainerDecision, 3 would-pin), no defect; report `Tests/Coverage/Quality-Gate-Test-Round-2026-10-20.md`. The runner's counts equal the local run in three CI runs. No plain gap is left. A defect - that a test finds needs his decision and rc9. Still his: the 7 - MaintainerDecision and 3 would-pin rows, the silent default scope for a - piped `AppliesTo` that PowerShell cannot convert (a design change), the 8 - getters of pipeline parameters, and the audit paths. + that a test finds needs his decision and rc9. Decision 27 settles the rest: + rc9 fixes the 10 rows and the piped optional parameters (designs to + follow); the audit paths over SMB are accepted (#34); the tests for the 8 + getters follow rc9. 7. Do not release stable 5.0.0 or equate a percentage with gate closure. diff --git a/.memory-bank/decisions/0027-open-items-before-5.0.0.md b/.memory-bank/decisions/0027-open-items-before-5.0.0.md new file mode 100644 index 0000000..8e94c6d --- /dev/null +++ b/.memory-bank/decisions/0027-open-items-before-5.0.0.md @@ -0,0 +1,143 @@ +--- +status: accepted +date: 2026-10-21 +last-verified: 2026-10-21 +owner: shared +source: maintainer answers of 2026-10-21 (fix scope B, items 3 to 7 change, review on); probes of 2026-10-21 on the published rc8 +--- + +# Decision 27: The open items before 5.0.0, and the piped optional parameters + +- Context: the tests-only round left no plain test gap (#129). On 2026-10-21 + the maintainer chose to fix the silent default scope of a piped `AppliesTo` + before 5.0.0 (rc9) and to go through the other open items one by one. rc9 + is the last prerelease: a change after its acceptance needs rc10, and after + 5.0.0 the repository is archived (Decision 18). So this is the last moment + to change any of the items below, and unchanged means accepted. +- Status: accepted at the level of scope (see "The maintainer's choices"). The + designs of the items 3 to 7 are still to be proposed and chosen. Every + recommendation in the tables is the agent's; the last column of the table of + the other items stays empty, because the choices are listed below. + +## New finding: the flaw is a family + +PowerShell skips a property of a piped object whose value it cannot convert to +the type of an optional parameter, and the parameter keeps its default. A named +call fails loudly; the same value on a piped object does not. Probe +`p-unconvertible-optional-params.ps1`, the published rc8, both editions (the +only difference is how `ReadData` prints): + +| Piped property | What rc8 does | +| --- | --- | +| `AccessType = 'Deny'` | A Deny entry, as intended | +| `AccessType = 'Denyy'` (typo), or a blank CSV cell | **An Allow entry**, no message | +| `AuditFlags = 'Failurre'` | Success and Failure are audited (the default), no message | +| `InheritanceFlags` or `PropagationFlags = 'Typo'` | Ignored; the default flags (`ContainerInherit`, `ObjectInherit`) | +| `AppliesTo = 'Typo'`, a blank cell, or `99` | Ignored; the broader default scope | +| `Remove-NTFSAccess` with `AccessType = 'Denyy'` | Looks for an Allow entry: the Deny entry stays, no message | +| `Get-FileHash2` with `Algorithm = 'SHA999'` | SHA256, no message | +| `-AccessType Denyy` as a named parameter | A binding error, as it should be | + +The decision of 2026-10-21 covers `AppliesTo` only. A typo for `Deny` that +creates an Allow entry is at least as serious, and it has the same cause. + +## Options for the fix + +Prototypes (`p-proto-appliesto-shapes.ps1`, `p-proto-object3.ps1`), both +editions, same attribute shape as `Add-NTFSAccess`: + +| Shape | Result | +| --- | --- | +| One parameter set with optional parameters | Does not help: the binder skips the unconvertible value there too | +| `AppliesTo` as `object` alone | Loud for a bad scope, but a CSV row with `AppliesTo` and `InheritanceFlags` is no longer `AmbiguousParameterSet`: the scope silently wins | +| `AppliesTo`, `InheritanceFlags`, `PropagationFlags`, and `AccessType` or `AuditFlags` as `object`, converted in the cmdlet with `LanguagePrimitives.ConvertTo` | Loud for every bad value (a non-terminating error for that object, the next object goes on, nothing carries over); `AppliesTo` with flags is `AmbiguousParameterSet` for every mix of strings and enums; valid values unchanged | + +| Option | What it is | Cost | +| --- | --- | --- | +| A | `AppliesTo` only (the decision as asked) | Leaves the Deny-to-Allow flip | +| B | The family in the four cmdlets (recommended): `AppliesTo`, `InheritanceFlags`, `PropagationFlags`, `AccessType` (access), `AuditFlags` (audit) | See below | +| C | B and `Get-FileHash2 -Algorithm` | B plus one cmdlet of low severity | +| D | No code change: pages and CHANGELOG say that piped values are not checked | Weak for a permissions tool | + +Consequences of B: the help shows `` for these parameters (the pages +list the values; an argument completer keeps tab completion); a named call +with a bad value is an error record of the cmdlet instead of a terminating +binding error; a blank cell for any of them is an error, not the default; a +`$null` `AccessType` stays the default (Allow); the pipeline conflict check is +now uniform. The work: tests first (the pins of the silent behavior change), +four cmdlets, four pages, the help file, the CHANGELOG, rc9, and the +acceptance (about 70 minutes with `Chain-Published.ps1`). An independent +review is recommended: public behavior and the permission scope. + +## The other open items + +| # | Item | What a user can notice | If changed | Recommended | Choice | +| --- | --- | --- | --- | --- | --- | +| 2 | The help says that a local standard user who asks about a domain account still gets "Access is denied" | Nothing changes in behavior | Docs only; rides with rc9 | Do it in rc9 | | +| 3 | Library-only items of the DLL that no cmdlet reaches: the `FileSecurity` conversions always throw; the `RemoveAll` filters ignore the account list (#113); the lazy path overloads; a `PrivilegeEnabler` that is not disposed stays enabled; the unused registry model and helper classes; `PipelineControl.IsEnd`; one unvisited catch in `Enable-Privileges` | Only .NET callers of the DLL | Code change and rc9 | Accept; list as known limits of the .NET API | | +| 4 | `Get-ChildItem2 -Filter` dot patterns differ from `Get-ChildItem` (`Report.*` misses `Report`; `Rep*.` returns nothing) | Documented, pinned by tests | New matching code and rc9 | Accept as documented | | +| 5 | The `-SecurityDescriptor` sets of the four add and remove cmdlets end with a terminating error when the change throws; the `-Path` sets write an error per item and go on (7 test rows stay unpinned) | A failing change to a descriptor in memory stops the cmdlet | Per-item handlers and rc9 | Accept | | +| 6 | Three small inconsistencies: the error category of `Get-NTFSAccess` after a failed ownership retry (`WriteError` there, `OpenError` elsewhere); `Get-NTFSOrphanedAccess` warns where its siblings write an error; `Set-NTFSSecurityDescriptor` takes `-Path` at position 2, its siblings at 1 | Scripts that check a category or pass a path by position | A breaking change for such scripts, and rc9 | Accept | | +| 7 | Seventeen owner-restore handlers do not pass on what a later command raises, in the rare case that it throws only for the `RestoreOwnerError` record | Rare | One check per handler, an elevated-only test, rc9 | Accept | | +| 8 | The ownership retry and the read denial of an audit write over SMB have no trigger on a Windows file server | None known | A seam (a design change), or the answer of a non-Windows server (#34) | Accept; #34 decides on 2026-11-02 | | +| 9 | Eight getters of piped parameters that no test binds by property name | None (tests only) | Tests only, no rc9 | Do it after the code of rc9 is final; the fix tests cover `AccessType`, `AuditFlags`, and `Algorithm` | | +| 10 | Lab and process only: the ACL of the lab stage folders under `C:\`, rollback checkpoints that report Standard, a publication recovery that never ran against the Gallery, test helpers that accept a link, the cleanup list (AppVeyor, Read the Docs, wiki, `test/transfer`, old checkpoints) | Not shipped | n/a | Accept; the cleanup before the archive is the maintainer's | | +| 11 | The deferred reviews of rc3 to rc7 (`progress.md`, open work 3) | Not new | n/a | Accept | | + +Decided before: the hard-link names under another root stay a documented known +limit (Decision 21); Decisions 22 and 24 are accepted; #34 is decided on +2026-11-02 (Decision 23). + +## The maintainer's choices, 2026-10-21 + +| Question | Answer | +| --- | --- | +| Scope of the fix of the piped optional parameters | B: the family in the four cmdlets (`AppliesTo`, `InheritanceFlags`, `PropagationFlags`, `AccessType`, `AuditFlags`) | +| Items to change in rc9 | 3 (library-only items), 4 (`Get-ChildItem2 -Filter` dot patterns), 5 (descriptor sets report per descriptor), 6 (three inconsistencies), 7 (17 owner-restore handlers) | +| Items accepted as recommended | 8 (audit retry and read denial over SMB; #34 decides on 2026-11-02), 10, 11. Items 2 and 9 need no decision: the help sentence goes into rc9, and the tests for the eight getters follow when the code of rc9 is final | +| Independent review of the rc9 change | Yes (`review: on`) | + +What follows: the agent proposes the design of each of the items 3 to 7 +(options, risk, tests, a recommended default); the maintainer chooses; the work +goes test-first into one branch, one commit per item, so that any item can be +dropped. A defect that the review finds is fixed before rc9 is tagged; a defect +that the acceptance finds needs rc10. One acceptance (about 70 minutes with +`Chain-Published.ps1`) covers rc9 as a whole. + +## Designs proposed, 2026-10-21 + +Five read-only research threads read the code, the tests, and the docs. The +sheet below is their result, verified in part by the probes above. Fix B is +decided; the rest is to be chosen. Recommended defaults are the agent's. + +| # | Design | Recommended | Alternatives and risks | +| --- | --- | --- | --- | +| B | `AppliesTo`, `InheritanceFlags`, `PropagationFlags`, `AccessType` (access cmdlets), `AuditFlags` (audit cmdlets) become `object` parameters; ProcessRecord converts them with `LanguagePrimitives.ConvertTo` into locals. One shared error: id `InvalidPipedParameterValue`, category `InvalidData`, target the piped object, message "The value '{0}' for parameter '-{1}' could not be converted to '{2}'. The piped object was skipped." (blank: "The value for parameter '-{0}' is blank. The piped object was skipped."). A null `AccessType` or `AuditFlags` stays the default. Argument completers (`IArgumentCompleter`, available in the referenced Windows PowerShell 5.0 assembly) keep tab completion. Docs: `Type: Object`, help from `New-ExternalHelp`, the CHANGELOG paragraph at lines 247 to 258 | As described | `Get-FileHash2 -Algorithm` has the same flaw (option C, not chosen). Named calls change from a terminating binding error to the error record of the cmdlet | +| 5 | In the four `-SecurityDescriptor` branches, a `try/catch (Exception)` around the change of each descriptor writes `AddAceError` or `RemoveAceError`, category `WriteError`, target the descriptor, message of the exception, and goes on; the later-command check of item 7 goes into the same catch. Lines: `AddAccess.cs` 176 to 184, `RemoveAccess.cs` 177 to 185, `AddAudit.cs` 175 to 185, `RemoveAudit.cs` 176 to 186 | As described | Tests: a failing descriptor followed by a valid one; the 7 unpinned rows | +| 7 | One `IsFromLaterCommand(ex)` check, rethrowing, in each of the 17 outer handlers (the pattern of `SetSecurityDescriptor.cs` 72 to 101): `AddAccess`, `RemoveAccess`, `ClearAccess`, `GetAccess`, `GetOrphanedAccess`, `GetEffectiveAccess`, `AddAudit`, `RemoveAudit`, `ClearAudit`, `GetFileHash2`, the six inheritance cmdlets, and `SetSecurityDescriptor` | As described | Tests: one parameterized elevated-only test (a later command that throws on the `RestoreOwnerError` record), like the existing `restoreOwnerCases` | +| 3.1 | `FileSystemSecurity2` conversions from `FileSecurity` and `DirectorySecurity` keep the given descriptor | Fix | Remove the operators: breaking public API. Medium risk | +| 3.2 | `RemoveFileSystemAccessRuleAll` and `RemoveFileSystemAuditRuleAll` honor the account list | Fix | High risk for external callers (they remove entries); the cmdlets pass no list. Tests for both rule types | +| 3.3 | The path and several accounts overloads of the two add methods write at once, like their siblings | Fix | Medium risk (the moment of an exception changes) | +| 3.4 | `PrivilegeEnabler` no longer keeps an undisposed instance reachable | Defer unless the maintainer insists | High risk: token state in every cmdlet; a finalizer test is not deterministic; every cmdlet disposes its enabler today | +| 3.6 | The registry model (about 500 lines), `FileSystemFlags`, `FileSystemEffectivePermissionEntry`, and two raw descriptor readers | Keep and document (Decisions 21 and 22) | Removal breaks unknown .NET callers of the public DLL | +| 3.9 | `PipelineControl.IsEnd` | Keep as defense in depth | A change touches the pipeline semantics of all cmdlets for no known defect | +| 3.10 | The malformed `EnablePrivileges` setting: one validation in the base class, the dead catch removed | Fix | Medium risk (base class) | +| 4 | `Get-ChildItem2 -Filter`. A: pass the pattern unchanged to AlphaFS (the Windows PowerShell 5.1 rules; brings back the 8.3 short-name matches that a past fix removed). B: one cmdlet-side matcher with the Win32 dot rules on the real names and a broad enumeration (about 40 lines; costs a larger enumeration over SMB). D: keep as documented | B | Even `Get-ChildItem` differs between the editions here, so "aligned" needs a stated policy: the Windows PowerShell 5.1 dot rules on real names, in both editions | +| 6a | `Get-NTFSAccess`, the category of `ReadSecurityError` after a failed ownership retry: `WriteError` in `Get-NTFSAudit`, `Get-NTFSEffectiveAccess`, `Get-NTFSInheritance`, and `Get-NTFSSecurityDescriptor` too, so it is the majority convention | Keep, and pin it with a test | `OpenError` would break scripts that check the category, and make the module inconsistent unless six cmdlets change | +| 6b | `Get-NTFSOrphanedAccess` warns for a read failure other than access denied | An error: `ReadSecurityError`, `OpenError`, target the path | Breaks `-WarningAction` users; `-ErrorAction Stop` newly stops | +| 6c | `Set-NTFSSecurityDescriptor` has `-SecurityDescriptor` at position 2 and no other positional parameter | Position 1 | Cosmetic: a lone positional parameter binds first whatever its number | + +## Assumption flagged for the maintainer's review + +- The lab suite: he answered "not sure, you pick". The agent took the + recommendation: run the full suite (1,615 cases per configuration) on the + lab machine classes now, against the published rc8, so that an OS-specific + finding can still go into rc9 instead of forcing rc10. It changes nothing in + the repository or the product. Evidence: `suite-newtests` in the session + folder. Result (2026-10-21, 09:10 to 09:33 UTC): 24 runs on six machine + classes (Windows Server 2019, 2022, and 2025, Windows 11 22H2 and 26H1, and + the host), 0 failures. Every run gained exactly 121 cases against the rc8 + acceptance, and the four new files give the counts of the CI runner (elevated + Desktop: Access 74/0, Audit 55/2, Inheritance 72/1, Items 90/0, executed and + skipped). No OS-specific finding. The machines are saved again, and + `OSWin11E` is off. diff --git a/.memory-bank/progress.md b/.memory-bank/progress.md index 3baabd1..aac6b74 100644 --- a/.memory-bank/progress.md +++ b/.memory-bank/progress.md @@ -33,16 +33,14 @@ Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl - 2026-10-08: #114 merged (`fcb370e`), rc5 published and live-tested. Decision 21 established the quality gate. Corrected four-run coverage: rc5 58.1% sequence points/38.0% branches, not the initial one-run result. -- 2026-10-08: rc6 Phase 2 added basic-user CI, parameter-set/error tests, - expanded domain/SMB cases, and fixes for privilege cleanup, path - resolution, ownership retries, item conflicts, output equality, and - inherited flags. Suite: 677; coverage 68.14% sequence/44.32% branches. - Lab acceptance of `7b0781f` passed; two independent review passes. -- 2026-10-08: rc7 implemented proposed Decision 22, including breaking - link binding/error changes, SimpleAccess traversal, cross-volume folder - preservation, and named effective-access warnings. Suite: 712, no - failures or test skipped everywhere. One review: no Blocker/Major. - Lab candidate `dc6e9f5`: 326 passed, 2 skipped, cleanup verified. +- 2026-10-08: rc6 Phase 2 (basic-user CI, parameter-set and error tests, + expanded domain/SMB cases, fixes for privilege cleanup, path resolution, + ownership retries, item conflicts, output equality, inherited flags; suite + 677, 68.14% sequence/44.32% branches; lab acceptance of `7b0781f` passed; + two review passes) and rc7 (Decision 22: breaking link binding and error + changes, SimpleAccess traversal, cross-volume folder preservation, named + effective-access warnings; suite 712; one review without Blocker or Major; + lab candidate `dc6e9f5`: 326 passed, 2 skipped, cleanup verified). - 2026-10-08: #115 merged (`b51d970`) and tagged rc6. Release run `37839669028` failed with HTTP 409 after Gallery publication. The log does not establish the previously assumed initial timeout/retry cause. @@ -135,8 +133,10 @@ Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl of 64 sets closed (7 before), 26 with a leftover (16 Limit, 7 MaintainerDecision, 3 would-pin); no defect. Report: `Tests/Coverage/Quality-Gate-Test-Round-2026-10-20.md`. On 2026-10-21 he - merged #129 (08:24Z) and #130 (08:47Z); the runner gave the local counts in - three CI runs (`39551726767` and two more). + merged #129 (08:24Z) and #130 (08:47Z); the new tests passed in three CI + runs and in 24 lab runs on six machine classes (0 failed). A probe then + found that piped optional parameters ignore a bad value (a typo for Deny + creates an Allow entry); Decision 27 sets the scope of rc9. ## Stable capabilities @@ -151,9 +151,8 @@ Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl 1. Decision 21 gate: the published rc7 and rc8 are accepted in the matrix and the first lab (records); stable follows rc8 (Decision 21, "Closing the - gate"). Do not release 5.0.0 until the other gates close: the decision on - #34 on 2026-11-02, the key check, and the decision on the open items (no - plain test gap is left). Release steps: + gate"). Do not release 5.0.0 until the other gates close: rc9 (Decision + 27), the decision on #34 on 2026-11-02, and the key check. Release steps: `Docs/Contributing/05-Releasing.md`; remove the prerelease label, date `[5.0.0]`, add the last prerelease (rc8) to `$publishedVersions` (never the version of the manifest), tag through CI. From 9bc38d01d5e65cba1fe430e1455dd4fb7491e134 Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Wed, 21 Oct 2026 11:07:06 +0000 Subject: [PATCH 3/7] docs(memory-bank): record the design choices of Decision 27 for rc9 The maintainer chose the designs of the open items on 2026-10-21: fix 3.1, 3.2, 3.3, and 3.10 of the library items, the dot rules of Get-ChildItem2 -Filter (option B), keep WriteError for Get-NTFSAccess and pin it, an error for Get-NTFSOrphanedAccess, and position 1 for Set-NTFSSecurityDescriptor. Fix B of the piped optional parameters is revised before the build: a bad value on the command line stays a terminating error, a bad piped value is an error per path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- .../decisions/0027-open-items-before-5.0.0.md | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/.memory-bank/decisions/0027-open-items-before-5.0.0.md b/.memory-bank/decisions/0027-open-items-before-5.0.0.md index 8e94c6d..0e0b4f6 100644 --- a/.memory-bank/decisions/0027-open-items-before-5.0.0.md +++ b/.memory-bank/decisions/0027-open-items-before-5.0.0.md @@ -3,7 +3,7 @@ status: accepted date: 2026-10-21 last-verified: 2026-10-21 owner: shared -source: maintainer answers of 2026-10-21 (fix scope B, items 3 to 7 change, review on); probes of 2026-10-21 on the published rc8 +source: maintainer answers of 2026-10-21 (fix scope B, items 3 to 7 change, review on; designs chosen in the third form); probes of 2026-10-21 on the published rc8 --- # Decision 27: The open items before 5.0.0, and the piped optional parameters @@ -14,10 +14,12 @@ source: maintainer answers of 2026-10-21 (fix scope B, items 3 to 7 change, revi is the last prerelease: a change after its acceptance needs rc10, and after 5.0.0 the repository is archived (Decision 18). So this is the last moment to change any of the items below, and unchanged means accepted. -- Status: accepted at the level of scope (see "The maintainer's choices"). The - designs of the items 3 to 7 are still to be proposed and chosen. Every - recommendation in the tables is the agent's; the last column of the table of - the other items stays empty, because the choices are listed below. +- Status: accepted. The scope and the designs are chosen (see "The + maintainer's choices", both tables). Every recommendation in the tables is + the agent's; the last column of the table of the other items stays empty, + because the choices are listed below. The details of fix B that the + maintainer did not see (error id, terminating or not) are the agent's design + and are flagged for the independent review. ## New finding: the flaw is a family @@ -97,10 +99,20 @@ limit (Decision 21); Decisions 22 and 24 are accepted; #34 is decided on | Items accepted as recommended | 8 (audit retry and read denial over SMB; #34 decides on 2026-11-02), 10, 11. Items 2 and 9 need no decision: the help sentence goes into rc9, and the tests for the eight getters follow when the code of rc9 is final | | Independent review of the rc9 change | Yes (`review: on`) | -What follows: the agent proposes the design of each of the items 3 to 7 -(options, risk, tests, a recommended default); the maintainer chooses; the work -goes test-first into one branch, one commit per item, so that any item can be -dropped. A defect that the review finds is fixed before rc9 is tagged; a defect +The design choices, third form, 2026-10-21 (each is the recommended default +except where noted): + +| Item | Choice | +| --- | --- | +| 3 | Fix 3.1 (`FileSecurity` and `DirectorySecurity` conversions), 3.2 (`RemoveAll` honors the account list), 3.3 (the path overloads write at once), 3.10 (malformed `EnablePrivileges` setting). Not fixed: 3.4 (`PrivilegeEnabler` never disposed: high risk, stays a known limit of the .NET API), 3.6 (registry model and helpers: kept, Decisions 21 and 22), 3.9 (`PipelineControl.IsEnd`: kept) | +| 4 | Option B: one matcher in the cmdlet with the Windows PowerShell 5.1 dot rules on the real names (8.3 short names stay ignored, invariant culture), in both editions | +| 6a | Keep `WriteError` for `ReadSecurityError` after a failed ownership retry, and pin it with a test | +| 6b | `Get-NTFSOrphanedAccess` writes an error for a read failure other than access denied: `ReadSecurityError`, `OpenError`, target the path | +| 6c | `Set-NTFSSecurityDescriptor -SecurityDescriptor` at position 1 (cosmetic) | +| B details | Not asked; the agent's design, see the row B below. `Get-FileHash2 -Algorithm` stays out (option C was not chosen) and is listed as a known limit | + +What follows: the work goes test-first into one branch, one commit per item, so +that any item can be dropped. A defect that the review finds is fixed before rc9 is tagged; a defect that the acceptance finds needs rc10. One acceptance (about 70 minutes with `Chain-Published.ps1`) covers rc9 as a whole. @@ -112,7 +124,7 @@ decided; the rest is to be chosen. Recommended defaults are the agent's. | # | Design | Recommended | Alternatives and risks | | --- | --- | --- | --- | -| B | `AppliesTo`, `InheritanceFlags`, `PropagationFlags`, `AccessType` (access cmdlets), `AuditFlags` (audit cmdlets) become `object` parameters; ProcessRecord converts them with `LanguagePrimitives.ConvertTo` into locals. One shared error: id `InvalidPipedParameterValue`, category `InvalidData`, target the piped object, message "The value '{0}' for parameter '-{1}' could not be converted to '{2}'. The piped object was skipped." (blank: "The value for parameter '-{0}' is blank. The piped object was skipped."). A null `AccessType` or `AuditFlags` stays the default. Argument completers (`IArgumentCompleter`, available in the referenced Windows PowerShell 5.0 assembly) keep tab completion. Docs: `Type: Object`, help from `New-ExternalHelp`, the CHANGELOG paragraph at lines 247 to 258 | As described | `Get-FileHash2 -Algorithm` has the same flaw (option C, not chosen). Named calls change from a terminating binding error to the error record of the cmdlet | +| B | `AppliesTo`, `InheritanceFlags`, `PropagationFlags`, `AccessType` (access cmdlets), `AuditFlags` (audit cmdlets) become `object` parameters; ProcessRecord converts them with `LanguagePrimitives.ConvertTo` into locals. One shared error: id `InvalidParameterValue`, category `InvalidArgument` (the category of the binder's own errors and of `AttributesEmpty`), message with the value, the parameter, and the valid names (a blank value has its own message). Revised before the build: a bad value on the command line stays a terminating error, as the binder made it (checked in `BeginProcessing`, so a `try`/`catch` around a named call still works); a bad value on a piped object is a non-terminating error per path (per descriptor in the `-SecurityDescriptor` sets), target that path, no item of that record is changed, and the next object goes on. A null `AccessType` or `AuditFlags` stays the default. Argument completers (`IArgumentCompleter`, available in the referenced Windows PowerShell 5.0 assembly) keep tab completion. Docs: `Type: Object`, help from `New-ExternalHelp`, the CHANGELOG paragraph at lines 247 to 258 | As described | `Get-FileHash2 -Algorithm` has the same flaw (option C, not chosen). The error of a named call now comes from the cmdlet, not the binder (other id, same terminating effect) | | 5 | In the four `-SecurityDescriptor` branches, a `try/catch (Exception)` around the change of each descriptor writes `AddAceError` or `RemoveAceError`, category `WriteError`, target the descriptor, message of the exception, and goes on; the later-command check of item 7 goes into the same catch. Lines: `AddAccess.cs` 176 to 184, `RemoveAccess.cs` 177 to 185, `AddAudit.cs` 175 to 185, `RemoveAudit.cs` 176 to 186 | As described | Tests: a failing descriptor followed by a valid one; the 7 unpinned rows | | 7 | One `IsFromLaterCommand(ex)` check, rethrowing, in each of the 17 outer handlers (the pattern of `SetSecurityDescriptor.cs` 72 to 101): `AddAccess`, `RemoveAccess`, `ClearAccess`, `GetAccess`, `GetOrphanedAccess`, `GetEffectiveAccess`, `AddAudit`, `RemoveAudit`, `ClearAudit`, `GetFileHash2`, the six inheritance cmdlets, and `SetSecurityDescriptor` | As described | Tests: one parameterized elevated-only test (a later command that throws on the `RestoreOwnerError` record), like the existing `restoreOwnerCases` | | 3.1 | `FileSystemSecurity2` conversions from `FileSecurity` and `DirectorySecurity` keep the given descriptor | Fix | Remove the operators: breaking public API. Medium risk | From fbb20ea4d980cf812b7f6a523e34e390403fa32c Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Wed, 21 Oct 2026 11:16:14 +0000 Subject: [PATCH 4/7] docs(memory-bank): record that the rc9 work items are running The designs of Decision 27 are chosen, and four work items run in worktrees under C:\Temp\ntfs-rc9 on the branch ai/rc9-before-stable. The inventory of open decisions in progress.md now points to Decision 27. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- .memory-bank/activeContext.md | 18 ++++++++++-------- .memory-bank/progress.md | 11 ++++++----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.memory-bank/activeContext.md b/.memory-bank/activeContext.md index 574a9a8..a1590e4 100644 --- a/.memory-bank/activeContext.md +++ b/.memory-bank/activeContext.md @@ -25,12 +25,14 @@ of the new error, a computer name of 32,718 characters, holds on Server 2019, and this Memory Bank (#130, 08:47Z); `master` is `d0cb57c`. The new tests gave the same counts on the runner (three CI runs) and on six machine classes of the labs (24 runs, 0 failed). A probe found that a typo in a piped `AccessType` -silently creates an Allow entry. He decided (Decision 27): rc9 fixes that -family and the items 3 to 7 of its sheet, with a review. Open before the -stable pull request: rc9 (designs, tests, review, acceptance of about 70 -minutes), his decision on #34 on 2026-11-02, and his check of -`PSGALLERY_API_KEY`. The stable change then touches only the label, the -CHANGELOG, and `$publishedVersions`. +silently creates an Allow entry. He decided (Decision 27) that rc9 fixes that +family and the items 3 to 7 of its sheet, with a review, and chose the +designs. Four work items run in worktrees under `C:\Temp\ntfs-rc9` (branch +`ai/rc9-before-stable`; specs in the session folder `files\rc9\specs`). Open +before the stable pull request: rc9 (integration, validation, review, +acceptance of about 70 minutes), his decision on #34 on 2026-11-02, and his +check of `PSGALLERY_API_KEY`. The stable change then touches only the label, +the CHANGELOG, and `$publishedVersions`. State at 2026-10-10: the maintainer integrated the release-gate stack into `master` (#116, #120, #118, #119, #121; `fa0701b`, CI green; GitHub closed #117 @@ -166,8 +168,8 @@ Decisions 22 and 24 on 2026-10-19 and decides 23 on 2026-11-02. `PSGALLERY_API_KEY` first, merges, and tags. Every release step is his. 3. Decision 27 (2026-10-21): rc9 changes the library-only items, the dot patterns of `Get-ChildItem2 -Filter`, the 17 owner-restore handlers, the - errors of the descriptor sets, and three inconsistencies; designs are being - researched. Decisions 22 and 24 are accepted (2026-10-19). + errors of the descriptor sets, and three inconsistencies; the designs are + chosen, four work items are in progress. Decisions 22 and 24 are accepted. 4. #34 waits for a tester until 2026-11-02 (Decision 23, option 3; the follow-up went up on 2026-10-19, no reply yet; checklist: `Tests/Lab/Non-Windows-File-Server-Test.md`). On that date the maintainer diff --git a/.memory-bank/progress.md b/.memory-bank/progress.md index aac6b74..bec16a0 100644 --- a/.memory-bank/progress.md +++ b/.memory-bank/progress.md @@ -136,7 +136,9 @@ Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl merged #129 (08:24Z) and #130 (08:47Z); the new tests passed in three CI runs and in 24 lab runs on six machine classes (0 failed). A probe then found that piped optional parameters ignore a bad value (a typo for Deny - creates an Allow entry); Decision 27 sets the scope of rc9. + creates an Allow entry); Decision 27 sets the scope of rc9, the designs were + chosen on 2026-10-21, and four work items started (branch + `ai/rc9-before-stable`). ## Stable capabilities @@ -177,10 +179,9 @@ Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl (`2112ee3`): 402 unvisited sequence points in 183 methods, all classified (`Tests/Coverage`): 167 explained from source with evidence, 16 open (8: `FileSecurity` conversions, `RemoveAll` account filters; 8 getters of - pipeline parameters that no test binds by property name). Other open - decisions: lazy path overloads, abandoned `PrivilegeEnabler`, dot patterns - of `Get-ChildItem2 -Filter`, 17 owner-restore handlers that do not pass on - what a later command raises (a rare combination), unused classes. No + pipeline parameters that no test binds by property name). Decision 27: rc9 + fixes the conversions, `RemoveAll`, the lazy overloads, the dot patterns, + and the 17 handlers; `PrivilegeEnabler` and unused classes stay. No trigger for an audit write's ownership retry was found on a local volume or a Windows file server (probe of 48 calls) and no test reaches it. A conditional ACE display remains a .NET representation limit, not evidence From 1c26ea7f4ec249003722477dd9ee9f17401aab2c Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Wed, 21 Oct 2026 14:19:19 +0000 Subject: [PATCH 5/7] docs(memory-bank): record the rc9 review, the known limits, and the lessons Decision 27 gets the review findings of rc9 and what became of each, with the known limits that the maintainer is told about. debugging-insights gets the lessons of the piped optional parameters (the binder skips a value that it cannot convert, and the price of an object parameter), of a differential oracle that covers only part of the input, of agents in parallel worktrees (one shared stash), and of the help generation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- .memory-bank/debugging-insights.md | 51 +++++++++++++++++++ .../decisions/0027-open-items-before-5.0.0.md | 42 +++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/.memory-bank/debugging-insights.md b/.memory-bank/debugging-insights.md index 053c132..54cbbb3 100644 --- a/.memory-bank/debugging-insights.md +++ b/.memory-bank/debugging-insights.md @@ -128,3 +128,54 @@ fails without it (Decision 16). gives up after 60 seconds when its runner never started (about 6 seconds normally). Before you blame the load for a stall, repeat the call alone with the same arguments. + +## Optional enum parameters that take pipeline input by property name + +- The binder skips a piped property that it cannot convert to the type of an + OPTIONAL parameter and keeps the default: a typo for `Deny`, a blank CSV + cell, or a misspelled scope silently made an Allow entry or the default + scope (probe `p-unconvertible-optional-params.ps1` on rc8, both editions; a + named call fails loudly; one parameter set with optional parameters does not + help). `Get-FileHash2 -Algorithm` has the same flaw and stays a known limit. +- Decision 27, fix B: the five parameters of the four add and remove cmdlets + are `object`, converted in the cmdlet by `ParameterConversion`. All five + must be `object`: with `AppliesTo` alone, a row with `AppliesTo` and flags + lost its `AmbiguousParameterSet`. The price was found by the review, not by + the author's tests: a `$null`, DBNull, or blank value of the OTHER group + binds too (a CSV with columns of both groups is `AmbiguousParameterSet`); a + named `$null` binds, where rc8 refused it (`MyInvocation.BoundParameters` + shows it in `BeginProcessing`); a script block is no longer delay-bound; the + completion of the names has to be rebuilt (quotes, wildcards, declaration + order); help shows `Object`. Probe every form of a value before you write a + claim, and ask a reviewer for the negative space. +- PowerShell calls the getter of a by-property-name parameter once per + command, when a piped object first binds it (`p-getter-calls.ps1`). A test + that must visit it pipes an object that has the property. A property getter + that throws reads as `$null` without a trace: test it through reflection. + +## A differential oracle that covers part of the input + +- The matcher of `Get-ChildItem2 -Filter` was checked against Windows + PowerShell 5.1 over 55,987 patterns, on 8.3-compliant names only, so that the + short name is the real name. Such names have at most one dot, where the first + and the last dot are the same, so a rule about the LAST dot was invisible: + `*.??` dropped `archive.tar.gz`. The review found it with 849k pairs. Cover + every dimension of the input, and neutralize a quirk of the oracle instead of + avoiding the inputs that trigger it: `fsutil file setshortname` gives a long + name a short name that matches nothing, `fsutil 8dot3name strip` removes it. +- A very long pattern ended the host with a stack overflow (recursion depth = + tokens): bound the input of a recursive matcher (`ValidateLength`). + +## Agents in parallel worktrees + +- `git stash` is ONE list for all worktrees: a `pop` takes the top entry of + whoever created it and moved the edits of one agent into another's tree. The + brief forbids stash, `restore`, `reset`, `clean`, and checkout of a sha; a RED + run on the unchanged product uses a private base worktree. Protect a foreign + stash with `git update-ref` before anything else. +- An agent that ends its turn without a report may have done nothing (a clean + worktree and an empty probe folder said so): write to it and ask. +- Help generation: `Update-MarkdownHelp` reads `Position` from the help file + that the build copies, not from the C# attribute, so a page edit alone drifts: + edit the page, `New-ExternalHelp`, rebuild, then check the docs (the files are + a fixpoint). A pair of asterisks in one paragraph loses them in the XML. diff --git a/.memory-bank/decisions/0027-open-items-before-5.0.0.md b/.memory-bank/decisions/0027-open-items-before-5.0.0.md index 0e0b4f6..4be75d6 100644 --- a/.memory-bank/decisions/0027-open-items-before-5.0.0.md +++ b/.memory-bank/decisions/0027-open-items-before-5.0.0.md @@ -153,3 +153,45 @@ decided; the rest is to be chosen. Recommended defaults are the agent's. Desktop: Access 74/0, Audit 55/2, Inheritance 72/1, Items 90/0, executed and skipped). No OS-specific finding. The machines are saved again, and `OSWin11E` is off. + +## Built in rc9, the review, and the known limits + +- How: four implementers worked in separate worktrees (WI-1 the five piped + parameters and item 5, WI-2 item 7 and the three inconsistencies, WI-3 the + library items, WI-4 the filter), test first, one commit per item. The agent + integrated them, ran the whole suite on the integrated tree, and had three + read-only reviewers read it (brief `rc9\REVIEW-BRIEF.md` in the session + folder). The findings became follow-up commits, and the branch `ai/rc9` was + rebuilt with `git cherry-pick` in the order of each chain, so every fix sits + in the commit of its item and any item can still be dropped. + +What the review found: + +| Finding | What became of it | +| --- | --- | +| Blocker: a `*` before a dot has to stop at the LAST dot, the matcher stopped at the first; `*.??` missed `archive.tar.gz`. The differential check ran on 8.3 names, which have one dot, and could not see it | Fixed; a differential check over 732,630 multi-dot pairs found no mismatch; the tests pin the multi-dot shapes | +| Major: with `object` parameters, a `$null`, DBNull, or blank value of the OTHER parameter group binds in both sets, so a CSV row with a blank cell of the other group is `AmbiguousParameterSet` (rc8 skipped the cell and created the entry) | Documented and pinned. **Flagged:** the alternative is a restructure of the parameter sets, a larger public change; the maintainer was told that the agent goes on with the documentation and has not objected | +| Major: a named `$null` (`-AccessType $rule.AccessTpye`) silently selected the default | Fixed: a terminating `InvalidParameterValue` for a name in `BoundParameters` whose value is `$null` | +| Minor: a script block is no longer delay-bound; the completers returned nothing for a quoted or wildcard word | Documented and pinned; the completers are fixed | +| Minor: since 3.1, `-SecurityDescriptor (Get-Acl $f)` binds, and then threw from the inherited-from lookup and marked the audit section as read; the null guard of `Name` was not pinned; `Get-NTFSInheritance` wrote its object in a `finally` after it rethrew the exception of a later command | Fixed; the guard is pinned through reflection, because a PowerShell property read turns a throwing getter into `$null` | +| Filter: platyPS removed paired asterisks of a paragraph; the PowerShell 7 claim was too broad; the CHANGELOG said nothing of the new `?`; a pattern of more than 32,767 characters ended the host with a stack overflow; one sentence contradicted itself | Fixed: one asterisk per paragraph, the exact shapes, the CHANGELOG sentence, `[ValidateLength(0,32767)]` | + +Known limits, kept and to be stated to the maintainer: + +- `Get-NTFSEffectiveAccess` on a FAT32 volume or on an item with a NULL DACL + ends with an `ArgumentOutOfRangeException` (mask 2097151). Found by a probe, + not caused by rc9, not fixed. +- The error branch of 6b (`Get-NTFSOrphanedAccess` cannot read an item) has no + deterministic trigger: a locked file, a long path, a dangling junction, and a + FAT32 VHD were tried. It is reviewed, not pinned. +- Item 7: 9 of the 17 handlers have no test. The getters' own + `FileSystemOwner.GetOwner` needs the same read right that the test takes + away, and the audit cmdlets write the SACL whatever the DACL says, so the + action never fails first. +- `Get-FileHash2 -Algorithm` keeps the silent default of a piped value that + does not convert (option C was not chosen). The settings `GetInheritedFrom`, + `GetFileSystemModeProperty`, and `IdentifyHardLinks` still read their value + with an unchecked cast, as `EnablePrivileges` did. `PrivilegeEnabler` (3.4) + stays undisposed, a known limit of the .NET API. +- In PowerShell 7, the case folding of `-Filter` differs from NTFS for a few + exotic letters (finding F7 of the review; not fixed). From 90e04c6081182fa18c0199171350b566a7acdcf4 Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Wed, 21 Oct 2026 17:19:59 +0000 Subject: [PATCH 6/7] docs(memory-bank): close out the rc9 work with the head, the final suite, and the open work Record that the branch ai/rc9 is complete at de67883 (32 commits over d0cb57c, 2,116 cases per configuration, 0 failed), what the two review rounds found, that the maintainer chose to reject a list for -AccessType and -AppliesTo, and what is left before the stable pull request (push, pull request, merge, and tag of rc9 by the maintainer, then the lab acceptance of the published bytes). Lessons for the next agent: PowerShell combines the numbers of a list for an enumeration that is not a flags enumeration bit by bit, and code that opens a one-element collection needs a depth limit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- .memory-bank/activeContext.md | 266 +++++++----------- .memory-bank/debugging-insights.md | 16 ++ .../decisions/0027-open-items-before-5.0.0.md | 24 ++ .memory-bank/progress.md | 90 +++--- .memory-bank/systemPatterns.md | 38 +-- .memory-bank/techContext.md | 6 +- 6 files changed, 204 insertions(+), 236 deletions(-) diff --git a/.memory-bank/activeContext.md b/.memory-bank/activeContext.md index a1590e4..2e06b75 100644 --- a/.memory-bank/activeContext.md +++ b/.memory-bank/activeContext.md @@ -9,30 +9,53 @@ source: current task evidence ## Current focus -State at 2026-10-21: 5.0.0-rc8 is published and accepted. The -maintainer merged #126 (the decisions of 2026-10-19) and #127 (`c719197`: the -fix of the false "no access" of `Get-NTFSEffectiveAccess`, the known limit of -the hard-link cmdlets in the pages and the CHANGELOG, and the label `rc8`) and -tagged `5.0.0-rc8` at about 10:28Z. The CI run `39408140862` passed, and the -Gallery has rc8 since 10:40:58Z, GitHub since 10:41:07Z. The identity check -passed. The lab acceptance of the published bytes passed in one detached driver -(68 minutes, 10:38 to 11:47Z): three cells 1,374/0/12, the suite in 24 runs on -six machine classes, the first lab 245/0/1 per edition, every end state CLEAN -(record `Tests/Lab/Acceptance-2026-10-20-published-rc8.md`, #128). The boundary -of the new error, a computer name of 32,718 characters, holds on Server 2019, -2022, 2025, and Windows 11 26H1. He merged the record, #128, on 2026-10-21 at -05:48Z, the tests-only round for the plain gaps (#129, 08:24Z; Next step 6), -and this Memory Bank (#130, 08:47Z); `master` is `d0cb57c`. The new tests gave -the same counts on the runner (three CI runs) and on six machine classes of the -labs (24 runs, 0 failed). A probe found that a typo in a piped `AccessType` -silently creates an Allow entry. He decided (Decision 27) that rc9 fixes that -family and the items 3 to 7 of its sheet, with a review, and chose the -designs. Four work items run in worktrees under `C:\Temp\ntfs-rc9` (branch -`ai/rc9-before-stable`; specs in the session folder `files\rc9\specs`). Open -before the stable pull request: rc9 (integration, validation, review, -acceptance of about 70 minutes), his decision on #34 on 2026-11-02, and his -check of `PSGALLERY_API_KEY`. The stable change then touches only the label, -the CHANGELOG, and `$publishedVersions`. +State at 2026-10-21: 5.0.0-rc8 is published and accepted (tag `c719197`, CI run +`39408140862`, Gallery 2026-10-20 10:40:58Z, GitHub 10:41:07Z, identity check +passed; lab acceptance of the published bytes 10:38 to 11:47Z, record +`Tests/Lab/Acceptance-2026-10-20-published-rc8.md`, #128). `master` is +`d0cb57c`: the maintainer merged #128 (2026-10-21 05:48Z), the tests-only round +#129 (08:24Z), and the Memory Bank #130 (08:47Z). + +The last prerelease before the stable 5.0.0 is rc9 (Decision 27). The branch +`ai/rc9` (base `d0cb57c`, 32 commits, head `de67883`) is complete and +validated; it is local until the maintainer pushes it, opens the pull request +(body: `C:\Temp\ntfs-rc9\final-msgs\pr-rc9-body.md`, temporary), merges it, and +tags `5.0.0-rc9`. It contains: the five piped parameters of `Add-` and +`Remove-NTFSAccess` and `-NTFSAudit` are `object`, converted in the cmdlet +(`ParameterConversion`), so a typo for `Deny` no longer creates an Allow entry; +a list for `-AccessType` and `-AppliesTo` is rejected; the `-SecurityDescriptor` +sets report a failing descriptor and go on; the 17 owner-restore handlers pass +on what a later command raises; `Get-ChildItem2 -Filter` has one matcher with +the Windows PowerShell 5.1 rules; the library fixes 3.1 to 3.3 and 3.10; +`Get-NTFSOrphanedAccess` writes an error; `-SecurityDescriptor` of +`Set-NTFSSecurityDescriptor` at position 1; tests that bind four parameters by +property name; label `rc9`. + +Validation of `de67883`: the full suite in the four CI configurations, 2,116 +cases each, 0 failed (rc8: 1,615; skipped 27, 359, 58, and 390, so every new +case runs where it can); the pages and the help file are a fixpoint (0 drift, 0 +broken links; the help file is identical after a second generation); +PSScriptAnalyzer reports nothing in the 11 changed scripts; the public surface +differs from rc8 by 16 `object` properties, 5 completer classes, 1 protected +method, and 1 parameter position, and equals the candidate of round 1; a +matrix of valid shapes of the five parameters, run on the published rc8 and on +this build in both editions, differs in exactly the 9 list rows of +`Add-NTFSAccess`. Two review rounds (Decision 27, "Built in rc9"): round 1 on the +first integration found a Blocker (the last-dot rule of the filter) and two +Major findings; round 2 on the final tree and three checks of its fixes found +only Minor findings (wrong statements in the pages, completers that were not +culture invariant, the list for `-AccessType` and `-AppliesTo`, ways around +that rejection, a collection that holds itself); all are fixed with a test +that is red without the fix, or decided. A blank, `$null`, or `DBNull` value of +the other parameter group is `AmbiguousParameterSet` (documented, not +restructured). + +Open before the stable pull request: the pull request, merge, and tag of rc9 +(maintainer); the lab acceptance of the published rc9 (agent, about 70 +minutes, `Chain-Published.ps1`); his decision on #34 on 2026-11-02; his check of +`PSGALLERY_API_KEY`. The stable change then touches only the label, the +CHANGELOG, and `$publishedVersions` (add `5.0.0-rc9`). The Memory Bank of this +work is a separate pull request (branch `ai/memory-bank-merged`). State at 2026-10-10: the maintainer integrated the release-gate stack into `master` (#116, #120, #118, #119, #121; `fa0701b`, CI green; GitHub closed #117 @@ -45,155 +68,66 @@ Decisions 22 and 24 on 2026-10-19 and decides 23 on 2026-11-02. ## Evidence -- rc6 Release run `37839669028`, attempt 2, succeeded; GitHub prerelease with - zip appeared 2026-10-09 07:01:34 UTC. The first attempt proves HTTP 409 - after Gallery publication, not the earlier assumed retry chronology. -- Integration on 2026-10-10 (UTC): #116 merged 09:10, #117 closed unmerged - 09:10:16 (events `base_ref_deleted`, `closed`), #120 merged 10:50, #118 - 11:12, #119 11:28, head branches deleted 11:34, CI on `master` at `fa0701b` - green 11:40. A `git merge-tree` simulation of the chain was conflict-free and - ended in the tree of the matrix branch. -- rc7 on 2026-10-10: tag at `fa0701b` about 12:20Z, CI run `38051611526` - green, Gallery 12:30:57Z, GitHub 12:31:09Z. `Test-PublishedRelease.ps1` - (12:33Z): tag commit on `master`, Gallery SHA-512 matches the nupkg, 11 - module files identical in nupkg and zip, manifest `5.0.0-rc7`; hashes in the - deployment notes, evidence in the session folder `published-rc7`. -- Gate 3 on the published rc7, 14:29 to 15:30 UTC (one detached driver; record - `Tests/Lab/Acceptance-2026-10-10-published-rc7.md`, evidence `gate3-rc7` with - a manifest): the three matrix cells (OSFile19, 22, 25 with OSWin11E, both - editions) 1,374 passed, 0 failed, 12 skipped, `LIVE_RESULT_VERIFIED` and - CLEAN in each; the suite in 24 runs on six machine classes without a failure - and with the host's skipped tests; the first lab with case 9 245 / 0 / 1 per - edition, CLEAN in four domains and on both machines. Each controller run - downloaded the package of the identity check (nupkg and DLL hashes equal). - Same counts as the final local candidate; no checkpoint was taken. -- Handoff 1 (paths), measured at `5a5d58b` (frozen Release, four configurations, - CI wrappers, then AltCover): 1,310 cases per configuration, zero failures - (baseline `3442194`: 914 cases); coverage 3,192/3,634 sequence points - (87.84%) and 1,273/1,978 branches (64.36%), against 74.21% and 50.39%. All 231 - methods with 442 unvisited points are classified: 223 explained, 8 open for - the maintainer. Skip eligibility was checked by row: all 578 skipped rows - (137 distinct tests) are executed in two other configurations. -- Eleven defects were fixed, ten with a guard that is red before the fix and - green after it (a red/green matrix over ten states of the branch: 76 rows - red at the base `f11ff41`, none after the last fix; the leak of a native - buffer has no guard). Mutation rounds at `5a5d58b`: 25 of 26 detected, M25 - (the check by type) an equivalent mutant. The matrix doesn't show that a test - preceded its fix: each fix commit carries both. Report: - `Tests/Coverage/Quality-Gate-Paths-2026-10-09.md`. +- Evidence of rc9 is outside git, in the session folder + `816cf47d-2f80-4eba-8ac9-41702c49560b\files\rc9`: the specs and review briefs, + `suite-full1` (first integration), `suite-final`, `suite-final2`, + `suite-final3`, and `suite-final4` (the head `de67883`), the probes (`p-*.ps1`, + `fixb-probe`, `shapes-r2`, `Run-Oracle.ps1`, `Run-Pathological.ps1`), the + published rc8 (`rc8-published`), and the analyzer and surface results. The + review probes of the reviewers are in `C:\Temp\ntfs-rc9\review*-probes-*` + (temporary). The worktrees under `C:\Temp\ntfs-rc9` are temporary too. +- Milestones of earlier gates (rc6 and rc7 releases, handoff 1, the operating + system matrix, handoff 5, the rc7 and rc8 acceptances) are in `progress.md` + and in the records and reports under `Tests/Lab` and `Tests/Coverage`. - Reviews: the custom `security-reviewer` can't start (its model is - unavailable; no override). The built-in `code-review` agent made nine static - passes of the paths work (no Blocker or Major) and four rounds on the matrix - (one Major, record accuracy, resolved by the replay; Minors corrected); the - built-in `security-review` agent found no exploitable vulnerability and two - LOW items left for the maintainer (Next step 5). -- Live candidate of 2026-10-09 (09:20 to 09:51 UTC): 330 passed, 0 failed, 2 - expected skips; published rc6: 326 passed, 4 expected failures, 2 skips; the - 11 tested files match the ZIP. Independent probes verified the fixture - removal on six machines (`Tests/Lab/Acceptance-2026-10-09-quality-gate.md`). -- Six checkpoints report Standard even after a successful ProductionOnly probe; - policy restored, no restore performed: don't claim verified Production - rollback evidence. -- Lab acceptance of the paths fixes, 2026-10-09 20:41 to 21:42 UTC: candidate - `83149ee` against its base `f11ff41`, the same 244 tests per edition (78 - new): 486 passed, 0 failed, 2 expected skips against 338 passed, 148 failed - (each green on the candidate); fixture removal verified. Record: - `Tests/Lab/Acceptance-2026-10-09-quality-gate-paths.md`. -- Operating-system matrix, 2026-10-10 (record - `Tests/Lab/Acceptance-2026-10-10-os-matrix.md` with CSV tables): the suite of - the final candidate `fdd7a8b` passes on OSFile19/22/25, OSWin11E, OSWin11, and - the host (24 runs, no failure; the baseline `83149ee` fails 4 elevated and 20 - basic-user tests on OSFile22 and OSFile25); the live controller passes in - three cells (1,374 passed, 0 failed, 12 skipped) and in the first lab with - case 9 (245 passed, 0 failed, 1 skipped per edition; fixture removed and - verified). The Admin-role effective-access failures in earlier cells were - stale account state, not the module: in a replay the baseline failed two of - three cells and the candidate one, and one lifetime of about ten minutes fits - 43 runs of 27 cells (the Windows mechanism is unknown). The controller names - the case-3 account anew for each fixture (`1dec389`); four more cells with it - passed. A dry run of `Run-MatrixSequence.ps1 -Version 5.0.0-rc6` showed that - the published-package path works. Labs at 07:50 UTC on 2026-10-10: no fixture - or probe residue; `OSWin11E` shuts itself down an hour after its start. -- Handoff 5, the coverage unknowns, 2026-10-10 to 11 (report - `Tests/Coverage/Quality-Gate-Unknowns-2026-10-10.md`; raw evidence in the - session folder `816cf47d-2f80-4eba-8ac9-41702c49560b\files\qg-unknowns` - with a hash manifest). rc7 measured at `fa0701b` (four frozen - configurations, AltCover): 3,198/3,649 sequence points (87.64%), 1,090/1,168 - explicit branch points; 232 unvisited methods, all classified. Live suite on - an instrumented copy (first lab and three cells) and unit suite on - `OSFile25`: together +9 sequence and +4 explicit branch points (the code of - `fdd7a8b`); no test or probe reaches the audit ownership retry or the audit - read denial. 101 new `It` blocks; 7 of 64 parameter sets closed, 51 partly, - 1 open, 4 left to the maintainer. Cultures `de-DE` and `tr-TR`: two defects, - fixed. The piped - `AppliesTo` (Decision 26, debugging insights): fixed in `93ed2c7`; the - independent reviews then found a carry-over of the scope between piped - objects (`9783d2a`; rc7 had it for descriptor objects) and two false - sentences of the documents about empty values (`7bc7925`, `2112ee3`). Final - commit `2112ee3`, product code of `9783d2a` (its help file differs from the - package that the labs accepted): 1,492 cases per configuration, 3,266/3,668 - points, 183 unvisited methods, all classified. The labs accepted the package - (`ap7`, `ap8`): first lab 245/0/1 per edition; the 22 files on - `OSFile19/22/25` and `OSWin11` 1,189/0 in 16 configurations; the three cells - 229/0/2 per edition; all end states clean at 13:45Z. The first start of the - cells did nothing: a `powershell.exe` that PowerShell 7 starts inherits its - `PSModulePath` (lab README). Server Core, ARM64, a localized system, and - non-Windows servers are out of scope (Decision 25). -- rc8, 2026-10-20: fix (b) test-first on `ai/fix-effective-access-init-errors`. - A `-ServerName` of 40,000 characters gave `Synchronize` and no error before - and gives an error now; two tests were red and are green in four - configurations, and the suite has 1,494 cases per configuration, 0 failed. - The independent review (`code-review`) found one Minor, the warning "based on - this computer" before the error (fixed, with tests), and three Nits. The - acceptance evidence is `rc8-published` in the session folder - `816cf47d-2f80-4eba-8ac9-41702c49560b\files\qg-unknowns` (430 files, with a - manifest); the published hashes are in the deployment notes. -- Raw evidence is outside git: the session folder + unavailable; no override); the built-in `code-review` agent reviewed the paths + work, the matrix, rc8, and rc9; the built-in `security-review` agent found no + exploitable vulnerability and two LOW items for the maintainer (Next step 5). +- Raw evidence of the older gates is outside git: the session folder `4b12e2f4-d4c7-4a5d-883a-ddb7421c4848\files` (`qg-paths`, the matrix runs, the - night log) and - `26f151b6-e46f-49bd-9398-b27e20603949\files\quality-gate-3442194-20261009`. + night log), `26f151b6-e46f-49bd-9398-b27e20603949\files\quality-gate-3442194-20261009`, + and `816cf47d-2f80-4eba-8ac9-41702c49560b\files\qg-unknowns` (430 files of + `rc8-published`, with a manifest; the published hashes are in the deployment + notes). +- Six checkpoints of the lab report Standard even after a successful + ProductionOnly probe; policy restored, no restore performed: don't claim + verified Production rollback evidence. ## Next step -1. Gate 3 is done for the published rc7 and rc8 (the records). The stable build - is accepted through rc8 (Decision 21, "Closing the gate"). Open: keep or - replace the matrix VMs (about 60 GB, saved between runs) and the evaluation - client (it shuts down every hour; `OSWin11E` is off), and a domain cell for - Windows 11 26H1, whose client loses the secure channel to the Server 2025 - domain controller. `Chain-Published.ps1` in the session files runs the whole - sequence (not in the kit; deployment notes). +1. The maintainer pushes `ai/rc9`, creates the pull request, merges it after + CI, and tags `5.0.0-rc9` (commands in the reply of 2026-10-21; every release + step is his). Then run `Chain-Published.ps1 -Version 5.0.0-rc9 -Tag 5.0.0-rc9 + -Evidence ` from the session files (about 70 minutes, detached, with the + heartbeat; save the labs afterwards) and write the acceptance record + `Tests/Lab/Acceptance--published-rc9.md`. A defect that it finds needs + rc10. 2. The stable pull request: no `Prerelease`, `## [5.0.0] - ` with an empty - `[Unreleased]` and the links, and `5.0.0-rc8` in `$publishedVersions` (the - list ends at rc7 now). The maintainer checks the expiry of - `PSGALLERY_API_KEY` first, merges, and tags. Every release step is his. -3. Decision 27 (2026-10-21): rc9 changes the library-only items, the dot - patterns of `Get-ChildItem2 -Filter`, the 17 owner-restore handlers, the - errors of the descriptor sets, and three inconsistencies; the designs are - chosen, four work items are in progress. Decisions 22 and 24 are accepted. -4. #34 waits for a tester until 2026-11-02 (Decision 23, option 3; the - follow-up went up on 2026-10-19, no reply yet; checklist: + `[Unreleased]` and the links, and `5.0.0-rc9` in `$publishedVersions` (the + list ends at rc7 now; rc8 comes with the rc9 pull request). The maintainer + checks the expiry of `PSGALLERY_API_KEY` first, merges, and tags. +3. #34 waits for a tester until 2026-11-02 (Decision 23, option 3; checklist: `Tests/Lab/Non-Windows-File-Server-Test.md`). On that date the maintainer chooses between waiting longer and accepting the untested risk with a release-note caveat. No agent can accept it. -5. Of the two LOW findings of the security review (record, Limits), the - swallowed initialization errors of `GetEffectiveAccess` are fixed in rc8 - (`25fe775`, #127): an error instead of a false "no access", and the warning - only with a result. He still decides the other: the ACL of the stage - folders under `C:\` in the lab kit (they inherit Authenticated Users: - Modify; protecting them is a design change of the controller and needs a new - acceptance). rc9 adds to the help that a local standard user who asks about - a domain account still gets "Access is denied" (Decision 27). -6. Handoff 5 is done and merged (Evidence). Decided on 2026-10-19 (Decision - 21): the hard-link names under another root stay a known limit; the pages - and the CHANGELOG say so since rc8. The tests-only round for the plain items - (68 `budget` mentions) ran on 2026-10-20: four implementers, one - `ParameterSets.*` file each, merged as #129: 89 `It` blocks, 121 cases, the - suite 1,494 to 1,615 per configuration, 0 failed; 38 of 64 sets closed, 26 - with a leftover (16 Limit, 7 MaintainerDecision, 3 would-pin), no defect; - report `Tests/Coverage/Quality-Gate-Test-Round-2026-10-20.md`. The runner's - counts equal the local run in three CI runs. No plain gap is left. A defect - that a test finds needs his decision and rc9. Decision 27 settles the rest: - rc9 fixes the 10 rows and the piped optional parameters (designs to - follow); the audit paths over SMB are accepted (#34); the tests for the 8 - getters follow rc9. +4. Open housekeeping: keep or replace the matrix VMs (about 60 GB, saved between + runs) and the evaluation client (it shuts down every hour; `OSWin11E` is + off); a domain cell for Windows 11 26H1, whose client loses the secure + channel to the Server 2025 domain controller; the cleanup list before the + archive (AppVeyor, Read the Docs, wiki, `test/transfer`, old checkpoints) is + the maintainer's. The tests-round report still says that the new tests "have + not run on Windows Server 2019/2022/Windows 11"; the 24 lab runs of + 2026-10-21 changed that (fix in a later documentation pull request). +5. Of the two LOW findings of the security review, the swallowed initialization + errors of `GetEffectiveAccess` are fixed in rc8; he still decides the other: + the ACL of the stage folders under `C:\` in the lab kit (they inherit + Authenticated Users: Modify; protecting them is a design change of the + controller and needs a new acceptance). +6. Known limits after rc9, for the archive (Decision 27): `Get-FileHash2 + -Algorithm` keeps the silent default for a piped value that does not convert; + three settings still read their value with an unchecked cast; + `PrivilegeEnabler` is not disposed in some paths; `Get-NTFSEffectiveAccess` + fails with an `ArgumentOutOfRangeException` on a FAT32 volume or an item with + a NULL DACL (older than rc9); 9 of the 17 owner-restore handlers and the + error branch of `Get-NTFSOrphanedAccess` cannot be pinned by a test. 7. Do not release stable 5.0.0 or equate a percentage with gate closure. diff --git a/.memory-bank/debugging-insights.md b/.memory-bank/debugging-insights.md index 54cbbb3..f0fc6d0 100644 --- a/.memory-bank/debugging-insights.md +++ b/.memory-bank/debugging-insights.md @@ -36,6 +36,11 @@ fails without it (Decision 16). both: two mutations proved it), and is proved red on the previous build and green on the new one in all four configurations (`Tests/ItemCmdlets.Tests.ps1`, `Tests/ObjectApis.Tests.ps1`). +- The argument completers of rc9 had the same flaw (`WildcardPattern` with + `IgnoreCase` only: `THISFOLDERO` found nothing under `tr-TR`); the + second review found it, not the scan. A Turkish test word must put a capital + `I` against a lowercase `i` of the name: `NOPROPAGATEINH` faces the capital + `I` of `Inherit` and passes without the fix, so prove every row red first. ## A test oracle that is wrong on a domain member @@ -148,6 +153,17 @@ fails without it (Decision 16). completion of the names has to be rebuilt (quotes, wildcards, declaration order); help shows `Object`. Probe every form of a value before you write a claim, and ask a reviewer for the negative space. +- PowerShell accepts a comma list or an array for an enumeration that is not + `[Flags]` and combines the numbers bit by bit (a logical or): + `-AppliesTo 'ThisFolderOnly,FilesOnly'` made a `FilesOnly` entry and + `-AccessType 'Allow,Deny'` a `Deny` entry (4.2.6 and rc8 alike). The + conversion rejects a list for such an enumeration, in whatever kind of + collection it comes; a single name and a one-element collection stay valid. + A matrix of valid shapes, run on the published build and on the new one, + showed that exactly the 9 list rows changed. Code that opens a one-element + collection needs a depth limit: an array that holds itself hung the first + version (the binder of rc8 ends the host with a stack overflow on it), so + the conversion opens at most 32 levels and reads at most two elements. - PowerShell calls the getter of a by-property-name parameter once per command, when a piped object first binds it (`p-getter-calls.ps1`). A test that must visit it pipes an object that has the property. A property getter diff --git a/.memory-bank/decisions/0027-open-items-before-5.0.0.md b/.memory-bank/decisions/0027-open-items-before-5.0.0.md index 4be75d6..8b01854 100644 --- a/.memory-bank/decisions/0027-open-items-before-5.0.0.md +++ b/.memory-bank/decisions/0027-open-items-before-5.0.0.md @@ -164,6 +164,30 @@ decided; the rest is to be chosen. Recommended defaults are the agent's. folder). The findings became follow-up commits, and the branch `ai/rc9` was rebuilt with `git cherry-pick` in the order of each chain, so every fix sits in the commit of its item and any item can still be dropped. +- Round 2 (brief `rc9\REVIEW-BRIEF-2.md`): two reviewers read the final tree + (scope A the four add and remove cmdlets, scope B everything else), then + checked the fixes of their own findings. No Blocker and no Major; nine Minor + findings: five wrong or incomplete statements in the pages and the CHANGELOG + (a script block "was silently ignored" when it was evaluated per object; + `-AppliesTo $null` keeps the binder's error; the carry-over of the scope + affected only objects with one flags property; the descriptor sets that go + on after a failing descriptor are a breaking change; the PowerShell 7 list of + patterns was too narrow), the trailing blank and `..` of the filter + (documented, not changed), a stale header of two test files, the completers + without `CultureInvariant` (fixed), and a list for `-AccessType` and + `-AppliesTo` whose numbers PowerShell combines bit by bit (the maintainer + chose on 2026-10-21 to reject it in rc9; older than rc9, the same in + 4.2.6). Two more checks of the fixes found that the rejection could be + bypassed through other kinds of collection (a hash set, a queue, the keys of + a dictionary, a LINQ result, a one-element collection that holds a comma + string), that a collection that holds itself never returned (the binder of + rc8 ends the host with a stack overflow on it), and that the message named + the type, not the typo: fixed in `e39aeed` and `da41a8e`, each with tests + that were red first (32 and 28 rows). Final suite on `de67883`: 2,116 cases + per configuration, 0 failed in four configurations (rc8: 1,615); the pages + and the help file are a fixpoint; PSScriptAnalyzer finds nothing in the 11 + changed scripts; the public surface equals the validated candidate; a matrix + of valid shapes differs from the published rc8 in exactly 9 list rows. What the review found: diff --git a/.memory-bank/progress.md b/.memory-bank/progress.md index bec16a0..f0e3360 100644 --- a/.memory-bank/progress.md +++ b/.memory-bank/progress.md @@ -17,51 +17,31 @@ merged #125 (Handoff 5) and #124 (Dependabot) and decided the path to stable (Decision 21, "Closing the gate"); on 2026-10-20 he merged #126 (the decisions) and #127 (the rc8 fix and label) and tagged rc8; on 2026-10-21 he merged #128 (the rc8 record), #129 (tests), and #130 (this file). The published rc7 and -rc8 passed their lab acceptance in the matrix and in the first lab. Stable -Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl -(Decision 18). +rc8 passed their lab acceptance in the matrix and in the first lab. rc9 +(Decision 27) is built on the local branch `ai/rc9` and waits for his push, +pull request, merge, and tag. Stable Gallery version: 4.2.6. After 5.0.0, +archive in favor of WindowsAccessControl (Decision 18). ## Recent milestones -- 2026-10-02 to 2026-10-06: documentation/help aligned with source, CI and - wiki moved to GitHub Actions, versioning/release automation established, - and prereleases rc1 to rc4 published. Earlier detail is in git, - `CHANGELOG.md`, `Docs/Version-History.md`, and Decisions 1 to 19. -- 2026-10-07: lab comparison of rc2/rc4 reproduced #34 over SMB and proved - changed-section writes preserve the owner. Remote effective-access - fallback returned no result; fixed test-first for rc5 (Decision 20). -- 2026-10-08: #114 merged (`fcb370e`), rc5 published and live-tested. - Decision 21 established the quality gate. Corrected four-run coverage: - rc5 58.1% sequence points/38.0% branches, not the initial one-run result. -- 2026-10-08: rc6 Phase 2 (basic-user CI, parameter-set and error tests, - expanded domain/SMB cases, fixes for privilege cleanup, path resolution, - ownership retries, item conflicts, output equality, inherited flags; suite - 677, 68.14% sequence/44.32% branches; lab acceptance of `7b0781f` passed; - two review passes) and rc7 (Decision 22: breaking link binding and error - changes, SimpleAccess traversal, cross-volume folder preservation, named - effective-access warnings; suite 712; one review without Blocker or Major; - lab candidate `dc6e9f5`: 326 passed, 2 skipped, cleanup verified). -- 2026-10-08: #115 merged (`b51d970`) and tagged rc6. Release run - `37839669028` failed with HTTP 409 after Gallery publication. The log - does not establish the previously assumed initial timeout/retry cause. - Published rc6 live tests differed only in rc7's warning expectation. -- 2026-10-09: release attempt 2 succeeded; rc6 GitHub prerelease and zip - appeared at 07:01:34 UTC. #116 passed CI on `d25647d`. -- 2026-10-09: autonomous follow-up on `ai/quality-gate-coverage` (#117, then - #120), through `3442194`: 202 cases above rc7; fixed rooted result paths and - the first-hidden-item omission; publication recovery verifies the exact - SHA-512 identity, not merely the version. Suite: 914 per configuration, zero - failures; 2,641/3,559 sequence points (74.21%), 974/1,933 branches (50.39%). - Live comparison: candidate 330 passed, 0 failed, 2 expected skips (`7594e0c`). -- 2026-10-09: handoff 1 (#118): suite 914 to 1,310 per configuration, zero - failures; 3,192/3,634 sequence points (87.84%), 1,273/1,978 branches; all 231 - unvisited methods classified (223 explained, 8 open). Eleven defects fixed, - ten with a guard that is red before the fix and green after it (76 rows red - at the base), among them a later command's exception that cmdlets swallowed - (a `throw` made `Remove-Item2` remove the next item) and a privilege left - enabled. Lab acceptance, `83149ee` against `f11ff41`: 486 passed, 0 failed, 2 - expected skips against 338 passed, 148 failed. Report in `Tests/Coverage`; - record `Tests/Lab/Acceptance-2026-10-09-quality-gate-paths.md`. +- 2026-10-02 to 2026-10-09: documentation and help aligned with the source, CI + and wiki on GitHub Actions, release automation, and rc1 to rc6 published + (rc5: the remote effective-access fallback, Decision 20; rc6 and the rc7 + candidate: Phase 2 and the behavior changes of Decision 22). #114 (`fcb370e`) + and #115 (`b51d970`) merged. The rc6 release run failed with HTTP 409 after + Gallery publication and attempt 2 succeeded (GitHub prerelease 2026-10-09 + 07:01:34Z); the log does not establish the earlier assumed timeout cause. + Detail: git, `CHANGELOG.md`, `Docs/Version-History.md`, Decisions 1 to 22. +- 2026-10-09: the autonomous follow-up (#117, then #120, through `3442194`) and + handoff 1 (#118) took the suite from 202 cases above rc7 to 1,310 per + configuration with zero failures and 3,192/3,634 sequence points (87.84%; + 74.21% before); publication recovery verifies the exact SHA-512 identity. + Eleven defects were fixed, ten with a guard that is red before the fix (76 + rows red at the base), among them a later command's exception that cmdlets + swallowed (a `throw` made `Remove-Item2` remove the next item) and a privilege + left enabled. Lab acceptance, `83149ee` against `f11ff41`: 486 passed, 0 + failed against 338 passed, 148 failed. Report in `Tests/Coverage`; record + `Tests/Lab/Acceptance-2026-10-09-quality-gate-paths.md`. - 2026-10-09 to 10: handoffs 2 to 4 under the maintainer's delegation (decisions D1 to D47 in the night log of the session files). The matrix lab `NtfsSecurityOsMatrixLab` (Server 2019, 2022, 2025, a Windows 11 Enterprise @@ -139,6 +119,19 @@ Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl creates an Allow entry); Decision 27 sets the scope of rc9, the designs were chosen on 2026-10-21, and four work items started (branch `ai/rc9-before-stable`). +- 2026-10-21: rc9 built and reviewed (Decision 27; branch `ai/rc9`, 32 commits + over `d0cb57c`, head `de67883`, local until he pushes). Four implementers + worked test-first in worktrees (the five piped parameters, the 17 handlers + and three inconsistencies, the library items, the filter); the chains were + cherry-picked in order, so every fix sits in the commit of its item. Round 1 + (three read-only reviewers) found a Blocker (the last-dot rule of the + filter) and two Major findings (a named `$null`; a blank value of the other + parameter group, documented); round 2 (two reviewers, three checks) found + only Minor findings, among them completers that were not culture invariant + (`tr-TR`) and a list for `-AccessType` or `-AppliesTo`, which PowerShell + combines bit by bit; he chose to reject it. Final suite on `de67883`: 2,116 + cases per configuration, 0 failed in four configurations (rc8: 1,615); docs + fixpoint; analyzer clean; valid shapes differ from rc8 in 9 list rows only. ## Stable capabilities @@ -152,12 +145,13 @@ Gallery version: 4.2.6. After 5.0.0, archive in favor of WindowsAccessControl ## Open work 1. Decision 21 gate: the published rc7 and rc8 are accepted in the matrix and - the first lab (records); stable follows rc8 (Decision 21, "Closing the - gate"). Do not release 5.0.0 until the other gates close: rc9 (Decision - 27), the decision on #34 on 2026-11-02, and the key check. Release steps: - `Docs/Contributing/05-Releasing.md`; remove the prerelease label, date - `[5.0.0]`, add the last prerelease (rc8) to `$publishedVersions` (never the - version of the manifest), tag through CI. + the first lab (records); stable follows rc9 (Decision 27): after his push, + pull request, merge, and tag of rc9 the agent runs the lab acceptance of + the published bytes (about 70 minutes). Do not release 5.0.0 until the other + gates close: that acceptance, the decision on #34 on 2026-11-02, and the key + check. Release steps: `Docs/Contributing/05-Releasing.md`; remove the + prerelease label, date `[5.0.0]`, add the last prerelease (rc9) to + `$publishedVersions` (never the version of the manifest), tag through CI. 2. Issues: #110's seven items were addressed by rc6, but #115 deliberately used no closing keyword. #34 stays open for non-Windows owner feedback or maintainer acceptance. #16, #21, #45, #89 await reporters. #68 tracks diff --git a/.memory-bank/systemPatterns.md b/.memory-bank/systemPatterns.md index 8f7d292..0da3a5d 100644 --- a/.memory-bank/systemPatterns.md +++ b/.memory-bank/systemPatterns.md @@ -1,6 +1,6 @@ --- status: current -last-verified: 2026-10-19 +last-verified: 2026-10-21 owner: active-agent source: repository and regression evidence --- @@ -15,13 +15,10 @@ source: repository and regression evidence | `NTFSSecurity.Init.ps1` | Loads Security2/privilege assemblies and prepends formatting | | `NTFSSecurity.dll` | 36 PowerShell cmdlets; BaseCmdlet path/privilege behavior | | `Security2.dll` | DACL/SACL objects, owners, inheritance, effective access, Win32 | -| AlphaFS | Long-path files/directories/links | -| PrivilegeControl / ProcessPrivileges | Token privilege operations | +| AlphaFS, PrivilegeControl, ProcessPrivileges | Long-path files/directories/links; token privilege operations | | `en-US/NTFSSecurity.dll-Help.xml` | Committed help generated from cmdlet Markdown | -## Decisions - -Read only task-relevant records; the index controls routing. +## Decisions (read only the task-relevant records; the index routes) | # | Decision | | --- | --- | @@ -51,6 +48,7 @@ Read only task-relevant records; the index controls routing. | 24 | [The operating-system matrix lab](decisions/0024-os-matrix-lab.md) | | 25 | [Four environments are out of scope for the tests](decisions/0025-out-of-scope-environments.md) | | 26 | [No default parameter set for Add and Remove (access, audit)](decisions/0026-no-default-parameter-set-add-remove.md) | +| 27 | [The open items before 5.0.0 and the piped optional parameters (rc9)](decisions/0027-open-items-before-5.0.0.md) | ## Patterns @@ -67,36 +65,38 @@ Read only task-relevant records; the index controls routing. attempts all cleanup, and preserves explicit enables. Dispose has no stream. - Pipeline getters never throw; per-item errors name input and allow continuation. - Folder moves never use CopyAllowed; preserve cross-volume source folders. -- Apply implied Hidden/Force before deciding to emit, including the first item. + Apply implied Hidden/Force before deciding to emit, including the first item. - A catch-all for one item's failures passes on what a later command raises - through a Write call (`IsFromLaterCommand`, `PipelineControl`; see - `BaseCmdlets.cs`); add a row to `Tests/PipelineControl.Tests.ps1` for a new - cmdlet. Record an enabled privilege before the next write. -- `Get-ChildItem2 -Filter` matches culture invariant; `*.*` means `*`. + through a Write call (`IsFromLaterCommand`, `BaseCmdlets.cs`); add a row to + `Tests/PipelineControl.Tests.ps1` for a new cmdlet. Record an enabled + privilege before the next write. +- `Get-ChildItem2 -Filter`: one matcher, 5.1 DOS wildcard rules (Decision 27). +- Optional by-name pipeline parameters are `object` + `ParameterConversion` (Decision 27). ### Tests and documentation - Tests import Release in isolated processes, both editions and privilege modes, with guarded sandboxes; a skip needs an eligible counterpart. -- Assert persisted state, errors/targets, continuation, and no failed - PassThru output. Prove new characterization guards with bounded mutations - (one round together only if no guard can fail because of another); restore - source exactly and rebuild before green validation or packaging. A retry - test asserts its precondition (the plain write is denied). +- Assert persisted state, errors/targets, continuation, and no failed PassThru + output. Prove characterization guards with bounded mutations (together only + if no guard can fail because of another); restore source and rebuild before + green runs or packaging. A retry test asserts its precondition (the plain + write is denied). - CI scripts and focused runs set `Stop`: a test that needs a non-terminating error names `-ErrorAction Continue`. Don't name a test variable like an automatic variable (`$foreach`): Pester runs the block inside a foreach. - Fixture DACLs use .NET SetAccessControl, not Set-Acl's unintended SACL writes. - Scope/descendant expectations are independent of the production converter. - Desktop platyPS: generate help, rebuild, round-trip unchanged, check links; - platyPS 0.14.2 turns paired asterisks into emphasis, even in backticks. + 0.14.2 turns paired asterisks into emphasis, even in backticks, and + `Update-MarkdownHelp` reads `Position` from the committed help file. - Live tests use only approved lab targets, SMB then independent server state; Get/SetFileSecurity preserves stored DACLs; rights oracles use S4U tokens. - A suite that is green on the host and CI misses defects that need a domain member or another token (the matrix found three): also run a domain member, other builds, and a basic user; a failure that follows cell order points to - stale account state (Decision 24). Oracles differ there too: `Get-Acl -Audit` - reads an item without audit entries as SACL-protected; read the SACL alone. + stale account state (Decision 24). `Get-Acl -Audit` reads an item without + audit entries as SACL-protected; read the SACL alone. ### CI, publication, and integration diff --git a/.memory-bank/techContext.md b/.memory-bank/techContext.md index 46ec278..c3e06c1 100644 --- a/.memory-bank/techContext.md +++ b/.memory-bank/techContext.md @@ -42,9 +42,9 @@ source: repository and executable evidence ## Constraints -- Manifest: ModuleVersion 5.0.0, prerelease rc8, published 2026-10-20 (tag at - `c719197`). Latest stable 4.2.6. `$publishedVersions` ends at rc7; the reuse - test fails if it holds the manifest's version, so the stable change adds rc8. +- Manifest: ModuleVersion 5.0.0, prerelease rc8 (tag at `c719197`; `ai/rc9` + sets rc9). Latest stable 4.2.6. `$publishedVersions` ends at rc7; the reuse + test fails if it holds the manifest's version, so rc9 adds rc8, stable rc9. - Changed-section writes preserve unchanged owner/group/DACL/SACL (19). Roots use root-folder APIs, not AlphaFS device security (#41). - CHANGELOG contains user-visible changes only (7); tests and CI-only fixes From fcdc2cd57367833dc8f973109a102cd4f43ba775 Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Wed, 21 Oct 2026 18:32:32 +0000 Subject: [PATCH 7/7] docs(memory-bank): record the last checks of round 2 and the final head of rc9 Record that the branch ai/rc9 ends at 696ac38 (36 commits over d0cb57c, 2,162 cases per configuration, 0 failed), that the last two checks of round 2 found four Nits in the message formatter and in the reading of a sequence (all fixed test-first, the last one at its root), that both reviewers closed with no finding, and that a collection that holds itself still ends the host through the three flags parameters, as in rc8, which stays a known limit. The lesson for the next agent: a failing Dispose must never change what was read. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- .memory-bank/activeContext.md | 24 ++++++++------ .memory-bank/debugging-insights.md | 26 +++++++++++++++- .../decisions/0027-open-items-before-5.0.0.md | 31 ++++++++++++++++--- .memory-bank/progress.md | 17 +++++----- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/.memory-bank/activeContext.md b/.memory-bank/activeContext.md index 2e06b75..ba9f45c 100644 --- a/.memory-bank/activeContext.md +++ b/.memory-bank/activeContext.md @@ -17,7 +17,7 @@ passed; lab acceptance of the published bytes 10:38 to 11:47Z, record #129 (08:24Z), and the Memory Bank #130 (08:47Z). The last prerelease before the stable 5.0.0 is rc9 (Decision 27). The branch -`ai/rc9` (base `d0cb57c`, 32 commits, head `de67883`) is complete and +`ai/rc9` (base `d0cb57c`, 36 commits, head `696ac38`) is complete and validated; it is local until the maintainer pushes it, opens the pull request (body: `C:\Temp\ntfs-rc9\final-msgs\pr-rc9-body.md`, temporary), merges it, and tags `5.0.0-rc9`. It contains: the five piped parameters of `Add-` and @@ -31,7 +31,7 @@ the Windows PowerShell 5.1 rules; the library fixes 3.1 to 3.3 and 3.10; `Set-NTFSSecurityDescriptor` at position 1; tests that bind four parameters by property name; label `rc9`. -Validation of `de67883`: the full suite in the four CI configurations, 2,116 +Validation of `696ac38`: the full suite in the four CI configurations, 2,162 cases each, 0 failed (rc8: 1,615; skipped 27, 359, 58, and 390, so every new case runs where it can); the pages and the help file are a fixpoint (0 drift, 0 broken links; the help file is identical after a second generation); @@ -42,13 +42,16 @@ matrix of valid shapes of the five parameters, run on the published rc8 and on this build in both editions, differs in exactly the 9 list rows of `Add-NTFSAccess`. Two review rounds (Decision 27, "Built in rc9"): round 1 on the first integration found a Blocker (the last-dot rule of the filter) and two -Major findings; round 2 on the final tree and three checks of its fixes found -only Minor findings (wrong statements in the pages, completers that were not -culture invariant, the list for `-AccessType` and `-AppliesTo`, ways around -that rejection, a collection that holds itself); all are fixed with a test -that is red without the fix, or decided. A blank, `$null`, or `DBNull` value of -the other parameter group is `AmbiguousParameterSet` (documented, not -restructured). +Major findings; round 2 on the final tree and five checks of its fixes found +only Minor findings and Nits (wrong statements in the pages, completers that +were not culture invariant, the list for `-AccessType` and `-AppliesTo`, ways +around that rejection, a collection that holds itself, a message formatter that +threw, an enumerator that fails in `Dispose`); all are fixed with a test that +is red without the fix, or decided, and both reviewers closed their last +findings with "no finding" on `696ac38`. A collection that holds itself still +ends the host through the three flags parameters, as in rc8 (known limit). A +blank, `$null`, or `DBNull` value of the other parameter group is +`AmbiguousParameterSet` (documented, not restructured). Open before the stable pull request: the pull request, merge, and tag of rc9 (maintainer); the lab acceptance of the published rc9 (agent, about 70 @@ -71,7 +74,8 @@ Decisions 22 and 24 on 2026-10-19 and decides 23 on 2026-11-02. - Evidence of rc9 is outside git, in the session folder `816cf47d-2f80-4eba-8ac9-41702c49560b\files\rc9`: the specs and review briefs, `suite-full1` (first integration), `suite-final`, `suite-final2`, - `suite-final3`, and `suite-final4` (the head `de67883`), the probes (`p-*.ps1`, + `suite-final3`, `suite-final4`, `suite-final5`, `suite-final6-b436423`, and + `suite-final7-696ac38` (the head), the probes (`p-*.ps1`, `fixb-probe`, `shapes-r2`, `Run-Oracle.ps1`, `Run-Pathological.ps1`), the published rc8 (`rc8-published`), and the analyzer and surface results. The review probes of the reviewers are in `C:\Temp\ntfs-rc9\review*-probes-*` diff --git a/.memory-bank/debugging-insights.md b/.memory-bank/debugging-insights.md index f0fc6d0..0bc4942 100644 --- a/.memory-bank/debugging-insights.md +++ b/.memory-bank/debugging-insights.md @@ -163,7 +163,31 @@ fails without it (Decision 16). showed that exactly the 9 list rows changed. Code that opens a one-element collection needs a depth limit: an array that holds itself hung the first version (the binder of rc8 ends the host with a stack overflow on it), so - the conversion opens at most 32 levels and reads at most two elements. + the conversion opens at most 32 levels and reads at most two elements. The + three flags parameters still hand such a collection to PowerShell's own + conversion, which ends the host with a stack overflow, as in rc8; not fixed + (no real input builds one, and a test would end the Pester process too). +- The message of a bad value is built inside a catch block, and a formatter + there must not throw: `Describe` called `ToString` of the one element outside + a guard, so an element whose `ToString` throws (a script method) ended a + piped command with an `ExtendedTypeSystemException` instead of one error for + that item (found by the last delta check of the second review; the version + before named a collection by its type and never formatted an element). Wrap + the whole formatter and fall back to the type name, in the short form + (`Type.ToString`; `FullName` spells out the assembly of every generic + argument). A test that pins a limit (ten elements named, two elements read) + is green on the code that it guards: prove it with a mutant of the limit (no + limit: 4 rows red; a limit of nine: 6 rows red). +- A loop that stops early runs `Dispose` of the enumerator, and `Dispose` can + fail: the catch of `TakeOneValue` returned the collection to PowerShell's + conversion, which combines a list bit by bit, so a sequence whose enumerator + throws in `Dispose` let a list through. The first patch (`isList = count > + 1` in the catch) fixed the reported shape (two elements) and left its + sibling (one element that holds a comma list); the closing check found it. + Fix the root: read with an explicit enumerator and release it in its own + guard, so that a failing release never changes what was read. The test needs + a compiled stand-in (`Add-Type`, as `PipelineControl.Tests.ps1` does); no + built-in enumerator fails in `Dispose`. - PowerShell calls the getter of a by-property-name parameter once per command, when a piped object first binds it (`p-getter-calls.ps1`). A test that must visit it pipes an object that has the property. A property getter diff --git a/.memory-bank/decisions/0027-open-items-before-5.0.0.md b/.memory-bank/decisions/0027-open-items-before-5.0.0.md index 8b01854..784d1dc 100644 --- a/.memory-bank/decisions/0027-open-items-before-5.0.0.md +++ b/.memory-bank/decisions/0027-open-items-before-5.0.0.md @@ -183,11 +183,23 @@ decided; the rest is to be chosen. Recommended defaults are the agent's. string), that a collection that holds itself never returned (the binder of rc8 ends the host with a stack overflow on it), and that the message named the type, not the typo: fixed in `e39aeed` and `da41a8e`, each with tests - that were red first (32 and 28 rows). Final suite on `de67883`: 2,116 cases - per configuration, 0 failed in four configurations (rc8: 1,615); the pages - and the help file are a fixpoint; PSScriptAnalyzer finds nothing in the 11 - changed scripts; the public surface equals the validated candidate; a matrix - of valid shapes differs from the published rc8 in exactly 9 list rows. + that were red first (32 and 28 rows). The last two checks found four Nits in + code that those fixes added or kept: the formatter of the message threw when + the text of an element throws (a terminating error that stopped a piped + command), its fallback named a generic type with the assembly of every type + argument, and an enumerator that throws in `Dispose` turned a list into a + value that PowerShell converts (first for two elements, then for one element + that holds a list): fixed in `ec58a18`, `ce34395`, `b436423`, and `696ac38`, + with 24, 2, 4, and 8 rows that were red first, and the pins of the limits + proved with two mutants. The last commit fixes the root, + not the shape: the collection is read with an explicit enumerator that is + released in its own guard, so a failing release changes nothing of what was + read. Final suite on `696ac38`: 2,162 cases per configuration, 0 failed in + four configurations (rc8: 1,615); the pages and the help file are a + fixpoint; PSScriptAnalyzer finds nothing in the 11 changed scripts; the + public surface equals the validated candidate; a matrix of valid shapes + differs from the published rc8 in exactly 9 list rows; both reviewers closed + their findings with "no finding". What the review found: @@ -219,3 +231,12 @@ Known limits, kept and to be stated to the maintainer: stays undisposed, a known limit of the .NET API. - In PowerShell 7, the case folding of `-Filter` differs from NTFS for a few exotic letters (finding F7 of the review; not fixed). +- A collection that holds itself, given to `-InheritanceFlags`, + `-PropagationFlags`, or `-AuditFlags`, ends the host with a stack overflow + inside PowerShell's own conversion, exactly as in rc8 (both reviewers + reproduced it in both editions, without the module too: any typed parameter + or cast does it). `-AccessType` and `-AppliesTo` reject it. Not fixed: no + real input builds such an object, a guard for the flags parameters would + need a visited-set walk of every argument, and a regression test would end + the Pester process before the fix. Named in the pull request text, not in + the CHANGELOG (user-visible changes only). diff --git a/.memory-bank/progress.md b/.memory-bank/progress.md index f0e3360..045b56c 100644 --- a/.memory-bank/progress.md +++ b/.memory-bank/progress.md @@ -119,19 +119,20 @@ archive in favor of WindowsAccessControl (Decision 18). creates an Allow entry); Decision 27 sets the scope of rc9, the designs were chosen on 2026-10-21, and four work items started (branch `ai/rc9-before-stable`). -- 2026-10-21: rc9 built and reviewed (Decision 27; branch `ai/rc9`, 32 commits - over `d0cb57c`, head `de67883`, local until he pushes). Four implementers +- 2026-10-21: rc9 built and reviewed (Decision 27; branch `ai/rc9`, 36 commits + over `d0cb57c`, head `696ac38`, local until he pushes). Four implementers worked test-first in worktrees (the five piped parameters, the 17 handlers and three inconsistencies, the library items, the filter); the chains were cherry-picked in order, so every fix sits in the commit of its item. Round 1 (three read-only reviewers) found a Blocker (the last-dot rule of the filter) and two Major findings (a named `$null`; a blank value of the other - parameter group, documented); round 2 (two reviewers, three checks) found - only Minor findings, among them completers that were not culture invariant - (`tr-TR`) and a list for `-AccessType` or `-AppliesTo`, which PowerShell - combines bit by bit; he chose to reject it. Final suite on `de67883`: 2,116 - cases per configuration, 0 failed in four configurations (rc8: 1,615); docs - fixpoint; analyzer clean; valid shapes differ from rc8 in 9 list rows only. + parameter group, documented); round 2 (two reviewers, five checks) found + only Minor findings and Nits, among them completers that were not culture + invariant (`tr-TR`) and a list for `-AccessType` or `-AppliesTo`, which + PowerShell combines bit by bit; he chose to reject it. Final suite on + `696ac38`: 2,162 cases per configuration, 0 failed in four configurations + (rc8: 1,615); docs fixpoint; analyzer clean; valid shapes differ from rc8 in + 9 list rows only; both reviewers: no finding. ## Stable capabilities