Skip to content

feat(service): protocol ports, validated runtime seeds and typed runtime hook (V8 S1) - #499

Merged
marlon-costa-dc merged 4 commits into
0.12.0-devfrom
feat/v8-s1-service-ports
Sep 26, 2026
Merged

marlon-costa-dc merged 4 commits into
0.12.0-devfrom
feat/v8-s1-service-ports

Conversation

@marlon-costa-dc

@marlon-costa-dc marlon-costa-dc commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Slice S1 of plan V8 (epic flext-4jtcb, bead flext-4jtcb.1; ADR-019 proposed in flext-sh/flext#274). It makes the service contract's dependency ports real in the kernel and deletes the dead runtime paths.

  • Ports. t.Port[P] = Annotated[P, SkipJsonSchema()]. A service field name: t.Port[p.X] = m.Field(exclude=True, ...) is validated by isinstance on construction and on assignment, and never enters the JSON Schema. FlextService.__pydantic_on_complete__ rejects a port type that is not a plain Protocol class (subscripted generic, concrete class) with c.ERR_SERVICE_PORT_TYPE; Pydantic itself rejects a Protocol that is not runtime-checkable.
  • Runtime. m.ServiceRuntime collaborators and m.RuntimeBootstrapOptions are validated ports. The x seeds runtime_settings and initial_context drop SkipValidation for t.Port[p.X | None]; settings_type and settings_overrides leave the schema, so model_json_schema() of any service works and lists only data.
  • Hook. u.resolve_runtime_options is a typed match over an options model or a component: the base's runtime_bootstrap_options is read through p.RuntimeBootstrapProvider (not declared on x, so no @override sweep), instance seeds win, any other source raises TypeError. No getattr overlay, no attribute probes, no model_copy(update=).
  • Builder. u.build_service_runtime uses the container's context and command bus; a dispatcher that cannot be resolved raises with its cause instead of becoming None.
  • Deleted, with zero uses in the fleet (validation workspace grep): the RuntimeBootstrapOptions fields services, factories, resources, container_overrides, wire_*, subproject and registry; ServiceRuntime.registry (which removes the registry↔runtime cycle); FlextRegistry.configure_runtime, create(runtime=) and the dead _create_initial_runtime; build_registry(runtime=); service_settings_type; _normalize_runtime_override_mapping; resolve_wire_targets; p.CloneableRuntime; the orphan tests/unit/_golden_public_api.json.
  • Failures. r.unwrap() and .value raise from the carried exception; __exit__ is typed.
  • Docs. docs/guides/service-patterns.md is rewritten for the contract. The stale dependency_injector_prompt.md and improvements/dependency-injection-audit.md are deleted, and overview.md and dependency-injection-advanced.md are aligned.
  • Projections. Regenerated by make gen and locks written by make upg with the current flext-infra.

Validation

  • Runtime through the public API: a port service accepts a real adapter and rejects a non-conforming value on construction and assignment; the schema lists only data; the hook sets the settings class and a seed overrides it; unwrap() carries __cause__; the registry builds without recursion.
  • Lane gates on 4f367dc0c, run with env -u VIRTUAL_ENV -u UV_PROJECT_ENVIRONMENT:
    • make gen exit 0 twice. make gen on the committed candidate leaves git status --porcelain --untracked-files=all empty (fixed point).
    • make fix and make fmt exit 0.
    • make check: lint, pyrefly, pyright, mypy (252 s), markdown, security, smells, loc-cap, layout, tier-whitelist, index-declarations, canonical-alias, direnv and deferred-self-reference all at 0. The only red is silent-failure 2 (below).
    • make test-full exit 0: the incremental phase is a testmon cache hit (0 changed files), then 2709 passed with warnings as errors, including the 17 new port and bootstrap tests.
  • Base red not caused by this PR: silent-failure 2 in _utilities/_beartype/_helpers_parts/helpers_part_01.py:33,93 (ImportError and NameError branches returning a sentinel). The same findings are in the fleet baseline at c47ea7d79. Their owner is lane flext-edcqq, whose uncommitted refactor (owner-aware alias resolution with new modules) is the fix; it is not portable as a hunk. The three unwrap_or(sentinel) test findings from the same baseline are fixed here by porting that lane's hunks byte-identically.
  • Fleet non-breakage runs in the V8 validation workspace before this leaves draft.

🤖 Generated with Claude Code


Summary by cubic

Implements slice S1 of the V8 service plan: dependency ports are now real in the kernel, the runtime hook is typed, and dead runtime paths and the registry↔runtime cycle are removed.

New Features

  • t.Port[P] validates a service dependency with isinstance on construction and assignment and never leaks it into the JSON Schema; non-Protocol or subscripted port types are rejected at class creation.
  • m.RuntimeBootstrapOptions and m.ServiceRuntime collaborators are validated ports; runtime_settings and initial_context seeds drop SkipValidation.
  • u.resolve_runtime_options is a typed match where instance seeds win and unknown sources raise TypeError.
  • u.build_service_runtime builds from the container's context and command bus; unresolvable dispatchers raise with their cause.
  • Result.unwrap() and Result.value raise with the carried exception as __cause__.

Refactors

  • PEP 695 alias evaluation is now owner-aware and source-backed (_beartype.type_aliases + module_source): a TYPE_CHECKING-only alias becomes a typed m.DeferredAlias, enforcement Report exposes report.complete for deferral-safe inspection, lazy_alias_suffixes propagates import failures, and facade lookup runs only for loaded packages so enforcement never imports packages as a side effect — clearing the two silent-failure findings in helpers_part_01.py.
  • Removed all runtime fields and methods with zero fleet uses: services, factories, resources, container_overrides, wire_*, subproject, registry; plus ServiceRuntime.registry, configure_runtime, create(runtime=), build_registry(runtime=), service_settings_type, resolve_wire_targets, and p.CloneableRuntime.
  • Rewrote service-patterns.md for the ADR-019 contract; deleted the stale DI prompt and audit docs and aligned overview/advanced guides.
  • Toolchain is frozen via committed mise.version and mise.lock; make upg resolves and locks at flext-infra 8c0c20eca and the rope 1.14.0+dc.2 fork, the projected Makefile drops .WAIT so GNU Make 4.3 runs make setup, workspace members resolve the workspace runtime, and CI passes the token only through BuildKit secrets.

Written for commit ebbe6f0. Summary will update on new commits.

Review in cubic

Marlon Costa and others added 2 commits September 25, 2026 19:54
…yped hook

t.Port[P] Annotated SkipJsonSchema; ServiceRuntime collaborators as
validated ports; runtime seeds t.Port[p.X | None]; settings_type out of
the JSON schema; RuntimeBootstrapProvider protocol hook with match-typed
resolution (unknown source raises TypeError); dead runtime options and
their reads removed after zero-use proof; model_validate replaces
model_copy(update=) on runtime assembly; unwrap chains the carried
exception. mise.version recorded via make upg; gen fixed point.
Rewrite tests/unit/test_service_bootstrap.py against the public contract:
option resolution (none, model passthrough, hook decides settings_type,
instance seed wins, context seed), runtime bound to the container context
and command bus, ports (real adapter accepted, non-conforming value rejected
on construction and assignment, fetch_global of a port service raises,
schema lists only data fields, subscripted and concrete port types rejected
at class creation). unwrap and .value carry __cause__. Port the flext-edcqq
lane's fix for the three unwrap_or(sentinel) test findings byte-identical.

Docs: rewrite docs/guides/service-patterns.md for the ADR-019 contract,
delete the stale dependency_injector_prompt.md and
improvements/dependency-injection-audit.md, align overview.md and
dependency-injection-advanced.md, update examples/ex_11. Delete the orphan
tests/unit/_golden_public_api.json (no reader since 6fd8045).

Projections regenerated by make gen and locks written by make upg with the
current flext-infra generator.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comment thread tests/protocols.py Fixed
Comment thread src/flext_core/_protocols/service.py Fixed
…ade check

Adopt the flext-edcqq lane's introspection repair (uncommitted in
~/fleet-closure-lanes/core-regen/flext-core, branch
fix/core-introspection-contract-20260925): PEP 695 alias values resolve
through FlextUtilitiesBeartypeTypeAliases with an explicit owner, a
deferred alias is a typed m.DeferredAlias instead of a swallowed NameError,
and lazy_alias_suffixes lets import failures propagate. This clears the two
silent-failure findings in _beartype/_helpers_parts/helpers_part_01.py.

