Skip to content

ID-75 — PullMD remote URL/feed source: PLAN ({75.4})

ID-75 — PullMD remote URL/feed source: PLAN ({75.4})

Section titled “ID-75 — PullMD remote URL/feed source: PLAN ({75.4})”

{75.4} PLAN artefact. Decomposes the ratified {75.2} PRODUCT (BI-1..BI-23) + {75.3} TECH (WP-A..WP-G, D-1..D-12, M1/M2, §5 landing-set contract, §6.1 spine) into implementation Subtasks {75.5}..{75.15}. Authored by a fresh Planner dispatch (Q-PLANNER-2); both predecessor specs read in full.

  • Task: ID-75 “Wire PullMD into cocoindex correctly — remote URL/feed source” (bl-217).
  • Ratifications inherited: TECH ratified by Liam S318 — OQ-T1 (CV 13 re-homing per §6.3), OQ-T2 (poller-fired POST /walk nudge + hourly fallback; CRON_SECRET reuse + net-new COCOINDEX_WORKER_URL), OQ-T3 (ingestion_source spelling).
  • Scope: Slice 1 (landing) only — BI-13/14/15 are ID-58/ID-71 seats, deliberately NOT decomposed here.
  • Authored: S318 (06/06/2026). Language: UK English; dates DD/MM/YYYY.

1. Code-intelligence orientation (run 06/06/2026 at this HEAD)

Section titled “1. Code-intelligence orientation (run 06/06/2026 at this HEAD)”
  • gitnexus_query({query: "feed articles url landing reference items promotion pipeline"}) returned the promotion-path symbols as standalone definitions with processes: [] (no indexed cross-module flow): Function:lib/intelligence/pipeline.ts:storeAsContentItem (:576-734), Function:lib/intelligence/pipeline.ts:processFeedSource (:276-536), Function:lib/intelligence/pipeline.ts:isDuplicate (:216-254), plus the untouched consumer surfaces (articles/rss routes) BI-12 protects.
  • gitnexus_context({name: "processFeedSource"}) — incoming calls: exactly 1 (runPipeline); processes: []. Verdict LOW structural / HIGH product significance — matches TECH §1.1 verbatim; the {75.13} brief carries the full impact-before-edit discipline regardless.
  • Python-side grounding is grep-based per .ast-dataflow/CLAUDE.md (ts-morph does not cover Python). Pre-verified for the WP-E wrinkle: inferContentType is exported at pipeline.ts:165, sole production caller at :704 (inside storeAsContentItem), and imported by exactly two test files (__tests__/lib/intelligence/content-type-update.test.ts, __tests__/lib/intelligence/si-gap-fixes.test.ts) — carried into the {75.13} brief.
  • Types-regen convention verified: the CI supabase-types-parity job generates from staging ($STAGING_PROJECT_REF, .github/workflows/ci.yml:1062-1069); the prod project-id in its error-hint string is stale. The {75.5} brief instructs staging-side regeneration accordingly.

2. Decomposition (11 Subtasks, {75.5}–{75.15})

Section titled “2. Decomposition (11 Subtasks, {75.5}–{75.15})”
IDTitle (short)WP / decisionsDeps (sibling-only)
75.5M1 migration — reference layerWP-A
75.6M2 migration — retrieval RPCsWP-B5
75.7URL normalise + SSRF leaf modules + parity fixtureWP-C (D-8)
75.8FeedUrlSource + UrlItem + EXECUTOR-VERIFY-1WP-C (D-1/D-2/D-4)7
75.9adapters.py — epoch-keyed fetch + HTML retirementWP-C/WP-D (D-4)
75.10flow.py — schemas + ingest_url componentWP-C steps 1–8 (D-6/D-7/D-9/D-10/D-12)5, 8, 9
75.11app_main wiring + containment (+ WP-G docstring)WP-C/WP-G10
75.12Cadence ops — Vercel env + Coolify hourly fallbackD-3 (OQ-T2)11
75.13TS promotion retirement + walk nudgeWP-E (D-3/D-5)11 (+ orchestrator gate, §4)
75.14Ontology register entry + doc editsWP-F5
75.15Prod cutover (Liam-gated)§6.1 step 66, 12, 13, 14

