Skip to content

fix(calendar): export VTODO CREATED from task creation time - #1653

Draft
seonghobae wants to merge 5 commits into
autoresearch/frontend-sec-bumpfrom
autoresearch/calendar-created-at-1086
Draft

seonghobae wants to merge 5 commits into
autoresearch/frontend-sec-bumpfrom
autoresearch/calendar-created-at-1086

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Current authority — 2026-09-11

  • protected root: develop@042b0c70531b229af3acbd0421a2f23098d848b3
  • canonical dependency-security parent: #1623@17a7618eda2b212b691f08fa936e042b34258fc9
  • original direct-develop CREATED repair: db74bb189817345fc9dbe1db038e5e787e5d9a45
  • ordinary parent adoption: 443d13e1446c8d7140e889a8bcbcf4c2b616f3bd
  • UTC-contract RED: e74537faa3cf39e7f628dbc5be4d6adefdbe800e
  • causal UTC repair: 184446b5a2c5e797e62ba5aa6dd5ce65bbc691ba
  • exact head / doctoring: f2f689c04b84b2eac4e36ff79c7343266885dc18
  • lifecycle: Draft / RFC 5545 VTODO change-management repair / CodeRabbit exact-head APPROVED / exact-base/head executable receipt + parent integration pending / do not merge

Finding and repair

generate_ics_from_task() carried CalendarTask.created_at but discarded it when generating VTODO, so downstream calendar clients received DTSTAMP without the calendar-store creation timestamp. The original repair added standard CREATED and a parsed regression.

Fresh standards review found a second invariant in the same boundary. RFC 5545 §3.8.7.1 requires CREATED to be UTC and §3.8.7.2 requires DTSTAMP on VTODO and likewise requires UTC. Passing arbitrary datetime objects directly to the serializer left that requirement implicit and could allow non-UTC or host-dependent naive values.

Source-order RED e74537f... requires offset-aware non-UTC inputs to serialize as UTC Z values and requires naive created_at / updated_at values to fail closed. Causal fix 184446b... restores CREATED and routes both change-management timestamps through one UTC normalization boundary. Naive values raise a field-specific ValueError instead of acquiring local-machine timezone meaning. DUE is intentionally unchanged because RFC 5545 permits other DATE-TIME forms for that property.

The production writeback caller in backend/api/calendar.py already constructs both values with datetime.datetime.now(datetime.timezone.utc), so the stricter serializer boundary preserves the live path.

Owner topology

The direct-develop predecessor inherited Security Scan failures from the stale frontend dependency tree. That source is not owned by a calendar serializer lane. 443d13e... preserves db74bb1... as first-parent provenance, adopts current #1623 as second parent, and starts from #1623's exact tree. The calendar source/test are then restored with the stronger RFC contract and doctoring; no dependency, lockfile, workflow, or security-owner source is copied here.

Fresh compare over #1623 is ahead-only / behind 0 and limited to exactly three files: backend/services/calendar_sync.py, backend/tests/test_calendar_sync.py, and docs/doctoring/calendar-vtodo-change-timestamps.md.

Evidence boundary

Pre-retarget direct-develop runs do not transfer. Current exact f2f689c... on feature base 17a7618... still has zero PR-triggered repository workflow runs at the latest lookup. This remains a live canary for the stacked-PR executable-evidence defect owned by ContextualWisdomLab/.github#2073; do not retarget to develop, push a dummy commit, copy workflow source, or synthesize a status.

CodeRabbit submitted formal APPROVED at 2026-09-11T02:51:26Z, after exact f2f689c... was created, so the independent current-head review lane is satisfied for the unchanged head. That approval does not substitute for executable evidence or #1623 prerequisite integration.

The UTC RED commit is source-order evidence, not claimed as a terminal hosted RED.

Standards traceability

docs/doctoring/calendar-vtodo-change-timestamps.md records the problem, constraint, alternatives, RED/fix lineage, acceptance boundary, and APA 7th citation for RFC 5545:

