docs(plan): plan V8 service base and ADR-019 (proposed) - #274
Conversation
Version the operator-approved plan V8 (FlextService with Protocol ports and typed operations, API and CLI derived from the service, fail-loud kernel) in docs/plans/2026-09-25-v8-flext-service-base/ and propose ADR-019 for the service contract: t.Port fields validated by isinstance and excluded from serialization, api.py as the single composition root, lazily discovered operations, CLI routes derived through flext-cli, and cause-preserving failures. Execution is tracked under epic flext-4jtcb (S0: flext-4jtcb.8). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Foreign red registered, not suppressed: the required |
|
ALHEIO-RED registered (V8 F0/S0, bead flext-4jtcb): the blocking codemod failure (5596 |
…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. -->
…ime hook (V8 S1) (#499) ## 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](https://claude.com/claude-code) <!-- This is an auto-generated description by cubic. --> --- ## 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. <sup>Written for commit ebbe6f0. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/flext-sh/flext-core/pull/499?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. -->
Every member was regenerated on flext-infra 4563c04ac (member runtime contract flext-x8gn6) with make upg locks on flext-core 080c81b17 / flext-cli ce36f45d / flext-tests 7dd55ef, and merged into its 0.12.0-dev with required checks green. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…v8/fleet-validation
…ith upg, fix root gates - Root projections regenerated with flext-infra 74249c4bd (member runtime contract, lazy-init election from the project's own chain): root `make gen` leaves all 31 members clean and is byte-identical on rerun. - Root `make upg` writes the superproject mise.lock, mise.version and uv.lock (the upg verb had never been propagated to the root). - Markdown gate: #271's formatted plan/lane-contract docs adopted; long lines/headings in the 09-22 plans and the 0.12 checkpoint rewrapped; V8 plan + ADR-019 formatted by `make fmt`/`make docs`. - silent-failure: check_changed_projects.py unwraps the command result so a failed run raises with its cause instead of returning a sentinel. - pyrefly: redundant int()/bool() conversions removed. WIP: the root layout gate still flags the parallel `codemod/` rename engine; it is removed once its campaigns land in flext-infra as rule data. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… core - Remove the superproject's parallel CSV rename engine (codemod/ + `make codemod RULE=… APPLY=Y`): flext-infra owns renames (FlextInfraApplyRenames inside `make mod`, campaigns as rule data per #881). Safe-deleted (mv to ignored .bak, deletion staged); the unported cli-prefixes/cacophony rows stay recoverable from 9a8f437 until each owning package renames first. custom.mk keeps pre-docs. - Pin flext-core to 4a43d674 (#503: lazy loader without private import probes), validated with the flext-cli and flext-api consumer suites. Fleet `make check` in the full workspace: exit 0, all 32 projects green. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merges 73cb90e. Every conflicted member pin on the wip side is an ancestor of the lane pin, so the lane pins stay; flext-target-oracle-wms moves to f3bff92, which records the primary's unpushed member commits (flext-target-oracle-wms#115). Generated projections (.sonarcloud.properties, .mise.toml, .beads/config.yaml) are the make gen output; wip hand-edits to them belong at their generator owner. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Preserve the local recovery checkpoint and incoming root history. Resolve member gitlinks to current 0.12.0-dev histories; incoming phase-1 generated-only commits remain reachable through the merge parent and are superseded by the current generation owners. Preserve target-oracle-wms staged locks in its recovery merge ancestry.
# Conflicts: # flext-cli # flext-core # flext-infra # flext-target-oracle-wms # flext-tests
…nd no foreign red Operator rulings of 2026-09-26: pure DI is definitive (S2b and compose removed, bead .9 superseded, D3 decided); modules stay within 200 logical lines (supersedes D-CAP 1000); selector-free root Make verbs are the only execution and evidence surface; a red has no foreign category (R8 superseded). Records S1 as merged (flext-core #499, d65ba487f), the integration SHAs of #502-#504, the parallel build of S2/S3 from one tip, and the 2026-09-26 make mod findings joining S8. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Pull request was converted to draft
Local pre-push gate before any PR, zero test baseline, timeouts with slowness treated as a defect, one source of truth per fact, no Pydantic model-construction helpers, and Pydantic-2-native validation inside models with logic in utilities. E9 lands only after the pre-push gate. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…odel declaration, SOLID, StrEnum) Data flows as m.* models typed by p.* protocols under CA and DI; a model is declared once and reused as is or by inheritance/composition; SOLID removes duplication and misplaced methods; closed value sets are StrEnum members in c used directly and as the Literal source. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every stable, locally green increment is committed, pushed, CI-confirmed and merged --no-ff promptly; lanes merge the integration tip before each push and consumers move to the new tips in the same cycle. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… tip) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion tips Gitlink conflicts resolved to each member's freshly fetched 0.12.0-dev tip (proved: every prior local pin is an ancestor). The superproject tip pinned 27 members at unmerged fix/phase1-wave-20260924 [WIP] generated-projection commits (2026-09-24 generator); those are superseded by each member's later CI-green regeneration and remain intact on their remote branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…with member tips Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ifest SSOT flext-infra 9cae2bd8a made ProjectSpec.dependency_revisions required, so this manifest (the only one carrying a project block) failed WorkspaceManifestSpec validation and every is_fleet_umbrella/scope build on the root raised. Declare the empty mapping the removed default supplied: members resolve from the workspace, not from pinned provider revisions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…f the V8 rules Adds §0 mapping each principle to its blocking pre-push check and the laws that apply it, single-sources the law numbering (R1-R33) for every copy of the plan, adds the one-Rope-cycle rule and the test budget (10 s per test, 60 s justified slow case, 120 s suite), and aligns R25 with that budget and a 300 s ceiling for gate verbs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-R26 08 records the measured state at the end of session 5f6ecb1d, the mandatory runbook order, the open findings (fmt drift, Sonar scope, test-full reds, markdown fences on 13 members), and the pending operator decisions. R23-R26 record the operator's 2026-09-26 laws: pydantic model-creation helpers are exterminated (models reused AS IS by inheritance/composition), every flow uses models and Protocols (CA/DI), StrEnum owns literals and constants on the c facade, and the landing cadence is short with local validation before every push.
…docs/v8-service-base-plan # Conflicts: # docs/plans/2026-09-25-v8-flext-service-base/04-rules.md
Adopts the concurrent stabilization lane (421d89a). Its content already matches this lane except flext-target-oracle-wms, pinned at 78ee31c4d (their reconciliation of the preserved member locks; descends from the member tip). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Consolidated lanes into this PR (fast-forwards only, no force): it now carries the primary |
…an docs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…docs/v8-service-base-plan # Conflicts: # docs/plans/2026-09-25-v8-flext-service-base/04-rules.md
…docs/v8-service-base-plan
|




Summary
Versions the operator-approved plan V8 and proposes ADR-019, the fleet's service contract:
docs/plans/2026-09-25-v8-flext-service-base/: index, evidence (file:line), V7 review, normative contract, rules R1–R22, phases S0–S10, verification, and a mini-guide for other sessions.docs/architecture/adr/019-service-contract-ports-operations.md(PROPOSED), with ports ast.Port[p.X](validated byisinstance, excluded from serialization),api.pyas the single composition root, lazily discovered typed operations, CLI routes derived through flext-cli, and cause-preserving failures.docs/architecture/adr/README.md: index entry.Tracking: epic
flext-4jtcb, slice S0flext-4jtcb.8.Validation
make checkin the lane (~/flext-work/v8-docs/flext): markdown gate[OK] 0 errors. The check report has no finding on any file this PR adds or changes.ec666f2c25fails the same way.codemodreports 5596facade-base-by-class-namefindings under the pinned flext-infra09cfb4dea. The flext-infra tip makes those findings observational and family-scoped (e10ec3ffb,6e3467c4d). The gitlink bump is owned byflext-itpd1.3..venv(flext-x8gn6).flext-7kb38.🤖 Generated with Claude Code
Summary by cubic
Versions the operator-approved plan V8 for the FLEXT service base, proposes ADR-019 for the fleet's service contract, and rolls the V8 wave toolchain work into the root.
t.Port[p.X]fields validated byisinstanceand excluded from serialization,api.pyas the single composition root, lazily discovered typed operations, CLI routes derived throughflext-cli, and cause-preserving failures.flext-core#499.0.12.0-dev; declaresdependency_revisions: {}in the workspace manifest, now required by the pinned fleet toolchain.Refactors
make setupinstalls from the committedmise.lock/mise.version/uv.lock, andmake upgwrites those locks.codemod/,make codemod) sinceflext-infraowns renames, and pinsflext-coreto the lazy-loader tip validated against theflext-cliandflext-apiconsumer suites.Written for commit 9f72fe2. Summary will update on new commits.