diff --git a/.envrc b/.envrc index 118bafc8..3a61d11c 100644 --- a/.envrc +++ b/.envrc @@ -19,11 +19,14 @@ watch_file mise.lock PROJECT_ROOT="$(find_up pyproject.toml)" PROJECT_ROOT="${PROJECT_ROOT%/*}" # A nested standalone checkout never inherits an enclosing repository's tools. -# Attached members retain their declared workspace runtime boundary. -runtime_parent="$(cd "${PROJECT_ROOT}/./.." && pwd -P)" +# A member checked out as a submodule shares its Git superproject runtime, the +# same root its Makefile resolves (flext-x8gn6). +RUNTIME_ROOT="$(git -C "${PROJECT_ROOT}" rev-parse --show-superproject-working-tree)" +RUNTIME_ROOT="${RUNTIME_ROOT:-${PROJECT_ROOT}}" +runtime_parent="$(cd "${RUNTIME_ROOT}/.." && pwd -P)" export GIT_CEILING_DIRECTORIES="${runtime_parent}" export MISE_CEILING_PATHS="${runtime_parent}" -VENV_DIR="${PROJECT_ROOT}/.venv" +VENV_DIR="${RUNTIME_ROOT}/.venv" PROJECT_STATE_ROOT="${PROJECT_ROOT%/*}/.flext-runtime/${PROJECT_ROOT##*/}" # Scratch never lives inside a versioned tree: the home scratch root mirrors # the absolute checkout path so a sandbox is never a tracked scope of any @@ -126,8 +129,8 @@ if env -i \ 'MISE_GITHUB_OAUTH_CLIENT_ID=' \ 'MISE_GITHUB_OAUTH_EXPORT_ENV=' \ 'MISE_GITHUB_OAUTH_OPEN_BROWSER=false' \ -'MISE_LOCKFILE=false' \ -'MISE_LOCKED=false' \ +'MISE_LOCKFILE=true' \ +'MISE_LOCKED=true' \ 'MISE_LOCKFILE_PLATFORMS=linux-x64,linux-arm64,macos-x64,macos-arm64,windows-x64' \ "HOME=${scratch}/home" \ "USERPROFILE=${scratch}/home" \ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1dbf069d..1b64f846 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,7 +145,7 @@ jobs: run: | CI=Y make gen git status --short - test -z "$(git status --porcelain --untracked-files=all)" + test -z "$(git status --porcelain --untracked-files=all --ignore-submodules=none)" # Setup installs frozen from the committed uv.lock (`uv sync --locked`) # and never rewrites it; the deps audit proves that locked graph. @@ -168,7 +168,7 @@ jobs: - name: Candidate cleanliness (blocking) run: | git status --short - test -z "$(git status --porcelain --untracked-files=all)" + test -z "$(git status --porcelain --untracked-files=all --ignore-submodules=none)" # End SECTION: ci job # === SECTION: release-plan job (managed) === diff --git a/.gitignore b/.gitignore index 02001b4c..2b8979b3 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,9 @@ */.hooks.json.agents-governance.json .claude/*.agents-governance.json .gemini/*.agents-governance.json +.claude/settings.json .claude/settings.local.json +.gemini/settings.json # Operator-private local config overrides /config/codegen-overrides.local.yaml diff --git a/.mise.toml b/.mise.toml index ae1a7887..ccb6fd26 100644 --- a/.mise.toml +++ b/.mise.toml @@ -14,11 +14,11 @@ # === SECTION: settings (managed) === # Source: config:codegen.toolchain.mise_lockfile / mise_locked / mise_lockfile_platforms [settings] -lockfile = false -locked = false +lockfile = true +locked = true lockfile_platforms = ["linux-x64", "linux-arm64", "macos-x64", "macos-arm64", "windows-x64"] [tool_config] -locked = false +locked = true # End SECTION: settings # === SECTION: tools (managed) === diff --git a/Makefile b/Makefile index 6324fa0b..21e77700 100644 --- a/Makefile +++ b/Makefile @@ -135,7 +135,11 @@ TESTMON_DATAFILE := $(PROJECT_STATE_ROOT)/testmon/.testmondata export TESTMON_DATAFILE # === SECTION: REPOSITORY_ROOT isolation (managed) === # Source: physical checkout topology; caller variables cannot select a workspace. -ifneq ($(filter standalone,$(MAKE_PROFILE))$(GEN_INIT_ONLY),) +# Operator law 2026-09-24 (flext-x8gn6): inside a workspace every make run, root +# or member, uses the workspace runtime. A member resolves the Git superproject +# that checks it out as a submodule; a checkout without one (a standalone clone, +# a linked worktree) owns its runtime. +ifneq ($(GEN_INIT_ONLY),) override REPOSITORY_ROOT := $(MAKEFILE_ROOT) else override REPOSITORY_ROOT := $(shell cd "$(MAKEFILE_ROOT)" && root=$$(git rev-parse --show-superproject-working-tree) && if [ -n "$$root" ]; then cd "$$root" && pwd -P; else pwd -P; fi) @@ -241,6 +245,7 @@ _bootstrap_setup_tools: caller_xdg_data_home="$$caller_home/.local/share"; \ fi; \ caller_path="$$PATH"; \ +mise_lockfile_platforms="linux-x64,linux-arm64,macos-x64,macos-arm64,windows-x64"; \ caller_comspec="$${COMSPEC:-}"; \ caller_pathext="$${PATHEXT:-}"; \ caller_systemroot="$${SYSTEMROOT:-}"; \ @@ -370,9 +375,9 @@ mise_exec() { \ 'MISE_GITHUB_OAUTH_CLIENT_ID=' \ 'MISE_GITHUB_OAUTH_EXPORT_ENV=' \ 'MISE_GITHUB_OAUTH_OPEN_BROWSER=false' \ -'MISE_LOCKFILE=false' \ -'MISE_LOCKED=false' \ -'MISE_LOCKFILE_PLATFORMS=linux-x64,linux-arm64,macos-x64,macos-arm64,windows-x64' \ +'MISE_LOCKFILE=true' \ +'MISE_LOCKED=true' \ +$${mise_lockfile_platforms:+"MISE_LOCKFILE_PLATFORMS=$$mise_lockfile_platforms"} \ "HOME=$$scratch/home" \ "USERPROFILE=$$scratch/home" \ "APPDATA=$$scratch/appdata" \ @@ -458,17 +463,16 @@ $${mise_config_argument:+"$$mise_config_argument"} \ fi; \ caller_mise_version="$$runtime_release"; \ printf 'mise setup receipt=%s storage=%s\n' "$$runtime_release" "$$mise_storage_root"; \ - # Only ``upg`` resolves: it re-resolves every ``latest`` selector and the \ - # Python minor line into mise.lock, with download URLs and checksums. \ + # Only ``upg`` resolves. Artifact tools own a five-platform URL/checksum \ + # matrix; npm owns one platform-independent Aube dependency graph. \ if [ "$(TOOL_BOOTSTRAP_RESOLVE)" = "1" ]; then \ - mise_checked "$$scratch/lock.log" mise_exec project "$$latest_mise" -C "$$project_root" lock --bump; \ + mise_checked "$$scratch/lock-artifacts.log" mise_exec project "$$latest_mise" -C "$$project_root" lock --bump python uv kubectl helm kind direnv taplo ast-grep gitleaks "aqua:boyter/scc" kubeconform node go make "github:qltysh/qlty" "github:kucherenko/jscpd" "github:microsoft/waza"; \ + mise_lockfile_platforms=; \ + mise_checked "$$scratch/lock-npm-prettier.log" mise_exec project "$$latest_mise" -C "$$project_root" lock --bump "npm:prettier"; \ + mise_lockfile_platforms="linux-x64,linux-arm64,macos-x64,macos-arm64,windows-x64"; \ fi; \ # ``locked`` mode installs exactly what the committed mise.lock pins. \ mise_checked "$$scratch/install.log" mise_exec project "$$latest_mise" -C "$$project_root" install --yes; \ - # ``mise install`` may reuse an installed fuzzy match. Upgrade Python inside \ - # the configured minor line so ``python = \"3.13\"`` always resolves the \ - # newest available 3.13 patch without rewriting the project selector. \ - mise_checked "$$scratch/python-upgrade.log" mise_exec project "$$latest_mise" -C "$$project_root" upgrade --no-prune python; \ mise_checked "$$scratch/uv-version.log" mise_exec project "$$latest_mise" -C "$$project_root" exec -- uv --version; \ uv_output=$$(cat "$$scratch/uv-version.log"); \ case "$$uv_output" in \ @@ -1093,6 +1097,11 @@ _builtin_setup_submodules: done .PHONY: _builtin_require_github_auth +# The credential check precedes the Mise pin check even under -j. `make setup` +# first runs on the host's make before Mise installs the declared one, so the +# ordering uses .NOTPARALLEL (every GNU Make; 4.4+ serializes only this target's +# prerequisites) instead of .WAIT, which older releases read as a missing target. +.NOTPARALLEL: _bootstrap_setup_tools _bootstrap_setup_tools: _builtin_require_github_auth $(if $(filter upg,$(MAKECMDGOALS)),,_builtin_require_mise_pin) _builtin_require_github_auth: @if [ "$(GITHUB_CREDENTIAL_READ_STATUS)" != "0" ]; then \ @@ -1152,12 +1161,21 @@ endif # `upg` is the only recipe that resolves: the bootstrap above bumps mise.lock # before installing, and this lifecycle upgrades every uv.lock, provisions the # environment frozen from the new locks, and conforms dependency floors. +# The floors land in the codegen SSOT, so `gen` projects them into every +# pyproject and the locks are re-resolved against those raised floors before +# the frozen reprovision: the committed lock must match the committed +# pyproject, or `setup --locked` (the CI path) rejects it. # Branch-tracked git dependencies are moving sources by declaration # (workspace.yaml owns the branch): --refresh re-reads their metadata so a # stale cached requires-dist can never block or skew the resolution -# (flext-62fbu). +# (flext-62fbu). Like `setup`, it runs the declared pre-/post-upg lifecycle +# hooks, post-upg inside the activated environment. .PHONY: _upg_lifecycle _upg_lifecycle: _builtin_setup_submodules + @set -eu; \ + case " $(CUSTOM_DECLARED_TARGETS) " in \ + *" pre-upg "*) $(SELF_MAKE) pre-upg ;; \ + esac $(call _run_for_all_projects,--upgrade --refresh) @$(SELF_MAKE) _builtin_setup_environment @set -eu; \ @@ -1167,7 +1185,19 @@ _upg_lifecycle: _builtin_setup_submodules for project in $$selected; do set -- "$$@" --projects "$$project"; done; \ $(PROJECT_FLEXT_INFRA) deps modernize --repository-root "$(PROJECT_ROOT)" \ --apply --rewrite-constraints "$$@" + @$(SELF_MAKE) gen + $(call _run_for_all_projects,) + @$(SELF_MAKE) _builtin_setup_environment $(call _run_for_all_projects,--check) + +@XDG_DATA_HOME="$${SETUP_DIRENV_XDG_DATA_HOME:?missing persistent direnv data home}" \ + "$${SETUP_DIRENV:?missing Mise-resolved direnv executable}" exec "$(PROJECT_ROOT)" $(SELF_MAKE) _upg_activated + +.PHONY: _upg_activated +_upg_activated: + @set -eu; \ + case " $(CUSTOM_DECLARED_TARGETS) " in \ + *" post-upg "*) $(SELF_MAKE) post-upg ;; \ + esac # _builtin-self-* targets serve the workspace root itself (project selector diff --git a/mise.lock b/mise.lock index 822df049..ba62f2ae 100644 --- a/mise.lock +++ b/mise.lock @@ -568,36 +568,36 @@ url = "https://github.com/tamasfe/taplo/releases/download/0.10.0/taplo-windows-x url_api = "https://api.github.com/repos/tamasfe/taplo/releases/assets/257323062" [[tools.uv]] -version = "0.12.18" +version = "0.12.19" backend = "aqua:astral-sh/uv" specifiers = ["latest"] [tools.uv."platforms.linux-arm64"] -checksum = "sha256:afb6291f3f0a6b4521fc67b947822506c41dde5b60d2189dd8f3695b2ac8c9e7" -url = "https://github.com/astral-sh/uv/releases/download/0.12.18/uv-aarch64-unknown-linux-gnu.tar.gz" -url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/582430569" +checksum = "sha256:0804e9b164c64b6914182d5920c08551958a095986f10a3731056df701126436" +url = "https://github.com/astral-sh/uv/releases/download/0.12.19/uv-aarch64-unknown-linux-gnu.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/587158851" provenance = "github-attestations" [tools.uv."platforms.linux-x64"] -checksum = "sha256:89eadd7c76fc063887959510d5ba0ab1264dfd5f1143b925ddb73021a40acf16" -url = "https://github.com/astral-sh/uv/releases/download/0.12.18/uv-x86_64-unknown-linux-gnu.tar.gz" -url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/582430671" +checksum = "sha256:23bf5552d220e0842b65c862097b2ebaeba0064b74eda5e565e77fd25969d8c8" +url = "https://github.com/astral-sh/uv/releases/download/0.12.19/uv-x86_64-unknown-linux-gnu.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/587159011" provenance = "github-attestations" [tools.uv."platforms.macos-arm64"] -checksum = "sha256:cf40e0c6a202190ccd9e0406dcfdd5b2d6668a9a5c779b17948963df32aafe5b" -url = "https://github.com/astral-sh/uv/releases/download/0.12.18/uv-aarch64-apple-darwin.tar.gz" -url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/582430554" +checksum = "sha256:a9a8df1eedeb192f2e47e40e2faabfb387db4b850209118786d42f89dde3e0ba" +url = "https://github.com/astral-sh/uv/releases/download/0.12.19/uv-aarch64-apple-darwin.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/587158826" provenance = "github-attestations" [tools.uv."platforms.macos-x64"] -checksum = "sha256:2e4108f5395397c8bc5d43bf83d3bdbb2d0e92b90d0efa607756be704905fa33" -url = "https://github.com/astral-sh/uv/releases/download/0.12.18/uv-x86_64-apple-darwin.tar.gz" -url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/582430660" +checksum = "sha256:cb5fa57bafe68fc0fb94b17f06bee0b0b9a7feb94ccbd110445afa0696e39273" +url = "https://github.com/astral-sh/uv/releases/download/0.12.19/uv-x86_64-apple-darwin.tar.gz" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/587158992" provenance = "github-attestations" [tools.uv."platforms.windows-x64"] -checksum = "sha256:cae6a3bc25239f83dffb467a4b180508d9da23986c04639ebfa44e43e6a84bff" -url = "https://github.com/astral-sh/uv/releases/download/0.12.18/uv-x86_64-pc-windows-msvc.zip" -url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/582430665" +checksum = "sha256:6dbb02d79e419522f1c500f0adb1cddcff0cda7d59b0d66ea7f5e3b4a1b2f5f0" +url = "https://github.com/astral-sh/uv/releases/download/0.12.19/uv-x86_64-pc-windows-msvc.zip" +url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/587159002" provenance = "github-attestations" diff --git a/uv.lock b/uv.lock index ff17c5f4..b85b0e9c 100644 --- a/uv.lock +++ b/uv.lock @@ -394,7 +394,7 @@ wheels = [ [[package]] name = "flext-cli" version = "0.12.0" -source = { git = "https://github.com/flext-sh/flext-cli.git?rev=0.12.0-dev#13b9b144487e210732ff306a94f4d36f686e2678" } +source = { git = "https://github.com/flext-sh/flext-cli.git?rev=0.12.0-dev#ce36f45d6438e0b90ca809715a1be6dc65cfae05" } dependencies = [ { name = "annotated-types" }, { name = "beartype" }, @@ -421,7 +421,7 @@ dependencies = [ [[package]] name = "flext-core" version = "0.12.0" -source = { git = "https://github.com/flext-sh/flext-core.git?rev=0.12.0-dev#c47ea7d7975b9c920ca4b1db4a5f7f0ac8b96cfb" } +source = { git = "https://github.com/flext-sh/flext-core.git?rev=0.12.0-dev#d65ba487fd56312f1a5fc809ea478f0413634978" } dependencies = [ { name = "annotated-types" }, { name = "beartype" }, @@ -437,7 +437,7 @@ dependencies = [ [[package]] name = "flext-infra" version = "0.12.0" -source = { git = "https://github.com/flext-sh/flext-infra.git?rev=0.12.0-dev#dfa7bb68246389d6ff1b9528d019027793a7bfd9" } +source = { git = "https://github.com/flext-sh/flext-infra.git?rev=0.12.0-dev#4563c04ac340487ffab47cc55e741ef6c09d7198" } dependencies = [ { name = "annotated-types" }, { name = "beartype" }, @@ -1712,15 +1712,11 @@ wheels = [ [[package]] name = "rope" -version = "1.14.0" -source = { registry = "https://pypi.org/simple" } +version = "1.14.0+dc.2" +source = { git = "https://github.com/marlon-costa-dc/rope.git?rev=1.14.0%2Bdc.2#d2571e8cfabe2e00de7783e153403ac0cf4828d4" } dependencies = [ { name = "pytoolconfig", extra = ["global"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/3a/85e60d154f26ecdc1d47a63ac58bd9f32a5a9f3f771f6672197f02a00ade/rope-1.14.0.tar.gz", hash = "sha256:8803e3b667315044f6270b0c69a10c0679f9f322ed8efe6245a93ceb7658da69", size = 296801, upload-time = "2025-07-12T17:46:07.786Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/75/35/130469d1901da2b3a5a377539b4ffcd8a5c983f1c9e3ba5ffdd8d71ae314/rope-1.14.0-py3-none-any.whl", hash = "sha256:00a7ea8c0c376fc0b053b2f2f8ef3bfb8b50fecf1ebf3eb80e4f8bd7f1941918", size = 207143, upload-time = "2025-07-12T17:46:05.928Z" }, -] [[package]] name = "rpds-py"