Ceiling check: 11 of 25 — comfortably within the soft cap. Full briefs (the details fields) live in the Subtask records returned to the Orchestrator for ledger-cli add-subtasks 75.

Wave 1 (parallel — disjoint file sets):
75.5 (supabase/migrations + database.types.ts)
75.7 (url_normalise.py, url_validation.py, parity fixture + tests)
75.9 (adapters.py + adapter tests + write-path HTML fixtures)
Wave 2 (parallel):
75.6 ← 5 (migrations dir + types — serialised behind 5)
75.8 ← 7 (url_source.py + tests; FIRST STEP = EXECUTOR-VERIFY-1)
75.14 ← 5 (docs/ontology/* — documents the LANDED M1 shape)
Wave 3 (serial):
75.10 ← 5, 8, 9 (flow.py component; shares the write-path test file with 9,
consumes 8's memo verdict + 9's _pullmd_fetch)
Wave 4 (serial):
75.11 ← 10 (flow.py app_main; same file as 10 ⇒ serial)
[deploy via onprem-deploy.yml → {62.10} §5 proof becomes runnable (ID-62, task-level)]
Wave 5 (parallel):
75.12 ← 11 (ops/env/runbook — no code files)
75.13 ← 11 + ORCHESTRATOR GATE: {62.10} proof green (cross-TASK, not a subtask dep)
Wave 6:
75.15 ← 6, 12, 13, 14 + HUMAN GATE: Liam prod ratification

Why this shape:

  • M1 before M2 (75.6 ← 75.5): the RPCs reference the table; both CLI-only, staging-first.
  • 75.5 / 75.7 / 75.9 are genuinely parallel-safe — fully disjoint file sets. 75.9 (adapters + HTML retirement) has no dependency on the URL substrate; WP-D is unconditional.
  • 75.10 is the convergence point: it needs the schema contract (5), the source + EXECUTOR-VERIFY-1 signature verdict (8), and _pullmd_fetch (9); it also edits the same write-path test file as 9, so serialisation avoids worktree conflicts.
  • 75.11 after 75.10: same file (flow.py); the component must exist before the binding site mounts it.
  • Proof gates retirement (TECH §6.1 steps 3–4): 75.13 must not land before the §5 landing-set proof is green, or passed articles land nowhere in the gap. The proof is {62.10} — ID-62’s Subtask — so the gate is task-level orchestration, restated in 75.13’s details, never a cross-Task subtask dependency.
  • 75.15 is Liam-gated (prod push + prod env), depending on the full staged slice including docs (75.14) so ratification reviews a complete picture.

4. Cross-task coordination (no constraint bends)

Section titled “4. Cross-task coordination (no constraint bends)”
  • {62.10} (ID-62) consumes TECH §5. Runnable once 75.5 + 75.7–75.11 are deployed to the staging worker; explicitly does NOT require 75.13 (its green run gates 75.13). A re-shaped details text for {62.10} was returned to the Orchestrator alongside this PLAN (ID-62’s ledger record is the Orchestrator’s to edit, not this Planner’s).
  • {42.11}/{42.12} reconcile flags (BI-23) restated in 75.13: the manual-URL path (app/api/ingest/url/route.ts) is untouched here.
  • ID-45/T7: consumes the landing model; no data movement in ID-75 (§6.2).
  • EXECUTOR-VERIFY-1 (memo over frozen dataclass) — first step of 75.8 with the documented scalar fallback; verdict fixes 75.10’s ingest_url signature.
  • Retirement gap — handled by the wave-5 gate above.
  • Idle-mode gate covers both sources (TECH §8) — accepted v1; 75.11 brief forbids splitting the gate.
  • Supabase link drift — every migration-touching brief (75.5/75.6/75.15) opens with the verify-and-relink discipline; worktree first action is the staging link.
DateSessionNote
06/06/2026S318{75.4} PLAN authored under the ratified PRODUCT+TECH pair by a fresh Planner. 11 Subtasks ({75.5}–{75.15}), sibling-only deps verified, EXECUTOR-VERIFY-1 surfaced as the explicit first step of {75.8}, {62.10} re-shape rider returned to the Orchestrator as text.