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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
53 changes: 46 additions & 7 deletions .github/workflows/python-runtime-qualification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ on:
workflow_dispatch:
inputs:
baseline_runtime_wheel_url:
description: HTTPS URL for the previously qualified 0.1.x runtime wheel
required: true
description: Optional HTTPS URL for a previously qualified 0.1.x runtime wheel
required: false
default: ""
type: string
baseline_runtime_wheel_sha256:
description: Expected SHA-256 for the baseline runtime wheel
required: true
description: Required SHA-256 when a baseline runtime wheel URL is supplied
required: false
default: ""
type: string

permissions:
Expand Down Expand Up @@ -58,8 +60,8 @@ jobs:
- name: Build and consume clean artifacts
run: |
python -m build --sdist --wheel --outdir artifacts/python-runtime runtimes/python
python scripts/verify-python-runtime-install.py --server artifacts/python-runtime
python scripts/write-python-runtime-platform-receipt.py artifacts/python-runtime --output artifacts/qualification/platform.json
python scripts/verify-python-runtime-install.py --server artifacts/python-runtime --output artifacts/qualification/clean-install.json
python scripts/write-python-runtime-platform-receipt.py artifacts/python-runtime --clean-install-evidence artifacts/qualification/clean-install.json --output artifacts/qualification/platform.json

- name: Upload platform qualification evidence
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down Expand Up @@ -100,7 +102,37 @@ jobs:
npm ci --ignore-scripts --prefix clients/javascript
(cd clients/javascript && npm pack --json --pack-destination ../../artifacts/javascript)

- name: Validate optional upgrade baseline inputs
id: baseline
env:
BASELINE_RUNTIME_WHEEL_URL: ${{ inputs.baseline_runtime_wheel_url }}
BASELINE_RUNTIME_WHEEL_SHA256: ${{ inputs.baseline_runtime_wheel_sha256 }}
run: |
python - <<'PY'
import os

url_supplied = bool(os.environ["BASELINE_RUNTIME_WHEEL_URL"].strip())
hash_supplied = bool(
os.environ["BASELINE_RUNTIME_WHEEL_SHA256"].strip()
)
if url_supplied != hash_supplied:
raise SystemExit(
"Supply both baseline wheel inputs or leave both empty."
)
with open(
os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8"
) as output:
output.write(
"enabled=" + ("true" if url_supplied else "false") + "\n"
)
print(
"python-runtime-upgrade-baseline="
+ ("supplied" if url_supplied else "not-supplied")
)
PY

