Skip to content

Source and presenter-profile intake (4.3.1) - #131

Merged
leynos merged 16 commits into
mainfrom
4-3-1-source-and-presenter-profile-intake-script-generation
Jun 11, 2026
Merged

Source and presenter-profile intake (4.3.1)#131
leynos merged 16 commits into
mainfrom
4-3-1-source-and-presenter-profile-intake-script-generation

Conversation

@lodyai

@lodyai lodyai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds docs/execplans/4-3-1-source-and-presenter-profile-intake-script-generation.md, the execution plan for roadmap item 4.3.1, the first half of the source-to-script vertical slice from ADR 009.
  • The plan covers the REST intake surface (POST /v1/uploads, POST /v1/ingestion-jobs, POST /v1/ingestion-jobs/{job_id}/sources and their GET pairs), an ObjectStorePort with a local-filesystem adapter, an IdempotencyStorePort backed by a SQL unique constraint, and a new IngestionJob.intake_state column kept orthogonal to the existing multi-source merge status.
  • It also pins the new error-code-to-HTTP-status table, the multipart canonical body-hash recipe, the at-most-once awaiting_sources → ready_for_generation transition, and a two-phase blob-write pattern that keeps the multipart path safe under rollback.

Notes for reviewers

  • The plan is the artefact to review; no production code lands here. It is a DRAFT ExecPlan that follows the conventions in the execplans skill.
  • Scope deliberately defers the two-step upload (POST /v1/uploads/init + PUT bytes), magic-byte sniffing, S3-compatible adapters, and Vidai Mock fixtures — each with an explicit deferral target. See the Decision log and Risks sections.
  • The draft was revised after a Logisphere community-of-experts pre-implementation review; the change list is in the Revision history section at the bottom.
  • The plan signposts the relevant skills (hexagonal-architecture, python-router and its follow-ons, python-testing, python-verification, hypothesis, execplans, leta, commit-message, en-gb-oxendict) and the relevant documentation (ADR 009, ADR 014, docs/episodic-tui-api-design.md, docs/async-sqlalchemy-with-pg-and-falcon.md, docs/testing-async-falcon-endpoints.md, docs/testing-sqlalchemy-with-pytest-and-py-pglite.md).

Test plan

  • Reviewer confirms the success criteria match ADR 009 and the TUI API design.
  • Reviewer confirms the deferred items (init/PUT, magic-byte sniffing, S3, Vidai Mock) are acceptable for this slice.
  • Reviewer confirms the hexagonal-boundary plan (new Hecate prefixes in domain_ports, application, and outbound_adapter).
  • npx markdownlint-cli2 docs/execplans/4-3-1-source-and-presenter-profile-intake-script-generation.md — passes locally.

References

  • ExecPlan: docs/execplans/4-3-1-source-and-presenter-profile-intake-script-generation.md
  • Roadmap item: docs/roadmap.md §4.3.1
  • ADR 009: docs/adr/adr-009-source-to-script-rest-vertical-slice.md
  • ADR 014 (hexagonal enforcement): docs/adr/adr-014-hexagonal-architecture-enforcement.md
  • Lody session: https://lody.ai/leynos/sessions/dee6eb0d-6d7a-44e0-9f2f-9ef266660431

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @LodyAI[bot], you have reached your weekly rate limit of 2500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 68fd31cd-7a59-4423-a343-4059ea3aefc7

📥 Commits

Reviewing files that changed from the base of the PR and between facfef0 and 349321d.

