Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# windows-tier-lib-modules — self-referential bootstrap evidence

## What changed

`scripts/lib/windows-verification-scope.ps1` tier-2 (`deploy_dryrun`) pattern:

```diff
-'^scripts/lib/(?!platform/)[^/]+\.ps1$',
+'^scripts/lib/(?!platform/)[^/]+\.psm?1$',
```

A PowerShell **module** directly under `scripts/lib/` now owes the same Windows evidence as a
script there.

## Why it is bootstrap debt

This file decides how much Windows verification evidence **every other PR** owes. A branch that
changes it verifies the new classification with the changed checker itself, so the pre-merge run
cannot prove that what merges is what gets enforced. The obligation closes with a post-merge
fixpoint run from `main`.

Mechanism paths changed by this PR (both declared in the ledger entry):

- `scripts/lib/windows-verification-scope.ps1`
- `scripts/self-referential-bootstrap-ledger.json`

`scripts/tests/test-windows-verification-scope.ps1` is also changed but is **not** a classified
mechanism path (`Get-SelfReferentialMechanismPaths` returns only the two above for this PR's
changed-path set), so it is deliberately not declared.

## The gap, in one line

`scripts/lib/rebuild-test-deploy.ps1` is tier 2 and imports `scripts/lib/StructLog.psm1`, which was
tier 0 — a deploy library's own dependency owed no Windows evidence.

Full before/after classification, the evidence that this was oversight rather than design, and the
contract command runs are in [`verification.txt`](verification.txt).

## Verification contract

| Field | Value |
|---|---|
| id | `windows-tier-lib-modules/v1` |
| command_ids | `test-windows-verification-scope`, `test-pr-body-evidence`, `invoke-powershell-static` |
| contract_sha256 | `5545d1f629a74c7062da9a7c0bac5e15dced6494982be658b962ad659146d5be` |

All three passed on this branch pre-merge; the same ordered set must pass from `main` to close the
entry.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
windows-tier-lib-modules — pre-merge verification

branch : fix/windows-tier-covers-lib-modules
base : 35d6672ff92c131855499157537c8c63e410898e
date : 2026-08-17T07:58:59Z

Why this is bootstrap debt: this PR changes scripts/lib/windows-verification-scope.ps1, which
decides how much Windows evidence every OTHER PR owes. The pre-change checker cannot prove that
the post-change classification is the one enforced after merge, because the branch runs the
changed checker against itself. Only a post-merge run from main closes that.


## 1. Gap reproduction — BASE copy of the checker, unmodified

The base checker was materialized with `git show 35d6672:scripts/lib/windows-verification-scope.ps1`
and dot-sourced directly, so this is the classification origin/main actually enforces today.

scripts/lib/StructLog.psm1 Tier=0 Id=none Required=False
scripts/lib/rebuild-test-deploy.ps1 Tier=2 Id=deploy_dryrun Required=True

The asymmetry is the finding: scripts/lib/rebuild-test-deploy.ps1 imports StructLog.psm1
(`grep -rl "StructLog\.psm1" scripts/` lists it), so a tier-2 deploy library depends on a file
that the same pattern classifies as owing no Windows evidence at all. The dependency escaped the
tier its dependant sits in.

