Skip to content

Add deterministic weekly workflow boundary - #36

Closed
Pigbibi wants to merge 2 commits into
mainfrom
feat/pert-weekly-workflow-boundary-reslice
Closed

Add deterministic weekly workflow boundary#36
Pigbibi wants to merge 2 commits into
mainfrom
feat/pert-weekly-workflow-boundary-reslice

Conversation

@Pigbibi

@Pigbibi Pigbibi commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Fresh reslice from origin/main implementing the producer-side weekly workflow boundary. This does not reuse PR #35.

  • Adds a side-effect-free dispatch guard before RSS fetch/live publication.
  • Manual runs require an exact completed UTC ISO week.
  • Scheduled runs read the current run through GitHub's workflow-run REST API and validate fixed repository/workflow path/main ref, run id, event=schedule, run_attempt=1, and full producer SHA. The API created_at date determines the previous complete ISO week; runner date -u is not period authority.
  • Adds only actions:read to existing permissions; no id-token, secrets, or new external store.
  • Orders existing live publication and rss-source-pipeline upload before dedicated weekly build, so dedicated fail-closed does not hide legacy/source evidence.
  • Keeps the exact political-event-weekly-v1 five-file/30-day/feed-complete/digest-bound contract.

Scope boundaries

No QAR consumer, Pages, publisher, monthly, identity/store/registry, migration/compatibility, trading, position, order, broker, funds, or leverage changes.

Validation

  • python3 -m pytest -q — 132 passed
  • uv run pytest -q — 132 passed
  • python3 -m compileall -q src scripts tests — passed
  • actionlint .github/workflows/rss_source_pipeline.yml — passed
  • git diff --check — passed
  • ruff — unavailable locally
  • local schedule/manual guard characterization passed

External workflow execution is intentionally not triggered by this worker.

Co-Authored-By: Codex <noreply@openai.com>
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🤖 Codex PR Review

🚫 Merge blocked: 1 serious issue(s) found in high-risk files

⚖️ Codex Review Arbitration

🚫 block: Current finding remains valid. The PR still allows any already-completed manual week regardless of age: validate_manual_period() only enforces Monday/Sunday shape plus expected_end <= run_created_at.date(), with no lower bound or source-window check. In the workflow, the RSS fetch is still a live/current run and the manual period_start/as_of are not used to derive the fetch window; days remains a separate input with default "50". Then build_weekly_artifact() simply filters the already-fetched source_events to the requested dates and explicitly allows zero matching rows via _csv_snapshot(..., allow_empty=True), which tests/test_weekly_artifact.py::test_event_filtering_and_zero_event_are_deterministic locks in. feed_status.complete only validates the current fetch status object, not whether the fetched snapshot fully covers the requested historical week. That means an older manual week outside the live RSS/default horizon can still produce an empty or truncated weekly artifact while the feed status reports success. This does not conflict with the prior blocking finding; the prior one required rejecting current/future incomplete weeks, while this one concerns too-old completed weeks built from an unpinned live snapshot.

🚫 Blocking Issues

These issues must be fixed before this PR can be merged:

1. 🟠 [HIGH] Logic in src/political_event_tracking_research/workflow_boundary.py

validate_manual_period() accepts any older completed ISO week, but the workflow still builds the artifact from the current RSS fetch/live snapshot. For manual runs outside the effective feed retention window (or outside the default days horizon), build_weekly_artifact() will silently filter whatever happens to be present and can publish an empty or truncated historical week while feed_status.complete still reports success for the current fetch. (line 51)

Suggestion: Fail closed for manual periods that are older than the supported source window, or derive/validate the fetch window from the requested week before publishing. If historical backfills are required, bind the build to a pinned historical source snapshot instead of the current live RSS pull.

ℹ️ Other Findings

1. 🟡 [MEDIUM] Logic in scripts/validate_weekly_workflow.py

The workflow passes --producer-ref "${GITHUB_SHA}", but the script never compares that value with the head_sha returned by the Actions REST payload. If the checked-out commit and the validated run payload ever diverge, the job will execute code from one revision while stamping the artifact with another producer_ref, breaking provenance and weakening the boundary this PR is trying to enforce. (line 32)

Suggestion: After validate_scheduled_run() / validate_manual_run(), explicitly require args.producer_ref == evidence.producer_ref and fail closed on mismatch before any fetch, write, or publish step.


Review by Codex PR Review bot • PR

@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: 9137cd7f02

ℹ️ 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".



def _status(value: object) -> WeeklyFeedStatus:
if not isinstance(value, Mapping) or any(key not in value for key in ("feed_count", "successful_feed_count", "failed_feed_count", "complete")):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Populate feed completion before requiring it

The workflow passes data/output/rss_source_pipeline/source_fetch_status.json from fetch_rss_sources.py, whose write_fetch_status() only emits generated_at, feed counts, item_count, and feeds; it never writes complete. With a fully successful fetch this check therefore raises feed_status_invalid, so every Build completed weekly producer artifact step exits before uploading political-event-weekly-v1 unless the status writer is updated or this adapter derives complete from the existing counts.