📒 Files selected for processing (58)
  • Makefile
  • alembic/versions/20260610_000009_add_source_intake_tables.py
  • docs/adr/adr-015-upload-and-idempotency-ports.md
  • docs/contents.md
  • docs/developers-guide.md
  • docs/episodic-podcast-generation-system-design.md
  • docs/execplans/2-3-3-generate-guest-bios-from-reference-document-bindings.md
  • docs/execplans/4-1-2-finalize-rest-surfaces.md
  • docs/execplans/4-3-1-source-and-presenter-profile-intake-script-generation.md
  • docs/execplans/issue-92-oversized-module-decomposition.md
  • docs/tei-rapporteur-users-guide.md
  • docs/testing-sqlalchemy-with-pytest-and-py-pglite.md
  • docs/users-guide.md
  • episodic/api/app.py
  • episodic/api/dependencies.py
  • episodic/api/errors.py
  • episodic/api/resources/__init__.py
  • episodic/api/resources/source_intake.py
  • episodic/api/serializers.py
  • episodic/api/source_idempotency.py
  • episodic/api/source_intake_support.py
  • episodic/canonical/domain.py
  • episodic/canonical/entity_protocols.py
  • episodic/canonical/idempotency.py
  • episodic/canonical/idempotency_service.py
  • episodic/canonical/ingestion_sources.py
  • episodic/canonical/object_store.py
  • episodic/canonical/source_intake_service.py
  • episodic/canonical/storage/__init__.py
  • episodic/canonical/storage/entity_mappers.py
  • episodic/canonical/storage/entity_models.py
  • episodic/canonical/storage/filesystem_object_store.py
  • episodic/canonical/storage/ingestion_job_repositories.py
  • episodic/canonical/storage/models.py
  • episodic/canonical/storage/models_base.py
  • episodic/canonical/storage/source_intake_mappers.py
  • episodic/canonical/storage/source_intake_models.py
  • episodic/canonical/storage/source_intake_repositories.py
  • episodic/canonical/storage/uow.py
  • episodic/canonical/unit_of_work_protocols.py
  • episodic/canonical/upload_protocols.py
  • episodic/canonical/uploads.py
  • pyproject.toml
  • tests/__snapshots__/test_source_intake_api.ambr
  • tests/canonical_storage/test_source_intake_repositories.py
  • tests/features/source_intake.feature
  • tests/fixtures/api.py
  • tests/fixtures/database.py
  • tests/fixtures/test_database.py
  • tests/steps/test_source_intake_steps.py
  • tests/test_api_route_versioning.py
  • tests/test_brief_loaders.py
  • tests/test_env_runtime_wiring.py
  • tests/test_filesystem_object_store.py
  • tests/test_idempotency_properties.py
  • tests/test_idempotency_service.py
  • tests/test_reference_document_bindings_facade.py
  • tests/test_source_intake_api.py
👮 Files not reviewed due to content moderation or server errors (58)
  • tests/test_brief_loaders.py
  • tests/test_reference_document_bindings_facade.py
  • Makefile
  • tests/fixtures/database.py
  • tests/fixtures/test_database.py
  • tests/test_env_runtime_wiring.py
  • tests/test_idempotency_properties.py
  • tests/canonical_storage/test_source_intake_repositories.py
  • tests/test_filesystem_object_store.py
  • tests/test_idempotency_service.py
  • tests/fixtures/api.py
  • tests/test_api_route_versioning.py
  • tests/features/source_intake.feature
  • tests/steps/test_source_intake_steps.py
  • tests/test_source_intake_api.py
  • tests/snapshots/test_source_intake_api.ambr
  • docs/adr/adr-015-upload-and-idempotency-ports.md
  • episodic/canonical/object_store.py
  • episodic/canonical/source_intake_service.py
  • docs/episodic-podcast-generation-system-design.md
  • episodic/canonical/uploads.py
  • episodic/canonical/idempotency.py
  • episodic/canonical/storage/source_intake_mappers.py
  • docs/contents.md
  • docs/execplans/2-3-3-generate-guest-bios-from-reference-document-bindings.md
  • docs/execplans/4-3-1-source-and-presenter-profile-intake-script-generation.md
  • episodic/canonical/unit_of_work_protocols.py
  • docs/execplans/issue-92-oversized-module-decomposition.md
  • episodic/canonical/upload_protocols.py
  • episodic/canonical/ingestion_sources.py
  • episodic/canonical/storage/filesystem_object_store.py
  • episodic/api/dependencies.py
  • pyproject.toml
  • docs/execplans/4-1-2-finalize-rest-surfaces.md
  • episodic/api/app.py
  • docs/testing-sqlalchemy-with-pytest-and-py-pglite.md
  • episodic/api/source_intake_support.py
  • docs/developers-guide.md
  • episodic/canonical/domain.py
  • episodic/canonical/entity_protocols.py
  • docs/tei-rapporteur-users-guide.md
  • episodic/canonical/storage/models_base.py
  • episodic/canonical/storage/entity_models.py
  • episodic/canonical/storage/entity_mappers.py
  • episodic/canonical/idempotency_service.py
  • episodic/api/serializers.py
  • episodic/api/source_idempotency.py
  • episodic/api/errors.py
  • episodic/api/resources/init.py
  • episodic/api/resources/source_intake.py
  • docs/users-guide.md
  • alembic/versions/20260610_000009_add_source_intake_tables.py
  • episodic/canonical/storage/ingestion_job_repositories.py
  • episodic/canonical/storage/source_intake_repositories.py
  • episodic/canonical/storage/init.py
  • episodic/canonical/storage/uow.py
  • episodic/canonical/storage/source_intake_models.py
  • episodic/canonical/storage/models.py

Source and Presenter-Profile Intake: REST API Implementation

Overview

This PR implements the initial REST surface for roadmap item 4.3.1 (source-and-presenter-profile intake for script generation), providing the domain models, application services, and HTTP endpoints for a source-intake vertical slice as specified in ADR 009. The work includes execution planning, architectural decision recording, comprehensive domain modelling, SQLAlchemy persistence layers, and end-to-end integration tests.

Key Implementation Components

Architectural Decisions:

  • ADR 015 (Upload and idempotency ports) establishes two core driven ports:
    • ObjectStorePort for persisting opaque upload bytes with server-generated identifiers and filesystem-safety constraints
    • IdempotencyStore for retryable POST operations using (principal_id, operation, idempotency_key) as the logical key
    • Request fingerprinting via canonical UTF-8 JSON and multipart SHA-256 hashing with operation-specific metadata allowlists
    • Domain-only idempotency outcome types (Acquired, Replay, Conflict, InFlight) with opaque serialised outcome persistence

Domain Models:

  • IntakeState enum (AWAITING_SOURCES, READY_FOR_GENERATION, CANCELLED) added to IngestionJob
  • Upload and UploadInitRequest entities with declared/actual size and content-hash validation
  • IngestionJobSource for pre-generation source attachments supporting both upload and remote URI links via AttachmentKind
  • IdempotencyRecord and IdempotencyAcquireRequest with state tracking and replay payload persistence
  • IngestionJobListFilters for pagination and optional filtering by series profile and intake state

Application Services:

  • register_upload: streams payload to ObjectStorePort, validates declared size/hash, transitions upload to READY state
  • create_ingestion_job: creates pending ingestion job for a series profile in AWAITING_SOURCES state
  • attach_source_to_ingestion_job: creates source attachment and transitions job to READY_FOR_GENERATION
  • acquire_or_replay: deterministic idempotency workflow with outcome serialisation/deserialisation
  • Paginated job listing with optional filters and counts

HTTP API Surface:

  • POST /v1/uploads: multipart form upload with idempotency-key support
  • POST /v1/ingestion-jobs: JSON request to create intake-stage ingestion job
  • GET /v1/ingestion-jobs: paginated job listing with optional series-profile and intake-state filters
  • GET /v1/ingestion-jobs/{job_id}: job status with optional next_poll_after_seconds guidance
  • POST /v1/ingestion-jobs/{job_id}/sources: attach upload or remote URI source with idempotency

Persistence:

  • FilesystemObjectStore adapter implementing ObjectStorePort with safe path resolution and atomic writes
  • SqlAlchemyUploadRepository, SqlAlchemyIngestionJobSourceRepository, SqlAlchemyIdempotencyStore backed by new ORM models
  • SqlAlchemyIngestionJobRepository supporting conditional intake_state transitions via SQL UPDATE with WHERE clause
  • Alembic migration adding uploads, ingestion_job_sources, and idempotency_records tables with uniqueness/check constraints
  • Schema isolation via shared session-scoped py-pglite process with per-test schema reset using asyncio.Lock

Documentation and Design Links:

  • Updated system design document to include ADR 015 and new tables (ingestion_job_sources, idempotency_records)
  • Execution plan (4-3-1) specifies REST intake workflow, error mapping, multipart hashing recipe, and staged implementation guidance
  • Developers guide extended with source-intake idempotency contract, error-code table, and observability requirements
  • Users guide documents the source-intake workflow for end users

Testing Strategy

  • Unit tests: canonical JSON fingerprinting, multipart hash matching against ADR 015 worked vector, idempotency property-based tests (Hypothesis)
  • Integration tests: round-trip object storage, fixture-based repository tests, source-intake end-to-end flow
  • BDD scenario: editorial team upload, source attachment, and idempotency conflict verification
  • API contract tests: route versioning, response envelope snapshots
  • Fixture enhancements: pglite_node_environment session-scoped fixture, _schema_reset_lock serialisation, concurrent schema isolation

Out-of-Scope Deferrals

Per ADR 015 and the execution plan:

  • Two-step upload (POST /v1/uploads/init + PUT /{upload_id}/bytes)
  • S3-compatible object-store adapters
  • Magic-byte content-type sniffing
  • Vidai Mock test fixtures
  • Automated idempotency record purge worker

