feat(devtools): add lab schema commit, the real full-corpus persist path - #3538
Conversation
Problem: `devtools lab schema generate --full-corpus` is documented across this repo as the entry point for regenerating committed provider schema packages, but `generate_provider_schema()` (what it calls) only returns a preview `GenerationResult` -- it never calls `persist_generated_provider_bundle`, the function that actually writes `polylogue/schemas/providers/<provider>/ versions/...` via `SchemaRegistry.replace_provider_packages`. That write path only existed inside `generate_all_schemas`, which had zero CLI/devtools wiring (only called from demo seeding and a unit test). A full-corpus regenerate against the live archive silently no-ops on committed files while printing plausible generation output. Solution: add `devtools lab schema commit` (`devtools/schema_commit.py`), backed by `polylogue.schemas.operator.commit.commit_provider_schema`, which calls `generate_all_schemas` for real and reports a before/after diff per package version (new/changed/unchanged, sample counts). Safety checking reuses `_types_by_path` from `tests/unit/schemas/test_promotion_monotonicity.py`, now extracted to `polylogue/schemas/type_narrowing.py` so the production commit path and its test coverage share one implementation, and reports (non-zero exit) if any previously-committed leaf type was lost or narrowed -- though `SchemaRegistry.replace_provider_packages` already enforces monotonic merging, so this is a defense-in-depth check, verified end to end in `test_thin_regeneration_window_cannot_narrow_committed_union`. A `--dry-run` mode runs the same real generation against a scratch copy of the committed directory so the report is accurate without touching committed files. `commit` is deliberately separate from `devtools lab schema promote` (`promote_schema_cluster`): promote takes one reviewed evidence cluster (from `generate --cluster`) into a single package version; commit performs a full-corpus, potentially multi-version replace. Neither supersedes the other. `generate_all_schemas` gained a `full_corpus` passthrough parameter (it never threaded it to `_build_provider_bundle` before). Updated `docs/internals.md` and `docs/providers/index.md`, which repeated the stale "generate is the entry point" claim. Verification: `devtools test tests/unit/schemas/test_operator_commit.py tests/unit/schemas/test_promotion_monotonicity.py tests/unit/devtools/test_schema_commit_command.py tests/unit/devtools/test_schema_lab_commands.py` -- 32 passed. `devtools verify --quick` exit 0 (ruff format/check, mypy --strict, render all --check). `devtools render devtools-reference` and `devtools render topology-projection` regenerated for the new command/module. Ref polylogue-k45pq Ref polylogue-2qx.3 Co-Authored-By: Claude <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 34 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughAdds full-corpus provider schema committing with dry-run support, schema change reporting, CLI registration, documentation, shared narrowing helpers, persistence tests, and index reparse metadata updates. ChangesSchema commit workflow
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CLI as schema_commit CLI
participant Operator as commit_provider_schema
participant Generator as generate_all_schemas
participant Packages as Provider schema packages
CLI->>Operator: Submit SchemaCommitRequest
Operator->>Generator: Generate full-corpus schemas
Generator->>Packages: Write or stage schema packages
Operator->>Packages: Compare previous and generated schemas
Operator-->>CLI: Return SchemaCommitResult
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…hema-commit-full-corpus # Conflicts: # docs/plans/topology-target.yaml
…fier tightening The classifier-fingerprint gate (PR #3532, merged after this branch was cut) correctly caught that PR #3537's looks_like_ai tightening moved a parser decision boundary without a declared reparse delta. Bump INDEX_SCHEMA_VERSION to 54, declare the SEMANTIC_REPARSE delta, and acknowledge the manifest entry accordingly. Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@devtools/command_catalog.py`:
- Around line 1571-1584: Escape or wrap the provider placeholder in inline code
within the use_when text of the “lab schema commit” CommandSpec so generated
Markdown displays it literally; then regenerate the command catalog to update
docs/devtools.md at line 68, with no direct manual change needed there beyond
the generated output.
In `@devtools/schema_commit.py`:
- Around line 74-90: Update main() around build_schema_privacy_config() so
ValueError from an invalid --privacy-config is caught, reported to stderr with a
“schema-commit:” prefixed message, and causes main() to return 1 instead of
exposing a traceback; preserve the existing schema commit flow for valid
configurations.
In `@polylogue/schemas/type_narrowing.py`:
- Around line 34-41: Update types_by_path to merge type sets when accumulating
results from multiple schema branches, preserving all types for duplicate paths
instead of allowing later found.update() calls to replace earlier values. Ensure
composed anyOf/oneOf branches retain both string and number types, and add a
regression test covering this behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a4622fc5-a892-4c2a-a330-053ceab16c63
📒 Files selected for processing (19)
devtools/command_catalog.pydevtools/schema_commit.pydevtools/schema_generate.pydocs/devtools.mddocs/internals.mddocs/plans/classifier-fingerprints.jsondocs/plans/topology-target.yamldocs/providers/index.mdpolylogue/schemas/generation/workflow.pypolylogue/schemas/operator/commit.pypolylogue/schemas/operator/inference.pypolylogue/schemas/operator/models.pypolylogue/schemas/operator/workflow.pypolylogue/schemas/type_narrowing.pypolylogue/storage/sqlite/archive_tiers/index.pypolylogue/storage/sqlite/lifecycle.pytests/unit/devtools/test_schema_commit_command.pytests/unit/schemas/test_operator_commit.pytests/unit/schemas/test_promotion_monotonicity.py
CodeRabbit findings on PR #3538: - types_by_path's found.update() let a later anyOf/oneOf branch silently overwrite an earlier branch's type set at the same path, which could hide a real narrowing (a schema keeping only the last branch's type wouldn't register as narrowed). Union the sets instead. Regression test added and confirmed to fail without the fix. - schema_commit.py's main() let an invalid --privacy-config ValueError escape as a traceback instead of a clean CLI failure -- now caught and reported like schema_generate.py already does. - command_catalog.py's <provider> placeholder rendered as raw HTML in generated docs -- wrapped in backticks, regenerated docs/devtools.md. Co-Authored-By: Claude <noreply@anthropic.com>
xofj: all six April chatgpt content types already implemented and verified reaching production. 2qx.3: schema-inference pipeline wiring already done via k45pq/PR #3538; only the real execution run remains, tracked by tnqqt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lo4gGibHP94JeF62vivvwA
… (PR #3408) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lo4gGibHP94JeF62vivvwA
Summary
devtools lab schema generate --full-corpusis documented across this repo as the entry point for regenerating committed provider schema packages, but it only ever previews a generation and never writes topolylogue/schemas/providers/. This addsdevtools lab schema commit, the actual persisting entry point.Problem
generate_provider_schema()(whatdevtools lab schema generatecalls, viainfer_schema()) only returns aGenerationResult-- it never callspersist_generated_provider_bundle, the function that writespolylogue/schemas/providers/<provider>/versions/...viaSchemaRegistry.replace_provider_packages. That write path only existed insidegenerate_all_schemas, which had zero CLI/devtools wiring: its only callers werepolylogue/demo/workspace.py(demo seeding) and a unit test. A full-corpus regenerate against the live archive therefore silently no-ops on the committed package files while printing plausible-looking generation output (sample_count, versions, suggested corpus specs) -- confirmed live: a 138-day-old package showed zerogit diffafter a 30M-sample "full-corpus regenerate".Solution
devtools lab schema commitcommand (devtools/schema_commit.py), backed bypolylogue.schemas.operator.commit.commit_provider_schema. It callsgenerate_all_schemasfor real and reports a before/after diff per package version: new / changed / unchanged, sample counts.generate_all_schemasgained afull_corpuspassthrough parameter -- it never threaded the flag to_build_provider_bundlebefore, so full-corpus semantics were unreachable even from the one caller that did persist._types_by_path(fromtests/unit/schemas/test_promotion_monotonicity.py) is extracted topolylogue/schemas/type_narrowing.pyso the production commit path and its test coverage share one implementation.commitreports (and exits non-zero on) any previously-committed leaf type that was lost or narrowed. In practiceSchemaRegistry.replace_provider_packagesalready enforces monotonic merging end-to-end, so this is defense-in-depth, verified directly intest_thin_regeneration_window_cannot_narrow_committed_union.--dry-runruns the same real generation against a scratch copy of the committed provider directory (viashutil.copytree) so the report reflects real registry merge/carry-forward behavior without ever touching the committed tree.devtools lab schema promote(promote_schema_cluster) makes this redundant: it does not.promotetakes one reviewed evidence cluster (fromgenerate --clustermode) into a single registered package version -- a narrow, single-version operation.commitperforms a full-corpus, potentially multi-version replace across every versiongenerate_all_schemasproduces for a provider. Documented this distinction in both modules' docstrings and indocs/internals.md.docs/internals.mdanddocs/providers/index.md, which repeated the stale "generateis the entry point for committed packages" claim.Verification
devtools test tests/unit/schemas/test_operator_commit.py tests/unit/schemas/test_promotion_monotonicity.py tests/unit/devtools/test_schema_commit_command.py tests/unit/devtools/test_schema_lab_commands.py tests/unit/core/test_schema_generation.py-- 64 passed, 1 skipped (unrelated slow test).devtools verify --quick-- exit 0 (ruff format, ruff check, mypy --strict,render all --check, layering, closure-matrix, schema-versioning policy, schema promotion audit).devtools render devtools-referenceanddevtools render topology-projectionregenerated for the new command/module and committed.devtools verify(testmon-affected pytest) -- this worktree had no seeded testmon baseline and seeding it runs close to the full non-slow suite, which is out of scope for a foreground-only verification pass on this change; the explicit file-selection run above covers every touched module and its existing neighbors.Coordinator follow-up
Once merged, the real per-provider commit invocation is:
Per the task instructions, do not run this against the live archive until polylogue-u19l's quarantine-pruning pass lands.
Ref polylogue-k45pq
Ref polylogue-2qx.3
Summary by CodeRabbit
New Features
lab schema committo generate and persist provider schemas from the full archive.Documentation
Maintenance