0.12.0 dev - #341
Conversation
The construction mixin factories were typed as returning the mixin itself instead of the concrete FlextResult facade. Rebind all return types and cls casts to FlextResult[V] so consumers see the public result type.
…/OO structure - Merge p.Result auxiliary protocols into single structural protocol - Move result internals to _result/ package with clean inheritance chain - Remove mixin aliases and compatibility layers - Align value access error message with RuntimeError convention - Restore successful_result and failed_result static helpers - Allow None payload in map operations (returns convention) - Fix dependency-injector wiring type resolution - Update project metadata error handling for missing project table
- p.Result now uses an explicit covariant TypeVar (Protocol[T_co]) with a covariant-safe member set: higher-order callbacks use Callable[..., X], lash/recover/flow_through return honest Result[T_co | U], and __or__/map_or keep single general signatures. Result[str] now flows into Result[JsonPayload] at handler boundaries (structural assignment was impossible while the protocol was invariant). - FlextResultConstruction.ok returns the declared protocol type p.Result[V] (constructing the concrete FlextResult internally) so generic consumers solve the payload type nominally instead of through structural matching. - FlextResultTransforms: lash/recover/flow_through widened to [U] forms, map_or overloads collapsed to the general form (same precision), redundant casts removed. - Remove stale pyrefly ignore in _dependency_bindings and fix the Result[None] annotation in test_result_recent_behaviors. Validated: pyrefly check 0 errors (src+tests+examples), ruff check/format clean, pytest result suites green.
The overload set could not cover the protocol's general map_or signature for static checkers (mypy reported FlextResult[Never] not assignable to p.Result[V] at FlextResultConstruction.ok); the single general form keeps identical precision and satisfies p.Result on mypy, pyrefly and pyright. Also removes the now-unused type: ignore in _result/base.py and the stale overload import. Validated: mypy clean on the result chain, pyrefly 0 errors project-wide, ruff clean.
…o basedpyright consumers - Add explicit __init__ to FlextResult so basedpyright sees the value/error keyword parameters on the concrete generic class. - Return FlextResult[V] from FlextResultConstruction.ok() so callers typed as r[T] accept the result without a cast. - Normalize log_level declaration to plain Field(default=...) so type checkers infer the default and DcBackupSettings(workspace_root=...) calls type-check cleanly. - Rename validate_error_data helper (dropping the leading underscore) so it can be reused from the concrete result facade.
…ssions for 0.12.0-dev alignment - Rename covariant TypeVar to ResultT_co and restore covariant=True in protocols.result to satisfy Ruff PLC0105 and preserve p.Result variance. - Resolve merge conflict in root .mise.toml beads tool pin. - Replace unsafe model_dump override in DecoratorConfig with mp.PlainSerializer for middleware so JSON dumps remain JsonValue-compatible without manual mutation of immutable mappings. - Tighten result construction/transform/composition typing and update tests for mypy var-annotated and structural subtyping checks. - Bump internal version metadata and regenerate examples/typings artifacts. make check and make test pass (2625 tests) in flext-core.
…ublic FlextResult
Only the principal workspace root owns a Beads ledger (issue-prefix 'mro'); a member must not carry .beads/ state. The tracked ledger here was an empty accidental init (0 issues) and made workspace conform fail closed with 'standalone project must not own Beads state'. Untrack .beads/ and ignore it; the directory is archived on disk as .beads.bak rather than deleted.
Apply canonical conform output plus the 5 E202 whitespace-before-close- bracket defects in examples/ex_04_flext_dispatcher.py that the newly generated per-file-ignores policy correctly stopped masking. Examples are first-class code, so the defect is fixed at the source rather than exempted.
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
📝 WalkthroughWalkthroughThe change restructures the result implementation and protocols, updates workspace orchestration and CI, tightens service and dispatcher typing, revises project metadata utilities, and adjusts tests, environment configuration, and development tooling. ChangesWorkspace and result architecture
Estimated code review effort: 5 (Critical) | ~120 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| pass | ||
|
|
||
| @overload | ||
| def __or__(self, default: T) -> T: ... |
| @overload | ||
| def __or__(self, default: T) -> T: ... | ||
| @overload | ||
| def __or__[D](self, default: D) -> T | D: ... |
| def dispatch_message( | ||
| self, message: p.Routable, operation: str = ... | ||
| ) -> pr.ResultLike[t.JsonPayload] | t.JsonPayload | None: ... | ||
| ) -> pr.Result[t.JsonPayload] | t.JsonPayload | None: ... |
| def handle( | ||
| self, message: p.Routable | ||
| ) -> pr.ResultLike[t.JsonPayload] | t.JsonPayload | None: ... | ||
| ) -> pr.Result[t.JsonPayload] | t.JsonPayload | None: ... |
| def execute( | ||
| self, message: p.Routable | ||
| ) -> pr.ResultLike[t.JsonPayload] | t.JsonPayload | None: ... | ||
| ) -> pr.Result[t.JsonPayload] | t.JsonPayload | None: ... |
| @runtime_checkable | ||
| class FailureLike(Protocol): | ||
| @property | ||
| def error(self) -> str | None: ... |
| @property | ||
| def error(self) -> str | None: ... | ||
| @property | ||
| def error_code(self) -> str | None: ... |
| @property | ||
| def error_code(self) -> str | None: ... | ||
| @property | ||
| def error_data(self) -> t.JsonMapping | None: ... |
| @property | ||
| def error_data(self) -> t.JsonMapping | None: ... | ||
| @property | ||
| def exception(self) -> BaseException | None: ... |
| @property | ||
| def exception(self) -> BaseException | None: ... | ||
| @property | ||
| def failure(self) -> bool: ... |
There was a problem hiding this comment.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/flext_core/_runtime/_dependency_bindings.py (1)
166-180: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winForward configured packages to the wiring call.
packagesis accepted but discarded, whilesrc/flext_core/_utilities/model_runtime.pypasseswire_packageshere. Package-only wiring therefore does nothing.Proposed fix
- _ = packages - wiring.wire(container, modules=modules_to_wire or None, packages=None) + wiring.wire( + container, + modules=modules_to_wire or None, + packages=packages, + )#!/bin/bash set -euo pipefail rg -n -C3 'wiring\.wire\(' src/flext_core/_runtime/_dependency_bindings.py rg -n -C3 'wire_packages|packages=' src/flext_core/_utilities/model_runtime.py tests🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/flext_core/_runtime/_dependency_bindings.py` around lines 166 - 180, Update the dependency-wiring function containing modules_to_wire to forward the configured packages argument to wiring.wire instead of discarding it. Preserve the existing module and class-derived module handling, and ensure package-only configuration from model_runtime.py’s wire_packages reaches the wiring call.
🧹 Nitpick comments (9)
Makefile (1)
409-421: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winBootstrap downloads and executes a release binary with no integrity check.
curl -fsSL "$$url"→chmod +x→mvtrusts TLS alone; the post-install--versioncompare only reads what the downloaded binary reports about itself, so a substituted/corrupted asset still passes. mise publishes per-asset checksums alongside releases; verifying one beforemvcloses this bootstrap supply-chain gap. Also, thecurlfailure branch at Line 413 exits silently — add a message with the URL to make CI failures diagnosable.Note: this file is a generated projection (
@flext-managed), so the fix belongs in the flext-infraMakefile.j2SSOT.#!/bin/bash # Confirm mise publishes checksum assets for the pinned release ver=$(grep -E '^MISE_VERSION *:=' Makefile | awk -F':= *' '{print $2}' | tr -d ' ') echo "pinned mise version: $ver" curl -fsSL "https://api.github.com/repos/jdx/mise/releases/tags/v$ver" \ | jq -r '.assets[].name' | grep -iE 'sha|sig|checksum' | head -20🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Makefile` around lines 409 - 421, Update the flext-infra Makefile.j2 source template, not the generated Makefile, to verify the downloaded mise asset against the release-published checksum before chmod/mv or execution. Preserve the existing temporary-file flow and version validation, and add an error message including $$url in the curl failure branch before exiting.src/flext_core/_models/handler.py (1)
170-177: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win
when_used="always"breaks python-mode round-tripping ofmiddleware.With
always,model_dump()(python mode) also yields["pkg.mod.MyMiddleware", ...], soDecoratorConfig.model_validate(config.model_dump())can no longer reconstruct the field (stris nottype[p.Middleware]), and any consumer that inspected the actual classes from a python dump now gets strings. If the intent is only human/JSON-readable output,when_used="json"preserves python-mode fidelity while giving the same JSON shape.♻️ Restrict stringification to JSON serialization
mp.PlainSerializer( lambda value: [ f"{middleware_type.__module__}.{middleware_type.__qualname__}" for middleware_type in value ], return_type=list[str], - when_used="always", + when_used="json", ),Worth confirming no code path re-validates a python-mode dump of
DecoratorConfig.#!/bin/bash # Look for round-trip usage of DecoratorConfig dumps and middleware consumption rg -nP -C3 'DecoratorConfig' --type=py | head -60 rg -nP -C3 '\bmiddleware\b' --type=py -g '!**/.venv/**' | head -60🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/flext_core/_models/handler.py` around lines 170 - 177, Update the PlainSerializer in the middleware field configuration to use JSON-only serialization instead of applying stringification in all modes. Preserve JSON output as fully qualified middleware class-name strings while keeping python-mode dumps as the original middleware classes for validation and consumers.src/flext_core/_protocols/result.py (1)
11-11: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
mpis only needed for a lazily-evaluated bound — consider moving it underTYPE_CHECKING.
FlextModelsPydanticis used solely into_model[U: mp.BaseModel](Line 124); PEP 695 type-parameter bounds are evaluated lazily, so this eager import of the models layer from the protocols layer buys nothing at runtime while adding a protocols→models dependency edge (and cycle exposure) plus import cost.mandtare already handled that way.♻️ Move the models import into the type-checking block
-from flext_core._models.pydantic import FlextModelsPydantic as mp - ResultT_co = TypeVar("ResultT_co", covariant=True) if TYPE_CHECKING: from collections.abc import Callable from types import TracebackType + from flext_core._models.pydantic import FlextModelsPydantic as mp from flext_core._typings.base import FlextTypingBase as t🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/flext_core/_protocols/result.py` at line 11, Move the FlextModelsPydantic import for alias mp from the module-level runtime imports into the existing TYPE_CHECKING block, while preserving its use as the bound in to_model[U: mp.BaseModel]. Keep the runtime protocol behavior and the existing m and t type-only import handling unchanged..mise.toml (1)
6-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePython pin loosened from
3.13.11to3.13in both pin files. Same root cause: the interpreter is now resolved to an arbitrary latest 3.13.x while every other tool in.mise.tomlremains patch-pinned, so bootstrapped environments can differ between developers and CI runs.
.mise.toml#L6-L15: restore a patch-levelpythonpin (or document why the minor-only pin is intentional given the exact pins foruv,taplo,ast-grep,gitleaks,tokei)..python-version#L1-L1: keep this file in lockstep with the.mise.tomlpin granularity so uv and mise resolve the identical interpreter.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.mise.toml around lines 6 - 15, Restore a patch-level Python pin in .mise.toml, matching the repository’s pinned interpreter version, and update .python-version to the identical patch-level value; keep both files in lockstep so mise and uv resolve the same deterministic interpreter.pyproject.toml (1)
57-65: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winConsolidate duplicate dependency constraints.
pyreflyandpytestare each declared twice, andyamlfixadds another constraint alongside an existing bounded declaration. Keep one intentional specification per tool in the SSOT; otherwise resolution and regeneration can drift.Also applies to: 106-106
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pyproject.toml` around lines 57 - 65, Consolidate the duplicate dependency entries in the project’s tool dependency list: keep exactly one intentional constraint for pyrefly and pytest, and merge yamlfix’s duplicate constraints into its existing bounded declaration. Preserve the intended version bounds while removing redundant specifications from the SSOT.ci/docker/alpine.Dockerfile (1)
4-4: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winRun the CI image as a non-root user.
No
USERis declared, so bootstrap and smoke commands run as root. Create a dedicated user, chown/workspace, and switch to it before the default command.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ci/docker/alpine.Dockerfile` at line 4, Update the Alpine image definition around the FROM instruction to create a dedicated non-root user, ensure /workspace is owned by that user, and declare USER before the default command so bootstrap and smoke commands execute without root privileges.Source: Linters/SAST tools
src/flext_core/result.py (1)
17-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRedundant base list;
FlextResultUnwrap[T]alone is equivalent.The five layers already form a linear chain (
Unwrap → Composition → Transforms → Construction → Behavior), so the explicit list only duplicates the existing linearization — and it will raise an MRO error if that chain is ever reordered.♻️ Collapse to the topmost layer
-class _FlextResult[T]( - FlextResultUnwrap[T], - FlextResultComposition[T], - FlextResultTransforms[T], - FlextResultConstruction[T], - FlextResultBehavior[T], -): +class _FlextResult[T](FlextResultUnwrap[T]):🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/flext_core/result.py` around lines 17 - 23, Update the _FlextResult class declaration to inherit only from FlextResultUnwrap[T], relying on its existing inheritance chain instead of listing all five layers explicitly.src/flext_core/service.py (1)
31-31: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winDropping the
p.Basebound weakens the domain-result contract.With only a default and no upper bound,
FlextService[int]/FlextService[str]now type-check, soexecute() -> p.Result[TDomainResult]no longer guarantees a structuralp.Basepayload.tests/base.pyline 14 still declaresTDomainResult: p.Base = p.Base, leaving the test base stricter than the production kernel. Restore the bound unless a concrete subclass required a non-p.Basepayload.♻️ Restore the bound alongside the default
-class FlextService[TDomainResult = p.Base](x): +class FlextService[TDomainResult: p.Base = p.Base](x):#!/bin/bash # Which payload types are actually parameterized on FlextService / its aliases? rg -nP --type=py -C2 'FlextService\[' src tests examples # Declared runtime target for PEP 696 defaults rg -n 'requires-python|target-version' pyproject.toml cat .python-version 2>/dev/null🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/flext_core/service.py` at line 31, Update the TDomainResult declaration on FlextService to retain p.Base as its upper bound while keeping p.Base as the default, restoring the structural payload contract used by execute(). Verify concrete FlextService parameterizations remain compatible and do not broaden the type beyond p.Base.src/flext_core/_result/behavior.py (1)
32-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSilence the SonarCloud "empty method" finding on
__exit__.The no-op
__exit__is intentional (context-manager sugar only), but SonarCloud flags it as a failure requiring either a comment or an implementation.🔧 Proposed fix
def __exit__( self, _exc_type: type[BaseException] | None, _exc_val: BaseException | None, _exc_tb: object, ) -> None: + # Intentional no-op: context-manager protocol exists only for `with` ergonomics. pass🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/flext_core/_result/behavior.py` around lines 32 - 38, Add an explanatory comment inside the no-op __exit__ method documenting that it is intentionally empty because the context manager provides syntax-only behavior, resolving SonarCloud’s empty-method finding without changing its behavior.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci-matrix.yml:
- Around line 8-12: Update the branch filters in .github/workflows/ci-matrix.yml
lines 8-12 and .github/workflows/ci.yml lines 4-10 to include main for
pull_request events; also include main for push events if these workflows must
run on mainline pushes.
- Around line 33-39: Update the actions/checkout step in the CI matrix workflow
to set persist-credentials to false, while preserving the existing pinned action
reference and Docker build steps.
In `@ci/docker/alpine.Dockerfile`:
- Line 14: Replace the broad COPY instruction in the Alpine Docker build with a
controlled build context: add a suitable .dockerignore excluding repository
metadata, caches, environment files, credentials, and other unnecessary
artifacts, then copy only the project inputs required by the image build.
- Line 16: Update the Alpine bootstrap command containing `mise trust` and `mise
install` so it succeeds on `alpine:3.21`; capture and inspect the complete `mise
install` failure, then adjust the bootstrap prerequisites or invocation to
resolve the reported cause while preserving installation of the configured
tools.
- Around line 23-28: Update the failure handling around the bootstrap command in
the Dockerfile to stop classifying errors via broad “uv.lock” or “flext-core”
substring matches. Recognize the external blocker only through a precise
documented error signature or explicit external-blocker status, and continue
exiting with the original status for all other failures.
- Line 11: Replace the unpinned root-level installer command with a reproducible
mise installation in the Dockerfile: use a trusted pinned base image or package
source, or download a versioned release artifact and verify its checksum or
signature before installation. Keep the resulting mise installation available to
subsequent image build steps.
In `@ci/docker/arch.Dockerfile`:
- Line 18: Install a compatible Rust/Cargo toolchain before the mise
installation command in ci/docker/arch.Dockerfile:18-18,
ci/docker/debian.Dockerfile:19-19, ci/docker/fedora.Dockerfile:18-18, and
ci/docker/ubuntu.Dockerfile:19-19, ensuring mise can provision the
cargo:tokei@14.0.0 dependency in each image.
- Around line 22-31: Remove the broad bare “flext-core” fallback from the make
setup failure handling in ci/docker/arch.Dockerfile lines 22-31,
ci/docker/debian.Dockerfile lines 23-32, ci/docker/fedora.Dockerfile lines
22-31, and ci/docker/ubuntu.Dockerfile lines 23-32. Only soft-pass a uniquely
identified, explicitly accepted lock-boundary error; all other bootstrap
failures must exit with their original status.
- Line 13: Replace the mutable pipe-to-shell Mise installers with the generator
template’s version-pinned installation and checksum- or signature-verification
flow. Apply the same verified installation change at
ci/docker/arch.Dockerfile:13-13, ci/docker/debian.Dockerfile:14-14,
ci/docker/fedora.Dockerfile:13-13, and ci/docker/ubuntu.Dockerfile:14-14.
In `@pyproject.toml`:
- Line 732: Update the pyproject.toml uv configuration by replacing the
open-ended required-version constraint with the tested pinned uv version or an
explicitly bounded range, so untested newer releases are not permitted.
In `@src/flext_core/_result/composition.py`:
- Line 9: Replace package-root imports of c/r with their defining modules to
avoid partially initialized package access: in
src/flext_core/_result/composition.py:9-9 import c from
flext_core._constants.errors; in
src/flext_core/_utilities/parser_coerce.py:13-13 retain c and m if already safe,
but source r from flext_core.result; in
src/flext_core/_utilities/settings.py:23-23 restore r from flext_core.result; in
src/flext_core/dispatcher.py:12-12 remove r from the grouped root import and
import FlextResult as r from flext_core.result; and in
src/flext_core/loggings.py:21-21 remove r from the grouped root import and
source it from flext_core.result.
- Around line 81-86: Update the cleanup handling in the result composition flow
so a cleanup exception does not replace an already failed operation result. When
`result` represents an `op` failure, preserve its message, error code, error
data, and exception; only return the cleanup failure when the operation
otherwise succeeded.
In `@src/flext_core/_result/construction.py`:
- Around line 22-29: Update Result.require_error to allow legitimately empty
failure messages, including error="" produced by fail(None, ...) and
str(exception) for bare exceptions. Preserve failure propagation for downstream
callers such as from_failure, _from_result, and the transform methods by
returning the normalized error value without raising solely because it is empty.
In `@tests/integration/test_migration_validation.py`:
- Around line 172-181: Update test_service_execute_returns_success and its
NoopService docstring to use the r[bool] contract, changing the documented
payload from r[None] to r[bool]. Add an assertion that outcome.value is True,
while preserving the existing success assertion.
In `@tests/unit/test_result_recent_behaviors.py`:
- Around line 121-126: Update test_map_returning_none_reports_success to match
the current map/ok contract: assert the result is successful and verify
result.value is None, while retaining the existing mapping setup.
---
Outside diff comments:
In `@src/flext_core/_runtime/_dependency_bindings.py`:
- Around line 166-180: Update the dependency-wiring function containing
modules_to_wire to forward the configured packages argument to wiring.wire
instead of discarding it. Preserve the existing module and class-derived module
handling, and ensure package-only configuration from model_runtime.py’s
wire_packages reaches the wiring call.
---
Nitpick comments:
In @.mise.toml:
- Around line 6-15: Restore a patch-level Python pin in .mise.toml, matching the
repository’s pinned interpreter version, and update .python-version to the
identical patch-level value; keep both files in lockstep so mise and uv resolve
the same deterministic interpreter.
In `@ci/docker/alpine.Dockerfile`:
- Line 4: Update the Alpine image definition around the FROM instruction to
create a dedicated non-root user, ensure /workspace is owned by that user, and
declare USER before the default command so bootstrap and smoke commands execute
without root privileges.
In `@Makefile`:
- Around line 409-421: Update the flext-infra Makefile.j2 source template, not
the generated Makefile, to verify the downloaded mise asset against the
release-published checksum before chmod/mv or execution. Preserve the existing
temporary-file flow and version validation, and add an error message including
$$url in the curl failure branch before exiting.
In `@pyproject.toml`:
- Around line 57-65: Consolidate the duplicate dependency entries in the
project’s tool dependency list: keep exactly one intentional constraint for
pyrefly and pytest, and merge yamlfix’s duplicate constraints into its existing
bounded declaration. Preserve the intended version bounds while removing
redundant specifications from the SSOT.
In `@src/flext_core/_models/handler.py`:
- Around line 170-177: Update the PlainSerializer in the middleware field
configuration to use JSON-only serialization instead of applying stringification
in all modes. Preserve JSON output as fully qualified middleware class-name
strings while keeping python-mode dumps as the original middleware classes for
validation and consumers.
In `@src/flext_core/_protocols/result.py`:
- Line 11: Move the FlextModelsPydantic import for alias mp from the
module-level runtime imports into the existing TYPE_CHECKING block, while
preserving its use as the bound in to_model[U: mp.BaseModel]. Keep the runtime
protocol behavior and the existing m and t type-only import handling unchanged.
In `@src/flext_core/_result/behavior.py`:
- Around line 32-38: Add an explanatory comment inside the no-op __exit__ method
documenting that it is intentionally empty because the context manager provides
syntax-only behavior, resolving SonarCloud’s empty-method finding without
changing its behavior.
In `@src/flext_core/result.py`:
- Around line 17-23: Update the _FlextResult class declaration to inherit only
from FlextResultUnwrap[T], relying on its existing inheritance chain instead of
listing all five layers explicitly.
In `@src/flext_core/service.py`:
- Line 31: Update the TDomainResult declaration on FlextService to retain p.Base
as its upper bound while keeping p.Base as the default, restoring the structural
payload contract used by execute(). Verify concrete FlextService
parameterizations remain compatible and do not broaden the type beyond p.Base.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a91070d9-2953-4ecb-8a12-48fb658c15c0
📒 Files selected for processing (114)
.agents/INSTRUCTION_SURFACE.md.agents/skills/rules-cmd.bak-20260725T214500/SKILL.md.beads/.gitignore.beads/README.md.beads/backup/LOCK.beads/backup/backup_state.json.beads/backup/h6mbga66itkhrhtji8j986g8944trmlt.darc.beads/backup/i5r9boc7btoavocdoffrrcnho6dfr995.darc.beads/backup/manifest.beads/backup/mt450ckcsvqtjh4v6ufap2cla4p8bjc9.darc.beads/config.yaml.beads/embeddeddolt/beads/.dolt/config.json.beads/embeddeddolt/beads/.dolt/noms/LOCK.beads/embeddeddolt/beads/.dolt/noms/journal.idx.beads/embeddeddolt/beads/.dolt/noms/manifest.beads/embeddeddolt/beads/.dolt/noms/nbs_manifest_3630928294.beads/embeddeddolt/beads/.dolt/noms/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv.beads/embeddeddolt/beads/.dolt/repo_state.json.beads/embeddeddolt/beads/.dolt/temptf/dolt_embedded_metrics.beads/interactions.jsonl.beads/issues.jsonl.beads/metadata.json.github/workflows/ci-matrix.yml.github/workflows/ci.yml.gitignore.mise.toml.python-version.vscode/settings.jsonMakefileci/docker/alpine.Dockerfileci/docker/arch.Dockerfileci/docker/debian.Dockerfileci/docker/fedora.Dockerfileci/docker/ubuntu.Dockerfileexamples/_models/ex00.pyexamples/ex_04_flext_dispatcher.pyexamples/typings.pypyproject.tomlsrc/flext_core/__version__.pysrc/flext_core/_decorators/_railway.pysrc/flext_core/_exceptions/_factories_parts/flextexceptionsfactories_part_01.pysrc/flext_core/_exceptions/_factories_parts/flextexceptionsfactories_part_02.pysrc/flext_core/_exceptions/_factories_parts/flextexceptionsfactories_part_03.pysrc/flext_core/_exceptions/_factories_parts/flextexceptionsfactories_part_04.pysrc/flext_core/_models/handler.pysrc/flext_core/_protocols/_result_parts/flextprotocolsresult_part_01.pysrc/flext_core/_protocols/_result_parts/flextprotocolsresult_part_02.pysrc/flext_core/_protocols/_result_parts/flextprotocolsresult_part_03.pysrc/flext_core/_protocols/_result_parts/flextprotocolsresult_part_04.pysrc/flext_core/_protocols/handler.pysrc/flext_core/_protocols/result.pysrc/flext_core/_result/__init__.pysrc/flext_core/_result/base.pysrc/flext_core/_result/behavior.pysrc/flext_core/_result/composition.pysrc/flext_core/_result/construction.pysrc/flext_core/_result/transforms.pysrc/flext_core/_result/unwrap.pysrc/flext_core/_result_parts/__init__.pysrc/flext_core/_result_parts/behavior.pysrc/flext_core/_result_parts/construction.pysrc/flext_core/_result_parts/transforms.pysrc/flext_core/_runtime/_dependency_bindings.pysrc/flext_core/_settings.pysrc/flext_core/_typings/services.pysrc/flext_core/_utilities/_checker_parts/checker_part_02.pysrc/flext_core/_utilities/_checker_parts/checker_part_03.pysrc/flext_core/_utilities/_enforcement_collect_parts/enforcement_collect_part_01.pysrc/flext_core/_utilities/_guards_type_protocol_types.pysrc/flext_core/_utilities/_mapper_access_parts/mapper_access_part_01.pysrc/flext_core/_utilities/args.pysrc/flext_core/_utilities/config.pysrc/flext_core/_utilities/dispatcher_execute.pysrc/flext_core/_utilities/handler.pysrc/flext_core/_utilities/mapper.pysrc/flext_core/_utilities/model_runtime.pysrc/flext_core/_utilities/parser_coerce.pysrc/flext_core/_utilities/project_metadata.pysrc/flext_core/_utilities/settings.pysrc/flext_core/dispatcher.pysrc/flext_core/loggings.pysrc/flext_core/result.pysrc/flext_core/service.pytests/base.pytests/integration/test_architecture.pytests/integration/test_documented_patterns.pytests/integration/test_integration.pytests/integration/test_migration_validation.pytests/integration/test_system.pytests/protocols.pytests/unit/_utilities/test_mapper.pytests/unit/test_coverage_loggings.pytests/unit/test_deprecation_warnings.pytests/unit/test_enforcement_namespace_part_02.pytests/unit/test_exceptions_structured_contracts.pytests/unit/test_handler_decorator_discovery.pytests/unit/test_handler_decorator_edges.pytests/unit/test_handler_discovery_class.pytests/unit/test_loggings_full_coverage.pytests/unit/test_models_base_full_coverage.pytests/unit/test_public_api_contract.pytests/unit/test_result.pytests/unit/test_result_callables_fold.pytests/unit/test_result_chain_helpers.pytests/unit/test_result_laws.pytests/unit/test_result_recent_behaviors.pytests/unit/test_result_transforms.pytests/unit/test_service.pytests/unit/test_service_registration_spec.pytests/unit/test_typings_aliases.pytests/unit/test_utilities_project_metadata.pytests/unit/test_utilities_project_metadata_read.pytests/unit/test_utilities_runtime_violation_registry_coverage_100.pytests/unit/test_version.py
💤 Files with no reviewable changes (21)
- .beads/embeddeddolt/beads/.dolt/config.json
- .beads/embeddeddolt/beads/.dolt/noms/manifest
- .beads/README.md
- .beads/backup/manifest
- .agents/INSTRUCTION_SURFACE.md
- .beads/embeddeddolt/beads/.dolt/repo_state.json
- .beads/.gitignore
- .beads/backup/backup_state.json
- src/flext_core/_protocols/_result_parts/flextprotocolsresult_part_04.py
- .beads/config.yaml
- .beads/metadata.json
- .beads/embeddeddolt/beads/.dolt/noms/nbs_manifest_3630928294
- .agents/skills/rules-cmd.bak-20260725T214500/SKILL.md
- src/flext_core/_result_parts/behavior.py
- src/flext_core/_result_parts/init.py
- src/flext_core/_protocols/_result_parts/flextprotocolsresult_part_03.py
- src/flext_core/_protocols/_result_parts/flextprotocolsresult_part_02.py
- src/flext_core/_result_parts/transforms.py
- src/flext_core/_result_parts/construction.py
- src/flext_core/_protocols/_result_parts/flextprotocolsresult_part_01.py
- tests/unit/test_utilities_project_metadata.py
| on: | ||
| push: | ||
| branches: [0.12.0-dev] | ||
| pull_request: | ||
| branches: [0.12.0-dev] |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Restore CI coverage for the main PR target.
PR #341 targets main, but both workflows only match 0.12.0-dev; therefore neither workflow runs for this PR.
.github/workflows/ci-matrix.yml#L8-L12: includemainin thepull_requestbranch filter (and inpushif mainline pushes require this workflow)..github/workflows/ci.yml#L4-L10: includemainin thepull_requestbranch filter (and inpushif mainline pushes require this workflow).
📍 Affects 2 files
.github/workflows/ci-matrix.yml#L8-L12(this comment).github/workflows/ci.yml#L4-L10
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/ci-matrix.yml around lines 8 - 12, Update the branch
filters in .github/workflows/ci-matrix.yml lines 8-12 and
.github/workflows/ci.yml lines 4-10 to include main for pull_request events;
also include main for push events if these workflows must run on mainline
pushes.
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| - name: Build ${{ matrix.distro }} image | ||
| run: >- | ||
| docker build | ||
| -f ci/docker/${{ matrix.distro }}.Dockerfile | ||
| -t ci-matrix-${{ matrix.distro }} | ||
| . |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow file =="
cat -n .github/workflows/ci-matrix.yml | sed -n '1,120p'
echo
echo "== usages of persist-credentials and checkout context in workflow =="
rg -n "persist-credentials|actions/checkout|checkout\\.|GITHUB_TOKEN|git " .github/workflows -S || true
echo
echo "== workflow files mentioning checkout context usage =="
rg -n "github\\.event|github.sha|checkout/shallow|baseRef|commit_sha|submodules|ssh-keys|persist-credentials" .github/workflows -S || trueRepository: flext-sh/flext-core
Length of output: 1927
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow file =="
cat -n .github/workflows/ci-matrix.yml | sed -n '1,160p'
echo
echo "== actions/checkout steps with context in workflows =="
python3 - <<'PY'
from pathlib import Path
for p in Path('.github/workflows').glob('*.yml'):
text = p.read_text()
if 'actions/checkout@' in text:
print(f'--- {p} ---')
for i,line in enumerate(text.splitlines(), 1):
if 'actions/checkout@' in line or 'persist-credentials' in line:
start=max(1,i-8); end=min(len(text.splitlines()), i+14)
lines=text.splitlines()
for n in range(start,end+1):
print(f'{n:4}: {lines[n-1]}')
print()
PY
echo
echo "== checkout with persist-credentials: false present? =="
rg -n "persist-credentials:\s*false" .github/workflows || trueRepository: flext-sh/flext-core
Length of output: 1927
Disable persisted checkout credentials.
This job’s Docker builds only need the repository context; there is no authenticated Git access after checkout. Set persist-credentials: false for the checkout step.
Proposed change
with:
+ persist-credentials: false📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Build ${{ matrix.distro }} image | |
| run: >- | |
| docker build | |
| -f ci/docker/${{ matrix.distro }}.Dockerfile | |
| -t ci-matrix-${{ matrix.distro }} | |
| . | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Build ${{ matrix.distro }} image | |
| run: >- | |
| docker build | |
| -f ci/docker/${{ matrix.distro }}.Dockerfile | |
| -t ci-matrix-${{ matrix.distro }} | |
| . |
🧰 Tools
🪛 zizmor (1.28.0)
[warning] 33-33: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/ci-matrix.yml around lines 33 - 39, Update the
actions/checkout step in the CI matrix workflow to set persist-credentials to
false, while preserving the existing pinned action reference and Docker build
steps.
Source: Linters/SAST tools
|
|
||
| # mise installs the supported Python 3.13 family. | ||
| # uv is supplied by the managed environment without a project patch pin. | ||
| RUN curl -fsSL https://mise.run | sh |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate Dockerfile =="
git ls-files | rg '(^|/)ci/docker/alpine\.Dockerfile$|Dockerfile$' || true
echo "== target file =="
if [ -f ci/docker/alpine.Dockerfile ]; then
nl -ba ci/docker/alpine.Dockerfile | sed -n '1,80p'
fi
echo "== curl/pipe occurrences in Dockerfiles =="
rg -n '\bcurl\s+.*\|\s*(sudo\s+)?sh\b|\bcurl\s+.*\|\s*bash\b|\bcurl\s+.*\|\s*sh\s+-s\b|\bcurl\s+.*\|\s*sh\s+' ci/docker Dockerfile .github 2>/dev/null || trueRepository: flext-sh/flext-core
Length of output: 1927
🌐 Web query:
mise.run installer curl https://mise.run/sh install script redirect curlfsSLL
💡 Result:
To install the mise CLI on macOS or Linux, you can use the official installer script provided at mise.run [1][2]. The standard method for installation is to pipe the output of the curl command into sh [1][3]: curl https://mise.run | sh This command downloads and executes an installer script [4][5], which by default installs the mise binary to ~/.local/bin/mise [6][1]. Shell-Specific Installers For a more streamlined setup, the project provides shell-specific endpoints that install mise and automatically append the necessary activation line to your shell's configuration file (e.g., ~/.zshrc, ~/.bashrc, or ~/.config/fish/config.fish) [1][7]: curl https://mise.run/zsh | sh curl https://mise.run/bash | sh curl https://mise.run/fish | sh Configuration Options You can customize the installation by setting environment variables before running the command [1][7]. Common options include: MISE_INSTALL_PATH=/some/path: Specifies the directory where the mise binary will be installed (default is ~/.local/bin/mise) [1][7]. MISE_VERSION=v202X.X.X: Installs a specific version of mise [1][7]. MISE_INSTALL_SKIP_IF_EXISTS=1: Skips the installation if the binary already exists at the target path and matches the version [1][7]. While your query mentioned curlfsSLL, the standard practice for this installer is using curl -fsSL [5]. The -fsSL flags are recommended to ensure the script runs quietly, fails on server errors, and follows redirects: curl -fsSL https://mise.run | sh [5] For security-conscious environments, you can also verify the installation by downloading the signature file and verifying it with GPG before executing the script [7].
Citations:
- 1: https://mise.en.dev/installing-mise.html
- 2: https://github.com/jdx/mise/blob/30996304/docs/installing-mise.md
- 3: https://mise.en.dev/getting-started.html
- 4: https://mise.jdx.dev/install.sh
- 5: https://mise.run/bash
- 6: https://mise.run/
- 7: https://mise.jdx.dev/installing-mise.html
🌐 Web query:
site:github.com/jdx/mise "curl" "https://mise.run" "signature" "GPG"
💡 Result:
The command curl https://mise.run | sh is the standard method for installing mise [1][2]. This process installs the binary directly and does not involve a GPG signature verification of the installation script itself [1]. Regarding GPG signature verification in mise: 1. Software Verification: Mise handles security verification differently depending on the tool being installed. For tools using the aqua backend, mise provides native, automatic verification using methods like Cosign, Minisign, SLSA provenance, and GitHub attestations, requiring no external dependencies [1][2]. 2. GPG Verification: For tools that require GPG (such as Node.js), mise historically relied on the gpg binary installed on the system [3][4]. However, recent updates have moved toward native in-process verification using the rPGP crate to reduce external dependencies [5]. 3. Configuration: Verification for tools is enabled by default [5]. If you encounter issues with GPG verification, you can disable it for a specific operation using the MISE_GPG_VERIFY=false environment variable (e.g., MISE_GPG_VERIFY=false mise use --global node@24) [6][3]. Alternatively, verify that your system GPG configuration is not blocking required algorithms or causing conflicts [4][7]. For official installation instructions, always refer to the documentation at https://mise.run.
Citations:
- 1: https://github.com/jdx/mise/blob/30996304/docs/tips-and-tricks.md
- 2: jdx/mise@v2025.9.15...v2025.9.16
- 3: Node install fails at gpg verification when using `--raw` jdx/mise#4475
- 4: Can't install node@24, gpg key import fails jdx/mise#6796
- 5: https://github.com/jdx/mise/releases
- 6: GPG signature verification error when installing Node.js v24.12.0 jdx/mise#7237
- 7: GPG signature verification fails due to UTF-8 encoding error jdx/mise#3768
Avoid running the unpinned mise installer as root.
curl -fsSL https://mise.run | sh fetches mutable install script code and executes it in the image build without checksum/signature verification. Use a reproducible install method: pin a trusted Docker/base image or package manager source, or download/checksum/signature-verify a versioned release artifact before installing mise.
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis
[failure] 11-11: Avoid executing downloaded artifacts directly without verification.
[warning] 11-11: Not enforcing HTTPS here might allow for redirections to insecure websites. Make sure it is safe here.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ci/docker/alpine.Dockerfile` at line 11, Replace the unpinned root-level
installer command with a reproducible mise installation in the Dockerfile: use a
trusted pinned base image or package source, or download a versioned release
artifact and verify its checksum or signature before installation. Keep the
resulting mise installation available to subsequent image build steps.
Source: Linters/SAST tools
| RUN curl -fsSL https://mise.run | sh | ||
| ENV PATH="/root/.local/bin:/root/.local/share/mise/shims:${PATH}" | ||
| WORKDIR /workspace | ||
| COPY . . |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
Avoid copying the entire checkout into the image.
.gitignore does not control the Docker build context, so COPY . . can bake .git, caches, environment files, or credentials into image layers. Add a suitable .dockerignore and copy only required project inputs.
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis
[failure] 14-14: Copying recursively might inadvertently add sensitive data to the container. Make sure it is safe here.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ci/docker/alpine.Dockerfile` at line 14, Replace the broad COPY instruction
in the Alpine Docker build with a controlled build context: add a suitable
.dockerignore excluding repository metadata, caches, environment files,
credentials, and other unnecessary artifacts, then copy only the project inputs
required by the image build.
Source: Linters/SAST tools
| from pydantic import ValidationError | ||
|
|
||
| from flext_core._constants.errors import FlextConstantsErrors as c | ||
| from flext_core import c |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
flext_core submodules now resolve c/r through the package root instead of their defining modules. Each of these modules is imported (directly or transitively) by flext_core/__init__.py, so from flext_core import ... executes against a partially initialized package and only works while __init__.py happens to bind those names early enough. Import the defining module in each case; src/flext_core/_result/unwrap.py line 7 already shows the pattern.
src/flext_core/_result/composition.py#L9-L9: replacefrom flext_core import cwithfrom flext_core._constants.errors import FlextConstantsErrors as c.src/flext_core/_utilities/parser_coerce.py#L13-L13: keepc, mas-is if already proven safe, but sourcerfromflext_core.resultagain.src/flext_core/_utilities/settings.py#L23-L23: restorefrom flext_core.result import ralongside the protocol/type imports.src/flext_core/dispatcher.py#L12-L12: droprfrom the grouped root import and restorefrom flext_core.result import FlextResult as r.src/flext_core/loggings.py#L21-L21: droprfrom the grouped root import and source it fromflext_core.result(this module initializes earliest, so it is the most exposed).
#!/bin/bash
# Import order in the package root vs. submodules that import from it
rg -n '^(from|import) ' src/flext_core/__init__.py | head -60
rg -n 'from flext_core import' src/flext_core --type=py📍 Affects 5 files
src/flext_core/_result/composition.py#L9-L9(this comment)src/flext_core/_utilities/parser_coerce.py#L13-L13src/flext_core/_utilities/settings.py#L23-L23src/flext_core/dispatcher.py#L12-L12src/flext_core/loggings.py#L21-L21
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/flext_core/_result/composition.py` at line 9, Replace package-root
imports of c/r with their defining modules to avoid partially initialized
package access: in src/flext_core/_result/composition.py:9-9 import c from
flext_core._constants.errors; in
src/flext_core/_utilities/parser_coerce.py:13-13 retain c and m if already safe,
but source r from flext_core.result; in
src/flext_core/_utilities/settings.py:23-23 restore r from flext_core.result; in
src/flext_core/dispatcher.py:12-12 remove r from the grouped root import and
import FlextResult as r from flext_core.result; and in
src/flext_core/loggings.py:21-21 remove r from the grouped root import and
source it from flext_core.result.
| if cleanup: | ||
| try: | ||
| cleanup(resource) | ||
| except c.CATCHABLE_RUNTIME_EXCEPTIONS as exc: | ||
| return result_class.fail(str(exc), exception=exc) | ||
| return cls.fail(str(exc), exception=exc) | ||
| return result |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Cleanup failure masks the primary op failure.
If op already failed and cleanup then raises, the returned result carries only the cleanup error; the original error message, error_code, error_data, and exception are dropped.
🐛 Preserve the primary failure
if cleanup:
try:
cleanup(resource)
except c.CATCHABLE_RUNTIME_EXCEPTIONS as exc:
- return cls.fail(str(exc), exception=exc)
+ if result.failure:
+ return result
+ return cls.fail(str(exc), exception=exc)
return result📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if cleanup: | |
| try: | |
| cleanup(resource) | |
| except c.CATCHABLE_RUNTIME_EXCEPTIONS as exc: | |
| return result_class.fail(str(exc), exception=exc) | |
| return cls.fail(str(exc), exception=exc) | |
| return result | |
| if cleanup: | |
| try: | |
| cleanup(resource) | |
| except c.CATCHABLE_RUNTIME_EXCEPTIONS as exc: | |
| if result.failure: | |
| return result | |
| return cls.fail(str(exc), exception=exc) | |
| return result |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/flext_core/_result/composition.py` around lines 81 - 86, Update the
cleanup handling in the result composition flow so a cleanup exception does not
replace an already failed operation result. When `result` represents an `op`
failure, preserve its message, error code, error data, and exception; only
return the cleanup failure when the operation otherwise succeeded.
| @staticmethod | ||
| def require_error(source: p.FailureLike) -> str: | ||
| """Extract error message from any failed Result.""" | ||
| error = source.error | ||
| if not error: | ||
| msg = c.ERR_RESULT_FAILURE_MESSAGE_REQUIRED | ||
| raise ValueError(msg) | ||
| return error |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
require_error raises on legitimately-empty failure messages.
fail(None, ...) normalizes to error="" (line 110), and a bare exception (raise ValueError()) caught by map/flat_map/filter/tap/create_from_callable produces str(exc) == "" via cls.fail(str(exc), exception=exc). Any later require_error() call on such a failed result (used by from_failure, _from_result, and — per transforms.py — flat_map, map, map_error, fold, lash, tap_error, to_model) will then raise an unrelated ValueError instead of propagating the failure, breaking the railway chain's fail-safety guarantee.
🐛 Proposed fix
`@staticmethod`
def require_error(source: p.FailureLike) -> str:
"""Extract error message from any failed Result."""
error = source.error
- if not error:
+ if error is None:
msg = c.ERR_RESULT_FAILURE_MESSAGE_REQUIRED
raise ValueError(msg)
return error📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @staticmethod | |
| def require_error(source: p.FailureLike) -> str: | |
| """Extract error message from any failed Result.""" | |
| error = source.error | |
| if not error: | |
| msg = c.ERR_RESULT_FAILURE_MESSAGE_REQUIRED | |
| raise ValueError(msg) | |
| return error | |
| `@staticmethod` | |
| def require_error(source: p.FailureLike) -> str: | |
| """Extract error message from any failed Result.""" | |
| error = source.error | |
| if error is None: | |
| msg = c.ERR_RESULT_FAILURE_MESSAGE_REQUIRED | |
| raise ValueError(msg) | |
| return error |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/flext_core/_result/construction.py` around lines 22 - 29, Update
Result.require_error to allow legitimately empty failure messages, including
error="" produced by fail(None, ...) and str(exception) for bare exceptions.
Preserve failure propagation for downstream callers such as from_failure,
_from_result, and the transform methods by returning the normalized error value
without raising solely because it is empty.
| def test_service_execute_returns_success(self) -> None: | ||
| """A concrete FlextService.execute honors the r[None] contract.""" | ||
|
|
||
| class NoopService(FlextService[None]): | ||
| class NoopService(FlextService[bool]): | ||
| @override | ||
| def execute(self, **_kwargs: t.Scalar) -> p.Result[None]: | ||
| return r[None].ok(None) | ||
| def execute(self, **_kwargs: t.Scalar) -> p.Result[bool]: | ||
| return r[bool].ok(True) | ||
|
|
||
| outcome = NoopService().execute() | ||
| tm.that(outcome.success, eq=True) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Assert the new bool service payload.
The test double now returns r[bool].ok(True), but the test only checks success and absence of an error. It would still pass if execute() returned False; also update the docstring at Line 173 from r[None] to r[bool].
Proposed test fix
- """A concrete FlextService.execute honors the r[None] contract."""
+ """A concrete FlextService.execute honors the r[bool] contract."""
...
tm.that(outcome.success, eq=True)
+ tm.that(outcome.value, eq=True)
tm.that(outcome.error, none=True)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def test_service_execute_returns_success(self) -> None: | |
| """A concrete FlextService.execute honors the r[None] contract.""" | |
| class NoopService(FlextService[None]): | |
| class NoopService(FlextService[bool]): | |
| @override | |
| def execute(self, **_kwargs: t.Scalar) -> p.Result[None]: | |
| return r[None].ok(None) | |
| def execute(self, **_kwargs: t.Scalar) -> p.Result[bool]: | |
| return r[bool].ok(True) | |
| outcome = NoopService().execute() | |
| tm.that(outcome.success, eq=True) | |
| def test_service_execute_returns_success(self) -> None: | |
| """A concrete FlextService.execute honors the r[bool] contract.""" | |
| class NoopService(FlextService[bool]): | |
| `@override` | |
| def execute(self, **_kwargs: t.Scalar) -> p.Result[bool]: | |
| return r[bool].ok(True) | |
| outcome = NoopService().execute() | |
| tm.that(outcome.success, eq=True) | |
| tm.that(outcome.value, eq=True) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/integration/test_migration_validation.py` around lines 172 - 181,
Update test_service_execute_returns_success and its NoopService docstring to use
the r[bool] contract, changing the documented payload from r[None] to r[bool].
Add an assertion that outcome.value is True, while preserving the existing
success assertion.
| def test_map_returning_none_reports_success(self) -> None: | ||
| """``map`` producing ``None`` yields a success with a ``None`` payload.""" | ||
| """``map`` producing ``None`` is rejected and returns failure.""" | ||
| result: p.Result[None] = r[str].ok("x").map(lambda _: None) | ||
|
|
||
| assert result.success is True | ||
| assert result.failure is True | ||
| assert result.error is not None |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Align this test with the current map contract.
Based on src/flext_core/_result/transforms.py:82-93 and src/flext_core/_result/construction.py:147-150, mapping None currently returns a successful result carrying None. Lines 125-126 therefore assert the opposite behavior and will fail. Either change map/ok to reject None, or update this test to assert success and result.value is None.
Proposed test alignment
- def test_map_returning_none_reports_success(self) -> None:
- """``map`` producing ``None`` is rejected and returns failure."""
+ def test_map_returning_none_preserves_none_value(self) -> None:
+ """``map`` may produce a successful ``None`` payload."""
result: p.Result[None] = r[str].ok("x").map(lambda _: None)
- assert result.failure is True
- assert result.error is not None
+ assert result.success is True
+ assert result.value is None📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def test_map_returning_none_reports_success(self) -> None: | |
| """``map`` producing ``None`` yields a success with a ``None`` payload.""" | |
| """``map`` producing ``None`` is rejected and returns failure.""" | |
| result: p.Result[None] = r[str].ok("x").map(lambda _: None) | |
| assert result.success is True | |
| assert result.failure is True | |
| assert result.error is not None | |
| def test_map_returning_none_preserves_none_value(self) -> None: | |
| """``map`` may produce a successful ``None`` payload.""" | |
| result: p.Result[None] = r[str].ok("x").map(lambda _: None) | |
| assert result.success is True | |
| assert result.value is None |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/unit/test_result_recent_behaviors.py` around lines 121 - 126, Update
test_map_returning_none_reports_success to match the current map/ok contract:
assert the result is successful and verify result.value is None, while retaining
the existing mapping setup.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ci/docker/fedora.Dockerfile (1)
28-37: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winRestrict the setup soft-pass to the exact known lock boundary. Matching the generic string
flext-corecan hide unrelated bootstrap failures.
ci/docker/fedora.Dockerfile#L28-L37: replace the output substring check with a precise lock-boundary predicate.ci/docker/ubuntu.Dockerfile#L29-L38: use the same precise predicate.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ci/docker/fedora.Dockerfile` around lines 28 - 37, Restrict the setup soft-pass condition in ci/docker/fedora.Dockerfile lines 28-37 and ci/docker/ubuntu.Dockerfile lines 29-38 to a precise uv.lock/flext-core lock-boundary match, replacing the generic flext-core substring check. Keep unrelated setup failures propagating their original status in both Dockerfiles.
🧹 Nitpick comments (1)
Makefile (1)
398-401: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
status --porcelainalso trips on untracked files.Setup will hard-fail on any stray untracked file inside a managed gitlink (build outputs, editor scratch files), even though nothing tracked diverges. Consider restricting the dirty check to tracked changes.
♻️ Suggested narrowing
- if [ -n "$$(git -C "$$child_root" status --porcelain)" ]; then \ + if [ -n "$$(git -C "$$child_root" status --porcelain --untracked-files=no)" ]; then \ printf 'ERROR: %s: local changes must be reconciled before setup\n' "$$child_path" >&2; \ exit 1; \ fi; \🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Makefile` around lines 398 - 401, Update the dirty-check condition in the managed gitlink setup flow to detect only tracked modifications, excluding untracked files from the failure condition. Preserve the existing error message and exit behavior when tracked changes are present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ci/docker/alpine.Dockerfile`:
- Around line 16-17: Add the Alpine musl build dependencies with apk before the
rustup and mise installation steps: install gcc and musl-dev ahead of the RUN
command invoking rustup, while preserving the existing Rust toolchain and PATH
setup.
In `@ci/docker/fedora.Dockerfile`:
- Around line 16-19: Replace the mutable curl-piped installers in
ci/docker/fedora.Dockerfile lines 16-19 and ci/docker/ubuntu.Dockerfile lines
17-20 with pinned uv and Rustup artifacts downloaded at fixed versions and
verified against published checksums before installation; preserve the resulting
uv, Cargo, and mise shim PATH setup in both Dockerfiles.
In `@pyproject.toml`:
- Around line 304-309: Update the Pyrefly search-path configuration to avoid
invalid sibling paths during standalone CI checks. Either provision the
flext-cli, flext-infra, and flext-tests repositories before make check, or
conditionally include their src paths only when they exist, while preserving the
current paths when available.
---
Outside diff comments:
In `@ci/docker/fedora.Dockerfile`:
- Around line 28-37: Restrict the setup soft-pass condition in
ci/docker/fedora.Dockerfile lines 28-37 and ci/docker/ubuntu.Dockerfile lines
29-38 to a precise uv.lock/flext-core lock-boundary match, replacing the generic
flext-core substring check. Keep unrelated setup failures propagating their
original status in both Dockerfiles.
---
Nitpick comments:
In `@Makefile`:
- Around line 398-401: Update the dirty-check condition in the managed gitlink
setup flow to detect only tracked modifications, excluding untracked files from
the failure condition. Preserve the existing error message and exit behavior
when tracked changes are present.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 974c6f2e-9529-409a-bb93-1971132a6fa1
📒 Files selected for processing (13)
.envrc.github/workflows/ci-matrix.yml.github/workflows/ci.yml.gitignore.mise.toml.vscode/settings.jsonMakefileci/docker/alpine.Dockerfileci/docker/arch.Dockerfileci/docker/debian.Dockerfileci/docker/fedora.Dockerfileci/docker/ubuntu.Dockerfilepyproject.toml
| RUN curl -fsSL https://astral.sh/uv/install.sh | sh | ||
| # tokei (and any future cargo-backed mise tool) needs a Rust toolchain. | ||
| RUN curl -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain stable | ||
| ENV PATH="/root/.local/bin:/root/.cargo/bin:/root/.local/share/mise/shims:${PATH}" |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | grep -E '^ci/docker/(fedora|ubuntu)\.Dockerfile$' || true
for f in ci/docker/fedora.Dockerfile ci/docker/ubuntu.Dockerfile; do
if [ -f "$f" ]; then
echo "== $f =="
nl -ba "$f" | sed -n '1,80p'
fi
done
echo "== related usage =="
for f in ci/docker/fedora.Dockerfile ci/docker/ubuntu.Dockerfile; do
[ -f "$f" ] || continue
echo "== security-related lines in $f =="
rg -n 'curl |wget |sh -s|--fetch|checksum|sha|uv install|rustup.rs|sed -i|chmod|sudo|apt|dnf|apk|curl --insecure|-k|SKIP|curl .*curl|pip ' -- "$f" || true
doneRepository: flext-sh/flext-core
Length of output: 300
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for f in ci/docker/ubuntu.Dockerfile ci/docker/fedora.Dockerfile; do
if [ -f "$f" ]; then
echo "== outline-ish $f =="
awk '{printf "%4d: %s\n", NR, $0}' "$f" | sed -n '1,120p'
fi
done
echo "== relevant installer/security lines =="
awk '
/INSTALL_SOURCES|curl|wget|sh -s|--fetch|--default-toolchain|checksum|sha|uv install|rustup.rs|sed -i|chmod|sudo|apt|dnf|apk|curl --insecure|-k|--silent|--progress/{print FILENAME ":" FNR ":" $0}
' ci/docker/ubuntu.Dockerfile ci/docker/fedora.DockerfileRepository: flext-sh/flext-core
Length of output: 5059
Use reproducible, checksum-validated uv and Rust bootstraps. Both Dockerfiles execute mutable installer scripts directly from curl | sh, including uv and Rustup:
ci/docker/fedora.Dockerfile:16-18ci/docker/ubuntu.Dockerfile:17-19
Replace those with pinned artifacts using verified downloads/checksums instead of invoking remote scripts at build time.
📍 Affects 2 files
ci/docker/fedora.Dockerfile#L16-L19(this comment)ci/docker/ubuntu.Dockerfile#L17-L20
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ci/docker/fedora.Dockerfile` around lines 16 - 19, Replace the mutable
curl-piped installers in ci/docker/fedora.Dockerfile lines 16-19 and
ci/docker/ubuntu.Dockerfile lines 17-20 with pinned uv and Rustup artifacts
downloaded at fixed versions and verified against published checksums before
installation; preserve the resulting uv, Cargo, and mise shim PATH setup in both
Dockerfiles.
| search-path = [ | ||
| ".", | ||
| "src", | ||
| ".", | ||
| "../flext-cli/src", | ||
| "../flext-infra/src", | ||
| "../flext-tests/src", | ||
| "src", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for path in ../flext-cli/src ../flext-infra/src ../flext-tests/src; do
if [[ -d "$path" ]]; then
printf 'present: %s\n' "$path"
else
printf 'missing: %s\n' "$path"
fi
done
rg -n -C2 'search-path|flext-(cli|infra|tests)' pyproject.toml .github/workflows/ci.ymlRepository: flext-sh/flext-core
Length of output: 1541
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- ci workflow excerpt ---\n'
sed -n '1,220p' .github/workflows/ci.yml
printf '\n--- pyproject pyrefly excerpt ---\n'
sed -n '285,315p' pyproject.toml
printf '\n--- repo tooling / pyrefly docs ---\n'
rg -n 'pyrefly|make check|check\s*=|run\s*=|search-path|pyrefly' . -g '!pyproject.toml' -g '!README.md' || trueRepository: flext-sh/flext-core
Length of output: 248
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- ci workflow excerpt ---'
sed -n '1,220p' .github/workflows/ci.yml
printf '%s\n' ''
printf '%s\n' '--- pyproject pyrefly excerpt ---'
sed -n '285,315p' pyproject.toml
printf '%s\n' ''
printf '%s\n' '--- repo tooling / pyrefly docs references ---'
rg -n 'pyrefly|make check|check\s*=|run\s*=|search-path|pyrefly' . -g '!pyproject.toml' -g '!README.md' || trueRepository: flext-sh/flext-core
Length of output: 11317
🌐 Web query:
Pyrefly 1.1.1 search-path missing directory configuration
💡 Result:
In Pyrefly 1.1.1, the "search-path" configuration option is used to define the root directories from which the tool resolves imports [1][2]. When Pyrefly cannot find a specific directory or module, it is often because the project's import root is not correctly identified or configured [3][4]. To resolve missing directory or import path issues: 1. Explicit Configuration: You can manually set the search path in your project's configuration file (pyproject.toml or pyrefly.toml) under the [tool.pyrefly] section [1][5]. For example: [tool.pyrefly] search-path = ["."] 2. Understand Automatic Heuristics: Pyrefly automatically attempts to infer an "import root" based on your project structure (e.g., looking for a src/ directory or the presence of init.py files) [1][3]. If these heuristics are incorrectly identifying your project layout, you can override them by explicitly setting search-path [6][2]. 3. Disable Heuristics if Needed: If automatic search path discovery is causing conflicts, you can disable these heuristics by setting disable-search-path-heuristics = true in your configuration [1][2]. 4. Check Command-Line Usage: If you need to test a configuration change quickly, you can pass the --search-path flag via the command line (e.g., pyrefly check --search-path=.) to override the default import root [1][6]. If you are encountering errors stating that a module cannot be found, ensure that the path added to search-path points to the directory containing your package root, not just the directory containing the pyproject.toml file [3][4]. For further debugging, ensure that your site-package-path is correctly configured if you are working within a virtual environment [4].
Citations:
- 1: https://pyrefly.org/en/docs/configuration/
- 2: https://github.com/facebook/pyrefly/blob/b6dd8b08/website/docs/configuration.mdx
- 3: https://pyrefly.org/en/docs/import-resolution/
- 4: Could not find import of
dependency, looked in these locations (from config in/project/pyproject.toml) facebook/pyrefly#277 - 5: https://pyrefly.org/en/docs/installation/
- 6: Allow overriding import root facebook/pyrefly#671
🌐 Web query:
facebook pyrefly search-path missing directory error exit code
💡 Result:
When Pyrefly encounters a "missing directory" error—often manifesting as a "could not find import" diagnostic—it typically indicates that the tool's heuristic-based import resolution cannot locate your project files or dependencies [1][2]. Pyrefly commands, such as pyrefly check, return an exit code of 1 when configuration issues, missing files, or type errors are detected [3]. To resolve these errors, you can follow these steps: 1. Understand the Search Path Heuristics Pyrefly automatically adds certain directories (like src/) to your search path if they exist at the project root [1]. If your project structure deviates from these defaults, or if you need to include additional directories, you must manually configure the search-path [4][5]. 2. Configure search-path You can define explicit search paths in your pyproject.toml (under [tool.pyrefly]) or a pyrefly.toml file [5][6]: [tool.pyrefly] search-path = ["src", "."] If you need to disable Pyrefly's default path-guessing behavior to avoid conflicts, use the following configuration [7][4]: [tool.pyrefly] disable-search-path-heuristics = true search-path = ["."] 3. Verify Dependencies and Interpreter If the missing directory involves third-party packages, ensure your site-package-path is correctly configured or that Pyrefly is pointed to the correct Python interpreter [2][8]. You can check this by running python -c "import site; print(site.getsitepackages())" to verify where your packages are installed [8]. 4. CLI Override For quick testing or CI environments, you can override the configuration via the command line [5][3]: pyrefly check --search-path path/to/your/dir If you continue to see errors, verify the exact error message provided by Pyrefly, as it will often explicitly list the locations it checked, helping you identify if the issue is a missing directory, a misconfigured path, or an incorrect environment setting [2][8].
Citations:
- 1: https://pyrefly.org/en/docs/import-resolution/
- 2: https://pyrefly.org/en/docs/error-kinds/
- 3: https://deepwiki.com/facebook/pyrefly/4-command-line-interface
- 4: https://github.com/facebook/pyrefly/blob/b6dd8b08/website/docs/configuration.mdx
- 5: https://pyrefly.org/en/docs/configuration/
- 6: https://pyrefly.org/en/docs/IDE/
- 7: Local imports broken when outside main project src facebook/pyrefly#1239
- 8: Could not find import of
dependency, looked in these locations (from config in/project/pyproject.toml) facebook/pyrefly#277
🌐 Web query:
"pyrefly" "search-path" "does not exist" configuration
💡 Result:
In Pyrefly, a "does not exist" error related to the search-path configuration occurs when a directory specified in your configuration file or via command-line arguments cannot be found on the filesystem [1][2][3]. When you provide an invalid path to search-path, Pyrefly will issue a warning or error message—often formatted as Invalid --search-path: [path] does not exist—to notify you that the specified location is unreachable [1][2]. To resolve this issue, you should: 1. Verify the path: Check the directory path provided in your configuration file (e.g., pyrefly.toml) or command-line flag [2][3]. Ensure there are no typos and that the directory exists relative to your project root or as an absolute path [4]. 2. Check configuration location: If using a relative path, remember that Pyrefly resolves these paths based on the location of your configuration file [4]. 3. Debugging: You can use pyrefly dump-config to inspect how Pyrefly is currently interpreting your configuration and resolving paths [2][3]. If you wish to allow Pyrefly to operate without strict enforcement of all provided search paths or if you are encountering issues with automatic path resolution, you may want to review the disable-search-path-heuristics setting in your configuration, which controls how Pyrefly automatically constructs the search path [4][5][6].
Citations:
- 1: https://github.com/facebook/pyrefly/blob/b1e40b2d/test/errors.md
- 2: https://github.com/facebook/pyrefly/blob/b1e40b2d/test/config.md
- 3: https://github.com/facebook/pyrefly/blob/b6dd8b08/test/config.md
- 4: https://pyrefly.org/en/docs/configuration/
- 5: https://github.com/facebook/pyrefly/blob/b1e40b2d/crates/pyrefly_config/src/config.rs
- 6: https://github.com/facebook/pyrefly/blob/b6dd8b08/crates/pyrefly_config/src/config.rs
Keep Pyrefly search paths valid in CI.
The sibling paths ../flext-cli/src, ../flext-infra/src, and ../flext-tests/src are absent in standalone checks. Either provision/checkout those repos before make check, or conditionally omit these entries so Pyrefley does not fail when they are missing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pyproject.toml` around lines 304 - 309, Update the Pyrefly search-path
configuration to avoid invalid sibling paths during standalone CI checks. Either
provision the flext-cli, flext-infra, and flext-tests repositories before make
check, or conditionally include their src paths only when they exist, while
preserving the current paths when available.
Managed surfaces (.envrc, .mise.toml, CI matrix, docker images, Makefile, pyproject) regenerated by the current flext-infra conform SSOT and adopted as-is: the generated header moved from the retired 'workspace sync' owner to 'flext-infra codegen conform'.
A concurrent merge reintroduced the retired 'github:gastownhall/beads' 1.1.2 pin, whose binary only knows Dolt schema v53 and fails every conform preflight against the shared v61 mro ledger. Regenerated from the flext-infra SSOT (toolchain.beads: go module commit 423afdcb, reported_version 1.1.0) instead of hand-editing the projection.
The returns library is fully exterminated, but _validate_success_value survived it. That guard existed solely for the returns convention (introduced by f607749 as "T cannot be None (returns convention)"), so it kept rejecting a None payload after its only justification was deleted, breaking r[None].ok(None) at 34 call sites across 7 packages. Drop the guard and the last returns import, assign the payload directly, and narrow it at the single assignment point. Success with no payload is now representable; failure still leaves _payload unset, so the two states stay distinguishable. test_map_returning_none_reports_success asserted the opposite of its own name: map() never special-cased None, the failure was the guard raising inside ok() and being swallowed by the broad except. Corrected to the observed contract.
There was a problem hiding this comment.
Pull request overview
This PR advances the 0.12.0-dev line by refactoring flext_core’s result system into a single covariant p.Result protocol with a concrete r[T] implementation (and None as a valid success payload), while also regenerating project tooling/CI surfaces (Makefile, pyproject, workflows, docker CI matrix) to match the new release environment.
Changes:
- Refactors
FlextResultinternals intosrc/flext_core/_result/and updates protocols/typings to removeResultLikein favor ofp.Result. - Updates utilities and enforcement/project-metadata helpers to use the new result and metadata boundaries.
- Regenerates dev tooling and CI (Make surface, workflows, docker matrix, editor + env files) for
0.12.0-dev.
Reviewed changes
Copilot reviewed 93 out of 105 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_version.py | Adjusts subclass-creation test. |
| tests/unit/test_utilities_project_metadata.py | Removes now-obsolete document default tests. |
| tests/unit/test_utilities_project_metadata_read.py | Updates result contract wording. |
| tests/unit/test_service_registration_spec.py | Adds casts for typed registration records. |
| tests/unit/test_result.py | Adds None-payload success tests. |
| tests/unit/test_result_recent_behaviors.py | Updates recent result behavior expectations. |
| tests/unit/test_result_laws.py | Adds explicit result type annotations. |
| tests/unit/test_result_chain_helpers.py | Adds explicit result type annotations. |
| tests/unit/test_result_callables_fold.py | Adds explicit result/value type annotations. |
| tests/unit/test_models_base_full_coverage.py | Small hash implementation tweak. |
| tests/unit/test_loggings_full_coverage.py | Migrates ResultLike → Result. |
| tests/unit/test_handler_decorator_edges.py | Updates middleware dump expectation. |
| tests/unit/test_enforcement_namespace_part_02.py | Adds explicit typed local variable. |
| tests/unit/test_deprecation_warnings.py | Adds explicit result type annotations. |
| tests/unit/test_coverage_loggings.py | Migrates ResultLike → Result. |
| tests/protocols.py | Exposes SuccessCheckable alias. |
| tests/integration/test_system.py | Updates result typing in integration tests. |
| tests/integration/test_migration_validation.py | Updates service example payload typing. |
| tests/integration/test_integration.py | Adds explicit result type annotations. |
| tests/integration/test_documented_patterns.py | Adds explicit result type annotations. |
| tests/integration/test_architecture.py | Adds explicit scan result annotations. |
| tests/base.py | Refactors test service base typing. |
| src/flext_core/service.py | Adjusts service generic parameter definition. |
| src/flext_core/result.py | Rebuilds FlextResult facade on new parts. |
| src/flext_core/loggings.py | Switches to facade r import. |
| src/flext_core/dispatcher.py | Switches to facade r import. |
| src/flext_core/_utilities/settings.py | Switches to facade r import. |
| src/flext_core/_utilities/project_metadata.py | Refactors metadata read/build boundary. |
| src/flext_core/_utilities/parser_coerce.py | Switches to facade r import. |
| src/flext_core/_utilities/model_runtime.py | Refactors local variable naming/typing. |
| src/flext_core/_utilities/mapper.py | Switches to facade r import. |
| src/flext_core/_utilities/handler.py | Fixes context variable usage clarity. |
| src/flext_core/_utilities/dispatcher_execute.py | Migrates ResultLike → Result checks. |
| src/flext_core/_utilities/config.py | Switches to facade r import. |
| src/flext_core/_utilities/args.py | Switches to facade r import. |
| src/flext_core/_utilities/_mapper_access_parts/mapper_access_part_01.py | Tightens local result typing. |
| src/flext_core/_utilities/_guards_type_protocol_types.py | Updates protocol union to Result. |
| src/flext_core/_utilities/_enforcement_collect_parts/enforcement_collect_part_01.py | Refactors enforcement project resolution. |
| src/flext_core/_utilities/_checker_parts/checker_part_03.py | Switches to facade r import. |
| src/flext_core/_utilities/_checker_parts/checker_part_02.py | Switches to facade r import. |
| src/flext_core/_typings/services.py | Expands service registration typing. |
| src/flext_core/_settings.py | Adjusts settings field declaration. |
| src/flext_core/_runtime/_dependency_bindings.py | Updates DI wiring API usage. |
| src/flext_core/_result/unwrap.py | Updates unwrap semantics for None payload. |
| src/flext_core/_result/transforms.py | New transforms layer for result. |
| src/flext_core/_result/construction.py | New construction/factory layer for result. |
| src/flext_core/_result/composition.py | Refactors composition ops onto new layers. |
| src/flext_core/_result/behavior.py | New dunder/behavior layer for result. |
| src/flext_core/_result/base.py | New internal base model for result. |
| src/flext_core/_result/init.py | New result package initializer. |
| src/flext_core/_result_parts/transforms.py | Removes legacy result mixin transforms. |
| src/flext_core/_result_parts/construction.py | Removes legacy result mixin construction. |
| src/flext_core/_result_parts/behavior.py | Removes legacy result mixin behavior. |
| src/flext_core/_result_parts/init.py | Removes legacy result parts package init. |
| src/flext_core/_protocols/result.py | Consolidates protocols to single Result. |
| src/flext_core/_protocols/handler.py | Updates handler return contracts to Result. |
| src/flext_core/_protocols/_result_parts/flextprotocolsresult_part_04.py | Removes legacy protocol split file. |
| src/flext_core/_protocols/_result_parts/flextprotocolsresult_part_03.py | Removes legacy protocol split file. |
| src/flext_core/_protocols/_result_parts/flextprotocolsresult_part_02.py | Removes legacy protocol split file. |
| src/flext_core/_protocols/_result_parts/flextprotocolsresult_part_01.py | Removes legacy protocol split file. |
| src/flext_core/_models/handler.py | Serializes middleware types deterministically. |
| src/flext_core/_exceptions/_factories_parts/flextexceptionsfactories_part_04.py | Updates result type references. |
| src/flext_core/_exceptions/_factories_parts/flextexceptionsfactories_part_03.py | Updates result type references. |
| src/flext_core/_exceptions/_factories_parts/flextexceptionsfactories_part_02.py | Updates result type references. |
| src/flext_core/_exceptions/_factories_parts/flextexceptionsfactories_part_01.py | Updates lazy result type resolution. |
| src/flext_core/_decorators/_railway.py | Switches to facade r import. |
| src/flext_core/version.py | Improves homepage parsing robustness. |
| pyproject.toml | Updates deps + tools + pytest/ruff/pyright config. |
| Makefile | Regenerated canonical make surface. |
| examples/typings.py | Migrates ResultLike → Result. |
| examples/ex_04_flext_dispatcher.py | Updates handler signatures to r[T]. |
| examples/_models/ex00.py | Updates example domain result typing. |
| ci/docker/ubuntu.Dockerfile | Adds Ubuntu clean-machine docker build. |
| ci/docker/fedora.Dockerfile | Adds Fedora clean-machine docker build. |
| ci/docker/debian.Dockerfile | Adds Debian clean-machine docker build. |
| ci/docker/arch.Dockerfile | Adds Arch clean-machine docker build. |
| ci/docker/alpine.Dockerfile | Adds Alpine clean-machine docker build. |
| .vscode/settings.json | Updates editor excludes + env discovery. |
| .python-version | Switches to 3.13 family pin. |
| .mise.toml | Regenerated toolchain pins for 0.12.0-dev. |
| .gitignore | Replaces restrictive ignore policy with generated ignores. |
| .github/workflows/ci.yml | Updates CI workflow for 0.12.0-dev. |
| .github/workflows/ci-matrix.yml | Adds cross-distro CI matrix workflow. |
| .envrc | Regenerated direnv activation for standalone repo. |
| .beads/README.md | Removes Beads README (repo-local). |
| .beads/metadata.json | Removes repo-local beads metadata. |
| .beads/issues.jsonl | Repo-local beads data file touched. |
| .beads/interactions.jsonl | Repo-local beads data file touched. |
| .beads/embeddeddolt/beads/.dolt/temptf/dolt_embedded_metrics | Removes embedded dolt metrics artifact. |
| .beads/embeddeddolt/beads/.dolt/repo_state.json | Removes embedded dolt repo state. |
| .beads/embeddeddolt/beads/.dolt/noms/nbs_manifest_3630928294 | Removes embedded dolt manifest. |
| .beads/embeddeddolt/beads/.dolt/noms/manifest | Removes embedded dolt manifest file. |
| .beads/embeddeddolt/beads/.dolt/noms/LOCK | Embedded dolt lock file touched. |
| .beads/embeddeddolt/beads/.dolt/config.json | Removes embedded dolt config. |
| .beads/config.yaml | Removes repo-local beads config. |
| .beads/backup/manifest | Removes beads backup manifest. |
| .beads/backup/LOCK | Beads backup lock file touched. |
| .beads/backup/backup_state.json | Removes beads backup state. |
| .beads/.gitignore | Removes beads-local ignore file. |
Suppressed comments (1)
src/flext_core/_utilities/_enforcement_collect_parts/enforcement_collect_part_01.py:115
_project()calls_owning_project_root()(which can now raiseRuntimeError) and re-raises on pyproject read errors. Since_namespace_items()calls_project()without a try/except, these RuntimeErrors can crash enforcement collection instead of skipping the target (consistent with the function’s... | Nonecontract).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Operator contract (mro-e9j0.6 C7): setup PROVISIONS tooling only — mise, | ||
| # venv, dependencies. It never generates, conforms, or mutates project code; | ||
| # `make gen` (APPLY=Y) is the single public conformance/generation surface. |
| if TYPE_CHECKING: | ||
| from tests.protocols import p | ||
|
|
||
|
|
||
| class TestsFlextServiceBase[TDomainResult: t.JsonPayload | t.SequenceOf[t.JsonPayload]]( | ||
| tests_s[TDomainResult] | ||
| class TestsFlextServiceBase[TDomainResult: p.Base = p.Base]( |
| try: | ||
| document = upm.read_project_document_cached(project_root) | ||
| except (OSError, ValueError) as exc: | ||
| raise RuntimeError(_ERR_ENFORCEMENT_NAMESPACE_METADATA) from exc |
There was a problem hiding this comment.
16 issues found across 105 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="ci/docker/ubuntu.Dockerfile">
<violation number="1" location="ci/docker/ubuntu.Dockerfile:23">
P1: A compromise or changed response from any installer endpoint becomes root code execution during CI image builds. Pin verified release artifacts and validate checksums/signatures before installation.</violation>
<violation number="2" location="ci/docker/ubuntu.Dockerfile:36">
P1: Local ignored files are baked into the image because the complete build context is copied with no `.dockerignore`. This can expose developer credentials/configuration to image consumers; add an allowlist or at least exclude VCS metadata, env files, and local tool state.</violation>
</file>
<file name="src/flext_core/_result/base.py">
<violation number="1" location="src/flext_core/_result/base.py:67">
P2: String-backed `success` input can create inconsistent result state: `success="false"` becomes `self.success is False`, but this raw-value branch stores `value` and never stores `exception`. Branch on Pydantic's validated `self.success` so payload/exception follow the exposed status.</violation>
</file>
<file name="src/flext_core/_result/construction.py">
<violation number="1" location="src/flext_core/_result/construction.py:26">
P2: Cloning a valid empty-message failure currently raises `ValueError`: `fail(None)` produces `error == ""`, but this truthiness check rejects it. Preserve empty strings so `from_failure(r.fail(None))` remains a failed result rather than breaking error propagation.</violation>
</file>
<file name="Makefile">
<violation number="1" location="Makefile:706">
P3: `make status` cannot diagnose a fresh or broken environment: it now exits at `_builtin_require_environment` before printing status. Leave this read-only diagnostic target runnable without a venv.</violation>
</file>
<file name=".mise.toml">
<violation number="1" location=".mise.toml:14">
P2: Python version pinned to `"3.13"` (floating) instead of the previous exact `"3.13.11"`. This means mise will resolve to whatever the latest 3.13.x patch is at install time, which can differ across environments and CI runs. Different patch versions may introduce subtle behavioral differences, making environment-dependent bugs harder to reproduce.</violation>
</file>
<file name="src/flext_core/_result/transforms.py">
<violation number="1" location="src/flext_core/_result/transforms.py:40">
P2: Transforms crash or replace a valid `fail(None)` result instead of propagating/recovering it. Avoid `require_error` in these instance failure paths; pass the normalized error string so empty-error failures retain their error metadata and carried exception.</violation>
</file>
<file name="ci/docker/fedora.Dockerfile">
<violation number="1" location="ci/docker/fedora.Dockerfile:22">
P2: Image builds execute whatever `mise.run` serves at build time as root, making this CI artifact non-reproducible and exposing the build to installer-endpoint compromise. Pin a release artifact and verify its checksum/signature before execution.</violation>
<violation number="2" location="ci/docker/fedora.Dockerfile:27">
P2: Rust tooling can change or be compromised independently of this repository because the mutable rustup installer and `stable` channel run during every build. Pin and verify the installer/toolchain used for the image.</violation>
</file>
<file name="src/flext_core/_typings/services.py">
<violation number="1" location="src/flext_core/_typings/services.py:99">
P2: Concrete-message free-function handlers now fail static checking when passed to `register_handler` or assigned to `DispatchableHandler`, despite being the supported routed-handler pattern. Keep this callable arm variadic (or make the alias generic over the routed message type) so handlers such as `def handler(command: CreateCommand)` remain registerable.</violation>
</file>
<file name="src/flext_core/_utilities/project_metadata.py">
<violation number="1" location="src/flext_core/_utilities/project_metadata.py:60">
P2: A pyproject without `[project]` now succeeds as fabricated `unknown`/`0.0.0` package metadata, so callers cannot distinguish a non-package workspace from valid PEP 621 metadata. Preserve the prior failure in `read_project_metadata` (or make `project` optional) rather than inventing a `Project`.</violation>
</file>
<file name="src/flext_core/_utilities/dispatcher_execute.py">
<violation number="1" location="src/flext_core/_utilities/dispatcher_execute.py:31">
P2: Handlers returning a non-`r` implementation of the advertised `p.Result` contract are rejected before this branch runs. Normalize `p.Result` values as results too, so structural result handlers preserve success/failure outcomes.</violation>
</file>
<file name="pyproject.toml">
<violation number="1" location="pyproject.toml:721">
P2: Example files can now violate module naming and executable-shebang checks without CI reporting them. This blanket example-tree suppression conflicts with the repository’s required tool coverage; keep these checks enabled and fix or narrowly justify individual files instead.</violation>
</file>
<file name="src/flext_core/result.py">
<violation number="1" location="src/flext_core/result.py:18">
P3: The explicit base list repeats the complete inheritance chain already supplied by `FlextResultUnwrap`. Keeping only that base preserves the same public methods while avoiding a fragile, needlessly complex MRO.</violation>
<violation number="2" location="src/flext_core/result.py:29">
P3: Direct `FlextResult(..., error_data=ConfigMap_or_model_dump_carrier)` calls now fail type checking despite remaining supported by the constructor implementation and factory API. Preserve the public mapping/model-input annotation so direct construction retains its established contract.</violation>
</file>
<file name="src/flext_core/_protocols/result.py">
<violation number="1" location="src/flext_core/_protocols/result.py:24">
P1: Public protocol aliases disappear from `p`, so existing annotations/imports such as `p.ResultLike[...]` fail at evaluation and the public-API contract no longer matches. Preserve these protocol names (or update every supported consumer as an intentional breaking API change) while consolidating the implementation.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| # End SECTION: managed tool bootstrap | ||
|
|
||
| WORKDIR /workspace | ||
| COPY . . |
There was a problem hiding this comment.
P1: Local ignored files are baked into the image because the complete build context is copied with no .dockerignore. This can expose developer credentials/configuration to image consumers; add an allowlist or at least exclude VCS metadata, env files, and local tool state.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At ci/docker/ubuntu.Dockerfile, line 36:
<comment>Local ignored files are baked into the image because the complete build context is copied with no `.dockerignore`. This can expose developer credentials/configuration to image consumers; add an allowlist or at least exclude VCS metadata, env files, and local tool state.</comment>
<file context>
@@ -0,0 +1,60 @@
+# End SECTION: managed tool bootstrap
+
+WORKDIR /workspace
+COPY . .
+
+# === SECTION: mise install (managed) ===
</file context>
| # Source: config:python_version, template (installer URLs) | ||
| # mise installs the supported Python 3.13 family. | ||
| # uv is supplied by the managed environment without a project patch pin. | ||
| RUN curl -fsSL https://mise.run | sh |
There was a problem hiding this comment.
P1: A compromise or changed response from any installer endpoint becomes root code execution during CI image builds. Pin verified release artifacts and validate checksums/signatures before installation.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At ci/docker/ubuntu.Dockerfile, line 23:
<comment>A compromise or changed response from any installer endpoint becomes root code execution during CI image builds. Pin verified release artifacts and validate checksums/signatures before installation.</comment>
<file context>
@@ -0,0 +1,60 @@
+# Source: config:python_version, template (installer URLs)
+# mise installs the supported Python 3.13 family.
+# uv is supplied by the managed environment without a project patch pin.
+RUN curl -fsSL https://mise.run | sh
+# uv is intentionally supplied by the caller environment; install it explicitly
+# in clean-machine images so the project bootstrap can resolve dependencies.
</file context>
| python = "3.13.11" | ||
| uv = "0.11.32" | ||
| # Deploy toolchain (single source: Infra.codegen.toolchain in codegen.yaml). | ||
| python = "3.13" |
There was a problem hiding this comment.
P2: Python version pinned to "3.13" (floating) instead of the previous exact "3.13.11". This means mise will resolve to whatever the latest 3.13.x patch is at install time, which can differ across environments and CI runs. Different patch versions may introduce subtle behavioral differences, making environment-dependent bugs harder to reproduce.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .mise.toml, line 14:
<comment>Python version pinned to `"3.13"` (floating) instead of the previous exact `"3.13.11"`. This means mise will resolve to whatever the latest 3.13.x patch is at install time, which can differ across environments and CI runs. Different patch versions may introduce subtle behavioral differences, making environment-dependent bugs harder to reproduce.</comment>
<file context>
@@ -1,14 +1,24 @@
-python = "3.13.11"
-uv = "0.11.32"
-# Deploy toolchain (single source: Infra.codegen.toolchain in codegen.yaml).
+python = "3.13"
+# Native toolchain (single source: Infra.codegen.toolchain in codegen.yaml).
kubectl = "1.32.0"
</file context>
| python = "3.13" | |
| python = "3.13.11" |
| FlextResultTransformsMixin[T], | ||
| FlextResultUnwrapMixin[T], | ||
| class _FlextResult[T]( | ||
| FlextResultUnwrap[T], |
There was a problem hiding this comment.
P3: The explicit base list repeats the complete inheritance chain already supplied by FlextResultUnwrap. Keeping only that base preserves the same public methods while avoiding a fragile, needlessly complex MRO.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/flext_core/result.py, line 18:
<comment>The explicit base list repeats the complete inheritance chain already supplied by `FlextResultUnwrap`. Keeping only that base preserves the same public methods while avoiding a fragile, needlessly complex MRO.</comment>
<file context>
@@ -2,200 +2,60 @@
- FlextResultTransformsMixin[T],
- FlextResultUnwrapMixin[T],
+class _FlextResult[T](
+ FlextResultUnwrap[T],
+ FlextResultComposition[T],
+ FlextResultTransforms[T],
</file context>
| self, | ||
| error_code: str | None = None, | ||
| error_data: tb.JsonMapping | ts.ConfigModelInput | None = None, | ||
| error_data: JsonDict | None = None, |
There was a problem hiding this comment.
P3: Direct FlextResult(..., error_data=ConfigMap_or_model_dump_carrier) calls now fail type checking despite remaining supported by the constructor implementation and factory API. Preserve the public mapping/model-input annotation so direct construction retains its established contract.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/flext_core/result.py, line 29:
<comment>Direct `FlextResult(..., error_data=ConfigMap_or_model_dump_carrier)` calls now fail type checking despite remaining supported by the constructor implementation and factory API. Preserve the public mapping/model-input annotation so direct construction retains its established contract.</comment>
<file context>
@@ -2,200 +2,60 @@
self,
error_code: str | None = None,
- error_data: tb.JsonMapping | ts.ConfigModelInput | None = None,
+ error_data: JsonDict | None = None,
*,
value: T | None = None,
</file context>
| @$(UV_RUN) $(PROJECT_NAME) $(ARGS) | ||
|
|
||
| _builtin_status_diagnostics: | ||
| _builtin_status_diagnostics: _builtin_require_environment |
There was a problem hiding this comment.
P3: make status cannot diagnose a fresh or broken environment: it now exits at _builtin_require_environment before printing status. Leave this read-only diagnostic target runnable without a venv.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Makefile, line 706:
<comment>`make status` cannot diagnose a fresh or broken environment: it now exits at `_builtin_require_environment` before printing status. Leave this read-only diagnostic target runnable without a venv.</comment>
<file context>
@@ -210,80 +386,361 @@ _builtin_help_usage:
@$(UV_RUN) $(PROJECT_NAME) $(ARGS)
-_builtin_status_diagnostics:
+_builtin_status_diagnostics: _builtin_require_environment
@printf 'profile=%s\nattached=%s\nproject=%s\nruntime=%s\n' \
'$(MAKE_PROFILE)' '$(ATTACHED_MEMBER)' '$(PROJECT_ROOT)' '$(RUNTIME_ROOT)'
</file context>
| _builtin_status_diagnostics: _builtin_require_environment | |
| _builtin_status_diagnostics: |
FlextService declared aliases but not validate_by_name, so constructing any service with its declared field name (e.g. workspace_root= for the workspace alias) was rejected by static analysis: 299 unexpected-keyword errors across flext-infra. Runtime already accepted it via a subclass model_config, which hid the contract gap.
pydantic.computed_field has no zero-argument overload, so `@m.computed_field()` failed no-matching-overload under static analysis. The bare decorator is the documented form.
…e-commit, make, docker)
Regenerated stale managed projections (ci workflows, Dockerfiles, Makefile, .gitignore, pyproject managed sections) to match current flext-infra templates/config via make gen WHAT=all APPLY=Y. Refs mro-xf56.
Remove stray blank line after # [MANAGED] section markers so deps-modernize and codegen-conform agree on a single fixed point. Refs mro-xf56.
The managed pyproject projection was missing the blank line the canonical generator emits after each '# [MANAGED]' marker, so 'make gen WHAT=check' reported drift from a clean clone. Regenerated through the canonical generator, never hand-edited; a second generator run is byte-identical (idempotent fixed point). Refs: mro-wkii.17.39
flext c9832249/81cc760ad inserted a blank line after each '# [MANAGED]' marker. That was a regression: the canonical emitter appends the marker immediately before its section (deps/phases/inject_comments.py:173-182, out.append(marker) then out.append(line)) and _collapse_blank_lines only removes duplicates -- it never inserts one. So the generator's fixed point has NO blank line, and the committed projection permanently disagreed with it, keeping 'make gen WHAT=check' red on 32 pyproject files with no tree state able to satisfy it. Reverted by running the canonical modernizer.conform_source over each projection, never by hand. Refs: mro-shxw
Co-authored-by: Cursor <cursoragent@cursor.com>
|



Summary by cubic
Unified the result system on a covariant
p.Resultwith a concreter[T]facade, removedResultLike, allowedNoneas a success payload, and tightened protocols, handlers, DI, and utilities. Regenerated CI/tooling (incl. multi-distro matrix) and excluded a standaloneuvcycle.Refactors
p.Resultcovariant; removedResultLike; updated handlers/protocols/utilities/tests to usep.Result; factories return concreter[T].src/flext_core/_protocols/result.py; moved internals tosrc/flext_core/_result/(base/behavior/construction/transforms/composition/unwrap); widenedlash/recover/flow_through; simplifiedmap_or; clarified value/unwrap errors; allowedNonepayloads.dependency_injector.wiring.wire; serialized middleware withmp.PlainSerializer; service registration accepts class refs;FlextServicevalidates by field name and alias.@computed_fieldusage and exposed as staticmethod facades; normalizedSettings.log_level; hardened project metadata parsing and homepage resolution.CI and Tooling
ci-matrixand Dockerfiles; expanded blocking CI push branches todev,develop, and0.12.0-dev.pyproject.toml; standardized Python3.13; addedast-grep,gitleaks,tokei,taplo,pyright; addedsgconfig.yml; excluded standaloneuvcycle..beads/; refreshed.envrc,.gitignore,.vscode; simplified.github/dependabot.yml; scopedAGENTS.mdto project rules.Written for commit 9236a21. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes
Chores