Configuration Changes

  • Pytest timeout increased from 60 to 180 seconds to accommodate py-pglite startup and Alembic migrations
  • Hecate boundaries extended to include episodic.canonical.idempotency domain ports and episodic.canonical.idempotency_service application layer
  • PYTEST_XDIST_WORKERS conditional handling prevents xdist plugin loading when single-worker testing

Related Documentation

  • ADR 009: Source-to-script REST vertical slice design
  • ADR 014: Hexagonal architecture boundaries
  • ADR 015: Upload and idempotency ports (established in this PR)
  • System design document: updated with tables, ER diagram (Figure 18), and vertical-slice mapping
  • Execution plan 4-3-1: comprehensive REST intake workflow and implementation roadmap

Walkthrough

Add the intake ADR and execution plan, define intake and idempotency domain/storage contracts, wire the new API routes and handlers, update runtime fixtures, and add end-to-end validation for uploads, ingestion jobs, and replay/conflict handling.

Changes

Source-intake architecture and implementation slice

Layer / File(s) Summary
Contract and planning docs
docs/adr/adr-015-upload-and-idempotency-ports.md, docs/contents.md, docs/developers-guide.md, docs/episodic-podcast-generation-system-design.md, docs/users-guide.md, docs/testing-sqlalchemy-with-pytest-and-py-pglite.md, docs/execplans/4-3-1-source-and-presenter-profile-intake-script-generation.md, docs/execplans/2-3-3-generate-guest-bios-from-reference-document-bindings.md, docs/execplans/4-1-2-finalize-rest-surfaces.md, docs/execplans/issue-92-oversized-module-decomposition.md, docs/tei-rapporteur-users-guide.md
ADR-015 defines the intake ports, request hashing, observability, and storage vocabulary; the execution plan adds the staged intake rollout and contracts; the related guides, system design, and existing execplan notes are updated or reflowed to match.
Domain, storage, and migration model
episodic/canonical/..., alembic/versions/20260610_000009_add_source_intake_tables.py
IntakeState, upload and attachment entities, idempotency records, repository protocols, object-store boundaries, filesystem persistence, SQLAlchemy models/mappers/repositories, unit-of-work wiring, and the Alembic schema migration are added for intake and replay state.
API wiring and source intake handlers
episodic/api/...
The app registers uploads and ingestion-job routes, new dependency fields and error mapping are added, multipart/idempotency helpers are introduced, and source-intake resources serialise upload, job, and source responses.
Runtime and fixture support
Makefile, pyproject.toml, tests/fixtures/api.py, tests/fixtures/database.py
Pytest execution defaults, timeout settings, Hecate prefixes, API dependency wiring, and py-pglite fixture lifecycle behaviour are updated for the new intake slice.
Validation coverage
tests/...
New tests cover filesystem object-store behaviour, idempotency hashing and replay rules, route versioning, repository round-trips, bindings and loader regressions, source-intake API flows, and the BDD end-to-end upload-to-status path.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant UploadsResource
  participant SourceIntakeService
  participant SqlAlchemyUnitOfWork
  participant FilesystemObjectStore
  participant SqlAlchemyIdempotencyStore
  Client->>UploadsResource: POST /v1/uploads
  UploadsResource->>SourceIntakeService: register_upload(...)
  SourceIntakeService->>FilesystemObjectStore: put(...)
  SourceIntakeService->>SqlAlchemyUnitOfWork: add Upload and commit
  UploadsResource->>SqlAlchemyIdempotencyStore: acquire/complete replay state
  UploadsResource->>Client: 201 upload response or replay/conflict
Loading

Possibly related issues

Possibly related PRs

  • leynos/episodic#111: Both PRs touch episodic/api/errors.py; this PR adds source-intake error mapping on top of the shared HTTP error-envelope work.
  • leynos/episodic#105: Both PRs adjust episodic/api/app.py route registration for canonical /v1 resources, and this PR extends that wiring with intake endpoints.

Poem

Bytes in a bottle, keys in a queue,
Intake paths open, idempotent too.
Uploads go sailing, jobs wake and align,
Replays return neatly, as steady asाइन?
🛶✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 4-3-1-source-and-presenter-profile-intake-script-generation

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@lodyai
lodyai Bot marked this pull request as ready for review June 9, 2026 18:23

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @LodyAI[bot], you have reached your weekly rate limit of 2500000 diff characters.

Please try again later or upgrade to continue using Sourcery

codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai coderabbitai Bot added the Roadmap label Jun 9, 2026
@lodyai
lodyai Bot force-pushed the 4-3-1-source-and-presenter-profile-intake-script-generation branch from e6bbbff to c9dc016 Compare June 10, 2026 00:30
codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos leynos changed the title Plan source and presenter-profile intake (4.3.1) Source and presenter-profile intake (4.3.1) Jun 10, 2026
@leynos

leynos commented Jun 10, 2026

Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@lodyai

lodyai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== test_reference_document_bindings_facade.py ==="
cat tests/test_reference_document_bindings_facade.py

echo ""
echo "=== test_brief_loaders.py (first 30 lines) ==="
head -30 tests/test_brief_loaders.py

echo ""
echo "=== database.py - lock check ==="
grep -n "Lock\|_schema_reset_lock\|_reset_public_schema" tests/fixtures/database.py

echo ""
echo "=== ADR-015 - HTTP concepts check ==="
grep -n "route\|response_status\|response_body\|response_headers\|IdempotencyOutcome\|Acquired\|Replay\|Conflict\|InFlight\|serialised_outcome\|operation" docs/adr/adr-015-upload-and-idempotency-ports.md | head -60

echo ""
echo "=== Open issues ==="
gh issue list --repo leynos/episodic --state open --limit 50 --json number,title | jq '.[] | {number, title}'

Length of output: 12245



@leynos: All in-scope checks are now resolved. Here is the updated status table.

Status of failed checks

Check Status Verdict
Testing (Overall) — identity checks in test_reference_document_bindings_facade.py ❌ Error Resolvedis checks replaced with four functional tests exercising create_reference_binding, get_reference_binding, list_reference_bindings, and list_reference_bindings_paged against a real database fixture
Module-Level Documentation — terse docstring in test_brief_loaders.py ❌ Error Resolved — docstring expanded to nine lines covering purpose, entities, pipeline relationship, and stub strategy
Testing (Unit And Behavioural) — no 4.3.1 implementation tests ⚠️ Warning 🔖 Out of scope — tracked in #133
Testing (Property / Proof) — Hypothesis state-machine tests ⚠️ Warning 🔖 Out of scope — tracked in #134
Testing (Compile-Time / Ui) — multipart fingerprint integration tests ⚠️ Warning 🔖 Out of scope — tracked in #135
Domain Architecture — HTTP concepts in IdempotencyStore port ⚠️ Warning Resolved — ADR 015 now uses operation in the uniqueness tuple, serialised_outcome: bytes in place of response_status/response_body/response_headers, and defines domain-only outcome types Acquired, Replay, Conflict, InFlight
Concurrency And State — no lock on _reset_public_schema ⚠️ Warning Resolved_schema_reset_lock = asyncio.Lock() added at module level; _reset_public_schema serialises all calls through it

@leynos

leynos commented Jun 10, 2026

Copy link
Copy Markdown
Owner

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

codescene-delta-analysis[bot]

This comment was marked as outdated.

leynos added 4 commits June 11, 2026 12:37
Add a shared async reset lock around the py-pglite public schema reset
fixture so concurrent callers cannot drop `public` during another reset.
Cover the path with a fixture test that verifies both lock use and the
post-reset schema state.

Document the xdist serialisation rule, and make the runtime wiring
readiness test run lifespan shutdown so the database engine is disposed
before the next py-pglite fixture starts.
Add upload, source attachment, idempotency, and object-store domain
contracts for the source-intake workflow. Include a filesystem-backed
object-store adapter so local intake paths can persist and stream opaque
upload payloads behind the new port.

Cover the ADR 015 multipart fingerprint, object-store path and size
guards, and idempotency replay/conflict invariants with focused tests.
Record the published ADR vector discrepancy in the execplan so the
compatibility value remains explicit.
Apply formatter-driven line wrapping to existing documentation touched by
the validation workflow. Keep the changes textual only so Markdown lint
and diagram validation remain clean.
Add Alembic-backed upload, source-attachment, and idempotency storage plus source-intake application services and /v1 Falcon resources.

Cover SQLAlchemy repository round trips, domain idempotency outcomes, the ADR 015 multipart worked vector, a BDD source-intake scenario, a response-envelope snapshot, and the end-to-end upload/job/source/poll workflow.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos

leynos commented Jun 11, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

Complex Method

episodic/canonical/idempotency.py: post_init
post_init has a cyclomatic complexity of 10, threshold = 9