The class visitor consults a package's lazy exports only when the package
is loaded: the import that created a real class already loaded its package,
so a class whose package is not loaded is synthetic and declares no facade.
Enforcement no longer imports packages as a side effect.

Protocol stubs with a docstring drop the redundant ellipsis (CodeQL
py/ineffectual-statement on PR #499). Projections and uv.lock regenerated
by make gen with flext-infra b75fd83dd.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@marlon-costa-dc
marlon-costa-dc marked this pull request as ready for review September 25, 2026 23:47
marlon-costa-dc added a commit to flext-sh/flext-infra that referenced this pull request Sep 26, 2026
…on the host make (#867)

## Summary

Unblocks every CI that runs `make setup` with the current generator, and
makes the superproject CI able to run member gates (V8 S0 /
flext-sh/flext#274, beads `flext-x8gn6`, `flext-4jtcb.8`).

- **`.WAIT` removed (all repos red at setup).** `_bootstrap_setup_tools`
used `.WAIT`, a GNU Make 4.4 token. `make setup` first runs on the
runner's GNU Make 4.3, before Mise installs make 4.4.1, and fails with
`No rule to make target '.WAIT'`. That failure is in this repo's own tip
CI (c298e4e) and in flext-sh/flext-core#499. `.NOTPARALLEL:
_bootstrap_setup_tools` keeps the credential check ahead of the Mise pin
check on every GNU Make release.
- **Members inside a workspace use the workspace runtime (`flext-x8gn6`,
operator law 2026-09-24).** Every member renders `MAKE_PROFILE :=
standalone`, and the `REPOSITORY_ROOT` isolation skipped the physical
superproject for that profile. So a submodule member resolved its own
`.venv`, and the superproject CI failed all 31 members with 'missing
environment interpreter'. `REPOSITORY_ROOT` now always comes from the
physical Git superproject; only `GEN_INIT_ONLY` keeps the Makefile's own
root. The generated `.envrc` resolves the same root for `VENV_DIR` and
the Git and Mise ceilings. A standalone clone or linked worktree has no
superproject and keeps its own runtime; measured: `git rev-parse
--show-superproject-working-tree` is empty in a linked worktree and
returns the workspace for a submodule.
- **#866 integration red repaired.** The merge resurrected the rope
monkeypatch that 8ece05a retired for the fork `1.14.0+dc.2`
(`_rope/pep695_patch.py` plus its protocols and resolvers). It was
applied nowhere and failed lint with 14 SLF001 findings; this PR
completes the cutover. The fork carries the PEP 695 handlers (measured);
the PEP 701 occurrence search is not in the fork and was already
inactive. In `nesting_types.py`, a scope without a declaring module now
raises (pyrefly bad-argument-type), and the visitor declares `@override`
methods (N815, missing-override).

## Validation

- New test `tests/unit/codegen/test_codegen_make_member_runtime.py`. A
rendered member checked out as a submodule of a real superproject
resolves `RUNTIME_ROOT`, `UV_PROJECT` and `RUNTIME_VENV` from the
superproject. The same fixture without a superproject keeps its own.
- Lane gates: `make gen` exit 0, `make fix` and `make fmt` exit 0, `make
check` exit 0 (all gates OK). The base tip failed lint 17 and pyrefly 4.
- Runtime proof for `.WAIT` on GNU Make 4.3: this PR's CI setup step on
the GitHub runner.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes `make setup` run on the host's older GNU Make and makes workspace
members share the workspace runtime instead of their own `.venv`,
unblocking CI for regenerated repositories and member gates.

**Bug Fixes**
- Replaced `.WAIT` with `.NOTPARALLEL` so the credential check still
precedes the Mise pin check on GNU Make 4.3, which treated `.WAIT` as a
missing target.
- Submodule members previously resolved their own `.venv`;
`REPOSITORY_ROOT` and the generated `.envrc` now resolve the Git
superproject runtime, while standalone clones and linked worktrees keep
their own.

**Refactors**
- Completed the cutover away from the retired rope monkeypatch (the fork
carries PEP 695 handlers) and removed its protocols and resolvers.
- `nesting_types.py` raises when a scope has no declaring module and
declares `@override` handlers, fixing lint and pyrefly failures.

<sup>Written for commit 0f31573.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/flext-sh/flext-infra/pull/867?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
marlon-costa-dc added a commit to flext-sh/flext-infra that referenced this pull request Sep 26, 2026
## Summary

`make upg` locks `npm:prettier` platform-independently by clearing
`mise_lockfile_platforms`. But the runner still exported
`MISE_LOCKFILE_PLATFORMS=` (empty), and mise 2026.9.14 rejects that with
`Invalid platform format ''`. So `make upg` failed in every regenerated
repository, including the flext-core S1 lane (flext-sh/flext-core#499,
which needs `upg` to pick up #867).

The variable is now passed only when it names platforms (`${var:+...}`,
the idiom the recipe already uses for passthrough variables). The
template contract test is updated.

## Validation

- Runtime: `make upg` in this repository completes; stage
`lock-npm-prettier` exits 0. This PR commits the locks that run
refreshed.
- `make gen` and `make check` exit 0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes `make upg` failing when locking `npm:prettier`
platform-independently. The runner exported an empty
`MISE_LOCKFILE_PLATFORMS=`, which mise 2026.9.14 rejects; the variable
is now only passed when it names platforms. Bumps mise to 2026.9.14 and
refreshes lockfiles.

<sup>Written for commit d8c54c5.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/flext-sh/flext-infra/pull/868?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
…NU Make 4.3)

make upg pins flext-infra at 8c0c20eca (flext-sh/flext-infra#867 and #868)
and the rope fork 1.14.0+dc.2; make gen projects the Makefile without .WAIT,
so the CI runner's GNU Make 4.3 can run make setup, and members inside a
workspace resolve the workspace runtime.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@marlon-costa-dc
marlon-costa-dc merged commit d65ba48 into 0.12.0-dev Sep 26, 2026
8 of 10 checks passed
@marlon-costa-dc
marlon-costa-dc deleted the feat/v8-s1-service-ports branch September 26, 2026 00:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant