V0.31 Scope - Downstream Discovery Task Bridge#
Status: COMPLETE (v0.31.0 release close)
v0.31.0 closed the downstream discovery task bridge. Release conclusion (recorded at release close):
downstream_discovery_task_bridge
The v0.31 arc delivered exactly what this scope document froze — the executable PySINDy PDELibrary task runner (v0.31b1), the diagnostic-only WeakPDELibrary wrapper (v0.31b2), a temporary PySINDy 1.x compatibility policy (v0.31b3), a public JSON-only example (v0.31c), and an adversarial-audit setuptools cap (v0.31c1). No new report schema was introduced; no root export was added; no WSINDy or noise-robustness claim was made. See docs/releases/V0_31_RELEASE_READINESS.md for the full release-close ledger.
Historical scope-freeze record (kept for provenance)#
v0.31 is the downstream-discovery task-bridge release. It designs a narrow, submodule-only bridge from canonical PDELie objects into PySINDy’s PDELibrary (and, as a diagnostic-only wrapper, WeakPDELibrary), records a stable TaskResult schema for the composed task output, and freezes what stays out of scope.
The first executed slice is the design-only sub-release v0.31a, which adds documents, configs, and audit tests without modifying any runtime code, adding any new optional dependency, or bumping the package version. v0.31a is design-only; runtime lands in v0.31b+.
Release conclusion (recorded by v0.31a):
downstream_discovery_task_bridge_design_only
Sequencing#
Per the current planning agreement recorded in docs/planning/ROADMAP.md, v0.31 sequences before v0.30.1: the discovery task bridge delivers the larger user-facing scientific delta, while the submodule-only symmetry-method registry MVP is smaller and can follow. In particular, SymmetryCandidate wrapper is v0.30.1 responsibility not v0.31 — no SymmetryCandidate contract or wrapper lands in this release.
Stable Intent#
v0.31 widens the downstream-discovery surface from the existing narrow bridge (pdelie.discovery.to_pysindy_trajectories, pdelie.discovery.fit_pysindy_discovery) to a small task layer that composes canonical PDELie inputs, PySINDy’s PDE-form libraries, and PDELie’s existing recovery / residual reporting into one stable JSON-compatible artifact.
Two user paths are unlocked by the runtime that this scope freezes:
PySINDy
PDELibrarybridge (periodic-only in v0.31):fit_pysindy_discoveryaccepts a caller-suppliedpysindy_modelconfigured with aPDELibraryand adifferentiation_methodcompatible with PDELie’s canonical scalar 1D periodic layout. The scope-frozen policy for this milestone is: PySINDy PDELibrary bridge is periodic-only in v0.31; FD-nonperiodic extension is explicitly deferred. The v0.30cfinite_differencebackend does not become a supported PySINDy-side derivative source in this release. Runtime enforcement is two-layered: the existingto_pysindy_trajectoriesgate atsrc/pdelie/discovery/pysindy_bridge.py:27-28continues to reject nonperiodic fields, and v0.31b runtime adds apdelie.tasks.discoveryentry-point BC guard that raisesPySINDyDiscoveryUnsupportedBoundaryErrorbefore assembling PySINDy trajectories. Both layers are required becausefit_pysindy_discoveryaccepts raw trajectory arrays and does not consult boundary metadata — bridge-only enforcement leaves a hole for callers who assemble trajectories directly. The composedTaskResultrecordspysindy_bridge_variant = "periodic_only_v1"so a future FD-nonperiodic bridge variant (v0.32.5 target) can be distinguished at read time without a schema-version bump.WeakPDELibrarydiagnostic wrapper: an optional wrapper that composes PySINDy’sWeakPDELibraryoutput into a PDELie-side diagnostic report. The wrapper is diagnostic-only — it is not a public weak derivative backend, not a WSINDy design-matrix layer, not a claim of weak-form supportability, and not a replacement for the existingpdelie.residuals.weak_1dslice.
The composed task output is a TaskResult payload (design in docs/design/DISCOVERY_TASK_RESULT_SCHEMA.md) with summary_type = "discovery_task_result" and summary_schema_version = "0.1".
Scope#
The v0.31 release scope is:
a new submodule
pdelie.tasks.discoverythat composes canonical FieldBatch inputs, PySINDy PDE-library fitting, and PDELie recovery/residual reporting into a stableTaskResultartifactloosening of
pdelie.discovery.fit_pysindy_discoveryto accept a caller-suppliedpysindy_model(currently rejected asconfig != Noneatsrc/pdelie/discovery/pysindy_adapter.py:196-204), routed through the existing periodic-onlyto_pysindy_trajectoriesbridgea
WeakPDELibrarydiagnostic wrapper withsummary_type = "pdelie_weak_pde_library_diagnostic"carryingdiagnostic_only: trueand using method/test-function/quadrature identifier strings distinct from the pdelie-nativeweak_1dpathan additive supportability-policy update that adds
supports_pysindy_weak_library_diagnosticand re-scopessupports_weak_derivative_backendto explicitly cover the public strong-derivative-only pdelie-native path while noting that the WeakPDELibrary wrapper is a diagnostic-scope weak derivative backendrelease-gate consolidation via a row in
configs/release_gate_manifest.jsonreplayed bytests/test_release_gates.py— the v0.31 release-gate is a row in configs/release_gate_manifest.json and not a new tests/test_v0_31_release_gate.py file, following the v0.30f consolidation pattern
The v0.31 deliverables, design-frozen in v0.31a and implemented from v0.31b onward:
pdelie.tasks.discoveryskeleton (run_pysindy_pde_taskor similar; final name pinned in v0.31b design)fit_pysindy_discovery(config=...)config loosening; the existingScopeValidationErrorgate is narrowed to a runtime schema-validation gateTaskResultschema runtime under strict JSON (_validate_strict_json_compatible, mirroringsrc/pdelie/reporting/summaries.py:1311and:1954)WeakPDELibraryDiagnosticwrapper, submodule-only (pdelie.tasks.discovery, notpdelie.residuals)supportability_policydict update covering both bullet points above
Deferred Scope#
Explicit non-goals (the scope-freeze test asserts every phrase is present):
no root API — no root
pdelie.run_discovery_task, no rootpdelie.fit_pysindy_pde_task, no rootpdelie.TaskResult, no rootpdelie.WeakPDELibraryDiagnostic, no rootpdelie.SymmetryCandidate, no rootpdelie.SymmetryMethod, no rootpdelie.discover_symmetriesno WSINDy implementation — v0.31 does not add a WSINDy design matrix, a weak sparse recovery layer, or an SR3-style weak solver
no weak nonperiodic — the v0.30 nonperiodic readiness surface stays strong-form-only; no nonperiodic weak residuals in v0.31
no noise robustness claim — v0.31 does not certify robustness of discovery to additive noise;
pdelie.data.add_gaussian_noiseremains an ingestion helper, not a discovery-side robustness gateno clean/noisy gate — v0.31 does not add a policy that gates a discovery TaskResult on clean-vs-noisy inputs
no external dataset benchmark claim — v0.31 does not claim recovery on any external dataset; readiness reports and TaskResult are configured evidence, not benchmarks
no PDEBench support claim — external-dataset readiness cookbooks remain a
v0.32scopeno The Well support claim — same as above
no multi-channel — TaskResult carries
input_layout = "scalar_1d_uniform"as a first-class field so v0.34a-c multi-channel widening does not retrofit the schema, but multi-channel dispatch itself is out of v0.31no 2D — the canonical
('batch','time','x','var')layout remains the sole supported layoutscalar 1D only — every v0.31 code path assumes a single scalar variable
no promotion of lint/typecheck/coverage to blocking in v0.31 — the v0.30e advisory jobs stay advisory
no LieGG / trained-model extraction in v0.31 — deferred to
v0.35ano multi-channel or 2D FieldBatch dispatch in v0.31 — deferred to
v0.34no SymmetryCandidate contract in v0.31 — deferred to
v0.30.1(submodule-only symmetry-method registry MVP)no symmetry-method registry in v0.31 — the
pdelie.symmetry.SymmetryMethodregistry MVP +SymmetryCandidatewrapper contract freeze both land inv0.30.1, sequenced after v0.31 per the ROADMAPno PyPI or TestPyPI publication — Git-tag-only through the
v0.xseries
Additional retention:
weak_1d retained through v0.32 close; removal contingent on the v0.31 PDELibrary bridge shipping a documented replacement path AND the WeakPDELibrary diagnostic wrapper landing a validated parity harness with a documented O((dx)^p) tolerance.
TaskResult Schema (Designed in v0.31a)#
The composed task output has summary_schema_version = "0.1" and summary_type = "discovery_task_result". The full field-by-field design is documented in docs/design/DISCOVERY_TASK_RESULT_SCHEMA.md. Summary:
task_name: strbackend_name: Literal["pysindy"](Literal expansion is v0.32+)backend_version: dict[str, str]with required keyspysindy,sklearn,pdelietarget_convention: Literal["pde_library", "weak_pde_library"]derivative_backend: str— promoted fromfit_config.pysindy_model.differentiation_method, referencing the v0.30cspectral_fd/finite_differencedispatchinput_layout: Literal["scalar_1d_uniform"](reserved enum for v0.34+ multi-channel/2D expansion)library_feature_names: list[str](renamed fromlibrary_termsfor continuity withsummarize_discovery_resultatsrc/pdelie/discovery/contracts.py:395)selected_terms: dict[str, dict[str, float]](verbatim fromequation_termsof the embeddeddiscovery_result)coefficients: dict | None(optional; opt-in shape, not required)support_precision: float,support_recall: float,support_f1: float,exact_support: bool,coefficient_relative_l2: floattrain_residual: dict | None,heldout_residual: dict | None(both strict-numeric{size, l2_norm, rms, max_abs}when present, matching the normative shape from_residual_summary_or_noneatsrc/pdelie/discovery/contracts.py:198-214)weak_contract: dict | None(non-null ifftarget_convention == "weak_pde_library"; carriesmethod_family,test_function_family,quadrature_rule,diagnostic_only: true)warnings: list[str]underlying_discovery_result: dict(embeddedsummarize_discovery_resultpayload; sibling wrapper, not parent/child)
The composed payload MUST pass json.loads(json.dumps(payload, allow_nan=False)) == payload before return, via _validate_strict_json_compatible(payload, name="discovery_task_result summary") — mirroring src/pdelie/reporting/summaries.py:1311 and :1954. Only 2 of 14 current summarize_* functions enforce allow_nan=False; TaskResult must not inherit the assumption of strict-JSON safety from the permissive _summary_payload funnel.
WeakPDELibrary Wrapper (Designed in v0.31a)#
The wrapper composes PySINDy’s WeakPDELibrary output into a PDELie diagnostic report with:
summary_type = "pdelie_weak_pde_library_diagnostic"method_family = "pysindy_weak_pde_library_polynomial_gauss_v1"(distinct from the pdelie-nativeweak_1dvalue"local_separable_quartic_bump_trapezoid_v1"atsrc/pdelie/residuals/weak_1d.py:20)test_function_familydistinct from the pdelie-native"separable_quartic_bump_beta"atsrc/pdelie/residuals/weak_1d.py:22quadrature_ruledistinct from the pdelie-native"composite_tensor_product_trapezoidal_native_window"atsrc/pdelie/residuals/weak_1d.py:21explicit
"diagnostic_only": truemarker so downstream tooling cannot mistake the wrapper for a supportability claim
The three pdelie-native identifier strings are recorded here so any future WeakPDELibrary-wrapper TaskResult does not accidentally collide with them; there is no enum or allowlist gating these strings today, so provenance disambiguation is the design’s responsibility.
Supportability Policy Update (Designed in v0.31a)#
The supportability-policy dict gains one new key and one re-scoping note:
supports_pysindy_weak_library_diagnostic: True— records that the WeakPDELibrary wrapper is available as a diagnostic-only surfacesupports_weak_derivative_backendis re-scoped to “public strong-derivative-only pdelie-native path” with an explicit note that WeakPDELibrary is a diagnostic-scope weak derivative backend, not a public weak derivative backend
Both are additive; no existing public field is removed.
Retention Window#
weak_1d retained through v0.32 close; removal contingent on the v0.31 PDELibrary bridge shipping a documented replacement path AND the WeakPDELibrary diagnostic wrapper landing a validated parity harness with a documented O((dx)^p) tolerance.
Milestones#
M0: scope freeze — COMPLETE (in v0.31a; this release)
M1:
pdelie.tasks.discoveryskeleton +fit_pysindy_discoveryconfig loosening — DESIGN COMPLETE in v0.31a, IMPLEMENTATION DEFERRED to v0.31bM2: TaskResult schema runtime + strict-JSON adversarial test — DESIGN COMPLETE in v0.31a, IMPLEMENTATION DEFERRED to v0.31b
M3: WeakPDELibrary diagnostic wrapper — DESIGN COMPLETE in v0.31a, IMPLEMENTATION DEFERRED to v0.31b (contingent on the installed PySINDy version exposing
WeakPDELibrary)M4: supportability-policy dict update — DESIGN COMPLETE in v0.31a, IMPLEMENTATION DEFERRED to v0.31b
M5: release-gate consolidation — CONFIRMED as manifest row (no new tests/test_v0_31_release_gate.py file), IMPLEMENTATION at v0.31 release close (v0.31 proper)
Release Gate (v0.31 close)#
The v0.31 release-gate is a row in configs/release_gate_manifest.json replayed by tests/test_release_gates.py, not a new tests/test_v0_31_release_gate.py file. This follows the v0.30f consolidation pattern: no standalone per-version release-gate file is added; the declarative content becomes a manifest row alongside the existing 18 rows.
v0.31a Sub-Release Gate#
v0.31a is complete when:
this scope document is in place and required phrases are present
the design document
docs/design/DISCOVERY_TASK_RESULT_SCHEMA.mdis in place and required schema fields are documentedconfigs/planning/v0_31_discovery_task_bridge_scope.jsonis present and strictly JSON-compatible (allow_nan=False)docs/planning/ROADMAP.mdrecordsv0.31adocs/planning/PLAN.mdrecordsv0.31awith the decision labeldocs/specs/API_STABILITY.mdcontains the “Decision-only note for the frozenv0.31a” subsectiontests/test_v0_31_discovery_task_bridge_scope.pypassestests/test_discovery_task_result_schema.pypasses with the NaN adversarial testthe full test suite still passes
no file under
src/pdelie/is modifiedno version bump in
pyproject.tomlno new optional dependency added
no new CI job added