Skip to content

Commit f56d511

Browse files
committed
Validate product website and native coverage gates
Build a product-first Three.js site from authenticated GitHub JSON evidence. Include independent TUnit/Node/CDP qualification and required analyzer MTP coverage, with scoped candidate source and unchanged runtime baseline. Public publication and database qualification remain separate.
1 parent 9c570f8 commit f56d511

322 files changed

Lines changed: 191243 additions & 391 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.editorconfig‎

Lines changed: 508 additions & 7 deletions
Large diffs are not rendered by default.

‎.github/workflows/AGENTS.md‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# GitHub Actions workflows
2+
3+
## Purpose and entry points
4+
- Owns repository CI qualification and GitHub Pages publication workflows.
5+
- Canonical workflows: `ci.yml` (restore, Release build, TUnit unit/integration/recovery suites and comparison artifact production) and `pages.yml` (verified artifact download, site checks/build and Pages deployment).
6+
7+
## Ownership and boundaries
8+
- Workflow changes belong to the feature or infrastructure contract they implement and must preserve the repository's single-repository, canonical-slice architecture. Workflow YAML is delivery infrastructure, not a place to hide missing product behavior.
9+
- Qualification and tests must run in GitHub Actions. Do not add local qualification shortcuts, skipped suites, fake runtime proof, unaudited performance values, or claims beyond the run's actual SHA and artifacts.
10+
- Keep permissions least-privileged, actions pinned, secrets out of logs, and Pages evidence bound to the successful source run/revision.
11+
12+
## Commands and evidence
13+
- CI test commands are the workflow's actual invocations: `dotnet build KeyLoad.slnx --no-restore --configuration Release`; `dotnet test --project tests/KeyLoad.UnitTests --no-build --no-restore --configuration Release`; equivalent commands for `tests/KeyLoad.IntegrationTests`, `tests/KeyLoad.RecoveryTests` and `tests/KeyLoad.ComparisonTests` as defined in `ci.yml`.
14+
- Pages invokes `node --test site/scripts/measurements.test.mjs` and `node site/scripts/build.mjs` against the downloaded comparison artifact. Dispatch/inspect using the root workflow, retain run/job URLs, exact SHA and artifacts. These checks are not to be run locally as substitutes for CI qualification.
15+
16+
## Skills and protected risks
17+
- Applicable skills: none installed; skill installation is prohibited by owner direction.
18+
- Never bypass branch protections, expose tokens, downgrade a required suite, or conflate build success with RF3, recovery, endurance or production readiness.
19+
20+
## Read-first and canonical slice ownership
21+
- Read the [root policy](../../AGENTS.md), [architecture map](../../docs/Architecture.md), [RepositoryGovernance feature](../../docs/Features/RepositoryGovernance.md), and [ADR-032](../../docs/ADR/ADR-032-mcaf-governance.md) first.
22+
- Owned slices: `RepositoryGovernance` and `BenchmarkComparisons`; target paths: `Features/RepositoryGovernance/` and `Features/BenchmarkComparisons/`.
23+
- Workflow edits are shared delivery infrastructure for these slices; retain the exact evidence provenance and permission boundaries.
24+
- `pages.yml` currently invokes Node’s `node --test` runner; this conflicts with root policy requiring TUnit for all tests and is migration debt, not permission to add another framework.
25+
26+
## ADR-040 site qualification migration
27+
- Existing Node command listings above are the preserved historical baseline. Root TUnit policy controls their replacement with the full independently buildable `tests/KeyLoad.SiteTests` suite in `pages.yml`. Its explicit validation-only mode qualifies candidate website source against downloaded successful-main-CI historical reports and uploads review artifacts without deploying.
28+
- Validation and publication jobs retain least privileges and separate website-source and measured-source revisions. Publication must continue to use qualified measured-source checkout and cannot infer current database qualification from a historical site test. A validation result never authorizes DNS or public deployment.

‎.github/workflows/pages.yml‎

