Skip to content

planning: add Qt to web interface migration plan#9740

Closed
oharboe wants to merge 1 commit intoThe-OpenROAD-Project:masterfrom
Pinata-Consulting:qt-to-web-plan
Closed

planning: add Qt to web interface migration plan#9740
oharboe wants to merge 1 commit intoThe-OpenROAD-Project:masterfrom
Pinata-Consulting:qt-to-web-plan

Conversation

@oharboe
Copy link
Collaborator

@oharboe oharboe commented Mar 12, 2026

Add migration plan document, Gantt charts, resource allocation charts, and Python script for chart generation. Covers framework analysis (FastAPI + React), architecture design, team structure, milestones, and comparison of classic vs AI-assisted development scenarios.

Add migration plan document, Gantt charts, resource allocation charts,
and Python script for chart generation. Covers framework analysis
(FastAPI + React), architecture design, team structure, milestones,
and comparison of classic vs AI-assisted development scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@oharboe oharboe closed this Mar 12, 2026
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive migration plan for moving from a Qt-based GUI to a web interface. The plan is well-documented in the markdown file, covering architecture, scenarios, and risks. The Python script for generating Gantt and resource charts is a great addition for visualizing the plan.

My review focuses on the Python script, where I've found some significant data inconsistencies in the resource allocation chart generation that should be addressed to ensure the planning artifacts are accurate. I've also included a suggestion to improve the maintainability of the plotting code.

Comment on lines +310 to +381
def create_resource_chart(output_file="resource_chart.png"):
"""Create resource allocation charts for both scenarios."""
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(18, 7))
fig.patch.set_facecolor('#FAFAFA')

roles = ["Tech Lead", "Backend", "Frontend", "DevOps", "QA", "UX/Docs"]
colors = ["#2C3E50", "#4A90D9", "#50C878", "#9B59B6", "#E74C3C", "#F5A623"]

# Classic scenario
phases_classic = ["Found.\n(M1-3)", "MVP\n(M4-7)", "Feat.\n(M8-11)",
"Test\n(M12-14)", "Deploy\n(M15-17)", "Retire\n(M18-20)"]
data_classic = np.array([
[1.0, 1.0, 0.5, 0.5, 0.5, 0.25],
[2.0, 2.0, 1.5, 1.0, 1.0, 0.5],
[1.0, 3.0, 3.0, 1.0, 1.0, 0.5],
[0.5, 0.5, 0.5, 1.0, 1.0, 0.5],
[0.0, 0.5, 0.5, 1.0, 0.5, 0.25],
[0.5, 0.5, 0.5, 0.25, 0.5, 0.25],
])

# AI-assisted scenario
phases_ai = ["Found.\n(M1-2)", "MVP\n(M3-5)", "Feat.\n(M5-8)",
"Test\n(M8-10)", "Deploy\n(M10-12)", "Retire\n(M12-13)"]
data_ai = np.array([
[1.0, 1.0, 0.5, 0.5, 0.5, 0.25],
[1.0, 1.0, 1.0, 0.5, 0.5, 0.25],
[1.0, 2.0, 2.0, 0.5, 0.5, 0.25],
[0.5, 0.5, 0.5, 1.0, 1.0, 0.5],
[0.0, 0.5, 0.5, 1.0, 0.5, 0.25],
[0.5, 0.5, 0.5, 0.25, 0.5, 0.25],
])

for ax, data, phases, title in [
(ax1, data_classic, phases_classic, "Classic Development (9 FTE peak)"),
(ax2, data_ai, phases_ai, "AI-Assisted / Claude (6 FTE peak)")
]:
ax.set_facecolor('#FAFAFA')
x = np.arange(len(phases))
width = 0.12
offsets = np.arange(len(roles)) - (len(roles) - 1) / 2

for i, (role, color) in enumerate(zip(roles, colors)):
bars = ax.bar(x + offsets[i] * width, data[i], width * 0.9,
label=role, color=color, alpha=0.85, edgecolor='white', linewidth=0.5)
for bar, val in zip(bars, data[i]):
if val > 0:
ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.02,
f'{val:.0f}' if val == int(val) else f'{val:.1f}',
ha='center', va='bottom', fontsize=6, color='#555')

totals = data.sum(axis=0)
ax.plot(x, totals, 'ko-', linewidth=2, markersize=7, label='Total FTE', zorder=5)
for xi, total in zip(x, totals):
ax.text(xi, total + 0.12, f'{total:.1f}', ha='center', fontsize=8,
fontweight='bold', color='#333')

ax.set_ylabel('FTE', fontsize=10)
ax.set_title(title, fontsize=11, fontweight='bold', color='#2C3E50')
ax.set_xticks(x)
ax.set_xticklabels(phases, fontsize=8)
ax.legend(loc='upper right', fontsize=7, ncol=2, framealpha=0.9)
ax.set_ylim(0, max(totals) + 1.5)
ax.grid(axis='y', alpha=0.3)

fig.suptitle('Resource Allocation Comparison', fontsize=14, fontweight='bold',
color='#2C3E50', y=1.02)
plt.tight_layout()
plt.savefig(output_file, dpi=200, bbox_inches='tight',
facecolor=fig.get_facecolor())
plt.close()
print(f"Resource chart saved to: {output_file}")

Copy link
Contributor

Choose a reason for hiding this comment

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

high

There are several inconsistencies in the data used to generate the resource allocation chart, which makes the resulting chart misleading.

  1. Incorrect Peak FTE:

    • For the "Classic" scenario, the data results in a peak of 7.5 FTE, but comments and the markdown plan state a peak of 9 FTE.
    • For the "AI-Assisted" scenario, the data results in a peak of 5.5 FTE, but the plan states 6 FTE.
  2. Inconsistent Person-Months:

    • The total effort calculated from this data is ~106 person-months for the classic scenario and ~55 for the AI-assisted one. This contradicts the ~155 and ~68 person-months mentioned elsewhere in this file and in the markdown plan.
  3. Incorrect Phase Durations for AI Scenario: The labels in phases_ai (e.g., "Feat.\n(M5-8)") do not match the actual phase durations from the Gantt chart data (e.g., Feature Parity is from month 5 to 7.5). This makes the x-axis of the AI resource chart incorrect.

  4. Likely Data Error: The FTE allocations for "Tech Lead", "DevOps", "QA", and "UX/Docs" are identical in both data_classic and data_ai. This seems unlikely given the overall team size reduction and is probably a copy-paste error.

Please review and correct the data in data_classic and data_ai arrays and the phases_ai labels to ensure all generated charts are consistent with the overall project plan.

Comment on lines +32 to +55
def draw_gantt(ax, tasks, start_date, total_months, title, subtitle, team_text):
"""Draw a single Gantt chart on the given axes."""
bar_height = 0.55

for i, (name, phase, start_m, duration, is_milestone) in enumerate(tasks):
y_pos = len(tasks) - 1 - i
color = PHASE_COLORS[phase]

if is_milestone:
ax.plot(start_m, y_pos, marker='D', markersize=12, color=color,
markeredgecolor='white', markeredgewidth=2, zorder=5)
else:
bar = FancyBboxPatch(
(start_m, y_pos - bar_height / 2),
duration, bar_height,
boxstyle="round,pad=0.05",
facecolor=color, edgecolor='white',
linewidth=1.5, alpha=0.85, zorder=3
)
ax.add_patch(bar)
if duration >= 0.8:
ax.text(start_m + duration / 2, y_pos, f"{duration:.1f}m",
ha='center', va='center', fontsize=6.5,
color='white', fontweight='bold', zorder=4)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This function contains many hardcoded styling values (e.g., bar_height, markersize, fontsize, colors). To improve maintainability and make it easier to adjust the chart's appearance, consider grouping these values into a configuration dictionary or defining them as constants at the top of the script.

For example:

GANTT_STYLE = {
    'bar_height': 0.55,
    'milestone_marker': 'D',
    'milestone_size': 12,
    'bar_style': 'round,pad=0.05',
    'bar_alpha': 0.85,
    'text_color': 'white',
    'font_size_bar': 6.5,
    'font_size_task': 7.5,
    # ... and so on
}

def draw_gantt(...):
    bar_height = GANTT_STYLE['bar_height']
    ...
    ax.plot(..., marker=GANTT_STYLE['milestone_marker'], markersize=GANTT_STYLE['milestone_size'], ...)
    ...

This would make the plotting logic cleaner and styling more centralized.

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