Cycle 381: Issue-Number Cycle IDs
Priority: MEDIUM Status: DRAFT Domain: infra Dependencies: None Product: Flux — AI Hiring Assistant for small businesses Organization: Employ Inc.Problem
Cycle docs use manually-chosen sequential integers as identifiers. Three collisions have already occurred:cycle213 (feature flags AND deploy hardening), cycle217 (candidate identity AND nginx migration), cycle220 (select for hire AND notification system). The root cause is a global counter with no coordination mechanism — multiple engineers and AI agents independently pick “the next number” and collide.
Objective
Use the GitHub issue number as the cycle number. Issues are auto-incremented by GitHub — zero collision risk, zero new tooling, and the cycle ID doubles as a direct link to the project board.What This Cycle Does NOT Include
- Renaming existing merged cycle docs (they stay as
cycle202,cycle203, etc.) - Renaming in-progress cycle docs in open PRs
- Changes to the cycle lifecycle process (two-phase Plan PR → Code PR)
- Changes to the cross-model review requirement
The Convention
How it works
- Create a GitHub issue on the Flux project for the new cycle → get
#342 - Name the cycle doc
cycle342-descriptive-name.mdwithcycle: 342in frontmatter - Sub-cycles follow the existing convention:
cycle342.1-sub-task.md,cycle342.2-next.md - PR body includes
Closes #342→ board auto-closes on merge
Why this works
- Human-friendly — “cycle 342” works in conversation, in Slack, in standups
- Always unique — GitHub issue numbers are auto-incremented, zero collision risk
- Zero new tooling — no counter files, no CI validators, no naming conventions to learn
- Enforces discipline — every cycle must have a tracked project item before the doc is written
- Traceable — cycle number = issue number, so
#342links directly to the board - Sub-cycles preserved —
342.1,342.2etc. work exactly as today - Existing automation compatible —
cycle-board.ymlalready parses issue numbers from PR bodies;cycle-sync.ymlalready reads numericcycle:values
The rule
No cycle doc may be created without a corresponding GitHub issue. The issue must exist first — its number becomes the cycle number. This is not optional. If no issue exists, create one before writing the doc. This is what makes the system collision-proof: GitHub guarantees unique issue numbers.What changes
Numbers won’t be sequential (you might have cycles 318, 325, 341). Nobody needs them sequential — just unique and easy to reference.Process Change
Before (old convention)
- Pick the next number after the highest existing cycle doc
- Hope nobody else picked the same number
- Write the cycle doc
- Open plan PR
cycle-sync(if enabled) creates the issue from the doc
After (new convention)
- Create a GitHub issue first — title:
Cycle: <brief description>, label:cycle - Note the issue number (e.g.,
#342) - Write the cycle doc:
cycle342-descriptive-name.mdwithcycle: 342 - Open plan PR with
Closes #342in the body - Issue already exists on the board — no sync needed
Frontmatter
No changes to thecycle: field type or required fields. The value is still an integer — it just comes from GitHub instead of manual counting.
issue: field (already defined in CONTRIBUTING.md as optional) becomes effectively required for new cycles, since the cycle number IS the issue number.
Branch, PR, and Commit Conventions
No changes to the format — just the number source:Transition Rules
| Category | Action |
|---|---|
Merged docs (cycle133.1–cycle222) | Leave as-is. No rename. |
| In-progress PRs | Leave as-is. |
| New cycles from here forward | Create GitHub issue first, use issue number as cycle number. |
cycle-board.yml | No changes needed. |
cycle-sync.yml.disabled | Consider deprecating — issues are created manually first now, not auto-generated from docs. |
Issue template (cycle.yml) | No changes needed — still works for manually creating cycle issues. |
Concrete Example: HC-8 Select for Hire
If HC-8 were started under the new convention:- Create issue:
Cycle: Select for Hire — Data Contracts→ gets#342 - Create issue:
Cycle: Select for Hire — Hire Execution→ gets#343 - Create issue:
Cycle: Select for Hire — Hire UX→ gets#344
- Create issue:
Cycle: Select for Hire→ gets#342 - Docs:
cycle342-select-for-hire-backend.md,cycle342.1-hire-execution.md,cycle342.2-hire-ux.md
| Current | New convention |
|---|---|
cycle222-select-for-hire-backend.md | cycle342-select-for-hire-backend.md |
cycle222.1-select-for-hire-execution.md | cycle342.1-hire-execution.md |
cycle222.2-select-for-hire-ux.md | cycle342.2-hire-ux.md |
Edge Cases
What about cycles that aren’t on the board yet? — Create the issue first. That’s the point — every cycle gets tracked before work begins. What about AI agents creating cycles autonomously? — Agents usegh issue create to get a number, then write the doc. Same flow, automated.
What about sub-cycles? — Same as today: 342.1, 342.2. The parent issue is #342; sub-cycles don’t need their own issues unless they’re independently trackable.
What if cycle-sync is re-enabled? — It would need to skip doc-to-issue creation (issue already exists) and only do issue-to-doc sync (update labels/status from frontmatter). Or deprecate it entirely since the manual-first flow is simpler.
Deliverables
1. Update CONTRIBUTING.md
Sections to update (by heading):- “Cycle Document Frontmatter” — Add note that
cycle:value must be a GitHub issue number for new cycles. Noteissue:field should reference the same number. - “Phase 1: Cycle Plan PR” — Update the workflow to start with “Create a GitHub issue” before writing the doc.
- “Check Before You Start” — Already includes
gh issue create; add explicit note that the issue number becomes the cycle number.
2. Add CI unique-ID validator
Lightweight check on PRs touchingdocs/roadmap/cycles/*.md:
- Scan all cycle docs, extract
cycle:value - Fail if any two docs share the same
cycle:value (catches both legacy and new collisions) - Legacy duplicates (213×2, 217×2) need an allowlist until resolved
3. Consider deprecating cycle-sync.yml
With issues created manually first, the doc-to-issue sync is redundant. The workflow could be simplified to only sync labels/status, or removed entirely.
Testing
- Verify CONTRIBUTING.md changes are clear and examples use issue numbers
- Run unique-ID validator against all existing docs — confirm it flags known duplicates (213, 217) and passes everything else
- Verify
cycle-board.ymlstill works withCloses #<issue-number>in PR bodies (already confirmed by PR #310 fix)
Success Criteria
- CONTRIBUTING.md documents “create issue first, use issue number as cycle number”
- CONTRIBUTING.md updates Phase 1 workflow to start with issue creation
- CI unique-ID validator blocks merge on duplicate
cycle:values - No existing cycle docs modified
-
make quality-gatespasses