Browse Source

Merge pull request #121 from raandree/ai/memory-bank-integration-state

docs(memory-bank): record the integrated stack and curate the budgets
ai/gate3-published-rc7-acceptance
Raimund Andrée 1 day ago
committed by GitHub
parent
commit
6dd799fa96
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 282
      .memory-bank/activeContext.md
  2. 13
      .memory-bank/decisions/0015-merge-stacks-with-merge-commits.md
  3. 104
      .memory-bank/deployment-notes.md
  4. 164
      .memory-bank/progress.md
  5. 99
      .memory-bank/systemPatterns.md
  6. 195
      .memory-bank/techContext.md

282
.memory-bank/activeContext.md

@ -9,186 +9,122 @@ source: current task evidence
## Current focus ## Current focus
The maintainer asked on 2026-10-09 at 21:21 UTC to continue with the release-gate State at 2026-10-10 12:40 UTC: the maintainer integrated the release-gate stack
handoffs and to decide and report later. On 2026-10-10 at 09:10 UTC he merged into `master` (`fa0701b`, CI green at 11:40Z): #116 (rc7, `8a6be9f`), #120
#116 (rc7, merge commit `8a6be9f`; rc7 is neither tagged nor published). His (`bdb9981`; it replaced #117, which GitHub closed unmerged when the branch
`--delete-branch` also deleted the base branch of #117, so GitHub closed #117 deletion after #116 removed its base, see Decision 15), #118 (`03bef2c`,
unmerged; nothing is lost (`ai/quality-gate-coverage` is intact at `f11ff41`, handoff 1, the paths), and #119 (`fa0701b`, handoff 2, the operating-system
and the merge into `master` is conflict-free by simulation), and a new pull matrix). He tagged `fa0701b` as `5.0.0-rc7` at about 12:20Z, and rc7 is
request replaces it (Next step 1). Handoff 1 (paths) is draft #118 (`83149ee`, published (Gallery 12:30:57Z, GitHub 12:31:09Z); 4.2.6 stays the stable
CI green, base `ai/quality-gate-coverage`; rc6 is the latest published Gallery version. rc7 contains the Phase 2 behavior changes, the path tests and
candidate, 4.2.6 the stable Gallery version). Handoff 2 (operating-system fixes, and the three module fixes of the matrix (`962887a`, `fdd7a8b`). The
matrix) is draft #119 (`49734ef`, CI green, base `ai/quality-gate-paths`): the Memory Bank update is pull request #121 (CI green at 12:33Z, open when this was
lab `NtfsSecurityOsMatrixLab`, three fixes of the module in two commits written). Stable 5.0.0 stays gated (Decision 21).
that the matrix found (`962887a`, `fdd7a8b`), the kit, the controller changes, and the
record `Tests/Lab/Acceptance-2026-10-10-os-matrix.md` (Decision 24, proposed).
The final local candidate `fdd7a8b` passes the module's suite on five operating
systems and the host (24 runs, no failure) and the live controller in three
cells of the matrix (1,374 passed, 0 failed, 12 skipped) and in the first lab,
where case 9 runs (245 passed, 0 failed, 1 skipped per edition). Handoff 3: Decision 22 was confirmed
under the delegation and stays proposed; nothing is published. Handoff 4:
Decision 23 (the #34 dossier); the risk acceptance is the maintainer's. The
agent's decisions of the night are D1 to D46 in
`decisions-night-2026-10-09.md` of the session files. Stable 5.0.0 stays gated.
The earlier state of handoff 1, from the reviewed head `f11ff41` of #117: 28 The maintainer asked on 2026-10-09 at 21:21 UTC to continue with the
commits, which the maintainer pushed as draft #118. Every C# method that no test release-gate handoffs and to decide and report later. The agent's decisions are
visits is classified (223 explained, 8 open for the maintainer), and the D1 to D47 in `decisions-night-2026-10-09.md` of the session files. Decisions
other paths have behavior tests. Eleven defects were fixed, ten of them 22 (Phase 2), 23 (the #34 dossier), and 24 (the matrix) are proposed: the agent
with a regression guard that is red before the fix and green after it (owner confirmed Decision 22 under the delegation, and neither that nor any risk
restore, `InheritedFrom`, a later command that ends the pipeline or throws, acceptance is the maintainer's.
also at the error, verbose, and debug streams, `-Filter` brackets, null, and
`*.*`, public object APIs, a privilege left enabled); the leak of a native
buffer has no observable guard. The lab acceptance of those fixes was repeated
on 2026-10-09 (below); the published package still needs its own acceptance
in gate 3. Decisions 21/22 and stable 5.0.0
remain gated; Decision 22 is proposed: the agent confirmed all ten choices
on 2026-10-09 under the maintainer's delegation, and his own confirmation is
open.
## Evidence ## Evidence
- rc6 Release run `37839669028`, attempt 2, succeeded; GitHub prerelease - rc6 Release run `37839669028`, attempt 2, succeeded; GitHub prerelease with
with zip appeared 2026-10-09 07:01:34 UTC. First attempt proves HTTP 409 zip appeared 2026-10-09 07:01:34 UTC. The first attempt proves HTTP 409
after Gallery publication, not the previously assumed retry chronology. after Gallery publication, not the earlier assumed retry chronology.
- #116 was merged into `master` on 2026-10-10 at 09:10:12Z (merge commit - Integration on 2026-10-10 (UTC): #116 merged 09:10, #117 closed unmerged
`8a6be9f`, head `d25647d`); rc7 isn't tagged or published. #117 was closed 09:10:16 (events `base_ref_deleted`, `closed`), #120 merged 10:50, #118
unmerged at 09:10:16Z (events `base_ref_deleted`, `closed`). 11:12, #119 11:28, head branches deleted 11:34, CI on `master` at `fa0701b`
- Local changes: deletion/ownership guards (`a97e46f`); all scopes and green 11:40. A `git merge-tree` simulation of the chain was conflict-free and
inheritance (`e7ee203`); absolute basic-user results (`51dec86`); ended in the tree of the matrix branch.
exact-package publication recovery (`95b827e`); first-hidden-item fix - rc7 on 2026-10-10: tag at `fa0701b` about 12:20Z, CI run `38051611526`
(`d610372`); Force/descriptor guards (`3442194`); SMB regression above. green, Gallery 12:30:57Z, GitHub 12:31:09Z. `Test-PublishedRelease.ps1`
- Hidden omission was reproduced in all four configurations before the (12:33Z): tag commit on `master`, Gallery SHA-512 matches the nupkg, 11
fix. No parameter/design change. Publication tests are wholly mocked; module files identical in nupkg and zip, manifest `5.0.0-rc7`; hashes in the
exact ordinal SHA-512 identity is required, no real upload occurred. deployment notes, evidence in the session folder `published-rc7`.
- At `3442194` (start of Handoff 1): 914 cases per configuration, 2,641/3,559 - Handoff 1 (paths), measured at `5a5d58b` (frozen Release, four configurations,
sequence points (74.21%), 974/1,933 branches (50.39%), 918 unvisited CI wrappers, then AltCover): 1,310 cases per configuration, zero failures
points. All skipped templates had executed counterparts. (baseline `3442194`: 914 cases); coverage 3,192/3,634 sequence points
- Handoff 1 result at `5a5d58b` (frozen Release, four configurations, CI (87.84%) and 1,273/1,978 branches (64.36%), against 74.21% and 50.39%. All 231
wrappers, then AltCover): 1,310 cases per configuration, zero failures; methods with 442 unvisited points are classified: 223 explained, 8 open for
passed/skipped: elevated Desktop 1,286/24, Core 1,255/55; basic Desktop the maintainer. Skip eligibility was checked by row: all 578 skipped rows
1,076/234, Core 1,045/265. Coverage 3,192/3,634 sequence points (87.84%), (137 distinct tests) are executed in two other configurations.
1,273/1,978 branches (64.36%); 231 methods with 442 points stay unvisited, - Eleven defects were fixed, ten with a guard that is red before the fix and
all classified: 223 explained, 8 open. Skip eligibility was checked by row green after it (a red/green matrix over ten states of the branch: 76 rows
from a second full run per configuration: all 578 skipped rows (137 red at the base `f11ff41`, none after the last fix; the leak of a native
distinct tests) are executed in two other configurations. buffer has no guard). Mutation rounds at `5a5d58b`: 25 of 26 detected, M25
- Mutation rounds on the frozen tree at `5a5d58b`: 26 mutations in four (the check by type) an equivalent mutant. The matrix doesn't show that a test
rounds; 25 are detected by their guard in every configuration where it preceded its fix: each fix commit carries both. Report:
runs, and M25 (the check by type, an equivalent mutant) survives as `Tests/Coverage/Quality-Gate-Paths-2026-10-09.md`.
expected. At `d61dffa` three had escaped (the verbose and debug rows ran - Reviews: the custom `security-reviewer` can't start (its model is
under the CI runner's `Stop`, and an Init test could not fail for its unavailable; no override). The built-in `code-review` agent made nine static
branch), which led to `f4a16e1`. A first round at `630926f` had let one passes of the paths work (no Blocker or Major) and four rounds on the matrix
mutation escape, which led to the `-Filter` bracket defect. (one Major, record accuracy, resolved by the replay; Minors corrected); the
- Red/green matrix (measured after the last measurement, because the first built-in `security-review` agent found no exploitable vulnerability and two
red runs were not kept): the final tests of the eight files that guard the LOW items left for the maintainer (Next step 5).
fixes (650 cases per configuration) over the production code of ten states - Live candidate of 2026-10-09 (09:20 to 09:51 UTC): 330 passed, 0 failed, 2
of the branch, built in Release and run with the focused runner (it sets expected skips; published rc6: 326 passed, 4 expected failures, 2 skips; the
`Stop` like the CI wrappers) in the four configurations. 76 rows (73 in the 11 tested files match the ZIP. Independent probes verified the fixture
basic configurations) fail at the base `f11ff41`, each is green at the step removal on six machines (`Tests/Lab/Acceptance-2026-10-09-quality-gate.md`).
of its fix, none breaks later, and `d44a200` has none (the control). Defect - Six checkpoints report Standard even after a successful ProductionOnly probe;
9 (the native buffer) has no guard. The matrix does not show that a test was policy restored, no restore performed: don't claim verified Production
written before its fix: each fix commit carries both, and the red runs of rollback evidence.
that time were not kept. - Lab acceptance of the paths fixes, 2026-10-09 20:41 to 21:42 UTC: candidate
- Review: custom `security-reviewer` could not start (model unavailable); the `83149ee` against its base `f11ff41`, the same 244 tests per edition (78
built-in read-only `code-review` agent made nine static passes: no Blocker new): 486 passed, 0 failed, 2 expected skips against 338 passed, 148 failed
or Major; its Minor findings led to the `*.*`, help, test, later-command, (each green on the candidate); fixture removal verified. Record:
error-stream, and privilege fixes. Report: `Tests/Lab/Acceptance-2026-10-09-quality-gate-paths.md`.
`Tests/Coverage/Quality-Gate-Paths-2026-10-09.md` with an appendix of - Operating-system matrix, 2026-10-10 (record
explanations and CSV rows; raw evidence is in the session folder `Tests/Lab/Acceptance-2026-10-10-os-matrix.md` with CSV tables): the suite of
`4b12e2f4-d4c7-4a5d-883a-ddb7421c4848\files\qg-paths`. the final candidate `fdd7a8b` passes on OSFile19/22/25, OSWin11E, OSWin11, and
- Live packaged candidate, 09:20 to 09:51 UTC: 330 passed, zero failed, the host (24 runs, no failure; the baseline `83149ee` fails 4 elevated and 20
two expected Server-module skips. Published rc6: 326 passed, four basic-user tests on OSFile22 and OSFile25); the live controller passes in
expected failures (Hidden and rc7 warning text in each edition), two three cells (1,374 passed, 0 failed, 12 skipped) and in the first lab with
skips. Tested folder and all 11 ZIP files are byte-identical. case 9 (245 passed, 0 failed, 1 skipped per edition; fixture removed and
- Temporary host result verifier failed on Desktop JSON wrapping/full verified). The Admin-role effective-access failures in earlier cells were
test names; corrected verification passed on unchanged raw results in stale account state, not the module: in a replay the baseline failed two of
both editions. Cleanup wrapper's broad Error.Count was not acceptance three cells and the candidate one, and one lifetime of about ten minutes fits
proof. Independent probes verified all fixture objects/members/profiles 43 runs of 27 cells (the Windows mechanism is unknown). The controller names
gone from six machines. Raw failing markers and corrected evidence kept. the case-3 account anew for each fixture (`1dec389`); four more cells with it
- Review of the lab candidate: one read-only independent code review passed. A dry run of `Run-MatrixSequence.ps1 -Version 5.0.0-rc6` showed that
approved, high confidence, no significant findings or confirmed exploit. the published-package path works. Labs at 07:50 UTC on 2026-10-10: no fixture
- Six checkpoints exist but report Standard, even after a successful or probe residue; `OSWin11E` shuts itself down an hour after its start.
temporary ProductionOnly probe; policy restored, no restore performed. - Raw evidence is outside git: the session folder
Do not claim verified Production rollback evidence. `4b12e2f4-d4c7-4a5d-883a-ddb7421c4848\files` (`qg-paths`, the matrix runs, the
- Lab acceptance of the paths fixes, 20:41 to 21:42 UTC on 2026-10-09: the night log) and
candidate `83149ee` and its base `f11ff41` ran the same 244 tests per `26f151b6-e46f-49bd-9398-b27e20603949\files\quality-gate-3442194-20261009`.
edition (78 new, case 10) from their extracted packages. Candidate 486
passed, 0 failed, 2 expected skips; baseline 338 passed, 148 failed, each
green on the candidate; both editions gave the same counts. Fixture removal
verified by a separate read-only check in four domains and on both file
machines; six checkpoints (Standard type, no restore). Record, results CSV,
and limits: `Tests/Lab/Acceptance-2026-10-09-quality-gate-paths.md`. This
covers the gate-3 handoff table of the path report, except the published
package and the other operating systems.
- Wider matrix not deployed: 13 Server 2025 VMs; Windows 11/2019/2022
media present, OS detection cache empty. #34 has no reply since Oct 6.
- Full evidence: session artifact `quality-gate-3442194-20261009`;
repository report `Tests/Lab/Acceptance-2026-10-09-quality-gate.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` on OSFile19,
OSFile22, OSFile25, OSWin11E, OSWin11, and the host, four configurations each,
zero failures, skipped tests identical to the host's; the baseline `83149ee`
(run on OSFile22 and OSFile25) fails 4 elevated and 20 basic-user tests. Live: run
`rc7l`, three cells, 1,374 passed, 0 failed, 12 skipped. First lab (run `fl1`,
case 9 included, both editions): 245 passed, 0 failed, 1 skipped per edition,
fixture removed and verified clean. The Admin-role
effective-access failures of the earlier cells were not the module: in a replay
(`ab0` to `ab6`) the baseline failed two of three cells and the final candidate
one of three (not counting the warm-up `ab0`), and one model (the remote
authorization managers answer for an account name for about ten minutes after
the account was created again) fits all 43 Admin-role runs of 27 cells; the
Windows mechanism is unknown. The controller now names the account of case 3
anew for each fixture (`1dec389`); four more cells with it (`ab7` to `ab10`)
passed, two of them where the model predicts a failure for a reused name.
Reviewed by the built-in code-review agent (custom `security-reviewer`
unavailable): approve with Minor, fixed; a second review found one Major
(record accuracy), addressed by the replay; a follow-up review found no
Blocker or Major and five Minors, corrected; a second follow-up review found no
Blocker or Major and four Minors, corrected. The built-in `security-review`
agent (the custom reviewer is still unavailable) found no exploitable
vulnerability in the module changes and two LOW items that are not changed
(Next step 6). A dry run of `Run-MatrixSequence.ps1 -Version 5.0.0-rc6` on
OSFile19 showed that the published-package path works. State of the labs at
07:50 UTC on 2026-10-10: no fixture and no probe residue in either lab
(`Verify` of the matrix lab 07:45, of the first lab 07:29); the six VMs of the
matrix run, and `OSWin11E` (restarted 07:36) shuts itself down about an hour
after its start.
## Next step ## Next step
1. The maintainer integrates the rest of the stack (Decision 15; commands in 1. Gate 3 on the published rc7 (the agent runs it on request): the identity
the deployment notes). A **new** pull request from `ai/quality-gate-coverage` check is done (12:33Z); the live controller with `-Version 5.0.0-rc7` in
to `master` replaces #117; then #118 and, if its module fixes go into rc7, the first lab and `Run-MatrixSequence.ps1 -Version 5.0.0-rc7` for every
#119 are retargeted with `gh pr edit <n> --base master`, marked ready, and cell remain (deployment notes, "Accept a published package"). Open: keep or
merged. No `--delete-branch` while another open pull request uses the branch replace the matrix VMs (about 60 GB) and the evaluation client (it shuts
as its base; the head branches are deleted last. He decides which module down every hour), and a domain cell for Windows 11 26H1, whose client loses
fixes of the matrix branch belong to rc7 (two commits: `962887a` holds two the secure channel to the Server 2025 domain controller.
fixes, `fdd7a8b` one) and reviews them (Decision 24). 2. The change that sets the next version (rc8 or 5.0.0) adds `5.0.0-rc7` to
2. He decides the open items listed in the paths report: `FileSecurity` `$publishedVersions`; adding it earlier fails the reuse test (deployment
conversions, `RemoveAll` account filters, lazy path overloads, abandoned notes). Every release step is the maintainer's.
3. He decides the open items of the paths report: `FileSecurity` conversions,
`RemoveAll` account filters, lazy path overloads, abandoned
`PrivilegeEnabler`, dot patterns of `Get-ChildItem2 -Filter`, the 17 `PrivilegeEnabler`, dot patterns of `Get-ChildItem2 -Filter`, the 17
owner-restore handlers without the later-command check, unused classes owner-restore handlers without the later-command check, unused classes
(Decisions 21/22). (Decisions 21/22). He also confirms or changes the proposed Decisions 22 and
3. Gate 3: accept the published package in the first lab and in every cell of 24.
the matrix (`Run-MatrixSequence.ps1 -Version`) before the candidate counts as 4. #34 stays open (Decision 23; no reply since 2026-10-06): the maintainer
accepted; no local upload. The paths fixes were accepted locally (record chooses between waiting for a test of the published candidate on the
above). NetApp, EMC, and IBM ESS servers of the reporters (checklist:
4. Retain stacked-PR order (15): #116 (merged), the replacement of #117, #118, `Tests/Lab/Non-Windows-File-Server-Test.md`) and accepting the untested
then #119; a simulated merge in that order gives exactly the tree of the risk with a release-note caveat. No agent can accept it.
matrix branch (`62aa1ae`). Confirm or change Decision 22. 5. He decides the two LOW findings of the security review (record, Limits):
5. #34 stays open (Decision 23): the maintainer chooses between waiting for a
test of the published candidate on the NetApp, EMC, and IBM ESS servers of
the reporters (checklist: `Tests/Lab/Non-Windows-File-Server-Test.md`) and
accepting the untested risk with a release-note caveat. No agent can
accept it.
6. He decides the two LOW findings of the security review (record, Limits):
the swallowed initialization errors of `GetEffectiveAccess` (a false "no the swallowed initialization errors of `GetEffectiveAccess` (a false "no
access" instead of an error on an OS that refuses at initialization, and access" instead of an error on an OS that refuses at initialization; fix:
neither warning nor error when the local fallback fails; fix: record the record the exceptions in `authzException`, with a regression test and a
initialization exceptions in `authzException`, with a regression test and a check of "the error stays" in the help and CHANGELOG), and the ACL of the
check of the sentence "the error stays" in the help and CHANGELOG), and the stage folders under `C:\` in the lab kit (they inherit Authenticated Users:
ACL of the stage folders under `C:\` in the lab kit (they inherit Modify; protecting them is a design change of the controller and needs a new
Authenticated Users: Modify; protecting them is a design change of the acceptance). The help could also say that a local standard user who asks
controller and needs a new acceptance). The help could also say that a local about a domain account still gets "Access is denied".
standard user who asks about a domain account still gets "Access is denied". 6. Do not release stable 5.0.0 or equate a percentage with gate closure.
7. Do not release stable 5.0.0 or equate a percentage with gate closure.

13
.memory-bank/decisions/0015-merge-stacks-with-merge-commits.md

@ -16,4 +16,15 @@ source: maintainer decision of 2026-10-05
pull request would conflict, and the commit IDs in the descriptions and pull request would conflict, and the commit IDs in the descriptions and
the changelog would no longer exist on `master`. A merge commit keeps the changelog would no longer exist on `master`. A merge commit keeps
them, and each merge leaves `master` at the tree its pull request tested. them, and each merge leaves `master` at the tree its pull request tested.
- Applied: 5.0.0-rc2, the PRs #99 to #106 on 2026-10-05. - Applied: 5.0.0-rc2, the PRs #99 to #106 on 2026-10-05; 5.0.0-rc7, the PRs
#116, #120, #118, and #119 on 2026-10-10.
- Operating rule (2026-10-10): retarget each pull request of the stack to
`master` (`gh pr edit <n> --base master`) before the one below it is merged,
and delete a head branch only when no open pull request uses it as its base.
Deleting a base branch through the GitHub CLI closed #117 without a merge:
GitHub did not retarget it. The open reports cli/cli#1168 and cli/cli#14223
show the same events (the first says that the button on the pull request
page retargets, the second quotes a maintainer who sees a platform issue) and
report that a closed pull request can't be retargeted or reopened while its
base is missing (not tried here). #120, a new pull request from the same
head, replaced #117. Nothing was lost; no content conflicted.

104
.memory-bank/deployment-notes.md

@ -7,58 +7,51 @@ source: release gates of 5.0.0 (lab acceptance, OS matrix, publication plan), re
# Deployment notes # Deployment notes
## Publish the next prerelease (rc7) ## Publish the next prerelease (rc7 is published)
State on 2026-10-10 at 09:59 UTC: #116 (rc7, head `d25647d`) is merged into State on 2026-10-10 at 12:40 UTC: rc7 is published. The whole stack is merged
`master` (merge commit `8a6be9f`, 09:10:12Z). #117 (head `f11ff41`, base into `master` (`fa0701b`, the tree of `2b8643f`): #116 (rc7, `8a6be9f`, 09:10Z),
`ai/release-5.0.0-rc7`) was **closed without a merge** at 09:10:16Z: the #120 (`bdb9981`, 10:50Z), #118 (`03bef2c`, 11:12Z), and #119 (`fa0701b`,
`--delete-branch` of `gh pr merge 116` deleted its base branch, and GitHub 11:28Z). #117 had been closed without a merge at 09:10:16Z, when the branch
closed it (events `base_ref_deleted`, then `closed`) instead of retargeting it. deletion after the merge of #116 removed its base branch (Decision 15,
Nothing is lost: `ai/quality-gate-coverage` is intact at `f11ff41`, and operating rule); #120, a new pull request from its head `f11ff41`, replaced
`master` still lacks its change (25 files). #118 (draft, head `83149ee`, base it. The CI run on `master` at `fa0701b` passed at 11:40Z. The maintainer pushed
`ai/quality-gate-coverage`) and #119 (draft, head `49734ef`, base the lightweight tag `5.0.0-rc7` at `fa0701b` at about 12:20Z. The CI run
`ai/quality-gate-paths`) are open and green. A simulated merge chain `38051611526` of the tag passed: Build and test, then Release at 12:31:34Z
(`git merge-tree --write-tree`, no ref written) with merge commits without an approval step, because the `powershell-gallery` environment has no
(Decision 15) is conflict-free at every step: the coverage branch into `master` required reviewer. The Gallery has rc7 since 12:30:57Z, GitHub since 12:31:09Z.
gives the tree of `f11ff41`, #118 then gives `b1dc006`, and #119 gives
`62aa1ae`, the tree of the matrix branch. The manifest says `5.0.0` with
`Prerelease = 'rc7'`, and `$publishedVersions` in `Tests/Repository.Tests.ps1`
lists the versions up to rc6, as it must before rc7 is published.
The branch `ai/quality-gate-lab-matrix` (draft #119) is stacked on #118. It `Test-PublishedRelease.ps1 -Version 5.0.0-rc7` verified the published identity
holds three fixes of the module in two commits (`962887a` has two, `fdd7a8b` at 12:33Z: the tag commit is `fa0701b` on `master`, the Gallery's SHA-512
one). `fdd7a8b` reverts cleanly on its own; `962887a` doesn't matches the downloaded nupkg, the 11 module files are byte-identical in the
revert while `fdd7a8b` stays (the two conflict in `Security2/Win32/Lib.cs` and nupkg and the GitHub zip, and the manifest says `5.0.0-rc7`. The evidence is
`CHANGELOG.md`), and its two fixes go together. The branch also holds the kit of the outside git, in `published-rc7` of the session folder
operating-system matrix, the changes of the live controller, and the record `4b12e2f4-d4c7-4a5d-883a-ddb7421c4848\files`. The published bytes:
(Decision 24). rc7 contains the module fixes only if the branch is merged after
#118 and before the tag; otherwise they go to the next prerelease. The
maintainer decides.
Do not delete a head branch while another open pull request uses it as its - `NTFSSecurity.dll` SHA-256
base. On 2026-10-10 the deletion through `gh pr merge --delete-branch` closed `D3B7CBE362C37D1016559669CB2EFF5034A6945CA1B03DDB49F1361363D203A7`
#117 instead of retargeting it. The open reports `cli/cli#1168` and - `NTFSSecurity.zip` SHA-256
`cli/cli#14223` show the same two events and say that GitHub retargets only `9705C8CCFA0FB8FC355E401444044D94BF176729BA84104D2C423C429AC1430B`
when the branch is deleted with the button on the pull request page. The - nupkg SHA-256
latter also reports, and this was not tried here, that `gh pr edit --base` `40922397B7CB307C64DD99960659539AF5C8AD9D2F55C6BF26E8AB434DEC8DCC`
refuses a closed pull request and that `gh pr reopen` refuses while the base
branch is missing. A new pull request from the same head is the repair.
1. Open a new pull request from `ai/quality-gate-coverage` to `master` (it The release notes of a prerelease are the `[Unreleased]` section of
replaces #117, same head and title), wait for its CI, and merge it with `CHANGELOG.md`.
**Create a merge commit**. Do not delete the branch yet.
2. Retarget #118 (`gh pr edit 118 --base master`), mark it ready, and merge it rc7 contains everything that is merged: the behavior changes of Phase 2
the same way. Then do the same for #119 if its module fixes go into rc7. (#116), the quality-gate paths (#120, #118), and the three module fixes of
A retarget doesn't start CI again (`pull_request` in `ci.yml` has the the matrix (#119, in two commits: `962887a` holds two, `fdd7a8b` one; they
default event types), and the merge result is the tree that CI tested. don't revert separately, because they conflict in `Security2/Win32/Lib.cs` and
3. Delete the head branches only after the last pull request that uses one as `CHANGELOG.md`), with the kit, the controller changes, and the record of the
its base is merged or retargeted. operating-system matrix (Decision 24).
4. Tag the merge commit on `master` with `5.0.0-rc7` and push the tag. The
`release` job checks the tag against the manifest and builds nothing new: 1. Accept the published package (next section). The identity check is done;
it publishes the package that the `build` job tested. Approve the the first lab and every cell of the matrix remain (gate 3).
deployment of the `powershell-gallery` environment if it asks. 2. Add `5.0.0-rc7` to `$publishedVersions` in `Tests/Repository.Tests.ps1`
5. After the publication, add `5.0.0-rc7` to `$publishedVersions` with the only in the change that sets the next version (rc8 or 5.0.0), as
next change that goes to `master`. `Docs/Contributing/05-Releasing.md` says. The test "Should not reuse a
version that the PowerShell Gallery already has" fails when the list holds
the version of the manifest, which still says rc7.
## Accept a published package ## Accept a published package
@ -68,7 +61,8 @@ Local `-ModulePath` runs are validation; the gate needs the published bytes.
-OutputPath <folder>` (read-only): tag and commit on `master`, the CI run -OutputPath <folder>` (read-only): tag and commit on `master`, the CI run
of the tag, the Gallery's SHA-512 against the downloaded nupkg (ordinal, of the tag, the Gallery's SHA-512 against the downloaded nupkg (ordinal,
case-sensitive base64), the nupkg against the GitHub zip file by file, and case-sensitive base64), the nupkg against the GitHub zip file by file, and
the identity of the manifest. Dry run on rc6: all checks passed. the identity of the manifest. Run on rc6 (dry run) and on rc7 (2026-10-10,
12:33Z): all checks passed.
2. `Tests/Lab/Invoke-NTFSSecurityLabTest.ps1 -Version <version>` in the 2. `Tests/Lab/Invoke-NTFSSecurityLabTest.ps1 -Version <version>` in the
existing lab, both editions, and `Tests/Lab/Acceptance/Run-MatrixSequence.ps1 existing lab, both editions, and `Tests/Lab/Acceptance/Run-MatrixSequence.ps1
-Version <version>` for each cell of the matrix (Decision 24; pass the file -Version <version>` for each cell of the matrix (Decision 24; pass the file
@ -163,9 +157,15 @@ Local `-ModulePath` runs are validation; the gate needs the published bytes.
logons returned the old account on the domain controller and member servers for logons returned the old account on the domain controller and member servers for
7 to 15 minutes. The five remedies tried (a ticket purge, `nltest /sc_reset`, a 7 to 15 minutes. The five remedies tried (a ticket purge, `nltest /sc_reset`, a
DNS flush, a restart of the Kerberos service, and waiting) helped only by DNS flush, a restart of the Kerberos service, and waiting) helped only by
waiting (see `techContext.md`). The controller names the account of case 3 anew waiting. A model with one lifetime (9.95 to 10.25 minutes) fits all 43
for each new fixture; a script of your own that recreates accounts needs unique Admin-role runs of 27 cells; the replay and the model are in the record of the
names too. matrix and in Decision 24. The controller names the account of case 3 anew
for each new fixture; a script of your own that recreates accounts needs
unique names too.
- `Wait-LabVM` waits for a heartbeat that a client may not report: retry
`New-LabPSSession` instead of waiting longer. After an unplanned shutdown,
test a domain session, not `nltest /sc_verify` (it stays stale), and repair
with `Test-ComputerSecureChannel -Repair`.
- Restart the evaluation client (`OSWin11E`) right before a sequence or a suite, - Restart the evaluation client (`OSWin11E`) right before a sequence or a suite,
not before several: it shuts down an hour after each start. The restart takes not before several: it shuts down an hour after each start. The restart takes
about two and a half minutes and may need the repair of the secure channel. about two and a half minutes and may need the repair of the secure channel.

164
.memory-bank/progress.md

@ -9,17 +9,13 @@ source: repository and validation evidence
## Current status ## Current status
5.0.0-rc6 is published on the Gallery and GitHub; its failed Release job 5.0.0-rc7 is published on the Gallery and GitHub (2026-10-10, tag at
recovered in attempt 2 on 2026-10-09. #116 (rc7, `d25647d`) was merged into `fa0701b`); rc6 is the one before it. On 2026-10-10 the maintainer merged the
`master` on 2026-10-10 (`8a6be9f`); rc7 is neither tagged nor published. #117 whole stack into `master` (`fa0701b`, CI green): #116 (rc7), #120 (it replaced
was closed unmerged when its base branch was deleted, so a new pull request #117, which GitHub closed unmerged when the branch deletion after #116 removed
from `ai/quality-gate-coverage` replaces it. Further quality-gate work is its base), #118 (the quality-gate paths), and #119 (the operating-system
`ai/quality-gate-paths` (draft #118), which classifies every remaining matrix with three module fixes, Decision 24 proposed). The published rc7 still
unvisited path (the open items are the maintainer's decisions), and needs its lab acceptance (gate 3). Stable Gallery version: 4.2.6.
`ai/quality-gate-lab-matrix` (draft #119, stacked on #118): the
operating-system matrix, three fixes of the module found by it, and the
controller changes (Decision 24, proposed).
Stable Gallery version: 4.2.6.
After 5.0.0, archive in favor of WindowsAccessControl (Decision 18). After 5.0.0, archive in favor of WindowsAccessControl (Decision 18).
## Recent milestones ## Recent milestones
@ -50,75 +46,52 @@ After 5.0.0, archive in favor of WindowsAccessControl (Decision 18).
Published rc6 live tests differed only in rc7's warning expectation. Published rc6 live tests differed only in rc7's warning expectation.
- 2026-10-09: release attempt 2 succeeded; rc6 GitHub prerelease and zip - 2026-10-09: release attempt 2 succeeded; rc6 GitHub prerelease and zip
appeared at 07:01:34 UTC. #116 passed CI on `d25647d`. appeared at 07:01:34 UTC. #116 passed CI on `d25647d`.
- 2026-10-09: autonomous follow-up on `ai/quality-gate-coverage`, through - 2026-10-09: autonomous follow-up on `ai/quality-gate-coverage` (#117, then
`3442194`, adds 202 cases above rc7: deletion/owner failures, all 13 #120), through `3442194`: 202 cases above rc7 (deletion/owner failures, all
scopes, inheritance transitions, enumeration, forced replacement, 13 scopes, inheritance transitions, enumeration, forced replacement,
descriptor failures, and offline CI recovery. Reproduced/fixed rooted descriptor failures, offline CI recovery); fixed rooted result paths and the
result-path handling and first-hidden-item omission. Publication recovery first-hidden-item omission; publication recovery verifies the exact SHA-512
verifies exact SHA-512 identity, not merely version existence. identity, not merely the version. Suite: 914 per configuration, zero
- 2026-10-09: final uninstrumented suite: 914 per configuration, zero failures; 2,641/3,559 sequence points (74.21%), 974/1,933 branches (50.39%).
failures; coverage: 2,641/3,559 sequence points (74.21%) and 974/1,933 Live comparison, 09:20 to 09:51 UTC: candidate 330 passed, 0 failed, 2
branches (50.39%), aggregate of four runs without AltCover `--save`. expected skips; published rc6 only its four expected failures (`7594e0c`).
All skipped templates have executed counterparts. Mutation guards were - 2026-10-09: handoff 1 (#118): suite 914 to 1,310 per configuration, zero
proved and production source restored; Release build/checks pass. failures; 3,192/3,634 sequence points (87.84%), 1,273/1,978 branches; all 231
- 2026-10-09: live comparison, 09:20 to 09:51 UTC: candidate 330 passed, unvisited methods classified (223 explained, 8 open). Eleven defects fixed,
zero failed, two expected skips; published rc6 four expected Hidden/ ten with a guard that is red before the fix and green after it (76 rows red
warning-text failures only. Independent cleanup probes verified fixture at the base), among them a later command's exception that cmdlets swallowed
absence; raw host-verifier failures retained with corrected verification. (a `throw` made `Remove-Item2` remove the next item) and a privilege left
Lab guards/acceptance committed in `7594e0c`. One independent code review enabled. Lab acceptance, `83149ee` against `f11ff41`: 486 passed, 0 failed, 2
approved with no significant finding (custom model unavailable; built-in expected skips against 338 passed, 148 failed. Report in `Tests/Coverage`;
fallback). All 11 tested files match the ZIP. OS/path gates stay open. record `Tests/Lab/Acceptance-2026-10-09-quality-gate-paths.md`.
- 2026-10-09: Handoff 1 on `ai/quality-gate-paths` (28 local commits, no
push): suite 914 to 1,310 per configuration, zero failures; coverage
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 (a
red/green matrix over ten states of the branch: 76 rows red at the base,
none after the last fix), among them a later command's exception that
cmdlets swallowed (a `throw` made `Remove-Item2` remove the next item; also
through the error stream) and a privilege left enabled. Nine static
passes of the built-in code-review agent: no Blocker or Major. Report in
`Tests/Coverage`.
- 2026-10-09: lab acceptance of those fixes, `83149ee` against its base
`f11ff41` with the same 244 tests per edition (78 new, case 10): candidate
486 passed, 0 failed, 2 expected skips; baseline 338 passed, 148 failed, all
148 green on the candidate; fixture removed and verified clean on six
machines. 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 - 2026-10-09 to 10: handoffs 2 to 4 under the maintainer's delegation (decisions
D1 to D46 in the night log of the session files). The matrix lab D1 to D47 in the night log of the session files). The matrix lab
`NtfsSecurityOsMatrixLab` (Server 2019, 2022, and 2025 file servers, Windows 11 `NtfsSecurityOsMatrixLab` (Server 2019, 2022, 2025, a Windows 11 Enterprise
Enterprise 22H2 client, Windows 11 26H1 suite only) found three defects of the 22H2 client, Windows 11 26H1 suite only) found three module defects, fixed in
module, fixed in `962887a` and `fdd7a8b`: audit inheritance by descriptor, `962887a` and `fdd7a8b`: audit inheritance by descriptor,
`Get-NTFSEffectiveAccess -ServerName ''`, and the same cmdlet for a user who `Get-NTFSEffectiveAccess -ServerName ''`, and the same cmdlet for a
isn't an administrator on a domain member. The final candidate passes the non-administrator on a domain member. The final candidate passes the module's
module's suite on every machine (24 runs, no failure) and the live controller suite on every machine (24 runs), the live controller in three cells (1,374
in three cells (1,374 passed, 0 failed, 12 skipped) and in the first lab with passed, 0 failed, 12 skipped), and the first lab with case 9 (245 passed, 0
case 9 (245 passed, 0 failed, 1 skipped per edition). The failures of the failed, 1 skipped per edition). The Server 2022 effective-access failures
effective-access tests in the Server 2022 cell were not a defect of the module: were stale account state, not the module (a replay; the Windows mechanism is
in a replay of the same cells the baseline failed two of three and the final unknown); the controller names the case-3 account anew (`1dec389`). Built-in
candidate one of three (not counting the warm-up cell), and one model (the reviews: Minors corrected, one Major resolved by the replay, no Blocker; the
remote authorization managers answer for an account name for about ten minutes built-in security review found no exploitable vulnerability and two LOW items
after the account was created again) fits all 43 Admin-role runs of 27 cells; left for the maintainer. Record:
the Windows mechanism is unknown. The controller `Tests/Lab/Acceptance-2026-10-10-os-matrix.md`.
names the account of case 3 anew for each fixture (`1dec389`). A read-only - 2026-10-10: the maintainer integrated the stack. His branch deletion after the
built-in review of the kit and the fixes approved with Minor findings, fixed in merge of #116 (`8a6be9f`, 09:10:12Z) removed the base branch of #117, and
`db04ef2`. A second review of the later commits found one Major (the record GitHub closed #117 unmerged three seconds later instead of retargeting it
called the cause settled without a baseline replay), addressed by the replay, (`cli/cli#14223` shows the same events); the earlier guidance that relied on a
`9344ff7`, and `ab0d8e1`; a follow-up review of those fixes found no Blocker or retarget was wrong. Nothing was lost: #120 (`bdb9981`, 10:50Z) replaced #117,
Major and five Minors, corrected in `e2384e5` and `70f494a`; a second then #118 (`03bef2c`, 11:12Z) and #119 (`fa0701b`, 11:28Z) merged after their
follow-up review (the first-lab run and the cleanup changes) found no Blocker or retargeting; CI on `master` passed at 11:40Z. Decision 15 has the rule.
Major and four Minors, corrected in `b78784d` and `dbb4bd6`; the built-in - 2026-10-10: rc7 published. The maintainer tagged `fa0701b` at about 12:20Z;
`security-review` agent found no exploitable vulnerability and two LOW items the CI run of the tag passed and the Release job published without an
that are not changed (record, Limits). Record: approval step (Gallery 12:30:57Z, GitHub 12:31:09Z). The identity check
`Tests/Lab/Acceptance-2026-10-10-os-matrix.md`; the agent pushed nothing. (`Test-PublishedRelease.ps1`, 12:33Z) passed: Gallery SHA-512, nupkg and zip
- 2026-10-10: the maintainer merged #116 (`8a6be9f`, 09:10:12Z) with `gh pr identical, manifest `5.0.0-rc7`. Hashes: deployment notes.
merge --delete-branch` and pushed the matrix branch as draft #119 (`49734ef`).
The deletion removed the base branch of #117, and GitHub closed #117
unmerged three seconds later instead of retargeting it (events
`base_ref_deleted`, `closed`; the same pair is in `cli/cli#14223`). The
earlier guidance, which relied on a retarget, was wrong. Nothing is lost; a
new pull request from `ai/quality-gate-coverage` replaces #117 (deployment
notes).
## Stable capabilities ## Stable capabilities
@ -131,11 +104,12 @@ After 5.0.0, archive in favor of WindowsAccessControl (Decision 18).
## Open work ## Open work
1. Decision 21 gate: review Decision 22, integrate reviewed quality-gate 1. Decision 21 gate: test the published rc7 (identity verified; the first lab
follow-up, publish the next candidate, and test the published package. and every matrix cell remain) and review Decision 22. Do not release 5.0.0
Do not release 5.0.0 until the remaining-path and OS-matrix gates close. until the remaining-path and OS-matrix gates close. Release steps:
Release steps: `Docs/Contributing/05-Releasing.md`; remove prerelease `Docs/Contributing/05-Releasing.md`; remove the prerelease label, date
label, date `[5.0.0]`, update `$publishedVersions`, tag through CI. `[5.0.0]`, add the last prerelease to `$publishedVersions` (never the
version of the manifest), tag through CI.
2. Issues: #110's seven items were addressed by rc6, but #115 deliberately 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 used no closing keyword. #34 stays open for non-Windows owner feedback
or maintainer acceptance. #16, #21, #45, #89 await reporters. #68 tracks or maintainer acceptance. #16, #21, #45, #89 await reporters. #68 tracks
@ -164,17 +138,13 @@ After 5.0.0, archive in favor of WindowsAccessControl (Decision 18).
write's ownership retry cannot run on a local volume and is covered only write's ownership retry cannot run on a local volume and is covered only
by the lab. A conditional ACE display remains a .NET representation limit, by the lab. A conditional ACE display remains a .NET representation limit,
not evidence of unconditional permissions. not evidence of unconditional permissions.
8. Publication recovery is implemented locally in `95b827e`, with 14 offline 8. Publication recovery (`95b827e`, merged in #120): 14 offline tests and exact
tests and exact artifact SHA-512 verification. Original upload errors artifact SHA-512 verification; the original upload errors remain errors for
remain errors for missing/different/unverifiable outcomes. Not deployed missing, different, or unverifiable outcomes. The agent published nothing,
until the maintainer merges/pushes; no publication was performed here. so the recovery has never run against the Gallery.
9. Operating-system matrix (Decision 24, proposed): the lab and the cells exist 9. Operating-system matrix (Decision 24, proposed): the lab and the cells exist
and the final local candidate passes them. Open: the acceptance of the and the candidate passes them; the published rc7 still needs its acceptance
published rc7 in every cell, keeping or replacing the VMs (about 60 GB) and in every cell. #34 has no new reply since 2026-10-06.
the evaluation client (it shuts down every hour), which module fixes go to 10. Lab rollback evidence: new checkpoints report Standard even after a
rc7, and a domain cell for Windows 11 26H1. #34 has no new reply since successful temporary ProductionOnly probe; original VM policy restored, no
2026-10-06. checkpoint restored. Don't represent them as verified Production snapshots.
10. Lab rollback evidence: new checkpoints exist but report Standard even
after a successful temporary ProductionOnly probe. Classification is
unresolved; original VM policy restored, no checkpoint restored. Do
not represent these as verified Production snapshots.

99
.memory-bank/systemPatterns.md

@ -1,6 +1,6 @@
--- ---
status: current status: current
last-verified: 2026-10-09 last-verified: 2026-10-10
owner: active-agent owner: active-agent
source: repository and regression evidence source: repository and regression evidence
--- ---
@ -66,82 +66,43 @@ Read only task-relevant records; the index controls routing.
- Pipeline getters never throw; per-item errors name input and allow continuation. - Pipeline getters never throw; per-item errors name input and allow continuation.
- Folder moves never use CopyAllowed; preserve cross-volume source folders. - 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 the failures of one item must pass on what a later command - A catch-all for one item's failures passes on what a later command raises
raises through a Write call. A downstream throw is an ordinary exception, through a Write call (`IsFromLaterCommand`, `PipelineControl`; see
so a type check finds only the end of the pipeline, break, and continue. `BaseCmdlets.cs`); add a row to `Tests/PipelineControl.Tests.ps1` for a new
BaseCmdlet notes the exception that its WriteObject, WriteError, cmdlet. Record an enabled privilege before the next write.
WriteVerbose, and WriteDebug raised (WriteWarning is not noted: no catch-all - `Get-ChildItem2 -Filter` has two matchers (AlphaFS, then a wildcard on the
encloses it); `IsFromLaterCommand` recognizes it, and the type check name); `*.*` means `*`, other dot patterns are an open decision.
`PipelineControl.IsEnd` backs it up for other calls into PowerShell. A write
inside a helper, such as the owner restore of `InvokeAsOwner`, is an
accepted gap: its handler reports the item's own error, which raises too.
Prefer writing outside the try. `Tests/PipelineControl.Tests.ps1` has rows
for every cmdlet: add a row for a new one, and keep the typed-throw rows
(they fail if PowerShell stops wrapping a thrown exception).
- Record an enabled privilege before the next write, which a later command
can answer with an exception: Dispose disables only what is recorded.
- `Get-ChildItem2 -Filter` has two matchers: the AlphaFS enumeration, whose
dot rules also differ from those of `Get-ChildItem` (probe: `Report.*` and
`Rep*.` in both editions), and a PowerShell wildcard on the name, where only
`*` and `?` are special. `*.*` is treated as `*`; the other dot patterns are
pinned by `ItemCmdlets.Tests` and are an open maintainer decision.
### Tests and documentation ### Tests and documentation
- Tests import Release in isolated processes, both editions and privilege - Tests import Release in isolated processes, both editions and privilege
modes. File/ACL/link fixtures use shared sandbox guards and cleanup. modes, with guarded sandboxes; a skip needs an eligible counterpart.
Privilege-dependent skips must have eligible counterparts in the matrix.
- Assert persisted state, errors/targets, continuation, and no failed - Assert persisted state, errors/targets, continuation, and no failed
PassThru output. Prove new characterization guards with bounded mutations; PassThru output. Prove new characterization guards with bounded mutations
restore source exactly and rebuild before green validation or packaging. (one round together only if no guard can fail because of another); restore
Apply the mutations of one round together only when no guard can fail source exactly and rebuild before green validation or packaging. A retry
because of another mutation; otherwise split the rounds. test asserts its precondition (the plain write is denied).
- A test that arranges a retry asserts its precondition (the plain write is - CI scripts and focused runs set `Stop`: a test that needs a non-terminating
denied), or it can pass without reaching the retry. error names `-ErrorAction Continue`. Don't name a test variable like an
- A test variable must not take the name of an automatic variable such as automatic variable (`$foreach`): Pester runs the block inside a foreach.
`$foreach`: Pester runs the block inside a foreach, and the value is lost.
- The CI scripts set `$ErrorActionPreference = 'Stop'`; focused runs do the
same, and a test that needs a non-terminating error (for example to take it
through `2>&1`) names `-ErrorAction Continue`.
- Fixture DACLs use .NET SetAccessControl, not Set-Acl's unintended SACL writes. - Fixture DACLs use .NET SetAccessControl, not Set-Acl's unintended SACL writes.
- Scope/descendant expectations are independent of the production converter. - Scope/descendant expectations are independent of the production converter.
- Drive-root tests map a sandbox folder with `subst` through - Desktop platyPS: generate help, rebuild, round-trip unchanged, check links;
`New-TestDriveMapping` (elevated only; the basic token cannot). Tests that platyPS 0.14.2 turns paired asterisks into emphasis, even in backticks.
need a letter without a volume take the lowest free one.
- Desktop platyPS: generate help, rebuild, round-trip unchanged, check links.
platyPS 0.14.2 turns a pair of asterisks in a paragraph into emphasis, also
inside backticks, and the help drops them: write the words, put patterns in
example code blocks, and check the generated XML.
- Live tests use only approved lab targets, SMB then independent server state; - Live tests use only approved lab targets, SMB then independent server state;
Get/SetFileSecurity preserves stored DACLs; rights oracles use S4U tokens. Get/SetFileSecurity preserves stored DACLs; rights oracles use S4U tokens.
- A suite that is green on the development host and on CI says little about a - A suite that is green on the host and CI misses defects that need a domain
feature that the environment lacks. The matrix found three defects that every member or another token (the matrix found three): also run a domain member,
earlier run had missed because the host is outside a domain and the CI other builds, and a basic user. A failure that follows cell order, not
runner's token differs: run the suite on a domain member, on other builds, and version, points to stale account state (Decision 24): alternate the cells.
as a basic user before a release, and classify a failure by a probe under the
real tokens (elevated, filtered, local standard, domain standard) before
calling it a defect or a design.
- A fixture that deletes an account and creates it again with the same name can
get a wrong answer for about ten minutes: the remote authorization managers
answered `0x100000` for the current SID while the local manager and a Kerberos
logon were right in the same second, and, when the accounts are created again
within seconds, the Kerberos S4U logons returned the old account (7 to 15
minutes). A failure that follows the order of the cells and not the version of
the module points to such state: run the baseline and the candidate in cells
that follow each other and alternate them (the replay of the record) before
blaming the code. The controller names the account of case 3 anew for each new
fixture.
### CI results and publication ### CI, publication, and integration
- Use Path.Combine then GetFullPath for a rooted-or-repository-relative - Discovery treats only PackageNotFound as absence. Rerun/uncertain-upload
result path; Join-Path appends even a rooted child and corrupts it. success needs Gallery SHA-512 equality with the exact build artifact
- Discovery handles only expected PackageNotFound as absence; repository, (ordinal Base64); anything else preserves the upload error. Secrets stay
authentication, and network errors remain failures. environment references; mock all publication commands, no test uploads.
- Rerun/uncertain-upload success requires Gallery SHA-512 equality with the - Gate prompts are self-contained: pins are historical, state is rechecked,
exact build artifact. Base64 is case-sensitive: use ordinal comparison. completion is evidence, risk acceptance is no test pass. In a stack of pull
Missing/different/unverifiable metadata preserves the upload error. requests, retarget each to `master` before merging the one below; delete a
- Secrets stay by environment reference, never in process arguments/logs. head branch only when no open pull request uses it as its base (Decision 15).
Test all external publication commands with mocks; no test may upload.
- AltCover aggregates all four sequential runs without --save. Report
sequence points, not unique source lines; keep unmatched paths visible.

195
.memory-bank/techContext.md

@ -1,6 +1,6 @@
--- ---
status: current status: current
last-verified: 2026-10-09 last-verified: 2026-10-10
owner: active-agent owner: active-agent
source: repository and executable evidence source: repository and executable evidence
--- ---
@ -37,16 +37,14 @@ source: repository and executable evidence
runs in a new process. Current prereleases share assembly version 5.0.0.0. runs in a new process. Current prereleases share assembly version 5.0.0.0.
- GitHub CLI: `C:\Program Files\GitHub CLI\gh.exe`, signed in as raandree. - GitHub CLI: `C:\Program Files\GitHub CLI\gh.exe`, signed in as raandree.
Read-only queries work; remote mutations belong to the maintainer. Read-only queries work; remote mutations belong to the maintainer.
- LabSources: `V:\LabSources`. All 13 deployed machines are Server 2025. - LabSources: `V:\LabSources`. The first lab's machines are Server 2025; the
Windows 11 consumer/enterprise-evaluation media and Server 2019/2022 matrix lab `NtfsSecurityOsMatrixLab` adds Server 2019/2022 and Windows 11.
ISO files exist. OS cache is empty; exact detected editions are not yet
verified. Do not equate present media with a deployed/tested OS matrix.
## Constraints ## Constraints
- Source manifest: ModuleVersion 5.0.0, prerelease rc7 on #116/follow-up. - Manifest: ModuleVersion 5.0.0, prerelease rc7, published 2026-10-10 (tag at
Latest stable: 4.2.6; latest published prerelease: rc6 (2026-10-08). `fa0701b`). Latest stable 4.2.6. The reuse test fails if `$publishedVersions`
GitHub rc6 release recovered 2026-10-09. rc7 publication is pending. holds the manifest's version: add rc7 in the change that sets the next one.
- Changed-section writes preserve unchanged owner/group/DACL/SACL (19). - Changed-section writes preserve unchanged owner/group/DACL/SACL (19).
Roots use root-folder APIs, not AlphaFS device security (#41). Roots use root-folder APIs, not AlphaFS device security (#41).
- CHANGELOG contains user-visible changes only (7); tests and CI-only fixes - CHANGELOG contains user-visible changes only (7); tests and CI-only fixes
@ -57,8 +55,6 @@ source: repository and executable evidence
Issue references use no closing keyword unless closure is intended. Issue references use no closing keyword unless closure is intended.
- Lab passwords stay in memory and are lab-only; no secret in repository, - Lab passwords stay in memory and are lab-only; no secret in repository,
logs, or process arguments. Live ACL mutations occur only in the lab. logs, or process arguments. Live ACL mutations occur only in the lab.
- Existing expired installation passwords of a.forest1/b.forest1 were
configured not to expire on 2026-10-07, matching the root domain.
## Build and focused checks ## Build and focused checks
@ -94,14 +90,11 @@ source: repository and executable evidence
- Packaging needs Compress-PSResource (Core 7.4+). New-ModulePackage copies - Packaging needs Compress-PSResource (Core 7.4+). New-ModulePackage copies
only FileList, validates the manifest, creates nupkg plus NTFSSecurity.zip. only FileList, validates the manifest, creates nupkg plus NTFSSecurity.zip.
Check package/file hashes and test the extracted artifact, not build extras. Check package/file hashes and test the extracted artifact, not build extras.
- Release runs only for validated version tags in powershell-gallery. - Release runs only for validated version tags in powershell-gallery; the API
API key stays as PSGALLERY_API_KEY environment reference. Helper key is the environment secret PSGALLERY_API_KEY. The rules of
Publish-ModulePackage treats only PackageNotFound as expected absence; `Publish-ModulePackage` are in `systemPatterns.md`. Read status through
existing-version skip and uncertain-upload recovery require exact Gallery `gh pr checks` and `gh run view --log-failed`. A successful Gallery upload
SHA-512 equality. Base64 comparison is case-sensitive. Unverifiable, followed by HTTP 409 does not prove its retry chronology.
missing, and different outcomes preserve errors. No test uploads.
- Read status through gh pr checks / gh run view --log-failed. A successful
Gallery upload followed by HTTP 409 does not prove its retry chronology.
## Coverage and test eligibility ## Coverage and test eligibility
@ -112,45 +105,35 @@ source: repository and executable evidence
four configurations sequentially with the real CI wrappers, then four configurations sequentially with the real CI wrappers, then
AltCover runner --collect recalculates the report. Compute option paths AltCover runner --collect recalculates the report. Compute option paths
before passing native arguments, not inline Join-Path expressions. before passing native arguments, not inline Join-Path expressions.
- Report sequence points, not unique source lines. Four-run baselines: - Report sequence points, not unique source lines. Four-run baselines: rc5
rc5 2,020/3,476 (58.1%), branches 711/1,873 (38.0%); 2,020/3,476 (58.1%); rc6 2,412/3,540 (68.14%); `3442194` 2,641/3,559
rc6 2,412/3,540 (68.14%), branches 850/1,918 (44.32%); (74.21%); `5a5d58b` 3,192/3,634 (87.84%), branches 1,273/1,978 (64.36%).
follow-up `3442194` 2,641/3,559 (74.21%), 974/1,933 (50.39%); The code changes the denominators: never present these as same-source
Handoff 1 `5a5d58b` 3,192/3,634 (87.84%), 1,273/1,978 (64.36%). Different increments. The branch summary counts 820 compiler-generated points; report
code changes denominators; never present these as same-source incremental the explicit branch points too (1,088/1,158, 93.96%). Suite at `5a5d58b`:
percentages. The branch summary counts 820 compiler-generated points (185 1,310 per configuration, zero failures (skipped: 24 and 55 elevated, 234
visited); report the explicit branch points as well (1,088/1,158, 93.96%). and 265 basic, Desktop and Core).
- Suite at `5a5d58b`: 1,310 per configuration, zero failures. Passed/skipped:
elevated Desktop 1,286/24, Core 1,255/55; basic Desktop 1,076/234,
Core 1,045/265.
- NUnit skipped ForEach names retain placeholders and parameter tuples, - NUnit skipped ForEach names retain placeholders and parameter tuples,
executed names expand them; raw-name intersection and positional alignment executed names expand them: raw-name intersection and positional alignment
are invalid. Skip eligibility is checked by row: run the suite once per are invalid. Check skip eligibility by row: run the suite once per
configuration with Pester PassThru (`Get-DiscoveryRows2.ps1 -Run` in the configuration with Pester PassThru and match skipped with executed rows by
session evidence) and match skipped with executed rows by file, line, file, line, path, name, and data (discovery alone misses tests that skip
path, name, and data. Discovery alone misses tests that skip themselves while running; write primitives, as `ConvertTo-Json` of rich rows hangs).
while they run, and `ConvertTo-Json` of rich data rows never finishes:
write primitives and type names.
- Remaining inventory: 442 points in 231 methods, classified by rule with - Remaining inventory: 442 points in 231 methods, classified by rule with
evidence (probe, IL scan, source reading); see `Tests/Coverage`. Preserve evidence (probe, IL scan, source reading); see `Tests/Coverage`. Preserve
raw XML, row CSVs, logs, commit identity, and build hashes. The frozen raw XML, row CSVs, logs, commit identity, and build hashes: the frozen
Build rewrites the hash file each time: save the hashes of the measured Build rewrites its hash file, so save the hashes of the measured assemblies
assemblies (AltCover `__Saved` copies) before any mutation build. (AltCover `__Saved` copies) before any mutation build.
- Bounded mutations: one script per round on the frozen worktree, with - Bounded mutations: one script per round on the frozen worktree, with guards
guards that no other mutation of the round can trip (an escape can be an that no other mutation of the round can trip (an escape can be an overlap
overlap or an equivalent mutant: check before changing a test). Restore or an equivalent mutant: check before changing a test). Restore the source
the source exactly and rebuild. exactly and rebuild.
- Red/green matrix, to show afterwards that a guard fails without its fix: - Red/green matrix (a guard fails without its fix): build each state of the
build each state of the branch (base, then each fix commit) in its own branch in its own Release worktree, lay the final `Tests` over it, run the
Release worktree, lay the final `Tests` over it (`git checkout <final> -- guarding files with the focused runner in all four configurations, and count
Tests`), run the guarding files with the focused runner (it sets failed rows per name with multiplicity; the last state is the control. Keep
`$ErrorActionPreference` to `Stop` like the CI wrappers) in all four the logs, a manifest with hashes, and the hash of each build: the first red
configurations, and count failed rows per name with their multiplicity (a runs of Handoff 1 were deleted and could not be reproduced.
block whose `BeforeAll` fails lists its data rows under one unexpanded
template name). The last state is the control and must have no failure.
Keep the logs and a manifest with their hashes, and hash each build: the
first red runs of Handoff 1 were deleted and could not be reproduced, and
the frozen runner rewrites its hash file at each build.
## Lab acceptance ## Lab acceptance
@ -159,36 +142,31 @@ source: repository and executable evidence
Controller accepts alternate machines; changing topology/OS scope waits Controller accepts alternate machines; changing topology/OS scope waits
for a maintainer decision. Do not repurpose another project's shared VMs. for a maintainer decision. Do not repurpose another project's shared VMs.
- Before a run: authenticated WinRM, LDAP RootDSE, Kerberos tickets, member - Before a run: authenticated WinRM, LDAP RootDSE, Kerberos tickets, member
secure channels, clocks; checkpoint only approved targets. Inspect actual secure channels, clocks; checkpoint only approved targets. New checkpoints
checkpoint kind: new checkpoints reported Standard even after a successful report Standard even after a successful ProductionOnly request (policy
temporary ProductionOnly request. Policy restored; no rollback performed; restored, no rollback): Production is unverified, not a passed safety check.
Production classification remains unverified, not a passed safety check.
- Run Tests\Lab\Invoke-NTFSSecurityLabTest.ps1 in elevated Desktop with - Run Tests\Lab\Invoke-NTFSSecurityLabTest.ps1 in elevated Desktop with
-Version for hash-checked Gallery packages or -ModulePath for the extracted -Version for hash-checked Gallery packages or -ModulePath for the extracted
build artifact, both editions. Per version/edition: Delegate, ServerAdmin, build artifact, both editions. Per version/edition: Delegate, ServerAdmin,
Admin on client, then Server independently checks persisted state. Admin on client, then Server independently checks persisted state.
- Controller writes Summary.json even when tests fail: validate every role, - Controller writes Summary.json even when tests fail: validate every role,
exit code, failure name, and total; DONE alone is not acceptance evidence. exit code, failure name, and total; DONE alone is not acceptance evidence.
Desktop ConvertFrom-Json can wrap arrays; explicitly enumerate the result Desktop ConvertFrom-Json can wrap arrays: enumerate the result and compare
and compare full Describe-prefixed names. Never gate cleanup on the global full Describe-prefixed names. Never gate cleanup on the global Error.Count
Error.Count, which includes handled errors; independently verify footprint. (it includes handled errors); verify the footprint independently.
- Remote Authz answers administrators and Access Control Assistance - Remote Authz answers administrators and Access Control Assistance
Operators (S-1-5-32-579); other accounts get access denied. Check firewall Operators (S-1-5-32-579); other accounts get access denied (check the
when remote resource-manager RPC fails. Expected rights use S4U tokens. firewall when its RPC fails). Expected rights use S4U tokens. A domain
A computer in a domain offers the remote interface to every caller, so the member offers the remote interface to every caller, so the default
denial also hit the default `-ServerName localhost` for a user who isn't an `-ServerName localhost` was denied for a non-administrator; hosts outside a
administrator; a computer outside a domain doesn't offer it, which is why the domain don't, so the host and CI missed it. Since `fdd7a8b` the local
tests passed on the development host and on CI. Since `fdd7a8b`, the local manager answers for a name of this computer; another computer stays denied.
manager answers for a name of this computer when the remote one refuses; the
denial stays for another computer (live test of the Delegate role).
- A live test is evidence of a fix only when it fails on the build without - A live test is evidence of a fix only when it fails on the build without
the fix: run the same tests, controller, and lab against the candidate and the fix: run the same tests, controller, and lab against the candidate and
the base of the branch, a new process per edition, and join both result the base, a new process per edition, and join the results by edition, role,
sets by edition, role, and full test name; the tests that pass on both are and full test name; tests that pass on both are controls (record of
controls (`Tests\Lab\Acceptance-2026-10-09-quality-gate-paths.md`). A 2026-10-09). PowerShell variables ignore case: `$edition` overwrote
validator must not name a loop variable like a typed parameter: PowerShell `$Edition`.
variables ignore case, so `$edition` overwrote `$Edition` and every edition
in the CSV became `System.String[]`.
- RemoveFixture after the run; verify OUs/accounts, share, folders, local - RemoveFixture after the run; verify OUs/accounts, share, folders, local
memberships, and test profiles removed. Credentials must never be printed. memberships, and test profiles removed. Credentials must never be printed.
@ -196,53 +174,20 @@ source: repository and executable evidence
- Lab `NtfsSecurityOsMatrixLab`: OSDC1 (Server 2025), OSFile19/22/25 (Server - Lab `NtfsSecurityOsMatrixLab`: OSDC1 (Server 2025), OSFile19/22/25 (Server
2019/2022/2025), OSWin11E (Windows 11 Enterprise Evaluation 22H2, the domain 2019/2022/2025), OSWin11E (Windows 11 Enterprise Evaluation 22H2, the domain
client), OSWin11 (Windows 11 Pro 26H1, suite only). Kit: `Tests\Lab\Acceptance`; client), OSWin11 (Windows 11 Pro 26H1, suite only). Kit
record: `Tests\Lab\Acceptance-2026-10-10-os-matrix.md`. `Tests\Lab\Acceptance`; record
- Run the module's own suite on every machine class before the controller `Tests\Lab\Acceptance-2026-10-10-os-matrix.md` (procedure, limits);
(`Run-MatrixLocalSuite.ps1`, elevated and basic, both editions, as scheduled the lessons of building it are in `deployment-notes.md`.
tasks with a batch logon at the highest run level): a child of a remoting - Run the module's own suite on every machine first (`Run-MatrixLocalSuite.ps1`
session has every privilege enabled and fails eight tests that expect them as scheduled tasks with a batch logon at the highest run level; a remoting
disabled. Skipped lists are compared as multisets against the host. child has every privilege enabled). One `Import-Lab` at a time. Compare skips
- AutomatedLab: one `Import-Lab` at a time, and none while a controller as multisets against the host. Hash each candidate and its package: builds
sequence runs (it re-imports the lab); `Wait-LabVM` waits for a heartbeat that aren't byte-reproducible.
a client may not report, so retry `New-LabPSSession`. The host's `bcdboot` - The 26H1 client can't keep its secure channel to a Server 2025 DC (suite
leaves the ESP of a Server 2019 or Windows 11 22H2 base image empty. only); the 22H2 evaluation client shuts down every hour: keep a run under an
- Windows PowerShell 5.1: `$PSScriptRoot` is empty in a parameter default under hour and test a domain session, not `nltest /sc_verify`.
`-File`; `2>&1` on a native command under `Stop` makes its stderr line - A fixture that re-creates an account name gets stale answers for about ten
terminating; `Get-LocalGroupMember` fails on an orphaned SID; `net localgroup minutes, for the baseline and the candidate alike (mechanism unknown; no
<name> <SID> /delete` refuses the SID of a name that its cache still remedy but waiting). The controller names the case-3 account anew for each
resolves (use `Remove-LocalGroupMember -SID`). fixture; the replay and the model are in the record. `Test-MatrixCleanup.ps1`
- Windows 11 26H1 (28000.1836) loses the secure channel to a Server 2025 domain verifies and repairs the probe's profiles and group entries.
controller (`NetrLogonGetCapabilities` level 2, 0xC0000022): suite only.
The 22H2 evaluation client shuts down every hour (license grace expired) and
can lose its machine password after an unplanned shutdown: keep a run under
an hour from its start, test a domain session (not `nltest /sc_verify`, which
stays stale), repair with `Test-ComputerSecureChannel -Repair`.
- Builds are not byte-reproducible (two unchanged assemblies differ per build):
hash each candidate and its package separately.
- The fixture's account for case 3 gets a new name for each new fixture
(`NtfsLiveSubject` and four digits). In the matrix lab, after an account was
deleted and created again with the same name, the remote authorization
managers (the client's for the default `-ServerName`, the file server's for its
name) answered for about ten minutes as if it had no groups (`0x100000`), for
the baseline and for the final candidate alike, while the Kerberos S4U logon of
the oracle, the
name resolution, and the local manager were right in the same second. A replay
with the baseline and the final candidate alternating failed the baseline in two
of three cells and the final candidate in one of three (not counting the warm-up
cell). The mechanism in Windows is unknown; a model with one lifetime (9.95 to
10.25 minutes for both tests, to within 0.05 minute) fits all 43 Admin-role runs
of 27 cells. When the accounts are created again within seconds, the S4U
logon itself returns the old account for 7 to 15 minutes. A `klist purge`,
`nltest /sc_reset`, a DNS flush, and a restart of the Kerberos service didn't
help. `Probe-AccountRecreation.ps1`, `Export-CellTimeline.ps1`, and
`Test-StaleAuthzModel.ps1` show it.
- `net.exe localgroup` lists a local user by its bare name and the entry of a
deleted domain account as its SID (or as its cached name for a while);
deleting a local user removes its entries from the local groups, so only the
entries of domain accounts stay orphaned. `Test-MatrixCleanup.ps1` finds the
entries of the account probe in Performance Log Users by a name with
`NtfsProbe` or by any unresolved `S-1-5-21-…` SID (every such member counts as
the probe's), and its profiles by their folder `C:\Users\NtfsProbe*`. The
cached-name form met real residue in a test; the bare-SID form and a profile
that stays loaded didn't.

Loading…
Cancel
Save