Skip to content

Event lifecycle: tracker-io engine + create/update/status-event skills#4

Merged
rparundekar merged 18 commits into
mainfrom
feat/event-lifecycle
Jul 1, 2026
Merged

Event lifecycle: tracker-io engine + create/update/status-event skills#4
rparundekar merged 18 commits into
mainfrom
feat/event-lifecycle

Conversation

@rparundekar

Copy link
Copy Markdown
Collaborator

Summary

Adds the event-lifecycle layer on top of the AAIF meetup skills — the per-event runbook (Event Tracker.docx) was the one part of running an event that nothing automated.

Two pieces:

  1. lib/aaif_meetups/ — a deterministic, stdlib-only docx engine (no Drive calls, no third-party deps):

    • office.py — read/write word/document.xml in a .docx zip; navigate/edit tables, rows, cells, paragraph runs.
    • tracker.py — event model over a tracker (list_events/read_event), edits (set_field/set_due_dates/add_event), and the shared date-stamping rule (new_due = new_event_date + (example_task_due − example_event_date); clock-time day-of cells are left alone).
  2. Three skills that operate on a local tracker file; each SKILL.md instructs the agent to drive the gws CLI directly (locate → download → upload):

    • aaif-event-status — read-only digest of overdue / due-soon tasks by owner.
    • aaif-create-event — clone the example section, fill details, stamp all phase due-dates; dedup-guard; mode is implicit (chapter ⇒ in-person tracker, series ⇒ online tracker).
    • aaif-update-event — change-driven edits ("add speaker", "move date"); recomputes due-dates when the date moves and flags stale downstream assets.

Also in this branch (Drive-cleanup groundwork):

  • Retired the per-folder SKILLS.md.docx references in create_chapter/create_series docs/docstrings (the 45 Drive copies were trashed and the template trackers re-pointed at this repo separately).

Design principle

Python = well-known, unchanging transforms only (clone / replace / restamp). Every Google Drive action stays with the agent via the gws CLI, kept flexible — Python never nests gws calls. create_chapter.py/create_series.py are unchanged from main apart from a docstring fix.

Testing

  • python -m unittest discover -s lib/aaif_meetups/tests — 14 tests (office round-trip + primitives, date math, event model, writes, clone-and-append with save→reload corruption check).
  • Per-skill core tests (classify, apply_local, apply_changes) on real tracker fixtures.
  • End-to-end dry-run validated against live Drive (read-only + local edit).

Spec: docs/superpowers/specs/2026-06-30-aaif-event-lifecycle-design.md · Plan: docs/superpowers/plans/2026-06-30-aaif-event-lifecycle.md

Out of scope (follow-ups)

