Skip to content

Commit 96f4e91

Browse files
authored
Merge pull request #16 from WebFirstLanguage/codex/wfl-orm-migrations
feat(database): add a WFL ORM and audited SQLite migrations
2 parents 4ec5c88 + fd1a65e commit 96f4e91

118 files changed

Lines changed: 11156 additions & 884 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.

‎.github/workflows/governance.yml‎

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- os: windows-latest
2727
runner: windows-latest
2828
runs-on: ${{ matrix.runner }}
29-
timeout-minutes: 10
29+
timeout-minutes: 15
3030
steps:
3131
- uses: actions/checkout@v4
3232
with:
@@ -35,7 +35,67 @@ jobs:
3535
- uses: actions/setup-python@v5
3636
with:
3737
python-version: '3.12'
38+
- name: Provision the current WFL nightly
39+
shell: pwsh
40+
run: |
41+
$ErrorActionPreference = 'Stop'
42+
# The GitHub daily release is an immutable mirror. The canonical
43+
# publisher can release a newer runtime on the same day to this CDN.
44+
$cdn = 'https://wfl.nyc3.cdn.digitaloceanspaces.com'
45+
# A previously cached pointer can retain the CDN's older one-hour TTL.
46+
$publicationUri = "$cdn/status.json?request=$([guid]::NewGuid().ToString('N'))"
47+
$publication = Invoke-RestMethod -Uri $publicationUri
48+
if ($publication.result -ne 'success' -or $publication.branch -ne 'main' -or
49+
$publication.version -notmatch '^\d+\.\d+\.\d+$' -or
50+
$publication.sha -notmatch '^[a-f0-9]{40}$') {
51+
throw 'Invalid official WFL publication record'
52+
}
53+
$releaseVersion = [regex]::Escape($publication.version)
54+
$pattern = if ($IsWindows) { "^wfl-$releaseVersion\.msi$" } else { "^wfl-$releaseVersion-linux-x86_64-[a-f0-9]{7,40}\.tar\.gz$" }
55+
$assets = @($publication.message -split '\s+' | Where-Object { $_ -match $pattern })
56+
if ($assets.Count -ne 1) { throw 'Publication must name one immutable platform-specific WFL asset' }
57+
$assetName = $assets[0]
58+
if (-not $IsWindows -and $assetName -match '-linux-x86_64-([a-f0-9]{7,40})\.tar\.gz$') {
59+
if (-not $publication.sha.StartsWith($Matches[1])) { throw 'WFL artifact revision does not match publication' }
60+
}
61+
$assetUrl = "$cdn/releases/$assetName"
62+
$checksum = (Invoke-WebRequest -Uri "$assetUrl.sha256").Content.Trim()
63+
$checksumPattern = '^([a-fA-F0-9]{64})\s+\*?' + [regex]::Escape($assetName) + '$'
64+
if ($checksum -notmatch $checksumPattern) { throw 'Invalid immutable WFL checksum sidecar' }
65+
$expectedDigest = $Matches[1].ToLowerInvariant()
66+
$runtimeRoot = Join-Path $env:RUNNER_TEMP 'scriptorium-wfl'
67+
New-Item -ItemType Directory -Path $runtimeRoot -Force | Out-Null
68+
$archive = Join-Path $runtimeRoot $assetName
69+
Invoke-WebRequest -Uri $assetUrl -OutFile $archive
70+
$digest = (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant()
71+
if ($expectedDigest -ne $digest) { throw 'WFL release asset digest mismatch' }
72+
if ($IsWindows) {
73+
$expanded = Join-Path $runtimeRoot 'expanded'
74+
$arguments = @('/a', "`"$archive`"", '/qn', "TARGETDIR=`"$expanded`"")
75+
$installer = Start-Process msiexec.exe -ArgumentList $arguments -Wait -PassThru -WindowStyle Hidden
76+
if ($installer.ExitCode -ne 0) { throw "WFL extraction failed: $($installer.ExitCode)" }
77+
$programs = @(Get-ChildItem -LiteralPath $expanded -Filter wfl.exe -File -Recurse)
78+
} else {
79+
tar -xzf $archive -C $runtimeRoot
80+
if ($LASTEXITCODE -ne 0) { throw 'WFL extraction failed' }
81+
$programs = @(Get-ChildItem -LiteralPath $runtimeRoot -Filter wfl -File -Recurse)
82+
}
83+
if ($programs.Count -ne 1) { throw 'Expected one extracted WFL executable' }
84+
$runtimePath = $programs[0].FullName
85+
$programs[0].DirectoryName | Out-File -FilePath $env:GITHUB_PATH -Append
86+
$version = & $runtimePath --version
87+
if ($LASTEXITCODE -ne 0) { throw 'Extracted WFL runtime did not start' }
88+
if ($version -ne "WebFirst Language (WFL) version $($publication.version)") { throw 'WFL executable version does not match publication' }
89+
@(
90+
'### Governance runtime',
91+
"- Publication: $cdn/status.json",
92+
"- WFL revision: $($publication.sha)",
93+
"- Asset: $assetUrl",
94+
"- SHA256: $digest",
95+
"- Runtime: $version",
96+
"- Scriptorium: $env:GITHUB_SHA"
97+
) | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append
3898
- name: Test repository tooling
39-
run: python -m unittest discover -s tests/tooling -v
99+
run: wfl scripts/run_tests.wfl --group tooling
40100
- name: Check repository hygiene
41101
run: python scripts/check_repo_hygiene.py
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
name: WFL ORM capability gates
2+
3+
on:
4+
push:
5+
branches: [codex/wfl-orm-migrations]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: orm-capabilities-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
runtime:
17+
name: Resolve current nightly
18+
runs-on: blacksmith-2vcpu-ubuntu-2404
19+
timeout-minutes: 5
20+
outputs:
21+
image: ${{ steps.runtime.outputs.image }}
22+
steps:
23+
- uses: actions/checkout@v4
24+
with:
25+
persist-credentials: false
26+
submodules: recursive
27+
- name: Pull nightly and record provenance
28+
id: runtime
29+
shell: bash
30+
run: |
31+
docker pull bsbyrdwfl/wfl:nightly
32+
image="$(docker image inspect --format '{{index .RepoDigests 0}}' bsbyrdwfl/wfl:nightly)"
33+
echo "image=$image" >> "$GITHUB_OUTPUT"
34+
version="$(docker run --rm --network none "$image" --version)"
35+
{
36+
echo '### ORM prerequisite evidence (not completed ORM validation)'
37+
echo "- Image: $image"
38+
echo "- Runtime: $version"
39+
echo "- Scriptorium: $(git rev-parse HEAD)"
40+
echo "- Scribe: $(git -C lib/scribe rev-parse HEAD)"
41+
echo '- Every probe, fixture, HTTP driver and assertion is WFL.'
42+
echo '- Unmet capability assertions fail their jobs without suppression.'
43+
} | tee -a "$GITHUB_STEP_SUMMARY"
44+
45+
probes:
46+
name: ${{ matrix.suite }}
47+
needs: runtime
48+
runs-on: blacksmith-2vcpu-ubuntu-2404
49+
timeout-minutes: 5
50+
strategy:
51+
fail-fast: false
52+
matrix:
53+
include:
54+
- suite: orm-native-baseline
55+
path: tests/runtime/orm-native-baseline.test.wfl
56+
- suite: transaction-validation-capability
57+
path: tests/runtime/transaction-validation-capability.test.wfl
58+
- suite: rebuild-foreign-keys-capability
59+
path: tests/runtime/rebuild-foreign-keys-capability.test.wfl
60+
- suite: process-capabilities
61+
path: tests/runtime/process-capabilities.test.wfl
62+
- suite: http-redirect-capability
63+
path: tests/runtime/http-redirect-capability.test.wfl
64+
- suite: media-body-limit
65+
path: tests/integration/media.test.wfl
66+
env:
67+
RESOLVED_IMAGE: ${{ needs.runtime.outputs.image }}
68+
PROBE_SUITE: ${{ matrix.path }}
69+
TEST_CONTAINER: scriptorium-probe-${{ github.run_id }}-${{ github.run_attempt }}-${{ strategy.job-index }}
70+
steps:
71+
- uses: actions/checkout@v4
72+
with:
73+
persist-credentials: false
74+
submodules: recursive
75+
- name: Invoke WFL capability suite
76+
shell: bash
77+
run: |
78+
docker pull "$RESOLVED_IMAGE"
79+
docker run --rm --init --name "$TEST_CONTAINER" \
80+
--user 0:0 --entrypoint /bin/sh \
81+
--mount "type=bind,source=$GITHUB_WORKSPACE,target=/source,readonly" \
82+
--env PROBE_SUITE --workdir /work "$RESOLVED_IMAGE" -ec '
83+
cp -a /source/. /work/
84+
exec wfl --test "$PROBE_SUITE"
85+
'
86+
- name: Clean up disposable container
87+
if: always()
88+
shell: bash
89+
run: |
90+
if docker container inspect "$TEST_CONTAINER" >/dev/null 2>&1; then
91+
docker container rm --force "$TEST_CONTAINER"
92+
fi

‎.github/workflows/update-scribe.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ jobs:
136136
echo
137137
echo '| Check or exact command | Result and evidence |'
138138
echo '|---|---|'
139-
echo '| `python3 scripts/run_tests.py --include-scribe` | Pending — this workflow prepares the dependency bump. Link WFL tests results for the current revision, including the nightly image digest and runtime version; record failures. |'
140-
echo '| `python -m unittest discover -s tests/tooling -v` | Pending — Governance results are not verified by this workflow. Link results for the current revision. |'
139+
echo '| `wfl --execution-timeout 1200 scripts/run_tests.wfl` | Pending — this workflow prepares the dependency bump. Link WFL tests results for the current revision, including the nightly image digest and runtime version; record failures. |'
140+
echo '| `wfl scripts/run_tests.wfl --group tooling` | Pending — Governance results are not verified by this workflow. Link results for the current revision. |'
141141
echo '| `python scripts/check_repo_hygiene.py` | Pending — Governance results are not verified by this workflow. Link results for the current revision. |'
142142
echo '| Affected HTTP/UI rendering journeys | Not run — upstream diff review is needed to identify affected paths. Record setup, expected/actual outcome, and evidence. |'
143143
echo

‎.github/workflows/wfl-tests.yml‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
wfl-tests:
1919
name: WFL nightly (Blacksmith)
2020
runs-on: blacksmith-2vcpu-ubuntu-2404
21-
timeout-minutes: 15
21+
timeout-minutes: 30
2222
env:
2323
WFL_IMAGE: bsbyrdwfl/wfl:nightly
2424
TEST_CONTAINER: scriptorium-tests-${{ github.run_id }}-${{ github.run_attempt }}
@@ -36,36 +36,40 @@ jobs:
3636
image="$(docker image inspect --format '{{index .RepoDigests 0}}' "$WFL_IMAGE")"
3737
echo "image=$image" >> "$GITHUB_OUTPUT"
3838
version="$(docker run --rm --network none "$image" --version)"
39+
runtime_revision="$(docker image inspect --format '{{index .Config.Labels "org.opencontainers.image.revision"}}' "$image")"
40+
[[ "$runtime_revision" =~ ^[a-f0-9]{40}$ ]] || { echo 'Official image is missing its WFL source revision'; exit 1; }
3941
{
4042
echo '### WFL nightly test environment'
4143
echo
4244
echo "- Image: $image"
4345
echo "- Runtime: $version"
46+
echo "- WFL revision: $runtime_revision"
4447
echo "- Scriptorium: $(git rev-parse HEAD)"
4548
echo "- Scribe: $(git -C lib/scribe rev-parse HEAD)"
4649
echo '- Runner: blacksmith-2vcpu-ubuntu-2404 (Linux x64)'
47-
echo '- Command: python3 scripts/run_tests.py --include-scribe'
48-
echo '- HTTP checks: python3 -m unittest discover -s tests/integration -v'
50+
echo '- Command: wfl --execution-timeout 1200 scripts/run_tests.wfl'
51+
echo '- Coverage: application, ORM/migrations/recovery, HTTP integration, tooling, examples, pinned Scribe'
4952
} | tee -a "$GITHUB_STEP_SUMMARY"
5053
51-
- name: Run WFL suites and HTTP configuration checks
54+
- name: Run the complete WFL suite
5255
shell: bash
5356
env:
5457
RESOLVED_IMAGE: ${{ steps.runtime.outputs.image }}
5558
run: |
5659
# The published image is a minimal runtime with a WFL entrypoint.
57-
# Install Python only in this disposable container. Scribe fixtures
58-
# go to its temporary directory; the checkout stays read-only.
60+
# Python is only the implementation of the repository hygiene checker.
61+
# Every scenario, fixture, assertion and test driver is WFL. A writable
62+
# disposable copy keeps synthetic databases/Git indexes off the checkout.
5963
docker run --rm --init --name "$TEST_CONTAINER" \
6064
--user 0:0 --entrypoint /bin/sh \
61-
--mount "type=bind,source=$GITHUB_WORKSPACE,target=/work,readonly" \
65+
--mount "type=bind,source=$GITHUB_WORKSPACE,target=/source,readonly" \
6266
--workdir /work "$RESOLVED_IMAGE" -ec '
6367
apt-get update
64-
apt-get install --yes --no-install-recommends python3
68+
apt-get install --yes --no-install-recommends python3 python-is-python3 git
69+
cp -a /source/. /work/
6570
python3 --version
6671
wfl --version
67-
python3 scripts/run_tests.py --include-scribe
68-
python3 -m unittest discover -s tests/integration -v
72+
wfl --execution-timeout 1200 scripts/run_tests.wfl
6973
'
7074
7175
- name: Clean up test container

‎.repo-hygiene.toml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ allowed-files = [
1010
"REPOSITORY_HYGIENE.md", "SECURITY.md", "main.wfl", "testing.md",
1111
]
1212
allowed-dirs = [
13-
".github", "admin", "app", "docs", "lib", "scripts", "static",
13+
".github", "admin", "app", "docs", "examples", "lib", "scripts", "static",
1414
"TestPrograms", "tests", "themes",
1515
]
1616

@@ -21,8 +21,9 @@ files = [
2121
"CONTRIBUTING.md", "GOVERNANCE.md", "LICENSE", "README.md",
2222
"REPOSITORY_HYGIENE.md", "SECURITY.md", "main.wfl", "testing.md",
2323
"docs/ARCHITECTURE.md", "docs/PROJECT-LAYOUT.md", "docs/THEMING.md",
24-
"scripts/check_repo_hygiene.py", "scripts/run_tests.py",
25-
"tests/tooling/test_repo_hygiene.py", "tests/tooling/test_run_tests.py",
24+
"scripts/check_repo_hygiene.py", "scripts/run_tests.wfl",
25+
"scripts/test_support.wfl", "scripts/resolve_runtime.wfl", "scripts/.wflcfg",
26+
"tests/tooling/hygiene.test.wfl", "tests/tooling/runner.test.wfl", "tests/tooling/.wflcfg",
2627
".github/pull_request_template.md", ".github/workflows/governance.yml",
2728
]
2829
# These paths must remain Git gitlinks; their contents are upstream-owned.

‎.wflcfg‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Scriptorium configuration (WFL runtime and application settings)
22
timeout_seconds = 60
3-
logging_enabled = false
3+
execution_logging = false
44
debug_report_enabled = false
55
log_level = info
66

‎CLAUDE.md‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,17 @@ violate the standard.
7474
- **Scribe is a submodule.** Don't edit `lib/scribe/` in place; changes go
7575
upstream to WebFirstLanguage/Scribe, then bump via
7676
`scripts/update-scribe.sh`.
77-
- **Checks:** `python scripts/run_tests.py` runs every Scriptorium WFL suite;
78-
add `--include-scribe` for dependency updates. Run
79-
`python -m unittest discover -s tests/tooling -v` and
80-
`python scripts/check_repo_hygiene.py` for repository tooling and hygiene.
81-
Python 3.11+ is needed for tooling; `wfl` is needed for application tests.
82-
The Governance workflow runs tooling tests and hygiene on Blacksmith Linux
83-
and GitHub-hosted Windows. The WFL tests workflow runs the application and
84-
pinned Scribe suites on Blacksmith using a freshly pulled `bsbyrdwfl/wfl:nightly` image;
77+
- **Checks:** `wfl --execution-timeout 1200 scripts/run_tests.wfl` runs the complete suite: application,
78+
ORM/migrations/recovery, HTTP integration, tooling, executable examples, and
79+
pinned Scribe. `--group tooling` or `--group application` selects a focused
80+
run. Run `python scripts/check_repo_hygiene.py` for the repository hygiene gate.
81+
Every test, fixture, assertion, helper and driver is WFL. Python 3.11+ and Git
82+
are required only for the hygiene checker's implementation subject. The runner
83+
uses the WFL executable that launched it, with an optional `--wfl` override.
84+
It needs the owned-process completion and `current_executable` runtime APIs.
85+
Governance provisions WFL and runs tooling and hygiene on Blacksmith Linux
86+
and GitHub-hosted Windows. WFL tests runs the complete suite on Blacksmith
87+
using a freshly pulled `bsbyrdwfl/wfl:nightly` image;
8588
its summary records the resolved image digest, runtime version, and source
8689
revisions. See
8790
[testing.md](testing.md) for commands, coverage limits, and merge evidence.

‎CONTRIBUTING.md‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ the baseline suites:
5555

5656
```sh
5757
wfl --version
58-
python scripts/run_tests.py
58+
wfl --execution-timeout 1200 scripts/run_tests.wfl
5959
```
6060

6161
Use `--wfl /absolute/path/to/wfl` if the interpreter is not on `PATH`; use
@@ -106,17 +106,16 @@ the PR:
106106

107107
```sh
108108
python scripts/check_repo_hygiene.py
109-
python -m unittest discover -s tests/tooling -v
110-
python scripts/run_tests.py
109+
wfl --execution-timeout 1200 scripts/run_tests.wfl
111110
```
112111

113-
For a Scribe pin, rendering, or template-engine integration change, also run:
112+
The complete command includes pinned Scribe. For a focused Scribe check, run:
114113

115114
```sh
116-
python scripts/run_tests.py --include-scribe
115+
wfl scripts/run_tests.wfl --group scribe
117116
```
118117

119-
The extra suite runs the pinned Scribe tests in a temporary copy because they
118+
The Scribe group runs the pinned tests in a temporary copy because they
120119
write fixtures. Follow [testing.md](testing.md) for HTTP, UI, security, migration,
121120
and recovery checks triggered by the change. Prose-only changes need relevant
122121
link, command, and hygiene checks; they do not need invented application tests.

0 commit comments

Comments
 (0)