doc3gpp 0.3.2__tar.gz → 0.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/AGENTS.md +2 -2
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/PKG-INFO +6 -6
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/README.md +5 -5
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/architecture.md +8 -5
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/cli.md +11 -10
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/web-server.md +8 -9
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/pyproject.toml +1 -1
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/cli.py +11 -4
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/data/skills/doc3gpp/SKILL.md +2 -2
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/spec_doc.py +5 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/spec_doc_source.py +32 -1
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/errors.py +4 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/mcp_server.py +12 -7
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/jobs.py +11 -5
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/spec_doc_parse.js +1 -1
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/workers/handlers.py +12 -8
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_mcp_end_to_end.py +15 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_doc_cli.py +61 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_doc_web.py +22 -1
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_job_worker.py +8 -17
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_jobs_sql.py +2 -2
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_source.py +7 -1
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_web_routes.py +2 -1
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.env.example +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.github/workflows/publish.yml +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.gitignore +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/.gitignore +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/2026-09-24-spec-doc-metadata-and-portal-fix/final-fix-report.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/2026-09-24-spec-doc-metadata-and-portal-fix/task-2-report.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/2026-09-24-spec-doc-web-portal/final-fix-report.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/2026-09-24-spec-doc-web-portal/task-2-report.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/2026-09-25-spec-parsed-output/final-fix-report.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/2026-09-25-spec-parsed-output/task-3-report.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/2026-09-25-spec-parsed-output/task-4-report.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/.superpowers/sdd/2026-09-25-spec-parsed-output/task-7-report.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/LICENSE +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/doc3gpp.toml.example +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/3gpp-knowledge.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/TODO.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/code-map.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/conventions.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/known-constraints.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-07-28-compact-output.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-07-28-tdoc-size-limit.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-07-29-fts5-search.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-07-29-tdoc-cr-body-changes.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-07-30-fts5-perf.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-07-31-embedding-search.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-01-fts5-hit-rename.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-01-fts5-semantic-rerank.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-01-semantic-search-revision.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-02-all-extra.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-02-remove-mysql-postgres.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-02-web-and-mcp-server.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-03-meeting-sync-display.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-03-meetings-tdoc-filter.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-04-web-ui-enhancements.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-05-tdoc-columns-dropdown.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-05-web-parse-and-search.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-07-mcp-sse-transport.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-10-spec-sync-list-show.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-11-spec-rapporteurs-comment.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-11-spec-rapporteurs-filter.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-12-mcp-spec-sync.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-12-single-spec-sync.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-12-spec-show-version-limit.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-12-spec-sync-dynareport-fetch.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-13-idempotent-cancel.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-13-mcp-parse-tdoc-url.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-13-per-spec-skip-rule.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-13-spec-per-version-details-flag.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-13-web-job-detail-params.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-13-web-mcp-meeting-name-filter.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-14-cover-page-summary-of-change.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-14-job-progress.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-14-sync-hub-page.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-14-version-display.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-14-web-tdoc-extracted-changes.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-19-tdocs-xlsx-metadata.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-08-19-web-mcp-tdoc-show-by-url.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-11-ran5-testcases.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-12-testcase-nested-statuses.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-12-testcase-separate-db.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-13-resource-schema.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-22-remote-embedding-api.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-23-spec-doc-parse.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-24-spec-doc-fetch-command-removal.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-24-spec-doc-metadata-and-portal-fix.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-24-tdoc-search-namespace.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-25-spec-doc-chunk-context.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-25-spec-doc-pagination.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-25-spec-parsed-output.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-26-unified-search-index.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/plans/2026-09-27-mcp-stdio.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-07-28-compact-output-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-07-28-tdoc-size-limit-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-07-29-fts5-search-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-07-29-tdoc-cr-body-changes-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-07-30-fts5-perf.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-07-31-embedding-search-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-01-fts5-hit-rename-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-01-fts5-semantic-rerank-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-01-semantic-search-revision-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-02-all-extra-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-02-remove-mysql-postgres-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-02-web-and-mcp-server-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-03-meeting-sync-display-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-03-meetings-tdoc-filter-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-04-web-ui-enhancements-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-05-tdoc-columns-dropdown-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-05-web-parse-and-search-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-10-spec-sync-list-show-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-11-spec-rapporteurs-comment-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-11-spec-rapporteurs-filter-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-12-mcp-spec-sync-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-12-single-spec-sync-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-12-spec-show-version-limit-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-12-spec-sync-dynareport-fetch-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-13-docs-review-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-13-idempotent-cancel-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-13-mcp-parse-tdoc-url-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-13-spec-per-version-details-flag-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-13-web-job-detail-params-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-13-web-mcp-meeting-name-filter-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-14-cover-page-summary-of-change-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-14-sync-hub-page-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-14-version-display-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-14-web-jobs-cancel-button-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-14-web-tdoc-extracted-changes-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-19-tdocs-xlsx-metadata-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-08-19-web-mcp-tdoc-show-by-url-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-11-ran5-testcases-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-12-testcase-nested-statuses-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-12-testcase-separate-db-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-13-resource-schema-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-22-remote-embedding-api-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-23-spec-doc-parse-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-24-spec-doc-fetch-command-removal-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-24-spec-doc-metadata-and-portal-fix-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-24-spec-doc-web-portal-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-24-tdoc-search-namespace-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-25-spec-doc-chunk-context-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-25-spec-doc-pagination-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-25-spec-parsed-output-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-26-unified-search-index-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/docs/superpowers/specs/2026-09-27-mcp-stdio-design.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/scripts/dev_run.sh +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/scripts/test_sqlite.sh +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/cli_auto_sync.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/cli_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/cli_server.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/cli_url_helpers.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/config.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/data/doc3gpp.toml.example +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/index.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/jobs.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/meeting.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/schema_info.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/search.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/semantic_search.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/spec.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/sync.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/tdoc.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/tdoc_cr.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/tdoc_cr_change_details.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/tdoc_file.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/tdoc_show.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/testcase.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/tsg.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/unified_search.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/models/wi.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/calendar_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr/body_changes.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr/cover_page.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr/cr_parsers.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr/header.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr/helpers.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr/ttcn_functions.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr/ttcn_sections.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/cr_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/direct_extractor.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/docx_converter.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/html_parsers.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/normalizers.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/spec_doc.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/spec_doc_chunker.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/spec_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/spec_release.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/tdoc_file_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/tdoc_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/tdoc_parsers.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/testcase_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/parsers/wi_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/repository/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/repository/protocols.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/cache.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/cache_keys.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/calendar_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/client.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/ftp_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/portal_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/spec_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/tdoc_zip_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/testcase_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/scraping/wi_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/_duration.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/embedding/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/embedding/chunker.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/embedding/remote_embedder.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/factory.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/meetings_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/search_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/semantic_reranker.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/semantic_search_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/spec_doc_index_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/spec_doc_search_facade.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/spec_doc_search_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/spec_doc_semantic_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/spec_doc_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/spec_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/tdoc_cr_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/tdoc_file_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/tdoc_index_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/tdoc_search_facade.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/tdoc_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/tdoc_sync_coordinator.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/testcase_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/tsg_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/services/wi_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/settings/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/settings/config_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/settings/config_writer.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/settings/loader.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/settings/schema.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/backends/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/backends/sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/cache.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/compression.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/base.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/fts5_query.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/migrate.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/migrations/README.md +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/models.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/session.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/specdata_base.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/db/testcase_base.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/export.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/jobs_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/meeting_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/rich_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/search_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/spec_doc_search_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/spec_doc_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/spec_doc_vector_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/spec_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/tdoc_cr_change_details_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/tdoc_cr_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/tdoc_cr_ttcn_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/tdoc_file_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/tdoc_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/testcase_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/tsg_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/vector_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/storage/repositories/wi_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/app.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/deps.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/install.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/mcp_stdio.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/render.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/landing.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/meetings.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/search.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/spec_docs.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/specs.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/sync.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/tdocs.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/testcases.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/tsgs.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/routes/wis.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/state.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/htmx.min.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/job_poller.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/meeting_sync.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/search.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/spec_clipboard.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/spec_sync.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/sync_hub.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/tdoc_columns.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/js/tdoc_parse.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/static/style.css +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/base.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/job_status.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/landing.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/meeting_list.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/meeting_show.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/_job_row.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/job_status.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/meeting_filters.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/meeting_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/pagination.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/schema_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/search_form.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/search_resource_tabs.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/search_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/search_results_table.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/spec_doc_chunks.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/spec_doc_search_form.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/spec_doc_search_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/spec_doc_search_results_table.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/spec_doc_show_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/spec_doc_toc_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/spec_filters.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/spec_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/sync_recent_jobs.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/tdoc_filters.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/tdoc_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/testcase_filters.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/testcase_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/wi_filters.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/partials/wi_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/schema.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/search_results.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/spec_doc_show.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/spec_doc_toc.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/spec_docs_search.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/spec_list.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/spec_show.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/sync.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/tdoc_content.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/tdoc_list.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/tdoc_show.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/testcase_list.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/testcase_show.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/tsg_list.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/tsg_show.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates/wi_list.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/templates_setup.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/workers/__init__.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/src/doc3gpp/web/workers/job_worker.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/conftest.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/sample_pages/3GPP-meeting-R5.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/search_corpus.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/semantic_search_corpus.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/spec_pages/R5_crs.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/spec_pages/R5_detail.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/spec_pages/R5_detail_portal.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/spec_pages/R5_etsi.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/spec_pages/R5_list.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_cr_doc/C6-250028.zip +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_cr_doc/R5-227476.zip +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_cr_doc/R5-253079.zip +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_cr_doc/R5s260009.zip +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_cr_doc/R5s260051.zip +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_cr_doc/R5s260135.zip +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_cr_doc/R5s260176.zip +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_xlsx/TDoc_List_Meeting_85434_portal.xlsx +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/tdoc_xlsx/TDoc_List_Meeting_RAN5#111.xlsx +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/fixtures/wi_pages/R5.html +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_auto_sync_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_cli_server.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_cli_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_config_init_cli_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_config_set_cli_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_db_reset_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_embed_after_parse.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_meeting_service_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_migrate_tsg_spec_last_sync_drop.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_online_3gpp_calendar.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_online_spec_doc_sync.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_online_spec_sync.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_online_tdoc_fetch_r5.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_online_tdoc_parse.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_online_testcase_sync.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_parse_tdoc_url_job_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_schema_parity.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_sdk_integration.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_after_parse.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_extras_disabled.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_index_lifecycle.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_indexes.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_previews_per_column.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_query_sem_rerank.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_schema.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_sem_end_to_end.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_snippet_column.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_search_weighted_bm25.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_semantic_extras_disabled.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_doc_repo.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_doc_search_repo.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_doc_search_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_doc_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_migration.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_parsed_output.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_spec_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_sqlite_backend.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_sync_hub_end_to_end.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_cr_change_details_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_cr_rename_migration.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_cr_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_cr_ttcn_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_file_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_parse_direct_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_parse_ftp_batch_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_parse_local_batch_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdoc_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdocs_xlsx_metadata_migration_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tdocs_xlsx_metadata_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_testcase_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_testcase_sql.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_tsg_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_vector_index_lifecycle.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_vector_repo_get_min_distance.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_vector_schema_migration.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_web_end_to_end.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_web_search_end_to_end.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/integration/test_wi_sqlite.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/_job_polling_smoke.js +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_bind_job_polling_on_terminal.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_body_changes_extractor.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cache_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cache_keys.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_calendar_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_calendar_parser_defensive.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_chunker.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cli_auto_sync.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cli_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cli_search.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cli_search_sem.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cli_server_start.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cli_server_stubs.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cli_version.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_compact_helpers.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_config_init_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_config_set_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_config_writer.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_cr_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_db_reset_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_docx_converter.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_factory_semantic.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_ftp_listing.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_fts5_query.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_index_services.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_job_row_partial.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_list_output_format.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_cli_filters_combined.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_cli_invalid_fields.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_cli_location_filter.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_repository_combined_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_repository_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_repository_location_filter.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_repository_upsert.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_meeting_sync_tsg_validation.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_packaging_semantic.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_parse_tdoc_url_route.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_parsers_utils.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_portal_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_protocols_semantic.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_remote_embedder.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_remote_embedding_settings.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_rrf.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_schema_info.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_scraper_client.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_search_query_builder.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_search_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_search_settings.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_semantic_models.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_semantic_reranker.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_semantic_search_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_semantic_settings.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_server_settings.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_services_factory.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_settings.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_settings_config_file.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_blocks.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_chunker.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_models.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_search_facade.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_service_reads.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_settings.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_doc_vector_metadata.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_model.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_orm.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_release.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_spec_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_storage_utils.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_sync_hub_page.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_cache.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_cli_fields.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_cr_change_details_model.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_cr_model.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_cr_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_cr_service_body_changes.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_cr_service_ftp_batch.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_file_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_file_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_file_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_parse_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_parse_direct.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_parse_settings.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_parse_url_batch.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_repository_crud.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_repository_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_search_facade.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_service_sync.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_show_record.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_sync_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_sync_coordinator.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_url_not_found.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tdoc_zip_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_testcase_db_url.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_testcase_model.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_testcase_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_testcase_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_testcase_source.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tsg_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tsg_repository.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tsg_service.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_tsg_url_pattern.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_ttcn_functions.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_unified_search_models.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_web_app.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_web_errors.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_web_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_web_install.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_web_jobs_routes.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_web_template_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_wi_cli.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_wi_parser.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/test_wi_repository_filters.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/web/test_landing_version.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/web/test_mcp_server.py +0 -0
- {doc3gpp-0.3.2 → doc3gpp-0.3.3}/tests/unit/web/test_mcp_stdio.py +0 -0
|
@@ -356,8 +356,8 @@ Workflows in one line (full prose in `docs/architecture.md`):
|
|
|
356
356
|
with `--resume`, `--stale-only`, and `--batch`, or `IndexStatus` with no
|
|
357
357
|
rebuild flag. Hybrid weighting comes from
|
|
358
358
|
`Settings.semantic_search.fts5_weight`.
|
|
359
|
-
|
|
360
|
-
|
|
359
|
+
- `doc3gpp spec doc parse --spec <id> [--release R] [--version V] [--force]` accepts exactly one spec and calls `SpecDocService.parse_many` with a one-item list → resolve the numeric-newest `SpecVersion` with a non-empty `.zip` URL via `resolve_spec_doc_version` (after optional release filtering); when both `--release` and `--version` are given, their release numbers must align (for example, `Rel-18` with `18.5.0`); explicit `--version` is strict and fails clearly when its ZIP link is missing. Fetch the ZIP with internal `fetch_spec_doc_zip` when absent (or use the zip cache at `{spec_doc.cache_dir}/zips/<spec_id>/<version>.zip`), and record the download. `--force` re-downloads before re-parsing, including pairs that already carry `parsed_at`.
|
|
360
|
+
- `doc3gpp spec doc parse --spec <id> [--release R] [--version V] [--force]` → immutable-skip when `(spec_id, version)` already carries `parsed_at` (unless `--force`) → `parse` = fetch-if-missing + `list_spec_docx` + `convert_document_to_blocks` + `order_spec_files` + `extract_spec_toc` + `chunk_blocks` → `upsert_toc` + `replace_chunks` + per-file markdown cache (`{spec_doc.cache_dir}/markdown/<spec_id>/<version>/`) + `record_parsed` + best-effort auto-index (`upsert_for_version`) / auto-embed (`index_for_version`). Oversized zips → skip bucket; unknown spec/version or empty (no-docx) zips → failure bucket. Prints `ok/skipped/failed` buckets only (`--format/--output/--compact` accepted but ignored). Background `parse_spec_docs` jobs use scalar `spec_id` / optional `release` / `version` / `force`, log and store the result in `result.failure_details`. Chunk/search metadata uses newline-delimited combined `sections` and `tables`; TOC entries retain `section_no` / `title`.
|
|
361
361
|
- `doc3gpp spec doc toc show --spec <id> --version <v> [--fields] [--format/--output/--compact]` → `SpecDocService.get_toc` (stored `(spec_id, version)` rows; miss → `BadParameter`). Default fields `section_no, title, level, source_file` (`[output.fields] spec_doc_toc`).
|
|
362
362
|
- `doc3gpp spec doc search [--text TEXT] [--semantic TEXT] [filters]` →
|
|
363
363
|
`SpecDocSearchFacade.search` with the same four mode-selection rules and
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: doc3gpp
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Provide 3GPP TDoc information with full text search capability — a Python CLI/library, a local web UI, and an MCP server for AI clients.
|
|
5
5
|
Project-URL: Homepage, https://github.com/jerrywang121/doc3gpp
|
|
6
6
|
Project-URL: Repository, https://github.com/jerrywang121/doc3gpp
|
|
@@ -366,7 +366,7 @@ values on every version row.
|
|
|
366
366
|
|
|
367
367
|
```bash
|
|
368
368
|
# use newest version with a published .zip, fetch-if-missing, convert every .docx, chunk, and auto-index
|
|
369
|
-
doc3gpp spec doc parse --spec 38.331 --
|
|
369
|
+
doc3gpp spec doc parse --spec 38.331 --release Rel-18 --version 18.5.0
|
|
370
370
|
doc3gpp spec doc parse --spec 38.331 --force # re-download and re-parse
|
|
371
371
|
|
|
372
372
|
# inspect the stored TOC and search chunk text/combined metadata
|
|
@@ -377,10 +377,10 @@ doc3gpp spec doc index --rebuild
|
|
|
377
377
|
doc3gpp spec doc schema --format json
|
|
378
378
|
```
|
|
379
379
|
|
|
380
|
-
Background `parse_spec_docs` jobs retain
|
|
381
|
-
result (`failure_details`) and log.
|
|
382
|
-
|
|
383
|
-
|
|
380
|
+
Background `parse_spec_docs` jobs retain the selected spec's failure reason in
|
|
381
|
+
the job result (`failure_details`) and log. Each job targets one spec; when
|
|
382
|
+
both release and version are supplied, their release numbers must align (for
|
|
383
|
+
example, `Rel-18` with `18.5.0`).
|
|
384
384
|
|
|
385
385
|
Spec-document rows live in a separate sibling database, normally
|
|
386
386
|
`<main-stem>_specdata.db`, and are cached below the dedicated
|
|
@@ -283,7 +283,7 @@ values on every version row.
|
|
|
283
283
|
|
|
284
284
|
```bash
|
|
285
285
|
# use newest version with a published .zip, fetch-if-missing, convert every .docx, chunk, and auto-index
|
|
286
|
-
doc3gpp spec doc parse --spec 38.331 --
|
|
286
|
+
doc3gpp spec doc parse --spec 38.331 --release Rel-18 --version 18.5.0
|
|
287
287
|
doc3gpp spec doc parse --spec 38.331 --force # re-download and re-parse
|
|
288
288
|
|
|
289
289
|
# inspect the stored TOC and search chunk text/combined metadata
|
|
@@ -294,10 +294,10 @@ doc3gpp spec doc index --rebuild
|
|
|
294
294
|
doc3gpp spec doc schema --format json
|
|
295
295
|
```
|
|
296
296
|
|
|
297
|
-
Background `parse_spec_docs` jobs retain
|
|
298
|
-
result (`failure_details`) and log.
|
|
299
|
-
|
|
300
|
-
|
|
297
|
+
Background `parse_spec_docs` jobs retain the selected spec's failure reason in
|
|
298
|
+
the job result (`failure_details`) and log. Each job targets one spec; when
|
|
299
|
+
both release and version are supplied, their release numbers must align (for
|
|
300
|
+
example, `Rel-18` with `18.5.0`).
|
|
301
301
|
|
|
302
302
|
Spec-document rows live in a separate sibling database, normally
|
|
303
303
|
`<main-stem>_specdata.db`, and are cached below the dedicated
|
|
@@ -622,12 +622,15 @@ and syncs each through the `--tsg` path below.
|
|
|
622
622
|
|
|
623
623
|
### Spec-document corpus (parse → TOC → search)
|
|
624
624
|
|
|
625
|
-
1. `doc3gpp spec doc parse --spec <id
|
|
626
|
-
[--force]` calls `SpecDocService.parse_many
|
|
625
|
+
1. `doc3gpp spec doc parse --spec <id> [--release R] [--version V]
|
|
626
|
+
[--force]` accepts exactly one spec and calls `SpecDocService.parse_many`
|
|
627
|
+
with a one-item list. The version resolves via
|
|
627
628
|
`resolve_spec_doc_version` — for automatic selection, filters to rows with
|
|
628
629
|
a non-empty `.zip` URL, then applies numeric sort on `SpecVersion.version`
|
|
629
630
|
(segment-wise ints, non-numeric → 0); optional `release` filters before
|
|
630
|
-
|
|
631
|
+
selection. When both `release` and `version` are supplied, their release
|
|
632
|
+
numbers must agree (for example, `Rel-18` with `18.5.0`). An explicit
|
|
633
|
+
`version` is strict and raises
|
|
631
634
|
`SpecDocUnknownVersionError` if its ZIP link is missing. A miss raises
|
|
632
635
|
`SpecDocUnknownSpecError` (no
|
|
633
636
|
`spec_versions` rows — run `spec sync --spec-id` first) or
|
|
@@ -1093,8 +1096,8 @@ the `spec doc` / `toc` / `search` triplet, 40 commands) plus the `server` group
|
|
|
1093
1096
|
- `sync` — `--tsg`
|
|
1094
1097
|
- `list` — filters by `--tsg`, `--name`, `--acronym`, `--release`
|
|
1095
1098
|
- `spec doc` (nested under `spec` as `spec doc ...`):
|
|
1096
|
-
- `parse` —
|
|
1097
|
-
|
|
1099
|
+
- `parse` — exactly one `--spec` (required), `--release`, `--version`,
|
|
1100
|
+
`--force/-f`; resolves the numeric-newest or pinned
|
|
1098
1101
|
version, fetches the ZIP when missing, and records the download;
|
|
1099
1102
|
`--force` re-downloads and re-parses, including already-parsed pairs.
|
|
1100
1103
|
Also accepts `--format/--output/--compact` (currently ignored); prints
|
|
@@ -2415,12 +2415,12 @@ strict and fails clearly if that version has no ZIP link. Run
|
|
|
2415
2415
|
|
|
2416
2416
|
Purpose:
|
|
2417
2417
|
|
|
2418
|
-
- Fetch-if-missing, convert, chunk, and index one
|
|
2419
|
-
`
|
|
2418
|
+
- Fetch-if-missing, convert, chunk, and index one spec; prints one `ok`,
|
|
2419
|
+
`skipped <reason>`, or `failed <reason>` (stderr) line.
|
|
2420
2420
|
|
|
2421
2421
|
Options:
|
|
2422
2422
|
|
|
2423
|
-
- --spec: spec id to parse;
|
|
2423
|
+
- --spec: spec id to parse; exactly one is required.
|
|
2424
2424
|
- --release: release marker, e.g. `Rel-18`. Optional pin.
|
|
2425
2425
|
- --version: exact version, e.g. `18.5.0`. Optional pin.
|
|
2426
2426
|
- --force, -f: re-download and re-parse the resolved version, including
|
|
@@ -2439,11 +2439,12 @@ Behavior:
|
|
|
2439
2439
|
`spec_doc_sources.downloaded_at` before conversion.
|
|
2440
2440
|
- `--force` re-downloads the resolved ZIP and then re-parses it, including when
|
|
2441
2441
|
the `(spec_id, version)` pair already has `parsed_at`.
|
|
2442
|
-
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
(`
|
|
2442
|
+
- The `(spec_id, version)` source row is skipped when it already carries
|
|
2443
|
+
`parsed_at` (unless `--force`); oversized zips land in the `skipped` bucket;
|
|
2444
|
+
unknown spec/version, empty (no-`.docx`) zips, and every other error land in
|
|
2445
|
+
the `failures` bucket. When both `--release` and `--version` are supplied,
|
|
2446
|
+
their release numbers must agree (for example, `Rel-18` requires a version
|
|
2447
|
+
beginning with `18.`).
|
|
2447
2448
|
- `parse` = fetch-if-missing + `list_spec_docx` (`.doc` entries warn-skip) +
|
|
2448
2449
|
`convert_document_to_blocks` + `order_spec_files` (front-matter TOC file first,
|
|
2449
2450
|
then section-tuple sort, TOC tiebreak, unnumbered lexicographic tail) +
|
|
@@ -2468,8 +2469,8 @@ Examples:
|
|
|
2468
2469
|
# Parse the newest version of 38.331 with a published ZIP download link.
|
|
2469
2470
|
doc3gpp spec doc parse --spec 38.331
|
|
2470
2471
|
|
|
2471
|
-
# Parse
|
|
2472
|
-
doc3gpp spec doc parse --spec 38.331 --
|
|
2472
|
+
# Parse one spec at a pinned release and version.
|
|
2473
|
+
doc3gpp spec doc parse --spec 38.331 --release Rel-18 --version 18.5.0
|
|
2473
2474
|
|
|
2474
2475
|
# Re-parse even when already parsed.
|
|
2475
2476
|
doc3gpp spec doc parse --spec 38.331 --force
|
|
@@ -207,16 +207,15 @@ the target is missing or not `X-Doc3gpp-Managed` by doc3gpp.
|
|
|
207
207
|
| POST | `/jobs/spec-docs/index` | Enqueue unified spec-doc FTS5/vector index maintenance. |
|
|
208
208
|
| POST | `/jobs/cache/purge` | Enqueue `cache_purge` (requires `yes: true`). |
|
|
209
209
|
| POST | `/jobs/parse/tdoc-url` | Enqueue `parse_tdoc_url` (a single 3GPP FTP URL or folder; `url` must be `https://www.3gpp.org/ftp/...`, `recursive` XOR `max_depth`). |
|
|
210
|
-
| POST | `/jobs/parse/spec-docs` | Enqueue `parse_spec_docs` for one
|
|
210
|
+
| POST | `/jobs/parse/spec-docs` | Enqueue `parse_spec_docs` for one spec id (`spec_id`, optional `release`, `version`, and `force`); progress is streamed through the normal job SSE endpoint. This job is intentionally not a panel on the eleven-form `/sync` hub. |
|
|
211
211
|
| POST | `/jobs/{id}/cancel` | Cancel a queued/running job. Accepts `?format=html` to return the refreshed job row as an `outerHTML` swap target for the list page's per-row Cancel button. JSON otherwise. |
|
|
212
212
|
| POST | `/jobs/sync_tdocs` | Flat alias for `sync_tdocs` (form or JSON). |
|
|
213
213
|
| GET | `/sync` | Sync hub page: eleven enqueue forms (meetings, tdocs, all-tdocs, specs-by-tsg, specs-by-id, parse-tdocs, parse-tdoc-url, TDoc index maintenance, spec-document index maintenance, cache-purge, testcases) + a "Recent sync jobs" table. |
|
|
214
214
|
| GET | `/sync?format=fragment` | Recent-jobs table fragment (wrapped in `<div id="recent-jobs">`) for HTMX `outerHTML` swap. |
|
|
215
215
|
|
|
216
|
-
`parse_spec_docs` records
|
|
217
|
-
job log.
|
|
218
|
-
|
|
219
|
-
in the result.
|
|
216
|
+
`parse_spec_docs` records the spec error in `result.failure_details` and the
|
|
217
|
+
job log. A failed parse job has a populated `error` and result; a successful or
|
|
218
|
+
skipped parse reports its corresponding one-spec result.
|
|
220
219
|
|
|
221
220
|
Append `?format=json` to any list/detail route to get the CLI-equivalent
|
|
222
221
|
JSON. Append `?format=html` (or omit) for the browsable HTML view.
|
|
@@ -279,8 +278,8 @@ specdata source row has not been downloaded or parsed; a downloaded source is
|
|
|
279
278
|
waiting for parsing; and a parsed source shows its parse timestamp, DOCX and
|
|
280
279
|
chunk counts. The only document action is `Parse document` (or `Force
|
|
281
280
|
re-parse`, available only for a parsed source. It enqueues the existing
|
|
282
|
-
`POST /jobs/parse/spec-docs` job with `
|
|
283
|
-
and `force`, then
|
|
281
|
+
`POST /jobs/parse/spec-docs` job with scalar `spec_id`, the selected exact
|
|
282
|
+
`version`, and `force`, then
|
|
284
283
|
polls the normal job status. The parser downloads a missing ZIP internally;
|
|
285
284
|
there is intentionally no standalone spec-document fetch route or fetch
|
|
286
285
|
control.
|
|
@@ -530,8 +529,8 @@ The spec-document tools use the separate specdata database. `get_spec_toc`
|
|
|
530
529
|
reads one parsed `(spec_id, version)` TOC, `search_spec_docs` selects among
|
|
531
530
|
FTS5, vector, hybrid, and filter-only chunk search, and `get_spec_doc_index`
|
|
532
531
|
reports index status. `parse_spec_docs` enqueues the same
|
|
533
|
-
`PARSE_SPEC_DOCS` job as `POST /jobs/parse/spec-docs`; it accepts
|
|
534
|
-
`
|
|
532
|
+
`PARSE_SPEC_DOCS` job as `POST /jobs/parse/spec-docs`; it accepts one
|
|
533
|
+
`spec_id`, optional `release`/`version`, and `force`.
|
|
535
534
|
|
|
536
535
|
The MCP `serverInfo` block returned on every `initialize` handshake carries `name` ("doc3gpp"), `version` (from `importlib.metadata.version("doc3gpp")`, falling back to `doc3gpp.__version__`), `title`, `description`, and `website_url`. Clients do not need a tool call to read the version.
|
|
537
536
|
|
|
@@ -7,7 +7,7 @@ allow-direct-references = true
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "doc3gpp"
|
|
10
|
-
version = "0.3.
|
|
10
|
+
version = "0.3.3"
|
|
11
11
|
description = "Provide 3GPP TDoc information with full text search capability — a Python CLI/library, a local web UI, and an MCP server for AI clients."
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.10"
|
|
@@ -36,7 +36,7 @@ from doc3gpp.config import get_settings
|
|
|
36
36
|
from doc3gpp.models.meeting import Meeting
|
|
37
37
|
from doc3gpp.models.schema_info import SCHEMA_FIELDS, schema_payload
|
|
38
38
|
from doc3gpp.models.spec import Spec, SpecVersion
|
|
39
|
-
from doc3gpp.models.spec_doc import SpecDocSearchFilters
|
|
39
|
+
from doc3gpp.models.spec_doc import SpecDocSearchFilters, SpecDocSelectionError
|
|
40
40
|
from doc3gpp.models.sync import BulkSyncOutcome, SyncOutcome
|
|
41
41
|
from doc3gpp.models.tdoc import TDoc, TDocWithMeeting
|
|
42
42
|
from doc3gpp.models.tdoc_cr import (
|
|
@@ -55,6 +55,7 @@ from doc3gpp.parsers.docx_converter import PythonDocxNotInstalledError
|
|
|
55
55
|
from doc3gpp.parsers.normalizers import normalize_ftp_path
|
|
56
56
|
from doc3gpp.scraping.cache import CacheStatus, TDocCache
|
|
57
57
|
from doc3gpp.scraping.cache_keys import derive_cache_file
|
|
58
|
+
from doc3gpp.scraping.spec_doc_source import validate_release_version_alignment
|
|
58
59
|
from doc3gpp.scraping.tdoc_zip_source import canonicalise_tdoc_id
|
|
59
60
|
from doc3gpp.services.factory import (
|
|
60
61
|
build_meeting_service,
|
|
@@ -5132,7 +5133,7 @@ def spec_doc_parse(
|
|
|
5132
5133
|
spec: list[str] | None = typer.Option( # noqa: B008 - Typer option declaration
|
|
5133
5134
|
None,
|
|
5134
5135
|
"--spec",
|
|
5135
|
-
help="Spec id to parse
|
|
5136
|
+
help="Spec id to parse (exactly one required).",
|
|
5136
5137
|
),
|
|
5137
5138
|
release: str | None = typer.Option(
|
|
5138
5139
|
None, "--release", help="Release marker, e.g. Rel-18.",
|
|
@@ -5160,10 +5161,16 @@ def spec_doc_parse(
|
|
|
5160
5161
|
help="Strip output formatting: JSON drops indent and operator-space. No-op for ``table``.",
|
|
5161
5162
|
),
|
|
5162
5163
|
) -> None:
|
|
5163
|
-
"""
|
|
5164
|
+
"""Parse one spec; print its success/skip/failure result."""
|
|
5164
5165
|
create_schema("all")
|
|
5165
5166
|
if not spec:
|
|
5166
|
-
raise typer.BadParameter("pass
|
|
5167
|
+
raise typer.BadParameter("pass exactly one --spec <id>")
|
|
5168
|
+
if len(spec) != 1:
|
|
5169
|
+
raise typer.BadParameter("--spec may be provided only once")
|
|
5170
|
+
try:
|
|
5171
|
+
validate_release_version_alignment(release, version)
|
|
5172
|
+
except SpecDocSelectionError as exc:
|
|
5173
|
+
raise typer.BadParameter(str(exc)) from exc
|
|
5167
5174
|
svc = build_spec_doc_service()
|
|
5168
5175
|
result = svc.parse_many(spec, release=release, version=version, force=force)
|
|
5169
5176
|
for sid in result.successes:
|
|
@@ -20,7 +20,7 @@ Read tools return a single text item containing JSON (except `get_tdoc_content`,
|
|
|
20
20
|
| Meeting calendar | `list_meetings` with `tsg`, `name`, or `year`; `get_meeting` with numeric `meeting_id` | `sync_meetings({"tsg":"R5"})` fetches and parses that TSG's calendar | Re-list, then use `get_meeting` to obtain its meeting ID and FTP URL. There is no separate meeting-parse tool. |
|
|
21
21
|
| Meeting TDocs | `list_tdocs` with `meeting_id`, `tdoc_id`, `title`, `spec`, etc.; `get_tdoc` with `tdoc_id` or `ftp_url` | `sync_tdocs({"meeting_id":260013})` after the meeting exists; alternatively `sync_tdocs_by_meeting({"meeting":"RAN5#106"})`. For document extraction, `parse_tdocs({"filter":{"tdoc_id":"R5-260013"}})`; for a direct 3GPP FTP URL use `parse_tdoc_url({"url":"https://www.3gpp.org/ftp/..."})`. | `get_tdoc` for cover/extract metadata; `get_tdoc_content({"tdoc_id":"R5-260013"})` for cached markdown if available; `search_tdoc` for indexed content and filters. |
|
|
22
22
|
| Specifications | `list_specs` with `tsg`, `spec_id`, `title`, or `parsed`; `get_spec` with dotted `spec_id` | `sync_specs({"tsg":"R5"})` or `sync_specs({"spec_id":"38.331"})` (exactly one selector). `force` bypasses the sync interval; `per_version_details` fetches extra PDF/CR-list details. | `get_spec` returns versions, release markers, ZIP URLs, and per-version `parsed` state. Paginate versions with `limit`/`offset` if needed. |
|
|
23
|
-
| Specification documents | Start with `get_spec` to identify a version with a ZIP URL; `get_spec_toc` needs an already parsed exact `(spec_id, version)` | `parse_spec_docs({"
|
|
23
|
+
| Specification documents | Start with `get_spec` to identify a version with a ZIP URL; `get_spec_toc` needs an already parsed exact `(spec_id, version)` | `parse_spec_docs({"spec_id":"38.331","version":"18.5.0"})` downloads if needed and parses one spec; omit `version` to resolve a suitable stored version (optionally constrain with `release`). When both `release` and `version` are supplied, their release numbers must align, e.g. `Rel-18` with `18.5.0`. `force` re-downloads and re-parses. | `get_spec_toc({"spec_id":"38.331","version":"18.5.0"})`; `search_spec_docs` with `spec_id`, `version`, `text` or `semantic`, `sections`, `tables`. Note '%' wildcards to match section / table titles to improve search. If search section numbers or table numbers, use '%' at the end to match sub-sections or sub-tables. e.g. `"section":"5.3.2%"` or `"table":"6.1.1.2.3-%"`. |
|
|
24
24
|
| RAN5 testcases | `list_testcases` with `testcase` (ID pattern), `title`, `spec`, `group`, `status` (TTCN), or `gcf_status` (GCF/PTCRB) | `sync_testcases({})` fetches and parses the latest RAN5 status snapshot in one job; `{"force":true}` re-downloads and re-parses a snapshot already recorded. No separate testcase parse tool. | `get_testcase({"testcase_id":"<id>"})` returns all stored groups; pass `group` for one group. Each result has nested `statuses` entries containing `path`, `gcf_ptcrb`, and `ttcn_status`. |
|
|
25
25
|
|
|
26
26
|
Filters on list/search tools generally accept SQL-LIKE `%` wildcards (for example `title:"%handover%"`); plain values match exactly. Testcase `group` is an exact match: `5G`, `LTE`, `IMS`, `UTRA`, `POS`, or `MCX`. `list_meetings`, `list_tdocs`, `list_specs`, and `list_testcases` default to 50 rows: use `limit` and `offset` to page. `search_tdoc` and `search_spec_docs` select FTS5 with `text`, vector search with `semantic`, hybrid with both, and filter-only with neither. Semantic search requires its configured embedding service. If text search reports an unavailable or corrupt index, inspect `get_tdoc_index` or `get_spec_doc_index`; use `index_tdocs({"rebuild":true})` or `index_spec_docs({"rebuild":true})` when rebuilding is needed, then poll that job. Parse normally attempts automatic indexing, but indexing can fail independently.
|
|
@@ -44,7 +44,7 @@ search_tdoc {"text":"handover","meeting_id":<meeting_id>}
|
|
|
44
44
|
sync_specs {"spec_id":"38.331"}
|
|
45
45
|
get_job {"job_id":"<spec-sync job_id>"} # poll until terminal
|
|
46
46
|
get_spec {"spec_id":"38.331"}
|
|
47
|
-
parse_spec_docs {"
|
|
47
|
+
parse_spec_docs {"spec_id":"38.331","version":"<ZIP-backed version from get_spec>"}
|
|
48
48
|
get_job {"job_id":"<spec-doc-parse job_id>"} # poll until terminal
|
|
49
49
|
get_spec_toc {"spec_id":"38.331","version":"<parsed version>"}
|
|
50
50
|
search_spec_docs {"text":"handover","spec_id":"38.331","version":"<parsed version>", "sections":"5.2.2.3%"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""DTOs for the spec-document corpus (separate specdata sqlite file)."""
|
|
2
2
|
from __future__ import annotations
|
|
3
|
+
|
|
3
4
|
from dataclasses import dataclass, field
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
|
|
@@ -18,6 +19,10 @@ class SpecDocUnknownVersionError(SpecDocError):
|
|
|
18
19
|
self.available = available or []
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
class SpecDocSelectionError(SpecDocError):
|
|
23
|
+
"""Raised when a release/version selection is internally inconsistent."""
|
|
24
|
+
|
|
25
|
+
|
|
21
26
|
class SpecDocNoDocxError(SpecDocError):
|
|
22
27
|
pass
|
|
23
28
|
|
|
@@ -2,13 +2,43 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
|
+
import re
|
|
5
6
|
|
|
6
7
|
from doc3gpp.models.spec import SpecVersion
|
|
7
|
-
from doc3gpp.models.spec_doc import SpecDocUnknownVersionError
|
|
8
|
+
from doc3gpp.models.spec_doc import SpecDocSelectionError, SpecDocUnknownVersionError
|
|
8
9
|
|
|
9
10
|
logger = logging.getLogger(__name__)
|
|
10
11
|
|
|
11
12
|
|
|
13
|
+
def validate_release_version_alignment(
|
|
14
|
+
release: str | None,
|
|
15
|
+
version: str | None,
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Ensure an explicitly selected release agrees with the version major."""
|
|
18
|
+
if release is None or version is None:
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
release_match = re.fullmatch(r"Rel-(\d+)", release)
|
|
22
|
+
if release_match is None:
|
|
23
|
+
raise SpecDocSelectionError(
|
|
24
|
+
f"release {release!r} must use the form 'Rel-<number>' when paired with a version"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
version_match = re.match(r"(\d+)(?:\.|$)", version)
|
|
28
|
+
if version_match is None:
|
|
29
|
+
raise SpecDocSelectionError(
|
|
30
|
+
f"version {version!r} must begin with a numeric release when paired with {release!r}"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
release_major = release_match.group(1)
|
|
34
|
+
version_major = version_match.group(1)
|
|
35
|
+
if release_major != version_major:
|
|
36
|
+
raise SpecDocSelectionError(
|
|
37
|
+
f"release {release!r} does not match version {version!r}; "
|
|
38
|
+
f"expected a version beginning with {release_major}."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
12
42
|
def _version_key(v: SpecVersion) -> tuple[int, ...]:
|
|
13
43
|
parts: list[int] = []
|
|
14
44
|
for seg in v.version.split("."):
|
|
@@ -22,6 +52,7 @@ def _version_key(v: SpecVersion) -> tuple[int, ...]:
|
|
|
22
52
|
def resolve_spec_doc_version(
|
|
23
53
|
versions: list[SpecVersion], release: str | None = None, version: str | None = None
|
|
24
54
|
) -> SpecVersion:
|
|
55
|
+
validate_release_version_alignment(release, version)
|
|
25
56
|
if not versions:
|
|
26
57
|
raise SpecDocUnknownVersionError("no versions stored for this spec", available=[])
|
|
27
58
|
|
|
@@ -38,6 +38,7 @@ from doc3gpp.models.semantic_search import (
|
|
|
38
38
|
)
|
|
39
39
|
from doc3gpp.models.spec_doc import (
|
|
40
40
|
SpecDocNoDocxError,
|
|
41
|
+
SpecDocSelectionError,
|
|
41
42
|
SpecDocTooLargeError,
|
|
42
43
|
SpecDocUnknownSpecError,
|
|
43
44
|
SpecDocUnknownVersionError,
|
|
@@ -137,6 +138,7 @@ _MCP_RESOURCE_BY_EXC: dict[type[Exception], tuple[str, int]] = {
|
|
|
137
138
|
SpecUnknownOnUpstreamError: ("spec", MCP_CODE_NOT_FOUND),
|
|
138
139
|
SpecDocUnknownSpecError: ("spec_doc", MCP_CODE_NOT_FOUND),
|
|
139
140
|
SpecDocUnknownVersionError: ("spec_doc", MCP_CODE_NOT_FOUND),
|
|
141
|
+
SpecDocSelectionError: ("spec_doc", MCP_CODE_INVALID_PARAMS),
|
|
140
142
|
SpecDocTooLargeError: ("spec_doc", MCP_CODE_TOO_LARGE),
|
|
141
143
|
SpecDocNoDocxError: ("spec_doc", MCP_CODE_INVALID_PARAMS),
|
|
142
144
|
JobNotFoundError: ("job", MCP_CODE_NOT_FOUND),
|
|
@@ -184,6 +186,7 @@ _ERROR_SLUGS: dict[type[Exception], str] = {
|
|
|
184
186
|
SpecUnknownOnUpstreamError: "spec_unknown_on_upstream",
|
|
185
187
|
SpecDocUnknownSpecError: "spec_doc_unknown_spec",
|
|
186
188
|
SpecDocUnknownVersionError: "spec_doc_unknown_version",
|
|
189
|
+
SpecDocSelectionError: "spec_doc_invalid_selection",
|
|
187
190
|
SpecDocTooLargeError: "spec_doc_too_large",
|
|
188
191
|
SpecDocNoDocxError: "spec_doc_no_docx",
|
|
189
192
|
InvalidFilterError: "invalid_filter",
|
|
@@ -210,6 +213,7 @@ _STATUS_BY_EXC: dict[type[Exception], int] = {
|
|
|
210
213
|
SpecUnknownOnUpstreamError: 404,
|
|
211
214
|
SpecDocUnknownSpecError: 404,
|
|
212
215
|
SpecDocUnknownVersionError: 404,
|
|
216
|
+
SpecDocSelectionError: 400,
|
|
213
217
|
SpecDocTooLargeError: 422,
|
|
214
218
|
SpecDocNoDocxError: 422,
|
|
215
219
|
InvalidFilterError: 400,
|
|
@@ -33,12 +33,13 @@ from doc3gpp.models.semantic_search import (
|
|
|
33
33
|
SemanticSearchUnavailableError,
|
|
34
34
|
VectorIndexUnavailableError,
|
|
35
35
|
)
|
|
36
|
-
from doc3gpp.models.spec_doc import SpecDocSearchFilters
|
|
36
|
+
from doc3gpp.models.spec_doc import SpecDocSearchFilters, SpecDocSelectionError
|
|
37
37
|
from doc3gpp.models.unified_search import (
|
|
38
38
|
spec_doc_search_result_to_dict,
|
|
39
39
|
tdoc_search_result_to_dict,
|
|
40
40
|
)
|
|
41
41
|
from doc3gpp.parsers.direct_extractor import is_3gpp_ftp_url
|
|
42
|
+
from doc3gpp.scraping.spec_doc_source import validate_release_version_alignment
|
|
42
43
|
from doc3gpp.web import render
|
|
43
44
|
from doc3gpp.web.errors import (
|
|
44
45
|
MCP_CODE_INTERNAL_ERROR,
|
|
@@ -915,18 +916,22 @@ def build_mcp_server(state: WebState) -> MCPServer:
|
|
|
915
916
|
) -> str:
|
|
916
917
|
return _enqueue(state, JobKind.SYNC_TESTCASES, {"force": force}, "queued sync_testcases")
|
|
917
918
|
|
|
918
|
-
@server.tool(name="parse_spec_docs", description="Enqueue a spec-doc parse
|
|
919
|
+
@server.tool(name="parse_spec_docs", description="Enqueue a spec-doc parse (mirrors `doc3gpp spec doc parse`). The spec resolves its version via the stored spec_versions rows; results land as {requested, successes, skipped, failures}. Returns a job_id; poll `get_job` for progress and `cancel_job` to abort.")
|
|
919
920
|
@_mcp_error_guard
|
|
920
921
|
def parse_spec_docs(
|
|
921
|
-
|
|
922
|
+
spec_id: Annotated[str, Field(description="Spec id to parse (e.g. '38.331').")],
|
|
922
923
|
release: Annotated[str | None, Field(description="Release marker (e.g. 'Rel-18').")] = None,
|
|
923
924
|
version: Annotated[str | None, Field(description="Exact version (e.g. '18.5.0').")] = None,
|
|
924
925
|
force: Annotated[bool, Field(description="Re-parse already-parsed pairs.")] = False,
|
|
925
926
|
) -> str:
|
|
926
|
-
if not
|
|
927
|
-
raise InvalidFilterError("
|
|
927
|
+
if not spec_id.strip():
|
|
928
|
+
raise InvalidFilterError("spec_id is required")
|
|
929
|
+
try:
|
|
930
|
+
validate_release_version_alignment(release, version)
|
|
931
|
+
except SpecDocSelectionError as exc:
|
|
932
|
+
raise InvalidFilterError(str(exc)) from exc
|
|
928
933
|
params: dict[str, Any] = {
|
|
929
|
-
"
|
|
934
|
+
"spec_id": spec_id,
|
|
930
935
|
"force": force,
|
|
931
936
|
}
|
|
932
937
|
if release is not None:
|
|
@@ -935,7 +940,7 @@ def build_mcp_server(state: WebState) -> MCPServer:
|
|
|
935
940
|
params["version"] = version
|
|
936
941
|
return _enqueue(
|
|
937
942
|
state, JobKind.PARSE_SPEC_DOCS, params,
|
|
938
|
-
f"queued parse_spec_docs for {
|
|
943
|
+
f"queued parse_spec_docs for {spec_id}",
|
|
939
944
|
)
|
|
940
945
|
|
|
941
946
|
@server.tool(name="index_tdocs", description="Enqueue TDoc FTS5/vector index maintenance.")
|
|
@@ -20,7 +20,9 @@ from fastapi.responses import JSONResponse, StreamingResponse
|
|
|
20
20
|
from pydantic import BaseModel
|
|
21
21
|
|
|
22
22
|
from doc3gpp.models.jobs import Job, JobKind, JobStatus, JSONValue
|
|
23
|
+
from doc3gpp.models.spec_doc import SpecDocSelectionError
|
|
23
24
|
from doc3gpp.repository.protocols import JobRepository
|
|
25
|
+
from doc3gpp.scraping.spec_doc_source import validate_release_version_alignment
|
|
24
26
|
from doc3gpp.web.deps import get_job_repo, get_job_worker
|
|
25
27
|
from doc3gpp.web.errors import (
|
|
26
28
|
InvalidFilterError,
|
|
@@ -143,7 +145,7 @@ class _ParseTDocURLBody(BaseModel):
|
|
|
143
145
|
|
|
144
146
|
|
|
145
147
|
class _ParseSpecDocsBody(BaseModel):
|
|
146
|
-
|
|
148
|
+
spec_id: str
|
|
147
149
|
release: str | None = None
|
|
148
150
|
version: str | None = None
|
|
149
151
|
force: bool = False
|
|
@@ -324,13 +326,17 @@ async def post_parse_spec_docs(
|
|
|
324
326
|
body: _ParseSpecDocsBody,
|
|
325
327
|
job_repo: JobRepository = Depends(get_job_repo),
|
|
326
328
|
) -> JSONResponse:
|
|
327
|
-
"""Enqueue a spec-doc parse
|
|
328
|
-
if not body.
|
|
329
|
+
"""Enqueue a single spec-doc parse (mirrors ``doc3gpp spec doc parse``)."""
|
|
330
|
+
if not body.spec_id.strip():
|
|
329
331
|
raise InvalidFilterError(
|
|
330
|
-
"parse/spec-docs requires a non-empty '
|
|
332
|
+
"parse/spec-docs requires a non-empty 'spec_id' string in the body"
|
|
331
333
|
)
|
|
334
|
+
try:
|
|
335
|
+
validate_release_version_alignment(body.release, body.version)
|
|
336
|
+
except SpecDocSelectionError as exc:
|
|
337
|
+
raise InvalidFilterError(str(exc)) from exc
|
|
332
338
|
params: dict[str, JSONValue] = {
|
|
333
|
-
"
|
|
339
|
+
"spec_id": body.spec_id,
|
|
334
340
|
"force": body.force,
|
|
335
341
|
}
|
|
336
342
|
if body.release is not None:
|
|
@@ -24,7 +24,9 @@ from doc3gpp.cli_auto_sync import (
|
|
|
24
24
|
)
|
|
25
25
|
from doc3gpp.models.index import IndexRequest
|
|
26
26
|
from doc3gpp.models.jobs import Job, JobKind, JSONValue
|
|
27
|
+
from doc3gpp.models.spec_doc import SpecDocSelectionError
|
|
27
28
|
from doc3gpp.parsers.direct_extractor import is_3gpp_ftp_url
|
|
29
|
+
from doc3gpp.scraping.spec_doc_source import validate_release_version_alignment
|
|
28
30
|
from doc3gpp.settings.schema import Settings
|
|
29
31
|
from doc3gpp.web.state import ServiceContainer
|
|
30
32
|
|
|
@@ -456,24 +458,26 @@ async def _parse_spec_docs(
|
|
|
456
458
|
progress: ProgressFn,
|
|
457
459
|
cancel_event: asyncio.Event,
|
|
458
460
|
) -> Mapping[str, JSONValue]:
|
|
459
|
-
|
|
460
|
-
if not isinstance(
|
|
461
|
-
isinstance(s, str) for s in spec_ids
|
|
462
|
-
):
|
|
461
|
+
spec_id = job.params.get("spec_id")
|
|
462
|
+
if not isinstance(spec_id, str) or not spec_id.strip():
|
|
463
463
|
raise ValueError(
|
|
464
|
-
"parse_spec_docs job requires a non-empty '
|
|
464
|
+
"parse_spec_docs job requires a non-empty 'spec_id' string parameter"
|
|
465
465
|
)
|
|
466
466
|
release = job.params.get("release")
|
|
467
467
|
version = job.params.get("version")
|
|
468
468
|
force = bool(job.params.get("force", False))
|
|
469
469
|
release = release if isinstance(release, str) else None
|
|
470
470
|
version = version if isinstance(version, str) else None
|
|
471
|
+
try:
|
|
472
|
+
validate_release_version_alignment(release, version)
|
|
473
|
+
except SpecDocSelectionError as exc:
|
|
474
|
+
raise ValueError(str(exc)) from exc
|
|
471
475
|
|
|
472
476
|
service = getattr(services, "spec_doc", None)
|
|
473
477
|
if service is None:
|
|
474
478
|
raise RuntimeError("spec-doc parse is not available in this build")
|
|
475
479
|
|
|
476
|
-
progress(f"parsing
|
|
480
|
+
progress(f"parsing spec doc {spec_id}")
|
|
477
481
|
|
|
478
482
|
def on_progress(event: str, data: Mapping[str, object]) -> None:
|
|
479
483
|
if event == "spec_done":
|
|
@@ -483,7 +487,7 @@ async def _parse_spec_docs(
|
|
|
483
487
|
raise asyncio.CancelledError()
|
|
484
488
|
result = await asyncio.to_thread(
|
|
485
489
|
service.parse_many,
|
|
486
|
-
|
|
490
|
+
[spec_id],
|
|
487
491
|
release=release,
|
|
488
492
|
version=version,
|
|
489
493
|
force=force,
|
|
@@ -499,7 +503,7 @@ async def _parse_spec_docs(
|
|
|
499
503
|
force=True,
|
|
500
504
|
)
|
|
501
505
|
return {
|
|
502
|
-
"requested":
|
|
506
|
+
"requested": 1,
|
|
503
507
|
"successes": len(result.successes),
|
|
504
508
|
"skipped": len(result.skipped),
|
|
505
509
|
"failures": len(result.failures),
|
|
@@ -113,6 +113,21 @@ def test_list_tools_exposes_read_and_job_tools(sqlite_env) -> None:
|
|
|
113
113
|
assert not any(name.startswith("fetch_spec") for name in names)
|
|
114
114
|
|
|
115
115
|
|
|
116
|
+
def test_parse_spec_docs_uses_scalar_spec_id(sqlite_env) -> None:
|
|
117
|
+
import asyncio
|
|
118
|
+
|
|
119
|
+
_, server = _state_and_server()
|
|
120
|
+
|
|
121
|
+
async def run():
|
|
122
|
+
tools = await server.list_tools()
|
|
123
|
+
return next(tool for tool in tools if tool.name == "parse_spec_docs")
|
|
124
|
+
|
|
125
|
+
tool = asyncio.run(run())
|
|
126
|
+
properties = tool.input_schema["properties"]
|
|
127
|
+
assert "spec_id" in properties
|
|
128
|
+
assert "spec_ids" not in properties
|
|
129
|
+
|
|
130
|
+
|
|
116
131
|
def test_call_list_meetings_empty(sqlite_env) -> None:
|
|
117
132
|
"""Empty result is a single ``[]`` JSON string (not zero content items)."""
|
|
118
133
|
import asyncio
|
|
@@ -59,3 +59,64 @@ def test_spec_doc_parse_forwards_force(monkeypatch):
|
|
|
59
59
|
|
|
60
60
|
assert result.exit_code == 0, result.output
|
|
61
61
|
assert calls == [(["38.331"], None, None, True)]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_spec_doc_parse_rejects_repeated_spec(monkeypatch):
|
|
65
|
+
calls = []
|
|
66
|
+
|
|
67
|
+
class FakeResult:
|
|
68
|
+
successes = {}
|
|
69
|
+
skipped = {}
|
|
70
|
+
failures = {}
|
|
71
|
+
|
|
72
|
+
class FakeService:
|
|
73
|
+
def parse_many(self, spec_ids, *, release, version, force):
|
|
74
|
+
calls.append((spec_ids, release, version, force))
|
|
75
|
+
return FakeResult()
|
|
76
|
+
|
|
77
|
+
monkeypatch.setattr("doc3gpp.cli.create_schema", lambda _scope: None)
|
|
78
|
+
monkeypatch.setattr("doc3gpp.cli.build_spec_doc_service", lambda: FakeService())
|
|
79
|
+
|
|
80
|
+
result = CliRunner().invoke(
|
|
81
|
+
app,
|
|
82
|
+
["spec", "doc", "parse", "--spec", "38.331", "--spec", "38.523-1"],
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
assert result.exit_code != 0, result.output
|
|
86
|
+
assert calls == []
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_spec_doc_parse_rejects_misaligned_release_and_version(monkeypatch):
|
|
90
|
+
calls = []
|
|
91
|
+
|
|
92
|
+
class FakeResult:
|
|
93
|
+
successes = {}
|
|
94
|
+
skipped = {}
|
|
95
|
+
failures = {}
|
|
96
|
+
|
|
97
|
+
class FakeService:
|
|
98
|
+
def parse_many(self, spec_ids, *, release, version, force):
|
|
99
|
+
calls.append((spec_ids, release, version, force))
|
|
100
|
+
return FakeResult()
|
|
101
|
+
|
|
102
|
+
monkeypatch.setattr("doc3gpp.cli.create_schema", lambda _scope: None)
|
|
103
|
+
monkeypatch.setattr("doc3gpp.cli.build_spec_doc_service", lambda: FakeService())
|
|
104
|
+
|
|
105
|
+
result = CliRunner().invoke(
|
|
106
|
+
app,
|
|
107
|
+
[
|
|
108
|
+
"spec",
|
|
109
|
+
"doc",
|
|
110
|
+
"parse",
|
|
111
|
+
"--spec",
|
|
112
|
+
"38.331",
|
|
113
|
+
"--release",
|
|
114
|
+
"Rel-18",
|
|
115
|
+
"--version",
|
|
116
|
+
"17.5.0",
|
|
117
|
+
],
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
assert result.exit_code != 0, result.output
|
|
121
|
+
assert "does not match" in result.output
|
|
122
|
+
assert calls == []
|