Lines changed: 139 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,136 @@ on:
55
branches: [main]
66
types: [completed]
77
workflow_dispatch:
8+
inputs:
9+
mode:
10+
description: Validate website source without deployment, or publish qualified source
11+
required: true
12+
default: validate
13+
type: choice
14+
options: [validate, publish]
15+
evidence_run:
16+
description: Successful main push KeyLoad CI run (blank selects latest successful run)
17+
required: false
18+
type: string
819
permissions:
920
contents: read
1021
actions: read
11-
pages: write
12-
id-token: write
1322
concurrency:
1423
group: keyload-pages
1524
cancel-in-progress: false
1625
jobs:
26+
validate:
27+
if: github.event_name == 'workflow_dispatch' && inputs.mode == 'validate'
28+
runs-on: ubuntu-latest
29+
timeout-minutes: 20
30+
steps:
31+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32+
- name: Select authenticated historical evidence
33+
id: evidence
34+
env:
35+
GH_TOKEN: ${{ github.token }}
36+
GH_REPO: ${{ github.repository }}
37+
REQUESTED_RUN: ${{ inputs.evidence_run }}
38+
shell: bash
39+
run: |
40+
run_id="$REQUESTED_RUN"
41+
if [ -z "$run_id" ]; then
42+
run_id=$(gh run list --workflow ci.yml --branch main --event push --status success --limit 1 --json databaseId --jq '.[0].databaseId')
43+
fi
44+
[[ "$run_id" =~ ^[1-9][0-9]*$ ]]
45+
run=$(gh api "repos/$GH_REPO/actions/runs/$run_id")
46+
revision=$(jq -r --arg repo "$GH_REPO" 'select(.conclusion == "success" and .event == "push" and .head_branch == "main" and .head_repository.full_name == $repo and .path == ".github/workflows/ci.yml") | .head_sha' <<< "$run")
47+
[[ "$revision" =~ ^[a-f0-9]{40}$ ]]
48+
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"
49+
echo "revision=$revision" >> "$GITHUB_OUTPUT"
50+
mkdir -p artifacts/site-evidence
51+
printf '%s\n' "$run" > artifacts/site-evidence/run.json
52+
gh api --paginate --slurp "repos/$GH_REPO/actions/runs/$run_id/jobs?per_page=100" | jq '{total_count: .[0].total_count, jobs: [.[].jobs[]]}' > artifacts/site-evidence/jobs.json
53+
jq -e '.total_count == (.jobs | length) and (.jobs | length > 0 and all(.[]; .status == "completed" and .conclusion == "success"))' artifacts/site-evidence/jobs.json
54+
gh api --paginate --slurp "repos/$GH_REPO/actions/runs/$run_id/artifacts?per_page=100" | jq '{total_count: .[0].total_count, artifacts: [.[].artifacts[]]}' > artifacts/site-evidence/artifacts.json
55+
jq -e '.total_count == (.artifacts | length)' artifacts/site-evidence/artifacts.json
56+
jq -e '[.artifacts[] | select(.name == "comparison-suite" and .expired == false)] | length == 1' artifacts/site-evidence/artifacts.json
57+
gh run download "$run_id" --name comparison-suite --dir artifacts/comparisons
58+
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
59+
with:
60+
global-json-file: global.json
61+
- name: Retain candidate source and runtime versions
62+
shell: bash
63+
run: |
64+
git rev-parse HEAD > artifacts/site-evidence/website-revision.txt
65+
git ls-files -z | xargs -0 sha256sum > artifacts/site-evidence/source.sha256
66+
node --version > artifacts/site-evidence/node-version.txt
67+
dotnet --info > artifacts/site-evidence/dotnet-info.txt
68+
rg --files --hidden --no-ignore -0 artifacts/comparisons | sort -z | xargs -0 sha256sum > artifacts/site-evidence/report-files.sha256
69+
chrome=$(command -v google-chrome || command -v google-chrome-stable || command -v chromium || command -v chromium-browser)
70+
test -n "$chrome" && test -x "$chrome"
71+
"$chrome" --version > artifacts/site-evidence/browser-version.txt
72+
printf 'KEYLOAD_SITE_BROWSER=%s\n' "$chrome" >> "$GITHUB_ENV"
73+
- name: Qualify required analyzer dependency
74+
shell: bash
75+
run: |
76+
dotnet restore tests/KeyLoad.Analyzers.Tests/KeyLoad.Analyzers.Tests.csproj
77+
dotnet build tests/KeyLoad.Analyzers.Tests/KeyLoad.Analyzers.Tests.csproj --no-restore --configuration Release
78+
mkdir -p artifacts/site-evidence/analyzer-coverage
79+
cp scripts/Features/CodeQuality/site-analyzer-coverage.settings.xml artifacts/site-evidence/analyzer-coverage/coverage.config.xml
80+
pwsh --version > artifacts/site-evidence/powershell-version.txt
81+
pwsh -NoProfile -File scripts/Features/CodeQuality/site-analyzer-coverage.ps1 -Mode Prepare -Repository "$GITHUB_WORKSPACE" -Contract "$GITHUB_WORKSPACE/scripts/Features/CodeQuality/site-analyzer-coverage.contract.json" -EvidenceRoot "$GITHUB_WORKSPACE/artifacts/site-evidence/analyzer-coverage"
82+
dotnet test --project tests/KeyLoad.Analyzers.Tests --no-build --no-restore --configuration Release --report-trx --results-directory artifacts/site-evidence/analyzer-tests --coverage --coverage-settings "$GITHUB_WORKSPACE/artifacts/site-evidence/analyzer-coverage/coverage.config.xml" --coverage-output-format cobertura --coverage-output "$GITHUB_WORKSPACE/artifacts/site-evidence/analyzer-coverage/coverage.cobertura.xml"
83+
- name: Enforce native analyzer coverage counts
84+
if: success() || failure()
85+
shell: pwsh
86+
run: ./scripts/Features/CodeQuality/site-analyzer-coverage.ps1 -Mode Verify -Repository "$env:GITHUB_WORKSPACE" -Contract "$env:GITHUB_WORKSPACE/scripts/Features/CodeQuality/site-analyzer-coverage.contract.json" -EvidenceRoot "$env:GITHUB_WORKSPACE/artifacts/site-evidence/analyzer-coverage" -CoverageReport "$env:GITHUB_WORKSPACE/artifacts/site-evidence/analyzer-coverage/coverage.cobertura.xml"
87+
- name: Restore and build independent site qualification
88+
run: |
89+
dotnet restore tests/KeyLoad.SiteTests/KeyLoad.SiteTests.csproj
90+
dotnet build tests/KeyLoad.SiteTests/KeyLoad.SiteTests.csproj --no-restore --configuration Release
91+
- name: Verify focused format
92+
shell: bash
93+
run: |
94+
dotnet format src/KeyLoad.Analyzers/KeyLoad.Analyzers.csproj --verify-no-changes --no-restore --severity warn --verbosity minimal > artifacts/site-evidence/format-analyzers.txt 2>&1
95+
dotnet format tests/KeyLoad.Analyzers.Tests/KeyLoad.Analyzers.Tests.csproj --verify-no-changes --no-restore --severity warn --verbosity minimal > artifacts/site-evidence/format-analyzer-tests.txt 2>&1
96+
dotnet format tests/KeyLoad.SiteTests/KeyLoad.SiteTests.csproj --verify-no-changes --no-restore --severity warn --verbosity minimal > artifacts/site-evidence/format-site-tests.txt 2>&1
97+
- name: Validate actual candidate governance inventory
98+
run: node scripts/Features/RepositoryGovernance/verify.mjs
99+
- name: Run full site TUnit suite
100+
env:
101+
KEYLOAD_SITE_REPORTS: ${{ github.workspace }}/artifacts/comparisons
102+
KEYLOAD_SITE_REPOSITORY: ${{ github.workspace }}
103+
KEYLOAD_SITE_EVIDENCE_RUN: ${{ steps.evidence.outputs.run_id }}
104+
KEYLOAD_SITE_MEASURED_REVISION: ${{ steps.evidence.outputs.revision }}
105+
KEYLOAD_SITE_COVERAGE: ${{ github.workspace }}/artifacts/site-evidence/js-coverage
106+
NODE_V8_COVERAGE: ${{ github.workspace }}/artifacts/site-evidence/js-coverage/node
107+
run: |
108+
mkdir -p artifacts/site-evidence/js-coverage/node
109+
dotnet test --project tests/KeyLoad.SiteTests --no-build --no-restore --configuration Release --report-trx --results-directory artifacts/site-evidence/site-tests
110+
- name: Build candidate review artifact
111+
env:
112+
EVIDENCE_RUN: ${{ steps.evidence.outputs.run_id }}
113+
EVIDENCE_REVISION: ${{ steps.evidence.outputs.revision }}
114+
WEBSITE_REVISION: ${{ github.sha }}
115+
run: node site/scripts/build.mjs --reports=artifacts/comparisons --output=_site --revision="$EVIDENCE_REVISION" --evidence-url="https://github.com/${{ github.repository }}/actions/runs/$EVIDENCE_RUN" --site-revision="$WEBSITE_REVISION"
116+
- name: Retain source, test and preview evidence
117+
if: always()
118+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
119+
with:
120+
name: site-qualification-${{ github.sha }}
121+
path: |
122+
_site
123+
artifacts/site-evidence
124+
artifacts/code-quality/KeyLoad.SiteTests
125+
artifacts/code-quality/KeyLoad.Analyzers
126+
artifacts/code-quality/KeyLoad.Analyzers.Tests
127+
tests/KeyLoad.Analyzers.Tests/bin/Release/net10.0/KeyLoad.Analyzers.dll
128+
tests/KeyLoad.Analyzers.Tests/bin/Release/net10.0/KeyLoad.Analyzers.pdb
129+
tests/KeyLoad.SiteTests/**/TestResults/**
130+
tests/KeyLoad.Analyzers.Tests/**/TestResults/**
17131
publish:
18-
if: github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event != 'pull_request' && github.event.workflow_run.head_repository.full_name == github.repository)
132+
if: (github.event_name == 'workflow_dispatch' && inputs.mode == 'publish') || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push' && github.event.workflow_run.head_repository.full_name == github.repository)
133+
permissions:
134+
contents: read
135+
actions: read
136+
pages: write
137+
id-token: write
19138
runs-on: ubuntu-latest
20139
timeout-minutes: 10
21140
environment:
@@ -28,30 +147,42 @@ jobs:
28147
GH_TOKEN: ${{ github.token }}
29148
GH_REPO: ${{ github.repository }}
30149
COMPLETED_RUN: ${{ github.event.workflow_run.id }}
150+
REQUESTED_RUN: ${{ inputs.evidence_run }}
31151
shell: bash
32152
run: |
33-
run_id="$COMPLETED_RUN"
153+
run_id="${COMPLETED_RUN:-$REQUESTED_RUN}"
34154
if [ -z "$run_id" ]; then
35155
run_id=$(gh run list --workflow ci.yml --branch main --event push --status success --limit 1 --json databaseId --jq '.[0].databaseId')
36156
fi
37-
test -n "$run_id" && test "$run_id" != "null"
38-
revision=$(gh api "repos/$GH_REPO/actions/runs/$run_id" --jq '.head_sha')
157+
[[ "$run_id" =~ ^[1-9][0-9]*$ ]]
158+
run=$(gh api "repos/$GH_REPO/actions/runs/$run_id")
159+
revision=$(jq -r --arg repo "$GH_REPO" 'select(.conclusion == "success" and .event == "push" and .head_branch == "main" and .head_repository.full_name == $repo and .path == ".github/workflows/ci.yml") | .head_sha' <<< "$run")
160+
[[ "$revision" =~ ^[a-f0-9]{40}$ ]]
39161
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"
40162
echo "revision=$revision" >> "$GITHUB_OUTPUT"
41163
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
42164
with:
43165
ref: ${{ steps.evidence.outputs.revision }}
166+
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
167+
with:
168+
global-json-file: global.json
44169
- name: Build from verified comparison reports
45170
env:
46171
GH_TOKEN: ${{ github.token }}
47172
GH_REPO: ${{ github.repository }}
48173
EVIDENCE_RUN: ${{ steps.evidence.outputs.run_id }}
49174
EVIDENCE_REVISION: ${{ steps.evidence.outputs.revision }}
175+
KEYLOAD_SITE_REPORTS: ${{ github.workspace }}/artifacts/comparisons
176+
KEYLOAD_SITE_REPOSITORY: ${{ github.workspace }}
177+
KEYLOAD_SITE_EVIDENCE_RUN: ${{ steps.evidence.outputs.run_id }}
178+
KEYLOAD_SITE_MEASURED_REVISION: ${{ steps.evidence.outputs.revision }}
50179
shell: bash
51180
run: |
52181
gh run download "$EVIDENCE_RUN" --name comparison-suite --dir artifacts/comparisons
53-
node --test site/scripts/measurements.test.mjs
54-
node site/scripts/build.mjs --reports=artifacts/comparisons --output=_site --revision="$EVIDENCE_REVISION" --evidence-url="https://github.com/$GH_REPO/actions/runs/$EVIDENCE_RUN"
182+
dotnet restore tests/KeyLoad.SiteTests/KeyLoad.SiteTests.csproj
183+
dotnet build tests/KeyLoad.SiteTests/KeyLoad.SiteTests.csproj --no-restore --configuration Release
184+
dotnet test --project tests/KeyLoad.SiteTests --no-build --no-restore --configuration Release
185+
node site/scripts/build.mjs --reports=artifacts/comparisons --output=_site --revision="$EVIDENCE_REVISION" --evidence-url="https://github.com/$GH_REPO/actions/runs/$EVIDENCE_RUN" --site-revision="$EVIDENCE_REVISION"
55186
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
56187
- uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
57188
with:

0 commit comments

Comments
 (0)