From f70f219d63cad4a39120cbf7fd2dd0ba28299a9b Mon Sep 17 00:00:00 2001 From: egdev6 Date: Fri, 5 Jun 2026 17:30:05 +0200 Subject: [PATCH 1/2] docs(harness): document issue and story gates --- .atl/skills/component-contributor/SKILL.md | 10 +++-- .../references/stories.md | 11 +++-- .atl/skills/component-spec-proposer/SKILL.md | 24 +++++----- .../references/github-project-update.md | 4 +- .atl/skills/components-auditor/SKILL.md | 2 + .atl/skills/github-project-tasks/SKILL.md | 44 +++++++++++++------ .../references/issue-body-template.md | 6 ++- .atl/skills/pr-reviewer/SKILL.md | 3 ++ .atl/skills/worktree-location/SKILL.md | 4 +- .github/ISSUE_TEMPLATE/a11y.yml | 4 +- .github/ISSUE_TEMPLATE/ci.yml | 4 +- .github/ISSUE_TEMPLATE/component.yml | 4 +- .github/ISSUE_TEMPLATE/fix.yml | 4 +- .github/ISSUE_TEMPLATE/npm.yml | 4 +- .github/ISSUE_TEMPLATE/storybook.yml | 6 ++- .github/ISSUE_TEMPLATE/tokens.yml | 4 +- .github/ISSUE_TEMPLATE/update.yml | 4 +- .github/PULL_REQUEST_TEMPLATE.md | 1 + README.en.md | 4 +- README.md | 4 +- docs/CONTRIBUTING.en.md | 28 +++++++----- docs/CONTRIBUTING.md | 28 +++++++----- docs/CONTRIBUTOR-FLOW.en.md | 34 ++++++++------ docs/CONTRIBUTOR-FLOW.md | 31 ++++++++----- docs/ENVIRONMENT-SETUP.en.md | 2 +- docs/ENVIRONMENT-SETUP.md | 2 +- docs/GUIDELINES.en.md | 4 +- docs/GUIDELINES.md | 4 +- docs/QUICK_START.en.md | 4 +- docs/QUICK_START.md | 4 +- 30 files changed, 179 insertions(+), 113 deletions(-) diff --git a/.atl/skills/component-contributor/SKILL.md b/.atl/skills/component-contributor/SKILL.md index c2681516..92f663c5 100644 --- a/.atl/skills/component-contributor/SKILL.md +++ b/.atl/skills/component-contributor/SKILL.md @@ -34,7 +34,7 @@ Load by intent: | Radix primitive | `.atl/skills/component-contributor/references/radix-patterns.md` | | `className` merging | `.atl/skills/component-contributor/references/tailwind-merge.md` | | Contributor PR workflow | `.atl/skills/component-contributor/references/git-workflow.md` | -| Starting from a GitHub issue or board task | `.atl/skills/github-project-tasks/SKILL.md` — verify issue label `status:approved`, then run START WORK before implementation | +| Starting from a GitHub issue or board task | `.atl/skills/github-project-tasks/SKILL.md` — verify issue label `status:approved` and assignee ownership, then run START WORK before implementation | ## Workflow @@ -42,19 +42,21 @@ Follow these phases in order. Do not skip gates because a component looks simple **Non-negotiable approval gate:** implementation must not start under any circumstance unless the linked GitHub issue has the exact label `status:approved`. Chat approval, assumptions, offline mode, or a local copy of the spec do not satisfy this gate. +**Non-negotiable assignee gate:** before reading the implementation spec in detail, planning, creating a branch/worktree, mutating GitHub, or writing code from a linked issue, verify current assignees. If the issue is assigned to someone other than the contributor/user, stop and tell the user they must get explicit permission before reassigning it. + ### 0 — Contributor onboarding Only when working directly with a contributor: confirm they understand React + strict TypeScript, Tailwind v4 tokens, CVA, the 6-file pattern, Storybook as docs, and tests in `.test.tsx`. If not, teach briefly before proceeding. ### 1 — Approval gate, START WORK, then spec intake -If implementation will proceed from a GitHub issue or Project board card, first verify that the linked issue has the exact label `status:approved`. If it is missing, stop and ask for maintainer/project lead approval; do not read the implementation spec in detail, plan, or code. +If implementation will proceed from a GitHub issue or Project board card, first verify that the linked issue has the exact label `status:approved` and is not assigned to someone else. If the label is missing, stop and ask for maintainer/project lead approval; do not read the implementation spec in detail, plan, or code. If another assignee is present, stop before any action and tell the user they need explicit permission before reassigning the issue. -After the label is present, load `.atl/skills/github-project-tasks/SKILL.md` and run **START WORK** before spec intake, planning, or coding: assign the issue to the contributor/user, move Project status to `In progress`, and record the planned branch/worktree. Offline/no-network mode may only skip GitHub mutations after evidence confirms the issue already has `status:approved`; it never bypasses the approval gate. +After the label and assignee gates pass, load `.atl/skills/github-project-tasks/SKILL.md` and run **START WORK** before spec intake, planning, or coding: verify assignees, assign the issue to the contributor/user, move Project status to `In progress`, and record the planned branch/worktree. Offline/no-network mode may only skip GitHub mutations after evidence confirms the issue already has `status:approved` and is unassigned or assigned to the contributor/user; it never bypasses the approval or assignee gates. Then extract component name, tier, props, variants, states, accessibility behavior, reference URL, and design notes. If the spec lives in a GitHub issue, read issue comments too; validated specs may live there. -Stop and ask when the issue label `status:approved` is missing or cannot be verified, START WORK cannot be completed, or required behavior, accessibility, states, or variants are missing. Do not invent public API and do not begin implementation. +Stop and ask when the issue label `status:approved` is missing or cannot be verified, the issue is assigned to someone else without explicit reassignment permission, START WORK cannot be completed, or required behavior, accessibility, states, or variants are missing. Do not invent public API and do not begin implementation. ### 1.5 — Spec critique diff --git a/.atl/skills/component-contributor/references/stories.md b/.atl/skills/component-contributor/references/stories.md index 887978a6..0522abc8 100644 --- a/.atl/skills/component-contributor/references/stories.md +++ b/.atl/skills/component-contributor/references/stories.md @@ -20,7 +20,10 @@ Use this reference BEFORE writing or reviewing stories. Do not improvise Storybo - `## Description` — required for every component; describe what it does and when to use it. - `## Dependencies` — include only when the story/component uses other design-system components or external primitives; list each dependency and why it is used. - `## Usage Guide` — include only when usage is complex; explain composition, constraints, or non-obvious behavior. -- Story-level docs must be written as a JSDoc block immediately above each `export const StoryName`; do **not** render documentation cards, panels, helper text blocks, or usage notes inside the story canvas. +- Story-level docs must be written as a useful JSDoc block immediately above each `export const StoryName`; do **not** render documentation cards, panels, helper text blocks, or usage notes inside the story canvas. +- Each story must earn its place: demonstrate a distinct state, variant axis, composition constraint, accessibility behavior, or integration context. Do not add stories that duplicate coverage already provided by controls, args, or another story. +- Do **not** add a generic `DarkMode` story just to show the component in dark theme. Storybook already provides global dark/light switching via the toolbar. +- A dedicated dark-mode story is allowed only when it demonstrates behavior the global theme toggle cannot express, such as local dark-scope rendering, portal theme inheritance, or a theme-specific bug/regression case. State that reason in the story JSDoc. - Story render functions and decorators are examples only: they may provide layout needed to demonstrate the component, but not narrative documentation UI. - `Default` story args must not override the component `defaultVariants`. - Interactive components must include `Disabled` and interaction-focused stories as appropriate. @@ -59,7 +62,7 @@ export default meta; type Story = StoryObj; /** - * Shows the default component configuration using its default variants. + * Demonstrates the component with its built-in default variants so consumers can compare other stories against the baseline API. */ export const Default: Story = { args: { @@ -78,7 +81,9 @@ export const Default: Story = { - Is the component-level docs JSDoc block immediately above `const meta`? - Does the component-level JSDoc block include required `## Description`? - Are `## Dependencies` and `## Usage Guide` included only when applicable? -- Does each story have a concise JSDoc block immediately above its `export const StoryName`? +- Does each story JSDoc explain the scenario and why it matters instead of restating the story name or saying only "Shows the component"? +- Is every story necessary, with no duplicate coverage that controls, args, the global dark-mode toolbar, or another story already provide? +- Are generic theme-only `DarkMode` stories absent unless they document a local scope, portal inheritance, or regression case that the toolbar cannot express? - Are documentation cards, panels, helper text blocks, and usage notes absent from the story canvas? - Does `meta.parameters.docs` avoid `description.component`? - Are examples aligned with the canonical component API and public docs style? diff --git a/.atl/skills/component-spec-proposer/SKILL.md b/.atl/skills/component-spec-proposer/SKILL.md index 13692ca1..ad7e671b 100644 --- a/.atl/skills/component-spec-proposer/SKILL.md +++ b/.atl/skills/component-spec-proposer/SKILL.md @@ -36,21 +36,23 @@ Do not implement the component. Your job is to turn a vague task into a validate | Accessibility contract is vague or missing | Stop and ask; do not produce a ready-to-approve spec. | | Composite keyboard/focus behavior unclear | Ask for the intended pattern before validation. | | Expected a11y tests are missing | Add them before asking for approval. | +| Linked issue assigned to someone else | Stop before GitHub writes or implementation handoff; tell the user they need explicit permission before reassigning or taking over the issue. | | User approves proposal | Add the validated spec to the issue, then leave implementation blocked until a maintainer/project lead adds the issue label `status:approved`. | | User requests changes | Revise the proposal and ask for validation again. | ## Execution Steps -1. Read the GitHub issue, if provided: title, body, comments, assignees, and URL. If the rendered issue page does not expose the comment thread, fetch the issue comments via the GitHub API (`/repos/{owner}/{repo}/issues/{number}/comments`) or `gh api` before continuing. -2. Fetch and study the reference URL. Extract behavior, states, accessibility, anatomy, and examples. -3. Identify the semantic pattern: native element, Radix primitive, or WAI-ARIA/APG pattern. For composites, define roles, relationships, keyboard behavior, focus lifecycle, and announced states before proposing API details. -4. Compare against project rules from `component-contributor`, especially Phase 1 requirements. -5. Present a proposed spec using `references/spec-template.md` with concrete accessibility acceptance criteria and expected tests. -6. Include an `Assumptions to validate` section for choices not explicit in the issue/reference, especially screen reader, focus, or keyboard decisions. -7. Ask the user to approve, reject, or edit the proposal. Do not write to GitHub before approval. -8. After approval, append or update a GitHub issue comment headed `## Validated component spec` using the approved spec. -9. Locate the Project item for the issue only to confirm it exists; do not move Project Status to `In progress` from this skill. -10. Report the issue URL, project item ID, approval state, and next command/action: wait for the `status:approved` issue label, then run START WORK via `github-project-tasks`, then start `component-contributor`. +1. Read the GitHub issue metadata first, if provided: title, assignees, labels, and URL. Confirm the contributor/user before comparing assignees. If the issue is assigned to someone other than the contributor/user, stop before further workflow action or GitHub writes and tell the user they need explicit permission before reassigning or taking over the issue. +2. Read the GitHub issue body and comments, if provided. If the rendered issue page does not expose the comment thread, fetch the issue comments via the GitHub API (`/repos/{owner}/{repo}/issues/{number}/comments`) or `gh api` before continuing. +3. Fetch and study the reference URL. Extract behavior, states, accessibility, anatomy, and examples. +4. Identify the semantic pattern: native element, Radix primitive, or WAI-ARIA/APG pattern. For composites, define roles, relationships, keyboard behavior, focus lifecycle, and announced states before proposing API details. +5. Compare against project rules from `component-contributor`, especially Phase 1 requirements. +6. Present a proposed spec using `references/spec-template.md` with concrete accessibility acceptance criteria and expected tests. +7. Include an `Assumptions to validate` section for choices not explicit in the issue/reference, especially screen reader, focus, or keyboard decisions. +8. Ask the user to approve, reject, or edit the proposal. Do not write to GitHub before approval. +9. After approval, append or update a GitHub issue comment headed `## Validated component spec` using the approved spec. +10. Locate the Project item for the issue only to confirm it exists; do not move Project Status to `In progress` from this skill. +11. Report the issue URL, project item ID, approval state, and next command/action: wait for the `status:approved` issue label, then run START WORK via `github-project-tasks`, then start `component-contributor`. ## Output Contract @@ -79,7 +81,7 @@ After approval and GitHub update, return: **Spec**: Added to issue as `Validated component spec` **Project setup**: {team/category present or missing setup} **Approval gate**: Waiting for issue label `status:approved` -**Next**: After the issue has label `status:approved`, run START WORK via `github-project-tasks`, then run `component-contributor` for implementation. +**Next**: After the issue has label `status:approved` and is unassigned or assigned to the contributor/user, run START WORK via `github-project-tasks`, then run `component-contributor` for implementation. ``` ## References diff --git a/.atl/skills/component-spec-proposer/references/github-project-update.md b/.atl/skills/component-spec-proposer/references/github-project-update.md index 84378c4a..e80236ee 100644 --- a/.atl/skills/component-spec-proposer/references/github-project-update.md +++ b/.atl/skills/component-spec-proposer/references/github-project-update.md @@ -20,7 +20,7 @@ item_id=$(gh project item-list 1 \ ``` Do not move Project Status to `In progress` from `component-spec-proposer`. -That transition belongs to START WORK in `github-project-tasks`, after spec approval, after the linked issue has label `status:approved`, and immediately before implementation. +That transition belongs to START WORK in `github-project-tasks`, after spec approval, after the linked issue has label `status:approved`, after assignee ownership is verified, and immediately before implementation. If the issue is assigned to someone else, stop and require explicit permission before reassignment/takeover. Add the approved spec to the issue: @@ -32,4 +32,4 @@ gh issue comment NUMBER \ If a previous `Validated component spec` comment exists, prefer editing it manually or with the GitHub API instead of adding duplicates. -After writing the validated spec, report that the task is waiting for the issue label `status:approved`. Do not start `component-contributor` or move the Project item to `In progress` until that label is present. +After writing the validated spec, report that the task is waiting for the issue label `status:approved` and assignee ownership verification. Do not start `component-contributor` or move the Project item to `In progress` until both gates pass. diff --git a/.atl/skills/components-auditor/SKILL.md b/.atl/skills/components-auditor/SKILL.md index 4d58c237..ddf18671 100644 --- a/.atl/skills/components-auditor/SKILL.md +++ b/.atl/skills/components-auditor/SKILL.md @@ -52,6 +52,8 @@ Audit against `.atl/skills/_shared/component-contract.md`: Use the Storybook and testing references as the single source of truth. In particular: - story docs live in JSDoc above `const meta` and each story export; +- each story JSDoc explains the scenario and why it matters, not just the story name; +- story set is necessary and non-duplicative, including no generic theme-only `DarkMode` story when the global Storybook dark-mode toolbar covers the case; - `parameters.docs.description.component` is not used; - no manual `argTypes` unless a documented exception exists; - event args use `action(...)`; diff --git a/.atl/skills/github-project-tasks/SKILL.md b/.atl/skills/github-project-tasks/SKILL.md index 04c89722..10e37176 100644 --- a/.atl/skills/github-project-tasks/SKILL.md +++ b/.atl/skills/github-project-tasks/SKILL.md @@ -14,7 +14,7 @@ metadata: Use this skill for Stack-and-Flow GitHub issue + Project board work. It has four modes: - **CREATE** — create issue(s), add to Project, set fields. -- **START WORK** — after the linked issue has label `status:approved`, assign the issue, move the Project item to `In progress`, and record the branch/worktree plan before implementation starts. +- **START WORK** — after the linked issue has label `status:approved`, verify the assignee is empty or already the contributor/user, assign the issue, move the Project item to `In progress`, and record the branch/worktree plan before implementation starts. If the issue is assigned to someone else, stop before any mutation and require explicit permission to reassign it. - **END WORK** — comment validation/PR evidence and move the Project item to `Done` only after the task is genuinely complete. - **AUDIT** — detect malformed existing issues or board items. @@ -72,7 +72,8 @@ Option IDs: - Always write multi-line issue bodies to a temp file and pass `--body-file`. - Confirm task name, tier/type, reference URL when applicable, assignee, team, category, and milestone before CREATE. - Milestone is mandatory for CREATE. If it is missing, ask interactively before creating the issue; do not invent it. -- Before implementation starts from a GitHub issue, require the exact issue label `status:approved`, then run START WORK: assign the issue to the contributor/user and move the Project item to `In progress`. +- Before implementation starts from a GitHub issue, require the exact issue label `status:approved`, then run START WORK: verify current assignees, assign the issue to the contributor/user, and move the Project item to `In progress`. +- If a linked issue is already assigned to someone other than the contributor/user, stop before assignment, Project status changes, branch/worktree actions, planning, or implementation. Notify the user: `Issue #{number} is already assigned to @{assignee}; ask for explicit permission before reassigning it.` Continue only after explicit permission is provided in the current task context. - Before marking a task done, run END WORK: add validation/PR evidence and move the Project item to `Done` only when merged or explicitly approved by the maintainer/user. - Do not invent a missing reference URL; ask or research. @@ -134,7 +135,7 @@ $itemId = gh project item-add 1 ` ## Mode 2 — START WORK -Run this before implementation starts from an existing GitHub issue or board card, after the linked issue has label `status:approved`. Offline/no-network mode may skip GitHub mutations only after approval evidence confirms the label is present; it does not permit implementation without `status:approved`. +Run this before implementation starts from an existing GitHub issue or board card, after the linked issue has label `status:approved`. Offline/no-network mode may skip GitHub mutations only after evidence confirms the label is present and the assignee gate is satisfied; it does not permit implementation without `status:approved` or against an issue assigned to someone else without explicit reassignment permission. Inputs required: @@ -143,11 +144,12 @@ Inputs required: 3. GitHub username of the contributor/user doing the work. 4. Planned branch name. 5. Planned worktree path when a worktree will be used. +6. Explicit maintainer/user permission to reassign, only when the issue is already assigned to someone else. Steps: 1. Confirm the issue is the right task and the contributor/user is correct. -2. Verify the exact issue label `status:approved` is present. If it is missing, stop; do not move the Project item to `In progress`. +2. Verify the exact issue label `status:approved` is present. If it is missing, stop; do not assign the issue or move the Project item to `In progress`. ```powershell $approvalLabel = gh issue view {issue_number} ` @@ -158,7 +160,21 @@ $approvalLabel = gh issue view {issue_number} ` If `$approvalLabel` is empty, the approval gate is not satisfied. Stop; implementation must not start under any circumstance. -3. Assign the issue: +3. Verify assignee ownership before any mutation, branch/worktree action, planning, or implementation: + +```powershell +$assignees = gh issue view {issue_number} ` + --repo Stack-and-Flow/design-system ` + --json assignees ` + --jq '.assignees[].login' + +$ownedByContributor = $assignees | Select-String -SimpleMatch '{username}' +$assignedToOther = $assignees | Where-Object { $_ -and $_ -ne '{username}' } +``` + +If `$assignedToOther` is not empty and explicit maintainer/user permission to reassign is not present in the current task context, stop before mutating GitHub or starting work. Notify the user: `Issue #{number} is already assigned to @{assignee}; ask for explicit permission before reassigning it.` + +4. Assign the issue when it is unassigned, already assigned to `{username}`, or explicit reassignment permission was provided: ```powershell gh issue edit {issue_number} ` @@ -166,8 +182,8 @@ gh issue edit {issue_number} ` --add-assignee {username} ``` -4. Ensure the issue is on Project `1`. If not, add it with `gh project item-add`. -5. Resolve the Project item ID for existing cards: +5. Ensure the issue is on Project `1`. If not, add it with `gh project item-add`. +6. Resolve the Project item ID for existing cards: ```powershell $issueUrl = "https://github.com/Stack-and-Flow/design-system/issues/{issue_number}" @@ -180,7 +196,7 @@ $itemId = gh project item-list 1 ` If `$itemId` is empty after adding/checking the Project item, stop and report the blocker. -6. Move Project Status to `In progress`: +7. Move Project Status to `In progress`: ```powershell gh project item-edit ` @@ -190,8 +206,8 @@ gh project item-edit ` --single-select-option-id 47fc9ee4 ``` -7. Confirm Team and Category are set. If missing, set them using the option IDs above. -8. Report the work-start state: +8. Confirm Team and Category are set. If missing, set them using the option IDs above. +9. Report the work-start state: ```markdown ## Work Started @@ -199,6 +215,7 @@ gh project item-edit ` **Issue**: #{number} — {title} **Assignee**: @{username} **Approval gate**: issue label `status:approved` verified +**Assignee gate**: issue was unassigned, already assigned to @{username}, or explicit reassignment permission was recorded **Project status**: In progress **Team**: {team} **Category**: {category} @@ -206,7 +223,7 @@ gh project item-edit ` **Worktree**: `{path or "not used"}` ``` -Do not start implementation if the `status:approved` label is missing or unverified. Do not start implementation if assignment, item lookup, or `In progress` status fails, unless the user explicitly asks to continue offline/no-network after the approval label has been verified. +Do not start implementation if the `status:approved` label is missing or unverified. Do not start implementation if the assignee gate fails, assignment fails, item lookup fails, or `In progress` status fails, unless the user explicitly asks to continue offline/no-network after both the approval label and assignee gate have been verified. ## Branch and Worktree Naming @@ -346,9 +363,10 @@ For START WORK, return the `## Work Started` report shown in Mode 2, or: ## Work Start Skipped **Issue**: #{number} — {title} -**Reason**: offline/no-network requested or GitHub mutation failed after `status:approved` was verified +**Reason**: offline/no-network requested, issue already assigned to someone else without explicit reassignment permission, or GitHub mutation failed after `status:approved` was verified **Approval gate**: issue label `status:approved` verified; if not verified, implementation remains blocked -**Required follow-up**: assign issue, move Project status to `In progress`, confirm team/category +**Assignee gate**: {unassigned / already assigned to @{username} / assigned to @{assignee}; explicit reassignment permission required} +**Required follow-up**: get explicit permission before reassigning when assigned to someone else; then assign issue, move Project status to `In progress`, confirm team/category **Branch**: `{branch}` **Worktree**: `{path or "not used"}` ``` diff --git a/.atl/skills/github-project-tasks/references/issue-body-template.md b/.atl/skills/github-project-tasks/references/issue-body-template.md index e7520d13..42b0e29f 100644 --- a/.atl/skills/github-project-tasks/references/issue-body-template.md +++ b/.atl/skills/github-project-tasks/references/issue-body-template.md @@ -36,7 +36,8 @@ Out of scope: - [ ] Issue triaged with Team and Category fields set on the Project board, and GitHub milestone assigned. - [ ] Specification or plan recorded in this issue when behavior, API, accessibility, or tokens are affected. - [ ] Validated spec reviewed and linked issue labeled `status:approved` before implementation starts. -- [ ] START WORK completed after label `status:approved`: assignee set, Project status moved to `In progress`, branch/worktree recorded. +- [ ] Assignee ownership checked before START WORK; if assigned to someone else, explicit reassignment permission documented. +- [ ] START WORK completed after label `status:approved` and assignee gate: assignee set, Project status moved to `In progress`, branch/worktree recorded. - [ ] Implementation completed inside the approved scope. - [ ] Validation evidence recorded in the PR or issue. - [ ] PR opened and linked with `Closes #NNN`. @@ -45,7 +46,7 @@ Out of scope: ### Specification or plan -For component work, paste or link the approved `## Validated component spec` from `component-spec-proposer` before implementation starts. After the spec is defined, the contributor waits for the issue label `status:approved`; no START WORK or implementation happens before that label. +For component work, paste or link the approved `## Validated component spec` from `component-spec-proposer` before implementation starts. After the spec is defined, the contributor waits for the issue label `status:approved` and verifies assignee ownership; no START WORK or implementation happens before both gates pass. For non-component work, record: @@ -78,6 +79,7 @@ For non-component work, record: Filled during START WORK: - Approval marker: issue label status:approved +- Assignee gate: unassigned / assigned to contributor / explicit reassignment permission - Assignee: - Branch: - Worktree: diff --git a/.atl/skills/pr-reviewer/SKILL.md b/.atl/skills/pr-reviewer/SKILL.md index ba01d934..f75f12c6 100644 --- a/.atl/skills/pr-reviewer/SKILL.md +++ b/.atl/skills/pr-reviewer/SKILL.md @@ -35,6 +35,7 @@ Run first. If any check fails, return **REJECTED** and do not continue to option | CI/build/test evidence missing or failing | Inspect CI output or run the agreed local commands. | | Package compatibility evidence missing for package-facing changes | When the diff changes package output, exports, generated declarations, peer ranges, CI/package distribution policy, or a React major version, require `pnpm run build` and `pnpm run verify:package` evidence. Tests/Storybook alone are insufficient for React major upgrades. | | No linked issue | PR description must contain `Closes #NNN` unless maintainer explicitly waives it. | +| Linked issue assigned to someone else without permission evidence | Fetch linked issue assignees; if any assignee is not the contributor/user, require explicit reassignment/takeover permission before review proceeds. | | Invalid PR title | Conventional Commit format: `(): `. | | PR template incomplete | No required placeholder sections left empty. | | Branch/diff scope unclear | Diff contains unrelated work without an explicit explanation. | @@ -80,6 +81,7 @@ Do not duplicate the component checklist here; cite the audit evidence and only ### 4 — Git hygiene +- [ ] Linked issue assignee gate passed before branch/work started, or explicit permission to reassign/take over is documented. - [ ] Branch name follows issue-derived project convention when applicable: `{type}/{issue-number}-{slug}` (for example `feat/123-button`) or has an approved exception. - [ ] Commit messages and PR title follow Conventional Commit format. - [ ] Allowed types: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`. @@ -112,6 +114,7 @@ Do not duplicate the component checklist here; cite the audit evidence and only - [CRITICAL|MAJOR] `file:line` — {problem} — Fix: {what to do} ### Evidence checked +- Linked issue assignee gate: {pass/fail/not applicable} - Component audit: {pass/fail/not applicable} - Visual review: {pass/fail/not applicable} - Typecheck/tests/build/storybook: {results} diff --git a/.atl/skills/worktree-location/SKILL.md b/.atl/skills/worktree-location/SKILL.md index 1dbfbb59..21262217 100644 --- a/.atl/skills/worktree-location/SKILL.md +++ b/.atl/skills/worktree-location/SKILL.md @@ -34,7 +34,9 @@ Instead: ## Branch and Worktree Naming -When work starts from a GitHub issue, use the same naming convention as `github-project-tasks` START WORK: +When work starts from a GitHub issue, first verify the `github-project-tasks` START WORK gates: the issue has `status:approved` and is unassigned or assigned to the contributor/user. If it is assigned to someone else, stop before creating a branch/worktree and require explicit permission before reassigning or taking it over. + +Then use the same naming convention as `github-project-tasks` START WORK: ```text branch: {type}/{issue-number}-{slug} diff --git a/.github/ISSUE_TEMPLATE/a11y.yml b/.github/ISSUE_TEMPLATE/a11y.yml index df79fd73..6c70e892 100644 --- a/.github/ISSUE_TEMPLATE/a11y.yml +++ b/.github/ISSUE_TEMPLATE/a11y.yml @@ -9,7 +9,7 @@ body: ## Accessibility Task Use this for WCAG, ARIA, keyboard navigation, focus management, screen reader behavior, or contrast issues. - Current flow: reproduce/audit -> define expected accessible behavior -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> keyboard/screen reader/axe evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: reproduce/audit -> define expected accessible behavior -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> keyboard/screen reader/axe evidence -> PR -> END WORK after merge or maintainer approval. Use `[FIX]` for accessibility defects and `[UPDATE]` for intentional accessibility improvements. @@ -106,7 +106,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/ci.yml b/.github/ISSUE_TEMPLATE/ci.yml index fcd860eb..630ab0a5 100644 --- a/.github/ISSUE_TEMPLATE/ci.yml +++ b/.github/ISSUE_TEMPLATE/ci.yml @@ -9,7 +9,7 @@ body: ## Infrastructure Task Use this for GitHub Actions, Vite, Biome, Lefthook, Storybook build, tests, release automation, or project tooling. - Current flow: define problem and risk -> plan exact config change -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> verify with local command or workflow run -> PR -> END WORK after merge or maintainer approval. + Current flow: define problem and risk -> plan exact config change -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> verify with local command or workflow run -> PR -> END WORK after merge or maintainer approval. - type: dropdown id: area @@ -89,7 +89,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/component.yml b/.github/ISSUE_TEMPLATE/component.yml index 5bcc3265..054cac92 100644 --- a/.github/ISSUE_TEMPLATE/component.yml +++ b/.github/ISSUE_TEMPLATE/component.yml @@ -9,7 +9,7 @@ body: ## New Component Task Use this for atoms, molecules, and organisms. New components must go through `component-spec-proposer` before implementation. - Current flow: reference and context -> validated component spec -> wait for issue label `status:approved` -> START WORK Project gate -> implementation -> component audit, visual review, accessibility evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: reference and context -> validated component spec -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implementation -> component audit, visual review, accessibility evidence -> PR -> END WORK after merge or maintainer approval. Set the title prefix to `[ATOMS]`, `[MOLECULES]`, or `[ORGANISMS]` based on the selected level. @@ -102,7 +102,7 @@ body: label: Workflow gates options: - label: Spec proposal must be approved before implementation starts. - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: Implementation must follow the 6-file component pattern. - label: Component audit, visual review, accessibility evidence, and focused tests are required before PR review. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/fix.yml b/.github/ISSUE_TEMPLATE/fix.yml index b36eb384..a5868cac 100644 --- a/.github/ISSUE_TEMPLATE/fix.yml +++ b/.github/ISSUE_TEMPLATE/fix.yml @@ -9,7 +9,7 @@ body: ## Bug Fix Task Use this when existing behavior is wrong or regressed. - Current flow: reproduce with evidence -> identify root cause/spec -> wait for issue label `status:approved` -> START WORK Project gate -> fix with regression test -> focused validation -> PR -> END WORK after merge or maintainer approval. + Current flow: reproduce with evidence -> identify root cause/spec -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> fix with regression test -> focused validation -> PR -> END WORK after merge or maintainer approval. - type: input id: affected-area @@ -87,7 +87,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/npm.yml b/.github/ISSUE_TEMPLATE/npm.yml index b8a36e3d..ebe454fa 100644 --- a/.github/ISSUE_TEMPLATE/npm.yml +++ b/.github/ISSUE_TEMPLATE/npm.yml @@ -9,7 +9,7 @@ body: ## NPM / Dependencies Task Use this for dependency updates, security fixes, peer dependency changes, package metadata, or dependency removals. - Current flow: research changelog and risk -> define update plan -> wait for issue label `status:approved` -> START WORK Project gate -> update -> verify build/tests/package consumption -> PR -> END WORK after merge or maintainer approval. + Current flow: research changelog and risk -> define update plan -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> update -> verify build/tests/package consumption -> PR -> END WORK after merge or maintainer approval. - type: dropdown id: change-type @@ -90,7 +90,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/storybook.yml b/.github/ISSUE_TEMPLATE/storybook.yml index 72e3988c..6ee56565 100644 --- a/.github/ISSUE_TEMPLATE/storybook.yml +++ b/.github/ISSUE_TEMPLATE/storybook.yml @@ -9,7 +9,7 @@ body: ## Storybook / Docs Task Use this for stories, MDX docs, controls, usage guidelines, visual examples, or Storybook configuration. - Current flow: identify documentation gap -> define required stories/docs -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> Storybook/manual visual evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: identify documentation gap -> define required stories/docs -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> Storybook/manual visual evidence -> PR -> END WORK after merge or maintainer approval. - type: input id: affected-area @@ -85,6 +85,8 @@ body: label: Storybook/docs gates options: - label: Stories follow project conventions and do not use Storybook `play` functions. + - label: Each story has useful JSDoc explaining the scenario and why it matters. + - label: Stories are non-redundant; generic `DarkMode` stories are avoided because Storybook has a global dark-mode toolbar. - label: Controls and args reflect the public API. - label: Visual states and edge cases are represented when relevant. - label: Accessibility notes are included for interactive examples when relevant. @@ -94,7 +96,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/tokens.yml b/.github/ISSUE_TEMPLATE/tokens.yml index e46da328..c96e0c5e 100644 --- a/.github/ISSUE_TEMPLATE/tokens.yml +++ b/.github/ISSUE_TEMPLATE/tokens.yml @@ -9,7 +9,7 @@ body: ## Design Tokens Task Use this for CSS custom properties, Tailwind token utilities, color, typography, spacing, radius, shadow, motion, or token documentation. - Current flow: audit token need and consumers -> define token/spec impact -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> contrast/visual/docs evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: audit token need and consumers -> define token/spec impact -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> contrast/visual/docs evidence -> PR -> END WORK after merge or maintainer approval. - type: dropdown id: token-type @@ -99,7 +99,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/ISSUE_TEMPLATE/update.yml b/.github/ISSUE_TEMPLATE/update.yml index 6a36588b..5968d1dc 100644 --- a/.github/ISSUE_TEMPLATE/update.yml +++ b/.github/ISSUE_TEMPLATE/update.yml @@ -9,7 +9,7 @@ body: ## Update or Refactor Task Use this for behavior extensions, API changes, refactors, and quality improvements that are not simple bug fixes. - Current flow: define motivation and scope -> record validated spec/plan when behavior changes -> wait for issue label `status:approved` -> START WORK Project gate -> implement -> validation and audit evidence -> PR -> END WORK after merge or maintainer approval. + Current flow: define motivation and scope -> record validated spec/plan when behavior changes -> wait for issue label `status:approved` -> assignee gate -> START WORK Project gate -> implement -> validation and audit evidence -> PR -> END WORK after merge or maintainer approval. - type: input id: affected-area @@ -129,7 +129,7 @@ body: attributes: label: Workflow gates options: - - label: START WORK must run only after issue label `status:approved`; it assigns the issue, moves Project status to `In progress`, and records branch/worktree before implementation. + - label: START WORK must run only after issue label `status:approved` and assignee ownership are verified; if assigned to someone else, get explicit permission before reassigning, then move Project status to `In progress` and record branch/worktree before implementation. - label: PR must link this issue and include validation evidence. - label: END WORK moves the Project item to `Done` only after merge or explicit maintainer approval. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5a484e11..304b6873 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -27,6 +27,7 @@ Closes # - [ ] Linked issue is present with `Closes #NNN` or maintainer approved an exception. - [ ] Linked issue has label `status:approved` before implementation starts. +- [ ] Linked issue assignee was checked before work started; if it was assigned to someone else, explicit reassignment permission is documented. - [ ] Work was started through the Project flow: assignee set, Project status `In progress`, branch/worktree recorded. - [ ] PR title follows Conventional Commit format: `(): `. - [ ] Commits follow the same commitlint-enforced format. diff --git a/README.en.md b/README.en.md index 01ba0da7..21affcc6 100644 --- a/README.en.md +++ b/README.en.md @@ -77,9 +77,9 @@ This project uses GitHub Issues + GitHub Projects as the source workflow. Short path: 1. Pick an issue from the [Project Board](https://github.com/orgs/Stack-and-Flow/projects/1). -2. Before implementing, verify that the spec is defined and the issue has the `status:approved` label. +2. Before implementing, verify that the spec is defined, the issue has the `status:approved` label, and the issue is not assigned to someone else. 3. Only then run **START WORK**: - - assign the issue to the contributor; + - verify assignees and assign the issue to the contributor; - move the Project item to `In progress`; - record the branch and worktree. 4. Use issue-based branch names: diff --git a/README.md b/README.md index 64f7858f..6b35776a 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,9 @@ Este proyecto usa GitHub Issues + GitHub Projects como flujo de trabajo. Ruta corta: 1. Elegí una issue del [Project Board](https://github.com/orgs/Stack-and-Flow/projects/1). -2. Antes de implementar, verificá que la spec esté definida y que la issue tenga el label `status:approved`. +2. Antes de implementar, verificá que la spec esté definida, que la issue tenga el label `status:approved` y que no esté asignada a otra persona. 3. Recién después ejecutá **START WORK**: - - asignar la issue al contributor; + - verificar assignees y asignar la issue al contributor; - mover el Project item a `In progress`; - registrar branch y worktree. 4. Usá branch issue-based: diff --git a/docs/CONTRIBUTING.en.md b/docs/CONTRIBUTING.en.md index 860a33f9..9d738062 100644 --- a/docs/CONTRIBUTING.en.md +++ b/docs/CONTRIBUTING.en.md @@ -69,6 +69,9 @@ Storybook is our single source of truth. Every component MUST be fully documente - `## Description` is required. - `## Dependencies` only when the component uses other components or external primitives. - `## Usage Guide` only when usage is complex. +- **Story-level docs**: every `export const StoryName` needs useful JSDoc that explains the scenario and why it matters. Do not use filler that only restates the story name. +- **No redundant stories**: each story must demonstrate a distinct state, variant axis, composition constraint, accessibility behavior, or integration context. +- **No generic `DarkMode` story**: use the Storybook dark-mode toolbar for normal theme coverage. Add a dedicated dark-mode story only for local dark scope, portal theme inheritance, or a theme-specific regression that the toolbar cannot express, and document that reason in JSDoc. - **No `parameters.docs.description.component`**: component docs live in JSDoc above `const meta`. - **No `play` functions**: Interactions are tested in `ComponentName.test.tsx`, not in stories. @@ -134,7 +137,7 @@ echo "feat(button): add loading state" | pnpm exec commitlint ### Pull Request Process -1. Before implementing from an issue, verify that the spec is defined and the issue has the `status:approved` label; only then run **START WORK**: assign the issue, move it to `In progress`, and record the branch/worktree plan. +1. Before implementing from an issue, verify that the spec is defined, the issue has the `status:approved` label, and the issue is not assigned to someone else; only then run **START WORK**: verify assignees, assign the issue, move it to `In progress`, and record the branch/worktree plan. 2. Push your branch and open a PR against `main`. 3. Use a PR title with the same Conventional Commit format, for example `feat(button): add loading state`. 4. You can request automated Copilot review until the PR is ready for human review. @@ -201,17 +204,18 @@ Phase summary: 1. **Research** — investigate references, API, states, accessibility, and design. 2. **Spec proposal** — use `component-spec-proposer` to turn the task and reference into a validated issue spec. 3. **Approval gate** — once the spec is written, wait for the `status:approved` label on the issue; without that label there is no START WORK or implementation under any circumstance. -4. **START WORK** — after the `status:approved` label, assign the issue, move it to `In progress`, and record branch/worktree. -5. **Spec intake** — with START WORK already completed, `component-contributor` reads the `## Validated component spec` section without inventing behavior. -6. **Spec review** — the agent critiques gaps, risks, and inconsistencies before planning. -7. **Visual preflight** — tokens, surfaces, states, focus, transitions, and dark mode are aligned before the plan. -8. **Plan** — review and approve files, variants, tests, stories, and accessibility. -9. **Implementation** — the agent creates the 6 files and explains decisions. -10. **Visual review** — CRITICAL or MAJOR issues are fixed before continuing. -11. **Pre-PR review** — `components-auditor` validates architecture, tests, Storybook, tokens, visual states, and accessibility before PR. -12. **END WORK** — move the task to `Done` only with a merged PR or explicit maintainer/user approval plus validation evidence. - -> To activate the full flow, first prepare the spec with `component-spec-proposer`; after validation, wait for `status:approved`, share the issue URL, and ask the agent to implement the component. +4. **Assignee gate** — before any action on a linked issue, verify assignees; if it is assigned to someone else, explicit permission is required before reassigning it. +5. **START WORK** — after the `status:approved` label and assignee gate, assign the issue, move it to `In progress`, and record branch/worktree. +6. **Spec intake** — with START WORK already completed, `component-contributor` reads the `## Validated component spec` section without inventing behavior. +7. **Spec review** — the agent critiques gaps, risks, and inconsistencies before planning. +8. **Visual preflight** — tokens, surfaces, states, focus, transitions, and dark mode are aligned before the plan. +9. **Plan** — review and approve files, variants, tests, stories, and accessibility. +10. **Implementation** — the agent creates the 6 files and explains decisions. +11. **Visual review** — CRITICAL or MAJOR issues are fixed before continuing. +12. **Pre-PR review** — `components-auditor` validates architecture, tests, Storybook, tokens, visual states, and accessibility before PR. +13. **END WORK** — move the task to `Done` only with a merged PR or explicit maintainer/user approval plus validation evidence. + +> To activate the full flow, first prepare the spec with `component-spec-proposer`; after validation, wait for `status:approved`, verify the issue is not assigned to someone else, share the issue URL, and ask the agent to implement the component. --- diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 86cca38d..9ae1b2ad 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -68,6 +68,9 @@ Storybook es nuestra única fuente de verdad. Todo componente DEBE estar complet - `## Description` obligatorio. - `## Dependencies` solo si usa otros componentes o primitives externas. - `## Usage Guide` solo si la utilización es compleja. +- **Docs por story**: cada `export const StoryName` necesita JSDoc útil que explique el escenario y por qué importa. No uses texto de relleno que solo repite el nombre de la story. +- **Sin stories redundantes**: cada story debe demostrar un estado, eje de variante, restricción de composición, comportamiento de accesibilidad o contexto de integración distinto. +- **Sin story genérica `DarkMode`**: usa el toolbar dark-mode de Storybook para cobertura normal de tema. Añadí una story dark-mode dedicada solo para scope dark local, herencia de tema en portales o una regresión específica que el toolbar no pueda expresar, y documentá esa razón en JSDoc. - **Sin `parameters.docs.description.component`**: la documentación del componente vive en JSDoc encima de `const meta`. - **Sin `play` functions**: Las interacciones se testean en `ComponentName.test.tsx`, no en stories. @@ -133,7 +136,7 @@ echo "feat(button): add loading state" | pnpm exec commitlint ### Proceso de Pull Request -1. Antes de implementar desde una issue, verificá que la spec esté definida y que la issue tenga el label `status:approved`; recién ahí corré **START WORK**: asignar la issue, moverla a `In progress` y registrar branch/worktree. +1. Antes de implementar desde una issue, verificá que la spec esté definida, que la issue tenga el label `status:approved` y que no esté asignada a otra persona; recién ahí corré **START WORK**: verificar assignees, asignar la issue, moverla a `In progress` y registrar branch/worktree. 2. Sube tu rama y abre un PR contra `main`. 3. Usa un título de PR con el mismo formato Conventional Commit, por ejemplo `feat(button): add loading state`. 4. Puedes pedir revisión automática a Copilot hasta que esté listo para revisión humana. @@ -205,17 +208,18 @@ Resumen de fases: 1. **Research** — investigas referencias, API, estados, accesibilidad y diseño. 2. **Spec proposal** — usas `component-spec-proposer` para convertir la tarea y referencia en una spec validada en la issue. 3. **Approval gate** — una vez escrita la spec, esperas el label `status:approved` en la issue; sin ese label no hay START WORK ni implementación bajo ningún concepto. -4. **START WORK** — después del label `status:approved`, asignas la issue, la mueves a `In progress` y registras branch/worktree. -5. **Spec intake** — con START WORK ya completado, `component-contributor` lee la sección `## Validated component spec` sin inventar comportamiento. -6. **Review de spec** — el agente critica gaps, riesgos e inconsistencias antes de planificar. -7. **Prefase visual** — el agente alinea tokens, superficie, estados, focus, transición y dark mode antes del plan. -8. **Plan** — revisas y apruebas archivos, variantes, tests, stories y accesibilidad. -9. **Implementación** — el agente crea los 6 archivos y explica decisiones. -10. **Visual review** — se corrigen issues CRITICAL o MAJOR antes de continuar. -11. **Review pre-PR** — `components-auditor` valida arquitectura, tests, Storybook, tokens, visual y accesibilidad antes de abrir PR. -12. **END WORK** — al cerrar, la tarea pasa a `Done` solo con PR merged o aprobación explícita, más evidencia de validación. - -> Para activar el flujo completo, primero pedí la spec con `component-spec-proposer`; después de validarla, esperá `status:approved`, compartí la URL de la issue y decí "implementa este componente". +4. **Assignee gate** — antes de cualquier acción sobre una issue linkeada, verificas assignees; si está asignada a otra persona, hace falta permiso explícito antes de reasignarla. +5. **START WORK** — después del label `status:approved` y el assignee gate, asignas la issue, la mueves a `In progress` y registras branch/worktree. +6. **Spec intake** — con START WORK ya completado, `component-contributor` lee la sección `## Validated component spec` sin inventar comportamiento. +7. **Review de spec** — el agente critica gaps, riesgos e inconsistencias antes de planificar. +8. **Prefase visual** — el agente alinea tokens, superficie, estados, focus, transición y dark mode antes del plan. +9. **Plan** — revisas y apruebas archivos, variantes, tests, stories y accesibilidad. +10. **Implementación** — el agente crea los 6 archivos y explica decisiones. +11. **Visual review** — se corrigen issues CRITICAL o MAJOR antes de continuar. +12. **Review pre-PR** — `components-auditor` valida arquitectura, tests, Storybook, tokens, visual y accesibilidad antes de abrir PR. +13. **END WORK** — al cerrar, la tarea pasa a `Done` solo con PR merged o aprobación explícita, más evidencia de validación. + +> Para activar el flujo completo, primero pedí la spec con `component-spec-proposer`; después de validarla, esperá `status:approved`, verificá que la issue no esté asignada a otra persona, compartí la URL de la issue y decí "implementa este componente". --- diff --git a/docs/CONTRIBUTOR-FLOW.en.md b/docs/CONTRIBUTOR-FLOW.en.md index fb05f4de..1c5dbdce 100644 --- a/docs/CONTRIBUTOR-FLOW.en.md +++ b/docs/CONTRIBUTOR-FLOW.en.md @@ -7,10 +7,10 @@ This is the canonical document for contributing components to the design system. ## Quick summary ```text -Project task → Research → Spec proposal skill → Validated issue spec → wait for `status:approved` → START WORK → Spec review → Visual preflight → Plan → Implementation → Visual review → Pre-PR component review → PR → Review → Merge → END WORK +Project task → Research → Spec proposal skill → Validated issue spec → wait for `status:approved` → verify assignee → START WORK → Spec review → Visual preflight → Plan → Implementation → Visual review → Pre-PR component review → PR → Review → Merge → END WORK ``` -Core rule: **AI executes, the contributor decides**. The spec, visual criteria, and checkpoint approvals remain human responsibility. After the validated spec is written in the task, implementation stays blocked until the linked issue has the `status:approved` label. +Core rule: **AI executes, the contributor decides**. The spec, visual criteria, and checkpoint approvals remain human responsibility. After the validated spec is written in the task, implementation stays blocked until the linked issue has the `status:approved` label and is not assigned to someone else. --- @@ -34,8 +34,9 @@ If these sources disagree, the authority order is: `GUIDELINES*.md` / `DESIGN*.m 1. Pick a task in the [GitHub Projects Board](https://github.com/orgs/Stack-and-Flow/projects/1). 2. Verify that it has an issue attached. The issue is the implementation contract. -3. Do not run **START WORK** yet if the spec is not defined and approved. The contributor may research and propose the spec, but must not start implementation. -4. If the user requested offline/no-network work, do not mutate GitHub: record the required follow-up. Do not start implementation until verifying that the issue has the `status:approved` label. +3. Before taking a linked issue, verify assignees. If it is already assigned to someone else, stop and get explicit permission before reassigning or taking it over. +4. Do not run **START WORK** yet if the spec is not defined and approved. The contributor may research and propose the spec, but must not start implementation. +5. If the user requested offline/no-network work, do not mutate GitHub: record the required follow-up. Do not start implementation until verifying that the issue has the `status:approved` label and the assignee gate is satisfied. --- @@ -86,9 +87,9 @@ The skill must: 4. Wait for human approval. 5. Only after approval, write `## Validated component spec` in the issue. 6. Leave the task waiting for approval: do not move it to `In progress` from `component-spec-proposer`. -7. Indicate the next step: wait for the `status:approved` issue label before starting `component-contributor`. +7. Indicate the next step: wait for the `status:approved` issue label and verify the issue is unassigned or assigned to the contributor/user before starting `component-contributor`. -Do not use `component-contributor` to implement until the spec is validated and the issue has the `status:approved` label. +Do not use `component-contributor` to implement until the spec is validated, the issue has the `status:approved` label, and the assignee gate has passed. --- @@ -119,8 +120,9 @@ After documenting the spec, the contributor must wait for explicit maintainer/pr Rules: - Do not create the implementation branch, plan, or code before `status:approved`. +- Before any action on a linked issue, verify assignees. If it is assigned to someone else, stop and notify the user that explicit permission is required before reassigning it. - Do not move the Project item to `In progress` from the spec proposal phase. -- When the `status:approved` label is present on the issue, run **START WORK**: assign the issue, move the Project item to `In progress`, confirm Team/Category, and record branch/worktree. +- When the `status:approved` label is present and the assignee gate passes, run **START WORK**: assign the issue, move the Project item to `In progress`, confirm Team/Category, and record branch/worktree. - If the `status:approved` label is missing, stop and request approval; do not replace it with implicit chat approval. --- @@ -173,10 +175,10 @@ Implement this component using component-contributor. Issue: {issue_url} -Use the `## Validated component spec` section as the contract. Before reading the spec in detail, planning, or writing code, verify that the issue has the `status:approved` label; if it is missing, stop. Run START WORK before implementation intake. Do not invent props or behavior outside the spec. Pause at spec review, visual preflight, and plan checkpoints before writing code. +Use the `## Validated component spec` section as the contract. Before reading the spec in detail, planning, or writing code, verify that the issue has the `status:approved` label and is not assigned to someone else; if the label is missing or the assignee gate fails, stop. Run START WORK before implementation intake. Do not invent props or behavior outside the spec. Pause at spec review, visual preflight, and plan checkpoints before writing code. ``` -The agent must load `component-contributor`, check the `status:approved` label, run START WORK, and only then consume the validated spec from `component-spec-proposer`. If it skips a phase, stop it. +The agent must load `component-contributor`, check the `status:approved` label, verify assignees, run START WORK, and only then consume the validated spec from `component-spec-proposer`. If it skips a phase, stop it. --- @@ -184,12 +186,12 @@ The agent must load `component-contributor`, check the `status:approved` label, ### Phase 1 — Read the validated spec -Before this phase, the agent must already have verified the `status:approved` label and completed START WORK. It then reads the `## Validated component spec` section in the issue and extracts the component, tier, props, variants, states, accessibility, reference, and design notes. +Before this phase, the agent must already have verified the `status:approved` label, confirmed the issue is not assigned to someone else without explicit permission, and completed START WORK. It then reads the `## Validated component spec` section in the issue and extracts the component, tier, props, variants, states, accessibility, reference, and design notes. Expected output: - spec summary; -- evidence of the `status:approved` label and START WORK; +- evidence of the `status:approved` label, assignee gate, and START WORK; - questions if anything is ambiguous; - reference/token modules it plans to load. @@ -420,7 +422,8 @@ Minimum checklist: - [ ] Relevant tests pass. - [ ] Build or required checks pass. - [ ] Pre-PR component review included or summarized. -- [ ] Storybook docs have a JSDoc block above `const meta` and above every story export. +- [ ] Storybook docs have a JSDoc block above `const meta` and useful scenario/purpose JSDoc above every story export. +- [ ] Stories are non-redundant; no generic `DarkMode` story duplicates the toolbar. - [ ] `## Description` is present. - [ ] `## Dependencies` only when applicable. - [ ] `## Usage Guide` only when applicable. @@ -473,6 +476,10 @@ Only when composition or usage has non-obvious constraints. All content inside the JSDoc block must be in English, including headings, prose, and lists. +Each story-level JSDoc block above `export const StoryName` must explain the scenario and why it matters: state, variant axis, composition constraint, accessibility behavior, or integration context. Do not accept filler descriptions that only restate the story name. + +Use the Storybook dark-mode toolbar for normal theme coverage. Do not add a generic `DarkMode` story unless it demonstrates local dark scope, portal theme inheritance, or a theme-specific regression that the toolbar cannot express; the story JSDoc must state that reason. + --- ## Rules the AI cannot skip @@ -484,7 +491,8 @@ If the agent proposes any of the following, reject it: - using a single-file architecture; - omitting `.test.tsx` tests; - putting interactions in `play` functions instead of tests; -- writing stories without args, controls, a JSDoc block above `const meta`, or JSDoc above every story export; +- writing stories without args, controls, a JSDoc block above `const meta`, or useful JSDoc above every story export; +- adding redundant stories that duplicate controls, args, another story, or normal dark-mode toolbar coverage; - using `description.component` in `parameters.docs`; - using `interface` or `any`; - hardcoding colors, spacing, or fonts; diff --git a/docs/CONTRIBUTOR-FLOW.md b/docs/CONTRIBUTOR-FLOW.md index 895b2700..45376877 100644 --- a/docs/CONTRIBUTOR-FLOW.md +++ b/docs/CONTRIBUTOR-FLOW.md @@ -7,10 +7,10 @@ Este es el documento canónico para contribuir componentes al design system. `CO ## Resumen rápido ```text -Project task → Research → Spec proposal skill → Validated issue spec → esperar `status:approved` → START WORK → Spec review → Visual preflight → Plan → Implementación → Visual review → Pre-PR component review → PR → Review → Merge → END WORK +Project task → Research → Spec proposal skill → Validated issue spec → esperar `status:approved` → verificar assignee → START WORK → Spec review → Visual preflight → Plan → Implementación → Visual review → Pre-PR component review → PR → Review → Merge → END WORK ``` -La regla central: **la IA ejecuta, el contributor decide**. La spec, los criterios visuales y la aprobación de checkpoints son responsabilidad humana. Después de escribir la spec validada en la tarea, la implementación queda bloqueada hasta que la issue asociada tenga el label `status:approved`. +La regla central: **la IA ejecuta, el contributor decide**. La spec, los criterios visuales y la aprobación de checkpoints son responsabilidad humana. Después de escribir la spec validada en la tarea, la implementación queda bloqueada hasta que la issue asociada tenga el label `status:approved` y no esté asignada a otra persona. --- @@ -34,8 +34,9 @@ Si hay contradicción, el orden de autoridad es: `GUIDELINES.md` / `DESIGN.md` p 1. Elegí una tarea en el [GitHub Projects Board](https://github.com/orgs/Stack-and-Flow/projects/1). 2. Verificá que tenga issue asociada. La issue es el contrato de implementación. -3. No corras **START WORK** todavía si la spec no está definida y aprobada. El contributor puede investigar y proponer la spec, pero no puede arrancar implementación. -4. Si el usuario pidió trabajo offline/no-network, no mutés GitHub: dejá registrado el follow-up necesario. No empieces implementación hasta verificar que la issue tenga el label `status:approved`. +3. Antes de tomar una issue linkeada, verificá los assignees. Si ya está asignada a otra persona, frená y pedí permiso explícito antes de reasignártela o tomarla. +4. No corras **START WORK** todavía si la spec no está definida y aprobada. El contributor puede investigar y proponer la spec, pero no puede arrancar implementación. +5. Si el usuario pidió trabajo offline/no-network, no mutés GitHub: dejá registrado el follow-up necesario. No empieces implementación hasta verificar que la issue tenga el label `status:approved` y que el assignee gate esté satisfecho. --- @@ -86,9 +87,9 @@ La skill debe: 4. Esperar aprobación humana. 5. Recién después de la aprobación, escribir `## Validated component spec` en la issue. 6. Dejar la tarea esperando aprobación: no moverla a `In progress` desde `component-spec-proposer`. -7. Indicar el siguiente paso: esperar el marcador `status:approved` antes de arrancar `component-contributor`. +7. Indicar el siguiente paso: esperar el marcador `status:approved` y verificar que la issue esté sin assignee o asignada al contributor/usuario antes de arrancar `component-contributor`. -No uses `component-contributor` para implementar hasta que la spec esté validada y la issue tenga el label `status:approved`. +No uses `component-contributor` para implementar hasta que la spec esté validada, la issue tenga el label `status:approved` y el assignee gate haya pasado. --- @@ -119,8 +120,9 @@ Después de documentar la spec, el contributor debe esperar aprobación explíci Reglas: - No crear rama de implementación, plan ni código antes de `status:approved`. +- Antes de cualquier acción sobre una issue linkeada, verificá assignees. Si está asignada a otra persona, frená y avisá que hace falta permiso explícito antes de reasignártela. - No mover el Project item a `In progress` desde la fase de spec proposal. -- Cuando el label `status:approved` esté presente en la issue, corré **START WORK**: asignate la issue, mové el Project item a `In progress`, confirmá Team/Category y registrá branch/worktree. +- Cuando el label `status:approved` esté presente y el assignee gate pase, corré **START WORK**: asignate la issue, mové el Project item a `In progress`, confirmá Team/Category y registrá branch/worktree. - Si falta el label `status:approved`, frená y pedí aprobación; no lo reemplaces por aprobación implícita en chat. --- @@ -173,10 +175,10 @@ Implementá este componente usando component-contributor. Issue: {issue_url} -Usá la sección `## Validated component spec` como contrato. Antes de leer la spec en detalle, planificar o escribir código, verificá que la issue tenga el label `status:approved`; si falta, frená. Ejecutá START WORK antes del intake de implementación. No inventes props ni comportamiento fuera de la spec. Pausá en los checkpoints de spec review, visual preflight y plan antes de escribir código. +Usá la sección `## Validated component spec` como contrato. Antes de leer la spec en detalle, planificar o escribir código, verificá que la issue tenga el label `status:approved` y que no esté asignada a otra persona; si falta el label o el assignee gate falla, frená. Ejecutá START WORK antes del intake de implementación. No inventes props ni comportamiento fuera de la spec. Pausá en los checkpoints de spec review, visual preflight y plan antes de escribir código. ``` -El agente debe cargar `component-contributor`, comprobar el label `status:approved`, correr START WORK y recién después consumir la spec validada por `component-spec-proposer`. Si salta una fase, frenalo. +El agente debe cargar `component-contributor`, comprobar el label `status:approved`, verificar assignees, correr START WORK y recién después consumir la spec validada por `component-spec-proposer`. Si salta una fase, frenalo. --- @@ -184,12 +186,12 @@ El agente debe cargar `component-contributor`, comprobar el label `status:approv ### Fase 1 — Lectura de spec validada -Antes de esta fase, el agente ya debe haber verificado el label `status:approved` y completado START WORK. Luego lee la sección `## Validated component spec` de la issue y extrae componente, tier, props, variantes, estados, accesibilidad, referencia y notas de diseño. +Antes de esta fase, el agente ya debe haber verificado el label `status:approved`, confirmado que la issue no está asignada a otra persona sin permiso explícito y completado START WORK. Luego lee la sección `## Validated component spec` de la issue y extrae componente, tier, props, variantes, estados, accesibilidad, referencia y notas de diseño. Salida esperada: - resumen de la spec; -- evidencia del label `status:approved` y START WORK; +- evidencia del label `status:approved`, assignee gate y START WORK; - preguntas si algo es ambiguo; - módulos de referencia/tokens que va a cargar. @@ -472,6 +474,10 @@ Only when composition or usage has non-obvious constraints. Todo el contenido del bloque JSDoc debe estar en inglés, incluidos headings, texto descriptivo y listas. +Cada bloque JSDoc de story encima de `export const StoryName` debe explicar el escenario y por qué importa: estado, eje de variante, restricción de composición, comportamiento de accesibilidad o contexto de integración. No aceptes descripciones de relleno que solo repiten el nombre de la story. + +Usá el toolbar dark-mode de Storybook para cobertura normal de tema. No añadas una story genérica `DarkMode` salvo que demuestre scope dark local, herencia de tema en portales o una regresión específica que el toolbar no pueda expresar; el JSDoc de la story debe explicitar esa razón. + --- ## Reglas que la IA no puede saltarse @@ -483,7 +489,8 @@ Si el agente propone cualquiera de estas cosas, rechazalo: - usar una arquitectura de archivo único; - omitir tests `.test.tsx`; - meter interacciones en `play` functions en lugar de tests; -- escribir stories sin args, controles o bloque JSDoc encima de `const meta`; +- escribir stories sin args, controles, bloque JSDoc encima de `const meta` o JSDoc útil encima de cada story export; +- añadir stories redundantes que dupliquen controles, args, otra story o la cobertura normal del toolbar dark-mode; - usar `description.component` en `parameters.docs`; - usar `interface` o `any`; - hardcodear colores, spacing o fuentes; diff --git a/docs/ENVIRONMENT-SETUP.en.md b/docs/ENVIRONMENT-SETUP.en.md index 7fc44c68..03538fb8 100644 --- a/docs/ENVIRONMENT-SETUP.en.md +++ b/docs/ENVIRONMENT-SETUP.en.md @@ -107,7 +107,7 @@ When you want to implement a component, simply say: Implement this component: https://github.com/Stack-and-Flow/design-system/issues/XXX ``` -The agent will load `component-contributor` and follow the current workflow: `status:approved` label verification, START WORK when applicable, validated spec reading, spec review, visual preflight, plan, implementation, visual review, pre-PR component audit, and END WORK when closing the task. +The agent will load `component-contributor` and follow the current workflow: `status:approved` label verification, assignee verification, START WORK when applicable, validated spec reading, spec review, visual preflight, plan, implementation, visual review, pre-PR component audit, and END WORK when closing the task. --- diff --git a/docs/ENVIRONMENT-SETUP.md b/docs/ENVIRONMENT-SETUP.md index ca6705c5..7234c6eb 100644 --- a/docs/ENVIRONMENT-SETUP.md +++ b/docs/ENVIRONMENT-SETUP.md @@ -107,7 +107,7 @@ Cuando vayas a implementar un componente, simplemente di: Implementa este componente: https://github.com/Stack-and-Flow/design-system/issues/XXX ``` -El agente cargará la skill `component-contributor` y seguirá el flujo actual: verificación del label `status:approved`, START WORK cuando aplique, lectura de spec validada, spec review, visual preflight, plan, implementación, visual review, component audit pre-PR y END WORK al cerrar la tarea. +El agente cargará la skill `component-contributor` y seguirá el flujo actual: verificación del label `status:approved`, verificación de assignees, START WORK cuando aplique, lectura de spec validada, spec review, visual preflight, plan, implementación, visual review, component audit pre-PR y END WORK al cerrar la tarea. --- diff --git a/docs/GUIDELINES.en.md b/docs/GUIDELINES.en.md index 24934ad9..de0b2412 100644 --- a/docs/GUIDELINES.en.md +++ b/docs/GUIDELINES.en.md @@ -131,7 +131,9 @@ export type * from './types'; - **Mandatory Controls**: Use JSDoc comments (`/** @control text */`) in `types.ts` to power the controls. - **Mandatory Description**: Every component story MUST include a JSDoc block immediately above `const meta` with `## Description` required. Use `## Dependencies` and `## Usage Guide` only when applicable. - **No `parameters.docs.description.component`**: component docs live in JSDoc above `const meta`, not in `parameters.docs.description.component`. -- **Story-level docs**: add concise JSDoc immediately above every `export const StoryName`. +- **Story-level docs**: add useful JSDoc immediately above every `export const StoryName`; it must explain the scenario and why it matters, not just restate the story name. +- **No redundant stories**: each story must demonstrate a distinct state, variant axis, composition constraint, accessibility behavior, or integration context. +- **No generic `DarkMode` story**: use the Storybook dark-mode toolbar for normal theme coverage; dedicated dark-mode stories are only for local scope, portal inheritance, or theme-specific regressions the toolbar cannot express. - **Args**: Define default `args` for the base story without overriding `defaultVariants`. --- diff --git a/docs/GUIDELINES.md b/docs/GUIDELINES.md index be5f9f1b..bc2b121b 100644 --- a/docs/GUIDELINES.md +++ b/docs/GUIDELINES.md @@ -159,7 +159,9 @@ export type * from "./types"; }; ``` - **Sin `parameters.docs.description.component`**: la documentación del componente vive en el bloque JSDoc encima de `const meta`. -- **Stories documentadas**: añade un bloque JSDoc corto encima de cada `export const StoryName`. +- **Stories documentadas**: añade un bloque JSDoc útil encima de cada `export const StoryName`; debe explicar el escenario y por qué importa, no solo repetir el nombre de la story. +- **Sin stories redundantes**: cada story debe demostrar un estado, eje de variante, restricción de composición, comportamiento de accesibilidad o contexto de integración distinto. +- **Sin story genérica `DarkMode`**: usa el toolbar dark-mode de Storybook para cobertura normal de tema; las stories dark-mode dedicadas quedan solo para scope local, herencia en portales o regresiones de tema que el toolbar no pueda expresar. - **Args**: Define `args` por defecto para la story base sin pisar `defaultVariants`. --- diff --git a/docs/QUICK_START.en.md b/docs/QUICK_START.en.md index 768f02a7..8ab07835 100644 --- a/docs/QUICK_START.en.md +++ b/docs/QUICK_START.en.md @@ -34,8 +34,8 @@ Go to the [GitHub Project board](https://github.com/orgs/Stack-and-Flow/projects > **First time?** Look for issues tagged `layer: atom` with `category: component` — these are self-contained and well-defined. -Before writing code, make sure the spec is defined and the issue has the `status:approved` label. Only then run **START WORK**: -- assign the issue to yourself; +Before writing code, make sure the spec is defined, the issue has the `status:approved` label, and the issue is not assigned to someone else. Only then run **START WORK**: +- verify assignees and assign the issue to yourself; - move it to `In progress`; - record the branch and worktree plan. diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md index 7e3ec302..5f2d67ab 100644 --- a/docs/QUICK_START.md +++ b/docs/QUICK_START.md @@ -36,8 +36,8 @@ Ve al [tablero del proyecto en GitHub](https://github.com/orgs/Stack-and-Flow/pr > **¿Primera vez?** Busca issues etiquetados como `layer: atom` con `category: component` — son autocontenidos y bien definidos. -Antes de escribir código, asegurate de que la spec esté definida y la issue tenga el label `status:approved`. Recién entonces corré **START WORK**: -- asignate la issue; +Antes de escribir código, asegurate de que la spec esté definida, la issue tenga el label `status:approved` y no esté asignada a otra persona. Recién entonces corré **START WORK**: +- verificá assignees y asignate la issue; - movela a `In progress`; - registrá branch y worktree plan. From 3ac3ac489c89ac4ec11bccd59f3d78b78aba82b5 Mon Sep 17 00:00:00 2001 From: egdev6 Date: Fri, 5 Jun 2026 19:27:21 +0200 Subject: [PATCH 2/2] docs(harness): enforce bilingual docs --- .atl/AGENTS.md | 1 + .atl/skills/pr-reviewer/SKILL.md | 2 + docs/COMPONENTS.md | 491 +++++++++++++++---------------- docs/CONTRIBUTING.en.md | 11 + docs/CONTRIBUTING.md | 11 + 5 files changed, 256 insertions(+), 260 deletions(-) diff --git a/.atl/AGENTS.md b/.atl/AGENTS.md index 071a54aa..add1446f 100644 --- a/.atl/AGENTS.md +++ b/.atl/AGENTS.md @@ -62,6 +62,7 @@ Components live in `src/components/{atoms|molecules|organisms}/{kebab-name}/` wi - For package-facing changes (package output, exports, generated declarations, peer ranges, React major upgrades, or CI/package distribution policy), require `pnpm run build`; require `pnpm run verify:package` when published output or consumer compatibility can change. Tests/Storybook alone are not enough for React major upgrades. - Generated declarations must not leak internal path aliases or CSS side-effect imports into the published `.d.ts` output - English only — code, comments, stories +- Paired repository docs are bilingual: base `*.md` files are Spanish and matching `*.en.md` files are English. When editing docs under `docs/` or root README files, preserve that split, update both language variants when the content changes, and never replace the Spanish base file with English prose. - Commit messages must follow the commitlint-enforced Conventional Commit format: `(): `. PR titles should follow the same format for review consistency. Allowed types: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`. Use scopes for domains such as `a11y`, `tokens`, or `infra` instead of inventing custom types. --- diff --git a/.atl/skills/pr-reviewer/SKILL.md b/.atl/skills/pr-reviewer/SKILL.md index f75f12c6..a6b20861 100644 --- a/.atl/skills/pr-reviewer/SKILL.md +++ b/.atl/skills/pr-reviewer/SKILL.md @@ -38,6 +38,7 @@ Run first. If any check fails, return **REJECTED** and do not continue to option | Linked issue assigned to someone else without permission evidence | Fetch linked issue assignees; if any assignee is not the contributor/user, require explicit reassignment/takeover permission before review proceeds. | | Invalid PR title | Conventional Commit format: `(): `. | | PR template incomplete | No required placeholder sections left empty. | +| Paired docs language split broken | For root/docs `*.md` + `*.en.md` pairs, base `*.md` must remain Spanish and matching `*.en.md` must remain English unless maintainers explicitly approve a language migration. | | Branch/diff scope unclear | Diff contains unrelated work without an explicit explanation. | | Component audit missing for component changes | Run or cite `components-auditor`; CRITICAL/MAJOR findings block PR. | | Storybook conventions contradicted | Use `component-contributor/references/stories.md` as source of truth; reject drift such as `parameters.docs.description.component`. | @@ -56,6 +57,7 @@ Run after automatic rejection checks pass. - [ ] Generated/build/runtime artifacts are absent. - [ ] Review workload is reasonable; if over 400 changed lines, use chained PR strategy or record maintainer exception. - [ ] Public API changes are intentional and documented. +- [ ] Paired docs keep the repository language split: Spanish in base `*.md`, English in matching `*.en.md`. ### 2 — Component quality evidence diff --git a/docs/COMPONENTS.md b/docs/COMPONENTS.md index 74c1816b..271ae7f8 100644 --- a/docs/COMPONENTS.md +++ b/docs/COMPONENTS.md @@ -1,18 +1,18 @@ -# Stack-and-Flow — Component Visual Specification +# Stack-and-Flow — Especificación visual de componentes -> Reference for AI agents writing or reviewing component code. Covers every interactive state, glow system, transition rules, gradient border technique, and accessibility requirements. Derived from the Agent Teams reference project and Stack-and-Flow tokens. +> Referencia para agentes de IA que escriben o revisan código de componentes. Cubre todos los estados interactivos, el sistema de glow, las reglas de transición, la técnica de bordes con degradado y los requisitos de accesibilidad. Se basa en los tokens de Stack-and-Flow y en el contrato visual actual del proyecto. --- -## 1. Compositional Principles +## 1. Principios de composición -These rules are system-wide and non-negotiable. Every component must comply with all of them. +Estas reglas se aplican a todo el sistema y no admiten excepciones. Todos los componentes deben cumplirlas. -**Rule 1 — `backdrop-filter: blur` only on floating elements.** -Only elements that literally float above page content (navbar, mobile sidebar, modal backdrops, sticky bars, or an explicitly floating `CardContainer` with `backdropBlur` enabled) use `backdrop-filter`. Content cards are opaque — they use `background: #0B131E`. `blur` signals "I am floating"; opaque signals "I am content". Never apply `backdrop-filter` to feature cards, release cards, pipeline cards, or any card that lives in normal document flow. `CardContainer` defaults to `backdropBlur="none"`; `backdropBlur="sm" | "md" | "lg"` is only for floating/glass treatments above other content. +**Regla 1 — `backdrop-filter: blur` solo en elementos flotantes.** +Solo los elementos que realmente flotan sobre el contenido de la página (navbar, barra lateral móvil, fondos de modal, barras sticky o un `CardContainer` explícitamente flotante con `backdropBlur` activado) usan `backdrop-filter`. Las cards de contenido son opacas: usan `background: #0B131E`. El `blur` comunica "estoy flotando"; una superficie opaca comunica "soy contenido". Nunca apliques `backdrop-filter` a cards de features, release cards, pipeline cards ni a ninguna card que viva en el flujo normal del documento. `CardContainer` usa `backdropBlur="none"` por defecto; `backdropBlur="sm" | "md" | "lg"` queda reservado para tratamientos flotantes o glass por encima de otros contenidos. -**Rule 2 — Never animate gradient background directly. Use `::before` opacity instead.** -A `linear-gradient` cannot be transitioned by the browser. Instead, place the hover gradient on a `::before` pseudo-element with `opacity: 0`, then transition only `opacity` to `1` on hover. This runs on the GPU compositor and produces a smooth fade. The background property on the element itself remains static or uses only simple `background-color` transitions. +**Regla 2 — Nunca animes el fondo con degradado directamente. Usa la opacidad de `::before` en su lugar.** +El navegador no puede interpolar un `linear-gradient`. En su lugar, coloca el degradado de hover en un pseudo-elemento `::before` con `opacity: 0` y anima solo `opacity` hasta `1` al hacer hover. Eso se ejecuta en el compositor de la GPU y produce una transición suave. El `background` del elemento principal permanece estático o usa solo transiciones simples de `background-color`. ```css /* ✅ Correct pattern */ @@ -39,16 +39,16 @@ A `linear-gradient` cannot be transitioned by the browser. Instead, place the ho } ``` -**Rule 3 — Decorative glow is semantic; focus glow is accessibility.** -Treat decorative glow/elevation as part of the component contract, not as a raw visual toggle. A component may ship with decorative glow at rest, on hover, or not at all depending on its variant semantics. Where the component API supports it, expose `emphasis="default" | "flat"` so quiet contexts can suppress decorative glow without changing hierarchy, behavior, or semantics. +**Regla 3 — El glow decorativo es semántico; el glow de focus es accesibilidad.** +Trata el glow o la elevación decorativos como parte del contrato del componente, no como un simple interruptor visual. Un componente puede incluir glow decorativo en reposo, en hover o no incluirlo en absoluto según la semántica de su variante. Cuando la API lo permita, expón `emphasis="default" | "flat"` para que los contextos más sobrios puedan suprimir el glow decorativo sin alterar la jerarquía, el comportamiento ni la semántica. -Focus-visible rings/glows are different: they are accessibility affordances and must never be disabled by `emphasis`, quiet modes, or decorative shadow toggles. Never remove `shadow-glow-focus-*`, focus rings, or selected-state accessibility glow through decorative API controls. +Los anillos o glows de `focus-visible` son otra cosa: son indicadores de accesibilidad y nunca deben desactivarse mediante `emphasis`, modos sobrios ni toggles de sombra decorativa. Nunca elimines `shadow-glow-focus-*`, los anillos de focus ni el glow de accesibilidad del estado seleccionado a través de controles decorativos de la API. -**Rule 4 — `backdrop-filter` and gradient on the same element are forbidden.** -A frosted element (`backdrop-filter: blur`) must not also carry a decorative gradient background layer. They conflict visually (the blur already creates depth) and can cause GPU compositing artifacts. Choose one: frosted surface OR gradient surface. +**Regla 4 — `backdrop-filter` y un degradado en el mismo elemento están prohibidos.** +Un elemento con efecto esmerilado (`backdrop-filter: blur`) no debe llevar además una capa decorativa de fondo con degradado. Ambos recursos compiten visualmente (el blur ya aporta profundidad) y pueden generar artefactos de composición en la GPU. Elige una sola opción: superficie esmerilada O superficie con degradado. -**Rule 5 — Never use `transition: all`.** -Always enumerate exactly the properties being animated. `transition: all` animates every CSS property including layout-forcing ones (`width`, `height`, `top`, `left`, `padding`), which triggers reflow and causes jank. Permitted properties to animate: `opacity`, `transform`, `box-shadow`, `background-color`, `border-color`, `color`, `gap`. +**Regla 5 — No uses nunca `transition: all`.** +Enumera siempre exactamente las propiedades que se animan. `transition: all` anima todas las propiedades CSS, incluidas las que fuerzan layout (`width`, `height`, `top`, `left`, `padding`), lo que dispara reflow y genera tirones visuales. Las propiedades permitidas para animar son: `opacity`, `transform`, `box-shadow`, `background-color`, `border-color`, `color`, `gap`. ```css /* ✅ Correct */ @@ -59,53 +59,53 @@ transition: transition: all 0.25s ease; ``` -**Rule 6 — Hover direction is tonally upward for both primary and secondary.** -On `:hover`, primary button gradient shifts lighter (`#ff1a4b → #ff3366` start, `#cc0030 → #e0003a` end) and glow intensity increases. Secondary button background tint increases from `rgba(255,0,54,0.06)` to `rgba(255,0,54,0.12)` and border opacity increases. Hover always makes elements feel more elevated — never darker or more muted. +**Regla 6 — El hover debe aclarar el tono tanto en primary como en secondary.** +En `:hover`, el degradado del botón primary se aclara (`#ff1a4b → #ff3366` al inicio, `#cc0030 → #e0003a` al final) y la intensidad del glow aumenta. El tinte de fondo del botón secondary sube de `rgba(255,0,54,0.06)` a `rgba(255,0,54,0.12)` y también aumenta la opacidad del borde. El hover siempre debe hacer que los elementos se perciban más elevados, nunca más oscuros ni más apagados. -**Rule 7 — Focus ring uses `box-shadow`, never `outline`.** -`outline` does not respect `border-radius` — it draws a rectangle around a pill button. `box-shadow` follows the shape. Use: +**Regla 7 — El anillo de focus usa `box-shadow`, nunca `outline`.** +`outline` no respeta `border-radius`: dibuja un rectángulo alrededor de un botón tipo píldora. `box-shadow` sí sigue la forma. Usa: -- Dark: `box-shadow: 0 0 0 3px rgba(255, 0, 54, 0.40)` -- Light: `box-shadow: 0 0 0 3px rgba(219, 20, 60, 0.35)` +- Oscuro: `box-shadow: 0 0 0 3px rgba(255, 0, 54, 0.40)` +- Claro: `box-shadow: 0 0 0 3px rgba(219, 20, 60, 0.35)` -Never use `outline: none` without an alternative visible focus indicator. +Nunca uses `outline: none` sin un indicador de focus visible alternativo. -**Rule 8 — Disabled state uses opacity, never color change.** -`opacity: 0.4` on the entire component signals disabled. Never change text color, border color, or background to a "grey" variant — this creates a fake semantic signal and breaks the visual system. Always pair with `cursor: not-allowed` and `pointer-events: none`. +**Regla 8 — El estado disabled usa opacidad; nunca cambio de color.** +Aplicar `opacity: 0.4` a todo el componente comunica el estado disabled. Nunca cambies el color del texto, el color del borde ni el fondo a una variante "gris": eso crea una señal semántica falsa y rompe el sistema visual. Acompáñalo siempre con `cursor: not-allowed` y `pointer-events: none`. -**Rule 9 — Gradient borders use `::before` pseudo-element, never `border-image`.** -`border-image` does not work with `border-radius` — the gradient clips to a rectangle, destroying the pill shape. The correct technique uses `::before` absolutely positioned with `inset: -1.5px` and `z-index: -1`, with the gradient as its `background` and `border-radius: inherit`. +**Regla 9 — Los bordes con degradado usan un pseudo-elemento `::before`, nunca `border-image`.** +`border-image` no funciona con `border-radius`: el degradado se recorta como un rectángulo y rompe la forma de píldora. La técnica correcta usa un `::before` posicionado de forma absoluta con `inset: -1.5px` y `z-index: -1`, usando el degradado como `background` y `border-radius: inherit`. -**Rule 10 — Default touch target is 44×44px for interactive elements.** -Buttons and action-style links use a default minimum `height: 44px` from `sm` upward. Nav links: minimum `44px` high area. Dropdown items: `padding: 7px 12px` minimum with 14px font. Component-specific compact/dense size scales may go below 44px only when explicitly approved, documented on the prop/story, implemented on native controls, and still keyboard/focus accessible; use the default scale when touch-first targets are required. Calendar is an approved dense component scale because date grids need compact scanning density. +**Regla 10 — El objetivo táctil predeterminado para elementos interactivos es de 44×44px.** +Los botones y links de acción usan un mínimo predeterminado de `height: 44px` desde `sm` en adelante. Los nav links deben ofrecer al menos un área de `44px` de alto. Los items de dropdown usan como mínimo `padding: 7px 12px` con tipografía de 14px. Las escalas compactas o densas de componentes concretos pueden bajar de 44px solo cuando estén explícitamente aprobadas, documentadas en la prop o la story, implementadas sobre controles nativos y sigan siendo accesibles por teclado y focus; usa la escala predeterminada cuando el caso requiera objetivos touch-first. Calendar es una excepción densa aprobada porque las cuadrículas de fechas necesitan una densidad de escaneo compacta. -**Action size scale — `xs | sm | md | lg`.** -For `Button`, `IconButton`, and Link variants used as actions (`button` / `outlined`), `xs` is the dense compact size: reduce typography, icon size, gap, horizontal padding, and height so it is visibly smaller than `sm`. `Link` `regular` remains inline typography-only, while CTA-style `sm` and above keep the 44px target. +**Escala de tamaño de acción: `xs | sm | md | lg`.** +En `Button`, `IconButton` y las variantes de Link usadas como acciones (`button` / `outlined`), `xs` es el tamaño compacto y denso: reduce tipografía, tamaño de icono, separación, padding horizontal y altura para que se vea claramente más pequeño que `sm`. `Link` `regular` sigue siendo una variante tipográfica inline, mientras que los CTA `sm` y superiores conservan el objetivo de 44px. -**Rule 11 — Never animate layout-forcing properties.** -Do not animate `width`, `height`, `top`, `left`, `margin`, `padding`. These trigger layout reflow on every frame. For position animations use `transform: translateY/translateX`. For size animations use `transform: scale`. +**Regla 11 — No animes propiedades que fuerzan layout.** +No animes `width`, `height`, `top`, `left`, `margin` ni `padding`. Estas propiedades fuerzan reflow en cada frame. Para animaciones de posición usa `transform: translateY/translateX`. Para animaciones de tamaño usa `transform: scale`. -**Rule 12 — Cards that are interactive links use `position: relative; z-index: 1` on content children.** -When a card has a `::before` hover gradient overlay, all content children need `position: relative; z-index: 1` to appear above the overlay. Forgetting this causes text and icons to be covered by the gradient layer on hover. +**Regla 12 — Las cards que funcionan como enlaces interactivos usan `position: relative; z-index: 1` en sus hijos de contenido.** +Cuando una card tiene un overlay de degradado `::before` en hover, todos sus hijos de contenido necesitan `position: relative; z-index: 1` para quedar por encima del overlay. Si se omite, el texto y los iconos quedan tapados por la capa de degradado durante el hover. --- -## 2. State Behavior Reference +## 2. Referencia de comportamiento por estado -| State | What changes | What never changes | +| Estado | Qué cambia | Qué nunca cambia | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| **hover** | `box-shadow` intensifies; gradient shifts lighter (primary); background tint increases (secondary); `border-color` opacity increases; `transform: translateY(-6px)` on cards | Border radius; font weight; text color (stays `#ffffff` on primary/secondary); component dimensions | -| **focus** | `box-shadow` adds 3px ring: `0 0 0 3px rgba(255,0,54,0.40)` dark / `0 0 0 3px rgba(219,20,60,0.35)` light, merged with existing shadow | Gradient; background tint; `border-color`; dimensions | -| **active** | Gradient shifts darker (`#ff1a4b → #cc002b` primary); scale compresses slightly (`transform: scale(0.98)`); glow contracts | Border radius; text color; font weight | -| **disabled** | `opacity: 0.4`; `cursor: not-allowed`; `pointer-events: none` | All colors stay identical to base state — no grey substitution | +| **hover** | `box-shadow` se intensifica; el degradado se aclara (primary); aumenta el tinte de fondo (secondary); sube la opacidad de `border-color`; `transform: translateY(-6px)` en cards | Radio de borde; peso tipográfico; color del texto (se mantiene en `#ffffff` en primary y secondary); dimensiones del componente | +| **focus** | `box-shadow` añade un anillo de 3px: `0 0 0 3px rgba(255,0,54,0.40)` en oscuro / `0 0 0 3px rgba(219,20,60,0.35)` en claro, combinado con la sombra existente | Degradado; tinte de fondo; `border-color`; dimensiones | +| **active** | El degradado se oscurece (`#ff1a4b → #cc002b` en primary); la escala se comprime ligeramente (`transform: scale(0.98)`); el glow se contrae | Radio de borde; color del texto; peso tipográfico | +| **disabled** | `opacity: 0.4`; `cursor: not-allowed`; `pointer-events: none` | Todos los colores se mantienen idénticos al estado base, sin sustitución por grises | --- -## 3. Components +## 3. Componentes ### 3.1 Button — Primary -**Base (dark):** +**Base (oscuro):** ```css background: linear-gradient(135deg, #ff1a4b 0%, #cc0030 100%); @@ -130,7 +130,7 @@ transition: background 0.25s ease; ``` -**Hover (dark):** +**Hover (oscuro):** ```css background: linear-gradient(135deg, #ff3366 0%, #e0003a 100%); @@ -141,7 +141,7 @@ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2); ``` -**Hero variant hover (stronger glow — used in hero / sticky bar):** +**Hover de la variante hero (glow más intenso; se usa en hero / sticky bar):** ```css background: linear-gradient(135deg, #ff3366 0%, #e0003a 100%); @@ -152,7 +152,7 @@ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22); ``` -**Focus (dark):** +**Focus (oscuro):** ```css /* Merged with base box-shadow — add the focus ring as the outermost layer */ @@ -165,7 +165,7 @@ box-shadow: outline: none; ``` -**Active (dark):** +**Active (oscuro):** ```css transform: scale(0.98); @@ -181,14 +181,14 @@ pointer-events: none; /* gradient, glow, and colors remain identical to base — no grey substitution */ ``` -**Light mode:** -No differences for primary button — white text over red gradient passes contrast in both modes. The gradient values and glow remain the same. +**Modo claro:** +No hay diferencias para el botón principal: el texto blanco sobre un degradado rojo pasa el contraste en ambos modos. Los valores de gradiente y el brillo siguen siendo los mismos. --- ### 3.2 Button — Secondary -**Base (dark):** +**Base (oscuro):** ```css background: rgba(255, 0, 54, 0.06); @@ -212,7 +212,7 @@ transition: border-color 0.25s ease; ``` -**Hero / sticky bar base (slightly stronger glow):** +**Base para hero / sticky bar (glow ligeramente más fuerte):** ```css background: rgba(255, 0, 54, 0.06); @@ -223,7 +223,7 @@ box-shadow: inset 0 0 12px rgba(255, 0, 54, 0.05); ``` -**Hover (dark):** +**Hover (oscuro):** ```css background: rgba(255, 0, 54, 0.12); @@ -234,7 +234,7 @@ box-shadow: inset 0 0 16px rgba(255, 0, 54, 0.08); ``` -**Focus (dark):** +**Focus (oscuro):** ```css box-shadow: @@ -245,7 +245,7 @@ box-shadow: outline: none; ``` -**Active (dark):** +**Active (oscuro):** ```css transform: scale(0.98); @@ -260,7 +260,7 @@ cursor: not-allowed; pointer-events: none; ``` -**Light mode:** +**Modo claro:** ```css color: #cc0030; @@ -268,7 +268,7 @@ border-color: rgba(219, 20, 60, 0.5); /* background remains rgba(255,0,54,0.06) */ ``` -**Light mode hover:** +**Hover en modo claro:** ```css color: #8c0b26; @@ -279,7 +279,7 @@ border-color: rgba(219, 20, 60, 0.8); ### 3.3 Button — Ghost / Outlined -Ghost/outlined is implemented as a secondary button without the inset glow. Used in context where the element is inside a card or section with colored background: +La variante ghost/outlined se implementa como un botón secondary sin glow interno. Se usa cuando el elemento vive dentro de una card o una sección con fondo de color: ```css background: transparent; @@ -311,7 +311,7 @@ box-shadow: 0 0 0 3px rgba(255, 0, 54, 0.4); outline: none; ``` -**Note on `releaseLink` inline variant** — same pattern but smaller padding (`0.4rem 1rem`) and used inside cards: +**Nota sobre la variante inline `releaseLink`**: sigue el mismo patrón, pero con un padding más pequeño (`0.4rem 1rem`) y se usa dentro de cards: ```css display: inline-flex; @@ -353,7 +353,7 @@ transition: box-shadow 0.2s ease; ``` -**Placeholder:** +**Marcador de posición:** ```css color: #6a6b6c; @@ -381,7 +381,7 @@ cursor: not-allowed; pointer-events: none; ``` -**Light mode:** +**Modo claro:** ```css background: #ffffff; @@ -389,7 +389,7 @@ border-color: rgba(0, 0, 0, 0.18); color: #0a0a0a; ``` -**Light mode focus:** +**Focus en modo claro:** ```css border-color: rgba(219, 20, 60, 0.5); @@ -400,7 +400,7 @@ box-shadow: 0 0 0 3px rgba(219, 20, 60, 0.15); ### 3.5 Input — Error / Warning / Success States -States change only the `border-color` and `box-shadow`. Background, padding, and font remain identical to default. +Estos estados cambian solo `border-color` y `box-shadow`. El fondo, el padding y la tipografía permanecen idénticos al estado por defecto. **Error:** @@ -423,7 +423,7 @@ border-color: rgba(34, 197, 94, 0.7); /* --color-success: #22c55e */ box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.12); ``` -**Error message text:** +**Texto del mensaje de error:** ```css color: #ff0036; /* dark */ @@ -447,14 +447,14 @@ min-width: 150px; z-index: 100; /* --z-dropdown */ ``` -**Light mode:** +**Modo claro:** ```css background: #ffffff; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); ``` -**Positioning:** the panel appears below the trigger with a small gap. `position: absolute; top: calc(100% + 4px); left: 0`. +**Posicionamiento:** el panel aparece debajo del trigger con un pequeño espacio. `position: absolute; top: calc(100% + 4px); left: 0`. --- @@ -474,28 +474,28 @@ text-decoration: none; display: block; ``` -**Hover (dark):** +**Hover (oscuro):** ```css background: rgba(255, 255, 255, 0.07); color: #ffffff; ``` -**Hover (light):** +**Hover (claro):** ```css background: rgba(0, 0, 0, 0.05); color: #000000; ``` -**Active/selected (dark):** +**Active/seleccionado (oscuro):** ```css color: #ff0036; /* --color-brand-dark */ background: rgba(255, 0, 54, 0.08); ``` -**Active/selected (light):** +**Active/seleccionado (claro):** ```css color: #db143c; /* --color-brand-light */ @@ -506,7 +506,7 @@ background: rgba(219, 20, 60, 0.06); ### 3.8 Badge / Tag -**Brand / "New" — dark:** +**Marca / "Nuevo" — oscuro:** ```css background: #22c55e; /* success */ @@ -521,14 +521,14 @@ display: inline-block; vertical-align: middle; ``` -**"New" — light:** +**"Nuevo" — claro:** ```css background: #16a34a; color: #ffffff; ``` -**Brand pill badge (e.g. version tag, release tag):** +**Badge de marca tipo píldora (por ejemplo, etiqueta de versión o de release):** ```css display: inline-flex; @@ -546,7 +546,7 @@ font-weight: 600; letter-spacing: 0.02em; ``` -**Beta/warning pill badge:** +**Badge tipo píldora beta/de advertencia:** ```css background: color-mix(in srgb, #f59e0b 15%, transparent); @@ -565,7 +565,7 @@ text-transform: uppercase; ### 3.9 Card — Opaque -Used for feature cards, release list items, tech cards, pipeline steps, code blocks, and any structured content. +Se usa para cards de features, elementos de listas de releases, cards tecnológicas, pasos de pipeline, bloques de código y cualquier otro contenido estructurado. ```css background: rgba(255, 255, 255, 0.025); /* visually ~#0B131E in dark context */ @@ -580,7 +580,7 @@ transition: transform 0.3s ease; ``` -**`::before` gradient overlay (always present, triggers on hover):** +**Overlay de degradado en `::before` (siempre presente; se activa en hover):** ```css .card::before { @@ -612,14 +612,14 @@ box-shadow: transform: translateY(-6px); ``` -**Light mode base:** +**Base en modo claro:** ```css background: rgba(0, 0, 0, 0.02); border-color: rgba(0, 0, 0, 0.08); ``` -**Light mode hover:** +**Hover en modo claro:** ```css border-color: #db143c; /* var(--color-brand-light) */ @@ -627,7 +627,7 @@ box-shadow: 0 8px 40px rgba(255, 0, 54, 0.1); /* No transform: translateY in light mode — optional, not consistently applied */ ``` -**Content children inside card must have:** +**Los elementos de contenido dentro de la card deben tener:** ```css position: relative; @@ -638,7 +638,7 @@ z-index: 1; ### 3.10 Card — Frosted -Used only for explicitly floating CardContainer glass surfaces. Normal document-flow cards stay opaque. +Se usa solo para superficies tipo glass de `CardContainer` que flotan explícitamente. Las cards normales en el flujo del documento se mantienen opacas. ```css background: rgba(6, 12, 19, 0.38); /* --color-card-backdrop-dark */ @@ -648,7 +648,7 @@ border: 1px solid rgba(255, 0, 54, 0.5); /* --color-red-tint-border */ border-radius: 8px; /* or 12px for larger panels */ ``` -**Light mode:** +**Modo claro:** ```css background: rgba(255, 255, 255, 0.32); /* --color-card-backdrop-light */ @@ -657,7 +657,7 @@ backdrop-filter: blur(20px); border: 1px solid rgba(255, 0, 54, 0.5); /* --color-red-tint-border */ ``` -**CardContainer backdropBlur levels:** +**Niveles de `backdropBlur` en `CardContainer`:** ```css backdropBlur="sm"; /* --blur-card-sm: blur(10px) */ @@ -665,9 +665,9 @@ backdropBlur="md"; /* --blur-card-md: blur(20px) */ backdropBlur="lg"; /* --blur-card-lg: blur(36px) */ ``` -Use these only when the card is visually floating above other content. Leave `backdropBlur="none"` for normal content cards. +Úsalos solo cuando la card esté flotando visualmente por encima de otro contenido. Deja `backdropBlur="none"` para cards de contenido normal. -**Sticky CTA bar specific (floats below navbar after scroll):** +**Barra CTA fija (flota debajo de la navbar tras hacer scroll):** ```css background: rgba(27, 27, 29, 0.6); @@ -677,13 +677,13 @@ border-bottom: 1px solid rgba(255, 255, 255, 0.06); box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35); ``` -**CRITICAL:** Do NOT combine `backdrop-filter` with a gradient `background`. Choose one. +**CRÍTICO:** NO combines `backdrop-filter` con un `background` con degradado. Elige una sola opción. --- ### 3.11 Card — Tinted (Active) -Used for active sidebar items, active menu items, highlighted feature variants: +Se usa para elementos activos de la barra lateral, elementos activos del menú y variantes de features destacadas: ```css background: rgba(255, 0, 54, 0.08); /* --color-red-tint-low */ @@ -691,7 +691,7 @@ border: 1px solid rgba(255, 0, 54, 0.2); border-radius: 8px; ``` -**Active sidebar link specifically:** +**Enlace activo de la barra lateral:** ```css background: rgba(255, 0, 54, 0.1); /* --color-red-tint-mid */ @@ -701,7 +701,7 @@ border-radius: 8px; /* No additional border on sidebar links */ ``` -**Hover on tinted card:** +**Hover sobre la card tintada:** ```css border-color: rgba(255, 0, 54, 0.38); @@ -729,7 +729,7 @@ top: 0; z-index: 300; /* --z-navbar */ ``` -**Light mode:** +**Modo claro:** ```css background: rgba(255, 255, 255, 0.7); /* --color-navbar-light */ @@ -737,9 +737,9 @@ backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); ``` -**Logo image:** `width: 32px; height: 32px` — explicit size prevents CLS. +**Imagen del logotipo:** `width: 32px; height: 32px`: el tamaño explícito impide CLS. -**Nav links:** +**Enlaces de navegación:** ```css font-size: 0.85rem; @@ -749,11 +749,11 @@ transition: color 0.2s ease; text-decoration: none; ``` -**Nav link hover:** `color: #ffffff;` +**Hover de los enlaces de navegación:** `color: #ffffff;` -**Light mode nav links:** `color: #333333;` → `color: #000000;` hover. +**Enlaces de navegación en modo claro:** `color: #333333;` → `color: #000000;` en hover. -**Mobile sidebar panel:** +**Panel de la barra lateral móvil:** ```css background: rgba(27, 27, 29, 1); @@ -766,7 +766,7 @@ transition: transform 0.25s ease; ``` -**Mobile sidebar — show state:** +**Barra lateral móvil: mostrar estado:** ```css opacity: 1; @@ -775,7 +775,7 @@ z-index: 1000; height: 100dvh; ``` -**Mobile sidebar backdrop:** +**Fondo de la barra lateral móvil:** ```css background: rgba(0, 0, 0, 0.6); @@ -789,7 +789,7 @@ transition: opacity 0.25s ease; ### 3.13 Link — Inline -Links within body text (announcement bar, release notes, inline CTAs): +Enlaces dentro del cuerpo del texto (announcement bar, notas de release, CTA inline): ```css color: #ff4d6d; /* slightly lighter than brand for inline legibility */ @@ -808,9 +808,9 @@ color: #ff8099; border-bottom-color: rgba(255, 128, 153, 0.7); ``` -**Light mode inline link:** same pattern but use `#db143c` → `#c41136` hover. +**Link inline en modo claro:** sigue el mismo patrón, pero usa `#db143c` → `#c41136` en hover. -**Inline CTA link (featureCta — "Learn more →"):** +**Link inline CTA (`featureCta` — "Más información →"):** ```css color: var(--color-primary); /* #ff0036 dark / #db143c light */ @@ -823,7 +823,7 @@ transition: gap 0.2s ease; text-decoration: none; ``` -**Inline CTA hover:** `gap: 0.55rem;` — the arrow slides right. +**Hover del inline CTA:** `gap: 0.55rem;` — la flecha se desplaza hacia la derecha. --- @@ -842,14 +842,14 @@ text-decoration: none; display: block; ``` -**Hover (dark):** +**Hover (oscuro):** ```css background: rgba(255, 255, 255, 0.05); /* --color-white-tint-faint */ color: #ffffff; ``` -**Active (dark):** +**Active (oscuro):** ```css background: rgba(255, 0, 54, 0.1); /* --color-red-tint-mid */ @@ -857,7 +857,7 @@ color: #ff0036; font-weight: 600; ``` -**Mobile sidebar nav link:** +**Enlace de navegación de la barra lateral móvil:** ```css padding: 0.6rem 1rem; @@ -873,9 +873,9 @@ transition: ### 3.15 Modal / Dialog -No existing Modal component in reference codebase. Use the established surface and overlay tokens: +No existe un componente Modal en el código de referencia. Usa los tokens ya definidos para superficie y overlay: -**Backdrop:** +**Fondo:** ```css position: fixed; @@ -908,14 +908,14 @@ transition: transform 0.25s ease; ``` -**Open state:** +**Estado abierto:** ```css opacity: 1; transform: translate(-50%, -50%) scale(1); ``` -**Light mode panel:** +**Panel en modo claro:** ```css background: #ffffff; @@ -925,38 +925,9 @@ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); --- -### 3.16 Drawer +### 3.16 Announcement Bar / Version Banner -Drawer is a Radix Dialog-backed off-canvas dialog. It uses the approved compound anatomy: `Drawer.Trigger`, `Drawer.Content`, `Drawer.Header`, `Drawer.Title`, `Drawer.Description`, `Drawer.Body`, `Drawer.Footer`, and `Drawer.Close`. `Portal`, `Overlay`, and `Backdrop` remain internal to `Drawer.Content`. - -**Accessibility and anatomy:** - -- `Drawer.Title` is required so the dialog has an accessible name. -- `Drawer.Description` is optional and should explain context when the title alone is not enough. -- Built-in icon-only `Drawer.Close` is named `Close drawer`; custom close controls must provide visible text or their own accessible label. -- Header and footer are non-scrolling; `Drawer.Body` is the internal scroll region for long content. - -**Placement and responsive behavior:** - -- `placement="start" | "end" | "top" | "bottom"`; default is `end`. -- `start` and `end` are logical placements. On `md+`, LTR maps start/end to left/right and RTL maps start/end to right/left. -- Below `md`, side placements adapt to effective bottom sheet layout. -- Side sizes reuse `max-w-modal-*`; top, bottom, and mobile bottom layouts use `max-h-drawer-*` utilities based on `--size-drawer-block-viewport`. -- Bottom and mobile-adapted drawers use safe-area padding for footer actions. - -**Dismissal and motion:** - -- `dismissible` controls outside/backdrop dismissal only. -- `closeOnEscape` controls Escape-key dismissal only. -- Explicit close controls remain available for non-dismissible drawers. -- Overlay fades and panel slides by effective placement using `opacity` and `transform`; never use `transition: all`. -- `motion-reduce` removes drawer entrance/exit motion while preserving focus management. - ---- - -### 3.17 Announcement Bar / Version Banner - -**Announcement bar (Docusaurus global bar — full width above navbar):** +**Announcement Bar** (barra global de Docusaurus, a ancho completo sobre la navbar): ```css border-bottom: 1px solid rgba(255, 0, 54, 0.35); @@ -966,7 +937,7 @@ letter-spacing: 0.01em; /* Hidden on mobile: display: none at max-width: 768px */ ``` -**Link inside bar:** +**Link dentro de la barra:** ```css color: #ff4d6d; @@ -978,14 +949,14 @@ transition: border-color 0.2s ease; ``` -**Link hover:** +**Hover del link:** ```css color: #ff8099; border-bottom-color: rgba(255, 128, 153, 0.7); ``` -**Version Banner (custom component — dark strip between bar and page):** +**Version Banner** (componente personalizado: franja oscura entre la barra y la página): ```css background-color: #0d0d0d; @@ -997,15 +968,15 @@ line-height: 1.5; /* Hidden on mobile: display: none at max-width: 768px */ ``` -**Links in version banner:** Same `#ff4d6d` / `#db143c` light mode pattern as inline links. +**Enlaces del version banner:** siguen el mismo patrón `#ff4d6d` / `#db143c` en modo claro que los links inline. --- -## 4. Glow System +## 4. Sistema de resplandor -### 4-Layer Pattern (Button Primary — canonical example) +### Patrón de 4 capas (Button Primary — ejemplo canónico) -The primary button glow has four layers with distinct purposes: +El glow del botón primary tiene cuatro capas, cada una con un propósito distinto: ```css box-shadow: @@ -1027,7 +998,7 @@ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15); ``` -### Hover amplification: +### Amplificación en hover: ```css box-shadow: @@ -1040,22 +1011,22 @@ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2); /* inset: 0.20 vs 0.15 */ ``` -### Decorative glow timing and emphasis +### Temporización y énfasis del glow decorativo -| Element | Default decorative glow behavior | `emphasis="flat"` | +| Elemento | Comportamiento decorativo predeterminado del glow | `emphasis="flat"` | | ----------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | -| Button Primary | **Always-on** — 4-layer glow at rest, amplified on hover | Removes decorative glow, keeps focus ring | -| Button Secondary / Outlined | **Always-on** — soft contained glow at rest, amplified on hover | Removes decorative glow, keeps focus ring | -| IconButton Primary / Secondary / Outlined | Matches button semantics for the same variant family | Removes decorative glow, keeps focus ring | -| CTA Link `button` / `outlined` | Decorative glow by variant contract | Removes decorative glow, keeps focus ring | -| Chip | No decorative glow API; color/variant carries status semantics | N/A — focus/selected accessibility glow remains independent | -| Switch `emphasis="default"` | Decorative glow by emphasis contract | `emphasis="flat"` removes decorative glow, keeps focus ring | -| Feature Card | **Hover-only** — no glow at rest, box-shadow appears on hover | N/A unless a component-specific API is added | -| Nav Badge (GitHub stars) | **Hover-only** — amber ring appears only on hover | N/A unless a component-specific API is added | -| Logo icon (glowing) | **Always-on** — `filter: drop-shadow(0 0 20px rgba(255,0,54,0.4))` | Component-specific decision | -| Inline CTA links | **No glow** — color transition only | No effect | +| Button Primary | **Siempre activo**: glow de 4 capas en reposo, amplificado en hover | Elimina el glow decorativo y mantiene el anillo de focus | +| Button Secondary / Outlined | **Siempre activo**: glow suave y contenido en reposo, amplificado en hover | Elimina el glow decorativo y mantiene el anillo de focus | +| IconButton Primary / Secondary / Outlined | Sigue la misma semántica visual que los botones de la misma familia de variantes | Elimina el glow decorativo y mantiene el anillo de focus | +| CTA Link `button` / `outlined` | Glow decorativo según el contrato de su variante | Elimina el glow decorativo y mantiene el anillo de focus | +| Chip | No tiene API de glow decorativo; el color o la variante cargan la semántica de estado | N/A — el glow de focus/selección de accesibilidad sigue siendo independiente | +| Switch `emphasis="default"` | Glow decorativo según el contrato de énfasis | `emphasis="flat"` elimina el glow decorativo y mantiene el anillo de focus | +| Feature Card | **Solo en hover**: sin glow en reposo; `box-shadow` aparece en hover | N/A salvo que se añada una API específica del componente | +| Nav Badge (estrellas de GitHub) | **Solo en hover**: el anillo ámbar aparece únicamente al pasar el cursor | N/A salvo que se añada una API específica del componente | +| Icono del logo (con glow) | **Siempre activo** — `filter: drop-shadow(0 0 20px rgba(255,0,54,0.4))` | Decisión específica del componente | +| Links inline CTA | **Sin glow**: solo transición de color | Sin efecto | -### Secondary button glow (3-layer, contained): +### Glow del botón Secondary (3 capas, contenido): ```css box-shadow: @@ -1067,19 +1038,19 @@ box-shadow: inset 0 0 10px rgba(255, 0, 54, 0.04); ``` -No tight ring layer — secondary doesn't need a border simulation because it already has a real `border: 1.5px solid`. +No hay una capa de anillo ceñido: secondary no necesita simular un borde porque ya tiene un `border: 1.5px solid` real. --- -## 5. Gradient Border Technique +## 5. Técnica del borde degradado -### Why `border-image` fails with `border-radius` +### Por qué `border-image` falla con `border-radius` -`border-image` replaces the `border` rendering and ignores `border-radius`. A pill button (`border-radius: 9999px`) with `border-image` renders as a rectangle with gradient edge clips at the corners. There is no workaround for this in CSS — `border-image` is fundamentally incompatible with `border-radius`. +`border-image` reemplaza la representación `border` e ignora `border-radius`. Un botón tipo pastilla (`border-radius: 9999px`) con `border-image` se representa como un rectángulo con clips de borde degradados en las esquinas. No existe una solución alternativa para esto en CSS: `border-image` es fundamentalmente incompatible con `border-radius`. -### The `::before` pseudo-element technique +### Técnica con pseudo-elemento `::before` -The gradient border is created by positioning a pseudo-element behind the component that extends 1.5px in every direction using `inset: -1.5px`. The parent has `border: 1.5px solid transparent` and `background-clip: padding-box` to prevent the parent's background from showing through the border area. +El borde con degradado se crea colocando un pseudo-elemento detrás del componente y haciéndolo crecer 1.5px en cada dirección mediante `inset: -1.5px`. El elemento padre usa `border: 1.5px solid transparent` y `background-clip: padding-box` para evitar que el fondo del propio padre se vea a través del área del borde. ```css .gradient-border-component { @@ -1105,11 +1076,11 @@ The gradient border is created by positioning a pseudo-element behind the compon } ``` -### GPU compositing benefit +### Ventaja de composición en GPU -The `::before` gradient is a static painted layer. On hover, we transition only `opacity` on the `::before` (or swap the background with a higher-opacity version). Since `opacity` changes are handled by the GPU compositor — not the main thread — this avoids layout and paint work. Animating `background` directly on a gradient would repaint every frame. +El degradado de `::before` es una capa estática ya pintada. En hover solo se anima `opacity` sobre `::before` (o se sustituye el fondo por una versión con mayor opacidad). Como los cambios de `opacity` los resuelve el compositor de la GPU y no el hilo principal, se evita trabajo de layout y repintado. Animar `background` directamente sobre un degradado obligaría a repintar cada frame. -### Exact gradient values — Secondary button (ghost destello): +### Valores exactos del degradado: botón Secondary (resaltado ghost): ```css /* Tight directional gradient — white flash from top-left, red dominance mid, fades to transparent */ @@ -1121,99 +1092,99 @@ background: linear-gradient( ); ``` -### When to use gradient border +### Cuándo usar un borde con degradado -- Secondary / ghost buttons that need visual weight without solid fill -- Input fields in focus state (transition `::before` opacity from 0 to 1) -- Active cards with accent border -- Never on structural separators, table borders, or layout containers +- Botones secondary o ghost que necesitan peso visual sin relleno sólido +- Campos de input en estado de focus (transición de la opacidad de `::before` de 0 a 1) +- Cards activas con borde acentuado +- Nunca en separadores estructurales, bordes de tablas ni contenedores de layout. --- -## 6. Transition Rules +## 6. Reglas de transición -| Interaction type | Duration | Easing | Properties | +| Tipo de interacción | Duración | Easing | Propiedades | | ------------------------------------------ | --------------------- | -------------------------------- | ------------------------------------------ | -| Button hover (primary/secondary) | 250ms | `ease` | `box-shadow`, `background` | -| Button hover (secondary — includes border) | 250ms | `ease` | `box-shadow`, `background`, `border-color` | -| Card hover | 300ms | `ease` | `border-color`, `box-shadow`, `transform` | -| Card `::before` gradient reveal | 300ms | implicit `ease` | `opacity` | -| Dropdown / menu item hover | 150ms | `ease` | `background`, `color` | -| Inline link hover | 200ms | `ease` | `color`, `border-color` | -| Locale switcher / nav badge hover | 200ms | `ease` | `border-color`, `box-shadow` | -| GitHub stars badge parts | 200ms | `ease` | `background`, `color` | -| Modal / sidebar entrance | 250ms | `ease` | `opacity`, `transform` | -| Sticky bar entrance | 350ms | `ease` | `opacity`, `transform` | -| Scroll fade-in (IntersectionObserver) | 560ms | `cubic-bezier(0.2, 0.8, 0.2, 1)` | `opacity`, `transform` | -| Pipeline hover expand | 400–450ms | `cubic-bezier(0.4, 0, 0.2, 1)` | `flex`, `max-width` | -| Pipeline right panel fade-in | 200ms (delayed 450ms) | `ease` | `opacity` | -| Nav link color | 200ms | `ease` | `color` | - -**Rule:** NEVER use `transition: all`. Always enumerate exact properties. - -**Permitted animatable properties:** `opacity`, `transform`, `box-shadow`, `background-color`, `border-color`, `color`, `gap`, `flex`, `max-width` (for expand patterns), `filter` (for icon glows). - -**NEVER animate:** `width`, `height`, `top`, `right`, `bottom`, `left`, `margin`, `padding` — these trigger layout reflow. +| Hover de Button (primary/secondary) | 250ms | `ease` | `box-shadow`, `background` | +| Hover de Button (secondary — incluye borde) | 250ms | `ease` | `box-shadow`, `background`, `border-color` | +| Hover de Card | 300ms | `ease` | `border-color`, `box-shadow`, `transform` | +| Revelado del degradado `::before` en Card | 300ms | `ease` implícito | `opacity` | +| Hover de Dropdown / item de menú | 150ms | `ease` | `background`, `color` | +| Hover de link inline | 200ms | `ease` | `color`, `border-color` | +| Hover de locale switcher / nav badge | 200ms | `ease` | `border-color`, `box-shadow` | +| Partes del badge de estrellas de GitHub | 200ms | `ease` | `background`, `color` | +| Entrada de modal / barra lateral | 250ms | `ease` | `opacity`, `transform` | +| Entrada de barra sticky | 350ms | `ease` | `opacity`, `transform` | +| Scroll fade-in (`IntersectionObserver`) | 560ms | `cubic-bezier(0.2, 0.8, 0.2, 1)` | `opacity`, `transform` | +| Expansión hover de pipeline | 400–450ms | `cubic-bezier(0.4, 0, 0.2, 1)` | `flex`, `max-width` | +| Fade-in del panel derecho de pipeline | 200ms (retraso de 450ms) | `ease` | `opacity` | +| Color de enlaces de navegación | 200ms | `ease` | `color` | + +**Regla:** NO uses nunca `transition: all`. Enumera siempre las propiedades exactas. + +**Propiedades animables permitidas:** `opacity`, `transform`, `box-shadow`, `background-color`, `border-color`, `color`, `gap`, `flex`, `max-width` (para patrones de expansión), `filter` (para brillos de iconos). + +**No animes nunca:** `width`, `height`, `top`, `right`, `bottom`, `left`, `margin`, `padding`; todas ellas fuerzan reflow. --- -## 7. Accessibility Checklist +## 7. Lista de verificación de accesibilidad -### Buttons +### Botones -- [ ] Minimum height `44px` -- [ ] Focus ring: `box-shadow: 0 0 0 3px rgba(255, 0, 54, 0.40)` dark / `0 0 0 3px rgba(219, 20, 60, 0.35)` light -- [ ] Focus ring merged with existing `box-shadow` — never replaces it -- [ ] Focus ring never hidden: no `outline: none` without alternative -- [ ] Disabled: `opacity: 0.4`, `cursor: not-allowed`, `pointer-events: none` — no color change -- [ ] Primary: white `#ffffff` text over red gradient — contrast passes in both modes -- [ ] Secondary dark: `color: #ffffff` over `rgba(255,0,54,0.06)` — visually dark background context; border defines the affordance -- [ ] Secondary light: `color: #cc0030` — NEVER `#ff0036` in light mode (insufficient contrast over white) -- [ ] Touch target remains at least `44px` for default action sizes; explicitly approved compact/dense variants may use reduced visual targets when documented and keyboard/focus accessible -- [ ] `role="button"` if implemented as non-`