episodic/canonical/ingestion_sources.py: post_init
post_init has a cyclomatic complexity of 13, threshold = 9

episodic/canonical/uploads.py: post_init
post_init has a cyclomatic complexity of 10, threshold = 9

Why does this problem occur?

A Complex Method has a high cyclomatic complexity. The recommended threshold for the Python language is a cyclomatic complexity lower than 9.

How to fix it?

There are many reasons for Complex Method. Sometimes, another design approach is beneficial such as a) modeling state using an explicit state machine rather than conditionals, or b) using table lookup rather than long chains of logic. In other scenarios, the function can be split using EXTRACT FUNCTION. Just make sure you extract natural and cohesive functions. Complex Methods can also be addressed by identifying complex conditional expressions and then using the DECOMPOSE CONDITIONAL refactoring.

Helpful refactoring examples

To get a general understanding of what this code health issue looks like - and how it might be addressed - we have prepared some diffs for illustrative purposes.

SAMPLE

# complex_method.js
 function postItem(item) {
   if (!item.id) {
-    if (item.x != null && item.y != null) {
-      post(item);
-    } else {
-      throw Error("Item must have x and y");
-    }
+    // extract a separate function for creating new item
+    postNew(item);
   } else {
-    if (item.x < 10 && item.y > 25) {
-      put(item);
-    } else {
-      throw Error("Item must have an x and y value between 10 and 25");
-    }
+    // and one for updating existing items
+    updateItem(item);
   }
 }
+
+function postNew(item) {
+  validateNew(item);
+  post(item);
+}
+
+function updateItem(item) {
+  validateUpdate(item);
+  put(item);
+}
+

@leynos

leynos commented Jun 11, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

Large Method

episodic/api/app.py: create_app has 82 lines, threshold = 70
tests/steps/test_source_intake_steps.py: upload_and_attach_source has 70 lines, threshold = 70

Why does this problem occur?

Overly long functions make the code harder to read. The recommended maximum function length for the Python language is 70 lines of code. Severity: Brain Method - Complex Method - Long Method.

How to fix it?

We recommend to be careful here -- just splitting long functions don't necessarily make the code easier to read. Instead, look for natural chunks inside the functions that expresses a specific task or concern. Often, such concerns are indicated by a Code Comment followed by an if-statement. Use the EXTRACT FUNCTION refactoring to encapsulate that concern.

Document the origin/main rebase conflict resolution in the source-intake execplan and remove a Markdown blank-line lint issue exposed after the rebase.
@lodyai
lodyai Bot force-pushed the 4-3-1-source-and-presenter-profile-intake-script-generation branch from 38a45c4 to c5d59f7 Compare June 11, 2026 10:41
@leynos

leynos commented Jun 11, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

Code Duplication

episodic/api/source_idempotency.py: The module contains 2 functions with similar structure: _idempotency_conflict,_idempotency_in_flight

episodic/canonical/storage/source_intake_mappers.py: The module contains 4 functions with similar structure: _ingestion_job_source_from_record,_ingestion_job_source_to_record,_upload_from_record,_upload_to_record

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@coderabbitai

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

Move idempotency, ingestion-source, and upload dataclass validation branches into private module-level helpers so the __post_init__ methods stay as flat delegation sequences without changing validation semantics.
codescene-delta-analysis[bot]

This comment was marked as outdated.

Share idempotency conflict construction and metadata deep-copy mapping
through private helpers. Preserve the existing HTTP error payloads and
mapper copy semantics while keeping the mapper helpers type-preserving.
@lodyai

lodyai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

codescene-delta-analysis[bot]

This comment was marked as outdated.

Move Falcon route registration groups and the source-intake BDD API call
sequence into private helpers. Keep route strings, resource construction,
and test assertions unchanged while reducing large-method complexity.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos

leynos commented Jun 11, 2026

Copy link
Copy Markdown
Owner

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Code Duplication

episodic/canonical/storage/source_intake_mappers.py:

What lead to degradation?

The module contains 4 functions with similar structure: _ingestion_job_source_from_record,_ingestion_job_source_to_record,_upload_from_record,_upload_to_record

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@leynos

leynos commented Jun 11, 2026

Copy link
Copy Markdown
Owner

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

@coderabbitai

This comment was marked as resolved.

@leynos
leynos merged commit ee16ed2 into main Jun 11, 2026
4 of 5 checks passed
@leynos
leynos deleted the 4-3-1-source-and-presenter-profile-intake-script-generation branch June 11, 2026 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant