feat(hardware): backfill legacy hardware projects into the hardware flow#560
Draft
dhamariT wants to merge 1 commit into
Draft
feat(hardware): backfill legacy hardware projects into the hardware flow#560dhamariT wants to merge 1 commit into
dhamariT wants to merge 1 commit into
Conversation
Projects shipped before hardware_stage existed (column added 2026-06-02) sit at hardware_stage = nil, so Project#hardware? is false for them even when they are genuine hardware builds. The only available signal is the AI type classifier's project_type == "Hardware". Add OneTime::BackfillHardwareStageJob to promote those projects into the flow by stamping hardware_stage: - dry-run by default; pass dry_run: false to persist - defaults to "design" (no implied grant; design-phase time is uncounted for payout; can't trip the funding-stage lock) - writes via save(validate: false) so legacy rows that fail today's unrelated validations still classify, while PaperTrail audit and the Gorse / semantic-search re-index callbacks still fire - wrapped in PaperTrail.request so the version is attributed to the job
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
what's this do?
Adds a one-time backfill that brings legacy hardware projects into the new hardware flow.
the problem
There are two unrelated "type" concepts on
Project:project_type— an AI taxonomy label ("Web App", "CLI", "Hardware"…) set byProject::TypeCheckJob→SwAi::ProjectTypeService.hardware_stage(design/build/nil) — the canonical hardware discriminator.Project#hardware?is literallyhardware_stage.present?, and it drives funding → build → payout → the Lookout recorder.hardware_stagewas added 2026-06-02. Every project shipped before then hashardware_stage = nil, sohardware?isfalsefor them even when they're genuine hardware builds. There's no deterministic signal to recover them — funding requests, Lookout sessions, and phase-stamped devlogs all post-date the column (funding even validatesdesign_stage?on create), andproject_categoriesis a dead column with no write path. The only available signal isproject_type == "Hardware"from the AI classifier.what it does
OneTime::BackfillHardwareStageJobstampshardware_stageon projects whereproject_type == "Hardware"andhardware_stage IS NULL.dry_run: falseto persist."design"(the flow's entry stage). Safe for already-shipped projects: it implies no funding grant, design-phase time isn't credited toward build payout (so no payout change), and projects in scope can't already have a funding request, so the funding-stage lock never trips. Stage is overridable viastage:.save(validate: false)so legacy rows that would fail today's unrelated validations (URL format, banner type…) still get classified — while PaperTrail audit and the Gorse / semantic-search re-index callbacks still fire. Wrapped inPaperTrail.requestso the version is attributed to the job.how to run
"Hardware"— under-labeled hardware still needs manual admin tagging. Eyeball the dry-run list first.hardware_stageflipshardware?→ enables the Lookout recorder and hardware shipping gates going forward (intended).OneTime::BackfillDevlogPhaseJobafter this — it back-dates nil-phase devlogs into the project's current stage. Harmless with"design"(uncounted), but a"build"run would over-credit payout.show it works
Tested in
test/jobs/one_time/backfill_hardware_stage_job_test.rb: dry-run writes nothing, commit stampsdesignon AI-typed hardware projects only (software + already-staged untouched), explicit stage honored, invalid stage raises, legacy rows that fail current validations still classify, and the change is PaperTrail-audited to the job.follow-up (not in this PR)
OneTime::BackfillProjectTypeJob#scopefilterswhere.not(shipped_at: nil), but "shipped" really means having ship events (shipped_atis set inconsistently), so it enqueues nothing for old projects. Correct scope:Project.with_ship_events.where(project_type: nil, deleted_at: nil). Happy to fix in a separate PR.ai?
Claude 🥀