Not a deliberate exclusion:
- scripts/lib/StructLog.psm1 was added 2026-05-27 (#126); the pattern was written 2026-08-05
(#467), so .psm1 already existed under scripts/lib/ when the author typed `\.ps1$`.
- scripts/tests/test-windows-verification-scope.ps1 documents its "deliberate exclusions"
(docs, tests, frontend, README) and mentions neither `psm1` nor `module` anywhere.
- The pattern already treats EVERY non-platform .ps1 directly under scripts/lib/ as a deploy
library, including design-system-gate.ps1, pr-review-agent.ps1, openspec-lifecycle.ps1 and
self-referential-bootstrap.ps1 — none of which are deploy libraries. The design accepts
over-inclusion; the module extension was the one PowerShell file kind escaping it.


## 2. After the fix — HEAD copy

scripts/lib/StructLog.psm1 Tier=2 Id=deploy_dryrun Required=True
scripts/lib/rebuild-test-deploy.ps1 Tier=2 Id=deploy_dryrun Required=True
scripts/lib/platform/adapter.psm1 Tier=1 Id=platform_unit Required=True
scripts/lib/SomeModule.psd1 Tier=0 Id=none Required=False
scripts/lib/nested/helper.psm1 Tier=0 Id=none Required=False

The platform/ exclusion survives in both file kinds, and the widening does not over-reach: a
module manifest (.psd1) is not executable deploy logic, and nested paths stay out for the same
reason the .ps1 half of this pattern excludes them.


## 3. Verification contract commands (run on this branch)

$ pwsh -File scripts/tests/test-windows-verification-scope.ps1
[test-windows-verification-scope] all assertions passed

$ pwsh -File scripts/tests/test-pr-body-evidence.ps1
[test-pr-body-evidence] all assertions passed

$ pwsh -File scripts/tests/invoke-powershell-static.ps1
[invoke-powershell-static] passed


## 4. Known consequence for other branches

After merge, scripts/lib/agent-governance-policy.psm1 (branch
chore/agent-governance-policy-report-only) classifies as deploy_dryrun rather than none. That PR
must then declare the tier and carry deploy dry-run evidence, or land before this one. This is the
fix working as intended, not a regression, but it is a real cross-branch obligation.
7 changes: 6 additions & 1 deletion scripts/lib/windows-verification-scope.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ $script:WindowsVerificationTiers = @(
'^scripts/deploy-target-registry\.json$',
'^scripts/dev/rebuild-test-deploy\.ps1$',
'^scripts/stop-all\.ps1$',
'^scripts/lib/(?!platform/)[^/]+\.ps1$',
# .psm?1, not .ps1: a PowerShell MODULE directly under scripts/lib is a deploy library
# by the same reasoning as a script there, and modules are more likely to be shared
# dependencies. scripts/lib/StructLog.psm1 is imported by scripts/lib/rebuild-test-deploy.ps1,
# which this same pattern already puts in this tier - without the m? the dependency
# escaped the tier its dependant sits in.
'^scripts/lib/(?!platform/)[^/]+\.psm?1$',
'^compose\.[^/]+\.yml$'
)
Evidence = '.\scripts\deploy.ps1 -DryRun passes on Windows'
Expand Down
25 changes: 25 additions & 0 deletions scripts/self-referential-bootstrap-ledger.json
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,31 @@
"docs/evidence/conversion-service-ci-wiring/fixpoint/summary.md"
]
}
},
{
"id": "windows-tier-lib-modules",
"status": "open",
"pr": 570,
"opened_at": "2026-08-17T09:33:05Z",
"reason": "this PR changes scripts/lib/windows-verification-scope.ps1, the checker that decides how much Windows verification evidence every other PR owes; the branch can only exercise the new classification with the changed checker itself, so no pre-merge run can prove that what merges is what gets enforced, and only a post-merge run from main closes that gap",
"verification_mechanism_paths": [
"scripts/self-referential-bootstrap-ledger.json",
"scripts/lib/windows-verification-scope.ps1"
],
"verification_contract": {
"id": "windows-tier-lib-modules/v1",
"command_ids": [
"test-windows-verification-scope",
"test-pr-body-evidence",
"invoke-powershell-static"
],
"contract_sha256": "5545d1f629a74c7062da9a7c0bac5e15dced6494982be658b962ad659146d5be"
},
"bootstrap_evidence_refs": [
"docs/evidence/windows-tier-lib-modules/self-referential-bootstrap/README.md",
"docs/evidence/windows-tier-lib-modules/self-referential-bootstrap/verification.txt"
],
"fixpoint": null
}
]
}
14 changes: 13 additions & 1 deletion scripts/tests/test-windows-verification-scope.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ $t2a = Get-Tier @('scripts/deploy.ps1')
Assert-True ($t2a.Tier -eq 2 -and $t2a.Id -eq 'deploy_dryrun') "deploy.ps1 -> tier 2 (got $($t2a.Id))"
$t2b = Get-Tier @('scripts/lib/rebuild-test-deploy.ps1')
Assert-True ($t2b.Tier -eq 2) "scripts/lib top-level ps1 -> tier 2 (got $($t2b.Tier))"
# A module under scripts/lib owes the same evidence as a script there. StructLog.psm1 is imported by
# scripts/lib/rebuild-test-deploy.ps1 (tier 2), so excluding .psm1 let a deploy-library dependency
# escape the tier its dependant sits in.
$t2bm = Get-Tier @('scripts/lib/StructLog.psm1')
Assert-True ($t2bm.Tier -eq 2 -and $t2bm.Id -eq 'deploy_dryrun') "scripts/lib top-level psm1 -> tier 2 (got $($t2bm.Id))"
Assert-True ($t2bm.Required) 'a scripts/lib module owes Windows deploy dry-run evidence'
# The platform exclusion must survive the extension widening in both file kinds.
Assert-True ((Get-Tier @('scripts/lib/platform/adapter.psm1')).Id -eq 'platform_unit') 'platform modules stay tier 1, not tier 2'
$t2c = Get-Tier @('compose.host-kit.yml')
Assert-True ($t2c.Tier -eq 2) "compose file -> tier 2 (got $($t2c.Tier))"
$t2d = Get-Tier @('scripts/stop-all.ps1')
Expand Down Expand Up @@ -74,7 +82,11 @@ foreach ($exempt in @(
'scripts/tests/test-platform-adapter.ps1',
'web-viewer-sample/src/Window.tsx',
'bim-streaming-server/README.md',
'README.md'
'README.md',
# The .psm1 widening must not over-reach: a module manifest is not executable deploy logic, and
# nested paths stay out for the same reason the .ps1 half of this pattern excludes them.
'scripts/lib/SomeModule.psd1',
'scripts/lib/nested/helper.psm1'
)) {
$none = Get-Tier @($exempt)
Assert-True (-not $none.Required) "$exempt must not owe Windows evidence (got tier $($none.Tier))"
Expand Down
Loading