Useful? React with 👍 / 👎.

Comment on lines +58 to +60
if start.weekday() != 0 or end != expected_end - timedelta(days=1):
raise _invalid("manual_period_mismatch")
return start, end

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 Reject incomplete manual periods in the guard

validate_manual_period() only checks Monday/Sunday shape, so a manual dispatch for the current or a future ISO week (for example period_start=2026-07-13, as_of=2026-07-19 on July 15, 2026) passes the pre-side-effect guard. build_weekly_artifact() later rejects the same period as generated_at_invalid because generated_at is before period_end_exclusive, but that happens after RSS fetch and rss-source-pipeline upload (and live publication when commit_outputs=true), defeating the fail-fast boundary for incomplete weeks.

Useful? React with 👍 / 👎.

raise _invalid("generated_at_invalid")
if source_provenance != "official_rss_source_pipeline_v1" or run_mode not in {"scheduled", "manual"}:
raise _invalid("producer_contract_invalid")
raw_digest = _snapshot_digest(source_events, watchlist)

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 Bind the snapshot digest to emitted bytes

When the RSS snapshot contains rows outside the requested week, political_events.csv is filtered before being emitted but source_snapshot_digest is computed over the unfiltered input bytes. The five-file weekly artifact therefore does not contain the bytes needed to recompute this digest, and parse_weekly_artifact() only checks the per-file hashes, so a rewritten lock/manifest can carry an arbitrary source_snapshot_digest while still parsing successfully. For a digest-bound artifact, compute the aggregate over the emitted files or include the raw snapshot being digested.

Useful? React with 👍 / 👎.

source_events=args.source_events.read_bytes(),
watchlist=args.watchlist.read_bytes(),
feed_status=feed_status,
source_provenance="official_rss_source_pipeline_v1",

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 Bind custom inputs before labeling artifacts official

workflow_dispatch still lets operators point feeds_path, aliases_path, and watchlist_path at alternate CSVs, but the weekly builder always stamps the artifact with official_rss_source_pipeline_v1 and the five files do not record the config/feed identity. If a manual test uses a reduced feed list or alternate aliases/watchlist, the upload has the same political-event-weekly-v1 name and official provenance as the default scheduled artifact, so downstream consumers cannot tell that the feed universe was changed; either gate the weekly artifact to default inputs or bind the config paths/hashes/feed IDs in the contract.

Useful? React with 👍 / 👎.

Co-Authored-By: Codex <noreply@openai.com>
@Pigbibi

Pigbibi commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

PERMANENT_FREEZE/CLOSE_RESLICE: repeated terminal HIGH after absolute-final closure. Preserve branch, commits, reviews, checks, and tests; no further code action.

@Pigbibi Pigbibi closed this Jul 15, 2026

@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: 935309f235

ℹ️ 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".

Comment on lines +67 to +68
ref: ${{ github.sha }}
persist-credentials: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep the checkout pushable for live output commits

When COMMIT_OUTPUTS is true (scheduled runs and manual publish runs), the later publish step commits and invokes plain git push. This checkout is no longer pushable: ref: ${{ github.sha }} checks out a commit instead of the main branch, and persist-credentials: false opts out of the checkout token that actions/checkout says enables authenticated git commands (README); as soon as generated CSVs change, the push fails before either artifact upload runs. Check out a branch/push an explicit ref with token auth before keeping this hardening.

Useful? React with 👍 / 👎.

raise _invalid("manual_period_invalid") from None
if start.weekday() != 0 or end != expected_end - timedelta(days=1):
raise _invalid("manual_period_mismatch")
if run_created_at is not None and (type(run_created_at) is not datetime or run_created_at.tzinfo != timezone.utc or expected_end > run_created_at.date()):

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 Reject stale manual weeks without snapshots

When workflow_dispatch is used for any older completed ISO week, this guard accepts it even though the workflow always fetches the current RSS feeds rather than a historical snapshot for that week. A July manual run for a January period can therefore emit a complete-looking weekly artifact with zero or partial January events, which can silently corrupt downstream experiments; restrict manual periods to the immediately previous completed week or require an explicit historical source snapshot.

Useful? React with 👍 / 👎.

Comment on lines +39 to +40
if args.run_attempt != 1:
raise WorkflowBoundaryError("run_attempt_invalid")

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 Allow reruns to reuse the original attempt evidence

On a GitHub re-run, GITHUB_RUN_ATTEMPT increments while GITHUB_RUN_ID remains the same, so this guard exits before rebuilding the weekly artifact for attempts 2+. If the scheduled run fails after fetching or during artifact upload, operators cannot recover the same locked weekly production run with GitHub's normal re-run flow; allow reruns while binding the lock to attempt 1 evidence instead of rejecting the current attempt.

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