Skip to content

feat(portfolio-truth): --portfolio-truth-allow-empty-notion carry-forward#121

Merged
saagpatel merged 1 commit into
mainfrom
feat/allow-empty-notion-carry-forward
Jun 28, 2026
Merged

feat(portfolio-truth): --portfolio-truth-allow-empty-notion carry-forward#121
saagpatel merged 1 commit into
mainfrom
feat/allow-empty-notion-carry-forward

Conversation

@saagpatel

Copy link
Copy Markdown
Owner

Problem

The nightly portfolio-maintenance launchd job has failed every night since 2026-06-23. It runs report saagpatel --portfolio-truth with no NOTION_TOKEN, and the data-safety guard in portfolio_truth_publish.py correctly refuses to overwrite the existing output/portfolio-truth-latest.json (142 Notion context rows) with a 0-row headless run. The result: portfolio truth froze at 2026-06-19, and the downstream personal-ops ghra hub spoke degraded to 8 days stale.

The guard's error message already pointed at the intended escape ("run with an explicit no-Notion path"), but that path was never actually implemented as a flag.

Fix

Add an opt-in --portfolio-truth-allow-empty-notion flag (on both the report subcommand and the legacy top-level parser). When live Notion is unavailable, it carries the prior artifact's per-project advisory context forward (load_prior_notion_context) instead of dropping to zero, so a headless refresh updates risk / activity / git signals without losing advisory data.

  • Carry-forward injects at the single notion_context seam in build_portfolio_truth_snapshot, gated on include_notion.
  • The flag suppresses the drop guard (the operator explicitly opted into empty-Notion publishing); when the flag is off, the guard still protects against silent Notion drop exactly as before.
  • source_summary.notion_context_carried_forward records provenance, and a logger.warning fires whenever carry-forward activates so a real Notion regression stays observable.

Verification

  • Full suite: 2637 passed, 2 skipped; ruff check src/ tests/ clean.
  • New tests: reconstructor units (missing / malformed / empty-advisory), publish-level carry-forward, guard-still-fires when the flag is off, flag-suppresses-guard with no prior context, CLI report-subcommand parse, and an end-to-end run via main().
  • Sanity-checked load_prior_notion_context against the real frozen artifact: reconstructs 131 carry-forward rows.

Activation (follow-up, not in this PR)

After merge, the nightly job command needs --portfolio-truth-allow-empty-notion appended, and the checkout the job runs from must carry this change.

…-forward

The nightly portfolio-maintenance job has failed every night since 2026-06-23: it runs `report --portfolio-truth` with no NOTION_TOKEN, and the data-safety guard correctly refuses to overwrite existing truth (142 Notion context rows) with a 0-row headless run. This froze portfolio-truth-latest.json and degraded the personal-ops ghra hub spoke.

Add an opt-in --portfolio-truth-allow-empty-notion flag: when live Notion is unavailable, carry forward the prior artifact's per-project advisory context (load_prior_notion_context) instead of dropping to zero, so the refresh updates risk/activity/git signals without losing advisory data. The flag suppresses the drop guard (operator explicitly opted into empty-Notion publishing); source_summary records notion_context_carried_forward for provenance; a logger.warning fires on carry-forward so a real Notion regression stays observable.

Default (flag off) behavior is unchanged: the guard still protects against silent Notion drop.

Tests: reconstructor units, publish-level carry-forward + guard-still-fires + flag-suppresses-guard, CLI report-subcommand parse, and end-to-end via main().
@saagpatel saagpatel merged commit d9b5a6b into main Jun 28, 2026
4 checks passed
@saagpatel saagpatel deleted the feat/allow-empty-notion-carry-forward branch June 28, 2026 07:40

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 323b26902f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

legacy_rows = load_legacy_registry_rows(legacy_registry_path)
notion_context = load_safe_notion_project_context() if include_notion else {}
notion_context_carried_forward = False
if include_notion and not notion_context and notion_context_fallback:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve intentional empty Notion results

When this flag is used with a valid Notion token against a reachable Projects data source that legitimately has zero context rows, load_safe_notion_project_context() returns {} and this condition treats that the same as an unavailable Notion bootstrap. The publish then restores every advisory row from portfolio-truth-latest.json, so intentional row removals or an intentionally empty Notion source cannot be reflected while the scheduled flag is enabled; the fallback should only apply when the live load is unavailable, not when it succeeds empty.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant