Context
We recently implemented a "Child-Triggered Parent Refresh" strategy to fix sync gaps where adding a sub-issue didn't update the parent's updatedAt timestamp. This works well for parent-child relationships.
Problem
The current logic only checks issue.parent. It does not handle:
- Blocking Relationships: If Issue A blocks Issue B, and only A is updated/fetched, B's local file might remain stale (missing the "Blocked by A" entry) if GitHub doesn't bump B's
updatedAt.
- Edge Cases: Any other relationship change where the "other side" isn't automatically flagged as modified by GitHub.
Proposed Solution: Timeline-Based Discovery
Extend the post-processing logic in IssueSyncer.mjs to scan the timelineItems of all fetched issues.
- Scan Events: Iterate through
allIssues (the ones just pulled).
- Filter Events: Look for relationship events (
SUB_ISSUE_ADDED, BLOCKED_BY_ADDED, etc.) that occurred since the last sync.
- Collect IDs: Extract the IDs of the related issues (
event.subIssue.number, event.blockingIssue.number, etc.).
- Force Update: Add these IDs to the
forceUpdate set (merging with the existing issue.parent logic).
Implementation
Refactor the parentIdsToUpdate logic into a broader relatedIssuesToUpdate set.
const relatedIssuesToUpdate = new Set();
allIssues.forEach(issue => {
if (issue.parent) {
relatedIssuesToUpdate.add(issue.parent.number);
}
const relationshipEvents = issue.timelineItems?.nodes.filter(event =>
['SUB_ISSUE_ADDED_EVENT', 'BLOCKED_BY_ADDED_EVENT', ].includes(event.__typename) &&
new Date(event.createdAt) > new Date(metadata.lastSync)
);
relationshipEvents?.forEach(event => {
if (event.subIssue) relatedIssuesToUpdate.add(event.subIssue.number);
if (event.parent) relatedIssuesToUpdate.add(event.parent.number);
if (event.blockingIssue) relatedIssuesToUpdate.add(event.blockingIssue.number);
if (event.blockedIssue) relatedIssuesToUpdate.add(event.blockedIssue.number);
});
});
This ensures complete referential integrity for all relationship types.
Context
We recently implemented a "Child-Triggered Parent Refresh" strategy to fix sync gaps where adding a sub-issue didn't update the parent's
updatedAttimestamp. This works well for parent-child relationships.Problem
The current logic only checks
issue.parent. It does not handle:updatedAt.Proposed Solution: Timeline-Based Discovery
Extend the post-processing logic in
IssueSyncer.mjsto scan thetimelineItemsof all fetched issues.allIssues(the ones just pulled).SUB_ISSUE_ADDED,BLOCKED_BY_ADDED, etc.) that occurred since the last sync.event.subIssue.number,event.blockingIssue.number, etc.).forceUpdateset (merging with the existingissue.parentlogic).Implementation
Refactor the
parentIdsToUpdatelogic into a broaderrelatedIssuesToUpdateset.const relatedIssuesToUpdate = new Set(); allIssues.forEach(issue => { // 1. Existing Parent Check if (issue.parent) { relatedIssuesToUpdate.add(issue.parent.number); } // 2. New Timeline Scan const relationshipEvents = issue.timelineItems?.nodes.filter(event => ['SUB_ISSUE_ADDED_EVENT', 'BLOCKED_BY_ADDED_EVENT', /* ... all types */].includes(event.__typename) && new Date(event.createdAt) > new Date(metadata.lastSync) ); relationshipEvents?.forEach(event => { if (event.subIssue) relatedIssuesToUpdate.add(event.subIssue.number); if (event.parent) relatedIssuesToUpdate.add(event.parent.number); if (event.blockingIssue) relatedIssuesToUpdate.add(event.blockingIssue.number); if (event.blockedIssue) relatedIssuesToUpdate.add(event.blockedIssue.number); }); });This ensures complete referential integrity for all relationship types.