- name: Fetch verified upgrade baseline
if: ${{ steps.baseline.outputs.enabled == 'true' }}
env:
BASELINE_RUNTIME_WHEEL_URL: ${{ inputs.baseline_runtime_wheel_url }}
BASELINE_RUNTIME_WHEEL_SHA256: ${{ inputs.baseline_runtime_wheel_sha256 }}
Expand Down Expand Up @@ -150,9 +182,16 @@ jobs:
scripts/verify-python-runtime-external-worker.sh artifacts/runtime/*.whl
scripts/verify-python-runtime-mcp-conformance.sh artifacts/runtime/*.whl
python scripts/verify-python-runtime-security.py artifacts/runtime/*.whl --output artifacts/qualification/python-runtime-security.json
python scripts/verify-python-runtime-upgrade.py artifacts/baseline/*.whl artifacts/runtime/*.whl --output artifacts/qualification/python-runtime-upgrade.json
python scripts/benchmark-python-runtime.py --output artifacts/qualification/python-runtime-performance.json

- name: Run installed upgrade qualification
if: ${{ steps.baseline.outputs.enabled == 'true' }}
run: >-
python scripts/verify-python-runtime-upgrade.py
artifacts/baseline/*.whl
artifacts/runtime/*.whl
--output artifacts/qualification/python-runtime-upgrade.json

- name: Upload qualification evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
37 changes: 21 additions & 16 deletions PUBLIC-EXPORT-MANIFEST.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"fileCount": 814,
"fileCount": 815,
"files": [
{
"mode": "644",
Expand All @@ -16,6 +16,11 @@
"path": ".gcloudignore",
"sha256": "8407c8a13ba547c7b2ec31aaf4ca0ac79264ef510972cbc865f688609ec48f56"
},
{
"mode": "644",
"path": ".gitattributes",
"sha256": "d60f352d0db1404c70afb4bb8b2ca3fd1c610572aa40720e8a0b7baa7885418c"
},
{
"mode": "644",
"path": ".github/CODEOWNERS",
Expand Down Expand Up @@ -74,7 +79,7 @@
{
"mode": "644",
"path": ".github/workflows/python-runtime-qualification.yml",
"sha256": "66fa2c00be266319be8a9a64a85e98901f493868c2280d3627fe5ab7a89b7cf9"
"sha256": "e2644bbf1ea1b5cf06917e8a2f0a51359ebc519823fab7309ac7be6652f56d86"
},
{
"mode": "644",
Expand Down Expand Up @@ -124,7 +129,7 @@
{
"mode": "644",
"path": "README.md",
"sha256": "49c08cc55f653a1987a7ce9daf93a6a2cf2742af674363c9c479bb7f0622f5a9"
"sha256": "e0725bb5a4e54f6143f1b1afbbae3e48131ffc1ed7671ea7b261529dae01e6b7"
},
{
"mode": "644",
Expand Down Expand Up @@ -654,7 +659,7 @@
{
"mode": "644",
"path": "runtimes/python/README.md",
"sha256": "d6f49d16ef0d5c26e262488d6c0a62dbb1edc1653091f216ba410ca39313f8c0"
"sha256": "edec7886576e96ca62c04d80952efef731bc3ec4d6bc88dc8f3dace1dbee04a7"
},
{
"mode": "644",
Expand Down Expand Up @@ -789,7 +794,7 @@
{
"mode": "644",
"path": "runtimes/python/src/vyral_runtime/_local_experience.py",
"sha256": "7ed47623ae40fef2164a6ee94552a402470d33d99b0c3ed5b2ec5d9cc83e467f"
"sha256": "c00ff042ebb73e6518b9f2e87a50c61a4b1daf6512dd6fab472403f3d794689d"
},
{
"mode": "644",
Expand Down Expand Up @@ -1019,7 +1024,7 @@
{
"mode": "644",
"path": "runtimes/python/src/vyral_runtime/local/object_store.py",
"sha256": "de5562d037fb22a189dd644c9c4eec10a522c027c6da593f7a46ac104716df4c"
"sha256": "03c6a2d8319d9d86adb67f9a1633a5201a39ef7f29684957b30c8fd5ced53690"
},
{
"mode": "644",
Expand Down Expand Up @@ -1189,7 +1194,7 @@
{
"mode": "644",
"path": "runtimes/python/tests/test_local_experience.py",
"sha256": "ec153cd5f316be04bdeb2d2c38ffbbcda22af771a80478cadeff483d03bbc848"
"sha256": "fe7948aa0501f626ca7b7485048d0ee3a22438f187c8857256ab5773037664c0"
},
{
"mode": "644",
Expand All @@ -1204,7 +1209,7 @@
{
"mode": "644",
"path": "runtimes/python/tests/test_object_store.py",
"sha256": "9c335616e93c44ae80e8822ee9fb6907e375252464a4cfe92733651e92585b17"
"sha256": "b149ca5e551e41c4b42b62667e7c114f88b93a0bb824dc47a1ae8c0939857537"
},
{
"mode": "644",
Expand Down Expand Up @@ -1399,7 +1404,7 @@
{
"mode": "755",
"path": "scripts/export-public-tree.py",
"sha256": "be4a9d5d9bba838554c2abe803b0c84f3e66f4d8a970c5c31695df4be2271b76"
"sha256": "309b2a397b85609ea2dd1ecc03b06662e40cbe615cba88c3fb505ee25b6bb306"
},
{
"mode": "755",
Expand Down Expand Up @@ -1504,7 +1509,7 @@
{
"mode": "644",
"path": "scripts/test-export-public-tree.py",
"sha256": "a52a5ed8f2b9a89cb18a2292c3121f40c51f2cd3f12833c8d1c17b10217df8d0"
"sha256": "e834af5d61ce44dcd2ddcd3f0cfab37710aa30ed080122d41a6491427babe8c6"
},
{
"mode": "755",
Expand All @@ -1514,7 +1519,7 @@
{
"mode": "644",
"path": "scripts/test-python-runtime-platform-matrix.py",
"sha256": "6ec2270241fad474e45ef221232ec000c8215309e410e10230d145e6a8368a45"
"sha256": "3f8d53916d72ad2bfe25d7ba45d64baafa272d9b1f13661fc797021e2116a26f"
},
{
"mode": "755",
Expand Down Expand Up @@ -1694,7 +1699,7 @@
{
"mode": "755",
"path": "scripts/verify-python-runtime-install.py",
"sha256": "f64d7f981402da9718265b310a30a8ac3d8a8f15e5f6f71997fde3ea01d53a58"
"sha256": "2a105eee7f5c5b648c3160b2e5f4d3e88c710053a19b672b617454397d0ee132"
},
{
"mode": "755",
Expand All @@ -1704,7 +1709,7 @@
{
"mode": "644",
"path": "scripts/verify-python-runtime-platform-matrix.py",
"sha256": "082accbd32ed53d170be35af3299c64d2d6ba228f7d3af0eda0e6f7c0e349235"
"sha256": "479ebe8be702cdec6f2f6a2ca1cfaa8d2f67c1affacd7c0c6c93ba1fececdd4d"
},
{
"mode": "644",
Expand All @@ -1719,7 +1724,7 @@
{
"mode": "755",
"path": "scripts/verify-python-runtime.sh",
"sha256": "3b958588166ac6ad09a4f426203a99c36a104c58fb00a45d92e1aee879f613b2"
"sha256": "6a0c28f9829a74e5d4adfaac6a0c6832d532a2e14826f992cd17c7cf8728cf8f"
},
{
"mode": "755",
Expand All @@ -1744,7 +1749,7 @@
{
"mode": "644",
"path": "scripts/write-python-runtime-platform-receipt.py",
"sha256": "74c8a3bbd6f539ea02127ef2f506da4a07a9b0967ac69bd553fb38b4ac4f375a"
"sha256": "4610d63939fb59ece2a9747bbd70bf501139b5223aa5683a2a5c00ed039dd167"
},
{
"mode": "644",
Expand Down Expand Up @@ -4074,5 +4079,5 @@
],
"schemaVersion": 1,
"sourceDirty": false,
"treeSha256": "8a21a0a511b3acdce8fb6bfa727627d19b46e00a2666f14c036341366aa7100c"
"treeSha256": "24e6d0d2e0c1d04ee2b6149149cf2fa42f3e9bdd329bcea9db9f26c9d3297791"
}
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ without rerunning the quickstart:
vyral-runtime inspect --root ./.vyral/quickstart
```

Add `--json` to capture machine-readable first-citation, durable-receipt,
restart-recovery, and completion timings. Clean wheel and source-distribution
qualification runs the same command in an isolated environment and enforces a
five-minute first-citation budget rather than relying on a synthetic smoke.

The quickstart owns only the directory bearing its marker. Its reset command
refuses foreign, symbolic-link, home, filesystem-root, and working-directory
targets:
Expand Down
24 changes: 18 additions & 6 deletions runtimes/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ pre-release path. Once a qualified wheel is published, the install command can
be replaced with `python -m pip install vyral-runtime` without changing the
quickstart or inspection commands.

The quickstart JSON includes measured `firstCitationMs`, `durableReceiptMs`,
`restartRecoveryMs`, and `completedMs` milestones. Artifact qualification runs
the installed wheel and sdist through the first command, a second-process
idempotent replay, independent inspection, and marker-bounded reset. Each
supported platform cell rejects a first citation or complete command taking
more than five minutes.

```python
from vyral_runtime import VyralRuntime

Expand Down Expand Up @@ -252,16 +259,21 @@ dotnet test tests/Vyral.Tests.Conformance/Vyral.Tests.Conformance.csproj \
```

The main verification command runs the full unit suite with branch
instrumentation using pinned Coverage.py 7.15.2 and enforces a 77.5% combined
instrumentation using pinned Coverage.py 7.15.4 and enforces a 77.5% combined
line/branch regression floor. The floor is a regression guard, not a claim
that every dispatch or error branch is exhaustively tested.

The cross-platform qualification workflow is manual-only:
`.github/workflows/python-runtime-qualification.yml`. This preserves the
repository's current GitHub-run gate while keeping the promotion matrix
reproducible. Dispatch requires the HTTPS URL and SHA-256 of a previously
qualified `0.1.x` wheel so the installed upgrade gate cannot silently
self-compare the candidate. The aggregate job then runs
reproducible. Every cell builds both artifacts, installs each into a clean
environment, completes the real cited/restart quickstart, replays it from a
second process, inspects its limitations, and safely resets its owned state.
The HTTPS URL and SHA-256 of a previously qualified `0.1.x` wheel are optional
paired inputs: when supplied, the workflow also runs the installed upgrade
gate, which cannot silently self-compare the candidate. The aggregate job then runs
`scripts/verify-python-runtime-platform-matrix.py`; all nine cells must be
clean, refer to one commit, and agree on runtime and contract identity before
the matrix is valid promotion evidence.
clean, refer to one commit, agree on runtime and contract identity, and carry
passing measured local-experience evidence before the matrix is valid. A run
without a baseline proves the platform matrix but is not upgrade evidence and
does not by itself authorize maturity promotion.
25 changes: 25 additions & 0 deletions runtimes/python/src/vyral_runtime/_local_experience.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dataclasses import dataclass
from pathlib import Path
import shutil
from time import perf_counter

from .embeddings import EmbeddingProviderRegistry
from .execution import (
Expand Down Expand Up @@ -109,6 +110,10 @@ class LocalQuickstartResult:
completed_status: str
completed_result: object
dispatched_runs: int
first_citation_ms: float
durable_receipt_ms: float
restart_recovery_ms: float
completed_ms: float

def to_dict(self) -> dict[str, object]:
return {
Expand Down Expand Up @@ -143,6 +148,12 @@ def to_dict(self) -> dict[str, object]:
"completedResult": self.completed_result,
"dispatchedRuns": self.dispatched_runs,
},
"timings": {
"firstCitationMs": self.first_citation_ms,
"durableReceiptMs": self.durable_receipt_ms,
"restartRecoveryMs": self.restart_recovery_ms,
"completedMs": self.completed_ms,
},
}


Expand Down Expand Up @@ -180,6 +191,7 @@ async def run_local_quickstart(
*,
emit: Callable[[str], None] | None = None,
) -> LocalQuickstartResult:
started_at = perf_counter()
root = prepare_local_quickstart_root(root_path)
created_chunks = 0
reused_chunks = 0
Expand Down Expand Up @@ -288,6 +300,7 @@ async def run_local_quickstart(
raise RuntimeError(
"The local quickstart did not produce citation-ready context."
)
first_citation_ms = _elapsed_ms(started_at)
citations = tuple(
LocalQuickstartCitation(
citation.source_label or citation.record_id,
Expand Down Expand Up @@ -318,6 +331,7 @@ async def run_local_quickstart(
raise RuntimeError(
"Durable admission did not preserve the idempotent run identity."
)
durable_receipt_ms = _elapsed_ms(started_at)
_emit(
emit,
(
Expand All @@ -327,6 +341,7 @@ async def run_local_quickstart(
)

_emit(emit, "Closed the first runtime instance.")
restart_started_at = perf_counter()
with VyralRuntime.open_local(
root,
execution_plugins=(_QUICKSTART_PLUGIN,),
Expand All @@ -336,6 +351,7 @@ async def run_local_quickstart(
raise RuntimeError(
"The admitted run was not present after reopening local state."
)
restart_recovery_ms = _elapsed_ms(restart_started_at)
_emit(
emit,
(
Expand All @@ -359,6 +375,7 @@ async def run_local_quickstart(
"the same durable identity."
),
)
completed_ms = _elapsed_ms(started_at)

return LocalQuickstartResult(
root_path=str(root),
Expand All @@ -383,6 +400,10 @@ async def run_local_quickstart(
completed_status=completed.status,
completed_result=completed.result,
dispatched_runs=dispatched,
first_citation_ms=first_citation_ms,
durable_receipt_ms=durable_receipt_ms,
restart_recovery_ms=restart_recovery_ms,
completed_ms=completed_ms,
)


Expand Down Expand Up @@ -516,6 +537,10 @@ def _emit(emit: Callable[[str], None] | None, message: str) -> None:
emit(message)


def _elapsed_ms(started_at: float) -> float:
return round((perf_counter() - started_at) * 1_000, 3)


def run_local_quickstart_sync(
root_path: str | Path,
*,
Expand Down
Loading
Loading