@pennyfarthing/core 11.0.0 → 11.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -23
- package/package.json +1 -1
- package/packages/core/dist/cli/utils/010-detect-remove-old-packages.test.d.ts +20 -0
- package/packages/core/dist/cli/utils/010-detect-remove-old-packages.test.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/010-detect-remove-old-packages.test.js +278 -0
- package/packages/core/dist/cli/utils/010-detect-remove-old-packages.test.js.map +1 -0
- package/packages/core/dist/cli/utils/constants.d.ts +8 -2
- package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/constants.js +4 -1
- package/packages/core/dist/cli/utils/constants.js.map +1 -1
- package/packages/core/dist/cli/utils/constants.test.d.ts +10 -0
- package/packages/core/dist/cli/utils/constants.test.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/constants.test.js +38 -0
- package/packages/core/dist/cli/utils/constants.test.js.map +1 -0
- package/packages/core/dist/consultation/consultation-protocol.d.ts +139 -0
- package/packages/core/dist/consultation/consultation-protocol.d.ts.map +1 -0
- package/packages/core/dist/consultation/consultation-protocol.js +178 -0
- package/packages/core/dist/consultation/consultation-protocol.js.map +1 -0
- package/packages/core/dist/consultation/consultation-protocol.test.d.ts +20 -0
- package/packages/core/dist/consultation/consultation-protocol.test.d.ts.map +1 -0
- package/packages/core/dist/consultation/consultation-protocol.test.js +474 -0
- package/packages/core/dist/consultation/consultation-protocol.test.js.map +1 -0
- package/packages/core/dist/consultation/dialogue-manager.d.ts +75 -0
- package/packages/core/dist/consultation/dialogue-manager.d.ts.map +1 -0
- package/packages/core/dist/consultation/dialogue-manager.js +334 -0
- package/packages/core/dist/consultation/dialogue-manager.js.map +1 -0
- package/packages/core/dist/consultation/dialogue-manager.test.d.ts +19 -0
- package/packages/core/dist/consultation/dialogue-manager.test.d.ts.map +1 -0
- package/packages/core/dist/consultation/dialogue-manager.test.js +444 -0
- package/packages/core/dist/consultation/dialogue-manager.test.js.map +1 -0
- package/packages/core/dist/public/js/react/react.js +3 -3
- package/packages/core/dist/scripts/theme-detail.test.d.ts +10 -0
- package/packages/core/dist/scripts/theme-detail.test.js +199 -0
- package/packages/core/dist/server/api/git.d.ts +13 -1
- package/packages/core/dist/server/api/git.d.ts.map +1 -1
- package/packages/core/dist/server/api/git.js +53 -34
- package/packages/core/dist/server/api/git.js.map +1 -1
- package/packages/core/dist/server/api/health-score.d.ts.map +1 -1
- package/packages/core/dist/server/api/health-score.js +25 -1
- package/packages/core/dist/server/api/health-score.js.map +1 -1
- package/packages/core/dist/server/api/settings.d.ts.map +1 -1
- package/packages/core/dist/server/api/settings.js +63 -1
- package/packages/core/dist/server/api/settings.js.map +1 -1
- package/packages/core/dist/server/api/theme-agents.d.ts.map +1 -1
- package/packages/core/dist/server/api/theme-agents.js +61 -0
- package/packages/core/dist/server/api/theme-agents.js.map +1 -1
- package/packages/core/dist/server/server.d.ts.map +1 -1
- package/packages/core/dist/server/server.js +17 -12
- package/packages/core/dist/server/server.js.map +1 -1
- package/packages/core/dist/shared/skill-search.test.js +2 -2
- package/packages/core/dist/workflow/gate-file-validation.d.ts +49 -0
- package/packages/core/dist/workflow/gate-file-validation.d.ts.map +1 -0
- package/packages/core/dist/workflow/gate-file-validation.js +157 -0
- package/packages/core/dist/workflow/gate-file-validation.js.map +1 -0
- package/packages/core/dist/workflow/gate-file-validation.test.d.ts +19 -0
- package/packages/core/dist/workflow/gate-file-validation.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/gate-file-validation.test.js +536 -0
- package/packages/core/dist/workflow/gate-file-validation.test.js.map +1 -0
- package/packages/core/dist/workflow/gate-schema-validation.test.d.ts +14 -0
- package/packages/core/dist/workflow/gate-schema-validation.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/gate-schema-validation.test.js +339 -0
- package/packages/core/dist/workflow/gate-schema-validation.test.js.map +1 -0
- package/packages/core/dist/workflow/handoff.js +2 -2
- package/packages/core/dist/workflow/handoff.js.map +1 -1
- package/packages/core/dist/workflow/handoff.test.js +16 -0
- package/packages/core/dist/workflow/handoff.test.js.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.d.ts +4 -2
- package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.js +43 -8
- package/packages/core/dist/workflow/workflow-schema.js.map +1 -1
- package/pennyfarthing-dist/agents/README.md +6 -14
- package/pennyfarthing-dist/agents/architect.md +43 -29
- package/pennyfarthing-dist/agents/ba.md +30 -29
- package/pennyfarthing-dist/agents/dev.md +32 -43
- package/pennyfarthing-dist/agents/devops.md +57 -21
- package/pennyfarthing-dist/agents/orchestrator.md +3 -10
- package/pennyfarthing-dist/agents/pm.md +45 -31
- package/pennyfarthing-dist/agents/reviewer.md +20 -66
- package/pennyfarthing-dist/agents/sm-setup.md +2 -2
- package/pennyfarthing-dist/agents/sm.md +8 -30
- package/pennyfarthing-dist/agents/tea.md +25 -41
- package/pennyfarthing-dist/agents/tech-writer.md +33 -90
- package/pennyfarthing-dist/agents/ux-designer.md +39 -39
- package/pennyfarthing-dist/commands/benchmark-control.md +8 -64
- package/pennyfarthing-dist/commands/benchmark.md +8 -480
- package/pennyfarthing-dist/commands/job-fair.md +8 -97
- package/pennyfarthing-dist/commands/pf-benchmark-control.md +70 -0
- package/pennyfarthing-dist/commands/pf-benchmark.md +486 -0
- package/pennyfarthing-dist/commands/pf-chore.md +4 -4
- package/pennyfarthing-dist/commands/pf-ci.md +40 -0
- package/pennyfarthing-dist/commands/pf-close-epic.md +9 -27
- package/pennyfarthing-dist/commands/pf-continue-session.md +9 -213
- package/pennyfarthing-dist/commands/pf-create-branches-from-story.md +11 -353
- package/pennyfarthing-dist/commands/pf-docs.md +28 -0
- package/pennyfarthing-dist/commands/pf-epic.md +67 -0
- package/pennyfarthing-dist/commands/pf-git-cleanup.md +11 -52
- package/pennyfarthing-dist/commands/pf-git.md +75 -0
- package/pennyfarthing-dist/commands/pf-help.md +110 -128
- package/pennyfarthing-dist/commands/pf-job-fair.md +102 -0
- package/pennyfarthing-dist/commands/pf-new-work.md +9 -18
- package/pennyfarthing-dist/commands/pf-parallel-work.md +6 -66
- package/pennyfarthing-dist/commands/pf-release.md +11 -76
- package/pennyfarthing-dist/commands/pf-repo-status.md +11 -44
- package/pennyfarthing-dist/commands/pf-run-ci.md +8 -111
- package/pennyfarthing-dist/commands/pf-session.md +51 -0
- package/pennyfarthing-dist/commands/pf-solo.md +447 -0
- package/pennyfarthing-dist/commands/pf-sprint-planning.md +8 -104
- package/pennyfarthing-dist/commands/pf-standalone.md +1 -1
- package/pennyfarthing-dist/commands/pf-start-epic.md +9 -163
- package/pennyfarthing-dist/commands/pf-sync-epic-to-jira.md +8 -179
- package/pennyfarthing-dist/commands/pf-sync-work-with-sprint.md +8 -368
- package/pennyfarthing-dist/commands/pf-update-domain-docs.md +8 -78
- package/pennyfarthing-dist/commands/solo.md +8 -442
- package/pennyfarthing-dist/guides/agent-behavior.md +13 -13
- package/pennyfarthing-dist/guides/agent-coordination.md +7 -7
- package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +6 -5
- package/pennyfarthing-dist/guides/bikerack.md +128 -0
- package/pennyfarthing-dist/guides/brownfield-tools.md +133 -0
- package/pennyfarthing-dist/guides/command-tag-taxonomy.md +2 -2
- package/pennyfarthing-dist/guides/gate-schema.md +227 -0
- package/pennyfarthing-dist/guides/gates.md +120 -0
- package/pennyfarthing-dist/guides/handoff-cli.md +116 -0
- package/pennyfarthing-dist/guides/hooks.md +86 -4
- package/pennyfarthing-dist/guides/output-styles.md +65 -0
- package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +5 -5
- package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +4 -4
- package/pennyfarthing-dist/guides/prompt-patterns.md +5 -5
- package/pennyfarthing-dist/guides/reflector.md +4 -4
- package/pennyfarthing-dist/guides/session-artifacts.md +1 -1
- package/pennyfarthing-dist/guides/skill-schema.md +1 -1
- package/pennyfarthing-dist/guides/tandem-protocol.md +13 -1
- package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
- package/pennyfarthing-dist/guides/xml-tags.md +5 -4
- package/pennyfarthing-dist/personas/themes/hogans-heroes.yaml +11 -22
- package/pennyfarthing-dist/personas/themes/stephen-king.yaml +13 -24
- package/pennyfarthing-dist/scripts/core/dialogue-manager.sh +322 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +1 -1
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +19 -14
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.py +191 -57
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +26 -10
- package/pennyfarthing-dist/skills/pf-changelog/SKILL.md +4 -4
- package/pennyfarthing-dist/skills/pf-sprint/skill.md +1 -1
- package/pennyfarthing-dist/skills/skill-registry.schema.json +4 -0
- package/pennyfarthing-dist/skills/skill-registry.yaml +5 -0
- package/pennyfarthing-dist/workflows/2party-tdd.yaml +11 -0
- package/pennyfarthing-dist/workflows/agent-docs.yaml +2 -0
- package/pennyfarthing-dist/workflows/bdd-tandem.yaml +4 -0
- package/pennyfarthing-dist/workflows/bdd.yaml +4 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +1 -1
- package/pennyfarthing-dist/workflows/tdd-tandem.yaml +3 -0
- package/pennyfarthing-dist/workflows/tdd.yaml +3 -0
- package/pennyfarthing-dist/workflows/trivial.yaml +2 -0
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/cli.py +10 -11
- package/pennyfarthing_scripts/bikerack/debug_panel.py +218 -0
- package/pennyfarthing_scripts/bikerack/diffs_panel.py +203 -27
- package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/cli.py +114 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/epic/__init__.py +0 -0
- package/pennyfarthing_scripts/epic/cli.py +64 -0
- package/pennyfarthing_scripts/gate/__init__.py +1 -0
- package/pennyfarthing_scripts/gate/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/gate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/gate/__pycache__/validate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/gate/cli.py +56 -0
- package/pennyfarthing_scripts/gate/validate.py +266 -0
- package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git_group/__init__.py +0 -0
- package/pennyfarthing_scripts/git_group/cli.py +100 -0
- package/pennyfarthing_scripts/handoff/__init__.py +1 -0
- package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/gate_file.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/gate_runner.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/cli.py +120 -0
- package/pennyfarthing_scripts/handoff/complete_phase.py +155 -0
- package/pennyfarthing_scripts/handoff/gate_file.py +105 -0
- package/pennyfarthing_scripts/handoff/gate_runner.py +152 -0
- package/pennyfarthing_scripts/handoff/marker.py +109 -0
- package/pennyfarthing_scripts/handoff/resolve_gate.py +152 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/version_sentinel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/workflow.py +39 -0
- package/pennyfarthing_scripts/session/__init__.py +0 -0
- package/pennyfarthing_scripts/session/cli.py +87 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/import_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/story_finish.py +14 -0
- package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_108_2_remove_handoff_fallback.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_archive_epic.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bc.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_cli_normalization.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_epic_shard_validation.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_gate_file_resolution.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_gate_runner.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_resolve_gate_file_field.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_panel.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_topology_loader.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_version_sentinel.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/test_108_1_gate_migration.py +540 -0
- package/pennyfarthing_scripts/tests/test_108_2_remove_handoff_fallback.py +339 -0
- package/pennyfarthing_scripts/tests/test_confidence_sm_evaluation.py +253 -0
- package/pennyfarthing_scripts/tests/test_confidence_sm_gate.py +315 -0
- package/pennyfarthing_scripts/tests/test_gate_file_resolution.py +341 -0
- package/pennyfarthing_scripts/tests/test_gate_runner.py +620 -0
- package/pennyfarthing_scripts/tests/test_handoff_cli.py +929 -0
- package/pennyfarthing_scripts/tests/test_handoff_e2e.py +454 -0
- package/pennyfarthing_scripts/tests/test_resolve_gate_file_field.py +464 -0
- package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/agent.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/schema.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/skill_command.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/sprint.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/skill_command.py +200 -0
- package/pennyfarthing_scripts/validate/adapters/workflow.py +64 -0
- package/pennyfarthing_scripts/validate/cli.py +15 -4
- package/packages/core/dist/scripts/benchmark-integration.d.ts +0 -182
- package/packages/core/dist/scripts/benchmark-integration.d.ts.map +0 -1
- package/packages/core/dist/scripts/benchmark-integration.js +0 -691
- package/packages/core/dist/scripts/benchmark-integration.js.map +0 -1
- package/packages/core/dist/scripts/job-fair-aggregator.d.ts +0 -150
- package/packages/core/dist/scripts/job-fair-aggregator.d.ts.map +0 -1
- package/packages/core/dist/scripts/job-fair-aggregator.js +0 -547
- package/packages/core/dist/scripts/job-fair-aggregator.js.map +0 -1
- package/pennyfarthing-dist/agents/handoff.md +0 -250
- package/pennyfarthing-dist/agents/sm-handoff.md +0 -152
- package/pennyfarthing-dist/scripts/core/handoff-marker.sh +0 -112
- package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
"""Tests for gate.file field in resolve_gate — Story 106-3.
|
|
2
|
+
|
|
3
|
+
Epic: 106 (Gate Files & First Migration)
|
|
4
|
+
Story: 106-3 — Workflow YAML gate.file integration
|
|
5
|
+
|
|
6
|
+
Tests the gate.file field support in resolve_gate():
|
|
7
|
+
- Schema extension: gate.file extracted from workflow YAML
|
|
8
|
+
- Backward compatibility: gate.type-only workflows unchanged
|
|
9
|
+
- TDD workflow migration: green phase has file: gates/tests-pass
|
|
10
|
+
|
|
11
|
+
Acceptance Criteria:
|
|
12
|
+
- [AC1] resolve-gate.py reads gate.file field from workflow YAML phases
|
|
13
|
+
- [AC1] gate.file takes precedence over gate.type when both present
|
|
14
|
+
- [AC1] Returns gate_file: null when only gate.type exists
|
|
15
|
+
- [AC2] Workflows with only gate.type continue to work unchanged
|
|
16
|
+
- [AC2] Existing gate type logic remains functional
|
|
17
|
+
- [AC2] No breaking changes to resolve-gate API
|
|
18
|
+
- [AC3] Green phase in tdd.yaml has file: gates/tests-pass and type: tests_pass
|
|
19
|
+
- [AC3] Other phases remain unchanged (backward compat period)
|
|
20
|
+
- [AC3] File path is relative: gates/tests-pass (not absolute)
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import textwrap
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
import pytest
|
|
29
|
+
import yaml
|
|
30
|
+
|
|
31
|
+
from pennyfarthing_scripts.handoff.resolve_gate import resolve_gate
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
# Fixtures: Workflow YAML data with gate.file support
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
WORKFLOW_WITH_FILE_AND_TYPE = {
|
|
38
|
+
"workflow": {
|
|
39
|
+
"name": "tdd",
|
|
40
|
+
"phases": [
|
|
41
|
+
{"name": "setup", "agent": "sm"},
|
|
42
|
+
{"name": "red", "agent": "tea", "gate": {"type": "tests_fail"}},
|
|
43
|
+
{
|
|
44
|
+
"name": "green",
|
|
45
|
+
"agent": "dev",
|
|
46
|
+
"gate": {
|
|
47
|
+
"file": "gates/tests-pass",
|
|
48
|
+
"type": "tests_pass",
|
|
49
|
+
"condition": "All tests passing, no skipped tests",
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{"name": "review", "agent": "reviewer", "gate": {"type": "approval"}},
|
|
53
|
+
{"name": "finish", "agent": "sm"},
|
|
54
|
+
],
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
WORKFLOW_WITH_FILE_ONLY = {
|
|
59
|
+
"workflow": {
|
|
60
|
+
"name": "file-only",
|
|
61
|
+
"phases": [
|
|
62
|
+
{"name": "setup", "agent": "sm"},
|
|
63
|
+
{
|
|
64
|
+
"name": "green",
|
|
65
|
+
"agent": "dev",
|
|
66
|
+
"gate": {
|
|
67
|
+
"file": "gates/tests-pass",
|
|
68
|
+
"condition": "All tests passing",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{"name": "finish", "agent": "sm"},
|
|
72
|
+
],
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
WORKFLOW_WITH_TYPE_ONLY = {
|
|
77
|
+
"workflow": {
|
|
78
|
+
"name": "legacy",
|
|
79
|
+
"phases": [
|
|
80
|
+
{"name": "setup", "agent": "sm"},
|
|
81
|
+
{
|
|
82
|
+
"name": "green",
|
|
83
|
+
"agent": "dev",
|
|
84
|
+
"gate": {"type": "tests_pass"},
|
|
85
|
+
},
|
|
86
|
+
{"name": "finish", "agent": "sm"},
|
|
87
|
+
],
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
SESSION_WITH_ASSESSMENT = textwrap.dedent("""\
|
|
92
|
+
# Story 106-3: Workflow YAML gate.file integration
|
|
93
|
+
|
|
94
|
+
**Story ID:** 106-3
|
|
95
|
+
**Workflow:** tdd
|
|
96
|
+
**Phase:** green
|
|
97
|
+
**Phase Started:** 2026-02-15T10:00:00Z
|
|
98
|
+
|
|
99
|
+
## TEA Assessment
|
|
100
|
+
|
|
101
|
+
**Tests Written:** 5 tests
|
|
102
|
+
**Status:** RED confirmed
|
|
103
|
+
|
|
104
|
+
## Workflow Tracking
|
|
105
|
+
|
|
106
|
+
**Phase:** green
|
|
107
|
+
**Phase Started:** 2026-02-15T10:00:00Z
|
|
108
|
+
|
|
109
|
+
### Phase History
|
|
110
|
+
| Phase | Started | Ended | Duration |
|
|
111
|
+
|-------|---------|-------|----------|
|
|
112
|
+
| green | 2026-02-15T10:00:00Z | - | - |
|
|
113
|
+
|
|
114
|
+
### Handoff History
|
|
115
|
+
| From | To | Gate | Status | Timestamp |
|
|
116
|
+
|------|-----|------|--------|-----------|
|
|
117
|
+
""")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# ---------------------------------------------------------------------------
|
|
121
|
+
# Fixtures: Project structure
|
|
122
|
+
# ---------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@pytest.fixture
|
|
126
|
+
def project(tmp_path: Path) -> Path:
|
|
127
|
+
"""Create a minimal project structure with workflow YAMLs."""
|
|
128
|
+
workflows_dir = tmp_path / ".pennyfarthing" / "workflows"
|
|
129
|
+
workflows_dir.mkdir(parents=True)
|
|
130
|
+
|
|
131
|
+
for name, data in [
|
|
132
|
+
("tdd", WORKFLOW_WITH_FILE_AND_TYPE),
|
|
133
|
+
("file-only", WORKFLOW_WITH_FILE_ONLY),
|
|
134
|
+
("legacy", WORKFLOW_WITH_TYPE_ONLY),
|
|
135
|
+
]:
|
|
136
|
+
(workflows_dir / f"{name}.yaml").write_text(
|
|
137
|
+
yaml.dump(data, default_flow_style=False)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
(tmp_path / ".session").mkdir()
|
|
141
|
+
session_file = tmp_path / ".session" / "106-3-session.md"
|
|
142
|
+
session_file.write_text(SESSION_WITH_ASSESSMENT)
|
|
143
|
+
return tmp_path
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# ===========================================================================
|
|
147
|
+
# AC1: Schema Extension — gate.file extracted from workflow YAML
|
|
148
|
+
# ===========================================================================
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class TestResolveGateFilePresent:
|
|
152
|
+
"""AC1: resolve_gate returns gate_file when gate.file is in workflow YAML."""
|
|
153
|
+
|
|
154
|
+
def test_gate_file_populated_when_file_in_yaml(
|
|
155
|
+
self, project: Path
|
|
156
|
+
) -> None:
|
|
157
|
+
"""AC1: gate_file should be 'gates/tests-pass' when file field exists."""
|
|
158
|
+
result = resolve_gate("106-3", "tdd", "green", project_root=project)
|
|
159
|
+
assert result["gate_file"] == "gates/tests-pass"
|
|
160
|
+
|
|
161
|
+
def test_gate_type_still_populated_with_file(
|
|
162
|
+
self, project: Path
|
|
163
|
+
) -> None:
|
|
164
|
+
"""AC1: gate_type should still be 'tests_pass' when both file and type exist."""
|
|
165
|
+
result = resolve_gate("106-3", "tdd", "green", project_root=project)
|
|
166
|
+
assert result["gate_type"] == "tests_pass"
|
|
167
|
+
|
|
168
|
+
def test_both_fields_present_in_result(
|
|
169
|
+
self, project: Path
|
|
170
|
+
) -> None:
|
|
171
|
+
"""AC1: Both gate_file and gate_type should be non-None when both are in YAML."""
|
|
172
|
+
result = resolve_gate("106-3", "tdd", "green", project_root=project)
|
|
173
|
+
assert result["gate_file"] is not None
|
|
174
|
+
assert result["gate_type"] is not None
|
|
175
|
+
|
|
176
|
+
def test_status_still_ready_with_file(
|
|
177
|
+
self, project: Path
|
|
178
|
+
) -> None:
|
|
179
|
+
"""AC1: Status should still be 'ready' when assessment exists and gate.file is present."""
|
|
180
|
+
result = resolve_gate("106-3", "tdd", "green", project_root=project)
|
|
181
|
+
assert result["status"] == "ready"
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class TestResolveGateFileOnly:
|
|
185
|
+
"""AC1: resolve_gate handles gate with file but no type."""
|
|
186
|
+
|
|
187
|
+
def test_gate_file_populated_without_type(
|
|
188
|
+
self, project: Path
|
|
189
|
+
) -> None:
|
|
190
|
+
"""AC1: gate_file should be populated when only file exists (no type)."""
|
|
191
|
+
result = resolve_gate(
|
|
192
|
+
"106-3", "file-only", "green", project_root=project
|
|
193
|
+
)
|
|
194
|
+
assert result["gate_file"] == "gates/tests-pass"
|
|
195
|
+
|
|
196
|
+
def test_gate_type_null_when_only_file(
|
|
197
|
+
self, project: Path
|
|
198
|
+
) -> None:
|
|
199
|
+
"""AC1: gate_type should be None when only file is in gate."""
|
|
200
|
+
result = resolve_gate(
|
|
201
|
+
"106-3", "file-only", "green", project_root=project
|
|
202
|
+
)
|
|
203
|
+
assert result["gate_type"] is None
|
|
204
|
+
|
|
205
|
+
def test_status_skip_when_no_type_and_file_only(
|
|
206
|
+
self, project: Path
|
|
207
|
+
) -> None:
|
|
208
|
+
"""AC1: gate with file-only and no type → status depends on gate_type logic.
|
|
209
|
+
|
|
210
|
+
Current resolve_gate checks gate_type for skip logic:
|
|
211
|
+
- gate_type == 'manual' → skip
|
|
212
|
+
- gate_type is None → skip
|
|
213
|
+
So file-only gates (no type) currently get 'skip' status.
|
|
214
|
+
This is expected during migration — consumers check gate_file separately.
|
|
215
|
+
"""
|
|
216
|
+
result = resolve_gate(
|
|
217
|
+
"106-3", "file-only", "green", project_root=project
|
|
218
|
+
)
|
|
219
|
+
assert result["status"] == "skip"
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# ===========================================================================
|
|
223
|
+
# AC1: gate_file null when only gate.type exists
|
|
224
|
+
# ===========================================================================
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class TestResolveGateTypeOnlyReturnsNullFile:
|
|
228
|
+
"""AC1: gate_file is None when workflow only has gate.type."""
|
|
229
|
+
|
|
230
|
+
def test_gate_file_null_for_type_only(
|
|
231
|
+
self, project: Path
|
|
232
|
+
) -> None:
|
|
233
|
+
"""AC1: gate_file should be None when only gate.type exists."""
|
|
234
|
+
result = resolve_gate(
|
|
235
|
+
"106-3", "legacy", "green", project_root=project
|
|
236
|
+
)
|
|
237
|
+
assert result["gate_file"] is None
|
|
238
|
+
|
|
239
|
+
def test_gate_type_populated_for_type_only(
|
|
240
|
+
self, project: Path
|
|
241
|
+
) -> None:
|
|
242
|
+
"""AC1: gate_type should be 'tests_pass' for type-only gate."""
|
|
243
|
+
result = resolve_gate(
|
|
244
|
+
"106-3", "legacy", "green", project_root=project
|
|
245
|
+
)
|
|
246
|
+
assert result["gate_type"] == "tests_pass"
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# ===========================================================================
|
|
250
|
+
# AC2: Backward Compatibility
|
|
251
|
+
# ===========================================================================
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class TestResolveGateBackwardCompat:
|
|
255
|
+
"""AC2: Workflows with only gate.type continue to work unchanged."""
|
|
256
|
+
|
|
257
|
+
def test_legacy_workflow_status_ready(
|
|
258
|
+
self, project: Path
|
|
259
|
+
) -> None:
|
|
260
|
+
"""AC2: Legacy type-only workflow should return 'ready' with assessment."""
|
|
261
|
+
result = resolve_gate(
|
|
262
|
+
"106-3", "legacy", "green", project_root=project
|
|
263
|
+
)
|
|
264
|
+
assert result["status"] == "ready"
|
|
265
|
+
|
|
266
|
+
def test_legacy_workflow_next_agent(
|
|
267
|
+
self, project: Path
|
|
268
|
+
) -> None:
|
|
269
|
+
"""AC2: Legacy workflow should still resolve next_agent correctly."""
|
|
270
|
+
result = resolve_gate(
|
|
271
|
+
"106-3", "legacy", "green", project_root=project
|
|
272
|
+
)
|
|
273
|
+
assert result["next_agent"] == "sm"
|
|
274
|
+
|
|
275
|
+
def test_legacy_workflow_next_phase(
|
|
276
|
+
self, project: Path
|
|
277
|
+
) -> None:
|
|
278
|
+
"""AC2: Legacy workflow should still resolve next_phase correctly."""
|
|
279
|
+
result = resolve_gate(
|
|
280
|
+
"106-3", "legacy", "green", project_root=project
|
|
281
|
+
)
|
|
282
|
+
assert result["next_phase"] == "finish"
|
|
283
|
+
|
|
284
|
+
def test_resolve_result_contract_unchanged(
|
|
285
|
+
self, project: Path
|
|
286
|
+
) -> None:
|
|
287
|
+
"""AC2: RESOLVE_RESULT still has all 7 required fields."""
|
|
288
|
+
result = resolve_gate(
|
|
289
|
+
"106-3", "legacy", "green", project_root=project
|
|
290
|
+
)
|
|
291
|
+
required_fields = [
|
|
292
|
+
"status",
|
|
293
|
+
"gate_type",
|
|
294
|
+
"gate_file",
|
|
295
|
+
"next_agent",
|
|
296
|
+
"next_phase",
|
|
297
|
+
"assessment_found",
|
|
298
|
+
"error",
|
|
299
|
+
]
|
|
300
|
+
for field in required_fields:
|
|
301
|
+
assert field in result, f"Missing field: {field}"
|
|
302
|
+
|
|
303
|
+
def test_red_phase_type_only_unaffected(
|
|
304
|
+
self, project: Path
|
|
305
|
+
) -> None:
|
|
306
|
+
"""AC2: TDD red phase (type-only, no file) still works correctly."""
|
|
307
|
+
result = resolve_gate("106-3", "tdd", "red", project_root=project)
|
|
308
|
+
assert result["gate_type"] == "tests_fail"
|
|
309
|
+
assert result["gate_file"] is None
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
# ===========================================================================
|
|
313
|
+
# AC3: TDD Workflow Migration — verify actual tdd.yaml
|
|
314
|
+
# ===========================================================================
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class TestTddWorkflowMigration:
|
|
318
|
+
"""AC3: TDD workflow green phase has file: gates/tests-pass.
|
|
319
|
+
|
|
320
|
+
These tests read the ACTUAL tdd.yaml from the project to verify
|
|
321
|
+
the migration has been applied. They will FAIL until the Dev
|
|
322
|
+
updates tdd.yaml.
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
@pytest.fixture
|
|
326
|
+
def tdd_yaml(self) -> dict:
|
|
327
|
+
"""Load the actual tdd.yaml from pennyfarthing-dist."""
|
|
328
|
+
tdd_path = (
|
|
329
|
+
Path(__file__).resolve().parents[2]
|
|
330
|
+
/ "pennyfarthing-dist"
|
|
331
|
+
/ "workflows"
|
|
332
|
+
/ "tdd.yaml"
|
|
333
|
+
)
|
|
334
|
+
assert tdd_path.exists(), f"tdd.yaml not found at {tdd_path}"
|
|
335
|
+
return yaml.safe_load(tdd_path.read_text())
|
|
336
|
+
|
|
337
|
+
def _get_phase(self, tdd_yaml: dict, name: str) -> dict:
|
|
338
|
+
"""Get a phase by name from the workflow."""
|
|
339
|
+
for phase in tdd_yaml["workflow"]["phases"]:
|
|
340
|
+
if phase["name"] == name:
|
|
341
|
+
return phase
|
|
342
|
+
raise ValueError(f"Phase '{name}' not found")
|
|
343
|
+
|
|
344
|
+
def test_green_phase_has_gate_file(self, tdd_yaml: dict) -> None:
|
|
345
|
+
"""AC3: Green phase should have gate.file = 'gates/tests-pass'."""
|
|
346
|
+
green = self._get_phase(tdd_yaml, "green")
|
|
347
|
+
gate = green.get("gate", {})
|
|
348
|
+
assert gate.get("file") == "gates/tests-pass", (
|
|
349
|
+
f"Expected gate.file='gates/tests-pass', got gate={gate}"
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
def test_green_phase_keeps_legacy_type(self, tdd_yaml: dict) -> None:
|
|
353
|
+
"""AC3: Green phase should keep gate.type = 'tests_pass' for backward compat."""
|
|
354
|
+
green = self._get_phase(tdd_yaml, "green")
|
|
355
|
+
gate = green.get("gate", {})
|
|
356
|
+
assert gate.get("type") == "tests_pass", (
|
|
357
|
+
f"Expected gate.type='tests_pass', got gate={gate}"
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
def test_green_phase_file_is_relative(self, tdd_yaml: dict) -> None:
|
|
361
|
+
"""AC3: File path should be relative (gates/tests-pass), not absolute."""
|
|
362
|
+
green = self._get_phase(tdd_yaml, "green")
|
|
363
|
+
gate = green.get("gate", {})
|
|
364
|
+
file_path = gate.get("file", "")
|
|
365
|
+
assert not file_path.startswith("/"), (
|
|
366
|
+
f"gate.file should be relative, got: {file_path}"
|
|
367
|
+
)
|
|
368
|
+
assert file_path == "gates/tests-pass", (
|
|
369
|
+
f"Expected 'gates/tests-pass', got: {file_path}"
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
def test_red_phase_unchanged(self, tdd_yaml: dict) -> None:
|
|
373
|
+
"""AC3: Red phase should NOT have gate.file (backward compat period)."""
|
|
374
|
+
red = self._get_phase(tdd_yaml, "red")
|
|
375
|
+
gate = red.get("gate", {})
|
|
376
|
+
assert "file" not in gate, (
|
|
377
|
+
f"Red phase should not have gate.file yet, got gate={gate}"
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
def test_review_phase_unchanged(self, tdd_yaml: dict) -> None:
|
|
381
|
+
"""AC3: Review phase should NOT have gate.file (backward compat period)."""
|
|
382
|
+
review = self._get_phase(tdd_yaml, "review")
|
|
383
|
+
gate = review.get("gate", {})
|
|
384
|
+
assert "file" not in gate, (
|
|
385
|
+
f"Review phase should not have gate.file yet, got gate={gate}"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
def test_setup_phase_unchanged(self, tdd_yaml: dict) -> None:
|
|
389
|
+
"""AC3: Setup phase should remain gateless."""
|
|
390
|
+
setup = self._get_phase(tdd_yaml, "setup")
|
|
391
|
+
assert "gate" not in setup, (
|
|
392
|
+
f"Setup phase should not have a gate, got: {setup}"
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
def test_finish_phase_unchanged(self, tdd_yaml: dict) -> None:
|
|
396
|
+
"""AC3: Finish phase should remain gateless."""
|
|
397
|
+
finish = self._get_phase(tdd_yaml, "finish")
|
|
398
|
+
assert "gate" not in finish, (
|
|
399
|
+
f"Finish phase should not have a gate, got: {finish}"
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
# ===========================================================================
|
|
404
|
+
# AC3: Integration — resolve_gate against actual tdd.yaml
|
|
405
|
+
# ===========================================================================
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
class TestResolveGateWithRealTddYaml:
|
|
409
|
+
"""AC3: resolve_gate returns gate_file when run against actual tdd.yaml.
|
|
410
|
+
|
|
411
|
+
These integration tests use the real workflow file (via the project root)
|
|
412
|
+
to verify the end-to-end gate.file field extraction.
|
|
413
|
+
"""
|
|
414
|
+
|
|
415
|
+
@pytest.fixture
|
|
416
|
+
def real_project(self, tmp_path: Path) -> Path:
|
|
417
|
+
"""Create a project that uses the actual tdd.yaml from pennyfarthing-dist."""
|
|
418
|
+
tdd_source = (
|
|
419
|
+
Path(__file__).resolve().parents[2]
|
|
420
|
+
/ "pennyfarthing-dist"
|
|
421
|
+
/ "workflows"
|
|
422
|
+
/ "tdd.yaml"
|
|
423
|
+
)
|
|
424
|
+
assert tdd_source.exists(), f"tdd.yaml not found at {tdd_source}"
|
|
425
|
+
|
|
426
|
+
workflows_dir = tmp_path / ".pennyfarthing" / "workflows"
|
|
427
|
+
workflows_dir.mkdir(parents=True)
|
|
428
|
+
(workflows_dir / "tdd.yaml").write_text(tdd_source.read_text())
|
|
429
|
+
|
|
430
|
+
(tmp_path / ".session").mkdir()
|
|
431
|
+
session_file = tmp_path / ".session" / "106-3-session.md"
|
|
432
|
+
session_file.write_text(SESSION_WITH_ASSESSMENT)
|
|
433
|
+
return tmp_path
|
|
434
|
+
|
|
435
|
+
def test_green_phase_returns_gate_file(
|
|
436
|
+
self, real_project: Path
|
|
437
|
+
) -> None:
|
|
438
|
+
"""AC3: resolve_gate for tdd/green should return gate_file='gates/tests-pass'."""
|
|
439
|
+
result = resolve_gate(
|
|
440
|
+
"106-3", "tdd", "green", project_root=real_project
|
|
441
|
+
)
|
|
442
|
+
assert result["gate_file"] == "gates/tests-pass", (
|
|
443
|
+
f"Expected gate_file='gates/tests-pass', got: {result}"
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
def test_green_phase_still_returns_gate_type(
|
|
447
|
+
self, real_project: Path
|
|
448
|
+
) -> None:
|
|
449
|
+
"""AC3: resolve_gate for tdd/green should still return gate_type='tests_pass'."""
|
|
450
|
+
result = resolve_gate(
|
|
451
|
+
"106-3", "tdd", "green", project_root=real_project
|
|
452
|
+
)
|
|
453
|
+
assert result["gate_type"] == "tests_pass", (
|
|
454
|
+
f"Expected gate_type='tests_pass', got: {result}"
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
def test_red_phase_gate_file_is_none(
|
|
458
|
+
self, real_project: Path
|
|
459
|
+
) -> None:
|
|
460
|
+
"""AC3: resolve_gate for tdd/red should have gate_file=None (not migrated yet)."""
|
|
461
|
+
result = resolve_gate(
|
|
462
|
+
"106-3", "tdd", "red", project_root=real_project
|
|
463
|
+
)
|
|
464
|
+
assert result["gate_file"] is None
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|