Desruisseaux, B. (2009). Internet Calendaring and Scheduling Core Object Specification (iCalendar) (RFC 5545). Internet Engineering Task Force. https://doi.org/10.17487/RFC5545

Keep Draft until #1623 is protected-integrated or canonical stacked verification produces an exact current-base/head executable receipt with then-live required contexts terminal-success. No force push, destructive rebase, stale-evidence transfer, self-approval, dependency-owner duplication, or gate weakening.

generate_ics_from_task serialized only DTSTAMP (updated_at), so calendar clients could not distinguish task creation from modification. Emit iCalendar CREATED from CalendarTask.created_at per RFC 5545 and cover it with a parsed iCalendar regression.
@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: e8826849-c362-4012-bda7-a5a26e4c0101

📥 Commits

Reviewing files that changed from the base of the PR and between db74bb1 and f2f689c.

📒 Files selected for processing (3)
  • backend/services/calendar_sync.py
  • backend/tests/test_calendar_sync.py
  • docs/doctoring/calendar-vtodo-change-timestamps.md

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The ICS generator now validates created_at and updated_at, rejects naive timestamps, and normalizes valid values to UTC before emitting CREATED and DTSTAMP. Tests and documentation cover these rules.

Changes

Calendar timestamp normalization

Layer / File(s) Summary
Validate and normalize VTODO timestamps
backend/services/calendar_sync.py, backend/tests/test_calendar_sync.py, docs/doctoring/calendar-vtodo-change-timestamps.md
The generator rejects naive or invalid-offset timestamps and emits valid CREATED and DTSTAMP values in UTC. Tests verify parsed values, UTC conversion, and field-specific errors. Documentation records the timestamp rules and unchanged DUE behavior.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~15 minutes

Merge Risk: ⚪ Minimal · up to f2f68

Calendar exports now serialize change-management timestamps in UTC and reject invalid naive values, with no remaining actionable merge risk.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: exporting VTODO CREATED from the task creation time.
✨ 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 autoresearch/calendar-created-at-1086

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review exact develop@042b0c70531b229af3acbd0421a2f23098d848b3..db74bb189817345fc9dbe1db038e5e787e5d9a45. Check RFC 5545 §3.8.7.1 CREATED UTC conformance, serialization behavior, and whether the two-file delta preserves the distinct #1086/#1195 canonical email-provenance ownership. This PR now uses Refs #1086 rather than an auto-closing keyword.

@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='042b0c70531b229af3acbd0421a2f23098d848b3'
head='db74bb189817345fc9dbe1db038e5e787e5d9a45'

echo '== Commit relationship =='
git merge-base --is-ancestor "$base" "$head" && echo 'base is an ancestor of head'
git diff --check "$base..$head"
git diff --name-status "$base..$head"
git diff --stat "$base..$head"
git diff --find-renames --find-copies "$base..$head"

echo '== Candidate file maps =='
fd -t f 'calendar_sync\.py$|calendar\.py$' backend | sort | while IFS= read -r f; do
  echo "--- $f"
  ast-grep outline "$f" --items all --match 'generate_ics_from_task|CalendarTask' --view expanded || true
done

echo '== Relevant implementation, test, and caller contexts =='
rg -n -C 12 --glob '*.py' \
  'def generate_ics_from_task\b|class CalendarTask\b|created_at\s*=|updated_at\s*=|Todo\s*\(' \
  backend

echo '== Exact PR and issue metadata =='
gh pr view 1653 --repo ContextualWisdomLab/naruon \
  --json number,title,body,state,isDraft,baseRefOid,headRefOid,url,closingIssuesReferences

echo '--- Issue 1086 ---'
gh issue view 1086 --repo ContextualWisdomLab/naruon \
  --json number,title,state,body,url,closedByPullRequestsReferences

echo '--- Issue 1195 ---'
gh issue view 1195 --repo ContextualWisdomLab/naruon \
  --json number,title,state,body,url,closedByPullRequestsReferences

Length of output: 156157


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='042b0c70531b229af3acbd0421a2f23098d848b3'
head='db74bb189817345fc9dbe1db038e5e787e5d9a45'

echo '== Exact-range commit messages and issue-keyword references =='
git log --format='%H%n%B%n---' "$base..$head"
git log --format='%H %s' "$base..$head" | rg -n -i '(close[sd]?|fix(e[sd])?|resolve[sd]?|`#1086`|`#1195`)' || true

echo '== All CalendarTask construction and calendar export call sites =='
rg -n -U -C 8 --glob '*.py' \
  '(CalendarTask\s*\(|generate_ics_from_task\s*\()' backend

echo '== Calendar dependency declaration and installed serializer source, if available =='
rg -n -C 3 --glob 'requirements*.txt' --glob 'pyproject.toml' --glob 'poetry.lock' --glob 'uv.lock' \
  '(^|[-_ ])icalendar([<>=!~ ].*|$)' .
python - <<'PY'
from pathlib import Path
candidates = []
for root in (Path('.'), Path('/usr/local/lib'), Path('/usr/lib')):
    if root.exists():
        candidates.extend(root.rglob('prop.py'))
for path in candidates:
    if 'icalendar' in str(path) and path.is_file():
        print(f'--- {path}')
        text = path.read_text(errors='replace')
        for term in ('class vDDDTypes', 'def to_ical'):
            start = text.find(term)
            if start >= 0:
                print(text[start:start+2800])
                break
PY

echo '== Pull request references and issue timeline events =='
gh api "repos/ContextualWisdomLab/naruon/issues/1653/timeline?per_page=100" \
  -H 'Accept: application/vnd.github+json' \
  --jq '.[] | select(.event == "cross-referenced" or .event == "connected" or .event == "closed" or .event == "referenced") | {event,created_at,source:(.source.issue.number // .source.commit.sha // null),commit_id:(.commit_id // null)}' || true

gh api "repos/ContextualWisdomLab/naruon/issues/1086/timeline?per_page=100" \
  -H 'Accept: application/vnd.github+json' \
  --jq '.[] | select(.event == "cross-referenced" or .event == "closed" or .event == "referenced") | {event,created_at,source:(.source.issue.number // .source.commit.sha // null),commit_id:(.commit_id // null)}' || true

Length of output: 16034


@seonghobae I found one merge-blocking ownership issue.

  • db74bb189817345fc9dbe1db038e5e787e5d9a45 is exactly one commit ahead of 042b0c70531b229af3acbd0421a2f23098d848b3.
  • The range changes exactly two files.
  • CREATED is added from CalendarTask.created_at.
  • The only production caller supplies an aware UTC value.
  • The regression parses the generated VTODO and confirms that decoded CREATED equals the aware UTC source value.
  • The calendar export change does not overlap #1195's email-provenance files or implementation.

However, GitHub currently lists #1086 in PR #1653’s closingIssuesReferences. This conflicts with the required ownership boundary, even though the current PR body uses Refs #1086`` and the exact commit message has no closing keyword. Clear the closing association before merge. #1195 must remain the canonical lifecycle owner for `#1086`.

✅ 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.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Sep 10, 2026
@seonghobae
seonghobae changed the base branch from develop to autoresearch/frontend-sec-bump September 11, 2026 02:45

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Fresh exact-range review requested for canonical base 17a7618eda2b212b691f08fa936e042b34258fc9 → head f2f689c04b84b2eac4e36ff79c7343266885dc18. Please verify the RFC 5545 CREATED/DTSTAMP UTC contract, naive-datetime fail-closed behavior, and that the effective delta remains calendar-only plus doctoring. Pre-retarget checks/reviews are predecessor evidence only.

@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='17a7618eda2b212b691f08fa936e042b34258fc9'
head='f2f689c04b84b2eac4e36ff79c7343266885dc18'
repo='ContextualWisdomLab/naruon'

echo '== Exact range integrity and effective delta =='
git merge-base --is-ancestor "$base" "$head"
echo 'base is an ancestor of head'
git log --format='%H%n%B%n---' "$base..$head"
git diff --check "$base..$head"
git diff --name-status "$base..$head"
git diff --stat "$base..$head"
git diff --find-renames --find-copies "$base..$head"
git diff --unified=80 "$base..$head" -- backend/services/calendar_sync.py backend/tests/test_calendar_sync.py || true

echo '== Candidate file maps =='
fd -t f -a 'calendar_sync\.py$|models?\.py$|requirements.*\.txt$|pyproject\.toml$|poetry\.lock$|uv\.lock$' . \
  | sort \
  | while IFS= read -r file; do
      echo "--- $file"
      ast-grep outline "$file" --items all \
        --match 'generate_ics_from_task|CalendarTask|Todo|datetime|icalendar' \
        --view expanded || true
    done

echo '== Timestamp construction, export, and test contexts =='
rg -n -U -C 15 --glob '*.py' \
  '(def generate_ics_from_task\s*\(|class CalendarTask\b|CalendarTask\s*\(|generate_ics_from_task\s*\(|created_at\s*=|updated_at\s*=|\.add\(\s*["'\''](?:CREATED|DTSTAMP)["'\''])' \
  backend || true

echo '== Calendar serialization dependency declarations =='
rg -n -C 4 \
  --glob 'requirements*.txt' --glob 'pyproject.toml' --glob 'poetry.lock' --glob 'uv.lock' \
  '(^|[-_[:space:]])icalendar([<>=!~[:space:]].*|$)' . || true

echo '== Installed icalendar DATE-TIME serialization and parsing source, if present =='
python - <<'PY'
from pathlib import Path
roots = [Path('/usr/local/lib'), Path('/usr/lib')]
for root in roots:
    if not root.exists():
        continue
    for path in root.rglob('prop.py'):
        if 'icalendar' not in str(path).lower():
            continue
        text = path.read_text(errors='replace')
        if 'class vDDDTypes' not in text:
            continue
        print(f'--- {path}')
        start = text.index('class vDDDTypes')
        print(text[start:start + 6500])
PY

echo '== PR metadata and issue-reference state =='
gh pr view 1653 --repo "$repo" \
  --json number,state,isDraft,title,body,baseRefOid,headRefOid,closingIssuesReferences,url
gh api "repos/$repo/issues/1653/timeline?per_page=100" \
  -H 'Accept: application/vnd.github+json' \
  --jq '.[] | select(.event == "cross-referenced" or .event == "connected" or .event == "referenced" or .event == "closed") | {event, created_at, source: (.source.issue.number // .source.commit.sha // null)}' || true

Length of output: 203004


🤖 web_search executed:

RFC 5545 Section 3.8.7.1 CREATED and Section 3.8.7.2 DTSTAMP VTODO MUST be specified in UTC

Length of output: 13472


@seonghobae Review complete for 17a7618eda2b212b691f08fa936e042b34258fc9..f2f689c04b84b2eac4e36ff79c7343266885dc18.

I found no code findings.

  • The base is an ancestor of the requested head.
  • The effective delta changes three files only: calendar serializer, calendar tests, and calendar-specific doctoring.
  • CREATED uses CalendarTask.created_at.
  • DTSTAMP uses CalendarTask.updated_at.
  • Both values pass through one boundary that rejects naive or offset-less datetimes and normalizes aware values to UTC before serialization.
  • The tests verify UTC Z output for non-UTC offsets and field-specific ValueError failures for naive created_at and updated_at.
  • The live caller supplies UTC-aware timestamps.
  • RFC 5545 §3.8.7.1 requires UTC for CREATED. RFC 5545 §3.8.7.2 requires DTSTAMP on VTODO and requires UTC for its value.
  • The delta contains no email-provenance, dependency, lockfile, or workflow source. PR #1653 also has no closing issue references.

Runtime tests were not executed in this review environment.

✅ 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.

@seonghobae seonghobae added bug Something isn't working priority: high High-priority or P1 work labels Sep 12, 2026 — with ChatGPT Codex Connector
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority: high High-priority or P1 work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant