feat(chassis,tenancy): SDK-chassis-in-prod + strict tenant DB binding flags [l9-ecosystem-fix] - #195
Conversation
… flags Campaign l9-ecosystem-fix Wave 1 (reachable half) for the CEG target: - W7-01 strict_tenant_database (default off): removes the silent database="neo4j" fallback in GraphDriver.execute_query/execute_write; under the flag a missing database= raises. Back-compatible when off. - W7-02 require_sdk_chassis_in_prod (default off): resolve_chassis() fails startup on a non-SDK chassis when l9_env==prod. - DEC-001 identity contract resolved to OPTION-B (docs/adr): candidate identity is the namespaced entity_ref (<model>:<id>, e.g. res.partner:102), not a bare res.partner int nor a Neo4j-native id; explicit resolver required. Records the live entity_id vs contract entity_ref reconciliation as a residual task. - Canonical match contract fixtures (contracts/match_request.json, match_response.json) + conformance test rejecting removed required fields. - Register both flags in .claude/rules/feature-flags.md. Feature-gated, reversible. Tests: 21 targeted green; full unit+contracts suite exit 0; ruff + mypy (140 files) clean; contract scanner no violations. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QcrcFFfNb8SohQvpEajf4F
|
📋 Best Practices for Large Changes
✅ This PR passes the blocking limit but is larger than recommended. |
L9 Audit Harness Report
Step Results
Architecture Audit Findings
See Spec Coverage
See Next StepsAll checks passed. Safe to merge. |
|
There was a problem hiding this comment.
Pull request overview
This PR advances the l9-ecosystem-fix campaign by adding two production-safety feature flags (default-off) and introducing canonical match contract fixtures plus a decision record that formalizes candidate identity as the contract-defined entity_ref.
Changes:
- Add Wave 7 flags:
strict_tenant_database(enforces explicit Neo4j database binding when enabled) andrequire_sdk_chassis_in_prod(enforces SDK chassis in prod when enabled). - Introduce canonical
contracts/match_request.json/contracts/match_response.jsonfixtures with unit conformance tests. - Add ADR DEC-001 documenting candidate identity as a namespaced
entity_refand calling out current live-vs-contract divergence.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_graph_driver_database_binding.py | Adds unit tests for strict tenant DB binding behavior in GraphDriver. |
| tests/unit/test_canonical_contract_fixtures.py | Validates canonical request/response fixtures against Pydantic payload models. |
| tests/contracts/test_chassis_parity.py | Adds contract coverage for enforcing SDK chassis in prod when flagged. |
| engine/graph/driver.py | Removes implicit database="neo4j" parameter default and gates fallback behind strict_tenant_database. |
| engine/config/settings.py | Registers the two new Wave 7 feature flags and exposes is_production. |
| docs/adr/ADR-DEC-001-candidate-identity.md | Records DEC-001 (Option B) for candidate identity via entity_ref. |
| contracts/match_response.json | Adds canonical match response fixture. |
| contracts/match_request.json | Adds canonical match request fixture. |
| chassis/entrypoint.py | Enforces SDK chassis in prod when require_sdk_chassis_in_prod is enabled. |
| .claude/rules/feature-flags.md | Documents the new Wave 7 feature flags in the feature flag registry. |
| @pytest.mark.finding("EVID-003") | ||
| @pytest.mark.asyncio | ||
| async def test_explicit_database_is_preserved_when_strict() -> None: | ||
| """An explicit database= (as the internal health probe passes) stays valid.""" | ||
| driver = GraphDriver() | ||
| driver._raw_execute_query = AsyncMock(return_value=[]) # type: ignore[method-assign] | ||
| with patch("engine.config.settings.settings", _settings(strict=True)): | ||
| await driver.execute_query("RETURN 1", database="neo4j") | ||
| assert driver._raw_execute_query.await_args.args[2] == "neo4j" |



Summary
Reachable half of the l9-ecosystem-fix campaign for CEG: two production-safety feature flags (SDK-chassis-in-prod, strict tenant DB binding), the DEC-001 candidate-identity decision record, and canonical match contract fixtures — all bounded, reversible, and default-off.
What changed
strict_tenant_database(default off) — removes the silentdatabase="neo4j"fallback inGraphDriver.execute_query/execute_write; under the flag a missingdatabase=raises. Back-compatible when off. The one internal caller (health ping) already passesdatabase="neo4j"explicitly.require_sdk_chassis_in_prod(default off) —resolve_chassis()fails startup on a non-SDK chassis whenl9_env==prod. Staged behind the flag so the SDK chassis can be validated before enforcement.docs/adr/ADR-DEC-001-candidate-identity.md) — candidate identity is the namespacedentity_ref(<model>:<id>, e.g.res.partner:102), not a bareres.partnerint nor a Neo4j-native node id; an explicit resolver is required. Records the live-handlerentity_idvs contractentity_refreconciliation as a residual task.contracts/match_request.json,contracts/match_response.json) + conformance test rejecting removed/renamed required fields (no transport-forbidden fields on payloads)..claude/rules/feature-flags.md.Verification
ruff check+ruff format --checkclean;mypy— 140 files, no issues.tests/unit+tests/contractsexit 0.tools/contract_scanner.py— no violations.Residual risks
Settingsclasses:engine/config/settings.py(live, now Wave 1–7) vs the stalechassis/auth/settings.py(no Wave 7). Reconcile or remove the duplicate.entity_idnode property; aligning it to the contractentity_refis the open DEC-001 reconciliation (documented in the ADR).Part of the governed l9-ecosystem-fix Program Execution v2 campaign. Draft — merge is a separate program-owner (AUTH-001) approval.
Generated by Claude Code