diff --git a/.github/BRANCH_WORKFLOW.md b/.github/BRANCH_WORKFLOW.md index f609021fe..62e66864b 100644 --- a/.github/BRANCH_WORKFLOW.md +++ b/.github/BRANCH_WORKFLOW.md @@ -383,8 +383,8 @@ upload credential when the token's claims match the publisher above, and Sigstore and uploads its PEP 740 attestation. A failed-jobs re-run of the upload asks for a fresh token. Once a run has published this way, the old `melder_api_token` environment secret can be deleted and its token revoked on -TestPyPI: no workflow reads it. Production continues using its independent pypi -environment and PYPI_API_TOKEN credential. +TestPyPI: no workflow reads it. Production publishes the same way, through its +own `pypi` environment and PyPI Trusted Publisher (Final publication checks). An `invalid-publisher` error from the upload means the publisher's values and the job's claims disagree; an earlier OIDC attempt failed that way, so compare all four @@ -459,21 +459,57 @@ workflow on prod, starts a fresh qualification chain: 5. Recheck distribution identity and candidate qualification, then the live release tag, fetch/check prod again immediately before the PyPI upload action. Annotated tags use their peeled target; missing or moved tags refuse publication. +6. Upload by Trusted Publishing: `pypa/gh-action-pypi-publish`, pinned to its + commit, signs every file with Sigstore and uploads its PEP 740 attestation. +7. `Release / provenance` then checks every released file's provenance on PyPI + in the release candidate's five layers: a provenance exists; its publisher is + `python-publish.yml` in `pypi`; Sigstore verifies the attestation on the + production trust root; the signing certificate names this repository and its + owner (with their numeric ids), the workflow at the release tag (or `prod`, for + a manual dispatch), the released commit, this run and the attempt that + uploaded, its event, a GitHub-hosted runner, public visibility and the `pypi` + environment; and the attested statement names exactly the file and its + sha256. The files are on PyPI by then, so a refusal fails the run before the + release is announced but cannot unpublish anything; `.github/ci_cd/validating.md` + says what each refusal means. Its report, `release-provenance--`, + keeps each file's verified signer, run and trigger. Earlier dev/preprod success does not replace these checks. A prod movement during the checks or environment approval refuses publication. GitHub prerelease events do not trigger final publication. All publication runs share a serialization group. -Only the upload job uses the pypi environment and its PYPI_API_TOKEN secret. Production builds and validates fresh final distributions; it does not relabel or claim byte identity with an earlier rcN package. +Only the upload job uses the pypi environment, and PyPI publication has no +stored credential (owner, 2026-10-24). Add the publisher before the first final +release made with this workflow: on PyPI, the `melder` project -> Manage -> +Publishing -> add a GitHub publisher with exactly these values. + +| Field | Value | +| --- | --- | +| Owner | `Synaptic724` | +| Repository name | `melder` | +| Workflow name | `python-publish.yml` | +| Environment name | `pypi` | + +The upload job alone requests a short-lived OIDC token (`id-token: write`); PyPI +exchanges it for an upload credential when the token's claims match the +publisher above. An `invalid-publisher` error means they disagree and nothing +was uploaded: compare the four values, then **Re-run all jobs**. Once a release +has published this way, delete the `PYPI_API_TOKEN` environment secret and +revoke its token on PyPI: no workflow reads it, and a contract test refuses a +workflow that names either retired token. + Artifacts include the workflow run and attempt in their names. After a failed publication, use **Re-run all jobs** to obtain fresh qualification and fresh artifacts; rerunning only a failed upload must not reuse an earlier attempt's unqualified artifact implicitly, so a failed-jobs re-run of the upload stops before downloading anything, with an error naming **Re-run all jobs**. Confirm PyPI state before retrying an upload whose outcome is uncertain; existing -package versions are never silently skipped. +package versions are never silently skipped. A `Release / provenance` check that +failed only because PyPI or the verifier's trust root could not be reached is +rerun alone with **Re-run failed jobs**: it reads the same build and still +expects the attempt that uploaded, and it uploads nothing. ## Activating GitHub enforcement diff --git a/.github/ci_cd/README.md b/.github/ci_cd/README.md index dbc91b9f4..459bc9ded 100644 --- a/.github/ci_cd/README.md +++ b/.github/ci_cd/README.md @@ -4,7 +4,7 @@ Read this folder before you change anything under `.github/`, change `project.re dependencies in `pyproject.toml`, add a Python release, a CI job or a benchmark, or diagnose a failed run. It says what every CI file is for, how the pieces connect, how to extend them and how to check a change before handing it off. Branch and release policy (which pull request may target which branch, cutting a release, the TestPyPI and -PyPI credentials) lives in [BRANCH_WORKFLOW.md](../BRANCH_WORKFLOW.md); this folder links to it instead of +PyPI Trusted Publishers) lives in [BRANCH_WORKFLOW.md](../BRANCH_WORKFLOW.md); this folder links to it instead of repeating it. | Read | When | @@ -39,7 +39,8 @@ push to release_candidate, or a manual run there --> release-candidate.yml Windows and macOS) -> package-ready published release, or a manual run on prod --> python-publish.yml - release-gate -> hygiene, source-assets, repo-assets -> release-build -> pypi-publish + release-gate -> hygiene, source-assets, repo-assets -> release-build -> pypi-publish (PyPI, by Trusted + Publishing, with attestations) -> pypi-provenance (every released file's attestation verified) ``` Workflows only orchestrate. The decisions (routes, required results, Python matrices, installs, package checks) diff --git a/.github/ci_cd/extending.md b/.github/ci_cd/extending.md index 32659f1cf..73279f006 100644 --- a/.github/ci_cd/extending.md +++ b/.github/ci_cd/extending.md @@ -24,10 +24,11 @@ Every change below ends the same way: run the workflow tests, update this folder `RuntimeMatrixPolicy.TARGETS` together and run the full matrix. - `PYTHON_GIL=0` goes on the steps that run Melder, never on a whole job: Python's setup on macOS runs a certificate installer that cannot start with the GIL disabled. -- Secrets are passed explicitly and only where needed: `tests` receives `CODECOV_TOKEN` and nothing else, and the - PyPI token lives in the `pypi` environment, used by one job. TestPyPI publication has no secret: the - release candidate's `publish` job authenticates by Trusted Publishing and is the only job in any workflow that - holds `id-token: write`; a third-party action in a job that holds it is pinned to a full commit SHA. +- Secrets are passed explicitly and only where needed: `tests` receives `CODECOV_TOKEN` and nothing else. + Publication has no secret: the release candidate's `publish` job (TestPyPI, environment `pypitest`) and + `python-publish.yml`'s `pypi-publish` job (PyPI, environment `pypi`) authenticate by Trusted Publishing and are + the only jobs in any workflow that hold `id-token: write`; a third-party action in a job that holds it is pinned + to a full commit SHA, and no workflow may name the retired upload tokens `melder_api_token` or `PYPI_API_TOKEN`. - Artifact names carry `${{ github.run_id }}-${{ github.run_attempt }}`, so a rerun never picks up another attempt's files by accident. A job that downloads a build made earlier in the same run names it from the build job's output (`needs..outputs.artifact-name`), never from its own attempt, because a failed-jobs re-run @@ -52,15 +53,18 @@ workflow, as `speed-tests.yml` does for the speed tests. ## Add a stage to the release-candidate or publication run `package-ready` requires exactly `CIPolicy.CANDIDATE_JOBS`; a new release-candidate stage goes into its `needs` -and that list together. A publication job that must finish before the upload goes into `pypi-publish`'s `needs`. +and that list together. A publication job that must finish before the upload goes into `pypi-publish`'s `needs`; +a check of what was uploaded, like `pypi-provenance`, needs `pypi-publish`, downloads the build by +`needs.release-build.outputs.artifact-name` and reads the upload's attempt from `pypi-publish`'s outputs. ## Change the provenance tool The provenance check verifies with the toolchain the publishing action signs with, so the three move together in one change: -1. Pin `pypa/gh-action-pypi-publish` in `release-candidate.yml` to the new release's full commit SHA (with the - tag in a comment) and update the pinned SHA in `test_workflow_contracts.py`. +1. Pin `pypa/gh-action-pypi-publish` in `release-candidate.yml` and `python-publish.yml` to the new release's full + commit SHA (with the tag in a comment), the same in both, and update the pinned SHA in + `test_workflow_contracts.py`. 2. Regenerate `.github/provenance/requirements.txt` with the command in its header: `pypi-attestations` at the version that release's `requirements/runtime.txt` pins, with that file as constraints, so sigstore and the rest take the action's versions (hashes for every pin, wheels only, the helper release on Linux x64). diff --git a/.github/ci_cd/scripts.md b/.github/ci_cd/scripts.md index 8f9913dd9..20968879b 100644 --- a/.github/ci_cd/scripts.md +++ b/.github/ci_cd/scripts.md @@ -17,8 +17,9 @@ import, with two exceptions that run inside the environment they test: `run_runt | `ci_qualification.py` | `record`, `select`, `verify` | `ci.yml`, `verify-source-qualification.yml` | `test_source_qualification.py`, `test_checkout_identity.py` | | `check_candidate_run.py` | `--wait-seconds` | `ci.yml`, `python-publish.yml` | `test_candidate_publication.py` | | `testpypi_candidate.py` | `prepare-upload`, `probe-install` | `release-candidate.yml` | `test_candidate_publication.py` | -| `testpypi_provenance.py` | `verify` | `release-candidate.yml` | `test_candidate_provenance.py` | -| `verify_distributions.py` | `--directory`, `--release-tag` | `build-distributions.yml`, `python-publish.yml` | `test_distributions.py` | +| `testpypi_provenance.py` | `verify` | `release-candidate.yml`; `pypi_provenance.py` imports its layers | `test_candidate_provenance.py` | +| `pypi_provenance.py` | `verify` | `python-publish.yml` | `test_release_provenance.py` | +| `verify_distributions.py` | `--directory`, `--release-tag` | `build-distributions.yml`, `python-publish.yml`; `pypi_provenance.py` calls it with the release tag | `test_distributions.py` | | `normalize_sdist.py` | `--directory` | `build-distributions.yml` | `test_sdist_normalization.py` | | `smoke_wheel.py` | `--expected-version` | `build-distributions.yml`, `testpypi_candidate.py probe-install` | the distribution contract in `test_workflow_contracts.py` | @@ -107,6 +108,23 @@ sigstore, the versions `pypa/gh-action-pypi-publish` signs with. The same run fi genuine attestation `.github/provenance/known_good_provenance.json` must verify, and two tampered copies of it (another digest, another signer) must be refused, or no verdict counts. The expected identity lives in one class, `ProvenancePolicy`; every refusal names the file, the claim, what was expected and what was found. The report +`reports/provenance.json` is written only after every check passed. The layers that read an index +(`fetch_provenance`, `single_attestation`, `require_outcomes`) take it from the policy they are given, which is how +`pypi_provenance.py` reuses them for PyPI. + +### `pypi_provenance.py` + +`verify` runs in `Release / provenance`, after `pypi-publish` has uploaded a final release. It is the candidate +check with the release's identity: the same five layers, the same pinned verifier, lock and control, imported from +`testpypi_provenance.py`, and one policy class, `ReleaseProvenancePolicy` (a `ProvenancePolicy` subclass), naming +PyPI's Integrity API (`https://pypi.org/integrity/melder///provenance`), `python-publish.yml` and the +`pypi` environment. `release_context` reads the run: a published release at `refs/tags/`, the tag passed from +the event as `RELEASE_TAG`, or a manual dispatch on `prod` with no tag; anything else is refused before PyPI is +asked. The downloaded files are verified again with that tag, which must name the package version. Every released +file must then name exactly this run's upload: PyPI takes a file name once and the upload never skips one, so, +unlike the candidate check, no claim is matched by pattern - the workflow at the run's ref, the commit, the run, the +attempt `pypi-publish` reported (`RELEASE_PUBLISH_ATTEMPT`) and its event. A 404 that outlasts the retries is +reported as a release whose files are published without an accepted attestation. The report `reports/provenance.json` is written only after every check passed. ### `verify_distributions.py`, `normalize_sdist.py` and `smoke_wheel.py` @@ -121,14 +139,14 @@ agree, and a small bind, conjure and meld scenario must work with the GIL off. ## Other files in `.github` - `BRANCH_WORKFLOW.md`: branch, release and publication policy for people and agents. -- `provenance/`: the provenance check's tool, used only by `testpypi_provenance.py`. +- `provenance/`: the provenance checks' tool, used by `testpypi_provenance.py` and `pypi_provenance.py`. `.github/provenance/verify_attestations.py` is the verifier, the one script under `.github/` that imports packages outside the standard library, so it never runs on a bare interpreter. `.github/provenance/requirements.txt` is its hashed lock; its header gives the command that regenerates it. `.github/provenance/known_good_provenance.json` is the recorded control: PyPI's provenance of the pypi-attestations wheel the lock installs. Moving the tool is one change: the publishing action's pin in - `release-candidate.yml`, the lock at the versions that action signs with, and the control re-recorded for the - new pypi-attestations wheel with `ProvenanceControl` updated ([extending.md](extending.md)). + `release-candidate.yml` and `python-publish.yml`, the lock at the versions that action signs with, and the control + re-recorded for the new pypi-attestations wheel with `ProvenanceControl` updated ([extending.md](extending.md)). - `python/`: the Python release manifests ([python_versions.md](python_versions.md)). - `rulesets/`: `dev.json`, `preprod.json`, `release_candidate.json` and `prod.json` are the branch protection payloads. Each requires a pull request and the `CI / merge-ready` status from the GitHub Actions app (ID 15368) diff --git a/.github/ci_cd/validating.md b/.github/ci_cd/validating.md index d3fa2c2de..34f8d8952 100644 --- a/.github/ci_cd/validating.md +++ b/.github/ci_cd/validating.md @@ -47,13 +47,18 @@ Start with `CI / merge-ready`: its message lists every required job that did not | `RC / provenance`: "The pinned tool refused the recorded genuine attestation" | The verifier could not verify in that environment (most often Sigstore's trust root could not be fetched). **Re-run failed jobs**; if it persists, check the lock and the control ([extending.md](extending.md), "Change the provenance tool"). | | An RC job: "Artifact not found for name: candidate-dists--" | A failed-jobs re-run of a run that started before the build reported its artifact (2026-10-06); use **Re-run all jobs**. | | `Publish to PyPI`: "Use Re-run all jobs: this attempt did not build the distributions" | A failed-jobs re-run of the upload; publication never reuses an earlier attempt's build. Use **Re-run all jobs**. | +| `Publish to PyPI`: `invalid-publisher` | PyPI's Trusted Publisher and the job's OIDC claims disagree, and nothing was uploaded. Check the publisher's four values against BRANCH_WORKFLOW.md (owner `Synaptic724`, repository `melder`, workflow `python-publish.yml`, environment `pypi`), then **Re-run all jobs**. | +| `Release / provenance`: "PyPI holds no provenance for " | The files were uploaded but PyPI holds no accepted attestation for them. They are published and cannot be replaced: compare PyPI's Trusted Publisher with BRANCH_WORKFLOW.md and read the `Publish to PyPI` log before the release is announced; whether to yank it is the owner's call. | +| `Release / provenance`: "... does not name the expected signer" or "is not the expected Trusted Publisher" | The message lists each claim with what was expected and what was found. `ReleaseProvenancePolicy` in `pypi_provenance.py` holds the expected identity; a changed workflow, environment, repository or event changes it. The files are published: find the cause before the release is announced. | +| `Release / provenance`: a PyPI lookup, the tool's install or its trust root failed after the retries | **Re-run failed jobs**: the check runs alone again on the same build and still expects the attempt that uploaded. | | Prod pull request: "Candidate qualification has not passed" | The release-candidate run for that commit is pending or failed; finish or fix it, then rerun the check. | | The Codecov upload fails | Reporting only: it never blocks a merge. | Artifacts worth opening: `runtime-results-*` (JUnit) and `coverage-*` for each test cell, `runtime-python-matrix-*` (the releases a run tested), the speed tests' results folders (logs, `install.log`, -`environment.json`), `source-qualification-*`, and the release candidate's `candidate-*` reports, among them -`candidate-provenance-*`, which records each file's verified signer, run and trigger. +`environment.json`), `source-qualification-*`, the release candidate's `candidate-*` reports, among them +`candidate-provenance-*`, which records each file's verified signer, run and trigger, and a release's +`release-provenance-*`, which records the same for every file published to PyPI. ## Environment notes for agents diff --git a/.github/ci_cd/workflows.md b/.github/ci_cd/workflows.md index 8d5a42610..e5ef12d07 100644 --- a/.github/ci_cd/workflows.md +++ b/.github/ci_cd/workflows.md @@ -86,7 +86,12 @@ Publication runs are serialized. | `release-gate` (Require current prod HEAD) | The event, the checkout and the current `prod` head (and the live release tag) are one commit (`ci_policy.py release-head`), and that commit's candidate passed TestPyPI qualification (`check_candidate_run.py`). | | `hygiene`, `source-assets`, `repo-assets` | Hygiene and both asset checks again, fresh. The runtime tests do not run again: full CI and the release candidate tested this exact tree, and `release-gate` refuses any other (owner, 2026-10-24). | | `release-build` | Builds and verifies the distributions and compares the release tag with the package version (`build-distributions.yml`). | -| `pypi-publish` (Publish to PyPI) | In the `pypi` environment: refuses a failed-jobs re-run, because publication never reuses an earlier attempt's build (use **Re-run all jobs**), then rechecks the files, the candidate and the release head immediately before uploading with `PYPI_API_TOKEN`. | +| `pypi-publish` (Publish to PyPI) | In the `pypi` environment: refuses a failed-jobs re-run, because publication never reuses an earlier attempt's build (use **Re-run all jobs**), then rechecks the files, the candidate and the release head immediately before uploading them by Trusted Publishing with a PEP 740 attestation each (`pypa/gh-action-pypi-publish`, pinned to the commit the release candidate pins). With the release candidate's `publish` it is one of the two jobs that hold `id-token: write`; it uses no secret and reports its run attempt as an output. | +| `pypi-provenance` (Release / provenance) | After the upload, on the helper release, for every released file: reads its provenance from PyPI's Integrity API and checks it in the five layers `RC / provenance` uses, with the release's identity - its publisher is this workflow in `pypi`, and the signing certificate names this repository, the workflow at the run's ref (the release tag, or `prod` for a manual dispatch), the released commit, this run's upload attempt and its event (`pypi_provenance.py verify`). The files are on PyPI by then: a refusal fails the run, before the release is announced, but cannot unpublish them. Keeps `release-provenance--`. | + +`pypi-provenance` downloads the build `release-build` reports and reads the attempt `pypi-publish` recorded, so +after a PyPI lookup that ran out of retries **Re-run failed jobs** runs the check alone on the same files; it +never uploads anything. ## Reusable workflows diff --git a/.github/scripts/pypi_provenance.py b/.github/scripts/pypi_provenance.py new file mode 100644 index 000000000..6ef3b3874 --- /dev/null +++ b/.github/scripts/pypi_provenance.py @@ -0,0 +1,289 @@ +"""Verify the PEP 740 provenance of every file of a final release on PyPI, after the upload. + +The publication workflow's provenance job (Release / provenance) runs `verify` once `pypi-publish` has uploaded the +release by Trusted Publishing. For every built distribution it reads the provenance PyPI's Integrity API holds and +checks it in the same five layers as the release candidate's check (`testpypi_provenance.py`), with the release's +identity: + +1. a provenance exists; +2. its one bundle's publisher record is this repository's `python-publish.yml` in the `pypi` environment; +3. Sigstore verifies its one attestation on the production trust root (certificate chain, transparency log, + signature); +4. the signing certificate names this run's upload, claim by claim: the workflow at the run's ref (the release tag, + or `prod` for a manual dispatch), the released commit, this run and the attempt that uploaded, its event, the + `pypi` environment; +5. the attested statement names exactly this file and its sha256, with the PyPI publish predicate. + +The layers, the pinned verifier, its lock and its recorded control are the candidate check's, imported from +`testpypi_provenance.py`; only the policy and the run identity are the release's. The files are already on PyPI +when this runs, so a refusal cannot unpublish them: it fails the run, naming the file and what differs, before the +release is announced. +""" + +import argparse +import json +import os +import pathlib +import re +import tempfile +from collections.abc import Mapping, Sequence +from typing import Optional, TypedDict + +from ci_policy import git_output +from testpypi_candidate import FileIdentity, file_identity, package_version +from testpypi_provenance import (ExpectedIdentity, FulcioClaim, ProvenanceControl, ProvenancePolicy, certificate_der, + certificate_identity, check_identity, check_statement, control_entries, + fetch_provenance, require_outcomes, run_verifier, single_attestation, + tool_environment) +from verify_distributions import verify_distributions + + +class ReleaseContext(TypedDict): + """This publication run's identity, read from GitHub's default environment variables and checked before use. + + `ref` is the full ref the run and its signing certificate name; `tag` is the release's tag, or empty for a + manual dispatch on prod. + """ + + repository_id: str + owner_id: str + sha: str + workflow_sha: str + event: str + ref: str + tag: str + run_id: str + run_attempt: int + + +class ReleaseProvenancePolicy(ProvenancePolicy): + """Hold the release provenance check's identity: PyPI's Trusted Publisher for the publication workflow. + + The owner configures that publisher on PyPI (BRANCH_WORKFLOW.md): this repository, `python-publish.yml`, the + `pypi` environment. A publication run starts from a published GitHub release, at that release's tag, or from a + manual dispatch on `prod`, so the ref its certificate names is the run's own (`release_context`); every other + expected value is fixed here or inherited. The server, repository, owner, issuer, runner, visibility, statement + format, retry bounds and the pinned tool are `ProvenancePolicy`'s; this class overrides the index, the workflow, + the environment, the events and the refusal for a missing provenance. Change it only deliberately, together + with the publisher on PyPI. + """ + + INDEX_NAME = "PyPI" + INTEGRITY_ROOT = "https://pypi.org/integrity/melder/" + USER_AGENT = "melder-release-ci" + WORKFLOW = "python-publish.yml" + ENVIRONMENT = "pypi" + # A manual dispatch publishes from prod; a published release runs at TAG_REF_PREFIX + its tag. + REF = "refs/heads/prod" + TAG_REF_PREFIX = "refs/tags/" + RELEASE_EVENT = "release" + TRIGGERS: tuple[str, ...] = ("release", "workflow_dispatch") + # The verifier entries of released files are `release:`; the controls keep their own ids. + ENTRY_PREFIX = "release" + + @classmethod + def missing_provenance(cls, name: str) -> str: + """Return the refusal for a released file PyPI still holds no provenance for after the last lookup. + + The upload has already happened, so the remedy is to find out why before the release is announced: the + Trusted Publisher, or the upload step's log. + """ + return (f"PyPI holds no provenance for {name}: it was uploaded without Trusted Publishing, or PyPI did not " + "accept its attestation. The file is published and cannot be replaced: compare PyPI's Trusted " + "Publisher for melder with BRANCH_WORKFLOW.md and read the Publish to PyPI log before announcing " + "this release.") + + +def release_context(environment: Mapping[str, str], + policy: type[ReleaseProvenancePolicy] = ReleaseProvenancePolicy) -> ReleaseContext: + """Read and check this publication run's identity from GitHub's default environment variables. + + The run must come from one of the policy's events: a published release, whose tag the workflow passes as + `RELEASE_TAG` from the event and whose ref is that tag, or a manual dispatch on `prod`, which has no tag. Its + server, repository, ref and workflow ref must be the policy's at that ref; its commit SHAs must be full and its + numeric identifiers decimal. A tag that does not name the package version is refused later, with the files + (`released_files`). + + Args: + environment: The job's environment variables. + policy: The identity to check against; `ReleaseProvenancePolicy` in CI. + + Returns: + The checked run identity. + + Raises: + ValueError: Naming the variable that is missing or differs. + """ + event = environment.get("GITHUB_EVENT_NAME", "") + if event not in policy.TRIGGERS: + raise ValueError(f"GITHUB_EVENT_NAME is {event!r}; the release provenance check runs only for " + f"{', '.join(policy.TRIGGERS)}.") + tag = environment.get("RELEASE_TAG", "") + if event == policy.RELEASE_EVENT and not tag: + raise ValueError("RELEASE_TAG is ''; a published release's check needs that release's tag.") + if event != policy.RELEASE_EVENT and tag: + raise ValueError(f"RELEASE_TAG is {tag!r}; a manual dispatch publishes from {policy.REF} with no tag.") + ref = (policy.TAG_REF_PREFIX + tag) if tag else policy.REF + fixed = {"GITHUB_SERVER_URL": policy.SERVER, "GITHUB_REPOSITORY": policy.REPOSITORY, "GITHUB_REF": ref, + "GITHUB_WORKFLOW_REF": policy.workflow_uri(ref).removeprefix(policy.SERVER + "/")} + for name, value in fixed.items(): + if environment.get(name) != value: + raise ValueError(f"{name} is {environment.get(name)!r}; this {event} run's check runs only as {value!r}.") + formats = {"GITHUB_SHA": r"[0-9a-f]{40}(?:[0-9a-f]{24})?", "GITHUB_WORKFLOW_SHA": r"[0-9a-f]{40}(?:[0-9a-f]{24})?", + "GITHUB_REPOSITORY_ID": r"[1-9][0-9]*", "GITHUB_REPOSITORY_OWNER_ID": r"[1-9][0-9]*", + "GITHUB_RUN_ID": r"[1-9][0-9]*", "GITHUB_RUN_ATTEMPT": r"[1-9][0-9]*"} + for name, pattern in formats.items(): + if re.fullmatch(pattern, environment.get(name, "")) is None: + raise ValueError(f"{name} is {environment.get(name)!r}; expected it to match {pattern!r}.") + return {"repository_id": environment["GITHUB_REPOSITORY_ID"], "owner_id": environment["GITHUB_REPOSITORY_OWNER_ID"], + "sha": environment["GITHUB_SHA"], "workflow_sha": environment["GITHUB_WORKFLOW_SHA"], "event": event, + "ref": ref, "tag": tag, "run_id": environment["GITHUB_RUN_ID"], + "run_attempt": int(environment["GITHUB_RUN_ATTEMPT"])} + + +def publish_attempt(environment: Mapping[str, str], run_attempt: int) -> int: + """Read which attempt of this run uploaded the release, from the upload job's output. + + `pypi-publish` reports its run attempt (`RELEASE_PUBLISH_ATTEMPT`). A failed-jobs re-run of the provenance job + alone keeps that output from the attempt that uploaded, so it may be below this run's attempt; the attestations + name it. + + Raises: + ValueError: When the output is missing or malformed, or names an attempt after this one. + """ + attempt = environment.get("RELEASE_PUBLISH_ATTEMPT", "") + if re.fullmatch(r"[1-9][0-9]*", attempt) is None or int(attempt) > run_attempt: + raise ValueError(f"RELEASE_PUBLISH_ATTEMPT must be an attempt of this run up to {run_attempt}; got " + f"{attempt!r}.") + return int(attempt) + + +def release_identity(context: ReleaseContext, attempt: int, + policy: type[ReleaseProvenancePolicy] = ReleaseProvenancePolicy) -> ExpectedIdentity: + """Return the signing identity every released file's attestation must carry (layer 4). + + PyPI takes a file name once and the upload job never skips an existing file, so every file of this release was + uploaded, and signed, by this run's upload attempt: the publication workflow at the run's ref and commit, from + the run's event, in the `pypi` environment, on a GitHub-hosted runner of this public repository. Every claim is + exact; unlike the candidate check, nothing is matched by pattern. + + Args: + context: The checked run identity (`release_context`). + attempt: The attempt that uploaded (`publish_attempt`). + policy: The identity's fixed values; `ReleaseProvenancePolicy` in CI. + """ + signer = policy.workflow_uri(context["ref"]) + exact = { + FulcioClaim.ISSUER: policy.ISSUER, FulcioClaim.BUILD_SIGNER_URI: signer, + FulcioClaim.BUILD_SIGNER_DIGEST: context["workflow_sha"], FulcioClaim.RUNNER_ENVIRONMENT: policy.RUNNER, + FulcioClaim.SOURCE_REPOSITORY_URI: f"{policy.SERVER}/{policy.REPOSITORY}", + FulcioClaim.SOURCE_REPOSITORY_DIGEST: context["sha"], FulcioClaim.SOURCE_REPOSITORY_REF: context["ref"], + FulcioClaim.SOURCE_REPOSITORY_IDENTIFIER: context["repository_id"], + FulcioClaim.SOURCE_REPOSITORY_OWNER_URI: f"{policy.SERVER}/{policy.OWNER}", + FulcioClaim.SOURCE_REPOSITORY_OWNER_IDENTIFIER: context["owner_id"], + FulcioClaim.BUILD_CONFIG_URI: signer, FulcioClaim.BUILD_CONFIG_DIGEST: context["workflow_sha"], + FulcioClaim.BUILD_TRIGGER: context["event"], + FulcioClaim.RUN_INVOCATION_URI: (f"{policy.SERVER}/{policy.REPOSITORY}/actions/runs/{context['run_id']}" + f"/attempts/{attempt}"), + FulcioClaim.SOURCE_REPOSITORY_VISIBILITY: policy.VISIBILITY, + FulcioClaim.DEPLOYMENT_ENVIRONMENT: policy.ENVIRONMENT, + FulcioClaim.TOKEN_SUBJECT: f"repo:{policy.REPOSITORY}:environment:{policy.ENVIRONMENT}", + } + return {"san": signer, "exact": exact, "patterns": {}} + + +def released_files(directory: pathlib.Path, version: str, tag: str) -> dict[str, FileIdentity]: + """Verify the downloaded distributions again and return each file's identity. + + The wheel and sdist must be the verified pair for this version, and a release tag must name that version + (`verify_distributions`), so the digests the provenance must name are this run's build. + + Raises: + ValueError: When the files or the tag are not the release's. + """ + verify_distributions(directory, version, tag) + return {path.name: file_identity(path) for path in sorted(directory.iterdir())} + + +def verify_release(directory: pathlib.Path, report: pathlib.Path, environment: Mapping[str, str]) -> None: + """Verify every released file's PyPI provenance in five layers, then write the evidence report. + + The run's identity is checked first, then the built files are verified again against the version and the + release tag. The recorded control and every released file are checked with the candidate check's own layers + (1, 2, 4 and 5) before the tool environment is built, so a wrong signer refuses before anything is installed; + the pinned tool then checks layers 3 and 4 for all of them in one process, and its verdicts count only when it + verified the genuine control and refused both tampered copies. The report is written only after every check + has passed. + + Raises: + ValueError: Naming the file and what differs, for any refused layer, run variable or file. + urllib.error.URLError: When PyPI could not be read after the bounded retries. + subprocess.CalledProcessError: When the tool environment could not be built or the verifier could not run. + """ + policy = ReleaseProvenancePolicy + context = release_context(environment) + attempt = publish_attempt(environment, context["run_attempt"]) + version = package_version() + files = released_files(directory, version, context["tag"]) + expected = release_identity(context, attempt) + with tempfile.TemporaryDirectory(prefix="melder-release-provenance-", + dir=environment.get("RUNNER_TEMP")) as scratch: + root = pathlib.Path(scratch) + entries = control_entries() + evidence: dict[str, dict[str, object]] = {} + for name, identity in files.items(): + raw = fetch_provenance(version, name, policy) + try: + document = json.loads(raw) + except json.JSONDecodeError as error: + raise ValueError(f"PyPI's provenance of {name} is not JSON.") from error + attestation = single_attestation(document, name, policy.publisher()) + check_statement(attestation, name, identity["sha256"], name) + certificate = certificate_identity(certificate_der(attestation, name)) + check_identity(certificate, expected, name) + stored = root / f"{name}.provenance.json" + stored.write_bytes(raw) + entries.append({"id": f"{policy.ENTRY_PREFIX}:{name}", "name": name, "sha256": identity["sha256"], + "provenance": str(stored), "identity": {**expected, "issuer": policy.ISSUER}}) + evidence[name] = {"run_invocation": certificate["claims"][FulcioClaim.RUN_INVOCATION_URI], + "build_trigger": certificate["claims"][FulcioClaim.BUILD_TRIGGER]} + require_outcomes(run_verifier(tool_environment(root), entries, root), sorted(files), policy.ENTRY_PREFIX) + write_report(report, version, files, evidence, context, attempt) + + +def write_report(path: pathlib.Path, version: str, files: Mapping[str, FileIdentity], + evidence: Mapping[str, Mapping[str, object]], context: ReleaseContext, attempt: int) -> None: + """Retain this release's verified provenance identity as a small, credential-free JSON report. + + It names the index, the version, each file's sha256 and size and the run and trigger its certificate names, the + publisher and signer checked, the controls' verdicts, and the run: repository, checked-out commit, event, ref, + run, attempt and the attempt that uploaded. + """ + policy = ReleaseProvenancePolicy + path.parent.mkdir(parents=True, exist_ok=True) + report = { + "status": "provenance-verified", "index": policy.INDEX_NAME, "version": version, "files": dict(files), + "provenance": dict(evidence), "publisher": policy.publisher(), "signer": policy.workflow_uri(context["ref"]), + "controls": {ProvenanceControl.GOOD: "verified", ProvenanceControl.WRONG_DIGEST: "refused", + ProvenanceControl.WRONG_SIGNER: "refused"}, + "repository": policy.REPOSITORY, "commit": git_output(("rev-parse", "HEAD^{commit}")), + "event": context["event"], "ref": context["ref"], "run_id": context["run_id"], + "run_attempt": context["run_attempt"], "publish_attempt": attempt, + } + path.write_text(json.dumps(report, indent=2) + "\n", encoding="utf-8") + + +def main(argv: Optional[Sequence[str]] = None) -> int: + """Verify the release's PyPI provenance; never upload or install anything but the pinned tool.""" + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("operation", choices=("verify",)) + parser.add_argument("--directory", type=pathlib.Path, default=pathlib.Path("dist")) + parser.add_argument("--report", type=pathlib.Path, required=True) + args = parser.parse_args(argv) + verify_release(args.directory, args.report, os.environ) + print(f"OK: {args.operation}; report={args.report}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.github/scripts/testpypi_provenance.py b/.github/scripts/testpypi_provenance.py index d6339371d..d29c42d84 100644 --- a/.github/scripts/testpypi_provenance.py +++ b/.github/scripts/testpypi_provenance.py @@ -15,6 +15,10 @@ from its DER. Layers 3 and 4 are then checked by the pinned pypi-attestations and sigstore in their own environment (`.github/provenance/verify_attestations.py`), which first has to verify a recorded genuine attestation and refuse two tampered copies of it, so a tool that cannot verify, or does not check, fails the run instead of passing it. + +The release check, `pypi_provenance.py`, runs the same layers on PyPI after a final release's upload: it imports +them from here with its own `ProvenancePolicy` subclass, which names PyPI's Integrity API and the publication +workflow's identity. """ import argparse @@ -70,10 +74,17 @@ class ProvenancePolicy: The identity is the TestPyPI Trusted Publisher the owner configures (BRANCH_WORKFLOW.md): this repository, the `release-candidate.yml` workflow on `release_candidate`, the `pypitest` environment. Change it here, and only deliberately, when one of those changes. + + The layers the release check shares with this one (`fetch_provenance`, `single_attestation`, the verifier) read + the index from the policy they are given: `INDEX_NAME`, `INTEGRITY_ROOT`, `USER_AGENT`, the retry bounds and + `missing_provenance`. `pypi_provenance.ReleaseProvenancePolicy` overrides those with PyPI's and the publication + workflow's identity; everything else here (the server, the repository, the issuer, the tool) is shared. """ + INDEX_NAME = "TestPyPI" INTEGRITY_ROOT = "https://test.pypi.org/integrity/melder/" INTEGRITY_MEDIA_TYPE = "application/vnd.pypi.integrity.v1+json" + USER_AGENT = "melder-candidate-ci" SERVER = "https://github.com" OWNER = "Synaptic724" REPOSITORY = "Synaptic724/melder" @@ -95,14 +106,30 @@ class ProvenancePolicy: @classmethod def publisher(cls) -> dict[str, str]: - """Return the publisher record TestPyPI must hold for every candidate file (layer 2).""" + """Return the publisher record the index must hold for every file this check verifies (layer 2).""" return {"kind": "GitHub", "repository": cls.REPOSITORY, "workflow": cls.WORKFLOW, "environment": cls.ENVIRONMENT} @classmethod - def workflow_uri(cls) -> str: - """Return the signing workflow's URI: the certificate's SAN, Build Signer URI and Build Config URI.""" - return f"{cls.SERVER}/{cls.REPOSITORY}/.github/workflows/{cls.WORKFLOW}@{cls.REF}" + def workflow_uri(cls, ref: Optional[str] = None) -> str: + """Return the signing workflow's URI: the certificate's SAN, Build Signer URI and Build Config URI. + + Args: + ref: The full Git ref the workflow ran at; `REF` when omitted. The candidate always runs at `REF`; a + release runs at its tag or at `prod`, so the release check passes its run's ref. + """ + return f"{cls.SERVER}/{cls.REPOSITORY}/.github/workflows/{cls.WORKFLOW}@{cls.REF if ref is None else ref}" + + @classmethod + def missing_provenance(cls, name: str) -> str: + """Return the refusal for a file the index still holds no provenance for after the last lookup. + + On TestPyPI that means the file was uploaded by a token, before this check existed, or its attestation was + not accepted; the remedy is a candidate version TestPyPI has never seen. + """ + return (f"TestPyPI holds no provenance for {name}: it was uploaded without Trusted Publishing (by an API " + "token, before this check existed), or the upload's attestation was not accepted. Choose a new " + "candidate version so this workflow uploads every file with an attestation.") @staticmethod def tool_directory() -> pathlib.Path: @@ -484,50 +511,53 @@ def expected_identity(context: RunContext, uploaded_here: bool, publish_attempt: return {"san": policy.workflow_uri(), "exact": exact, "patterns": patterns} -def fetch_provenance(version: str, name: str) -> bytes: - """Read one file's provenance from TestPyPI's Integrity API (layer 1). +def fetch_provenance(version: str, name: str, policy: type[ProvenancePolicy] = ProvenancePolicy) -> bytes: + """Read one file's provenance from the policy's index, through its Integrity API (layer 1). - A 404 is retried, since TestPyPI may answer one for a moment after the upload, and so are the statuses in - `TestIndexPolicy.TRANSIENT_STATUSES`, timeouts and failed connections: up to `LOOKUP_ATTEMPTS` tries, - `RETRY_SECONDS` apart, each retry printed. Every other status raises at once. A response from any URL but the - one asked for is refused. No credentials are sent. + A 404 is retried, since an index may answer one for a moment after the upload, and so are the statuses in + `TestIndexPolicy.TRANSIENT_STATUSES`, timeouts and failed connections: up to the policy's `LOOKUP_ATTEMPTS` + tries, `RETRY_SECONDS` apart, each retry printed. Every other status raises at once. A response from any URL + but the one asked for is refused. No credentials are sent. + + Args: + version: The release whose file is looked up. + name: The file's name. + policy: The index to ask: `ProvenancePolicy` (TestPyPI) for the candidate, the release check's subclass for + PyPI. It supplies the Integrity API root, the user agent, the retry bounds and the refusal texts. Raises: - ValueError: When TestPyPI still answers 404 after the last attempt, or redirected the request. + ValueError: When the index still answers 404 after the last attempt (`policy.missing_provenance`), or + redirected the request. urllib.error.URLError: When the last attempt's failure was another HTTP status or a network error. """ - url = (ProvenancePolicy.INTEGRITY_ROOT + urllib.parse.quote(version, safe="") + "/" + url = (policy.INTEGRITY_ROOT + urllib.parse.quote(version, safe="") + "/" + urllib.parse.quote(name, safe="") + "/provenance") - request = urllib.request.Request(url, headers={"User-Agent": "melder-candidate-ci", - "Accept": ProvenancePolicy.INTEGRITY_MEDIA_TYPE}) + request = urllib.request.Request(url, headers={"User-Agent": policy.USER_AGENT, + "Accept": policy.INTEGRITY_MEDIA_TYPE}) attempt = 1 while True: try: with urllib.request.urlopen(request, timeout=30) as response: if response.url != url: - raise ValueError(f"TestPyPI answered the provenance of {name} from {response.url}; " + raise ValueError(f"{policy.INDEX_NAME} answered the provenance of {name} from {response.url}; " "refusing a redirected answer.") return response.read() except urllib.error.HTTPError as error: error.close() if error.code != 404 and error.code not in TestIndexPolicy.TRANSIENT_STATUSES: raise - if attempt == ProvenancePolicy.LOOKUP_ATTEMPTS: + if attempt == policy.LOOKUP_ATTEMPTS: if error.code == 404: - raise ValueError( - f"TestPyPI holds no provenance for {name}: it was uploaded without Trusted Publishing (by " - "an API token, before this check existed), or the upload's attestation was not accepted. " - "Choose a new candidate version so this workflow uploads every file with an attestation." - ) from error + raise ValueError(policy.missing_provenance(name)) from error raise failure = f"HTTP {error.code}" except (urllib.error.URLError, TimeoutError, ConnectionError) as error: - if attempt == ProvenancePolicy.LOOKUP_ATTEMPTS: + if attempt == policy.LOOKUP_ATTEMPTS: raise failure = type(error).__name__ - print(f"TestPyPI provenance lookup for {name} failed ({failure}), attempt {attempt} of " - f"{ProvenancePolicy.LOOKUP_ATTEMPTS}; retrying in {ProvenancePolicy.RETRY_SECONDS}s.", flush=True) - time.sleep(ProvenancePolicy.RETRY_SECONDS) + print(f"{policy.INDEX_NAME} provenance lookup for {name} failed ({failure}), attempt {attempt} of " + f"{policy.LOOKUP_ATTEMPTS}; retrying in {policy.RETRY_SECONDS}s.", flush=True) + time.sleep(policy.RETRY_SECONDS) attempt += 1 @@ -550,7 +580,7 @@ def single_attestation(document: object, label: str, publisher: Mapping[str, str differences = [f"{key} is {record.get(key)!r}, expected {value!r}" for key, value in publisher.items() if record.get(key) != value] if differences: - raise ValueError(f"TestPyPI's publisher record for {label} is not the expected Trusted Publisher: " + raise ValueError(f"The publisher record for {label} is not the expected Trusted Publisher: " + "; ".join(differences) + ".") attestations = bundle.get("attestations") if not isinstance(attestations, list) or len(attestations) != 1: @@ -697,12 +727,18 @@ def run_verifier(python: pathlib.Path, entries: Sequence[Mapping[str, object]], return outcomes -def require_outcomes(outcomes: Mapping[str, Mapping[str, object]], candidates: Sequence[str]) -> None: - """Accept the verifier's verdicts only when the controls split as they must and every candidate verified. +def require_outcomes(outcomes: Mapping[str, Mapping[str, object]], candidates: Sequence[str], + prefix: str = "candidate") -> None: + """Accept the verifier's verdicts only when the controls split as they must and every checked file verified. + + Args: + outcomes: The verifier's verdict for each entry, by entry id. + candidates: The names of the files checked, whose entries are `:`. + prefix: The id prefix their entries carry: `candidate` here, `release` for the release check. Raises: ValueError: When the tool refused the genuine control (it cannot verify here), accepted a tampered copy - (it is not checking), or refused a candidate file (naming the file and Sigstore's reason). + (it is not checking), or refused a file (naming the file and Sigstore's reason). """ good = outcomes[ProvenanceControl.GOOD] if good.get("outcome") != "verified": @@ -712,10 +748,10 @@ def require_outcomes(outcomes: Mapping[str, Mapping[str, object]], candidates: S if outcomes[entry_id].get("outcome") != "refused": raise ValueError(f"The pinned tool accepted a tampered copy of the recorded attestation ({entry_id}); " "it is not checking, so none of its verdicts can be trusted.") - refused = [f"{name}: {outcomes[f'candidate:{name}'].get('reason')}" for name in candidates - if outcomes[f"candidate:{name}"].get("outcome") != "verified"] + refused = [f"{name}: {outcomes[f'{prefix}:{name}'].get('reason')}" for name in candidates + if outcomes[f"{prefix}:{name}"].get("outcome") != "verified"] if refused: - raise ValueError("Sigstore refused the TestPyPI attestation of " + "; ".join(refused) + ".") + raise ValueError("Sigstore refused the attestation of " + "; ".join(refused) + ".") def verify_candidate(directory: pathlib.Path, report: pathlib.Path, environment: Mapping[str, str]) -> None: diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index d78459a2a..cfabefa0e 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -75,8 +75,15 @@ jobs: permissions: contents: read actions: read + # Trusted Publishing: this job's OIDC token is its only PyPI credential and signs each uploaded file's PEP 740 + # attestation. No other job of this workflow holds it. + id-token: write + outputs: + # The attempt that uploaded, for the provenance job: a failed-jobs re-run of that job alone keeps this output + # from the upload's attempt, which is the attempt the attestations name. + attempt: ${{ github.run_attempt }} environment: - # Only this job receives the environment-scoped PYPI_API_TOKEN. + # PyPI's Trusted Publisher for this workflow names this environment, and the job's OIDC token carries it. name: pypi url: https://pypi.org/project/melder/ steps: @@ -114,11 +121,46 @@ jobs: # This runs AFTER environment approval and fails if the release tag or # prod moved while checks, builds, or a human approval were pending. run: python .github/scripts/ci_policy.py release-head - - name: Publish freshly verified distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + - name: Publish freshly verified distributions to PyPI by Trusted Publishing, with attestations + # Pinned to its commit, as in release-candidate.yml, because this step runs with the job's id-token. With no + # user or password it authenticates as this workflow's PyPI Trusted Publisher (python-publish.yml, + # environment pypi) and signs every file in dist/ with Sigstore. + uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3 with: - user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} packages-dir: dist/ - attestations: false + attestations: true print-hash: true + + pypi-provenance: + name: Release / provenance + needs: [release-build, pypi-publish] + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: "3.14.7" + - name: Retrieve this run's verified distributions + # The build pypi-publish verified and uploaded, named by release-build's output so a failed-jobs re-run of + # this job alone reads the same files; the check verifies them again before it trusts their digests. + uses: actions/download-artifact@v8 + with: + name: ${{ needs.release-build.outputs.artifact-name }} + path: dist/ + - name: Verify every released file's PyPI provenance + # Five layers per file: a provenance exists, its publisher is this workflow in pypi, Sigstore verifies it, + # the certificate names this repository, workflow, ref, commit and upload attempt claim by claim, and the + # statement names the file's sha256. The pinned verifier first proves itself on a recorded attestation. + # The files are already on PyPI: a refusal fails this run before the release is announced. + env: + RELEASE_TAG: ${{ github.event.release.tag_name || '' }} + RELEASE_PUBLISH_ATTEMPT: ${{ needs.pypi-publish.outputs.attempt }} + run: python .github/scripts/pypi_provenance.py verify --report reports/provenance.json + - name: Retain provenance evidence + uses: actions/upload-artifact@v7 + with: + name: release-provenance-${{ github.run_id }}-${{ github.run_attempt }} + path: reports/provenance.json + if-no-files-found: error + retention-days: 90 diff --git a/README.md b/README.md index 031c43289..fb8f14e1c 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,11 @@ pip install melder **One dependency: pip.** Nothing else comes with it. Requires Python 3.14+. +Releases are published to PyPI from this repository's release workflow, which signs every file it uploads +([PEP 740](https://peps.python.org/pep-0740/)): +[check a download](https://melder.readthedocs.io/en/latest/beginner/install.html#check-a-downloaded-file) with +`pypi-attestations` before you install it. + Working from a clone? Use the repository's `uv.lock` and [locked contributor setup](https://github.com/Synaptic724/melder/blob/prod/CONTRIBUTING.md). @@ -1399,14 +1404,19 @@ Foresight is half of it. The other half is the live swap — **stage → notch meld**, on a running system, with the old version still sitting there: ```python -# 1. STAGE — bind a new version as an INACTIVE member of the existing index. -# It is parked and unresolvable: nothing melds it, nothing sees it yet. +# 1. STAGE — bind the edited ReportService (the candidate above, imported +# from the module it now lives in) as an INACTIVE member of the existing +# index. It is bound the way the index's first version was — bare, so +# addressed by its name, ReportService, at the default binding — and a +# version bound any other way is refused. It is parked and unresolvable: +# nothing melds it, nothing sees it yet. +from reports_v2 import ReportService as EditedReportService + id_v1 = index.selected_spell_id # the version serving now id_v2 = conduit.bind_inactive( - spell=ReportServiceV2, + spell=EditedReportService, # new code, the same name: a new spell_id spell_index=index, # the index the current version lives in existence="unique", - binding_name="v2", ) # 2. NOTCH — promote v2 to ACTIVE. The outgoing version parks, the index @@ -1414,10 +1424,19 @@ id_v2 = conduit.bind_inactive( conduit.notch_spell(spell_index=index, spell_id=id_v2) assert index.selected_spell_id == id_v2 -# 3. MELD — the very next resolution builds the NEW version. -service = conduit.meld(spell_id=id_v2) # → ReportServiceV2 +# 3. MELD — the very next resolution builds the NEW version, and the +# address follows the notch: a meld by name gets it too. +service = conduit.meld(spell_id=id_v2) # → the edited ReportService +assert conduit.meld("ReportService") is service ``` +**Every version of an index is bound the way its first version was** — the +same kind of spellframe and the same address (spellframe or class name, and +binding name). That is why a notch never moves the address, and why +`bind_inactive` refuses a renamed class bound bare: it would be another +address. When versions will carry different class names, bind them all under +one spellframe category (`spellframe="reports"`) from the first version on. + And because the old member is **parked, not destroyed**, rollback is the same verb pointed the other way: diff --git a/UX_and_AIX_experiences/04_expert/17_notch_swapping_a_live_object.py b/UX_and_AIX_experiences/04_expert/17_notch_swapping_a_live_object.py index 7f2cea9c2..c4b190cab 100644 --- a/UX_and_AIX_experiences/04_expert/17_notch_swapping_a_live_object.py +++ b/UX_and_AIX_experiences/04_expert/17_notch_swapping_a_live_object.py @@ -5,7 +5,8 @@ builds one, stages a second version onto it, shows that staging changes nothing about what resolves - which is why the swap is a two-step act - then takes the swap by the new version's spell_id, - melds it, and notches back. Everything runs on public calls. + melds it at the index's address, and notches back. Everything + runs on public calls. THE THREE VERBS @@ -15,6 +16,19 @@ conduit.notch_spell( v2 becomes the active member spell_index=index, spell_id=v2_id) + EVERY VERSION IS BOUND THE WAY THE FIRST ONE WAS. An index keeps + its first version's binding for life: the kind of spellframe + (none, a string category or a Protocol) and the address that + gives - the spellframe's name, or a bare class's own name, and + the binding name. `bind_inactive` refuses a version bound any + other way before anything is registered, so a retry with the + right arguments is admitted. That is why a notch never moves the + address, and whoever melds by the address follows the notch. Two + classes cannot share a bare address, so v1 and v2 are both bound + under one string category, "pricing" (2026-10-25; until then a + version could be staged at any address and a notch moved the + address with it). + NAME THE VERSION BY ITS SPELL_ID. A spell_id names one version, and the public spell_id->object lookups (`get_spell_by_spell_id`, `find_spell_by_spell_id`) answer exactly that version, active or @@ -39,12 +53,15 @@ 0. Checks the version: it must belong to the conduit's Spellbook and to the index you passed, or the call raises ValueError before anything moves. - 1. Parks the outgoing active spell off the four active owned + 1. Moves the address's frame claim from the outgoing version to + the incoming one in one compare-and-set. When another spell + holds the address it raises RuntimeError naming the holder, + and nothing moves. + 2. Parks the outgoing active spell off the four active owned maps, then TEARS DOWN ITS CREATION CONTEXT so the door epoch bumps and the warm fast-door cannot serve the stale spell. - 2. Promotes the parked candidate into the active maps. - 3. Repoints the index pointer and the framewide binding - signature, old spell_id -> new spell_id. + 3. Promotes the parked candidate into the active maps and + repoints the index pointer, old spell_id -> new spell_id. 4. Re-registers the index gated + dirty, so revalidation recompiles LAZILY on the next resolve rather than inside the window. @@ -54,9 +71,9 @@ does, the same way `link` does in expert 16. THE OUTGOING VERSION IS NOT DESTROYED. It stays a member of the - lineage, parked, which is why a rollback is structurally the same - act as the swap - a notch back by its spell_id - rather than a - restore. + lineage, parked, with the object it built, which is why a + rollback is structurally the same act as the swap - a notch back + by its spell_id - rather than a restore. MIND THE LAYER WHEN YOU READ THE SOURCE. `_apply_notch` says contracted borrowers are "NOT yet fanned out HERE (owner-side @@ -64,9 +81,10 @@ and `Conduit.notch_spell` one layer up does walk the links. A statement read out of its scope becomes a false one. SURFACE EXERCISED: Conduit.bind_inactive, Conduit.notch_spell(spell_id=...), - Conduit.meld, SpellIndex.selected_spell_id / - spells_in_index, Conduit.get_spell_by_spell_id -VERIFY: RUN GREEN 2026-10-17 on 3.14t, GIL off and on. + Conduit.meld(spellframe=...), + SpellIndex.selected_spell_id / spells_in_index, + Conduit.get_spell_by_spell_id +VERIFY: RUN GREEN 2026-10-25 on 3.14t, GIL off and on. """ import melder as md @@ -84,10 +102,11 @@ def __init__(self) -> None: def main() -> None: book = md.Spellbook(aetheric_frame="hotswap-world") v1_id = book.bind( - spell=HotSwapPricingV1, existence="unique", permissions="create", + spell=HotSwapPricingV1, spellframe="pricing", + existence="unique", permissions="create", ) conduit = book.conjure(dynamic=True, name="hotswap-root") - print("v1 bound and active") + print("v1 bound and active under the category 'pricing'") # THE INDEX IS PUBLICLY REACHABLE from the active spell, and it is a # LINEAGE: a set of member ids plus exactly one selection. @@ -98,16 +117,38 @@ def main() -> None: assert index.spells_in_index() == {v1_id} print("index: 1 member, selected =", v1_id[:12], "...") - # v1 RESOLVES. This is the world as it stands. - before = conduit.meld("HotSwapPricingV1") + # v1 RESOLVES at the index's address. This is the world as it stands. + before = conduit.meld(spellframe="pricing") assert before.rate == 100 - print("meld -> rate", before.rate) + print("meld(spellframe='pricing') -> rate", before.rate) + + # A VERSION BOUND ANOTHER WAY IS REFUSED. Bound bare, v2 would be + # addressed by its own name - another address than the index's - so + # bind_inactive refuses it before anything is registered. + try: + conduit.bind_inactive( + spell=HotSwapPricingV2, + spell_index=index, + existence="unique", + permissions="create", + ) + except ValueError as refusal: + assert "keeps the binding its first version" in str(refusal) + else: + raise AssertionError("a version bound another way must be refused") + assert index.spells_in_index() == {v1_id} + print() + print("bind_inactive bare -> ValueError: the index keeps its first") + print(" version's binding, and nothing was registered") - # STAGE A CANDIDATE. It is bound, owned, and a real member of the - # lineage - and it changes nothing about what resolves. + # STAGE A CANDIDATE bound the way the index's first version was. It is + # bound, owned, and a real member of the lineage - and it changes + # nothing about what resolves. The refused try left nothing behind, so + # this is not a spell_id collision. v2_id = conduit.bind_inactive( spell=HotSwapPricingV2, spell_index=index, + spellframe="pricing", existence="unique", permissions="create", ) @@ -116,13 +157,12 @@ def main() -> None: "staging must NOT move the selection - preparing a swap and " "taking it are two different acts" ) - print() - print("v2 staged: 2 members, selection UNCHANGED") + print("v2 staged under 'pricing': 2 members, selection UNCHANGED") # AND THE PARKED CANDIDATE IS INERT. The expensive half of the swap # has already happened - v2 is compiled, registered and owned - while # the old version is still the one serving traffic. - still = conduit.meld("HotSwapPricingV1") + still = conduit.meld(spellframe="pricing") assert still.rate == 100 print("meld -> rate", still.rate, " (v2 is parked, not resolvable)") print(" the costly half of a swap is done while v1 still serves") @@ -139,29 +179,35 @@ def main() -> None: # TAKE THE SWAP. The spell_id bind_inactive returned names the version; # the notch resolves it inside the call and checks that it belongs to - # this index before anything moves. + # this index before anything moves. The address does not move: it now + # serves v2. promoted = conduit.notch_spell(spell_index=index, spell_id=v2_id) assert promoted.spell_id == v2_id assert index.selected_spell_id == v2_id assert index.spells_in_index() == {v1_id, v2_id}, ( "a notch moves the selection; it removes no member" ) - after = conduit.meld(spell_id=v2_id) + after = conduit.meld(spellframe="pricing") assert after.rate == 250 + assert conduit.meld(spell_id=v2_id) is after print() - print("notch by spell_id: v2 selected, meld -> rate", after.rate) + print("notch by spell_id: v2 selected, and the address follows -") + print(" meld(spellframe='pricing') -> rate", after.rate) # ROLL BACK: the same verb pointed the other way, because v1 was - # parked, not destroyed. + # parked, not destroyed - and its object with it. conduit.notch_spell(spell_index=index, spell_id=v1_id) assert index.selected_spell_id == v1_id - back = conduit.meld(spell_id=v1_id) + back = conduit.meld(spellframe="pricing") assert back.rate == 100 - print("notch back by spell_id: v1 selected, meld -> rate", back.rate) + assert back is before + print("notch back by spell_id: v1 selected, meld -> rate", back.rate, + "(v1's own object)") print() - print("an index is a lineage with one selection") - print("staging adds a member; only a notch moves the selection") + print("an index is a lineage with one selection and one binding") + print("staging adds a member bound the same way; only a notch moves") + print("the selection, and the address follows it") print("nothing is destroyed by a notch, which is why rolling back") print("is the same act and not a restore") diff --git a/UX_and_AIX_experiences/04_expert/23_branching_the_record_and_joining_back.py b/UX_and_AIX_experiences/04_expert/23_branching_the_record_and_joining_back.py index f8387af88..7c2eb65fc 100644 --- a/UX_and_AIX_experiences/04_expert/23_branching_the_record_and_joining_back.py +++ b/UX_and_AIX_experiences/04_expert/23_branching_the_record_and_joining_back.py @@ -50,13 +50,19 @@ readable in the joined source lane Residence transfers with whatever moves, and the source is marked joined - it accepts no further work afterwards. + A NEW VERSION IS BOUND THE WAY THE FIRST ONE WAS. The receiver is + moved by staging RuleV2 on RuleV1's index, so both are bound + under one string category and binding name, ('rule', 'branch'): + an index keeps its first version's binding, and bind_inactive + refuses a version bound any other way (2026-10-25). SURFACE EXERCISED: research_create_lane (anchored, half-anchored and refused), research_heads, research_join with and without force, Conduit.bind_inactive to move the receiver, and the lane payload create_lane returns (a lane describe() snapshot: lane_type, anchor, nodes) -VERIFY: rides the owner's 3.14t harness; asserts are the contract. The - SURFACE line was corrected 2026-08-05; executable code unchanged. +VERIFY: RUN GREEN 2026-10-25 on 3.14t, GIL off and on; asserts are the + contract. The SURFACE line was corrected 2026-08-05, and both + versions moved under one binding 2026-10-25. """ import melder as md @@ -107,8 +113,8 @@ def main() -> None: rift_enabled=True, ai_native=True, ) - v1 = book.bind(spell=RuleV1, existence="unique", permissions="create", - binding_name="branch-v1") + v1 = book.bind(spell=RuleV1, spellframe="rule", existence="unique", + permissions="create", binding_name="branch") conduit = book.conjure(name="branch-root") print("v1 recorded on the default lane:", v1[:12], "...") @@ -171,10 +177,13 @@ def main() -> None: print(" the anchor: the only arrangement that is not a supersede") # NOW MOVE THE RECEIVER. A new version lands on the default lane, so - # 'stale-branch' is anchored at a point the receiver has left. + # 'stale-branch' is anchored at a point the receiver has left. It is + # bound the way v1's index was - ('rule', 'branch') - or it is refused. v2 = conduit.bind_inactive( spell=RuleV2, spell_index=conduit.get_spell_by_spell_id(v1).spell_index, + spellframe="rule", + binding_name="branch", existence="unique", permissions="create", ) diff --git a/UX_and_AIX_experiences/04_expert/26_codegen_create_modify_iterate.py b/UX_and_AIX_experiences/04_expert/26_codegen_create_modify_iterate.py index ca7eb21f4..579668867 100644 --- a/UX_and_AIX_experiences/04_expert/26_codegen_create_modify_iterate.py +++ b/UX_and_AIX_experiences/04_expert/26_codegen_create_modify_iterate.py @@ -44,6 +44,13 @@ The way to file it under a name is a different SET - a set is its own residence partition, so a version resident in one is simply unknown to another. + + A STAGED VERSION IS BOUND THE WAY THE INDEX'S FIRST ONE WAS. Rate + is bound under the string category 'Rate' with binding name + 'iterate-rate' - the address a bare bind of Rate has, so a meld of + 'Rate' still finds it - and RateV2 is staged the same way. Bound + bare, RateV2 would be addressed by its own name, and bind_inactive + refuses a version bound any other way (2026-10-25). SURFACE EXERCISED: CodegenCommandSystem.research_preview / validate_codegen / execute_codegen / materialize_codegen / research_create_lane / @@ -51,7 +58,8 @@ MutationResearch.research_set / create_research_set, ResearchSet.register_spell / create_lane / walk, Conduit.bind_inactive -VERIFY: rides the owner's 3.14t harness; asserts are the contract. +VERIFY: RUN GREEN 2026-10-25 on 3.14t, GIL off and on; asserts are the + contract. """ import melder as md @@ -104,8 +112,8 @@ def main() -> None: rift_enabled=True, ai_native=True, ) - v1 = book.bind(spell=Rate, existence="unique", permissions="create", - binding_name="iterate-rate") + v1 = book.bind(spell=Rate, spellframe="Rate", existence="unique", + permissions="create", binding_name="iterate-rate") conduit = book.conjure(name="iterate-root") print("v1 bound - an ACTIVE world entry:", v1[:12], "...") @@ -180,8 +188,10 @@ def main() -> None: assert index.spells_in_index() == {v1} assert conduit.meld("Rate", binding_name="iterate-rate").value == 1 + # Staged the way the index's first version was bound, or refused. staged = conduit.bind_inactive( spell=RateV2, spell_index=index, + spellframe="Rate", binding_name="iterate-rate", existence="unique", permissions="create", ) assert index.spells_in_index() == {v1, staged} diff --git a/UX_and_AIX_experiences/04_expert/28_the_record_crosses_as_a_json_string.py b/UX_and_AIX_experiences/04_expert/28_the_record_crosses_as_a_json_string.py index d36631e87..71f9380d5 100644 --- a/UX_and_AIX_experiences/04_expert/28_the_record_crosses_as_a_json_string.py +++ b/UX_and_AIX_experiences/04_expert/28_the_record_crosses_as_a_json_string.py @@ -37,14 +37,20 @@ purpose - `bind_inactive` declares its version into `default` automatically, and single residence means that id then lives in exactly one lane, so registering it onto a branch would raise the - rediscovery signal instead (expert 26 shows that refusal). + rediscovery signal instead (expert 26 shows that refusal). And the + staged version is bound the way the index's first one was: Policy + under the string category 'Policy' - the address a bare bind of + Policy has - with binding name 'wire-policy', and PolicyV2 the + same; bind_inactive refuses a version bound any other way + (2026-10-25). SURFACE EXERCISED: md.ResearchSet.from_payload, ResearchSet.describe / lane_names / walk / set_id / network_snapshot_shas, research_create_lane / research_join / research_heads, Conduit.bind_inactive, and the mesh quartet (with_store_handler / with_fetch_handler) -VERIFY: rides the owner's 3.14t harness; asserts are the contract. +VERIFY: RUN GREEN 2026-10-25 on 3.14t, GIL off and on; asserts are the + contract. """ import json @@ -102,8 +108,8 @@ def main() -> None: rift_enabled=True, ai_native=True, ) - v1 = book.bind(spell=Policy, existence="unique", permissions="create", - binding_name="wire-policy") + v1 = book.bind(spell=Policy, spellframe="Policy", existence="unique", + permissions="create", binding_name="wire-policy") conduit = book.conjure(name="wire-root") nexus = md.Nexus() @@ -140,10 +146,12 @@ def main() -> None: print("join('wire-clean') accepted - an empty line is a legal line;") print(" what makes it clean is the ANCHOR agreeing with the tip") - # Now move the receiver, so the second branch is provably stale. + # Now move the receiver, so the second branch is provably stale. The + # new version is bound the way the index's first one was. v2 = conduit.bind_inactive( spell=PolicyV2, spell_index=conduit.get_spell_by_spell_id(v1).spell_index, + spellframe="Policy", binding_name="wire-policy", existence="unique", permissions="create", ) print("v2 staged; the default lane moved on:", v2[:12], "...") diff --git a/UX_and_AIX_experiences/04_expert/29_reading_your_own_recorded_code.py b/UX_and_AIX_experiences/04_expert/29_reading_your_own_recorded_code.py index 83adb4cf8..1657e27c3 100644 --- a/UX_and_AIX_experiences/04_expert/29_reading_your_own_recorded_code.py +++ b/UX_and_AIX_experiences/04_expert/29_reading_your_own_recorded_code.py @@ -47,7 +47,8 @@ research_impact / research_residency / research_history / research_recent, Conduit.bind_inactive -VERIFY: rides the owner's 3.14t harness; asserts are the contract. +VERIFY: RUN GREEN 2026-10-25 on 3.14t, GIL off and on; asserts are the + contract. """ import importlib @@ -161,11 +162,15 @@ def main() -> None: # bind lands in the already-conjured frame and publishes incrementally; # the second rides its spell_index as a VERSION rather than a second # visible spell, which is why two classes named `Pricing` never collide. + # It is staged under the same binding name: every version of an index + # is bound the way its first one was, so both share one address + # (2026-10-25). v1 = book.bind(spell=first.Pricing, existence="unique", permissions="create", binding_name="well-pricing") v2 = conduit.bind_inactive( spell=second.Pricing, spell_index=conduit.get_spell_by_spell_id(v1).spell_index, + binding_name="well-pricing", existence="unique", permissions="create", ) module_name = MODULE_V1 diff --git a/UX_and_AIX_experiences/04_expert/31_organising_lanes_after_the_fact.py b/UX_and_AIX_experiences/04_expert/31_organising_lanes_after_the_fact.py index 83c824005..71b38ca43 100644 --- a/UX_and_AIX_experiences/04_expert/31_organising_lanes_after_the_fact.py +++ b/UX_and_AIX_experiences/04_expert/31_organising_lanes_after_the_fact.py @@ -37,11 +37,18 @@ and `default_lane` resolves by well-known name - so a set that archived it could not serve its own default. The refusal is checked at the door rather than discovered later. + + THE RECEIVER MOVES BY A NEW VERSION, BOUND THE WAY THE FIRST WAS. + Rule is bound under the string category 'Rule' - the address a + bare bind of Rule has - with binding name 'organise-rule', and + RuleV2 is staged the same way; bind_inactive refuses a version + bound any other way (2026-10-25). SURFACE EXERCISED: research_create_lane / research_attach / research_detach / research_archive / research_join / research_heads, ResearchSet.lane_names, Conduit.bind_inactive -VERIFY: rides the owner's 3.14t harness; asserts are the contract. +VERIFY: RUN GREEN 2026-10-25 on 3.14t, GIL off and on; asserts are the + contract. """ import melder as md @@ -81,8 +88,8 @@ def main() -> None: rift_enabled=True, ai_native=True, ) - v1 = book.bind(spell=Rule, existence="unique", permissions="create", - binding_name="organise-rule") + v1 = book.bind(spell=Rule, spellframe="Rule", existence="unique", + permissions="create", binding_name="organise-rule") conduit = book.conjure(name="organise-root") nexus = md.Nexus() @@ -137,10 +144,12 @@ def main() -> None: print("detach('forgetful') - the lane now remembers no origin") # Move the receiver so the contrast is honest, then show that a - # detached lane joins only as an explicit supersede. + # detached lane joins only as an explicit supersede. The new version + # is bound the way the index's first one was. v2 = conduit.bind_inactive( spell=RuleV2, spell_index=conduit.get_spell_by_spell_id(v1).spell_index, + spellframe="Rule", binding_name="organise-rule", existence="unique", permissions="create", ) print("default moved on:", v2[:12], "...") diff --git a/UX_and_AIX_experiences/04_expert/_concept_map.txt b/UX_and_AIX_experiences/04_expert/_concept_map.txt index 53ae3c11c..af37515ac 100644 --- a/UX_and_AIX_experiences/04_expert/_concept_map.txt +++ b/UX_and_AIX_experiences/04_expert/_concept_map.txt @@ -351,12 +351,19 @@ ARC C COMPLETE (lessons 10-15) - AR targeting, the codegen loop, and the notch_spell (repoint the selection) -> meld -> notch back. ALL THREE VERBS ARE USER SURFACE: notch_spell takes the spell_id bind_inactive returned (`spell_id=`) and resolves the exact version - inside the call - a lookup by a parked spell_id still resolves to - the ACTIVE member, which is why the version is named by its - spell_id (owner ruling 2026-10-16; until then the verb took only - the parked OBJECT and the lesson stopped at staging). A version of - another index, or of another Spellbook, is refused before anything - moves. + inside the call, which is why the version is named by its spell_id + (owner ruling 2026-10-16; until then the verb took only the parked + OBJECT and the lesson stopped at staging); since 0.2.8253 a lookup + by a parked spell_id answers that parked version too, where it + answered the ACTIVE member. A version of another index, or of + another Spellbook, is refused before anything moves. + EVERY VERSION IS BOUND THE WAY THE FIRST ONE WAS (2026-10-25): an + index keeps its first version's binding - the spellframe's kind + and the address - and bind_inactive refuses any other before it + registers anything, so a notch never moves the address and a meld + by the address follows the notch. The lesson binds both versions + under the category 'pricing', melds by it, and shows the bare + staging refused. WHAT STAGING BUYS: the expensive, failure-prone half of a swap - compiling, registering and owning the new version - happens while the old version is still serving, because a parked candidate is @@ -1286,6 +1293,18 @@ NAMED SCOPE DISCOVERY AND REPLAY (2026-09-23) membership refresh, named pooled reuse, required unnamed ancestry and successful structural replay with fresh identities/application values. +EVERY VERSION OF AN INDEX IS BOUND THE WAY ITS FIRST ONE WAS (2026-10-25) + 17, 23, 26, 28, 29 and 31 staged a version bound another way than + its index's first one - a renamed class bound bare, or the same class + at the default binding name - and bind_inactive now refuses that + before anything is registered. Each binds its versions under one + spellframe and binding name instead: 17 under the category 'pricing', + melding by it so the address is seen to follow the notch, with the + bare staging shown refused; 23 under ('rule', 'branch'); 26, 28 and + 31 under a category named like the first class - the address its + bare bind has, so melds by its name still resolve; 29 under the first + version's binding name. + REMAINING / NOT YET AUTHORED - boot melds (owner epic 2026-07-20, unassigned): conjure-time warm-up recipe riding the bind signature into checkpoints. diff --git a/UX_and_AIX_experiences/AGENTS.md b/UX_and_AIX_experiences/AGENTS.md index d4d6993f6..2ab1226ed 100644 --- a/UX_and_AIX_experiences/AGENTS.md +++ b/UX_and_AIX_experiences/AGENTS.md @@ -103,7 +103,8 @@ a probe here first; the probe's printed outcome then hardens the example. again under any binding_name, existence or spellframe is refused at bind ("Spell ID collision"), or at conjure when another Book holds it ("Conjure refused"). A changed class is a new spell_id: stage it with - bind_inactive and notch. Same-NAMED classes with different code coexist + bind_inactive, bound the way its index's first version was (next + bullet), and notch. Same-NAMED classes with different code coexist at different addresses (0.2.8206). Working patterns: subclass-per-role (24) and collection-as-spell registries (33). History: this bullet carried a DIVERGENCE FLAG - spell NAMES unique per @@ -111,6 +112,18 @@ a probe here first; the probe's printed outcome then hardens the example. SHA, against the owner's stated intent of SHA256 content matching. 0.2.8206 made Phase 4 check the full address and 0.2.8257 made the spell_id the code; the flag is closed. +- ONE INDEX, ONE BINDING (2026-10-25): a SpellIndex keeps its first + version's binding for life - the spellframe's kind (none, a string + category or a Protocol) and the address that gives - and + bind_inactive and add_to_spell_index refuse a version bound any other + way before anything registers or moves ("keeps the binding its first + version was bound with"). Stage an edited class under the index's + spellframe and binding_name; a renamed class bound bare is another + address, so bind both versions under one category (17, 23, 26, 28 and + 31). A notch never moves the address, and refuses one another spell + holds (RuntimeError naming the holder). Records written before + (record version below 5.0.0) are refused at the version gate: record + the world again. - One book conjures ONE conduit ever (RuntimeError on the second); scopes are lesser conduits, extra roots are extra books. - Unregistered meld raises one stable KeyError. Same-spell double-bind is diff --git a/agents/MELDER_AGENT_OPERATIONS.md b/agents/MELDER_AGENT_OPERATIONS.md index ab90c017e..9c5414330 100644 --- a/agents/MELDER_AGENT_OPERATIONS.md +++ b/agents/MELDER_AGENT_OPERATIONS.md @@ -455,7 +455,7 @@ Campaigns (`set_active_campaign` / `clear_active_campaign`) and staged ancestry ### Host-controlled exact-handle pattern -The older notch lesson stops at this lookup boundary. The newer public post-bind hooks deliver the actual registered active **and parked** `Spell`. A host can capture those handles at registration, and promote only after the bind itself returns successfully. The following is a **source-derived composition of public APIs, syntax-checked but not runtime-executed here**; validate it in a disposable 0.2.50 world before deployment. It installs its own hook on its own Book, not on a shared production Book. [HOOKS][C: Spellbook][C], [CONDUIT] +The older notch lesson stops at this lookup boundary. The newer public post-bind hooks deliver the actual registered active **and parked** `Spell`. A host can capture those handles at registration, and promote only after the bind itself returns successfully. The following is a **source-derived composition of public APIs**, run on 3.14t with the GIL off and on (2026-10-25); validate it in a disposable world before deployment. Both versions are bound under one spellframe category, `"price"`: every version of an index is bound the way its first version was, so a renamed class bound bare would be refused. It installs its own hook on its own Book, not on a shared production Book. [HOOKS][C: Spellbook][C], [CONDUIT] ```python import melder as md @@ -477,14 +477,14 @@ book = md.Spellbook(aetheric_frame="version-lab") root = None try: book.add_bind_hooks(post=[capture]) - old_id = book.bind(spell=PriceV1, existence="unique", permissions="create") + old_id = book.bind(spell=PriceV1, spellframe="price", existence="unique", permissions="create") root = book.conjure(dynamic=True, name="version-root") old_spell = versions[old_id] index = old_spell.spell_index new_id = root.bind_inactive( - spell=PriceV2, spell_index=index, - existence="unique", permissions="create", binding_name="v2", + spell=PriceV2, spell_index=index, spellframe="price", + existence="unique", permissions="create", ) candidate = versions[new_id] # exact object from the successful bind's hook assert candidate.spell_id == new_id @@ -512,9 +512,10 @@ finally: **Operational limits:** - Selection parks the outgoing version; it is not automatic disposal, resource retirement, or a rewrite of already-held application objects. Retire versions explicitly after consumers no longer need them. - The architecture's “owner-side only” warning describes an internal seam, not the whole current public operation. The inspected `Conduit.notch_spell` performs the local transaction, then deactivates stale borrowed copies and emits an index-notch notification for index-linked receivers. **Do not assume all borrowers automatically gain the new version**, or that the post-transaction fan-out is one indivisible action. Re-read grants, selection, and affected consumer behavior. [CONDUIT] -- On a notch exception, inspect the selected ID and consumer state before retrying: the owner switch may already have occurred. Preserve both failure and recovery reports; a recovery failure must not be labeled success. +- On a notch exception, inspect the selected ID and consumer state before retrying: the owner switch may already have occurred. Preserve both failure and recovery reports; a recovery failure must not be labeled success. A notch refused for its incoming version's structural check (0.2.8262) or for an address another spell holds (2026-10-25) moves nothing; the borrower fan-out after the transaction can still fail part-way. +- **One index, one binding** (2026-10-25): an index keeps its first version's binding - the spellframe's kind (none, a string category, a Protocol) and the address that gives (the spellframe's name, or a bare class's own name, and the binding name). `bind_inactive` and `add_to_spell_index` refuse a version bound any other way (ValueError, nothing registered or moved), and a notch never moves the address. Stage an edited class under the index's spellframe and binding name; bind versions that carry different class names under one category from the first version on. Crystallizer records older than record version 5.0.0 are refused: record the world again. [CONDUIT] - Moving/separating active index members is refused; first select another member. Separating the sole member is not the retirement route. No manual edits of `selected_spell_id`. -- Class-version fingerprints do not cover every method-body edit. Do not assume a source edit creates a new Spell ID; verify IDs, selected membership, recorded source, and behavior. Use deliberate version identities. [C: Binding][C] +- A spell_id is the SHA256 of the object's code (since 0.2.8257): an edit to a method, the constructor, a class-level value or a base is a new spell_id; a docstring, comment or line move is not. Verify IDs, selected membership, recorded source, and behavior anyway. Use deliberate version identities. [C: Binding][C] diff --git a/big_after.jsonl b/big_after.jsonl deleted file mode 100644 index ce4732f54..000000000 --- a/big_after.jsonl +++ /dev/null @@ -1,15 +0,0 @@ -{"label": "cand_t20_big1", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 20, "iters": 8000, "wall_s": 74.439, "hot_scopes": 3400000, "hot_scopes_per_s": 65718.7, "iteration": {"median_ms": 6.484, "p95_ms": 7.7658, "p99_ms": 8.4464, "avg_ms": 6.4669613125, "max_ms": 15.4816}, "threaded": {"median_ms": 3.70685, "p95_ms": 4.3438, "p99_ms": 4.682, "avg_ms": 3.7188553625, "max_ms": 10.1601}, "outer_create": {"median_ms": 0.0215, "p95_ms": 0.2512, "p99_ms": 0.413, "avg_ms": 0.0679445580882353, "max_ms": 1.9309}, "outer_cleanup": {"median_ms": 0.0039, "p95_ms": 0.007, "p99_ms": 0.0164, "avg_ms": 0.004245427588235294, "max_ms": 1.1355}, "outer_total": {"median_ms": 0.0547, "p95_ms": 0.2816, "p99_ms": 0.4445, "avg_ms": 0.09505464411764705, "max_ms": 8.8552}, "request_create": {"median_ms": 0.0019, "p95_ms": 0.0044, "p99_ms": 0.0059, "avg_ms": 0.0021975037647058823, "max_ms": 0.608}, "request_cleanup": {"median_ms": 0.0024, "p95_ms": 0.0041, "p99_ms": 0.0056, "avg_ms": 0.002487387382352941, "max_ms": 0.6255}, "request_total": {"median_ms": 0.0164, "p95_ms": 0.025, "p99_ms": 0.0335, "avg_ms": 0.016421112911764707, "max_ms": 6.8611}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 20, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t24_big1", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 24, "iters": 2500, "wall_s": 28.35, "hot_scopes": 1300000, "hot_scopes_per_s": 65553.0, "iteration": {"median_ms": 8.1342, "p95_ms": 9.6522, "p99_ms": 10.3629, "avg_ms": 7.932507599999999, "max_ms": 25.6551}, "threaded": {"median_ms": 4.60025, "p95_ms": 5.4047, "p99_ms": 5.7985, "avg_ms": 4.57384216, "max_ms": 19.6677}, "outer_create": {"median_ms": 0.035, "p95_ms": 0.3298, "p99_ms": 0.546, "avg_ms": 0.09060839038461538, "max_ms": 7.7985}, "outer_cleanup": {"median_ms": 0.004, "p95_ms": 0.0072, "p99_ms": 0.0161, "avg_ms": 0.004378837769230769, "max_ms": 8.0959}, "outer_total": {"median_ms": 0.0675, "p95_ms": 0.3605, "p99_ms": 0.5775, "avg_ms": 0.11813568261538462, "max_ms": 18.0724}, "request_create": {"median_ms": 0.0019, "p95_ms": 0.0045, "p99_ms": 0.0061, "avg_ms": 0.0022715577692307694, "max_ms": 8.0474}, "request_cleanup": {"median_ms": 0.0024, "p95_ms": 0.004, "p99_ms": 0.0056, "avg_ms": 0.0024697522307692305, "max_ms": 8.119}, "request_total": {"median_ms": 0.0164, "p95_ms": 0.025, "p99_ms": 0.034, "avg_ms": 0.016577598384615384, "max_ms": 14.0629}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 24, "max_idle": 256, "idle_count": 24, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t32_big1", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 32, "iters": 1897, "wall_s": 25.897, "hot_scopes": 1299445, "hot_scopes_per_s": 72980.7, "iteration": {"median_ms": 9.4016, "p95_ms": 11.5633, "p99_ms": 12.387, "avg_ms": 9.386048392198207, "max_ms": 49.2821}, "threaded": {"median_ms": 5.5844, "p95_ms": 6.4627, "p99_ms": 6.8271, "avg_ms": 5.57471085925145, "max_ms": 36.9582}, "outer_create": {"median_ms": 0.0579, "p95_ms": 0.4549, "p99_ms": 0.7497, "avg_ms": 0.1239556937000027, "max_ms": 1.9649}, "outer_cleanup": {"median_ms": 0.0039, "p95_ms": 0.0072, "p99_ms": 0.0156, "avg_ms": 0.004259933125295799, "max_ms": 0.8935}, "outer_total": {"median_ms": 0.0863, "p95_ms": 0.4837, "p99_ms": 0.7802, "avg_ms": 0.1505731012085929, "max_ms": 29.495}, "request_create": {"median_ms": 0.0019, "p95_ms": 0.0043, "p99_ms": 0.0058, "avg_ms": 0.0022537577965977785, "max_ms": 17.6709}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0038, "p99_ms": 0.0052, "avg_ms": 0.0023312463397835233, "max_ms": 0.9298}, "request_total": {"median_ms": 0.015, "p95_ms": 0.0241, "p99_ms": 0.032, "avg_ms": 0.015770774138189766, "max_ms": 21.3579}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 32, "max_idle": 256, "idle_count": 32, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t48_big1", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 48, "iters": 1250, "wall_s": 29.005, "hot_scopes": 1300000, "hot_scopes_per_s": 64427.2, "iteration": {"median_ms": 16.6945, "p95_ms": 19.8252, "p99_ms": 21.1327, "avg_ms": 16.14225904, "max_ms": 34.4647}, "threaded": {"median_ms": 9.04475, "p95_ms": 10.3796, "p99_ms": 10.9878, "avg_ms": 8.87866056, "max_ms": 14.0898}, "outer_create": {"median_ms": 0.1254, "p95_ms": 0.8436, "p99_ms": 1.1763, "avg_ms": 0.22090354207692306, "max_ms": 1.6031}, "outer_cleanup": {"median_ms": 0.0041, "p95_ms": 0.0079, "p99_ms": 0.0168, "avg_ms": 0.004975128153846153, "max_ms": 1.3882}, "outer_total": {"median_ms": 0.1548, "p95_ms": 0.8767, "p99_ms": 1.2089, "avg_ms": 0.2501065299230769, "max_ms": 9.5265}, "request_create": {"median_ms": 0.0023, "p95_ms": 0.0048, "p99_ms": 0.0065, "avg_ms": 0.0025600488461538463, "max_ms": 0.9388}, "request_cleanup": {"median_ms": 0.0025, "p95_ms": 0.0041, "p99_ms": 0.0057, "avg_ms": 0.0025620467692307695, "max_ms": 0.7249}, "request_total": {"median_ms": 0.0171, "p95_ms": 0.026, "p99_ms": 0.0351, "avg_ms": 0.01733640246153846, "max_ms": 7.0963}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 48, "max_idle": 256, "idle_count": 48, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t64_big1", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 64, "iters": 945, "wall_s": 29.458, "hot_scopes": 1299375, "hot_scopes_per_s": 63251.2, "iteration": {"median_ms": 21.8396, "p95_ms": 27.6142, "p99_ms": 29.9178, "avg_ms": 21.738714285714288, "max_ms": 57.6233}, "threaded": {"median_ms": 11.8259, "p95_ms": 14.659, "p99_ms": 16.2649, "avg_ms": 11.95666708994709, "max_ms": 32.0467}, "outer_create": {"median_ms": 0.2096, "p95_ms": 1.1475, "p99_ms": 1.3549, "avg_ms": 0.3174887864550265, "max_ms": 8.7418}, "outer_cleanup": {"median_ms": 0.0043, "p95_ms": 0.0084, "p99_ms": 0.0189, "avg_ms": 0.005733209042809043, "max_ms": 6.4659}, "outer_total": {"median_ms": 0.2417, "p95_ms": 1.1811, "p99_ms": 1.3929, "avg_ms": 0.34924345335257334, "max_ms": 20.1149}, "request_create": {"median_ms": 0.0022, "p95_ms": 0.005, "p99_ms": 0.0071, "avg_ms": 0.0036836057335257336, "max_ms": 2.3428}, "request_cleanup": {"median_ms": 0.0024, "p95_ms": 0.0042, "p99_ms": 0.0061, "avg_ms": 0.0032400728811928813, "max_ms": 1.3835}, "request_total": {"median_ms": 0.0166, "p95_ms": 0.0263, "p99_ms": 0.0388, "avg_ms": 0.01915617123617124, "max_ms": 12.3653}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 64, "max_idle": 256, "idle_count": 64, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t20_big2", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 20, "iters": 8000, "wall_s": 71.293, "hot_scopes": 3400000, "hot_scopes_per_s": 69592.4, "iteration": {"median_ms": 6.06375, "p95_ms": 7.5874, "p99_ms": 8.2116, "avg_ms": 6.106984925, "max_ms": 24.035}, "threaded": {"median_ms": 3.58835, "p95_ms": 4.2622, "p99_ms": 4.5862, "avg_ms": 3.6098924125000003, "max_ms": 19.2829}, "outer_create": {"median_ms": 0.0214, "p95_ms": 0.2447, "p99_ms": 0.4026, "avg_ms": 0.06633311155882353, "max_ms": 1.3628}, "outer_cleanup": {"median_ms": 0.0038, "p95_ms": 0.0064, "p99_ms": 0.0151, "avg_ms": 0.004027647735294118, "max_ms": 0.4895}, "outer_total": {"median_ms": 0.0528, "p95_ms": 0.2734, "p99_ms": 0.4319, "avg_ms": 0.09202381173529411, "max_ms": 17.7957}, "request_create": {"median_ms": 0.0018, "p95_ms": 0.0041, "p99_ms": 0.0056, "avg_ms": 0.0020617335, "max_ms": 0.4562}, "request_cleanup": {"median_ms": 0.0023, "p95_ms": 0.0038, "p99_ms": 0.0053, "avg_ms": 0.002332774294117647, "max_ms": 0.5878}, "request_total": {"median_ms": 0.0154, "p95_ms": 0.0239, "p99_ms": 0.0316, "avg_ms": 0.015492693588235294, "max_ms": 13.8752}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 20, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t24_big2", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 24, "iters": 2500, "wall_s": 25.937, "hot_scopes": 1300000, "hot_scopes_per_s": 73137.9, "iteration": {"median_ms": 7.02925, "p95_ms": 8.8976, "p99_ms": 9.7377, "avg_ms": 7.10985508, "max_ms": 28.6096}, "threaded": {"median_ms": 4.25245, "p95_ms": 5.0152, "p99_ms": 5.3961, "avg_ms": 4.2692191600000005, "max_ms": 22.7809}, "outer_create": {"median_ms": 0.0318, "p95_ms": 0.3082, "p99_ms": 0.5023, "avg_ms": 0.08430260176923077, "max_ms": 1.1768}, "outer_cleanup": {"median_ms": 0.0038, "p95_ms": 0.0065, "p99_ms": 0.0145, "avg_ms": 0.004035248307692307, "max_ms": 0.7164}, "outer_total": {"median_ms": 0.0627, "p95_ms": 0.3364, "p99_ms": 0.5318, "avg_ms": 0.11003435407692308, "max_ms": 21.0396}, "request_create": {"median_ms": 0.0018, "p95_ms": 0.0041, "p99_ms": 0.0055, "avg_ms": 0.002062474076923077, "max_ms": 0.5886}, "request_cleanup": {"median_ms": 0.0023, "p95_ms": 0.0039, "p99_ms": 0.0053, "avg_ms": 0.0023258412307692305, "max_ms": 0.5576}, "request_total": {"median_ms": 0.015, "p95_ms": 0.0241, "p99_ms": 0.0316, "avg_ms": 0.015501373153846155, "max_ms": 13.9192}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 24, "max_idle": 256, "idle_count": 24, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t32_big2", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 32, "iters": 1897, "wall_s": 25.352, "hot_scopes": 1299445, "hot_scopes_per_s": 74455.8, "iteration": {"median_ms": 9.1301, "p95_ms": 11.6389, "p99_ms": 12.351, "avg_ms": 9.200084132841328, "max_ms": 45.0981}, "threaded": {"median_ms": 5.4001, "p95_ms": 6.372, "p99_ms": 6.7597, "avg_ms": 5.431092936215077, "max_ms": 38.0721}, "outer_create": {"median_ms": 0.0544, "p95_ms": 0.4392, "p99_ms": 0.7245, "avg_ms": 0.11952626336628329, "max_ms": 1.5343}, "outer_cleanup": {"median_ms": 0.0038, "p95_ms": 0.0068, "p99_ms": 0.015, "avg_ms": 0.004118582086967898, "max_ms": 0.9928}, "outer_total": {"median_ms": 0.0825, "p95_ms": 0.4674, "p99_ms": 0.7553, "avg_ms": 0.1457941151799422, "max_ms": 32.4711}, "request_create": {"median_ms": 0.0019, "p95_ms": 0.0043, "p99_ms": 0.0058, "avg_ms": 0.0024000093886236045, "max_ms": 24.8718}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0038, "p99_ms": 0.0052, "avg_ms": 0.0023064475218266263, "max_ms": 0.7393}, "request_total": {"median_ms": 0.0149, "p95_ms": 0.0242, "p99_ms": 0.0318, "avg_ms": 0.015839451535078437, "max_ms": 28.1859}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 32, "max_idle": 256, "idle_count": 32, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t48_big2", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 48, "iters": 1250, "wall_s": 25.198, "hot_scopes": 1300000, "hot_scopes_per_s": 76016.4, "iteration": {"median_ms": 13.5628, "p95_ms": 17.4435, "p99_ms": 19.0068, "avg_ms": 13.68125608, "max_ms": 36.7016}, "threaded": {"median_ms": 8.05325, "p95_ms": 9.3744, "p99_ms": 10.0372, "avg_ms": 8.047232639999999, "max_ms": 16.4921}, "outer_create": {"median_ms": 0.1123, "p95_ms": 0.7431, "p99_ms": 1.1099, "avg_ms": 0.19768807707692307, "max_ms": 1.8486}, "outer_cleanup": {"median_ms": 0.0038, "p95_ms": 0.0071, "p99_ms": 0.0157, "avg_ms": 0.0044466863076923074, "max_ms": 1.2575}, "outer_total": {"median_ms": 0.14, "p95_ms": 0.7734, "p99_ms": 1.1396, "avg_ms": 0.22446476546153846, "max_ms": 8.5751}, "request_create": {"median_ms": 0.002, "p95_ms": 0.0045, "p99_ms": 0.0061, "avg_ms": 0.002558526307692308, "max_ms": 2.1745}, "request_cleanup": {"median_ms": 0.0023, "p95_ms": 0.0039, "p99_ms": 0.0054, "avg_ms": 0.0025001084615384615, "max_ms": 1.1858}, "request_total": {"median_ms": 0.015, "p95_ms": 0.0245, "p99_ms": 0.0328, "avg_ms": 0.01617783, "max_ms": 6.7973}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 48, "max_idle": 256, "idle_count": 48, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t64_big2", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 64, "iters": 945, "wall_s": 26.696, "hot_scopes": 1299375, "hot_scopes_per_s": 70303.0, "iteration": {"median_ms": 19.0967, "p95_ms": 26.4246, "p99_ms": 30.0373, "avg_ms": 19.558205185185187, "max_ms": 61.2133}, "threaded": {"median_ms": 11.0181, "p95_ms": 13.9377, "p99_ms": 16.0803, "avg_ms": 11.164533121693122, "max_ms": 35.4547}, "outer_create": {"median_ms": 0.1891, "p95_ms": 1.1039, "p99_ms": 1.3184, "avg_ms": 0.2936530740548341, "max_ms": 11.0614}, "outer_cleanup": {"median_ms": 0.0041, "p95_ms": 0.008, "p99_ms": 0.0198, "avg_ms": 0.005682097162097163, "max_ms": 1.8642}, "outer_total": {"median_ms": 0.219, "p95_ms": 1.1366, "p99_ms": 1.3562, "avg_ms": 0.32421167561327563, "max_ms": 22.2238}, "request_create": {"median_ms": 0.0021, "p95_ms": 0.0048, "p99_ms": 0.0067, "avg_ms": 0.003399825223665224, "max_ms": 2.2293}, "request_cleanup": {"median_ms": 0.0023, "p95_ms": 0.004, "p99_ms": 0.0057, "avg_ms": 0.0029904800384800384, "max_ms": 1.3886}, "request_total": {"median_ms": 0.0156, "p95_ms": 0.0255, "p99_ms": 0.037, "avg_ms": 0.01822448430976431, "max_ms": 12.9187}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 64, "max_idle": 256, "idle_count": 64, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t20_big3", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 20, "iters": 8000, "wall_s": 66.166, "hot_scopes": 3400000, "hot_scopes_per_s": 75096.5, "iteration": {"median_ms": 5.48135, "p95_ms": 7.3611, "p99_ms": 8.145, "avg_ms": 5.6593881875, "max_ms": 21.922}, "threaded": {"median_ms": 3.3984, "p95_ms": 4.1625, "p99_ms": 4.5628, "avg_ms": 3.4417098624999998, "max_ms": 16.9732}, "outer_create": {"median_ms": 0.0191, "p95_ms": 0.2313, "p99_ms": 0.382, "avg_ms": 0.062337677588235295, "max_ms": 1.8129}, "outer_cleanup": {"median_ms": 0.0036, "p95_ms": 0.0064, "p99_ms": 0.0156, "avg_ms": 0.003916055676470589, "max_ms": 0.4421}, "outer_total": {"median_ms": 0.0491, "p95_ms": 0.259, "p99_ms": 0.4106, "avg_ms": 0.0868170124117647, "max_ms": 16.0367}, "request_create": {"median_ms": 0.0016, "p95_ms": 0.0039, "p99_ms": 0.0052, "avg_ms": 0.0019311631470588235, "max_ms": 0.4722}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0037, "p99_ms": 0.005, "avg_ms": 0.0022246550588235297, "max_ms": 0.3754}, "request_total": {"median_ms": 0.0141, "p95_ms": 0.0233, "p99_ms": 0.0298, "avg_ms": 0.014763287352941178, "max_ms": 12.318}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 20, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t24_big3", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 24, "iters": 2500, "wall_s": 26.577, "hot_scopes": 1300000, "hot_scopes_per_s": 74627.4, "iteration": {"median_ms": 6.9079, "p95_ms": 8.8931, "p99_ms": 9.6183, "avg_ms": 6.96795248, "max_ms": 25.3874}, "threaded": {"median_ms": 4.18065, "p95_ms": 5.0188, "p99_ms": 5.3629, "avg_ms": 4.18112412, "max_ms": 20.103}, "outer_create": {"median_ms": 0.03, "p95_ms": 0.3004, "p99_ms": 0.4949, "avg_ms": 0.08198961330769232, "max_ms": 1.2927}, "outer_cleanup": {"median_ms": 0.0037, "p95_ms": 0.0065, "p99_ms": 0.0151, "avg_ms": 0.003957189, "max_ms": 0.6301}, "outer_total": {"median_ms": 0.0601, "p95_ms": 0.3283, "p99_ms": 0.5241, "avg_ms": 0.106991991, "max_ms": 18.2386}, "request_create": {"median_ms": 0.0017, "p95_ms": 0.004, "p99_ms": 0.0054, "avg_ms": 0.002032642230769231, "max_ms": 0.8367}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0038, "p99_ms": 0.0051, "avg_ms": 0.002266564923076923, "max_ms": 0.7028}, "request_total": {"median_ms": 0.0143, "p95_ms": 0.0235, "p99_ms": 0.0304, "avg_ms": 0.015086224307692308, "max_ms": 14.2715}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 24, "max_idle": 256, "idle_count": 24, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t32_big3", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 32, "iters": 1897, "wall_s": 25.274, "hot_scopes": 1299445, "hot_scopes_per_s": 75135.1, "iteration": {"median_ms": 9.0079, "p95_ms": 11.7543, "p99_ms": 12.5892, "avg_ms": 9.11691085925145, "max_ms": 26.466}, "threaded": {"median_ms": 5.4047, "p95_ms": 6.4068, "p99_ms": 6.8565, "avg_ms": 5.418286768581972, "max_ms": 19.6881}, "outer_create": {"median_ms": 0.0557, "p95_ms": 0.4413, "p99_ms": 0.7268, "avg_ms": 0.1203321432611615, "max_ms": 2.3953}, "outer_cleanup": {"median_ms": 0.0038, "p95_ms": 0.0067, "p99_ms": 0.0149, "avg_ms": 0.004070995617359719, "max_ms": 1.0309}, "outer_total": {"median_ms": 0.0832, "p95_ms": 0.4694, "p99_ms": 0.7563, "avg_ms": 0.1458766859697794, "max_ms": 17.9929}, "request_create": {"median_ms": 0.0018, "p95_ms": 0.0042, "p99_ms": 0.0056, "avg_ms": 0.002149741235681387, "max_ms": 1.5136}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0038, "p99_ms": 0.0051, "avg_ms": 0.0023006858312587296, "max_ms": 0.9381}, "request_total": {"median_ms": 0.0146, "p95_ms": 0.0238, "p99_ms": 0.0309, "avg_ms": 0.015305444247351753, "max_ms": 12.3683}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 32, "max_idle": 256, "idle_count": 32, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t48_big3", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 48, "iters": 1250, "wall_s": 27.003, "hot_scopes": 1300000, "hot_scopes_per_s": 68591.0, "iteration": {"median_ms": 15.2837, "p95_ms": 18.0196, "p99_ms": 19.2595, "avg_ms": 15.16233984, "max_ms": 39.3677}, "threaded": {"median_ms": 8.58025, "p95_ms": 9.7578, "p99_ms": 10.3312, "avg_ms": 8.59121216, "max_ms": 18.6528}, "outer_create": {"median_ms": 0.1238, "p95_ms": 0.8022, "p99_ms": 1.1472, "avg_ms": 0.21273347353846156, "max_ms": 1.8142}, "outer_cleanup": {"median_ms": 0.004, "p95_ms": 0.0075, "p99_ms": 0.0157, "avg_ms": 0.004538106769230769, "max_ms": 1.2115}, "outer_total": {"median_ms": 0.1524, "p95_ms": 0.8329, "p99_ms": 1.1779, "avg_ms": 0.2408120330769231, "max_ms": 10.2039}, "request_create": {"median_ms": 0.0021, "p95_ms": 0.0047, "p99_ms": 0.0064, "avg_ms": 0.002554340230769231, "max_ms": 1.2025}, "request_cleanup": {"median_ms": 0.0024, "p95_ms": 0.004, "p99_ms": 0.0056, "avg_ms": 0.002523971692307692, "max_ms": 1.2723}, "request_total": {"median_ms": 0.0164, "p95_ms": 0.0254, "p99_ms": 0.0348, "avg_ms": 0.01690772807692308, "max_ms": 7.5615}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 48, "max_idle": 256, "idle_count": 48, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "cand_t64_big3", "melder": "0.2.8234", "python": "3.14.7", "gil": "disabled", "threads": 64, "iters": 945, "wall_s": 26.651, "hot_scopes": 1299375, "hot_scopes_per_s": 71326.1, "iteration": {"median_ms": 19.0242, "p95_ms": 25.5725, "p99_ms": 27.3223, "avg_ms": 19.277656825396825, "max_ms": 54.6354}, "threaded": {"median_ms": 11.0925, "p95_ms": 13.576, "p99_ms": 14.6764, "avg_ms": 11.122129206349207, "max_ms": 30.6877}, "outer_create": {"median_ms": 0.1939, "p95_ms": 1.1025, "p99_ms": 1.3144, "avg_ms": 0.2953877184800385, "max_ms": 6.8345}, "outer_cleanup": {"median_ms": 0.0039, "p95_ms": 0.0071, "p99_ms": 0.0155, "avg_ms": 0.004801385435305436, "max_ms": 1.8772}, "outer_total": {"median_ms": 0.2214, "p95_ms": 1.1314, "p99_ms": 1.3459, "avg_ms": 0.32363209381433383, "max_ms": 14.3935}, "request_create": {"median_ms": 0.002, "p95_ms": 0.0046, "p99_ms": 0.0063, "avg_ms": 0.002730733698893699, "max_ms": 1.7264}, "request_cleanup": {"median_ms": 0.0023, "p95_ms": 0.004, "p99_ms": 0.0055, "avg_ms": 0.0026116419817219815, "max_ms": 1.4049}, "request_total": {"median_ms": 0.0155, "p95_ms": 0.0251, "p99_ms": 0.0354, "avg_ms": 0.017086671284271285, "max_ms": 10.0181}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 64, "max_idle": 256, "idle_count": 64, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 256, "idle_count": 0, "in_use_count": 0, "stretch_percent": 0, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} diff --git a/big_before.jsonl b/big_before.jsonl deleted file mode 100644 index 9147ade20..000000000 --- a/big_before.jsonl +++ /dev/null @@ -1,15 +0,0 @@ -{"label": "base_t20_big1", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 20, "iters": 8000, "wall_s": 67.974, "hot_scopes": 3400000, "hot_scopes_per_s": 71856.8, "iteration": {"median_ms": 5.8178, "p95_ms": 7.5147, "p99_ms": 8.2355, "avg_ms": 5.9145376625, "max_ms": 15.8094}, "threaded": {"median_ms": 3.53985, "p95_ms": 4.2436, "p99_ms": 4.6035, "avg_ms": 3.5614616875, "max_ms": 10.7678}, "outer_create": {"median_ms": 0.0206, "p95_ms": 0.2342, "p99_ms": 0.388, "avg_ms": 0.06357352261764707, "max_ms": 2.2868}, "outer_cleanup": {"median_ms": 0.0038, "p95_ms": 0.0065, "p99_ms": 0.0151, "avg_ms": 0.004064835235294118, "max_ms": 2.0287}, "outer_total": {"median_ms": 0.0522, "p95_ms": 0.2635, "p99_ms": 0.4183, "avg_ms": 0.08954945905882353, "max_ms": 9.5943}, "request_create": {"median_ms": 0.0017, "p95_ms": 0.0041, "p99_ms": 0.0056, "avg_ms": 0.0020187585294117647, "max_ms": 0.9826}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0038, "p99_ms": 0.0053, "avg_ms": 0.0022947144705882353, "max_ms": 0.7055}, "request_total": {"median_ms": 0.0152, "p95_ms": 0.0246, "p99_ms": 0.0321, "avg_ms": 0.015629844794117647, "max_ms": 7.9973}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t24_big1", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 24, "iters": 2500, "wall_s": 24.47, "hot_scopes": 1300000, "hot_scopes_per_s": 77812.0, "iteration": {"median_ms": 6.47435, "p95_ms": 8.7618, "p99_ms": 10.2062, "avg_ms": 6.68276984, "max_ms": 23.6449}, "threaded": {"median_ms": 4.1645, "p95_ms": 5.0469, "p99_ms": 5.6483, "avg_ms": 4.19476872, "max_ms": 18.2799}, "outer_create": {"median_ms": 0.0307, "p95_ms": 0.2879, "p99_ms": 0.4771, "avg_ms": 0.0790659676153846, "max_ms": 2.7129}, "outer_cleanup": {"median_ms": 0.0034, "p95_ms": 0.008, "p99_ms": 0.0456, "avg_ms": 0.004608852461538461, "max_ms": 2.1702}, "outer_total": {"median_ms": 0.063, "p95_ms": 0.3168, "p99_ms": 0.5086, "avg_ms": 0.10457384884615385, "max_ms": 16.9117}, "request_create": {"median_ms": 0.0017, "p95_ms": 0.0041, "p99_ms": 0.0086, "avg_ms": 0.0021418385384615385, "max_ms": 0.9322}, "request_cleanup": {"median_ms": 0.002, "p95_ms": 0.0037, "p99_ms": 0.005, "avg_ms": 0.0021867820769230772, "max_ms": 0.9247}, "request_total": {"median_ms": 0.0133, "p95_ms": 0.0244, "p99_ms": 0.0352, "avg_ms": 0.01502842476923077, "max_ms": 12.2576}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t32_big1", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 32, "iters": 1897, "wall_s": 25.357, "hot_scopes": 1299445, "hot_scopes_per_s": 75558.2, "iteration": {"median_ms": 8.9274, "p95_ms": 11.5521, "p99_ms": 12.5955, "avg_ms": 9.06585340010543, "max_ms": 28.4202}, "threaded": {"median_ms": 5.5427, "p95_ms": 6.4937, "p99_ms": 6.8989, "avg_ms": 5.525243753294675, "max_ms": 21.5264}, "outer_create": {"median_ms": 0.0517, "p95_ms": 0.4337, "p99_ms": 0.7122, "avg_ms": 0.11720486846307461, "max_ms": 10.8327}, "outer_cleanup": {"median_ms": 0.0038, "p95_ms": 0.0115, "p99_ms": 0.061, "avg_ms": 0.005415314768997534, "max_ms": 1.1352}, "outer_total": {"median_ms": 0.086, "p95_ms": 0.465, "p99_ms": 0.7464, "avg_ms": 0.14532674587997182, "max_ms": 19.6429}, "request_create": {"median_ms": 0.0018, "p95_ms": 0.0045, "p99_ms": 0.0213, "avg_ms": 0.0025487331899387814, "max_ms": 1.0983}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0038, "p99_ms": 0.0051, "avg_ms": 0.0023345440553467055, "max_ms": 1.1014}, "request_total": {"median_ms": 0.0151, "p95_ms": 0.0266, "p99_ms": 0.0459, "avg_ms": 0.016406072438618028, "max_ms": 12.8811}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t48_big1", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 48, "iters": 1250, "wall_s": 27.798, "hot_scopes": 1300000, "hot_scopes_per_s": 66157.3, "iteration": {"median_ms": 16.03355, "p95_ms": 19.2691, "p99_ms": 21.2233, "avg_ms": 15.720117519999999, "max_ms": 98.1401}, "threaded": {"median_ms": 9.0249, "p95_ms": 10.5479, "p99_ms": 11.5707, "avg_ms": 8.964677199999999, "max_ms": 15.0434}, "outer_create": {"median_ms": 0.1255, "p95_ms": 0.8041, "p99_ms": 1.1572, "avg_ms": 0.2141380126923077, "max_ms": 9.3301}, "outer_cleanup": {"median_ms": 0.0042, "p95_ms": 0.0186, "p99_ms": 0.0791, "avg_ms": 0.008289134384615385, "max_ms": 2.5944}, "outer_total": {"median_ms": 0.1634, "p95_ms": 0.8441, "p99_ms": 1.1944, "avg_ms": 0.2482354553076923, "max_ms": 9.3785}, "request_create": {"median_ms": 0.0022, "p95_ms": 0.0055, "p99_ms": 0.0284, "avg_ms": 0.003178085, "max_ms": 1.7148}, "request_cleanup": {"median_ms": 0.0025, "p95_ms": 0.0041, "p99_ms": 0.0057, "avg_ms": 0.0026091793846153848, "max_ms": 0.9383}, "request_total": {"median_ms": 0.0176, "p95_ms": 0.0305, "p99_ms": 0.054, "avg_ms": 0.01862307046153846, "max_ms": 5.2617}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t64_big1", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 64, "iters": 945, "wall_s": 29.964, "hot_scopes": 1299375, "hot_scopes_per_s": 62881.1, "iteration": {"median_ms": 22.1369, "p95_ms": 27.3519, "p99_ms": 32.0694, "avg_ms": 21.866651216931217, "max_ms": 72.9004}, "threaded": {"median_ms": 12.4079, "p95_ms": 15.5402, "p99_ms": 18.2091, "avg_ms": 12.554210793650793, "max_ms": 38.283}, "outer_create": {"median_ms": 0.2036, "p95_ms": 1.1352, "p99_ms": 1.3583, "avg_ms": 0.3126657548436748, "max_ms": 15.8061}, "outer_cleanup": {"median_ms": 0.0042, "p95_ms": 0.0598, "p99_ms": 0.4757, "avg_ms": 0.02045585392977393, "max_ms": 2.9741}, "outer_total": {"median_ms": 0.2606, "p95_ms": 1.1886, "p99_ms": 1.4285, "avg_ms": 0.363607735026455, "max_ms": 24.4339}, "request_create": {"median_ms": 0.0024, "p95_ms": 0.0063, "p99_ms": 0.0317, "avg_ms": 0.005318732621452621, "max_ms": 2.4401}, "request_cleanup": {"median_ms": 0.0026, "p95_ms": 0.0043, "p99_ms": 0.0065, "avg_ms": 0.0039747757190957194, "max_ms": 2.045}, "request_total": {"median_ms": 0.0179, "p95_ms": 0.0329, "p99_ms": 0.0614, "avg_ms": 0.02299312992784993, "max_ms": 14.7394}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t20_big2", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 20, "iters": 8000, "wall_s": 75.71, "hot_scopes": 3400000, "hot_scopes_per_s": 63608.7, "iteration": {"median_ms": 6.761, "p95_ms": 7.9673, "p99_ms": 8.5838, "avg_ms": 6.6814745, "max_ms": 22.7497}, "threaded": {"median_ms": 3.81475, "p95_ms": 4.4747, "p99_ms": 4.7699, "avg_ms": 3.8148765499999997, "max_ms": 18.0739}, "outer_create": {"median_ms": 0.0231, "p95_ms": 0.2613, "p99_ms": 0.4297, "avg_ms": 0.07099456385294119, "max_ms": 1.5192}, "outer_cleanup": {"median_ms": 0.004, "p95_ms": 0.0076, "p99_ms": 0.0168, "avg_ms": 0.004399866147058823, "max_ms": 0.6686}, "outer_total": {"median_ms": 0.0568, "p95_ms": 0.2921, "p99_ms": 0.4613, "avg_ms": 0.09855989505882354, "max_ms": 16.356}, "request_create": {"median_ms": 0.0019, "p95_ms": 0.0044, "p99_ms": 0.0061, "avg_ms": 0.002232971205882353, "max_ms": 0.5485}, "request_cleanup": {"median_ms": 0.0024, "p95_ms": 0.0041, "p99_ms": 0.0058, "avg_ms": 0.0025333671176470587, "max_ms": 0.8255}, "request_total": {"median_ms": 0.0166, "p95_ms": 0.025, "p99_ms": 0.0336, "avg_ms": 0.016662991382352943, "max_ms": 12.3631}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t24_big2", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 24, "iters": 2500, "wall_s": 26.405, "hot_scopes": 1300000, "hot_scopes_per_s": 71315.9, "iteration": {"median_ms": 7.33805, "p95_ms": 8.8457, "p99_ms": 9.4008, "avg_ms": 7.2915, "max_ms": 27.7418}, "threaded": {"median_ms": 4.42665, "p95_ms": 5.125, "p99_ms": 5.4067, "avg_ms": 4.40243888, "max_ms": 22.3613}, "outer_create": {"median_ms": 0.03175, "p95_ms": 0.307, "p99_ms": 0.5037, "avg_ms": 0.08404766761538462, "max_ms": 1.4285}, "outer_cleanup": {"median_ms": 0.0038, "p95_ms": 0.0091, "p99_ms": 0.0486, "avg_ms": 0.004780923230769231, "max_ms": 0.6726}, "outer_total": {"median_ms": 0.0661, "p95_ms": 0.3369, "p99_ms": 0.5347, "avg_ms": 0.11085320707692307, "max_ms": 20.765}, "request_create": {"median_ms": 0.0018, "p95_ms": 0.0043, "p99_ms": 0.0081, "avg_ms": 0.002250839923076923, "max_ms": 0.4302}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0038, "p99_ms": 0.0052, "avg_ms": 0.0022915046923076927, "max_ms": 0.2774}, "request_total": {"median_ms": 0.0152, "p95_ms": 0.0251, "p99_ms": 0.036, "avg_ms": 0.015877012153846154, "max_ms": 14.5946}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t32_big2", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 32, "iters": 1897, "wall_s": 28.385, "hot_scopes": 1299445, "hot_scopes_per_s": 65459.9, "iteration": {"median_ms": 10.7547, "p95_ms": 12.459, "p99_ms": 13.3153, "avg_ms": 10.46442245651028, "max_ms": 29.8635}, "threaded": {"median_ms": 6.0735, "p95_ms": 6.8881, "p99_ms": 7.2483, "avg_ms": 6.001301528729573, "max_ms": 22.8525}, "outer_create": {"median_ms": 0.0605, "p95_ms": 0.4715, "p99_ms": 0.7734, "avg_ms": 0.12834620172458241, "max_ms": 1.7812}, "outer_cleanup": {"median_ms": 0.0041, "p95_ms": 0.0118, "p99_ms": 0.0664, "avg_ms": 0.005928683322495374, "max_ms": 0.9824}, "outer_total": {"median_ms": 0.0959, "p95_ms": 0.505, "p99_ms": 0.8085, "avg_ms": 0.15868232807083024, "max_ms": 21.0214}, "request_create": {"median_ms": 0.0021, "p95_ms": 0.005, "p99_ms": 0.0256, "avg_ms": 0.0027870683253235036, "max_ms": 0.7375}, "request_cleanup": {"median_ms": 0.0024, "p95_ms": 0.0041, "p99_ms": 0.0057, "avg_ms": 0.0024964978894835873, "max_ms": 0.6582}, "request_total": {"median_ms": 0.0166, "p95_ms": 0.0284, "p99_ms": 0.0503, "avg_ms": 0.017475868620834282, "max_ms": 14.2524}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t48_big2", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 48, "iters": 1250, "wall_s": 26.967, "hot_scopes": 1300000, "hot_scopes_per_s": 70235.2, "iteration": {"median_ms": 14.8578, "p95_ms": 18.4537, "p99_ms": 19.9949, "avg_ms": 14.80739584, "max_ms": 88.1104}, "threaded": {"median_ms": 8.70975, "p95_ms": 9.9961, "p99_ms": 10.6886, "avg_ms": 8.66550504, "max_ms": 21.7024}, "outer_create": {"median_ms": 0.1173, "p95_ms": 0.7656, "p99_ms": 1.1331, "avg_ms": 0.20413981676923076, "max_ms": 9.3161}, "outer_cleanup": {"median_ms": 0.0042, "p95_ms": 0.017, "p99_ms": 0.0751, "avg_ms": 0.008051638153846154, "max_ms": 1.5926}, "outer_total": {"median_ms": 0.1551, "p95_ms": 0.8091, "p99_ms": 1.1724, "avg_ms": 0.23824749815384616, "max_ms": 10.2381}, "request_create": {"median_ms": 0.0021, "p95_ms": 0.0053, "p99_ms": 0.0281, "avg_ms": 0.0036698033076923075, "max_ms": 1.9945}, "request_cleanup": {"median_ms": 0.0024, "p95_ms": 0.0041, "p99_ms": 0.0058, "avg_ms": 0.0029679133846153847, "max_ms": 1.2826}, "request_total": {"median_ms": 0.0168, "p95_ms": 0.0299, "p99_ms": 0.0541, "avg_ms": 0.019162069384615385, "max_ms": 6.2491}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t64_big2", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 64, "iters": 945, "wall_s": 29.048, "hot_scopes": 1299375, "hot_scopes_per_s": 64587.2, "iteration": {"median_ms": 21.7196, "p95_ms": 26.0771, "p99_ms": 28.057, "avg_ms": 21.289061164021163, "max_ms": 67.1672}, "threaded": {"median_ms": 12.2358, "p95_ms": 14.8374, "p99_ms": 16.5631, "avg_ms": 12.267153862433862, "max_ms": 35.6368}, "outer_create": {"median_ms": 0.2002, "p95_ms": 1.1217, "p99_ms": 1.3424, "avg_ms": 0.3077200100817701, "max_ms": 15.931}, "outer_cleanup": {"median_ms": 0.0042, "p95_ms": 0.0501, "p99_ms": 0.4044, "avg_ms": 0.01782464684944685, "max_ms": 3.0189}, "outer_total": {"median_ms": 0.2523, "p95_ms": 1.17, "p99_ms": 1.4033, "avg_ms": 0.3541570575853776, "max_ms": 27.1021}, "request_create": {"median_ms": 0.0023, "p95_ms": 0.006, "p99_ms": 0.03, "avg_ms": 0.00461324936988937, "max_ms": 3.477}, "request_cleanup": {"median_ms": 0.0025, "p95_ms": 0.0041, "p99_ms": 0.0061, "avg_ms": 0.0034994206445406444, "max_ms": 1.6921}, "request_total": {"median_ms": 0.0175, "p95_ms": 0.0315, "p99_ms": 0.0577, "avg_ms": 0.021296588051948052, "max_ms": 12.188}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t20_big3", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 20, "iters": 8000, "wall_s": 71.111, "hot_scopes": 3400000, "hot_scopes_per_s": 70616.8, "iteration": {"median_ms": 5.9957, "p95_ms": 7.5149, "p99_ms": 8.1856, "avg_ms": 6.01839555, "max_ms": 24.0889}, "threaded": {"median_ms": 3.5492, "p95_ms": 4.2159, "p99_ms": 4.5557, "avg_ms": 3.5630711625, "max_ms": 19.1227}, "outer_create": {"median_ms": 0.021, "p95_ms": 0.241, "p99_ms": 0.3974, "avg_ms": 0.06533420826470589, "max_ms": 2.5051}, "outer_cleanup": {"median_ms": 0.0039, "p95_ms": 0.0068, "p99_ms": 0.0156, "avg_ms": 0.004188424176470589, "max_ms": 2.1884}, "outer_total": {"median_ms": 0.0521, "p95_ms": 0.2697, "p99_ms": 0.4271, "avg_ms": 0.09089899035294119, "max_ms": 17.7533}, "request_create": {"median_ms": 0.0018, "p95_ms": 0.0042, "p99_ms": 0.0056, "avg_ms": 0.002077053911764706, "max_ms": 0.5034}, "request_cleanup": {"median_ms": 0.0023, "p95_ms": 0.0038, "p99_ms": 0.0053, "avg_ms": 0.0023315742352941174, "max_ms": 1.7419}, "request_total": {"median_ms": 0.0151, "p95_ms": 0.0238, "p99_ms": 0.0309, "avg_ms": 0.015319762823529412, "max_ms": 12.6252}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t24_big3", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 24, "iters": 2500, "wall_s": 24.871, "hot_scopes": 1300000, "hot_scopes_per_s": 76247.6, "iteration": {"median_ms": 6.44715, "p95_ms": 9.3418, "p99_ms": 10.2413, "avg_ms": 6.81988884, "max_ms": 24.28}, "threaded": {"median_ms": 4.15505, "p95_ms": 5.2532, "p99_ms": 5.6898, "avg_ms": 4.22190592, "max_ms": 19.095}, "outer_create": {"median_ms": 0.0361, "p95_ms": 0.2892, "p99_ms": 0.4761, "avg_ms": 0.08013843907692308, "max_ms": 1.4131}, "outer_cleanup": {"median_ms": 0.0035, "p95_ms": 0.0079, "p99_ms": 0.0481, "avg_ms": 0.00468311, "max_ms": 0.8143}, "outer_total": {"median_ms": 0.0674, "p95_ms": 0.3192, "p99_ms": 0.5089, "avg_ms": 0.10614120015384615, "max_ms": 17.1234}, "request_create": {"median_ms": 0.0017, "p95_ms": 0.0044, "p99_ms": 0.0093, "avg_ms": 0.002251268153846154, "max_ms": 0.7064}, "request_cleanup": {"median_ms": 0.002, "p95_ms": 0.0038, "p99_ms": 0.0053, "avg_ms": 0.0022444996923076926, "max_ms": 0.7272}, "request_total": {"median_ms": 0.0136, "p95_ms": 0.0252, "p99_ms": 0.0366, "avg_ms": 0.015340077615384615, "max_ms": 13.5982}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t32_big3", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 32, "iters": 1897, "wall_s": 26.364, "hot_scopes": 1299445, "hot_scopes_per_s": 72863.6, "iteration": {"median_ms": 9.3694, "p95_ms": 11.9402, "p99_ms": 13.039, "avg_ms": 9.40112614654718, "max_ms": 35.825}, "threaded": {"median_ms": 5.6815, "p95_ms": 6.7147, "p99_ms": 7.1646, "avg_ms": 5.66627733263047, "max_ms": 28.7222}, "outer_create": {"median_ms": 0.054, "p95_ms": 0.4436, "p99_ms": 0.7296, "avg_ms": 0.12025266148240212, "max_ms": 5.2071}, "outer_cleanup": {"median_ms": 0.0039, "p95_ms": 0.0116, "p99_ms": 0.0618, "avg_ms": 0.005548622681221598, "max_ms": 5.2162}, "outer_total": {"median_ms": 0.0883, "p95_ms": 0.4755, "p99_ms": 0.764, "avg_ms": 0.14899227785708513, "max_ms": 26.1392}, "request_create": {"median_ms": 0.0019, "p95_ms": 0.0046, "p99_ms": 0.0219, "avg_ms": 0.0025833940643890277, "max_ms": 16.7369}, "request_cleanup": {"median_ms": 0.0023, "p95_ms": 0.0039, "p99_ms": 0.0052, "avg_ms": 0.0023397248055900786, "max_ms": 0.8603}, "request_total": {"median_ms": 0.0156, "p95_ms": 0.0272, "p99_ms": 0.0468, "avg_ms": 0.01673950640465737, "max_ms": 19.9949}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t48_big3", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 48, "iters": 1250, "wall_s": 24.152, "hot_scopes": 1300000, "hot_scopes_per_s": 78502.6, "iteration": {"median_ms": 13.0191, "p95_ms": 17.0175, "p99_ms": 18.7403, "avg_ms": 13.24796568, "max_ms": 55.8527}, "threaded": {"median_ms": 8.1434, "p95_ms": 9.5319, "p99_ms": 10.3637, "avg_ms": 8.102453839999999, "max_ms": 14.0023}, "outer_create": {"median_ms": 0.1108, "p95_ms": 0.7205, "p99_ms": 1.0988, "avg_ms": 0.1928240386923077, "max_ms": 8.5373}, "outer_cleanup": {"median_ms": 0.0039, "p95_ms": 0.0134, "p99_ms": 0.0653, "avg_ms": 0.006413322692307693, "max_ms": 1.4037}, "outer_total": {"median_ms": 0.1432, "p95_ms": 0.7533, "p99_ms": 1.1308, "avg_ms": 0.222257869, "max_ms": 11.3568}, "request_create": {"median_ms": 0.0019, "p95_ms": 0.0048, "p99_ms": 0.0258, "avg_ms": 0.0027730083846153847, "max_ms": 1.1312}, "request_cleanup": {"median_ms": 0.0022, "p95_ms": 0.0038, "p99_ms": 0.0051, "avg_ms": 0.002331951, "max_ms": 0.9969}, "request_total": {"median_ms": 0.0153, "p95_ms": 0.0279, "p99_ms": 0.0495, "avg_ms": 0.01662128453846154, "max_ms": 9.3734}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} -{"label": "base_t64_big3", "melder": "0.2.8233", "python": "3.14.7", "gil": "disabled", "threads": 64, "iters": 945, "wall_s": 26.147, "hot_scopes": 1299375, "hot_scopes_per_s": 72357.5, "iteration": {"median_ms": 18.2923, "p95_ms": 24.7084, "p99_ms": 27.632, "avg_ms": 19.002861798941797, "max_ms": 66.4106}, "threaded": {"median_ms": 11.2963, "p95_ms": 14.0078, "p99_ms": 16.0611, "avg_ms": 11.531345185185184, "max_ms": 38.5657}, "outer_create": {"median_ms": 0.183, "p95_ms": 1.082, "p99_ms": 1.3001, "avg_ms": 0.2877449690812891, "max_ms": 18.2405}, "outer_cleanup": {"median_ms": 0.004, "p95_ms": 0.042, "p99_ms": 0.3435, "avg_ms": 0.015409620394420395, "max_ms": 3.6061}, "outer_total": {"median_ms": 0.2318, "p95_ms": 1.129, "p99_ms": 1.3579, "avg_ms": 0.33111617223665224, "max_ms": 27.017}, "request_create": {"median_ms": 0.0021, "p95_ms": 0.0056, "p99_ms": 0.0293, "avg_ms": 0.004833179951899951, "max_ms": 3.2496}, "request_cleanup": {"median_ms": 0.0023, "p95_ms": 0.004, "p99_ms": 0.0059, "avg_ms": 0.003643803520923521, "max_ms": 1.6031}, "request_total": {"median_ms": 0.0163, "p95_ms": 0.0302, "p99_ms": 0.0568, "avg_ms": 0.02101996683020683, "max_ms": 14.9073}, "pools_at_end": {"conduit_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 20, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}, "root_spellspace_pool": {"baseline_idle": 20, "target_idle": 20, "max_idle": 20, "idle_count": 0, "in_use_count": 0, "stretch_percent": 200, "settle_time_seconds": 1800.0, "decay_percent_per_interval": 10, "decay_interval_seconds": 600.0}}, "counters": null} diff --git a/context_compass/artifact_board.md b/context_compass/artifact_board.md index cb2ab1e7c..63e215930 100644 --- a/context_compass/artifact_board.md +++ b/context_compass/artifact_board.md @@ -66,27 +66,32 @@ Disposition values | --- | --- | --- | --- | --- | --- | --- | --- | | tickets/tasks/backlog/2026-09-27_probe_creation_context_design_task.md | artifacts/pgo_strategies_20260927/ | measurement_evidence | backlog | retain_as_reference | Parked by owner with the adaptive-creation-contexts epic; the proof (cache ledger, live shapes, registration split) and every run retained for a reopen. | 2026-09-28T00:57:27Z | HELPFUL | -| tickets/tasks/2026-10-10_deny_file_access_under_safe_codegen_task.md | artifacts/core_protection_review_20261010/probes/codegen_probe.py | defect_reproducer | active | retain_as_reference | D-10 reproducer with its recorded output (codegen_probe_output.txt); rerun on 0.2.8267 under EPIC-2026-10-25-codegen_room_policy_defects, the runs in artifacts/codegen_room_policy_20261025/runs/. | 2026-10-25T00:16:54Z | HELPFUL | -| tickets/tasks/2026-10-10_enforce_import_policy_on_dynamic_imports_task.md | artifacts/core_protection_review_20261010/probes/codegen_probe2.py | defect_reproducer | active | retain_as_reference | D-11 reproducer with its recorded output (codegen_probe2_output.txt); rerun on 0.2.8267 under EPIC-2026-10-25-codegen_room_policy_defects, the runs in artifacts/codegen_room_policy_20261025/runs/. | 2026-10-25T00:16:54Z | HELPFUL | -| tickets/tasks/2026-10-10_refuse_materializing_over_live_modules_task.md | artifacts/core_protection_review_20261010/probes/probe_materialize.py | defect_reproducer | active | retain_as_reference | D-20 reproducers (with probe_materialize_fail.py) and their recorded outputs; rerun on 0.2.8267 under EPIC-2026-10-25-codegen_room_policy_defects, the runs in artifacts/codegen_room_policy_20261025/runs/. | 2026-10-25T00:16:54Z | HELPFUL | +| tickets/tasks/completed/2026-10-10_deny_file_access_under_safe_codegen_task.md | artifacts/core_protection_review_20261010/probes/codegen_probe.py | defect_reproducer | retained | retain_as_reference | D-10's reproducer with its recorded output (the review's pack); at 0.2.8270 it reports `open` refused under safe, hybrid and hybrid+precision and pathlib refused under hybrid (artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_b_gil0.txt, _gil1.txt); rerun it if the codegen ACL changes. | 2026-10-25T08:44:36Z | HELPFUL | +| tickets/tasks/completed/2026-10-10_enforce_import_policy_on_dynamic_imports_task.md | artifacts/core_protection_review_20261010/probes/codegen_probe2.py | defect_reproducer | retained | retain_as_reference | D-11's reproducer with its recorded output (codegen_probe2_output.txt); at 0.2.8271 it reports every `__import__` call refused under safe, hybrid, hybrid+precision and permissive - accepted under the last three before - (artifacts/codegen_room_policy_20261025/runs/codegen_probe2_d11_fix_gil0.txt, _gil1.txt); rerun it if the codegen import gate changes. | 2026-10-25T10:52:15Z | HELPFUL | +| tickets/tasks/completed/2026-10-10_refuse_materializing_over_live_modules_task.md | artifacts/core_protection_review_20261010/probes/probe_materialize.py | defect_reproducer | retained | retain_as_reference | D-20's reproducers (with probe_materialize_fail.py) and recorded outputs; they assume a successful materialize, so after 0.2.8272 they stop at their first refused case - artifacts/codegen_room_policy_20261025/scripts/d20_probe_materialize_refusals.py reports every case refused (runs/d20_probe_refusals_gil0.txt, _gil1.txt). | 2026-10-25T12:11:19Z | HELPFUL | | tickets/tasks/backlog/2026-10-16_investigate_lent_consumer_provider_loss_task.md | artifacts/meld_contract_scan_20261015/probe_rule2_lent_consumer.py | defect_reproducer | backlog | retain_as_reference | The lent-consumer reproducer (L1 follow, L3 index unlink, L4 sever) with its runs (runs/probe_rule2_lent_consumer_gil0.txt, _gil1.txt); rerun on the current tree when the task is scheduled. | 2026-10-16T11:48:20Z | HELPFUL | | tickets/tasks/backlog/2026-10-16_notch_seam_checks_incoming_before_parking_task.md | artifacts/public_notch_target_20261016/probes/probe_notch_target_today.py | defect_reproducer | backlog | retain_as_reference | Cases C4 and C5 (a notch whose incoming version is not parked for the index parks the outgoing one first) with their runs (runs/probe_notch_target_today_gil0.txt, _gil1.txt); rerun when the task is scheduled. | 2026-10-16T12:44:29Z | HELPFUL | -| tickets/tasks/2026-10-16_order_inflight_borrower_melds_against_notch_fanout_task.md | artifacts/meld_contract_scan_20261015/diag_race_kinds.py | defect_reproducer | active | retain_as_reference | The meld-vs-notch race classifier (kinds, first tracebacks, timelines) with probe_rule2_race_rate.py and their runs (runs/diag_race_kinds_*_gil0.txt, runs/probe_rule2_race_rate_*_gil*.txt); rerun on 0.2.8267 under EPIC-2026-10-25-notch_fanout_inflight_melds, the runs in artifacts/notch_fanout_race_20261025/runs/. | 2026-10-25T00:16:54Z | HELPFUL | +| tickets/tasks/completed/2026-10-16_order_inflight_borrower_melds_against_notch_fanout_task.md | artifacts/meld_contract_scan_20261015/diag_race_kinds.py | defect_reproducer | retained | retain_as_reference | The meld-vs-notch race classifier (kinds, first tracebacks, timelines) with probe_rule2_race_rate.py and their runs (runs/diag_race_kinds_*_gil0.txt, runs/probe_rule2_race_rate_*_gil*.txt); rerun on 0.2.8267 under EPIC-2026-10-25-notch_fanout_inflight_melds, the runs in artifacts/notch_fanout_race_20261025/runs/. | 2026-10-25T14:24:32Z | HELPFUL | | tickets/tasks/backlog/2026-10-17_spell_id_wording_in_held_files_task.md | artifacts/spell_id_wording_20261016/ | investigation_evidence | backlog | retain_as_reference | The inventory with its supplement, the per-occurrence decisions, the audit, the scripts and runs; re-inventory the held files before applying. | 2026-10-17T20:49:39Z | REQUIRED | | tickets/epics/2026-10-17_correctness_defects_epic.md | artifacts/correctness_defects_20261017/ | investigation_evidence | active | retain_as_reference | Probes, runs, notes and scripts of the correctness sweep; each confirmed defect's reproducer is rowed under its story too, and the three identity probes under EPIC-2026-10-18-spell_identity_is_the_code. | 2026-10-18T12:06:53Z | REQUIRED | -| tickets/stories/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_signature_claims.py | defect_reproducer | active | retain_as_reference | Cases C5, C7 with their runs (runs/probe_signature_claims_gil0.txt, _gil1.txt); re-run at the fix. | 2026-10-17T20:24:15Z | HELPFUL | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_signature_claims.py | defect_reproducer | active | retain_as_reference | Cases C5, C7 with their runs (runs/probe_signature_claims_gil0.txt, _gil1.txt); at the fix (0.2.8273, runs/probe_signature_claims_0_2_8273_gil0.txt, _gil1.txt, through scripts/run_with_alias.py) C5 and C6 are refused at the way in and C7 by the notch, C1-C4 unchanged. | 2026-10-25T12:26:46Z | HELPFUL | | tickets/stories/2026-10-17_restore_drops_separated_parked_version_story.md | artifacts/correctness_defects_20261017/probes/probe_restore_staged_structure.py | defect_reproducer | ready | retain_as_reference | Cases R1-R3 with restore_targets.py and their runs (runs/probe_restore_staged_structure_gil0.txt, _gil1.txt); re-run at the fix. | 2026-10-17T20:36:54Z | HELPFUL | -| tickets/stories/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_book_teardown_parked.py | defect_reproducer | active | retain_as_reference | Case T4 (the claim outlives the Book) with its runs (runs/probe_book_teardown_parked_gil0.txt, _gil1.txt); re-run at the fix. | 2026-10-17T21:13:35Z | HELPFUL | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_book_teardown_parked.py | defect_reproducer | active | retain_as_reference | Case T4 (the claim outlives the Book) with its runs (runs/probe_book_teardown_parked_gil0.txt, _gil1.txt); at the fix (runs/probe_book_teardown_parked_0_2_8273_gil0.txt, _gil1.txt, through scripts/run_with_alias.py) T4 is refused at the way in; T5 binds one class twice, refused since 0.2.8257. | 2026-10-25T12:26:46Z | HELPFUL | | tickets/stories/2026-10-17_restore_drops_separated_parked_version_story.md | artifacts/correctness_defects_20261017/probes/probe_graft_parked_members.py | defect_reproducer | ready | retain_as_reference | Case G2 (the graft side: the separated version comes back active) with its runs (runs/probe_graft_parked_members_gil0.txt, _gil1.txt). | 2026-10-17T21:47:06Z | HELPFUL | | tickets/stories/2026-10-19_notch_back_keeps_outgoing_dependencies_story.md | artifacts/failed_notch_refusal_20261018/probes/probe_notch_back_lineage_dependencies.py | defect_reproducer | ready | retain_as_reference | Cases H1-H4 (a notch back leaves the outgoing version's dependencies on the lineage; a borrower's consumer melding first is refused for good) with their runs on 0.2.8260 (runs/probe_notch_back_lineage_dependencies_0_2_8260_gil0.txt, _gil1.txt); re-run at the fix. | 2026-10-19T12:13:27Z | REQUIRED | | tickets/tasks/completed/2026-10-24_cache_file_write_failure_fails_meld_task.md | artifacts/cache_write_failure_20261024/ | defect_reproducer | retained | retain_as_reference | The defect's reproducer (probes/probe_cache_emit_failure.py, cases A-D) with its runs on 0.2.8265 and at the fix (runs/probe_*, runs/f6_*), the regression tests' red runs and the lane's scripts; rerun the probe if the cache save path changes. | 2026-10-24T21:32:03Z | HELPFUL | | tickets/tasks/completed/2026-10-24_windows_held_cache_bundle_test_task.md | artifacts/windows_held_bundle_20261024/ | test_harness | retained | retain_as_reference | The Linux emulation harness for the Windows-only held-bundle tests (scripts/) with the VM runs, the red runs on 0.2.8265 and the owner's Windows runs (runs/); rerun the harness if the cache save path changes. | 2026-10-24T23:03:28Z | HELPFUL | -| tickets/epics/2026-10-25_codegen_room_policy_defects_epic.md | artifacts/codegen_room_policy_20261025/ | investigation_evidence | active | retain_as_reference | The opening script of both epics (scripts/) and the 0.2.8267 reruns of D-10, D-11 and D-20 (runs/, as they land); disposition decided at closure. | 2026-10-25T00:16:54Z | HELPFUL | -| tickets/tasks/2026-10-16_order_inflight_borrower_melds_against_notch_fanout_task.md | artifacts/notch_fanout_race_20261025/ | investigation_evidence | active | retain_as_reference | The 0.2.8267 reruns of the race (runs/: the rate and kinds probes, the in-Book probe's 20- and 100-run captures), the in-Book probe (probes/) and this pass (scripts/); disposition decided at closure. | 2026-10-25T00:48:34Z | HELPFUL | -| tickets/stories/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/diag_notch_takes_other_books_address.py | defect_reproducer | active | retain_as_reference | The cross-Book case (a notch takes another Book's address; its teardown then frees it) with its run (runs/diag_notch_takes_other_books_address_0_2_8267.txt); re-run at the fix. | 2026-10-25T01:26:18Z | HELPFUL | -| tickets/stories/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_how_melds_follow_a_notch.py | measurement_evidence | active | retain_as_reference | What follows a notch at one address and across two (runs/probe_how_melds_follow_a_notch_0_2_8267.txt); re-run at the fix. | 2026-10-25T01:26:18Z | HELPFUL | -| tickets/stories/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/scripts/option_a_experiment/ | measurement_evidence | active | retain_as_reference | Option (A)'s scratch patches, the resumable test logger and runners, with runs/option_a_blast_radius_0_2_8267.txt (169 tests stage at another address); the fix's tests replace it. | 2026-10-25T01:26:18Z | REQUIRED | -| tickets/stories/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_mixed_record_under_option_a.py | defect_reproducer | active | retain_as_reference | A record holding a mixed index replayed under (A) (runs/probe_mixed_record_under_option_a_0_2_8267.txt); re-run at the fix for the owner's call 1. | 2026-10-25T01:26:18Z | REQUIRED | +| tickets/epics/completed/2026-10-25_codegen_room_policy_defects_epic.md | artifacts/codegen_room_policy_20261025/ | investigation_evidence | retained | retain_as_reference | The three defects' 0.2.8267 reruns, red/green/tier runs, the fix probes and the graph-descriptor scripts (d10, d11, d20); kept as the evidence the closures cite. | 2026-10-25T12:11:19Z | HELPFUL | +| tickets/tasks/completed/2026-10-16_order_inflight_borrower_melds_against_notch_fanout_task.md | artifacts/notch_fanout_race_20261025/ | investigation_evidence | retained | retain_as_reference | The 0.2.8267 reruns of the race (runs/: the rate and kinds probes, the in-Book probe's 20- and 100-run captures), the in-Book probe (probes/) and this pass (scripts/); disposition decided at closure. | 2026-10-25T14:24:32Z | HELPFUL | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/diag_notch_takes_other_books_address.py | defect_reproducer | active | retain_as_reference | The cross-Book case (a notch takes another Book's address; its teardown then frees it) with its run (runs/diag_notch_takes_other_books_address_0_2_8267.txt); at the fix its staging under another binding is refused (runs/diag_notch_takes_other_books_address_0_2_8273.txt). | 2026-10-25T12:26:46Z | HELPFUL | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_how_melds_follow_a_notch.py | measurement_evidence | active | retain_as_reference | What follows a notch at one address and across two (runs/probe_how_melds_follow_a_notch_0_2_8267.txt); at the fix the one-address case answers as before and the two-address staging is refused (runs/probe_how_melds_follow_a_notch_0_2_8273.txt). | 2026-10-25T12:26:46Z | HELPFUL | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/scripts/option_a_experiment/ | measurement_evidence | active | retain_as_reference | Option (A)'s scratch patches, the resumable test logger and runners (the meld-identity and stuck-consumer runners too), with runs/option_a_blast_radius_0_2_8267.txt (169 tests stage at another address); (A) landed at 0.2.8273, so the patches are history and the fix's tests replace them. | 2026-10-25T12:26:46Z | REQUIRED | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_mixed_record_under_option_a.py | defect_reproducer | active | retain_as_reference | A record holding a mixed index replayed under (A) (runs/probe_mixed_record_under_option_a_0_2_8267.txt); at the fix a mixed index cannot be built (runs/probe_mixed_record_under_option_a_0_2_8273.txt) and a 0.2.8267 record is refused by RecordVersion 5.0.0, the owner's call 1. | 2026-10-25T12:26:46Z | REQUIRED | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/correctness_defects_20261017/probes/probe_meld_identities_across_a_notch.py | measurement_evidence | active | retain_as_reference | Every meld form across a notch (spell_id, address, class, name, SpellMap, injection, borrowers) with its run (runs/probe_meld_identities_across_a_notch_0_2_8267.txt); at the fix the renamed bare stagings are refused and the other cases answer as before (runs/probe_meld_identities_across_a_notch_0_2_8273.txt). | 2026-10-25T12:26:46Z | REQUIRED | +| tickets/epics/2026-10-25_dependency_watchers_listen_for_names_epic.md | artifacts/correctness_defects_20261017/probes/diag_class_annotated_consumer_after_notch_back.py | defect_reproducer | active | retain_as_reference | The stuck class-annotated consumer (a notch back or a later bind under a spellframe) with its run (runs/diag_class_annotated_consumer_after_notch_back_0_2_8267.txt); the epic's S1 starts from it and its fix story re-runs it. | 2026-10-25T02:47:38Z | REQUIRED | +| tickets/tasks/completed/2026-10-25_creations_many_disposal_docstrings_task.md | artifacts/creations_many_disposal_20261025/ | defect_reproducer | retained | retain_as_reference | The two rebind probes (probes/: another disposal list; a slotted definition rebound as `many`) with their runs on 0.2.8267 and, at their fix, on 0.2.8275 (runs/*_0_2_8275_gil0.txt, _gil1.txt): R1 and R3 now dispose each product with its own list and R6a and R6b build a new object and raise nothing - the gap is closed (STORY-2026-10-25-creations_store_slots_by_binding, 0.2.8274). Kept as the before/after evidence; delete on the owner's word. | 2026-10-25T15:05:55Z | HELPFUL | +| tickets/stories/completed/2026-10-25_creations_store_slots_by_binding_story.md | artifacts/rebind_live_store_tests_20261025/ | defect_reproducer | retained | retain_as_reference | From TASK-2026-10-25-rebind_while_old_objects_are_alive_tests (closed into the story): the module's runs (normal and --runxfail), the S3 stand-in that flips its four defect cases, the E1-E7 examples probe and the S1-S11 store probe, the GIL off and on, on 0.2.8270 - the evidence the story's notes cite. S1-S9 are fixed at 0.2.8274 and pinned by the story's tests; rerun the store probe when Fix B (S10, S11: teardown order per object) is taken up. | 2026-10-25T14:06:11Z | HELPFUL | +| tickets/epics/2026-10-25_index_binding_risks_and_gaps_epic.md | artifacts/index_binding_risks_20261025/ | measurement_evidence | active | retain_as_reference | GAP-1's measurement script and its runs and the UX runs (GAP-10), on 0.2.8273 and 0.2.8275; the graph census belonged to GAP-12, dropped; each investigation runs its measurement again. | 2026-10-25T14:58:20Z | HELPFUL | ## Recently Cleared Artifacts @@ -99,6 +104,16 @@ Disposition values | tickets/stories/completed/2026-10-24_remove_many_child_holder_ownership_story.md | artifacts/many_child_removal_20261024/ | delete_on_close | The red and green runs, the release-note claim runs and the edit scripts; deleted at closure (the committed files stay in git history). | 2026-10-24T22:06:33Z | | tickets/stories/completed/2026-10-24_src_architecture_trim_to_spec_story.md | artifacts/src_architecture_to_spec_20261024/ | delete_on_close | The trim script (v2.1), its dry runs, the E0 baseline copies and the apply-run accounting; deleted at closure (the v1 script is in git 3bedd65bb; the accounting is in the story's Notes). | 2026-10-24T22:40:13Z | | tickets/stories/completed/2026-10-24_src_components_to_spec_story.md | artifacts/src_components_to_spec_20261024/ | delete_on_close | The edit script (driver, library, five op modules), its dry runs, the E0 baseline copies and the apply log; deleted at closure (the accounting is in the story's Notes; the old text is in git 9f240166f). | 2026-10-25T01:12:33Z | +| tickets/stories/completed/2026-10-25_probe_and_purge_reach_every_version_story.md | system_docs/patches/active/probe_and_purge_reach_every_version_2026_10_25/ | promote_to_documentation | Merged into src_architecture, src_components and tests_components at 0.2.8269 (the story's MEASURE note of 2026-10-25T08:07:18Z); the folder deleted at closure. | 2026-10-25T08:22:32Z | +| tickets/stories/completed/2026-10-25_probe_and_purge_reach_every_version_story.md | artifacts/probe_purge_every_version_20261025/ | delete_on_close | The probe of today's answers, the red, green and suite runs, the release-note claim runs and the lane's runners; summarized in the story's Notes and deleted at closure (the committed files stay in git history). | 2026-10-25T08:22:32Z | +| tickets/tasks/completed/2026-10-10_deny_file_access_under_safe_codegen_task.md | system_docs/patches/completed/codegen_open_builtin_posture_2026_10_25/ | promote_to_documentation | Merged into src_architecture, src_components and tests_components at 0.2.8270 (the task's Notes of 2026-10-25T02:59:13Z and 08:30:27Z); the folder moved from patches/active/ at closure. | 2026-10-25T08:44:36Z | +| tickets/tasks/completed/2026-10-10_enforce_import_policy_on_dynamic_imports_task.md | system_docs/patches/completed/codegen_dynamic_import_policy_2026_10_25/ | promote_to_documentation | Merged into src_architecture, src_components and tests_components at 0.2.8271 (the task's closure Summary and the consumption-mapping note of 2026-10-25T09:58:47Z); the folder moved from patches/active/ at closure. | 2026-10-25T10:52:15Z | +| tickets/tasks/completed/2026-10-10_refuse_materializing_over_live_modules_task.md | system_docs/patches/completed/codegen_materialize_namespace_2026_10_25/ | promote_to_documentation | Merged into src_architecture, src_components and tests_components at 0.2.8272 (the task's consumption-mapping and closure notes); the folder moved from patches/active/ at closure. | 2026-10-25T12:11:19Z | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | system_docs/patches/active/index_keeps_its_first_binding_2026_10_25/ | promote_to_documentation | Merged into src_architecture and src_components (the story's FACT note of 2026-10-25T11:57:21Z); the folder deleted at closure. | 2026-10-25T12:26:46Z | +| tickets/stories/completed/2026-10-17_notch_moves_signature_by_incoming_key_only_story.md | artifacts/index_keeps_its_binding_20261025/ | delete_on_close | The red, green, suite, R7 and UX runs and the lane's runner; summarized in the story's Notes and deleted at closure (the committed files stay in git history). | 2026-10-25T12:26:46Z | +| tickets/stories/completed/2026-10-25_creations_store_slots_by_binding_story.md | system_docs/patches/completed/creations_store_slots_by_binding_2026_10_25/ | promote_to_documentation | Merged into src_architecture, src_components, the tests pair and the graph at 0.2.8274 (the story's FACT notes of 2026-10-25T13:16:28Z and 13:34:11Z); the folder moved from patches/active/ at closure. | 2026-10-25T14:06:11Z | +| tickets/stories/completed/2026-10-25_creations_store_slots_by_binding_story.md | artifacts/creations_store_slots_20261025/ | delete_on_close | The red, green, suite and benchmark runs and the lane's scripts; summarized in the story's Notes (11:13:56Z, 12:19:51Z) and deleted at closure (the committed files are in git history, af169b072). | 2026-10-25T14:06:11Z | +| tickets/tasks/completed/2026-10-16_order_inflight_borrower_melds_against_notch_fanout_task.md | system_docs/patches/completed/notch_fanout_inside_window_2026_10_25/ | promote_to_documentation | Merged into src_architecture, src_components, tests_components and tests_architecture at 0.2.8275; the folder moved from patches/active/ at closure. | 2026-10-25T14:24:32Z | ## Notes diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe2_d11_fix_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe2_d11_fix_gil0.txt new file mode 100644 index 000000000..6b806dd60 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe2_d11_fix_gil0.txt @@ -0,0 +1,19 @@ +command: python -X gil=0 _probes/codegen_probe2.py (cwd: /tmp copy of 0.2.8270 tree + D-11; PYTHONPATH=src:.; Python 3.14.7t) +ran_at: 2026-10-25T10:18:16Z +safe __import__('subprocess') accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +safe __import__('socket' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +safe __import__('importlib' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +safe __import__('melder' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid __import__('subprocess') accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid __import__('socket' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid __import__('importlib' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid __import__('melder' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid+precision __import__('subprocess') accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid+precision __import__('socket' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid+precision __import__('importlib' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid+precision __import__('melder' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +permissive __import__('subprocess') accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +permissive __import__('socket' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +permissive __import__('importlib' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +permissive __import__('melder' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe2_d11_fix_gil1.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe2_d11_fix_gil1.txt new file mode 100644 index 000000000..0bdcf6103 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe2_d11_fix_gil1.txt @@ -0,0 +1,23 @@ +command: python -X gil=1 _probes/codegen_probe2.py (cwd: /tmp copy of 0.2.8270 tree + D-11; PYTHONPATH=src:.; Python 3.14.7t) +ran_at: 2026-10-25T10:18:17Z +/tmp/m0d11/src/melder/__init__.py:199: UserWarning: Python 3.14+ detected, but running in GIL-enabled mode. +melder is optimized for Python built with --disable-gil (PEP 703). +Performance may be degraded. + warnings.warn( +safe __import__('subprocess') accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +safe __import__('socket' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +safe __import__('importlib' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +safe __import__('melder' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid __import__('subprocess') accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid __import__('socket' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid __import__('importlib' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid __import__('melder' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid+precision __import__('subprocess') accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid+precision __import__('socket' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid+precision __import__('importlib' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +hybrid+precision __import__('melder' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +permissive __import__('subprocess') accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +permissive __import__('socket' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +permissive __import__('importlib' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +permissive __import__('melder' ) accepted=False result=None issues=("Builtin '__import__' is not allowed in this codegen mode.",) +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_b_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_b_gil0.txt new file mode 100644 index 000000000..2dc5dcec1 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_b_gil0.txt @@ -0,0 +1,29 @@ +command: python -X gil=0 codegen_probe.py /tmp/m0s2/probe_b_gil0 /src/melder/aether/spellbook/bind/bind.py (cwd: /tmp/m0s2/d10_b, a copy of the working tree with the D-10 fix and option B; PYTHONPATH=/src:) +python: 3.14.7 gil_enabled=False +ran_at: 2026-10-25T08:16:17Z +safe open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +safe open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +safe pathlib-write accepted=False wrote=False result=None issues=('Import statements are not allowed in this codegen mode.',) +safe import-melder accepted=False wrote=None result=None issues=('Import statements are not allowed in this codegen mode.',) +safe import-subprocess accepted=False wrote=None result=None issues=('Import statements are not allowed in this codegen mode.',) +hybrid open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid pathlib-write accepted=False wrote=False result=None issues=("Import root 'pathlib' is not allowed in this codegen mode.",) +hybrid import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +hybrid import-subprocess accepted=False wrote=None result=None issues=("Import root 'subprocess' is not allowed in this codegen mode.",) +hybrid+precision open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid+precision open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid+precision pathlib-write accepted=False wrote=False result=None issues=("Import root 'pathlib' is not allowed in this codegen mode.",) +hybrid+precision import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +hybrid+precision import-subprocess accepted=False wrote=None result=None issues=("Import root 'subprocess' is not allowed in this codegen mode.",) +permissive open-write accepted=True wrote=True result=1 issues= +permissive open-read-core accepted=True wrote=None result=74042 issues= +permissive pathlib-write accepted=True wrote=True result=1 issues= +permissive import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +permissive import-subprocess accepted=True wrote=None result='subprocess' issues= +full_access open-write accepted=True wrote=True result=1 issues= +full_access open-read-core accepted=True wrote=None result=74042 issues= +full_access pathlib-write accepted=True wrote=True result=1 issues= +full_access import-melder accepted=True wrote=None result='melder' issues= +full_access import-subprocess accepted=True wrote=None result='subprocess' issues= +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_b_gil1.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_b_gil1.txt new file mode 100644 index 000000000..8566f6856 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_b_gil1.txt @@ -0,0 +1,33 @@ +command: python -X gil=1 codegen_probe.py /tmp/m0s2/probe_b_gil1 /src/melder/aether/spellbook/bind/bind.py (cwd: /tmp/m0s2/d10_b, a copy of the working tree with the D-10 fix and option B; PYTHONPATH=/src:) +python: 3.14.7 gil_enabled=True +ran_at: 2026-10-25T08:16:18Z +/tmp/m0s2/d10_b/src/melder/__init__.py:199: UserWarning: Python 3.14+ detected, but running in GIL-enabled mode. +melder is optimized for Python built with --disable-gil (PEP 703). +Performance may be degraded. + warnings.warn( +safe open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +safe open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +safe pathlib-write accepted=False wrote=False result=None issues=('Import statements are not allowed in this codegen mode.',) +safe import-melder accepted=False wrote=None result=None issues=('Import statements are not allowed in this codegen mode.',) +safe import-subprocess accepted=False wrote=None result=None issues=('Import statements are not allowed in this codegen mode.',) +hybrid open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid pathlib-write accepted=False wrote=False result=None issues=("Import root 'pathlib' is not allowed in this codegen mode.",) +hybrid import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +hybrid import-subprocess accepted=False wrote=None result=None issues=("Import root 'subprocess' is not allowed in this codegen mode.",) +hybrid+precision open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid+precision open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid+precision pathlib-write accepted=False wrote=False result=None issues=("Import root 'pathlib' is not allowed in this codegen mode.",) +hybrid+precision import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +hybrid+precision import-subprocess accepted=False wrote=None result=None issues=("Import root 'subprocess' is not allowed in this codegen mode.",) +permissive open-write accepted=True wrote=True result=1 issues= +permissive open-read-core accepted=True wrote=None result=74042 issues= +permissive pathlib-write accepted=True wrote=True result=1 issues= +permissive import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +permissive import-subprocess accepted=True wrote=None result='subprocess' issues= +full_access open-write accepted=True wrote=True result=1 issues= +full_access open-read-core accepted=True wrote=None result=74042 issues= +full_access pathlib-write accepted=True wrote=True result=1 issues= +full_access import-melder accepted=True wrote=None result='melder' issues= +full_access import-subprocess accepted=True wrote=None result='subprocess' issues= +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_fix_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_fix_gil0.txt new file mode 100644 index 000000000..5f212821e --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_fix_gil0.txt @@ -0,0 +1,29 @@ +command: python -X gil=0 codegen_probe.py /tmp/m0s2/probe_out_gil0 /src/melder/aether/spellbook/bind/bind.py (cwd: /tmp/m0s2/d10_fix, a copy of the working tree with the D-10 fix; PYTHONPATH=/src:) +python: 3.14.7 gil_enabled=False +ran_at: 2026-10-25T02:26:37Z +safe open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +safe open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +safe pathlib-write accepted=False wrote=False result=None issues=('Import statements are not allowed in this codegen mode.',) +safe import-melder accepted=False wrote=None result=None issues=('Import statements are not allowed in this codegen mode.',) +safe import-subprocess accepted=False wrote=None result=None issues=('Import statements are not allowed in this codegen mode.',) +hybrid open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid pathlib-write accepted=True wrote=True result=1 issues= +hybrid import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +hybrid import-subprocess accepted=False wrote=None result=None issues=("Import root 'subprocess' is not allowed in this codegen mode.",) +hybrid+precision open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid+precision open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid+precision pathlib-write accepted=False wrote=False result=None issues=("Import root 'pathlib' is not allowed in this codegen mode.",) +hybrid+precision import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +hybrid+precision import-subprocess accepted=False wrote=None result=None issues=("Import root 'subprocess' is not allowed in this codegen mode.",) +permissive open-write accepted=True wrote=True result=1 issues= +permissive open-read-core accepted=True wrote=None result=74042 issues= +permissive pathlib-write accepted=True wrote=True result=1 issues= +permissive import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +permissive import-subprocess accepted=True wrote=None result='subprocess' issues= +full_access open-write accepted=True wrote=True result=1 issues= +full_access open-read-core accepted=True wrote=None result=74042 issues= +full_access pathlib-write accepted=True wrote=True result=1 issues= +full_access import-melder accepted=True wrote=None result='melder' issues= +full_access import-subprocess accepted=True wrote=None result='subprocess' issues= +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_fix_gil1.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_fix_gil1.txt new file mode 100644 index 000000000..db98e4a82 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/codegen_probe_d10_fix_gil1.txt @@ -0,0 +1,32 @@ +command: python -X gil=1 codegen_probe.py /tmp/m0s2/probe_out_gil1 /src/melder/aether/spellbook/bind/bind.py (cwd: /tmp/m0s2/d10_fix, a copy of the working tree with the D-10 fix; PYTHONPATH=/src:) +python: 3.14.7 gil_enabled=True +ran_at: 2026-10-25T02:26:38Z +/tmp/m0s2/d10_fix/src/melder/__init__.py:199: UserWarning: Python 3.14+ detected, but running in GIL-enabled mode. +melder is optimized for Python built with --disable-gil (PEP 703). +Performance may be degraded. +safe open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +safe open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +safe pathlib-write accepted=False wrote=False result=None issues=('Import statements are not allowed in this codegen mode.',) +safe import-melder accepted=False wrote=None result=None issues=('Import statements are not allowed in this codegen mode.',) +safe import-subprocess accepted=False wrote=None result=None issues=('Import statements are not allowed in this codegen mode.',) +hybrid open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid pathlib-write accepted=True wrote=True result=1 issues= +hybrid import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +hybrid import-subprocess accepted=False wrote=None result=None issues=("Import root 'subprocess' is not allowed in this codegen mode.",) +hybrid+precision open-write accepted=False wrote=False result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid+precision open-read-core accepted=False wrote=None result=None issues=("Builtin 'open' is not allowed in this codegen mode.",) +hybrid+precision pathlib-write accepted=False wrote=False result=None issues=("Import root 'pathlib' is not allowed in this codegen mode.",) +hybrid+precision import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +hybrid+precision import-subprocess accepted=False wrote=None result=None issues=("Import root 'subprocess' is not allowed in this codegen mode.",) +permissive open-write accepted=True wrote=True result=1 issues= +permissive open-read-core accepted=True wrote=None result=74042 issues= +permissive pathlib-write accepted=True wrote=True result=1 issues= +permissive import-melder accepted=False wrote=None result=None issues=("Import root 'melder' is not allowed in this codegen mode.",) +permissive import-subprocess accepted=True wrote=None result='subprocess' issues= +full_access open-write accepted=True wrote=True result=1 issues= +full_access open-read-core accepted=True wrote=None result=74042 issues= +full_access pathlib-write accepted=True wrote=True result=1 issues= +full_access import-melder accepted=True wrote=None result='melder' issues= +full_access import-subprocess accepted=True wrote=None result='subprocess' issues= +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_fix_tiers_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_fix_tiers_gil0.txt new file mode 100644 index 000000000..a64500a27 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_fix_tiers_gil0.txt @@ -0,0 +1,17 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx <35 codegen/ACL unit files in tests/unit/melder/aether> tests/component/melder/aether tests/integration/melder/aether (cwd: /tmp/m0s2/d10_b, a /tmp copy of the working tree; Python 3.14.7t) +ran_at: 2026-10-25T08:09:26Z +........................................................................ [ 86%] +........................................................................ [ 89%] +........................................................................ [ 91%] +.....................xxxx............................................... [ 94%] +........................................................................ [ 96%] +........................................................................ [ 98%] +................................. [100%] +=========================== short test summary info ============================ +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the frame set under the Spellbook lock while the write lands later under the FRAME lock inside Conduit.__init__, so every thread can pass before any thread registers. Closing it needs the atomic check-and-set in AethericFrame.register_conduit_spells - STORY-2026-08-02-aether-unified-spell-id-set. STRICT ON PURPOSE: when that story lands this test starts passing, xfail(strict) turns that into a FAILURE, and whoever fixed it is told to delete this marker. Do NOT loosen the assertion below to make this green. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-socket] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-importlib] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[precision-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +2980 passed, 5 xfailed in 33.91s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_fix_tiers_gil1.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_fix_tiers_gil1.txt new file mode 100644 index 000000000..a5d2c350d --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_fix_tiers_gil1.txt @@ -0,0 +1,17 @@ +command: python -X gil=1 -m pytest -p no:cacheprovider -q -rfEx <35 codegen/ACL unit files in tests/unit/melder/aether> tests/component/melder/aether tests/integration/melder/aether (cwd: /tmp/m0s2/d10_b, a /tmp copy of the working tree; Python 3.14.7t) +ran_at: 2026-10-25T08:10:09Z +src/melder/__init__.py:199 + /tmp/m0s2/d10_b/src/melder/__init__.py:199: UserWarning: Python 3.14+ detected, but running in GIL-enabled mode. + melder is optimized for Python built with --disable-gil (PEP 703). + Performance may be degraded. + warnings.warn( + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +=========================== short test summary info ============================ +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the frame set under the Spellbook lock while the write lands later under the FRAME lock inside Conduit.__init__, so every thread can pass before any thread registers. Closing it needs the atomic check-and-set in AethericFrame.register_conduit_spells - STORY-2026-08-02-aether-unified-spell-id-set. STRICT ON PURPOSE: when that story lands this test starts passing, xfail(strict) turns that into a FAILURE, and whoever fixed it is told to delete this marker. Do NOT loosen the assertion below to make this green. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-socket] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-importlib] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[precision-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +2980 passed, 5 xfailed, 1 warning in 32.69s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_red_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_red_gil0.txt new file mode 100644 index 000000000..ce63dcf3d --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_red_gil0.txt @@ -0,0 +1,28 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_pathlib_writes_a_file_only_where_the_import_list_admits_pathlib tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py::test_frame_acl_compiler_admits_pathlib_only_under_the_permissive_import_list (cwd: /tmp/m0s2/d10_b, a /tmp copy of the working tree: the option-B tests, src not yet changed; Python 3.14.7t) +ran_at: 2026-10-25T08:08:03Z + ) + configuration.set_codegen_configuration( + configuration.codegen_configuration.from_profile( + profile_factory(), + precision_profile=( + precision_profile_factory() if precision_profile_factory is not None else None + ), + ) + ) + configuration.finalize() + + compiled_surface = _build_compiler().compile_frame_access_surface( + _build_frame_descriptor(), + configuration, + ) + +> assert ("pathlib" in compiled_surface.allowed_import_module_roots) is pathlib_allowed +E AssertionError: assert ('pathlib' in ('base64', 'collections', 'copy', 'csv', 'dataclasses', 'datetime', ...)) is False +E + where ('base64', 'collections', 'copy', 'csv', 'dataclasses', 'datetime', ...) = .allowed_import_module_roots + +tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py:362: AssertionError +=========================== short test summary info ============================ +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_pathlib_writes_a_file_only_where_the_import_list_admits_pathlib[hybrid-None-False-Import root 'pathlib' is not allowed] +FAILED tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py::test_frame_acl_compiler_admits_pathlib_only_under_the_permissive_import_list[hybrid] +2 failed, 8 passed in 0.67s +exit: 1 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_component_integration_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_component_integration_gil0.txt new file mode 100644 index 000000000..299caed1b --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_component_integration_gil0.txt @@ -0,0 +1,25 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx tests/component tests/integration (cwd: /tmp/m0s2/d10_b, a /tmp copy of the working tree; Python 3.14.7t) +ran_at: 2026-10-25T08:11:02Z +......................................................x................. [ 22%] +................................................................ss..ss.. [ 50%] +ss..ss..ss..ss..ssss..ss..sss..ss....................................... [ 52%] +........................................xxxx............................ [ 65%] +..................................x..................................... [ 74%] +....................................ssss................................ [ 77%] +...................................................xxx.................. [ 79%] +...........................................x............................ [ 83%] +............................................................XX.......... [ 92%] +...............................ss....................................... [ 97%] +=========================== short test summary info ============================ +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the frame set under the Spellbook lock while the write lands later under the FRAME lock inside Conduit.__init__, so every thread can pass before any thread registers. Closing it needs the atomic check-and-set in AethericFrame.register_conduit_spells - STORY-2026-08-02-aether-unified-spell-id-set. STRICT ON PURPOSE: when that story lands this test starts passing, xfail(strict) turns that into a FAILURE, and whoever fixed it is told to delete this marker. Do NOT loosen the assertion below to make this green. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-socket] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-importlib] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[precision-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/conduit/test_conduit_integration_notch_revalidation.py::test_melds_racing_notches_get_a_version_or_the_lost_provider_refusal_and_end_on_the_last_version - OPEN, intermittent with the GIL off: a meld in flight while the lender's notch parks or reactivates the borrower's contracted copy can be built with the raw SpellContract default (AttributeError when it is used) or raise an internal RuntimeError ('many_only manifest references unknown spell_id', 'Cannot build CreationContext ...'), because the notch's fan-out runs after its transaction ends. It predates rule 2 at the same rate. TASK-2026-10-16-order_inflight_borrower_melds_against_notch_fanout. NOT STRICT: the race passes in most runs; whoever closes that task deletes this marker. +XFAIL tests/integration/melder/crystallizer/test_crystallizer_restore_integration.py::test_index_graft_round_trips_into_a_live_host_book - OPEN FEATURE CONFLICT - EPIC-2026-08-02-process-wide-spell-id-uniqueness. graft_runner._bind_selected (graft_runner.py:404) rebinds a LIVE Existence.unique spell into a host book on ANOTHER frame while the SOURCE book still holds it. Under process-wide uniqueness that is two spells wearing one spell_id, which is exactly what the regime forbids. THE TEST IS NOT WRONG - the graft lane is, and the fix is a design call: either the graft RELEASES the source claim first (a move, not a copy), or custody transfer is carved out of the regime explicitly. Marked rather than deleted because this is real shipped behaviour with real coverage. STRICT: whichever way it is ruled, this starts passing and the marker must come off. +XFAIL tests/integration/melder/crystallizer/test_crystallizer_restore_integration.py::test_multi_member_index_graft_parks_the_staged_members - OPEN FEATURE CONFLICT - EPIC-2026-08-02-process-wide-spell-id-uniqueness. graft_runner._bind_selected (graft_runner.py:404) rebinds a LIVE Existence.unique spell into a host book on ANOTHER frame while the SOURCE book still holds it. Under process-wide uniqueness that is two spells wearing one spell_id, which is exactly what the regime forbids. THE TEST IS NOT WRONG - the graft lane is, and the fix is a design call: either the graft RELEASES the source claim first (a move, not a copy), or custody transfer is carved out of the regime explicitly. Marked rather than deleted because this is real shipped behaviour with real coverage. STRICT: whichever way it is ruled, this starts passing and the marker must come off. +XFAIL tests/integration/melder/crystallizer/test_crystallizer_restore_integration.py::test_merge_graft_grows_an_existing_index_and_adopts_selection - OPEN FEATURE CONFLICT - EPIC-2026-08-02-process-wide-spell-id-uniqueness. graft_runner._bind_selected (graft_runner.py:404) rebinds a LIVE Existence.unique spell into a host book on ANOTHER frame while the SOURCE book still holds it. Under process-wide uniqueness that is two spells wearing one spell_id, which is exactly what the regime forbids. THE TEST IS NOT WRONG - the graft lane is, and the fix is a design call: either the graft RELEASES the source claim first (a move, not a copy), or custody transfer is carved out of the regime explicitly. Marked rather than deleted because this is real shipped behaviour with real coverage. STRICT: whichever way it is ruled, this starts passing and the marker must come off. +XFAIL tests/integration/melder/live_sim/test_live_sim_automatic.py::test_live_sim_automatic_bootstrap_melds_application - This should fail as SpellContracts are not eligible in automatic. +4767 passed, 29 skipped, 10 xfailed, 2 xpassed in 125.45s (0:02:05) +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_experimentation_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_experimentation_gil0.txt new file mode 100644 index 000000000..6279d3ecd --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_experimentation_gil0.txt @@ -0,0 +1,6 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx tests/experimentation (cwd: /tmp/m0s2/d10_b, a /tmp copy of the working tree; Python 3.14.7t) +ran_at: 2026-10-25T08:14:13Z +............................sss......................................... [ 28%] +...............................s........................................ [ 85%] +250 passed, 4 skipped in 8.57s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_unit_a_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_unit_a_gil0.txt new file mode 100644 index 000000000..6f38d10ae --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_unit_a_gil0.txt @@ -0,0 +1,17 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx tests/unit/melder/aether tests/unit/melder/utilities tests/unit/melder/build_assets tests/unit/github_workflows tests/unit/llm_support tests/unit/architecture_and_design (cwd: /tmp/m0s2/d10_b, a /tmp copy of the working tree; Python 3.14.7t) +ran_at: 2026-10-25T08:13:24Z +...................x.............................x....x.....x...x....... [ 78%] +.................................................x................x..... [ 79%] +........s....................s.......................................... [ 80%] +........................................................s............... [ 86%] +=========================== short test summary info ============================ +XFAIL tests/unit/melder/utilities/helpers/test_pack_testing.py::TestPackageAdvancedScenarios::test_call_fallback_fills_missing_positional_args +XFAIL tests/unit/melder/utilities/helpers/test_package_core.py::TestPackageThreadSafety::test_normalize_task_rejects_coroutines +XFAIL tests/unit/melder/utilities/helpers/test_package_core.py::TestPackageThreadSafety::test_validate_callable_rejects_coroutines +XFAIL tests/unit/melder/utilities/helpers/test_package_core.py::TestPackageThreadSafety::test_normalize_many_rejects_coroutine_in_iterable +XFAIL tests/unit/melder/utilities/helpers/test_package_core.py::TestPackageThreadSafety::test_is_valid_callable_with_package +XFAIL tests/unit/melder/utilities/helpers/test_package_decorators.py::TestPackDecorators::test_async_decorated_function_rejected +XFAIL tests/unit/melder/utilities/helpers/test_package_wrapping.py::TestPackage::test_package_rejects_coroutine +6323 passed, 3 skipped, 7 xfailed in 30.07s +:0: RuntimeWarning: coroutine 'coro' was never awaited +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_unit_b_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_unit_b_gil0.txt new file mode 100644 index 000000000..698917bea --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_suite_unit_b_gil0.txt @@ -0,0 +1,33 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx tests/unit/melder/spellbook tests/unit/melder/crystallizer tests/unit/melder/mutation_research (cwd: /tmp/m0s2/d10_b, a /tmp copy of the working tree; Python 3.14.7t) +ran_at: 2026-10-25T08:13:55Z + manifests = sorted(assets_root.glob("*/manifest/*.py")) + stamped = {} + for generated in manifests: + match = re.search( + r'^BUILT_FOR_VERSION\s*=\s*"([^"]+)"', + generated.read_text(encoding="utf-8"), + re.MULTILINE, + ) + if match: + stamped[generated.relative_to(assets_root).as_posix()] = match.group(1) + + assert stamped, ( + "no generated build assets carried a BUILT_FOR_VERSION stamp - the glob or " + "the pattern has drifted from the generated layout, so this gate is inert" + ) + unstamped = [ + generated.relative_to(assets_root).as_posix() + for generated in manifests + if generated.relative_to(assets_root).as_posix() not in stamped + ] + assert not unstamped, f"generated manifests carrying no version stamp: {unstamped}" + drifted = {name: v for name, v in stamped.items() if v != __version__} +> assert not drifted, f"assets stamped for the wrong version: {drifted} (package is {__version__})" +E AssertionError: assets stamped for the wrong version: {'_agent_documentation/manifest/agent_documentation_manifest.py': '0.2.8268', '_bind_guard/manifest/bind_guard_manifest.py': '0.2.8268', '_system_documents/manifest/graph_adjacency_manifest.py': '0.2.8268', '_system_documents/manifest/system_documents_index.py': '0.2.8268', '_system_documents/manifest/system_documents_manifest.py': '0.2.8268'} (package is 0.2.8269) +E assert not {'_agent_documentation/manifest/agent_documentation_manifest.py': '0.2.8268', '_bind_guard/manifest/bind_guard_manifes...fest/graph_adjacency_manifest.py': '0.2.8268', '_system_documents/manifest/system_documents_index.py': '0.2.8268', ...} + +tests/unit/melder/test_package_version_metadata.py:84: AssertionError +=========================== short test summary info ============================ +FAILED tests/unit/melder/test_package_version_metadata.py::test_generated_build_assets_are_stamped_for_the_live_version +1 failed, 3664 passed in 16.36s +exit: 1 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_ux_expert_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_ux_expert_gil0.txt new file mode 100644 index 000000000..412446b03 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_ux_expert_gil0.txt @@ -0,0 +1,28 @@ +command: PYTHONPATH=src python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx UX_and_AIX_experiences/pytest_examples/test_expert_examples.py UX_and_AIX_experiences/pytest_examples/test_expert_probes.py (cwd: /tmp/m0s2/d10_b, a /tmp copy of the working tree with option B; the lessons are outside the CI testpaths; Python 3.14.7t) +ran_at: 2026-10-25T08:15:25Z + structural validator refuses. This is why 30's two generated modules + declare ReportBase and ReportDonor rather than Report twice.""" + frame_name = "probe-dupname-frame" + book = _frame(frame_name) + + class Alpha: + def __init__(self) -> None: + self.tag = "a" + + Beta = type("Alpha", (), {"__init__": lambda self: None}) + + # Same order the failing run took: bind, conjure, then the SECOND bind + # is what trips the post-conjure structural validator. + book.bind(spell=Alpha, existence="unique", permissions="create", + binding_name="probe-dup-one") + book.conjure(name="probe-dup-root") + +> with pytest.raises(Exception) as collision: + ^^^^^^^^^^^^^^^^^^^^^^^^ +E Failed: DID NOT RAISE Exception + +UX_and_AIX_experiences/pytest_examples/test_expert_probes.py:1015: Failed +=========================== short test summary info ============================ +FAILED UX_and_AIX_experiences/pytest_examples/test_expert_probes.py::test_probe_two_visible_spells_may_not_share_a_name +1 failed, 84 passed in 8.12s +exit: 1 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_ux_probe_baseline_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_ux_probe_baseline_gil0.txt new file mode 100644 index 000000000..9dcdb94fc --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_b_ux_probe_baseline_gil0.txt @@ -0,0 +1,8 @@ +command: PYTHONPATH=/tmp/m0s2/d10_red/src python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx UX_and_AIX_experiences/pytest_examples/test_expert_probes.py::test_probe_two_visible_spells_may_not_share_a_name (cwd: /tmp/m0s2/d10_b; melder imported from /tmp/m0s2/d10_red/src, the 0.2.8267 tree before any D-10 change; Python 3.14.7t) +ran_at: 2026-10-25T08:15:55Z +melder from /tmp/m0s2/d10_red/src/melder/__init__.py 0.2.8267 +UX_and_AIX_experiences/pytest_examples/test_expert_probes.py:1015: Failed +=========================== short test summary info ============================ +FAILED UX_and_AIX_experiences/pytest_examples/test_expert_probes.py::test_probe_two_visible_spells_may_not_share_a_name +1 failed in 0.15s +exit: 1 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_final_tiers_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_final_tiers_gil0.txt new file mode 100644 index 000000000..ad6bfa9e0 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_final_tiers_gil0.txt @@ -0,0 +1,17 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx <35 codegen/ACL unit files in tests/unit/melder/aether> tests/component/melder/aether tests/integration/melder/aether (cwd: /tmp/m0s2/d10_final, a /tmp copy of the working tree; Python 3.14.7t) +ran_at: 2026-10-25T09:18:03Z +........................................................................ [ 96%] +........................................................................ [ 98%] +........................................... [100%] +=========================== short test summary info ============================ +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_with_other_disposal_methods_disposes_the_new_objects_with_their_own[root-teardown] - OPEN: a `many` key's disposal record keeps the list of the first definition that registered the key in a store, and Creations.register_many appends later objects under it without comparing lists, so a definition cleaned up and bound again under other disposal names (the same spell_id since 0.2.8257) has its objects disposed with the removed definition's methods while that definition's objects are still in the store. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_with_other_disposal_methods_disposes_the_new_objects_with_their_own[lesser-pool-return] - OPEN: a `many` key's disposal record keeps the list of the first definition that registered the key in a store, and Creations.register_many appends later objects under it without comparing lists, so a definition cleaned up and bound again under other disposal names (the same spell_id since 0.2.8257) has its objects disposed with the removed definition's methods while that definition's objects are still in the store. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_of_a_held_slotted_spell_as_many_returns_and_disposes_the_new_object[unique] - OPEN: Creations.register_many appends to whatever the key's live slot holds, so after a `unique` or `unique_per_conduit` definition whose object is still in the store is cleaned up and bound again as `many` (the same spell_id), the next meld builds its object and then raises AttributeError ("'Svc' object has no attribute 'append'"), and that object is neither returned nor recorded. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_of_a_held_slotted_spell_as_many_returns_and_disposes_the_new_object[unique-per-conduit] - OPEN: Creations.register_many appends to whatever the key's live slot holds, so after a `unique` or `unique_per_conduit` definition whose object is still in the store is cleaned up and bound again as `many` (the same spell_id), the next meld builds its object and then raises AttributeError ("'Svc' object has no attribute 'append'"), and that object is neither returned nor recorded. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the frame set under the Spellbook lock while the write lands later under the FRAME lock inside Conduit.__init__, so every thread can pass before any thread registers. Closing it needs the atomic check-and-set in AethericFrame.register_conduit_spells - STORY-2026-08-02-aether-unified-spell-id-set. STRICT ON PURPOSE: when that story lands this test starts passing, xfail(strict) turns that into a FAILURE, and whoever fixed it is told to delete this marker. Do NOT loosen the assertion below to make this green. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-socket] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-importlib] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[precision-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +2986 passed, 9 xfailed in 41.17s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_final_version_metadata_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_final_version_metadata_gil0.txt new file mode 100644 index 000000000..3c2150f04 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_final_version_metadata_gil0.txt @@ -0,0 +1,5 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx tests/unit/melder/test_package_version_metadata.py (cwd: /tmp/m0s2/d10_final, a /tmp copy of the working tree after the 0.2.8270 rebuild; Python 3.14.7t) +ran_at: 2026-10-25T09:19:03Z +.... [100%] +4 passed in 0.68s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_component_integration_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_component_integration_gil0.txt new file mode 100644 index 000000000..58363f1b0 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_component_integration_gil0.txt @@ -0,0 +1,24 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx tests/component tests/integration (cwd: /tmp/m0s2/d10_fix, a /tmp copy of the working tree with the D-10 fix; Python 3.14.7t) +ran_at: 2026-10-25T02:20:24Z +.................x...................................................... [ 22%] +.........................sssssssssssssssssssssssssssssssssssssssssss.... [ 51%] +...xxxx................................................................. [ 66%] +.....................................................................X.. [ 73%] +.....................................................................sss [ 76%] +s....................................................................... [ 78%] +............xxx......................................................... [ 80%] +....x................................................................... [ 84%] +.....................XX................................................. [ 93%] +................................................................ss...... [ 96%] +=========================== short test summary info ============================ +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the fra +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-socket] - OPEN: the import gate reads import statements only, and the compiler denies __import__ o +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-importlib] - OPEN: the import gate reads import statements only, and the compiler denies __import_ +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[precision-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __i +XFAIL tests/integration/melder/crystallizer/test_crystallizer_restore_integration.py::test_index_graft_round_trips_into_a_live_host_book - OPEN FEATURE CONFLICT - EPIC-2026-08-02-process-wide-spell-id-uniqueness. graft_runner._bind_selected +XFAIL tests/integration/melder/crystallizer/test_crystallizer_restore_integration.py::test_multi_member_index_graft_parks_the_staged_members - OPEN FEATURE CONFLICT - EPIC-2026-08-02-process-wide-spell-id-uniqueness. graft_runner._bind_sele +XFAIL tests/integration/melder/crystallizer/test_crystallizer_restore_integration.py::test_merge_graft_grows_an_existing_index_and_adopts_selection - OPEN FEATURE CONFLICT - EPIC-2026-08-02-process-wide-spell-id-uniqueness. graft_runner._bi +XFAIL tests/integration/melder/live_sim/test_live_sim_automatic.py::test_live_sim_automatic_bootstrap_melds_application - This should fail as SpellContracts are not eligible in automatic. +4708 passed, 49 skipped, 9 xfailed, 3 xpassed in 133.78s (0:02:13) +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_experimentation_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_experimentation_gil0.txt new file mode 100644 index 000000000..2d0f2fab0 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_experimentation_gil0.txt @@ -0,0 +1,4 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfE tests/experimentation (cwd: /tmp/m0s2/d10_fix, the D-10 fix; Python 3.14.7t) +ran_at: 2026-10-25T02:26:11Z +250 passed, 4 skipped in 9.63s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_unit_a_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_unit_a_gil0.txt new file mode 100644 index 000000000..bf070e393 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_unit_a_gil0.txt @@ -0,0 +1,5 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfE tests/unit/melder/aether tests/unit/melder/utilities tests/unit/melder/build_assets tests/unit/github_workflows tests/unit/llm_support tests/unit/architecture_and_design (cwd: /tmp/m0s2/d10_fix, the D-10 fix; copy holds src, tests, pyproject.toml, llm_support, .github, release_docs, architecture_and_design, README.md, .readthedocs.yaml, codecov.yml, benchmarks, context_compass/system_docs - not docs/; Python 3.14.7t) +ran_at: 2026-10-25T02:25:09Z +6247 passed, 3 skipped, 7 xfailed in 32.08s +:0: RuntimeWarning: coroutine 'coro' was never awaited +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_unit_b_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_unit_b_gil0.txt new file mode 100644 index 000000000..15146840d --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_suite_unit_b_gil0.txt @@ -0,0 +1,4 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfE tests/unit/melder/spellbook tests/unit/melder/crystallizer tests/unit/melder/mutation_research (cwd: /tmp/m0s2/d10_fix, the D-10 fix; Python 3.14.7t) +ran_at: 2026-10-25T02:25:43Z +3665 passed in 17.66s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_tiers_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_tiers_gil0.txt new file mode 100644 index 000000000..a457bfbc7 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_tiers_gil0.txt @@ -0,0 +1,15 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx <35 codegen/ACL unit files in tests/unit/melder/aether> tests/component/melder/aether tests/integration/melder/aether (cwd: /tmp/m0s2/d10_fix, a /tmp copy of the working tree with the D-10 fix; Python 3.14.7t) +ran_at: 2026-10-25T02:18:48Z +........................................................................ [ 90%] +...................................................xxxx................. [ 92%] +........................................................................ [ 95%] +........................................................................ [ 97%] +............................................................... [100%] +=========================== short test summary info ============================ +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the frame set under the Spe +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-socket] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-importlib] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[precision-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when im +2938 passed, 5 xfailed in 33.95s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_tiers_gil1.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_tiers_gil1.txt new file mode 100644 index 000000000..592bf0bc2 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_fix_tiers_gil1.txt @@ -0,0 +1,15 @@ +command: python -X gil=1 -m pytest -p no:cacheprovider -q -rfEx <35 codegen/ACL unit files in tests/unit/melder/aether> tests/component/melder/aether tests/integration/melder/aether (cwd: /tmp/m0s2/d10_fix, a /tmp copy of the working tree with the D-10 fix; Python 3.14.7t) +ran_at: 2026-10-25T02:19:23Z + melder is optimized for Python built with --disable-gil (PEP 703). + Performance may be degraded. + warnings.warn( + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +=========================== short test summary info ============================ +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the frame set under the Spe +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-socket] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-importlib] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[precision-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when im +2938 passed, 5 xfailed, 1 warning in 33.95s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_rebuild_0_2_8270.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_rebuild_0_2_8270.txt new file mode 100644 index 000000000..991968dc8 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_rebuild_0_2_8270.txt @@ -0,0 +1,31 @@ +D-10 rebuild at 0.2.8270 (melder_0), from the repository root on the device VM, Python 3.14.7 free-threaded, +PYTHONDONTWRITEBYTECODE=1 GIT_OPTIONAL_LOCKS=0. + +2026-10-25T08:46Z python src/melder/_build_assets/_build_asset_runner.py + WROTE _agent_documentation agent_documentation_manifest.py (469 entries, v0.2.8270) + WROTE _bind_guard bind_guard_manifest.py (629 entries, v0.2.8270) + PermissionError: [Errno 1] Operation not permitted: '.../src/melder/_build_assets/_system_documents/payloads/src_architecture_payload.py' + (write_payloads clears the stale payloads with unlink; the connected folder refused deletes) exit=1 + -> deletion requested once for the connected folder and granted by the owner for this session. +2026-10-25T09:02:48Z python src/melder/_build_assets/_build_asset_runner.py + WROTE _agent_documentation agent_documentation_manifest.py (469 entries, v0.2.8270) + WROTE _bind_guard bind_guard_manifest.py (629 entries, v0.2.8270) + WROTE _system_documents system_documents_manifest.py (4 entries, v0.2.8270) + exit=0 +2026-10-25T09:05:02Z python src/melder/_build_assets/_build_asset_runner.py --check + OK _agent_documentation current (v0.2.8270, schema 2.0.0, key match) + OK _bind_guard current (v0.2.8270, schema 2.0.0, key match) + OK _system_documents current (v0.2.8270, schema 2.0.0, key match) + exit=0 +2026-10-25T09:06:07Z python llm_support/_builder.py --include-untracked + WROTE src 585 files (source fingerprint moved) + WROTE tests 1154 files (source fingerprint moved) + WROTE other 418 files (source fingerprint moved) + WROTE manifest.json + exit=0 +2026-10-25T09:06:44Z python llm_support/_builder.py --check --include-untracked + OK src fingerprint and output proofs match + OK tests fingerprint and output proofs match + OK other fingerprint and output proofs match + exit=0 +No .git/index.lock left behind. diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_red_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_red_gil0.txt new file mode 100644 index 000000000..d5af93d10 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_red_gil0.txt @@ -0,0 +1,43 @@ +command: python -X gil=0 -m pytest -p no:cacheprovider -q -rfEx (cwd: /tmp/m0s2/d10_red, a /tmp copy of the working tree with D-10's tests and no src change; Python 3.14.7t) +ran_at: 2026-10-25T02:15:48Z +precision_profile_factory = > +open_denied = True +> assert ("open" in compiled_surface.denied_builtin_names) is open_denied +E AssertionError: assert ('open' in ('breakpoint', 'compile', 'delattr', 'dir', 'eval', 'exec', ...)) is True +E + where ('breakpoint', 'compile', 'delattr', 'dir', 'eval', 'exec', ...) = .denied_builtin_names +tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py:310: AssertionError +_ test_unit_codegen_system_default_posture_without_projection_denies_what_safe_denies _ +> assert "open" in configuration.denied_builtin_names +E AssertionError: assert 'open' in ('__import__', 'breakpoint', 'compile', 'dir', 'eval', 'exec', ...) +E + where ('__import__', 'breakpoint', 'compile', 'dir', 'eval', 'exec', ...) = .denied_builtin_names +tests/unit/melder/aether/test_codegen_system_unit_matrix.py:374: AssertionError +_ test_unit_codegen_builtins_strategy_leaves_open_out_of_the_safe_tuple_runtime_builtins _ +> assert "open" not in entries["__builtins__"] +E assert 'open' not in {'__name__': 'builtins', '__doc__': "Built-in functions, types, exceptions, and other objects.\n\nThis module provides...lt-in of that name is also needed.", '__package__': '', '__loader__': , ...} +tests/unit/melder/aether/test_codegen_namespace_runtime_unit_matrix.py:536: AssertionError +=========================== short test summary info ============================ +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_open_writes_a_file_only_under_permissive_and_full_access[safe-None-False] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_open_writes_a_file_only_under_permissive_and_full_access[hybrid-None-False] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_open_writes_a_file_only_under_permissive_and_full_access[hybrid-precision-False] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_open_reads_a_file_only_under_permissive_and_full_access[safe-None-False] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_open_reads_a_file_only_under_permissive_and_full_access[hybrid-None-False] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_open_reads_a_file_only_under_permissive_and_full_access[hybrid-precision-False] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_a_bare_reference_to_open_is_refused_where_open_is_denied[safe-None] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_a_bare_reference_to_open_is_refused_where_open_is_denied[hybrid-None] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_a_bare_reference_to_open_is_refused_where_open_is_denied[hybrid-precision] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_a_request_naming_a_frame_without_a_projection_cannot_open_files[safe] +FAILED tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_a_request_naming_a_frame_without_a_projection_cannot_open_files[full_access] +FAILED tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py::test_frame_acl_compiler_denies_open_exactly_where_the_safe_tuple_applies[safe] +FAILED tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py::test_frame_acl_compiler_denies_open_exactly_where_the_safe_tuple_applies[default] +FAILED tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py::test_frame_acl_compiler_denies_open_exactly_where_the_safe_tuple_applies[hybrid] +FAILED tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py::test_frame_acl_compiler_denies_open_exactly_where_the_safe_tuple_applies[hybrid+precision] +FAILED tests/unit/melder/aether/test_frame_acl_codegen_validation_profiles.py::test_frame_acl_compiler_denies_open_exactly_where_the_safe_tuple_applies[permissive+precision] +FAILED tests/unit/melder/aether/test_codegen_system_unit_matrix.py::test_unit_codegen_system_default_posture_without_projection_denies_what_safe_denies +FAILED tests/unit/melder/aether/test_codegen_namespace_runtime_unit_matrix.py::test_unit_codegen_builtins_strategy_leaves_open_out_of_the_safe_tuple_runtime_builtins +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_safe_profile_refuses_writing_files - OPEN: no codegen profile denies the open builtin - the runtime __builtins__ is the full builtins dict minus the profile's deny list, and no validator strategy inspects open or non-dunder method calls - so agent code in a safe room writes any file the process can write, although the safe profile documents that it denies writes. Core-protection review, Note 10. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-socket] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[None-importlib] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/integration/melder/aether/test_codegen_core_boundary_integration.py::test_hybrid_refuses_dynamic_imports_of_its_denied_roots[precision-subprocess] - OPEN: the import gate reads import statements only, and the compiler denies __import__ only when imports are off, so __import__ loads the roots the hybrid profile (and the precision overlay) deny. Core-protection review, Note 11. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +18 failed, 32 passed, 5 xfailed in 0.96s +exit: 1 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_windows_owner_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_windows_owner_gil0.txt new file mode 100644 index 000000000..3e8dc3466 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_windows_owner_gil0.txt @@ -0,0 +1,10 @@ +# The owner's run on Windows, pasted in chat at 2026-10-25T09:35Z and transcribed verbatim (trailing spaces trimmed): +# .venv_new, CPython 3.14 free-threaded (uv), melder editable from the working tree at 0.2.8270. +(.venv_new) PS C:\Users\Mark\PycharmProjects\melder_private> cd C:\Users\Mark\PycharmProjects\melder_private +(.venv_new) PS C:\Users\Mark\PycharmProjects\melder_private> $t = "tests\unit\melder\aether\test_frame_acl_codegen_validation_profiles.py", +>> "tests\unit\melder\aether\test_codegen_system_unit_matrix.py", +>> "tests\unit\melder\aether\test_codegen_namespace_runtime_unit_matrix.py", +>> "tests\integration\melder\aether\test_codegen_core_boundary_integration.py" +(.venv_new) PS C:\Users\Mark\PycharmProjects\melder_private> .\.venv_new\Scripts\python.exe -X gil=0 -m pytest -q -p no:cacheprovider $t +.............................................................................................................................................................................................xxxx.............................. [100%] +219 passed, 4 xfailed in 1.19s diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_windows_owner_gil1.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_windows_owner_gil1.txt new file mode 100644 index 000000000..aeb87aa72 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d10_windows_owner_gil1.txt @@ -0,0 +1,14 @@ +# The owner's run on Windows, pasted in chat at 2026-10-25T09:35Z and transcribed verbatim (trailing spaces trimmed): +# .venv_new, CPython 3.14 free-threaded (uv), melder editable from the working tree at 0.2.8270; $t as in +# d10_windows_owner_gil0.txt (the four D-10 test files). +(.venv_new) PS C:\Users\Mark\PycharmProjects\melder_private> .\.venv_new\Scripts\python.exe -X gil=1 -m pytest -q -p no:cacheprovider $t +.............................................................................................................................................................................................xxxx.............................. [100%] +========================================================================================================================================================================== warnings summary =========================================================================================================================================================================== +src\melder\__init__.py:199 + C:\Users\Mark\PycharmProjects\melder_private\src\melder\__init__.py:199: UserWarning: Python 3.14+ detected, but running in GIL-enabled mode. + melder is optimized for Python built with --disable-gil (PEP 703). + Performance may be degraded. + warnings.warn( + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +219 passed, 4 xfailed, 1 warning in 1.04s diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_import_cost_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_import_cost_gil0.txt new file mode 100644 index 000000000..8e98e59fe --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_import_cost_gil0.txt @@ -0,0 +1,10 @@ +measure: per-call cost of the guarded runtime __import__ for an ALLOWED root (json) vs the real __import__. +method: build a hybrid room's runtime builtins via CodegenBuiltinsStrategy, time N calls of the guarded + __import__('json') against builtins.__import__('json') (both resolve the cached module). +ran_at: 2026-10-25T10:18:36Z Python 3.14.7t, GIL off +N : 2000000 +real ns/call : 83.3 +guarded ns/call: 174.0 +delta ns/call : 90.7 (the guard's split + two membership tests) +denied-root refused: Import root 'subprocess' is not allowed in this codegen mode. +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_tiers_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_tiers_gil0.txt new file mode 100644 index 000000000..4a52ccb79 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_tiers_gil0.txt @@ -0,0 +1,9 @@ +command: python -X gil=0 -m pytest -q -rfEx <35 codegen/ACL unit files in tests/unit/melder/aether> tests/component/melder/aether tests/integration/melder/aether (cwd: /tmp copy of the 0.2.8270 tree + D-11; Python 3.14.7t) +ran_at: 2026-10-25T10:16:18Z +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_with_other_disposal_methods_disposes_the_new_objects_with_their_own[root-teardown] - OPEN: a `many` key's disposal record keeps the list of the first definition that registered the key in a store, and Creations.register_many appends later objects under it without comparing lists, so a definition cleaned up and bound again under other disposal names (the same spell_id since 0.2.8257) has its objects disposed with the removed definition's methods while that definition's objects are still in the store. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_with_other_disposal_methods_disposes_the_new_objects_with_their_own[lesser-pool-return] - OPEN: a `many` key's disposal record keeps the list of the first definition that registered the key in a store, and Creations.register_many appends later objects under it without comparing lists, so a definition cleaned up and bound again under other disposal names (the same spell_id since 0.2.8257) has its objects disposed with the removed definition's methods while that definition's objects are still in the store. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_of_a_held_slotted_spell_as_many_returns_and_disposes_the_new_object[unique] - OPEN: Creations.register_many appends to whatever the key's live slot holds, so after a `unique` or `unique_per_conduit` definition whose object is still in the store is cleaned up and bound again as `many` (the same spell_id), the next meld builds its object and then raises AttributeError ("'Svc' object has no attribute 'append'"), and that object is neither returned nor recorded. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_of_a_held_slotted_spell_as_many_returns_and_disposes_the_new_object[unique-per-conduit] - OPEN: Creations.register_many appends to whatever the key's live slot holds, so after a `unique` or `unique_per_conduit` definition whose object is still in the store is cleaned up and bound again as `many` (the same spell_id), the next meld builds its object and then raises AttributeError ("'Svc' object has no attribute 'append'"), and that object is neither returned nor recorded. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the frame set under the Spellbook lock while the write lands later under the FRAME lock inside Conduit.__init__, so every thread can pass before any thread registers. Closing it needs the atomic check-and-set in AethericFrame.register_conduit_spells - STORY-2026-08-02-aether-unified-spell-id-set. STRICT ON PURPOSE: when that story lands this test starts passing, xfail(strict) turns that into a FAILURE, and whoever fixed it is told to delete this marker. Do NOT loosen the assertion below to make this green. +3014 passed, 5 xfailed in 40.53s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_tiers_gil1.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_tiers_gil1.txt new file mode 100644 index 000000000..a85118254 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d11_tiers_gil1.txt @@ -0,0 +1,9 @@ +command: python -X gil=1 -m pytest -q -rfEx <35 codegen/ACL unit files in tests/unit/melder/aether> tests/component/melder/aether tests/integration/melder/aether (cwd: /tmp copy of the 0.2.8270 tree + D-11; Python 3.14.7t) +ran_at: 2026-10-25T10:17:00Z +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_with_other_disposal_methods_disposes_the_new_objects_with_their_own[root-teardown] - OPEN: a `many` key's disposal record keeps the list of the first definition that registered the key in a store, and Creations.register_many appends later objects under it without comparing lists, so a definition cleaned up and bound again under other disposal names (the same spell_id since 0.2.8257) has its objects disposed with the removed definition's methods while that definition's objects are still in the store. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_with_other_disposal_methods_disposes_the_new_objects_with_their_own[lesser-pool-return] - OPEN: a `many` key's disposal record keeps the list of the first definition that registered the key in a store, and Creations.register_many appends later objects under it without comparing lists, so a definition cleaned up and bound again under other disposal names (the same spell_id since 0.2.8257) has its objects disposed with the removed definition's methods while that definition's objects are still in the store. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_of_a_held_slotted_spell_as_many_returns_and_disposes_the_new_object[unique] - OPEN: Creations.register_many appends to whatever the key's live slot holds, so after a `unique` or `unique_per_conduit` definition whose object is still in the store is cleaned up and bound again as `many` (the same spell_id), the next meld builds its object and then raises AttributeError ("'Svc' object has no attribute 'append'"), and that object is neither returned nor recorded. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/conduit/test_conduit_component_rebind_while_old_objects_are_alive.py::test_rebind_of_a_held_slotted_spell_as_many_returns_and_disposes_the_new_object[unique-per-conduit] - OPEN: Creations.register_many appends to whatever the key's live slot holds, so after a `unique` or `unique_per_conduit` definition whose object is still in the store is cleaned up and bound again as `many` (the same spell_id), the next meld builds its object and then raises AttributeError ("'Svc' object has no attribute 'append'"), and that object is neither returned nor recorded. STORY-2026-10-18-revalidate_on_binding_change (S3, parked by the owner) closes it. STRICT ON PURPOSE: when the gap is closed this test passes, strict turns that into a failure, and whoever closed it deletes this marker. +XFAIL tests/component/melder/aether/test_aether_component_process_wide_spell_id_regime.py::test_component_concurrent_conjures_across_frames_admit_at_most_one - OPEN: the conjure sweep is a PREFLIGHT, not a mutual exclusion. It reads the frame set under the Spellbook lock while the write lands later under the FRAME lock inside Conduit.__init__, so every thread can pass before any thread registers. Closing it needs the atomic check-and-set in AethericFrame.register_conduit_spells - STORY-2026-08-02-aether-unified-spell-id-set. STRICT ON PURPOSE: when that story lands this test starts passing, xfail(strict) turns that into a FAILURE, and whoever fixed it is told to delete this marker. Do NOT loosen the assertion below to make this green. +3014 passed, 5 xfailed, 1 warning in 41.57s +exit: 0 diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_name_gate_cost_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_name_gate_cost_gil0.txt new file mode 100644 index 000000000..fc02c1cd4 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_name_gate_cost_gil0.txt @@ -0,0 +1,2 @@ +packages_distributions(): 10.30 ms per call (9 dists) +stdlib membership: 0.028 us diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_probe_refusals_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_probe_refusals_gil0.txt new file mode 100644 index 000000000..6ba3bd45e --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_probe_refusals_gil0.txt @@ -0,0 +1,17 @@ +[safe] melder.aether.spellbook.bind.bind: materialized=False | unchanged=True | refusal=Module name 'melder.aether.spellbook.bind.bind' is already loaded; materialize_codegen does not replace a live module. +[safe] melder.injected_probe: materialized=False | unchanged=True | refusal=Module name 'melder.injected_probe' is under the protected core root 'melder'. +[safe] csv: materialized=False | unchanged=True | refusal=Module name 'csv' is already loaded; materialize_codegen does not replace a live module. +[safe] json: materialized=False | unchanged=True | refusal=Module name 'json' is already loaded; materialize_codegen does not replace a live module. +[safe] pytest: materialized=False | unchanged=True | refusal=Module name 'pytest' is already loaded; materialize_codegen does not replace a live module. +[hybrid] melder.aether.spellbook.bind.bind: materialized=False | unchanged=True | refusal=Module name 'melder.aether.spellbook.bind.bind' is already loaded; materialize_codegen does not replace a live module. +[hybrid] melder.injected_probe: materialized=False | unchanged=True | refusal=Module name 'melder.injected_probe' is under the protected core root 'melder'. +[hybrid] csv: materialized=False | unchanged=True | refusal=Module name 'csv' is already loaded; materialize_codegen does not replace a live module. +[hybrid] json: materialized=False | unchanged=True | refusal=Module name 'json' is already loaded; materialize_codegen does not replace a live module. +[hybrid] pytest: materialized=False | unchanged=True | refusal=Module name 'pytest' is already loaded; materialize_codegen does not replace a live module. +[full_access] melder.aether.spellbook.bind.bind: materialized=False | unchanged=True | refusal=Module name 'melder.aether.spellbook.bind.bind' is already loaded; materialize_codegen does not replace a live module. +[full_access] melder.injected_probe: materialized=False | unchanged=True | refusal=Module name 'melder.injected_probe' is under the protected core root 'melder'. +[full_access] csv: materialized=False | unchanged=True | refusal=Module name 'csv' is already loaded; materialize_codegen does not replace a live module. +[full_access] json: materialized=False | unchanged=True | refusal=Module name 'json' is already loaded; materialize_codegen does not replace a live module. +[full_access] pytest: materialized=False | unchanged=True | refusal=Module name 'pytest' is already loaded; materialize_codegen does not replace a live module. +[hybrid] failed materialize raised: probe +residue after the failed materialize: [] diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_probe_refusals_gil1.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_probe_refusals_gil1.txt new file mode 100644 index 000000000..6ba3bd45e --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_probe_refusals_gil1.txt @@ -0,0 +1,17 @@ +[safe] melder.aether.spellbook.bind.bind: materialized=False | unchanged=True | refusal=Module name 'melder.aether.spellbook.bind.bind' is already loaded; materialize_codegen does not replace a live module. +[safe] melder.injected_probe: materialized=False | unchanged=True | refusal=Module name 'melder.injected_probe' is under the protected core root 'melder'. +[safe] csv: materialized=False | unchanged=True | refusal=Module name 'csv' is already loaded; materialize_codegen does not replace a live module. +[safe] json: materialized=False | unchanged=True | refusal=Module name 'json' is already loaded; materialize_codegen does not replace a live module. +[safe] pytest: materialized=False | unchanged=True | refusal=Module name 'pytest' is already loaded; materialize_codegen does not replace a live module. +[hybrid] melder.aether.spellbook.bind.bind: materialized=False | unchanged=True | refusal=Module name 'melder.aether.spellbook.bind.bind' is already loaded; materialize_codegen does not replace a live module. +[hybrid] melder.injected_probe: materialized=False | unchanged=True | refusal=Module name 'melder.injected_probe' is under the protected core root 'melder'. +[hybrid] csv: materialized=False | unchanged=True | refusal=Module name 'csv' is already loaded; materialize_codegen does not replace a live module. +[hybrid] json: materialized=False | unchanged=True | refusal=Module name 'json' is already loaded; materialize_codegen does not replace a live module. +[hybrid] pytest: materialized=False | unchanged=True | refusal=Module name 'pytest' is already loaded; materialize_codegen does not replace a live module. +[full_access] melder.aether.spellbook.bind.bind: materialized=False | unchanged=True | refusal=Module name 'melder.aether.spellbook.bind.bind' is already loaded; materialize_codegen does not replace a live module. +[full_access] melder.injected_probe: materialized=False | unchanged=True | refusal=Module name 'melder.injected_probe' is under the protected core root 'melder'. +[full_access] csv: materialized=False | unchanged=True | refusal=Module name 'csv' is already loaded; materialize_codegen does not replace a live module. +[full_access] json: materialized=False | unchanged=True | refusal=Module name 'json' is already loaded; materialize_codegen does not replace a live module. +[full_access] pytest: materialized=False | unchanged=True | refusal=Module name 'pytest' is already loaded; materialize_codegen does not replace a live module. +[hybrid] failed materialize raised: probe +residue after the failed materialize: [] diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_red_gil0.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_red_gil0.txt new file mode 100644 index 000000000..339215fc7 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_red_gil0.txt @@ -0,0 +1,32 @@ +________ test_a_failed_materialize_leaves_no_module_and_no_parent_shell ________ + def test_a_failed_materialize_leaves_no_module_and_no_parent_shell() -> None: +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[melder.aether.spellbook.bind.bind-safe] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[melder.aether.spellbook.bind.bind-hybrid] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[melder.aether.spellbook.bind.bind-full_access] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[csv-safe] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[csv-hybrid] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[csv-full_access] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[json-safe] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[json-hybrid] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[json-full_access] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[pytest-safe] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[pytest-hybrid] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materializing_over_a_loaded_module_is_refused_and_leaves_it_in_place[pytest-full_access] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_a_new_name_under_the_protected_core_root_is_refused[safe] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_a_new_name_under_the_protected_core_root_is_refused[hybrid] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_a_new_name_under_the_protected_core_root_is_refused[full_access] +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_an_unimported_standard_library_name_is_refused +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_an_unimported_installed_import_name_is_refused +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_a_failed_materialize_leaves_no_module_and_no_parent_shell +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_a_declared_namespace_rule_narrows_materialize_to_its_roots +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_a_denied_generation_root_is_refused +FAILED tests/integration/melder/aether/test_codegen_materialize_boundary_integration.py::test_materialized_code_runs_with_the_rooms_filtered_builtins +FAILED tests/unit/melder/aether/test_codegen_materialize_verb.py::test_a_loaded_module_name_is_refused_before_any_publication +FAILED tests/unit/melder/aether/test_codegen_materialize_verb.py::test_materialized_source_runs_with_the_engines_room_builtins +FAILED tests/unit/melder/aether/test_frame_acl_codegen_builder.py::test_frame_acl_codegen_builder_merges_materialize_module_roots +FAILED tests/unit/melder/aether/test_frame_acl_codegen_builder.py::test_frame_acl_validator_rejects_malformed_materialize_module_rules +FAILED tests/unit/melder/aether/test_frame_acl_compiler_contracts.py::test_frame_acl_compiler_generation_roots_matrix +FAILED tests/unit/melder/aether/test_frame_acl_compiled_access_surface.py::test_compiled_access_surface_carries_generation_roots +FAILED tests/unit/melder/crystallizer/test_synthetic_module.py::test_cleanup_restores_the_real_module_a_publication_displaced +FAILED tests/unit/melder/crystallizer/test_synthetic_module.py::test_detach_restores_the_parent_attribute_a_publication_displaced +29 failed, 117 passed in 1.11s diff --git a/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_tiers.txt b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_tiers.txt new file mode 100644 index 000000000..c0815a012 --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/runs/d20_tiers.txt @@ -0,0 +1,24 @@ +D-20 tiers on a /tmp copy of the device tree (src + tests + system_docs), 2026-10-25, 3.14.7t. +RED (tests in, source unchanged), GIL off: 29 failed, 117 passed (d20_red_gil0.txt). +GREEN, targeted (6 files): 146 passed GIL off; 146 passed + GIL warning GIL on. +GIL off: + tests/unit/melder 9249 passed, 3 skipped, 7 xfailed (2 build_assets failures in the copy without + context_compass/system_docs; 60 passed once it was copied in) + tests/component/melder 2478 passed, 43 skipped, 1 xfailed + tests/integration/melder/aether 917 passed + tests/integration/melder/crystallizer 282 passed, 3 xfailed + tests/integration/melder/mutation_research 67 passed + tests/integration/melder/conduit 355 passed, 4 skipped, 1 xpassed + tests/integration/melder/spellbook 678 passed, 2 failed (test_spellbook_integration_parked_before_conjure + x2: melder_3's store_key lane, M3-20; not D-20), 2 skipped, 2 xpassed + tests/integration/melder/live_sim 1 passed, 1 xfailed +GIL on: + tests/unit/melder 9251 passed, 3 skipped, 7 xfailed, 1 warning + tests/component/melder 2498 passed, 23 skipped, 1 xfailed, 1 warning + tests/integration/melder/aether 917 passed, 1 warning + integration crystallizer + mutation_research + conduit 704 passed, 4 skipped, 3 xfailed, 1 xpassed, 1 warning +Not run: tests/integration/melder/multithreading; Windows tiers; hosted CI. +Expert examples (pytest_examples/test_expert_examples.py): 34 passed, 4 failed (02, 09, 24, 27) at + list_cached_checkpoint_ids; the same four fail with D-20's SyntheticModule change reverted and with the builtins + merge off, and 02, 09, 24 never materialize - not D-20. Every materializing example (12, 26, 29, 30, 32, 33, 36) + passes; 27 materializes both its modules before its checkpoint assertion. diff --git a/context_compass/artifacts/codegen_room_policy_20261025/scripts/d10_b_copy.sh b/context_compass/artifacts/codegen_room_policy_20261025/scripts/d10_b_copy.sh new file mode 100644 index 000000000..db72415bb --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/scripts/d10_b_copy.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Copy the checkout to a fresh /tmp tree for D-10's option-B runs (melder_0, 2026-10-25). +# usage: d10_b_copy.sh (copies src, tests, pyproject.toml and the files the whole suite reads; not docs/) +set -eu +dest="${1:?dir}"; repo="$HOME/mnt/melder_private" +mkdir -p "$dest" /tmp/m0s2/tmp +rsync -a --delete --exclude __pycache__ --exclude __melder_cache__ --exclude "*.pyc" --exclude .pytest_cache \ + "$repo/src" "$repo/tests" "$repo/pyproject.toml" "$repo/README.md" "$repo/.readthedocs.yaml" "$repo/codecov.yml" \ + "$repo/benchmarks" "$repo/llm_support" "$repo/.github" "$repo/release_docs" "$repo/architecture_and_design" \ + "$repo/UX_and_AIX_experiences" "$dest/" +mkdir -p "$dest/context_compass" +rsync -a --delete "$repo/context_compass/system_docs" "$dest/context_compass/" +echo "copied to $dest: $(du -sh "$dest" | cut -f1)" diff --git a/context_compass/artifacts/codegen_room_policy_20261025/scripts/d10_b_suite.sh b/context_compass/artifacts/codegen_room_policy_20261025/scripts/d10_b_suite.sh new file mode 100644 index 000000000..8cca44ede --- /dev/null +++ b/context_compass/artifacts/codegen_room_policy_20261025/scripts/d10_b_suite.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# D-10 option B: one chunk of the whole suite on the /tmp copy, the GIL off (melder_0, 2026-10-25). +# usage: d10_b_suite.sh