feat: add recommendation pipeline contract#514
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 93bf949ac0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Introduces a versioned recommendation contract and related safety gates to support deterministic weighted_v1 scoring and a guarded fop_pipeline_v1 adapter (with mandatory fallback), plus documentation/fixtures and CI enforcement.
Changes:
- Adds a shared
weighted_v1fixture + contract documentation and enforces them via a new contract-gate script wired into CI and local tooling. - Updates the recommendation engine to load versioned config/weights, emit
recommendation_id, and record aRecommendationServedaudit envelope (including adapter/legal boundary). - Adds
fop_pipeline_v1adapter configuration + tests for success/fallback/endpoint allowlisting, and locks stats behind admin.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Feature/RecommendationExtendedTest.php | Adds coverage for recommendation_id, audit envelope, fixture parity, pipeline adapter behavior, and secured stats endpoint. |
| scripts/check-recommendation-contract.sh | Adds a fixture-hash + grep-based “contract gate” enforced in CI and local runs. |
| routes/modules/recommendations.php | Protects recommendation stats endpoint with admin middleware. |
| routes/modules/bookings.php | Ensures recommendations endpoint is behind module:recommendations. |
| docs/recommendation-engine-fixtures/weighted_v1.basic.json | Adds deterministic fixture to pin weighted_v1 scoring outputs. |
| docs/recommendation-engine-contract.md | Documents scoring semantics, config boundary, pipeline adapter rules, audit/legal boundary expectations. |
| docs/openapi/php.json | Updates OpenAPI snapshot for new stats response fields/structure. |
| config/recommendations.php | Introduces versioned defaults/weights and guarded pipeline settings. |
| app/Services/ModuleRegistry.php | Adds recommendations module config keys and JSON Schema constraints (algorithm, weights, pipeline config). |
| app/Http/Controllers/Api/RecommendationController.php | Implements versioned engine config, pipeline adapter call with fallback, stats expansion, and audit logging. |
| Makefile | Runs the recommendation contract gate as part of make ci. |
| .github/workflows/ci.yml | Enforces recommendation contract gate in GitHub Actions CI. |
| .github/scripts/fop-local-ci.sh | Runs recommendation contract gate in local CI script. |
| .gitea/workflows/ci.yaml | Enforces recommendation contract gate in Gitea CI. |
Comments suppressed due to low confidence (4)
docs/openapi/php.json:1
- The OpenAPI snapshot encodes several constraints/types that don’t match the implementation: (1)
algorithmisconst: weighted_v1even though config allowsfop_pipeline_v1; (2)algorithm_adapter.statusisconst: weighted_v1but the adapter returns values likesucceeded,fallback_error,fallback_not_configured; (3)top_recommended_lotsis typed asstringbut the controller returns an array of{lot_name, count}objects; and (4)total_recommendations_servedis typed asstringbut the controller returns a number. This will mislead clients and/or break generated SDKs—update the schema to reflect the real response shapes (enums/oneOf where needed, and correct array/object typing).
docs/openapi/php.json:1 - The OpenAPI snapshot encodes several constraints/types that don’t match the implementation: (1)
algorithmisconst: weighted_v1even though config allowsfop_pipeline_v1; (2)algorithm_adapter.statusisconst: weighted_v1but the adapter returns values likesucceeded,fallback_error,fallback_not_configured; (3)top_recommended_lotsis typed asstringbut the controller returns an array of{lot_name, count}objects; and (4)total_recommendations_servedis typed asstringbut the controller returns a number. This will mislead clients and/or break generated SDKs—update the schema to reflect the real response shapes (enums/oneOf where needed, and correct array/object typing).
docs/openapi/php.json:1 - The OpenAPI snapshot encodes several constraints/types that don’t match the implementation: (1)
algorithmisconst: weighted_v1even though config allowsfop_pipeline_v1; (2)algorithm_adapter.statusisconst: weighted_v1but the adapter returns values likesucceeded,fallback_error,fallback_not_configured; (3)top_recommended_lotsis typed asstringbut the controller returns an array of{lot_name, count}objects; and (4)total_recommendations_servedis typed asstringbut the controller returns a number. This will mislead clients and/or break generated SDKs—update the schema to reflect the real response shapes (enums/oneOf where needed, and correct array/object typing).
docs/openapi/php.json:1 - The OpenAPI snapshot encodes several constraints/types that don’t match the implementation: (1)
algorithmisconst: weighted_v1even though config allowsfop_pipeline_v1; (2)algorithm_adapter.statusisconst: weighted_v1but the adapter returns values likesucceeded,fallback_error,fallback_not_configured; (3)top_recommended_lotsis typed asstringbut the controller returns an array of{lot_name, count}objects; and (4)total_recommendations_servedis typed asstringbut the controller returns a number. This will mislead clients and/or break generated SDKs—update the schema to reflect the real response shapes (enums/oneOf where needed, and correct array/object typing).
Adds the ParkHub PHP recommendation pipeline contract: a deterministic
weighted_v1baseline plus a guardedfop_pipeline_v1adapter configuration.Scope
weighted_v1recommendation contract, fixture, and staticcontract gate.
fop_pipeline_v1adapter configuration with mandatoryweighted_v1fallback.
behavior, and explicit configuration.
with the Rust contract.
fop legalis reference-only:attorney review, citation verification, deployment-specific configuration
review, human signoff, and final legal judgment remain required.
make/pre-push review paths.
Verification
fop/local-ci/pr: success on45e06c764584f531a9489ce2642c6439ee62d022.Required checks,fop local CI attestation,Dependency Review,Composer Audit,npm Audit,Schemathesis,Secret scan,Zizmor, andOSV-Scanner.Review Boundary
This PR ships the contract and guarded integration boundary. It does not enable
unreviewed automated decision support by default and does not claim legal
compliance for a live deployment. Production enablement still needs endpoint
policy, health/status monitoring, rollback switch, privacy/legal review, and
operator signoff in the release packet.
Remaining Blocker
Branch protection is blocked only by the required eligible review. After review
approval, native auto-merge should merge the PR.