Skip to content

fix(generation): persist a subject reuse key so interrupted runs can be topped up (#1089) - #1961

Open
sloemo01 wants to merge 2 commits into
repowise-dev:mainfrom
sloemo01:fix/generation-topup-resume-1089
Open

fix(generation): persist a subject reuse key so interrupted runs can be topped up (#1089)#1961
sloemo01 wants to merge 2 commits into
repowise-dev:mainfrom
sloemo01:fix/generation-topup-resume-1089

Conversation

@sloemo01

@sloemo01 sloemo01 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

What

Fixes #1089. A run interrupted by a provider outage can never be topped up: pages are always regenerated, and the missing ones are unreachable.

Root cause

The cross-run reuse gate in PageGenerator._call_provider keyed exclusively on the freshly-rendered prompt's source_hash. But the prompt drifts run to run — RAG context is rebuilt and populated concurrently each run — so on a full re-run the gate almost never matched, every unchanged page re-billed, and the pages a failed run left behind were never reachable as a cheap top-up (a stub row was either regenerated from scratch or hidden entirely). The maintainer's guidance (issue thread) named the shape of the fix: a stable subject key + routing repowise generate through the same reuse path.

Changes

  • Persisted subject reuse key: new wiki_pages.content_hash column (Alembic 0057, chained after 0056). Both migration files (0056 coverage mapping_partial, 0057 content_hash) are included on this branch, so the chain 0055 → 0056 → 0057 is valid against main regardless of merge order — 0056 is byte-identical to the one in PR fix(coverage): flag severe path-mapping loss instead of treating it as success (#1746) #1955, so no conflict either way. Computed as sha256(subject_material : renderer_fingerprint) — the file's byte hash / group's member list / repo name folded with the prompt-template source, system prompt, language, style, and a hand-bumped generation version. Unlike source_hash it survives RAG-context drift, so an unchanged page is reused instead of re-billed.
  • Reuse gate prefers the subject key: _call_provider matches on content_hash when both sides have one (falling back to the prompt hash for pre-key pages), and never reuses a row a model didn't writeprovider_name == 'template' rows (keyless stubs, or stubs a failed provider call left) always re-call the model, so a top-up actually completes the missing pages.
  • repowise generate feeds prior pages into the gate (scoped_generation loads load_prior_pages and passes them through), so scoped refills reuse unchanged siblings instead of re-billing; a load failure degrades to no-reuse, never a failed run.
  • Structural pages get the same stable-key treatment via _structural_content_hash, and --force/workspace/upgrade call sites pass the key through.

Tests

  • test_reuse_gate.py (6): subject-key hit, template-stub never reused, fallback to prompt hash, fingerprint change forces regen, empty-material falls back.
  • test_content_hash_roundtrip.py (3): column persists, round-trips through load_prior_pages, legacy rows default empty.
  • test_scoped_generation_prior_pages.py (2): generate passes prior pages in; load failure degrades.
  • test_generation_persist.py (5): key survives persist. Generation + persistence + pipeline suites: 2,231 passed; ruff clean.

@repowise-bot

repowise-bot Bot commented Aug 28, 2026

Copy link
Copy Markdown

✅ Health of changed files: 4.1 → 4.4 (+0.4)
🚨 Change risk: high, riskier than 83% of this repo's commits.

📋 At a glance
3 files changed health · 5 hotspots touched · 6 new findings introduced · 5 co-change pairs left out · 5 files with recent fix history.

Files & modules (2)
  • packages (7 files)
    • .../page_generator/core.py
    • .../pipeline/scoped_generation.py
    • .../commands/upgrade_flow.py
    • .../init_cmd/command.py
    • .../persistence/models.py
    • .../page_generator/pertype.py
    • .../init_cmd/workspace.py
  • tests (2 files)
    • .../cli/test_generation_persist.py
    • .../generation/test_structural_salt.py

✅ Health gate: passed

📌 Before you merge

  • Run .../cli/test_edenai_reachability.py, .../cli/test_editor_setup.py, .../cli/test_health_rescore_gate.py, .../cli/test_file_page_volume_prompt.py (+14 more): they import the changed files
  • .../pipeline/persist.py changed together with .../persistence/models.py in 21 past commits and isn't in this PR
  • .../cli/helpers.py changed together with .../init_cmd/command.py in 14 past commits and isn't in this PR
  • .../ui/mode_selection.py changed together with .../init_cmd/command.py in 12 past commits and isn't in this PR
  • ...and 2 more co-change partners not in this PR

🎯 Blast radius (symbols whose signature this PR changed, and who calls them)

  • upsert_page in .../crud/pages.py signature changed. Called by 41 symbols outside this PR: tests/integration/test_persistence.py::TestVersionHistory::test_idempotent_reupsert_is_noop, tests/integration/test_persistence.py::TestVersionHistory::test_version_history_after_re_generation, .../cli/test_doctor_embed_recipe.py::_build_repo (+38 more)
  • _call_provider in .../page_generator/core.py signature changed. Called by 13 symbols outside this PR: .../generation/test_page_generator.py::test_a_first_time_page_is_not_marked_as_self_repaired, .../generation/test_page_generator.py::test_a_repaired_page_is_marked_as_self_repaired, .../generation/test_page_generator.py::test_artifact_violation_is_retried_once_and_recovers (+10 more)
  • run_repo_generation in .../init_cmd/generation.py signature changed. Called by 5 symbols outside this PR: .../cli/test_init_failure_reporting.py::TestStubsAreNotCountedTwice::_run, .../cli/test_init_failure_reporting.py::test_recorded_cost_includes_the_knowledge_graph_enrichment, .../cli/test_init_failure_reporting.py::test_run_repo_generation_reports_failures (+2 more)
🔎 More signals (3)

🗺️ Change map

flowchart LR
  subgraph PR ["Changed in this PR (2 modules)"]
    m_packages_cli["packages/cli (4 files)"]:::changed
    m_packages_core["packages/core (5 files)"]:::changed
  end
  d_packages_cli["packages/cli"]
  m_packages_core -->|7 files| d_packages_cli
  d_packages_server["packages/server"]
  m_packages_core -->|2 files| d_packages_server
  classDef changed fill:#dbeafe,stroke:#1d4ed8,color:#1e3a5f
  classDef warn fill:#fef3c7,stroke:#b45309,color:#78350f
  classDef guard fill:#dcfce7,stroke:#15803d,color:#14532d
Loading

Solid arrows: code that imports the changed files (138 direct dependents, from the last indexed snapshot). Dashed: history/tests.

🔥 Hotspots touched (5)

  • .../page_generator/core.py: 27 commits/90d, 9 dependents · primary owner: Raghav Chamadiya (77%)
  • .../commands/upgrade_flow.py: 19 commits/90d, 9 dependents · primary owner: Raghav Chamadiya (85%)
  • .../init_cmd/command.py: 55 commits/90d, 8 dependents · primary owner: Raghav Chamadiya (92%)
2 more
  • .../cli/test_generation_persist.py: 2 commits/90d, 0 dependents · primary owner: Raghav Chamadiya (100%)
  • .../generation/test_structural_salt.py: 2 commits/90d, 0 dependents · primary owner: Raghav Chamadiya (71%)

🔗 Hidden coupling (3 files)

  • .../persistence/models.py co-changes with these files (not in this PR):
    • .../pipeline/persist.py (21×, 🔴 strong)
    • .../persistence/test_models.py (12×, 🟡 notable)
  • .../init_cmd/command.py co-changes with these files (not in this PR):
    • .../cli/helpers.py (14×, 🟡 notable)
    • .../ui/mode_selection.py (12×, 🟡 notable)
  • .../page_generator/pertype.py co-changes with .../page_generator/levels.py (12×, 🟡 notable), not in this PR.

👀 Suggested reviewers @RaghavChamadiya


📊 See the full report for this PR
Your repo map with this PR's blast radius lit up, every caller of the contracts it changes, and health before and after. No sign-in. · ⭐ Star Repowise · 📥 Install bot · Silence on a single PR with [skip repowise] in the title · Per-repo toggle on repowise.dev/settings?tab=bot · Updated 2026-08-28 13:27 UTC

注册 for free to join this conversation on GitHub. Already have an account? 登录 to comment

标签

None yet

项目

None yet

Development

Successfully merging this pull request may close these issues.

A run interrupted by a provider outage can never be topped up: pages are always regenerated, and the missing ones are unreachable

1 participant