File-aware banner/deck generation (#3), chapter/series health (#4), and the two-plugin ops/organizer split (#5).

🤖 Generated with Claude Code

rparundekar and others added 15 commits June 30, 2026 20:17
Point create-chapter/create-online-series docs and script docstrings at the
repo skills instead of the retired per-folder SKILLS.md.docx. Add the design
spec and implementation plan for the event-lifecycle skills.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Renamed from gws.py to gws_cli.py to make clear it wraps the real gws binary
(https://github.com/googleworkspace/cli) via subprocess — it does not
reimplement Drive. Same calls create_chapter.py already uses, lifted into one
shared module.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the duplicated _gws/gws_json/... block from both scripts; import the still-
used helpers (list_children/create_folder/copy_file/gws_download/gws_upload) plus
FOLDER/MIME_BY_EXT from lib/aaif_meetups/gws_cli.py. Behavior unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ngine

Per the principle that gws actions belong to the agent (flexible) and Python is
only for well-known, unchanging transforms:

- Delete lib/aaif_meetups/gws_cli.py and remove locate_tracker from tracker.py —
  no Drive calls in Python anymore.
- The 3 skills (event-status/create-event/update-event) now operate on a LOCAL
  docx path; each SKILL.md instructs the agent to run gws (locate/download/upload)
  directly and call the deterministic script in between.
- Revert create_chapter/create_series to their original self-contained state.
- office.py + tracker.py remain pure-Python docx surgery (read/clone/set-field/
  restamp + date math).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 30, 2026 15:37

Copilot AI 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.

Pull request overview

This PR introduces an “event lifecycle” layer for AAIF meetups by adding a stdlib-only .docx (OOXML) engine and tracker model, plus three skills to create events, update events (including due-date restamping), and generate a read-only status digest from a local Event Tracker.docx.

Changes:

  • Add lib/aaif_meetups/office.py + tracker.py for deterministic local .docx table parsing/editing and event-centric operations (list/read/set-field/restamp/add).
  • Add three skills (aaif-event-status, aaif-create-event, aaif-update-event) with corresponding local-file scripts and unit tests.
  • Update chapter/series creation docs/docstrings to remove retired SKILLS.md.docx references and point organizers at aaif-* skills instead.

Reviewed changes

Copilot reviewed 19 out of 23 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
skills/aaif-update-event/SKILL.md New skill doc for change-driven event updates (download → local edit → upload).
skills/aaif-update-event/scripts/update_event.py CLI for updating detail fields and restamping due dates in a local tracker docx.
skills/aaif-update-event/scripts/test_update_event.py Unit tests for update-event core behavior (stale flags + date restamp).
skills/aaif-event-status/SKILL.md New skill doc for read-only task status digest (overdue / due soon).
skills/aaif-event-status/scripts/event_status.py CLI for computing overdue/due-soon tasks from a local tracker docx.
skills/aaif-event-status/scripts/test_event_status.py Unit test for classification logic (overdue vs due soon vs ignored).
skills/aaif-create-event/SKILL.md New skill doc for cloning example section and stamping due dates for a new event.
skills/aaif-create-event/scripts/create_event.py CLI to add a new event section to a local tracker docx (with dedup + dry-run).
skills/aaif-create-event/scripts/test_create_event.py Unit test verifying add-event behavior on a fixture copy.
skills/aaif-create-online-series/SKILL.md Doc update removing retired SKILLS.md.docx references.
skills/aaif-create-online-series/scripts/create_series.py Docstring update to reference aaif-* skills instead of SKILLS.md.
skills/aaif-create-chapter/SKILL.md Doc update removing retired SKILLS.md.docx references.
skills/aaif-create-chapter/scripts/create_chapter.py Docstring update to reference aaif-* skills instead of SKILLS.md.
lib/aaif_meetups/office.py New stdlib OOXML helpers for reading/writing word/document.xml and editing tables/cells.
lib/aaif_meetups/tracker.py New event model and write operations (set_field, restamp due dates, clone+append event).
lib/aaif_meetups/init.py Package marker for aaif_meetups.
lib/aaif_meetups/tests/init.py Test package marker.
lib/aaif_meetups/tests/test_office.py Unit tests for .docx round-trip and table primitives.
lib/aaif_meetups/tests/test_tracker.py Unit tests for date parsing/restamping, event model, and add-event behavior.
docs/superpowers/specs/2026-06-30-aaif-event-lifecycle-design.md Design spec for the tracker-io foundation and skills (with revision note).
docs/superpowers/plans/2026-06-30-aaif-event-lifecycle.md Implementation plan and testing checklist (with revision note).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread skills/aaif-create-event/scripts/create_event.py Outdated
Comment thread skills/aaif-create-event/scripts/create_event.py
Comment thread skills/aaif-update-event/scripts/update_event.py
Comment thread skills/aaif-create-event/SKILL.md Outdated
Comment thread skills/aaif-update-event/SKILL.md Outdated
Comment thread skills/aaif-update-event/SKILL.md Outdated
Comment thread skills/aaif-event-status/SKILL.md Outdated
Comment thread lib/aaif_meetups/tracker.py Outdated
@rparundekar

Copy link
Copy Markdown
Collaborator Author

Hero Self-Review

Ran all five pr-review-toolkit agents; verified the high-impact findings empirically against both fixtures. The stdlib-only + "no gws in Python; agent drives Drive" boundary holds cleanly across every file. Findings below are real correctness issues the 18 passing tests don't cover.

Critical (1)

  • [silent-failure / comment] create_event.py:13-16 + tracker.py:220 — fields silently dropped on online trackers. FIELD_MAP maps --platform→"VENUE" and --location→"LOCATION / CITY", but the online tracker's labels are PLATFORM / STREAM / JOIN LINK (verified) — it has no VENUE/LOCATION row. add_event calls _set_detail and discards its False (not-found) return, so --platform "Zoom" on an online series prints "Done." while writing nothing. On the IRL tracker, --venue and --platform both target VENUE (last-wins collision). Fix: map platform→"PLATFORM"; make add_event collect unmatched labels and error (same contract as set_field).

Important (5)

  • [test / code-reviewer] office.py:8,16-24save_document re-serializes via ElementTree and renames every namespaced prefix (r:idns2:id; 313 ns*: prefixes after save, verified). URIs are preserved so the file stays namespace-valid, but it's a fidelity regression and test_roundtrip only counts {w}tbl by URI, so it can't catch this. Fix: scan the root's xmlns: decls and ET.register_namespace them before serializing.
  • [silent-failure / code-reviewer] tracker.py:110_select matches the first title containing the query. Write path: update_event "AI Night" can edit "AI Night · Finance Edition" instead and report success. Read path: event_status re-selects each event by title (event_status.py:55), so when one title is a substring of another, one event prints twice and the other never. Fix: prefer an exact case-insensitive title match; warn/raise on ambiguous substring. For event_status, digest the already-resolved event object instead of re-selecting by title.
  • [code-reviewer] tracker.py:209-212 — cloned event keeps the example's caption and loses its heading. The span starts at detail_idx-1, which is the literal "Example event — duplicate this whole section per night…" paragraph; the real date/title heading (detail_idx-2) is excluded. Every created event is captioned "Example event…" with no heading. Fix: include + rewrite the heading paragraph; drop/replace the caption.
  • [silent-failure] tracker.py:24parse_event_date defaults a yearless date to the current year. --date "January 15" (today 2026-06-30) → 2026-01-15, 5 months in the past, shifting all due-dates backward. Reject yearless/ambiguous dates instead of guessing.
  • [comment] aaif-update-event/SKILL.md:41-42 — detail-label list is in-person only. Online uses PLATFORM / STREAM / JOIN LINK; --set "VENUE=…" on an online series raises LookupError. Document both label sets.

Suggestions (4)

  • [silent-failure] tracker.py:88 — a typo'd DATE & TIME makes an event silently undated, dropping it from next/latest selection with no warning.
  • [code-reviewer] office.py:51set_cell_text updates hyperlink display text but not the .rels r:id target, so --luma <new> (and cloned events) show the new URL but link to the old one.
  • [type-design] Introduce a Task dataclass (tracker.py:131). The 4-field task dict is read with .get("status") across a file boundary (event_status.py), so a typo'd key silently returns a default rather than erroring.
  • [test] Coverage gaps: multi-event selection (next/latest/ambiguous substring), year-boundary date math, set_field raising on a missing label, the online fixture (downloaded but never loaded), and a save→reload document.xml fidelity assertion (not just table count).

Strengths

  • The "Python edits a local docx, agent drives gws" boundary is clean — zero subprocess/gws calls in any Python (all 5 agents confirmed).
  • add_event test is behavioral: count delta, title, status reset, restamp, and save→reload.
  • restamp correctly preserves clock-time DAY OF cells and blanks; update_event's restamp-before-overwrite ordering is explicitly tested.
  • save_document same-path write verified safe (reads all members into memory before opening the write handle).

Self-review by Claude Code

Critical:
- create_event/add_event no longer silently drop unmatched detail labels;
  add_event raises listing missing labels. Map --platform -> PLATFORM (not VENUE),
  add --join (STREAM / JOIN LINK); flags must match the tracker's labels.

Important:
- office.save_document now registers the document's namespace prefixes so
  re-serialization preserves r:id / w14: / mc: etc. (was renaming everything to ns0/1/2).
- _select prefers an exact title match, then a unique substring; ambiguous
  substrings raise instead of silently editing the wrong event.
- event_status digests the resolved event ref directly (no title round-trip).
- add_event clones+rewrites the date/title heading and drops the stale
  'Example event — duplicate this whole section' caption.
- parse_event_date rejects yearless dates (was defaulting to current year).
- update/create SKILL.md document in-person vs online detail labels.

Suggestions:
- event_status flags events whose DATE & TIME failed to parse.
- Task is now a frozen dataclass (attribute access; typo'd field raises).
- Documented set_cell_text hyperlink-target limitation.
- Added tests: multi-event selection, year-boundary dates, raise-on-missing-label,
  add_event heading/caption, online fixture, save namespace fidelity, empty-cell.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rparundekar

Copy link
Copy Markdown
Collaborator Author

Hero Self-Review Improvements

All 10 findings (1 Critical, 5 Important, 4 Suggestions) fixed in 73f2605. 31 tests pass (was 18); pre-commit clean.

Critical (1 / 1 fixed):

  • create_event.py + tracker.py:add_event — fields silently dropped on label mismatch → fixed: add_event now raises listing unmatched labels; --platform maps to PLATFORM (not VENUE), --joinSTREAM / JOIN LINK added. Verified: --platform on a chapter tracker now aborts loudly instead of no-op'ing.

Important (5 / 5 fixed):

  • office.save_document re-serialization renamed all namespace prefixes (r:idns2:id) → fixed: register the doc's xmlns prefixes before serializing; verified 0 ns*: prefixes and 11 r:id preserved after save.
  • _select first-substring match could edit/print the wrong event → fixed: exact-title match first, unique substring next, ambiguous substring raises.
  • add_event kept the "Example event — duplicate…" caption and lost the heading → fixed: heading cloned + rewritten to the new date/title; caption dropped.
  • parse_event_date defaulted yearless dates to the current year → fixed: now raises; a year is required.
  • update/create SKILL.md listed in-person labels only → fixed: both docs now document chapter vs online label sets.

Suggestions (4 / 4 fixed):

  • event_status now flags events whose DATE & TIME didn't parse (was silently anchored to today).
  • Task is now a @dataclass(frozen=True) — attribute access, so a typo'd field raises instead of returning a .get() default.
  • Documented the set_cell_text hyperlink-target limitation (display text vs .rels target) in code + create-event SKILL.md.
  • Added the missing tests: multi-event selection, year-boundary date math, raise-on-missing-label, add_event heading/caption, online fixture coverage, save namespace fidelity, empty-cell, combined --set+--date.

Commit: 73f2605


Applied by Claude Code

- create_event dedup guard now uses an exact case-insensitive title match
  (was substring; 'Eval Night' wrongly matched 'Eval Night · Builder Series').
  Extracted title_exists() and covered it with a test.
- update_event --set now rejects a value without '=' with a clear error
  instead of silently clearing a field / raising an opaque LookupError.
- All three new SKILL.md files invoke scripts via ${CLAUDE_SKILL_DIR}/scripts/...
  per CONTRIBUTING.md, so they work when installed outside the repo checkout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rparundekar

Copy link
Copy Markdown
Collaborator Author

Respond-to-PR Improvements

Addressed all 8 Copilot review comments (6 code/doc fixes; 2 were already fixed by the earlier self-review commit 73f2605). All threads resolved.

Code changes (3 applied):

  • create_event.py:dedup — substring match wrongly aborted distinct titles → now an exact case-insensitive match (title_exists()), with a test. (be27df2)
  • update_event.py:apply_changes--set without = could silently clear a field → now raises ValueError("--set must be LABEL=VALUE"), with a test. (be27df2)
  • aaif-{create,update}-event + aaif-event-status SKILL.md — scripts now invoked via ${CLAUDE_SKILL_DIR}/scripts/... per CONTRIBUTING.md so they work when installed outside the repo. (be27df2)

Already fixed in 73f2605 (resolved):

  • --venue / --platform both → VENUE: now --platformPLATFORM (distinct), and a flag whose label is absent on the tracker raises — they can no longer silently collide.
  • add_event cloned heading not updated: now rewrites the heading to the new EVENT TITLE / DATE & TIME and drops the example caption.

Commits: 73f2605, be27df2

Remaining unresolved threads: none


Applied by Claude Code

Add LF Code of Conduct and Privacy Policy as standard footers in the
Luma description, attendee reminder, and announcement skills.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rparundekar rparundekar merged commit f1005c2 into main Jul 1, 2026
2 checks passed
@rparundekar rparundekar deleted the feat/event-lifecycle branch July 1, 2026 07:17
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.

2 participants