Skip to content

Release 3.54.0: required-behavior gates + Core Rust support - #515

Merged
mbinder45 merged 32 commits into
mainfrom
develop
Oct 6, 2026
Merged

mbinder45 merged 32 commits into
mainfrom
develop

Conversation

@ssmith-synaptixs

Copy link
Copy Markdown
Contributor

Summary

Promotes develop to main for the 3.54.0 release.

  • Required-behavior gates (SSPN-116): a project opts in via .spine/required-behavior.yaml — checks the model does not author and cannot edit away, re-verified after every refinement as a fourth independently-budgeted check in sdlc feature's native loop. Closes the ONTM-4 gap where a generated test could pass without exercising a feature's real default wiring. A legacy/token-only project without a manifest takes the exact refine() path it took before — additive, not a branch. Merged via PR #514.
  • Core Rust support (comprehension + Cargo-aware codegen/build/test), signed off for supported host environments across PR #509, PR #511, and PR #512 (installed-parser grammar fix). See the Core release evidence.
  • Two stale-doc gaps fixed while cutting this release, not caused by it: the Rust comprehension CHANGELOG entry was misfiled under the already-shipped 3.53.0 section instead of Unreleased, and capability-matrix.md's header plus gap4-adoption-distribution-roadmap.md's workflow tag were still stamped 3.52.0 from two releases ago.

Test plan

  • Full local gate green pre-push: ruff format --check ., mypy src tests (828 files), full pytest suite (5519 passed, 13 skipped, 51 deselected)
  • All five generated-artifact --check gates green: mcp-tools.py, matrix-count.py, state-numbers.py, both SVG renderers
  • orchestrator pkg accuracy --check — 0 gated regressions
  • orchestrator pkg verify — 0 errors
  • scripts/sdlc_shapes.py — all 4 repository shapes hold
  • orchestrator understand . — episteme builds clean (not committed; regenerates post-merge per .github/workflows/episteme.yml)
  • CI green on develop push (ea8579a9 → check, Dependency audit, CodeQL, Episteme)
  • Code-owner review + security scan check on this promotion PR

🤖 Generated with Claude Code

Synaptixs and others added 30 commits October 4, 2026 23:35
Generated by .github/workflows/episteme.yml; the knowledge base is derived from
the tree, not authored, and is regenerated after merge so branches never carry
it and never conflict over it.
… with 8 updates

Bumps the production-minor-patch group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [fastapi](https://github.com/fastapi/fastapi) | `0.141.1` | `0.142.2` |
| [types-aiobotocore-s3](https://github.com/youtype/mypy_boto3_builder) | `3.9.1` | `3.9.2` |
| [temporalio](https://github.com/temporalio/sdk-python) | `1.33.0` | `1.34.0` |
| [sqlglot](https://github.com/tobymao/sqlglot) | `30.18.0` | `30.21.0` |
| [opentelemetry-sdk](https://github.com/open-telemetry/opentelemetry-python) | `1.44.0` | `1.45.0` |
| [opentelemetry-exporter-otlp-proto-http](https://github.com/open-telemetry/opentelemetry-python) | `1.44.0` | `1.45.0` |
| [ruff](https://github.com/astral-sh/ruff) | `0.16.8` | `0.16.10` |
| [mypy](https://github.com/python/mypy) | `2.3.1` | `2.4.0` |



Updates `fastapi` from 0.141.1 to 0.142.2
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](fastapi/fastapi@0.141.1...0.142.2)

Updates `types-aiobotocore-s3` from 3.9.1 to 3.9.2
- [Release notes](https://github.com/youtype/mypy_boto3_builder/releases)
- [Commits](https://github.com/youtype/mypy_boto3_builder/commits)

Updates `temporalio` from 1.33.0 to 1.34.0
- [Release notes](https://github.com/temporalio/sdk-python/releases)
- [Changelog](https://github.com/temporalio/sdk-python/blob/main/CHANGELOG.md)
- [Commits](temporalio/sdk-python@1.33.0...1.34.0)

Updates `sqlglot` from 30.18.0 to 30.21.0
- [Commits](tobymao/sqlglot@v30.18.0...v30.21.0)

Updates `opentelemetry-sdk` from 1.44.0 to 1.45.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-python/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-python/blob/main/CHANGELOG.md)
- [Commits](open-telemetry/opentelemetry-python@v1.44.0...v1.45.0)

Updates `opentelemetry-exporter-otlp-proto-http` from 1.44.0 to 1.45.0
- [Release notes](https://github.com/open-telemetry/opentelemetry-python/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-python/blob/main/CHANGELOG.md)
- [Commits](open-telemetry/opentelemetry-python@v1.44.0...v1.45.0)

Updates `ruff` from 0.16.8 to 0.16.10
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](astral-sh/ruff@0.16.8...0.16.10)

Updates `mypy` from 2.3.1 to 2.4.0
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](python/mypy@v2.3.1...v2.4.0)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-version: 0.142.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-minor-patch
- dependency-name: types-aiobotocore-s3
  dependency-version: 3.9.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-minor-patch
- dependency-name: temporalio
  dependency-version: 1.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-minor-patch
- dependency-name: sqlglot
  dependency-version: 30.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-minor-patch
- dependency-name: opentelemetry-sdk
  dependency-version: 1.45.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-minor-patch
- dependency-name: opentelemetry-exporter-otlp-proto-http
  dependency-version: 1.45.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-minor-patch
- dependency-name: ruff
  dependency-version: 0.16.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-minor-patch
- dependency-name: mypy
  dependency-version: 2.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
…on-minor-patch-4e16c1bde2

chore(deps): bump the production-minor-patch group across 1 directory with 8 updates
Add Cargo-aware Rust codegen and validation gates
Generated by .github/workflows/episteme.yml; the knowledge base is derived from
the tree, not authored, and is regenerated after merge so branches never carry
it and never conflict over it.
Generated by .github/workflows/episteme.yml; the knowledge base is derived from
the tree, not authored, and is regenerated after merge so branches never carry
it and never conflict over it.
fix(rust): use maintained Orchard grammar for pinned source
Generated by .github/workflows/episteme.yml; the knowledge base is derived from
the tree, not authored, and is regenerated after merge so branches never carry
it and never conflict over it.
docs(rust): sign off core support after upstream lint merge
Generated by .github/workflows/episteme.yml; the knowledge base is derived from
the tree, not authored, and is regenerated after merge so branches never carry
it and never conflict over it.
…/preflight

SSPN-118. A project opts in by committing .spine/required-behavior.yaml:
checks that must pass before a run can report itself verified, distinct
from PreflightRunner (lint/type quality) and TestRunner (the model's own
tests). ONTM-4 showed generated tests can pass while the feature under
test never exercises its own default wiring; this closes that gap with
checks the model does not author and cannot edit away.

- contracts.py: RequiredBehaviorRunner Protocol, RequiredBehaviorResult,
  RequirementResult (carries environment_blocked, determined structurally
  from the exit code rather than text-sniffing output).
- required_behavior.py: SubprocessRequiredBehaviorRunner (self-skips
  without a manifest, mirroring SubprocessPreflightRunner's own
  "no pyproject.toml" behavior) and StubRequiredBehaviorRunner.
  load_manifest() fails loud on a malformed manifest rather than treating
  it as "no manifest" -- an unusable opt-in should not read as unverified.
- deps.py / worker.py: new SDLCDeps field, wired alongside preflight.

Found and fixed in passing: exec_capture() (process.py) raises
FileNotFoundError instead of returning a code when argv[0] doesn't
exist -- every other caller's argv[0] is a Spine-controlled interpreter
that's always present, so this never surfaced before. A manifest's
command is project-authored and can simply be wrong; handled locally in
required_behavior.py rather than changing the shared helper.

Hidden-check loading (SSPN-118/D16) and the loop integration (SSPN-119)
are separate tickets; this lands the Protocol/types/self-skip behavior
on its own, consumable by both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… loop

SSPN-119. required_behavior joins tests/types/coverage as its own
independently-budgeted check in run_feature's implement -> author_tests ->
refine loop, run after the coverage probe clears (the last, most specific
gate before a run reports itself passed). Own spent/budgets entry, same
reasoning the loop already applies to tests/types/coverage: a shared pool
starves whichever check runs last. Defaults to max_refine's value.

An environment-blocked requirement (missing fixture/command, not a code
defect) stops the loop immediately rather than spending refine budget on
something refine cannot fix by editing code -- same policy `tests` already
has via environment_blocker(), applied structurally here via
RequiredBehaviorResult.items[].environment_blocked instead of the
text-pattern heuristic that function uses (SSPN-118/D21).

Explicitly out of scope, per the ticket's own D22: _repair_after_revision
and review_response.py's review-feedback loop. Both already drive refine()
independently and are tracked as a named follow-up, not wired here.

New tests (4): pass completes the run unchanged, fail-then-pass drives
exactly one refine call, failure alone exhausts its own budget while
tests/types stay green the whole time, environment-blocked stops with
zero refine calls. All 118 pre-existing test_feature_runner.py tests stay
green unmodified -- none construct a .spine/required-behavior.yaml, so the
new kind is an inert no-op for every one of them, confirming SSPN-118's
self-skip design holds end to end.

Caught by the new tests, not by inspection: the first version of this
wired required_behavior's "needs refine" branch so it fell through into
the sibling coverage-budget block (same indentation, previously reachable
only when `gaps` was non-empty) -- silently corrupting the coverage
counter and calling author_tests with an empty gap list, which broke the
loop on the very first required_behavior failure. Fixed with an explicit
else so the two branches can no longer collide.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ctly

SSPN-120. PKGCodegenGrounder.context_for_required_entry_points() resolves
a required-behavior manifest's entry point against the PKG and surfaces
OTHER implementations of the same base type via the existing
implements_of()/implementors_of() primitives -- no new PKG fact type, no
extractor change (checked: the closest existing concept, the PROVIDES
edge, is Kotlin/C#-only; extending it for Python is its own track, not
this ticket).

Why this and not more context_for_spec: for an ONTM-4-shaped bug (a
missing call, not a wrong one), showing the model the buggy symbol's own
source proves nothing. A sibling that wires correctly -- a different rule
type's loader that does call its compiler -- is what actually helps.

Wired into LLMCodegenAdapter._grounding() additively: an empty lexical
match from context_for_spec must not suppress a sibling finding, and
vice versa (verified by test_grounding_is_additive_not_gated_on_lexical_
match, which deliberately uses a spec unrelated to the fixture's domain).
Guarded with getattr(), the same defensive pattern context_for_symbols
already uses, since not every CodegenGrounder test double implements it.

Extends SSPN-118's manifest schema with an optional `entry_point` field
(dotted path or short name) -- not present in the original ticket's
Requirement dataclass, needed for this to have anything to resolve
against. Backward compatible: existing manifests without it are
unaffected.

Tests: 6 new in test_grounding.py against a real on-disk fixture (common
base + a buggy implementation + a correctly-wired sibling) proving the
sibling surfaces and the target/base do not; 3 new in
test_required_behavior.py for the entry_point field; 2 end-to-end against
an ONTM-4-shaped fixture (default loader skips its compiler) proving the
real (non-faked) runner fails on the broken version and passes on the
fix, per this ticket's own exit criterion.

Gate: ruff/mypy src tests (824 files) clean. tests/sdlc/ -- 1610 passed,
2 skipped (unrelated missing extras), 0 regressions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
SSPN-121 (ai/spine half -- the spineharness docs/packaging half ships
as its own PR per SSPN-122/D30). Two gaps the roadmap's own wording
anticipated but the code didn't yet support.

Telemetry (D27): StageUsage/TokenLedger only ever got an entry via
record(stage, result: CompletionResult), called exclusively from real LLM
completions. required_behavior (SSPN-119) makes zero LLM calls -- pure
subprocess execution -- so it never appeared in the ledger, despite "
deterministic work may have zero model tokens while still having runtime;
label it accordingly" being the roadmap's own stated requirement.
record_deterministic() + StageUsage.deterministic_seconds close the gap;
wired into run_feature's loop around the required_behavior call. The
worklog table gains a Deterministic (s) column so a zero-token row with
real time reads as "ran real work", not "didn't run".

Three-outcome reporting (D28): nothing in types.py distinguished more
than a binary passed/failed verdict -- built from scratch, using data the
loop already computes (spent). _attempt_outcome() labels a successful
run as either "initial generated candidate passed with no correction
needed" or "first completed autonomous workflow after N refine(s)",
threaded into render_worklog's new Outcome line. The third outcome, a
later human-assisted continuation, happens in a separate call
(review_response.py) that review_response.py's own loop never re-checks
required_behavior for (SSPN-119/D22's deliberate scope cut) --
ReviewResponse.required_behavior_note documents that explicitly on every
instance, a standing fact rather than a blank field to source-dive for.

Tests: 3 new in test_recording.py for the deterministic path, 2 new in
test_feature_runner.py proving both outcome strings render in a real
posted worklog, 1 new in test_review_response.py for the documented
note. All passed on first run.

Gate: ruff/mypy src tests (824 files) clean, full-repo ruff check
clean. tests/sdlc/ + tests/core/llm/ -- 1656 passed, 2 skipped
(unrelated missing extras), 0 regressions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… gates

SSPN-122 gate-closing work. CHANGELOG.md gets one combined Unreleased
entry covering SSPN-118-121's cumulative addition (one entry, not four,
per this plan's "one MR" delivery model). STATE-OF-SPINE.md's source
modules/test functions/test files counts refreshed to match the source
(404/4659/392) -- state-numbers.py --check was failing on three stale
claims, mostly from upstream's Rust codegen landing since this branch
was cut, partly from this epic's own new module and tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…output type

SSPN-121 added ReviewResponse.required_behavior_note, and
sdlc_address_review's handler spreads **result.__dict__ into its return
dict -- the field was always going to flow through the MCP tool
unannounced. Caught by the real cost of running the full test suite
(not a scoped subset): tests/plugin/test_server.py's output-contract
check failed on the undeclared key. Declared it on SdlcAddressReviewOut
instead of filtering the field out of the response -- it's useful
information for an MCP caller too, not something to hide.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
load_manifest() returns tuple[Requirement, ...] -- its length isn't
statically known to be 1, so (requirement,) = load_manifest(tmp_path)
is a real static-analysis risk (CodeQL: "Left hand side of assignment
contains 1 variables, but right hand side is a tuple of length 0"),
even though these two tests' own fixtures guarantee exactly one
requirement at runtime. Indexes with an explicit length assertion
instead -- same safety, no destructuring CodeQL can flag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR #514's dependency-audit job failed on 3 new advisories against
versions already locked on develop (confirmed: develop's own most
recent audit run passed against these identical versions minutes
earlier -- the CVEs were published between that run and this PR's,
not introduced by this branch). All three are transitive (none pinned
in pyproject.toml): multidict via aiohttp/aiobotocore/yarl, fsspec via
huggingface-hub/torch (the asr extra), langgraph-sdk via langgraph.

uv lock --upgrade-package resolved all three within existing
constraints -- no pyproject.toml change needed:
  multidict      6.7.1    -> 6.9.1   (CVE-2026-104874's exact fix)
  fsspec      2026.4.0    -> 2026.9.0
  langgraph-sdk  0.4.2    -> 0.4.5

Verified before committing: re-ran the exact `pip-audit` command the
CI job uses -- "No known vulnerabilities found, 1 ignored" (the
pre-existing, already-justified click/PYSEC-2026-2132 entry, unchanged).
uv.lock diff touches only these 3 packages' versions, nothing else
moved. Full repo ruff/mypy clean. Full test suite re-run after
re-syncing: 5519 passed, 13 skipped (unrelated missing-tooling skips),
0 failed -- the fsspec/torch/huggingface-hub chain is deep enough that
this needed real verification, not just a clean resolver run.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
feat(sdlc): required-behavior gates (SSPN-116)
Generated by .github/workflows/episteme.yml; the knowledge base is derived from
the tree, not authored, and is regenerated after merge so branches never carry
it and never conflict over it.
Synaptixs and others added 2 commits October 5, 2026 21:56
Minor: required-behavior gates add a fourth, independently-budgeted check to
sdlc feature's native refine loop, re-verified after every refinement
(SSPN-116) — a project opts in via .spine/required-behavior.yaml and a legacy
project without one takes the exact code path it took before. Core Rust
support (comprehension + Cargo-aware codegen/build/test) is signed off for
supported host environments, closing the installed-parser grammar gate via a
pinned tree-sitter-rust-orchard and the Synaptreesitter lint-baseline gate via
its own upstream PR.

Also fixes two stale release-cut gaps found while cutting this one: the Rust
comprehension changelog entry was misfiled under the already-shipped 3.53.0
section instead of Unreleased, and capability-matrix.md's header plus
gap4-adoption-distribution-roadmap.md's workflow tag were still stamped
3.52.0 from two releases ago.

Stamps pyproject + the lockfile's own entry, the three plugin manifests, the
reusable-workflow tags (including the one in gap4-adoption-distribution-
roadmap.md), CHANGELOG (Unreleased -> 3.54.0), README "What's new",
CLI_REFERENCE, STATE-OF-SPINE (including its stale Rust-gate-open prose),
capability-matrix, SPEC-INDEX's recount line, and the re-rendered
architecture + knowledge-foundation SVG/PNG.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Generated by .github/workflows/episteme.yml; the knowledge base is derived from
the tree, not authored, and is regenerated after merge so branches never carry
it and never conflict over it.
Comment thread src/orchestrator/sdlc/preflight.py Dismissed
Comment thread src/orchestrator/sdlc/testenv.py Dismissed
Comment thread src/orchestrator/sdlc/testenv.py Dismissed
Comment thread src/orchestrator/sdlc/testenv.py Dismissed
@mbinder45
mbinder45 merged commit 423d4a2 into main Oct 6, 2026
13 checks passed
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.

3 participants