devrites 3.0.7 → 3.2.0
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/CHANGELOG.md +18 -0
- package/README.md +82 -50
- package/SECURITY.md +31 -29
- package/docs/adr/0001-go-engine-as-control-plane.md +1 -1
- package/docs/adr/0002-dual-host-harness.md +1 -1
- package/docs/adr/0004-state-schema-phases-sections.md +1 -2
- package/docs/adr/0006-clock-seam-and-engine-ci-gates.md +3 -4
- package/docs/adr/0009-prebuild-decision-coverage-and-readiness.md +67 -0
- package/docs/adr/0010-agent-first-fresh-context-orchestration.md +71 -0
- package/docs/adr/0011-define-plan-transition-rights.md +28 -0
- package/docs/adr/0012-semantic-workspace-upgrades.md +77 -0
- package/docs/adr/README.md +4 -0
- package/docs/agents/triage-labels.md +7 -7
- package/docs/architecture.md +179 -141
- package/docs/cli.md +47 -12
- package/docs/command-map.md +61 -38
- package/docs/engine/agent-contract.md +92 -15
- package/docs/engine/commands.md +248 -72
- package/docs/engine/state-schema.md +52 -23
- package/docs/engine/workspace-schema.md +103 -15
- package/docs/extensions.md +1 -1
- package/docs/flow.md +86 -51
- package/docs/harness-compliance.md +29 -5
- package/docs/orchestration.md +107 -79
- package/docs/quick-reference.md +11 -3
- package/docs/release.md +4 -3
- package/docs/skills.md +67 -38
- package/docs/usage.md +84 -39
- package/engine/cmd/releasepack/main.go +219 -0
- package/engine/cmd/releasepack/main_test.go +170 -0
- package/engine/commands.go +170 -23
- package/engine/git_guard.go +187 -0
- package/engine/git_guard_test.go +283 -0
- package/engine/hookpolicy.go +53 -55
- package/engine/hookpolicy_test.go +91 -1
- package/engine/hooks.go +296 -75
- package/engine/hooks_events_test.go +276 -6
- package/engine/hooks_workspace.go +640 -159
- package/engine/internal/devritespaths/paths.go +65 -10
- package/engine/internal/devritespaths/paths_test.go +110 -0
- package/engine/internal/doctor/doctor.go +153 -23
- package/engine/internal/doctor/doctor_test.go +74 -0
- package/engine/internal/forge/forge.go +940 -0
- package/engine/internal/forge/forge_test.go +576 -0
- package/engine/internal/forge/git.go +245 -0
- package/engine/internal/forge/liveness_unix.go +48 -0
- package/engine/internal/forge/liveness_windows.go +67 -0
- package/engine/internal/forge/manifest.go +402 -0
- package/engine/internal/gate/gate.go +90 -71
- package/engine/internal/gate/gate_test.go +71 -2
- package/engine/internal/harness/compliance.go +18 -24
- package/engine/internal/harness/harness.go +37 -44
- package/engine/internal/harness/harness_test.go +21 -5
- package/engine/internal/install/install.go +486 -38
- package/engine/internal/install/install_test.go +383 -10
- package/engine/internal/iohooks/iohooks.go +350 -59
- package/engine/internal/iohooks/iohooks_test.go +421 -1
- package/engine/internal/lib/buildreadiness.go +43 -18
- package/engine/internal/lib/clarifyreturn.go +91 -0
- package/engine/internal/lib/clarifyreturn_test.go +123 -0
- package/engine/internal/lib/context.go +54 -15
- package/engine/internal/lib/cursor_compat_test.go +8 -0
- package/engine/internal/lib/extensions.go +2 -3
- package/engine/internal/lib/gitauthority.go +601 -0
- package/engine/internal/lib/gitauthority_test.go +346 -0
- package/engine/internal/lib/jsonout.go +25 -11
- package/engine/internal/lib/jsonout_test.go +16 -0
- package/engine/internal/lib/lanes.go +14 -8
- package/engine/internal/lib/observability_test.go +358 -0
- package/engine/internal/lib/packageexistence.go +151 -35
- package/engine/internal/lib/packageexistence_test.go +163 -0
- package/engine/internal/lib/progress.go +11 -9
- package/engine/internal/lib/provenance.go +462 -0
- package/engine/internal/lib/provenance_test.go +154 -0
- package/engine/internal/lib/readiness_contract.json +118 -0
- package/engine/internal/lib/readinessartifact.go +533 -0
- package/engine/internal/lib/readinessartifact_test.go +422 -0
- package/engine/internal/lib/reconcile.go +712 -88
- package/engine/internal/lib/reconcile_test.go +335 -16
- package/engine/internal/lib/recoveryattempts.go +298 -0
- package/engine/internal/lib/recoveryattempts_test.go +215 -0
- package/engine/internal/lib/resolve.go +23 -19
- package/engine/internal/lib/runbook_context_test.go +20 -0
- package/engine/internal/lib/session.go +701 -9
- package/engine/internal/lib/session_test.go +80 -13
- package/engine/internal/lib/testintegrity.go +33 -37
- package/engine/internal/lib/testintegrity_test.go +63 -1
- package/engine/internal/migrate/migrate.go +81 -1
- package/engine/internal/migrate/migrate_test.go +22 -1
- package/engine/internal/reason/reason.go +180 -0
- package/engine/internal/reason/reason_test.go +35 -0
- package/engine/internal/rootfacts/facts.go +466 -0
- package/engine/internal/rootfacts/facts_test.go +306 -0
- package/engine/internal/safepath/safepath.go +55 -0
- package/engine/internal/safepath/safepath_test.go +69 -0
- package/engine/internal/safepath/safepath_windows_test.go +26 -0
- package/engine/internal/state/clarify_transition.go +165 -0
- package/engine/internal/state/clarify_transition_test.go +130 -0
- package/engine/internal/state/cmd/workflowmanifest/main.go +12 -8
- package/engine/internal/state/cursor.go +58 -0
- package/engine/internal/state/cursor_test.go +42 -1
- package/engine/internal/state/feature.go +35 -48
- package/engine/internal/state/schema.go +90 -37
- package/engine/internal/state/snapshot.go +18 -2
- package/engine/internal/state/state_test.go +187 -7
- package/engine/internal/state/status.go +48 -11
- package/engine/internal/state/workflow_manifest.json +231 -50
- package/engine/internal/toolpolicy/classifier.go +533 -0
- package/engine/internal/toolpolicy/classifier_test.go +424 -0
- package/engine/internal/toolpolicy/git.go +616 -0
- package/engine/internal/toolpolicy/scanner.go +382 -0
- package/engine/main.go +160 -77
- package/engine/observability_cli_test.go +52 -0
- package/engine/root_routing_test.go +277 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=approved.golden +1 -1
- package/engine/testdata/golden/TestParityBuildReadiness/arg=emptystatus.golden +1 -1
- package/engine/testdata/golden/TestParityBuildReadiness/arg=legacycontract.golden +1 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=noclarify.golden +1 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=novet.golden +1 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=stalevet.golden +1 -0
- package/engine/testdata/golden/TestParityBuildReadiness/arg=trailhash.golden +1 -1
- package/engine/testdata/golden/TestParityBuildReadiness/arg=trailpipe.golden +1 -1
- package/engine/testdata/golden/TestParityBuildReadiness/arg=vetnotready.golden +1 -0
- package/engine/testdata/golden/TestParityProgress/arg=allbuilt.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=done.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=mid.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=nophase.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=noslice.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=plan.golden +1 -1
- package/engine/testdata/golden/TestParityProgress/arg=seal.golden +1 -1
- package/engine/testdata/golden/TestParityReconcile/check-clean.golden +1 -1
- package/engine/testdata/golden/TestParityReconcile/inline-fallback.golden +1 -0
- package/engine/testdata/golden/TestParityReconcile/snapshot-no-allowlist.golden +1 -0
- package/engine/testdata/golden/TestParityWrightScope/devrites-edit-denied.golden +2 -0
- package/engine/testdata/golden/TestParityWrightScope/out-of-scope-enforce-denies.golden +1 -1
- package/engine/tests/adr_0011_define_plan_test.go +30 -0
- package/engine/tests/budget_test.go +19 -8
- package/engine/tests/concurrency_cli_test.go +7 -1
- package/engine/tests/doctor_cli_test.go +148 -2
- package/engine/tests/forge_cli_test.go +463 -0
- package/engine/tests/gate_test.go +63 -8
- package/engine/tests/hook_test.go +260 -8
- package/engine/tests/hooks_io_test.go +94 -3
- package/engine/tests/json_contract_test.go +127 -2
- package/engine/tests/migrate_cli_test.go +2 -2
- package/engine/tests/parity_buildreadiness_test.go +167 -10
- package/engine/tests/parity_learnings_test.go +16 -17
- package/engine/tests/parity_reconcile_test.go +20 -17
- package/engine/tests/parity_resolve_test.go +12 -11
- package/engine/tests/parity_test.go +21 -17
- package/pack/.claude/agents/devrites-code-reviewer.md +62 -48
- package/pack/.claude/agents/devrites-devex-reviewer.md +69 -53
- package/pack/.claude/agents/devrites-doubt-reviewer.md +29 -22
- package/pack/.claude/agents/devrites-evidence-scout.md +69 -0
- package/pack/.claude/agents/devrites-forge-judge.md +74 -61
- package/pack/.claude/agents/devrites-frontend-reviewer.md +48 -39
- package/pack/.claude/agents/devrites-performance-reviewer.md +49 -40
- package/pack/.claude/agents/devrites-plan-drafter.md +73 -0
- package/pack/.claude/agents/devrites-plan-reviewer.md +80 -47
- package/pack/.claude/agents/devrites-proof-runner.md +74 -0
- package/pack/.claude/agents/devrites-retrospector.md +48 -45
- package/pack/.claude/agents/devrites-security-auditor.md +46 -36
- package/pack/.claude/agents/devrites-simplifier-reviewer.md +50 -46
- package/pack/.claude/agents/devrites-slice-wright.md +153 -165
- package/pack/.claude/agents/devrites-spec-reviewer.md +34 -32
- package/pack/.claude/agents/devrites-strategy-reviewer.md +63 -34
- package/pack/.claude/agents/devrites-test-analyst.md +40 -30
- package/pack/.claude/agents/devrites-upgrade-planner.md +100 -0
- package/pack/.claude/settings.json +2 -1
- package/pack/.claude/skills/devrites-audit/SKILL.md +40 -61
- package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +24 -13
- package/pack/.claude/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
- package/pack/.claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
- package/pack/.claude/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
- package/pack/.claude/skills/devrites-doubt/SKILL.md +25 -17
- package/pack/.claude/skills/devrites-interview/SKILL.md +53 -52
- package/pack/.claude/skills/devrites-lib/SKILL.md +12 -9
- package/pack/.claude/skills/devrites-lib/reference/intent-map.md +4 -2
- package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
- package/pack/.claude/skills/devrites-lib/reference/reply-contract.md +8 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/README.md +38 -55
- package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
- package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +200 -190
- package/pack/.claude/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
- package/pack/.claude/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
- package/pack/.claude/skills/devrites-lib/reference/standards/code-review.md +16 -52
- package/pack/.claude/skills/devrites-lib/reference/standards/coding-style.md +2 -10
- package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
- package/pack/.claude/skills/devrites-lib/reference/standards/core.md +23 -18
- package/pack/.claude/skills/devrites-lib/reference/standards/deprecation.md +17 -57
- package/pack/.claude/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
- package/pack/.claude/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
- package/pack/.claude/skills/devrites-lib/reference/standards/hooks.md +3 -14
- package/pack/.claude/skills/devrites-lib/reference/standards/patterns.md +9 -25
- package/pack/.claude/skills/devrites-lib/reference/standards/performance.md +0 -9
- package/pack/.claude/skills/devrites-lib/reference/standards/principles.md +1 -3
- package/pack/.claude/skills/devrites-lib/reference/standards/security.md +17 -7
- package/pack/.claude/skills/devrites-lib/reference/standards/testing.md +1 -27
- package/pack/.claude/skills/devrites-lib/reference/standards/tooling.md +46 -50
- package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +40 -10
- package/pack/.claude/skills/devrites-source-driven/SKILL.md +23 -22
- package/pack/.claude/skills/rite/SKILL.md +10 -6
- package/pack/.claude/skills/rite/reference/menu.md +13 -7
- package/pack/.claude/skills/rite-adopt/SKILL.md +33 -37
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +33 -28
- package/pack/.claude/skills/rite-autocomplete/reference/loop.md +21 -21
- package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
- package/pack/.claude/skills/rite-build/SKILL.md +35 -30
- package/pack/.claude/skills/rite-build/reference/afk-discipline.md +41 -39
- package/pack/.claude/skills/rite-build/reference/evidence-standard.md +10 -0
- package/pack/.claude/skills/rite-build/reference/forge.md +186 -156
- package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +4 -3
- package/pack/.claude/skills/rite-build/reference/phase-contract.md +96 -175
- package/pack/.claude/skills/rite-build/reference/spec-drift-guard.md +10 -4
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +129 -134
- package/pack/.claude/skills/rite-clarify/SKILL.md +90 -0
- package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +61 -0
- package/pack/.claude/skills/rite-converge/SKILL.md +35 -25
- package/pack/.claude/skills/rite-define/SKILL.md +58 -32
- package/pack/.claude/skills/rite-define/reference/gates.md +16 -15
- package/pack/.claude/skills/rite-define/reference/plan-template.md +18 -8
- package/pack/.claude/skills/rite-frame/reference/failure-modes.md +22 -24
- package/pack/.claude/skills/rite-plan/SKILL.md +47 -16
- package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +4 -0
- package/pack/.claude/skills/rite-polish/SKILL.md +27 -23
- package/pack/.claude/skills/rite-prototype/SKILL.md +25 -26
- package/pack/.claude/skills/rite-prove/SKILL.md +27 -17
- package/pack/.claude/skills/rite-resolve/SKILL.md +12 -11
- package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +3 -0
- package/pack/.claude/skills/rite-review/SKILL.md +37 -28
- package/pack/.claude/skills/rite-seal/reference/phase-contract.md +27 -92
- package/pack/.claude/skills/rite-seal/reference/risk-and-rollback.md +13 -0
- package/pack/.claude/skills/rite-ship/reference/design-memory.md +31 -36
- package/pack/.claude/skills/rite-spec/SKILL.md +84 -135
- package/pack/.claude/skills/rite-spec/reference/investigation.md +37 -33
- package/pack/.claude/skills/rite-spec/reference/question-protocol.md +6 -2
- package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +25 -24
- package/pack/.claude/skills/rite-spec/reference/spec-template.md +9 -2
- package/pack/.claude/skills/rite-spec/reference/state-workspace.md +13 -3
- package/pack/.claude/skills/rite-temper/SKILL.md +62 -47
- package/pack/.claude/skills/rite-temper/reference/review-dimensions.md +24 -22
- package/pack/.claude/skills/rite-upgrade/SKILL.md +125 -0
- package/pack/.claude/skills/rite-vet/SKILL.md +114 -113
- package/pack/.claude/skills/rite-vet/reference/artifacts.md +50 -9
- package/pack/.claude/skills/rite-vet/reference/review-axes.md +39 -37
- package/pack/generated/claude/agents/devrites-code-reviewer.md +62 -48
- package/pack/generated/claude/agents/devrites-devex-reviewer.md +69 -53
- package/pack/generated/claude/agents/devrites-doubt-reviewer.md +29 -22
- package/pack/generated/claude/agents/devrites-evidence-scout.md +69 -0
- package/pack/generated/claude/agents/devrites-forge-judge.md +74 -61
- package/pack/generated/claude/agents/devrites-frontend-reviewer.md +48 -39
- package/pack/generated/claude/agents/devrites-performance-reviewer.md +49 -40
- package/pack/generated/claude/agents/devrites-plan-drafter.md +73 -0
- package/pack/generated/claude/agents/devrites-plan-reviewer.md +80 -47
- package/pack/generated/claude/agents/devrites-proof-runner.md +74 -0
- package/pack/generated/claude/agents/devrites-retrospector.md +48 -45
- package/pack/generated/claude/agents/devrites-security-auditor.md +46 -36
- package/pack/generated/claude/agents/devrites-simplifier-reviewer.md +50 -46
- package/pack/generated/claude/agents/devrites-slice-wright.md +153 -165
- package/pack/generated/claude/agents/devrites-spec-reviewer.md +34 -32
- package/pack/generated/claude/agents/devrites-strategy-reviewer.md +63 -34
- package/pack/generated/claude/agents/devrites-test-analyst.md +40 -30
- package/pack/generated/claude/agents/devrites-upgrade-planner.md +100 -0
- package/pack/generated/claude/settings.json +2 -1
- package/pack/generated/claude/skills/devrites-audit/SKILL.md +40 -61
- package/pack/generated/claude/skills/devrites-debug-recovery/SKILL.md +24 -13
- package/pack/generated/claude/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
- package/pack/generated/claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
- package/pack/generated/claude/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
- package/pack/generated/claude/skills/devrites-doubt/SKILL.md +25 -17
- package/pack/generated/claude/skills/devrites-interview/SKILL.md +53 -52
- package/pack/generated/claude/skills/devrites-lib/SKILL.md +12 -9
- package/pack/generated/claude/skills/devrites-lib/reference/intent-map.md +4 -2
- package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
- package/pack/generated/claude/skills/devrites-lib/reference/reply-contract.md +8 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/README.md +38 -55
- package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
- package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +200 -190
- package/pack/generated/claude/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
- package/pack/generated/claude/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
- package/pack/generated/claude/skills/devrites-lib/reference/standards/code-review.md +16 -52
- package/pack/generated/claude/skills/devrites-lib/reference/standards/coding-style.md +2 -10
- package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
- package/pack/generated/claude/skills/devrites-lib/reference/standards/core.md +23 -18
- package/pack/generated/claude/skills/devrites-lib/reference/standards/deprecation.md +17 -57
- package/pack/generated/claude/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
- package/pack/generated/claude/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
- package/pack/generated/claude/skills/devrites-lib/reference/standards/hooks.md +3 -14
- package/pack/generated/claude/skills/devrites-lib/reference/standards/patterns.md +9 -25
- package/pack/generated/claude/skills/devrites-lib/reference/standards/performance.md +0 -9
- package/pack/generated/claude/skills/devrites-lib/reference/standards/principles.md +1 -3
- package/pack/generated/claude/skills/devrites-lib/reference/standards/security.md +17 -7
- package/pack/generated/claude/skills/devrites-lib/reference/standards/testing.md +1 -27
- package/pack/generated/claude/skills/devrites-lib/reference/standards/tooling.md +46 -50
- package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +40 -10
- package/pack/generated/claude/skills/devrites-source-driven/SKILL.md +23 -22
- package/pack/generated/claude/skills/rite/SKILL.md +10 -6
- package/pack/generated/claude/skills/rite/reference/menu.md +13 -7
- package/pack/generated/claude/skills/rite-adopt/SKILL.md +33 -37
- package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +33 -28
- package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +21 -21
- package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
- package/pack/generated/claude/skills/rite-build/SKILL.md +35 -30
- package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +41 -39
- package/pack/generated/claude/skills/rite-build/reference/evidence-standard.md +10 -0
- package/pack/generated/claude/skills/rite-build/reference/forge.md +186 -156
- package/pack/generated/claude/skills/rite-build/reference/one-slice-cycle.md +4 -3
- package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +96 -175
- package/pack/generated/claude/skills/rite-build/reference/spec-drift-guard.md +10 -4
- package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +129 -134
- package/pack/generated/claude/skills/rite-clarify/SKILL.md +90 -0
- package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +61 -0
- package/pack/generated/claude/skills/rite-converge/SKILL.md +35 -25
- package/pack/generated/claude/skills/rite-define/SKILL.md +58 -32
- package/pack/generated/claude/skills/rite-define/reference/gates.md +16 -15
- package/pack/generated/claude/skills/rite-define/reference/plan-template.md +18 -8
- package/pack/generated/claude/skills/rite-frame/reference/failure-modes.md +22 -24
- package/pack/generated/claude/skills/rite-plan/SKILL.md +47 -16
- package/pack/generated/claude/skills/rite-plan/reference/task-breakdown.md +4 -0
- package/pack/generated/claude/skills/rite-polish/SKILL.md +27 -23
- package/pack/generated/claude/skills/rite-prototype/SKILL.md +25 -26
- package/pack/generated/claude/skills/rite-prove/SKILL.md +27 -17
- package/pack/generated/claude/skills/rite-resolve/SKILL.md +12 -11
- package/pack/generated/claude/skills/rite-resolve/reference/answer-protocol.md +3 -0
- package/pack/generated/claude/skills/rite-review/SKILL.md +37 -28
- package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +27 -92
- package/pack/generated/claude/skills/rite-seal/reference/risk-and-rollback.md +13 -0
- package/pack/generated/claude/skills/rite-ship/reference/design-memory.md +31 -36
- package/pack/generated/claude/skills/rite-spec/SKILL.md +84 -135
- package/pack/generated/claude/skills/rite-spec/reference/investigation.md +37 -33
- package/pack/generated/claude/skills/rite-spec/reference/question-protocol.md +6 -2
- package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +25 -24
- package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +9 -2
- package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +13 -3
- package/pack/generated/claude/skills/rite-temper/SKILL.md +62 -47
- package/pack/generated/claude/skills/rite-temper/reference/review-dimensions.md +24 -22
- package/pack/generated/claude/skills/rite-upgrade/SKILL.md +125 -0
- package/pack/generated/claude/skills/rite-vet/SKILL.md +114 -113
- package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +50 -9
- package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +39 -37
- package/pack/generated/codex/AGENTS.md +5 -2
- package/pack/generated/codex/agents/devrites-code-reviewer.toml +69 -47
- package/pack/generated/codex/agents/devrites-devex-reviewer.toml +75 -51
- package/pack/generated/codex/agents/devrites-doubt-reviewer.toml +35 -20
- package/pack/generated/codex/agents/devrites-evidence-scout.toml +75 -0
- package/pack/generated/codex/agents/devrites-forge-judge.toml +80 -59
- package/pack/generated/codex/agents/devrites-frontend-reviewer.toml +54 -37
- package/pack/generated/codex/agents/devrites-performance-reviewer.toml +55 -38
- package/pack/generated/codex/agents/devrites-plan-drafter.toml +79 -0
- package/pack/generated/codex/agents/devrites-plan-reviewer.toml +82 -47
- package/pack/generated/codex/agents/devrites-proof-runner.toml +80 -0
- package/pack/generated/codex/agents/devrites-retrospector.toml +54 -43
- package/pack/generated/codex/agents/devrites-security-auditor.toml +53 -35
- package/pack/generated/codex/agents/devrites-simplifier-reviewer.toml +56 -44
- package/pack/generated/codex/agents/devrites-slice-wright.toml +159 -163
- package/pack/generated/codex/agents/devrites-spec-reviewer.toml +40 -30
- package/pack/generated/codex/agents/devrites-strategy-reviewer.toml +65 -34
- package/pack/generated/codex/agents/devrites-test-analyst.toml +46 -28
- package/pack/generated/codex/agents/devrites-upgrade-planner.toml +106 -0
- package/pack/generated/codex/hooks.json +4 -14
- package/pack/generated/codex/skills/devrites-api-interface/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-audit/SKILL.md +47 -64
- package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-debug-recovery/SKILL.md +31 -16
- package/pack/generated/codex/skills/devrites-debug-recovery/reference/build-the-loop.md +24 -21
- package/pack/generated/codex/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +34 -6
- package/pack/generated/codex/skills/devrites-debug-recovery/reference/instrumentation.md +2 -2
- package/pack/generated/codex/skills/devrites-doubt/SKILL.md +32 -20
- package/pack/generated/codex/skills/devrites-frontend-craft/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-interview/SKILL.md +60 -55
- package/pack/generated/codex/skills/devrites-lib/SKILL.md +19 -12
- package/pack/generated/codex/skills/devrites-lib/reference/intent-map.md +4 -2
- package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +82 -137
- package/pack/generated/codex/skills/devrites-lib/reference/reply-contract.md +8 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/README.md +38 -55
- package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +53 -27
- package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +200 -190
- package/pack/generated/codex/skills/devrites-lib/reference/standards/anti-patterns.md +5 -15
- package/pack/generated/codex/skills/devrites-lib/reference/standards/ci-cd.md +27 -58
- package/pack/generated/codex/skills/devrites-lib/reference/standards/code-review.md +16 -52
- package/pack/generated/codex/skills/devrites-lib/reference/standards/coding-style.md +2 -10
- package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +18 -61
- package/pack/generated/codex/skills/devrites-lib/reference/standards/core.md +23 -18
- package/pack/generated/codex/skills/devrites-lib/reference/standards/deprecation.md +17 -57
- package/pack/generated/codex/skills/devrites-lib/reference/standards/development-workflow.md +4 -33
- package/pack/generated/codex/skills/devrites-lib/reference/standards/git-workflow.md +4 -20
- package/pack/generated/codex/skills/devrites-lib/reference/standards/hooks.md +3 -14
- package/pack/generated/codex/skills/devrites-lib/reference/standards/patterns.md +9 -25
- package/pack/generated/codex/skills/devrites-lib/reference/standards/performance.md +0 -9
- package/pack/generated/codex/skills/devrites-lib/reference/standards/principles.md +1 -3
- package/pack/generated/codex/skills/devrites-lib/reference/standards/security.md +17 -7
- package/pack/generated/codex/skills/devrites-lib/reference/standards/testing.md +1 -27
- package/pack/generated/codex/skills/devrites-lib/reference/standards/tooling.md +46 -50
- package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +40 -10
- package/pack/generated/codex/skills/devrites-prose-craft/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-refresh-indexes/SKILL.md +7 -3
- package/pack/generated/codex/skills/devrites-source-driven/SKILL.md +29 -24
- package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite/SKILL.md +21 -13
- package/pack/generated/codex/skills/rite/reference/menu.md +13 -7
- package/pack/generated/codex/skills/rite-adopt/SKILL.md +40 -40
- package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +40 -31
- package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +21 -21
- package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +15 -6
- package/pack/generated/codex/skills/rite-build/SKILL.md +42 -33
- package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +41 -39
- package/pack/generated/codex/skills/rite-build/reference/evidence-standard.md +10 -0
- package/pack/generated/codex/skills/rite-build/reference/forge.md +186 -156
- package/pack/generated/codex/skills/rite-build/reference/one-slice-cycle.md +4 -3
- package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +96 -175
- package/pack/generated/codex/skills/rite-build/reference/spec-drift-guard.md +10 -4
- package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +129 -134
- package/pack/generated/codex/skills/rite-clarify/SKILL.md +106 -0
- package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +61 -0
- package/pack/generated/codex/skills/rite-converge/SKILL.md +42 -28
- package/pack/generated/codex/skills/rite-customize/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-define/SKILL.md +65 -35
- package/pack/generated/codex/skills/rite-define/reference/gates.md +16 -15
- package/pack/generated/codex/skills/rite-define/reference/plan-template.md +18 -8
- package/pack/generated/codex/skills/rite-doctor/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-dogfood/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-explain/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-frame/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-frame/reference/failure-modes.md +22 -24
- package/pack/generated/codex/skills/rite-handoff/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-learn/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-plan/SKILL.md +54 -19
- package/pack/generated/codex/skills/rite-plan/reference/task-breakdown.md +5 -1
- package/pack/generated/codex/skills/rite-polish/SKILL.md +34 -26
- package/pack/generated/codex/skills/rite-pov/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-pr-feedback/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-pressure-test/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-prototype/SKILL.md +32 -29
- package/pack/generated/codex/skills/rite-prove/SKILL.md +34 -20
- package/pack/generated/codex/skills/rite-quick/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-resolve/SKILL.md +19 -14
- package/pack/generated/codex/skills/rite-resolve/reference/answer-protocol.md +3 -0
- package/pack/generated/codex/skills/rite-review/SKILL.md +44 -31
- package/pack/generated/codex/skills/rite-seal/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +27 -92
- package/pack/generated/codex/skills/rite-seal/reference/risk-and-rollback.md +13 -0
- package/pack/generated/codex/skills/rite-ship/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-ship/reference/design-memory.md +31 -36
- package/pack/generated/codex/skills/rite-spec/SKILL.md +91 -138
- package/pack/generated/codex/skills/rite-spec/reference/investigation.md +37 -33
- package/pack/generated/codex/skills/rite-spec/reference/question-protocol.md +6 -2
- package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +25 -24
- package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +9 -2
- package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +13 -3
- package/pack/generated/codex/skills/rite-status/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-temper/SKILL.md +69 -50
- package/pack/generated/codex/skills/rite-temper/reference/review-dimensions.md +24 -22
- package/pack/generated/codex/skills/rite-upgrade/SKILL.md +141 -0
- package/pack/generated/codex/skills/rite-upgrade/agents/openai.yaml +2 -0
- package/pack/generated/codex/skills/rite-vet/SKILL.md +121 -116
- package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +50 -9
- package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +40 -38
- package/pack/generated/codex/skills/rite-zoom-out/SKILL.md +7 -3
- package/package.json +1 -1
- package/scripts/build-release-tarball.sh +32 -15
- package/scripts/check-authority-drift.py +125 -0
- package/scripts/check-instruction-size-baseline.mjs +19 -11
- package/scripts/check-invocation-integrity.py +2 -0
- package/scripts/codex-generate.sh +69 -33
- package/scripts/grade-feature.sh +121 -40
- package/scripts/live-hosts/agent-result.schema.json +230 -0
- package/scripts/live-hosts/claude.sh +87 -0
- package/scripts/live-hosts/codex.sh +81 -0
- package/scripts/live-hosts/common.sh +113 -0
- package/scripts/live-hosts/fake-host.py +264 -0
- package/scripts/live-hosts/host-transport.py +287 -0
- package/scripts/release-check.sh +5 -1
- package/scripts/run-agent-contract-evals.py +1380 -0
- package/scripts/run-behavioral-evals.sh +24 -30
- package/scripts/run-evals.sh +1 -5
- package/scripts/run-live-behavioral-evals.py +1274 -144
- package/scripts/run-outcome-evals.sh +445 -88
- package/scripts/run-tests.mjs +30 -2
- package/scripts/skills-inventory.mjs +1 -1
- package/scripts/validate-workflow-security.py +39 -20
- package/scripts/validate-workspace-schema.py +362 -10
- package/scripts/validate.sh +21 -15
- package/engine/testdata/golden/TestParityWrightScope/devrites-edit-allowed.golden +0 -1
- /package/engine/testdata/golden/{TestParityReconcile/check-no-claimed.golden → TestParityBuildReadiness/arg=clarifyopen.golden} +0 -0
|
@@ -10,9 +10,11 @@ import (
|
|
|
10
10
|
)
|
|
11
11
|
|
|
12
12
|
type jsonEnvelope struct {
|
|
13
|
+
Schema string `json:"schema"`
|
|
13
14
|
Command string `json:"command"`
|
|
14
15
|
OK bool `json:"ok"`
|
|
15
16
|
ExitCode int `json:"exitCode"`
|
|
17
|
+
ReasonID string `json:"reason_id"`
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
func TestJSONContractCommandsEmitExactlyOneEnvelope(t *testing.T) {
|
|
@@ -41,6 +43,9 @@ func TestJSONContractCommandsEmitExactlyOneEnvelope(t *testing.T) {
|
|
|
41
43
|
if env.Command == "" {
|
|
42
44
|
t.Fatalf("missing command in envelope: %s", out)
|
|
43
45
|
}
|
|
46
|
+
if env.Schema != "devrites-command/v1" {
|
|
47
|
+
t.Fatalf("schema=%q\n%s", env.Schema, out)
|
|
48
|
+
}
|
|
44
49
|
if env.ExitCode != code {
|
|
45
50
|
t.Fatalf("envelope exitCode=%d process exit=%d\n%s", env.ExitCode, code, out)
|
|
46
51
|
}
|
|
@@ -51,6 +56,73 @@ func TestJSONContractCommandsEmitExactlyOneEnvelope(t *testing.T) {
|
|
|
51
56
|
}
|
|
52
57
|
}
|
|
53
58
|
|
|
59
|
+
func TestLifecycleGateJSONCarriesRuleOwnedReasonID(t *testing.T) {
|
|
60
|
+
root := newWorkspace(t)
|
|
61
|
+
for _, tc := range []struct {
|
|
62
|
+
command string
|
|
63
|
+
want string
|
|
64
|
+
}{
|
|
65
|
+
{"readiness", "DRV-GATE-READINESS-MISSING"},
|
|
66
|
+
{"seal", "DRV-GATE-SEAL-MISSING"},
|
|
67
|
+
} {
|
|
68
|
+
t.Run(tc.command, func(t *testing.T) {
|
|
69
|
+
out, _, code := runDevrites(t, root, tc.command, "auth-tokens", "--json")
|
|
70
|
+
if code != 3 {
|
|
71
|
+
t.Fatalf("%s exit=%d\n%s", tc.command, code, out)
|
|
72
|
+
}
|
|
73
|
+
var env jsonEnvelope
|
|
74
|
+
decodeExactlyOneJSON(t, out, &env)
|
|
75
|
+
if env.ReasonID != tc.want {
|
|
76
|
+
t.Fatalf("%s reason_id=%q, want %q\n%s", tc.command, env.ReasonID, tc.want, out)
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
func TestLifecycleGateAppendsRootRelativeV1Provenance(t *testing.T) {
|
|
83
|
+
root := newWorkspace(t)
|
|
84
|
+
_, _, _ = runDevrites(t, root, "readiness", "auth-tokens", "--json")
|
|
85
|
+
raw, err := os.ReadFile(filepath.Join(root, "timeline.jsonl"))
|
|
86
|
+
if err != nil {
|
|
87
|
+
t.Fatal(err)
|
|
88
|
+
}
|
|
89
|
+
if strings.Contains(string(raw), filepath.Dir(root)) {
|
|
90
|
+
t.Fatalf("timeline retained an absolute project path:\n%s", raw)
|
|
91
|
+
}
|
|
92
|
+
var boundaries []string
|
|
93
|
+
for _, line := range strings.Split(strings.TrimSpace(string(raw)), "\n") {
|
|
94
|
+
var event struct {
|
|
95
|
+
Schema string `json:"schema"`
|
|
96
|
+
Boundary string `json:"boundary"`
|
|
97
|
+
RootSource string `json:"root_source"`
|
|
98
|
+
Workspace string `json:"workspace"`
|
|
99
|
+
ReasonID string `json:"reason_id"`
|
|
100
|
+
Evidence []string `json:"evidence_paths"`
|
|
101
|
+
}
|
|
102
|
+
if json.Unmarshal([]byte(line), &event) != nil || event.Schema != "devrites-event/v1" {
|
|
103
|
+
continue
|
|
104
|
+
}
|
|
105
|
+
boundaries = append(boundaries, event.Boundary)
|
|
106
|
+
if event.RootSource != "DEVRITES_ROOT" {
|
|
107
|
+
t.Fatalf("non-canonical root/workspace provenance: %+v", event)
|
|
108
|
+
}
|
|
109
|
+
if event.Boundary == "lifecycle-gate" && event.Workspace != ".devrites/features/auth-tokens" {
|
|
110
|
+
t.Fatalf("gate workspace provenance: %+v", event)
|
|
111
|
+
}
|
|
112
|
+
if event.Boundary == "root-selection" && event.Workspace != "" {
|
|
113
|
+
t.Fatalf("root selection invented an inactive workspace: %+v", event)
|
|
114
|
+
}
|
|
115
|
+
for _, path := range event.Evidence {
|
|
116
|
+
if filepath.IsAbs(path) || strings.HasPrefix(path, "..") {
|
|
117
|
+
t.Fatalf("non-relative evidence %q", path)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if strings.Join(boundaries, ",") != "root-selection,lifecycle-gate" {
|
|
122
|
+
t.Fatalf("boundaries=%v\n%s", boundaries, raw)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
54
126
|
func TestContextShowJSONReportsActiveWorkspace(t *testing.T) {
|
|
55
127
|
root := newWorkspace(t)
|
|
56
128
|
if err := os.WriteFile(filepath.Join(root, "ACTIVE"), []byte("auth-tokens\n"), 0o644); err != nil {
|
|
@@ -63,18 +135,32 @@ func TestContextShowJSONReportsActiveWorkspace(t *testing.T) {
|
|
|
63
135
|
var got struct {
|
|
64
136
|
Root string `json:"root"`
|
|
65
137
|
Project string `json:"project"`
|
|
138
|
+
LexicalRoot string `json:"lexicalRoot"`
|
|
139
|
+
RootSelection string `json:"rootSelection"`
|
|
66
140
|
ActiveWorkspace string `json:"activeWorkspace"`
|
|
67
141
|
Source string `json:"source"`
|
|
68
|
-
|
|
142
|
+
Git struct {
|
|
143
|
+
TopLevel string `json:"topLevel"`
|
|
144
|
+
LinkedWorktree bool `json:"linkedWorktree"`
|
|
145
|
+
Submodule bool `json:"submodule"`
|
|
146
|
+
} `json:"git"`
|
|
147
|
+
HostCommands struct {
|
|
69
148
|
Claude string `json:"claude"`
|
|
70
149
|
Codex string `json:"codex"`
|
|
71
150
|
} `json:"hostCommands"`
|
|
72
151
|
Status []any `json:"status"`
|
|
73
152
|
}
|
|
74
153
|
decodeExactlyOneJSON(t, out, &got)
|
|
75
|
-
|
|
154
|
+
wantRoot, err := filepath.EvalSymlinks(root)
|
|
155
|
+
if err != nil {
|
|
156
|
+
t.Fatal(err)
|
|
157
|
+
}
|
|
158
|
+
if got.Root != wantRoot || got.Project != filepath.Dir(wantRoot) {
|
|
76
159
|
t.Fatalf("wrong roots: %+v", got)
|
|
77
160
|
}
|
|
161
|
+
if got.LexicalRoot != root || got.RootSelection != "DEVRITES_ROOT" {
|
|
162
|
+
t.Fatalf("wrong root provenance: %+v", got)
|
|
163
|
+
}
|
|
78
164
|
if got.ActiveWorkspace != filepath.Join(".devrites", "features", "auth-tokens") || got.Source != "ACTIVE" {
|
|
79
165
|
t.Fatalf("wrong active workspace: %+v", got)
|
|
80
166
|
}
|
|
@@ -86,6 +172,45 @@ func TestContextShowJSONReportsActiveWorkspace(t *testing.T) {
|
|
|
86
172
|
}
|
|
87
173
|
}
|
|
88
174
|
|
|
175
|
+
func TestContextShowJSONCarriesCanonicalRootHazards(t *testing.T) {
|
|
176
|
+
root := newWorkspace(t)
|
|
177
|
+
if err := os.WriteFile(filepath.Join(root, "ACTIVE"), []byte("ghost\n"), 0o644); err != nil {
|
|
178
|
+
t.Fatal(err)
|
|
179
|
+
}
|
|
180
|
+
out, errOut, code := runDevrites(t, root, "context", "show", "--json")
|
|
181
|
+
if code != 0 {
|
|
182
|
+
t.Fatalf("context show exit=%d stderr=%s", code, errOut)
|
|
183
|
+
}
|
|
184
|
+
var got struct {
|
|
185
|
+
RootSelection string `json:"rootSelection"`
|
|
186
|
+
Status []struct {
|
|
187
|
+
ID string `json:"id"`
|
|
188
|
+
Remediation string `json:"remediation"`
|
|
189
|
+
} `json:"status"`
|
|
190
|
+
}
|
|
191
|
+
decodeExactlyOneJSON(t, out, &got)
|
|
192
|
+
if got.RootSelection != "DEVRITES_ROOT" || len(got.Status) != 1 ||
|
|
193
|
+
got.Status[0].ID != "DRV-ACTIVE-STALE" || !strings.Contains(got.Status[0].Remediation, "rm -f") {
|
|
194
|
+
t.Fatalf("context root status = %+v\n%s", got, out)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
func TestContextShowSeparatesRootAndWorkspaceSelection(t *testing.T) {
|
|
199
|
+
root := newWorkspace(t)
|
|
200
|
+
out, errOut, code := runDevrites(t, root, "context", "show", "--json")
|
|
201
|
+
if code != 0 {
|
|
202
|
+
t.Fatalf("context show exit=%d stderr=%s", code, errOut)
|
|
203
|
+
}
|
|
204
|
+
var got struct {
|
|
205
|
+
RootSelection string `json:"rootSelection"`
|
|
206
|
+
Source string `json:"source"`
|
|
207
|
+
}
|
|
208
|
+
decodeExactlyOneJSON(t, out, &got)
|
|
209
|
+
if got.RootSelection != "DEVRITES_ROOT" || got.Source != "none" {
|
|
210
|
+
t.Fatalf("root/workspace selections are conflated: %+v", got)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
89
214
|
func decodeExactlyOneJSON(t *testing.T, text string, v any) {
|
|
90
215
|
t.Helper()
|
|
91
216
|
dec := json.NewDecoder(strings.NewReader(text))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
package main_test
|
|
2
2
|
|
|
3
|
-
// Issue 06: `migrate` workspace normalization
|
|
3
|
+
// CLI coverage for Issue 06: `migrate` workspace normalization.
|
|
4
4
|
|
|
5
5
|
import (
|
|
6
6
|
"os"
|
|
@@ -71,7 +71,7 @@ func TestMigrateNormalizesCanonicalWorkSchema(t *testing.T) {
|
|
|
71
71
|
if !strings.Contains(string(readme), "phase: temper") {
|
|
72
72
|
t.Errorf("README.md phase not derived from state.md\n%s", readme)
|
|
73
73
|
}
|
|
74
|
-
if !strings.Contains(string(readme), "schemaVersion:
|
|
74
|
+
if !strings.Contains(string(readme), "schemaVersion: 2") {
|
|
75
75
|
t.Errorf("README.md missing schemaVersion\n%s", readme)
|
|
76
76
|
}
|
|
77
77
|
for _, unwanted := range []string{"feature.md", "proof.md", "status.md"} {
|
|
@@ -1,36 +1,135 @@
|
|
|
1
1
|
package main_test
|
|
2
2
|
|
|
3
|
-
// TestParityBuildReadiness checks the build-readiness gate's stdout
|
|
3
|
+
// TestParityBuildReadiness checks the build-readiness gate's stdout and exit code
|
|
4
4
|
// against the golden snapshot for each state.md fixture.
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import (
|
|
7
|
+
"fmt"
|
|
8
|
+
"os"
|
|
9
|
+
"path/filepath"
|
|
10
|
+
"strings"
|
|
11
|
+
"testing"
|
|
12
|
+
|
|
13
|
+
"github.com/devrites/devrites/internal/lib"
|
|
14
|
+
)
|
|
7
15
|
|
|
8
16
|
func TestParityBuildReadiness(t *testing.T) {
|
|
9
17
|
work := t.TempDir()
|
|
10
18
|
|
|
11
|
-
// Status halts
|
|
19
|
+
// Status halts write only to stderr; parity covers stdout and the exit code.
|
|
12
20
|
writeFeatureFile(t, work, "await", "state.md", "- Status: awaiting_human\n") // exit 3
|
|
13
21
|
writeFeatureFile(t, work, "blocked", "state.md", "- Status: blocked\n") // exit 4
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
writeReadyArtifacts := func(slug string) {
|
|
24
|
+
t.Helper()
|
|
25
|
+
writeCoverageArtifacts(t, work, slug)
|
|
26
|
+
for name, body := range map[string]string{
|
|
27
|
+
"architecture.md": "# Architecture\n\nExisting layer.\n",
|
|
28
|
+
"plan.md": "# Plan\n\nOne slice.\n",
|
|
29
|
+
"tasks.md": "# Tasks\n\n## SLICE-001\nBuild.\n",
|
|
30
|
+
"traceability.md": "# Traceability\n\nAC-001 -> SLICE-001.\n",
|
|
31
|
+
"test-plan.md": `# Test plan
|
|
32
|
+
|
|
33
|
+
DevRites contract: devrites.readiness-artifacts.v2
|
|
34
|
+
|
|
35
|
+
## Build-entry preflight
|
|
36
|
+
| Gate | Command | Cwd | Expected | Prerequisites | Provenance to recapture |
|
|
37
|
+
| --- | --- | --- | --- | --- | --- |
|
|
38
|
+
| unit | go test ./... | engine | exit 0 | none | go version |
|
|
39
|
+
|
|
40
|
+
## Per-gap test requirements
|
|
41
|
+
| ID | Path / flow | Test file | Asserts | Kind | Slice | Priority |
|
|
42
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
43
|
+
| T1 | flow | flow_test.go | request → success | unit | SLICE-001 | P1 |
|
|
44
|
+
|
|
45
|
+
## Acceptance → test map
|
|
46
|
+
- AC-001 → T1
|
|
47
|
+
`,
|
|
48
|
+
} {
|
|
49
|
+
writeFeatureFile(t, work, slug, name, body)
|
|
50
|
+
}
|
|
51
|
+
root := filepath.Join(work, ".devrites")
|
|
52
|
+
digest, err := lib.ReadinessInputDigest(root, slug, "engineering")
|
|
53
|
+
if err != nil {
|
|
54
|
+
t.Fatal(err)
|
|
55
|
+
}
|
|
56
|
+
writeFeatureFile(t, work, slug, "eng-review.md", fmt.Sprintf(`# Eng review
|
|
57
|
+
|
|
58
|
+
DevRites contract: devrites.readiness-artifacts.v2
|
|
59
|
+
Implementation readiness: READY
|
|
60
|
+
Readiness inputs SHA-256: %s
|
|
61
|
+
|
|
62
|
+
## 2a. Build-entry preflight
|
|
63
|
+
| Gate | Command + cwd | Tool/version | Prerequisite owner | Full provenance inputs | Fixture/smoke | Verdict |
|
|
64
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
65
|
+
| unit | go test ./... | go | none | go.mod | focused | pass |
|
|
66
|
+
|
|
67
|
+
## 2b. Implementation readiness
|
|
68
|
+
| Surface | Requirement/decision | Boundary/wiring | Slice | Proof | Verdict |
|
|
69
|
+
| --- | --- | --- | --- | --- | --- |
|
|
70
|
+
| flow | AC-001 | existing | SLICE-001 | T1 | ready |
|
|
71
|
+
|
|
72
|
+
## 4. Failure modes
|
|
73
|
+
| New codepath | Realistic failure | Test? | Handling? | Silent? | Verdict |
|
|
74
|
+
| --- | --- | --- | --- | --- | --- |
|
|
75
|
+
| flow | invalid | yes | yes | no | ok |
|
|
76
|
+
|
|
77
|
+
## 7. Completion summary
|
|
78
|
+
- Ready.
|
|
79
|
+
`, digest))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// A ready feature has an approved plan, running status, and current
|
|
83
|
+
// clarification and vet artifacts.
|
|
84
|
+
for _, slug := range []string{"approved", "trailpipe", "trailhash", "emptystatus"} {
|
|
85
|
+
writeReadyArtifacts(slug)
|
|
86
|
+
}
|
|
87
|
+
writeFeatureFile(t, work, "approved", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 0
|
|
17
88
|
|
|
18
89
|
// Plan not approved: missing line, or the literal "none".
|
|
90
|
+
writeCoverageArtifacts(t, work, "noapprove")
|
|
91
|
+
writeCoverageArtifacts(t, work, "approvenone")
|
|
19
92
|
writeFeatureFile(t, work, "noapprove", "state.md", "- Status: running\n") // exit 2
|
|
20
93
|
writeFeatureFile(t, work, "approvenone", "state.md", "- Plan approved: none\n- Status: running\n") // exit 2
|
|
21
94
|
|
|
22
95
|
// field() strip: a trailing " | none" / " # note" annotation is trimmed off
|
|
23
96
|
// Status before the case match, so both stay "running" and reach OK.
|
|
24
|
-
writeFeatureFile(t, work, "trailpipe", "state.md", "- Plan approved: 2024-01-01\n- Status: running | none\n") // exit 0
|
|
25
|
-
writeFeatureFile(t, work, "trailhash", "state.md", "- Plan approved: 2024-01-01\n- Status: running # note\n") // exit 0
|
|
97
|
+
writeFeatureFile(t, work, "trailpipe", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running | none\n") // exit 0
|
|
98
|
+
writeFeatureFile(t, work, "trailhash", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running # note\n") // exit 0
|
|
99
|
+
|
|
100
|
+
// An empty Status with an approved plan renders as "running".
|
|
101
|
+
writeFeatureFile(t, work, "emptystatus", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: \n") // exit 0
|
|
102
|
+
|
|
103
|
+
// A plan cannot build without an explicit closed clarification scan and a
|
|
104
|
+
// successful engineering-readiness verdict. These are objective routes, not
|
|
105
|
+
// human questions.
|
|
106
|
+
writeFeatureFile(t, work, "noclarify", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 6
|
|
107
|
+
|
|
108
|
+
writeFeatureFile(t, work, "clarifyopen", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 6
|
|
109
|
+
writeFeatureFile(t, work, "clarifyopen", "brief.md", "# Brief\n\nOutcome.\n")
|
|
110
|
+
writeFeatureFile(t, work, "clarifyopen", "spec.md", "# Spec\n\nAC-001.\n")
|
|
111
|
+
writeFeatureFile(t, work, "clarifyopen", "decision-coverage.md", "# Decision coverage\n\n- Decision coverage: NEEDS CLARIFICATION\n")
|
|
26
112
|
|
|
27
|
-
|
|
28
|
-
|
|
113
|
+
writeFeatureFile(t, work, "novet", "state.md", "- Phase: plan\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 7
|
|
114
|
+
writeCoverageArtifacts(t, work, "novet")
|
|
115
|
+
|
|
116
|
+
writeFeatureFile(t, work, "vetnotready", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 7
|
|
117
|
+
writeCoverageArtifacts(t, work, "vetnotready")
|
|
118
|
+
writeFeatureFile(t, work, "vetnotready", "eng-review.md", "# Engineering review\n\n- Implementation readiness: NEEDS REPLAN\n")
|
|
119
|
+
|
|
120
|
+
writeReadyArtifacts("stalevet")
|
|
121
|
+
writeFeatureFile(t, work, "stalevet", "state.md", "- Phase: plan\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 7
|
|
122
|
+
|
|
123
|
+
writeCoverageArtifacts(t, work, "legacycontract")
|
|
124
|
+
writeFeatureFile(t, work, "legacycontract", "state.md", "- Phase: vet\n- Plan approved: 2024-01-01\n- Status: running\n") // exit 8
|
|
125
|
+
legacyCoverage := filepath.Join(work, ".devrites", "features", "legacycontract", "decision-coverage.md")
|
|
126
|
+
replaceInFile(t, legacyCoverage, "DevRites contract: devrites.readiness-artifacts.v2\n", "")
|
|
29
127
|
|
|
30
128
|
// "ghost" is intentionally never created → no workspace/state.md (exit 5).
|
|
31
129
|
for _, arg := range []string{
|
|
32
130
|
"await", "blocked", "approved", "noapprove", "approvenone",
|
|
33
|
-
"trailpipe", "trailhash", "emptystatus", "
|
|
131
|
+
"trailpipe", "trailhash", "emptystatus", "noclarify", "clarifyopen",
|
|
132
|
+
"novet", "vetnotready", "stalevet", "legacycontract", "ghost",
|
|
34
133
|
} {
|
|
35
134
|
c := parityCase{
|
|
36
135
|
workdir: work,
|
|
@@ -40,3 +139,61 @@ func TestParityBuildReadiness(t *testing.T) {
|
|
|
40
139
|
t.Run("arg="+arg, func(t *testing.T) { c.assertEqual(t) })
|
|
41
140
|
}
|
|
42
141
|
}
|
|
142
|
+
|
|
143
|
+
func replaceInFile(t *testing.T, path, old, replacement string) {
|
|
144
|
+
t.Helper()
|
|
145
|
+
data, err := os.ReadFile(path)
|
|
146
|
+
if err != nil {
|
|
147
|
+
t.Fatal(err)
|
|
148
|
+
}
|
|
149
|
+
body := string(data)
|
|
150
|
+
if strings.Count(body, old) != 1 {
|
|
151
|
+
t.Fatalf("%s: expected exactly one %q", path, old)
|
|
152
|
+
}
|
|
153
|
+
if err := os.WriteFile(path, []byte(strings.Replace(body, old, replacement, 1)), 0o644); err != nil {
|
|
154
|
+
t.Fatal(err)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
func writeCoverageArtifacts(t *testing.T, work, slug string) {
|
|
159
|
+
t.Helper()
|
|
160
|
+
writeFeatureFile(t, work, slug, "brief.md", "# Brief\n\nOutcome.\n")
|
|
161
|
+
writeFeatureFile(t, work, slug, "spec.md", "# Spec\n\n## Acceptance criteria\n- AC-001 succeeds.\n")
|
|
162
|
+
writeFeatureFile(t, work, slug, "decisions.md", "# Decisions\n\nNo open product decisions.\n")
|
|
163
|
+
writeFeatureFile(t, work, slug, "assumptions.md", "# Assumptions\n\nNo material assumptions.\n")
|
|
164
|
+
writeFeatureFile(t, work, slug, "questions.md", "# Questions\n\nNone.\n")
|
|
165
|
+
root := filepath.Join(work, ".devrites")
|
|
166
|
+
digest, err := lib.ReadinessInputDigest(root, slug, "coverage")
|
|
167
|
+
if err != nil {
|
|
168
|
+
t.Fatal(err)
|
|
169
|
+
}
|
|
170
|
+
writeFeatureFile(t, work, slug, "decision-coverage.md", fmt.Sprintf(`# Decision coverage
|
|
171
|
+
|
|
172
|
+
DevRites contract: devrites.readiness-artifacts.v2
|
|
173
|
+
Decision coverage: CLEAR
|
|
174
|
+
Coverage inputs SHA-256: %s
|
|
175
|
+
|
|
176
|
+
## Topology
|
|
177
|
+
| Surface | Kind | Related IDs | Evidence |
|
|
178
|
+
| --- | --- | --- | --- |
|
|
179
|
+
| flow | behavior | AC-001 | spec.md |
|
|
180
|
+
|
|
181
|
+
## Coverage matrix
|
|
182
|
+
| Surface | Dimension | Status | Canonical reference | Owner / validation gate | Consequence if wrong |
|
|
183
|
+
| --- | --- | --- | --- | --- | --- |
|
|
184
|
+
| flow | behavior | closed | AC-001 | rite-prove | failure |
|
|
185
|
+
|
|
186
|
+
## Assumption audit
|
|
187
|
+
| Assumption | Evidence | Confidence | Owner | Validation | Consequence if wrong |
|
|
188
|
+
| --- | --- | --- | --- | --- | --- |
|
|
189
|
+
| none | n/a | high | n/a | n/a | n/a |
|
|
190
|
+
|
|
191
|
+
## Residual uncertainty
|
|
192
|
+
| Item | Why nonblocking | Owner | Validation gate |
|
|
193
|
+
| --- | --- | --- | --- |
|
|
194
|
+
| none | n/a | n/a | n/a |
|
|
195
|
+
|
|
196
|
+
## Readiness verdict
|
|
197
|
+
No unresolved decision remains.
|
|
198
|
+
`, digest))
|
|
199
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
package main_test
|
|
2
2
|
|
|
3
3
|
// TestParityLearnings checks the learnings command against the golden snapshots.
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// never depends on a platform-specific tie-break.
|
|
4
|
+
// Learning state lives at the root selected by DEVRITES_ROOT. The mine and nudge
|
|
5
|
+
// fixtures use counts of 3 and 2 so sorting never depends on a platform-specific
|
|
6
|
+
// tie.
|
|
8
7
|
|
|
9
8
|
import (
|
|
10
9
|
"path/filepath"
|
|
@@ -14,10 +13,11 @@ import (
|
|
|
14
13
|
func TestParityLearnings(t *testing.T) {
|
|
15
14
|
learn := func(a ...string) []string { return append([]string{"learnings"}, a...) }
|
|
16
15
|
|
|
17
|
-
//
|
|
18
|
-
// appends
|
|
19
|
-
// contract
|
|
16
|
+
// Add to a fresh workspace. Bash creates the ledger and a dated entry, then Go
|
|
17
|
+
// appends another. Only stdout ("learnings: recorded.") and exit 0 belong to
|
|
18
|
+
// the contract because the dated file entry is nondeterministic.
|
|
20
19
|
addw := t.TempDir()
|
|
20
|
+
mkdirAllT(t, addw, ".devrites")
|
|
21
21
|
t.Run("add", func(t *testing.T) {
|
|
22
22
|
(parityCase{
|
|
23
23
|
workdir: addw, env: libRootEnv(addw),
|
|
@@ -25,7 +25,7 @@ func TestParityLearnings(t *testing.T) {
|
|
|
25
25
|
}).assertEqual(t)
|
|
26
26
|
})
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// List a prepared ledger. Both implementations print the file unchanged.
|
|
29
29
|
listw := t.TempDir()
|
|
30
30
|
writeFile(t, listw, filepath.Join(".devrites", "learnings.md"),
|
|
31
31
|
"# DevRites learnings ledger\n\n"+
|
|
@@ -38,10 +38,9 @@ func TestParityLearnings(t *testing.T) {
|
|
|
38
38
|
}).assertEqual(t)
|
|
39
39
|
})
|
|
40
40
|
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
// count 2. Distinct counts ⇒ deterministic order on any `sort`.
|
|
41
|
+
// Mine and nudge use two archived features. Normalization strips IDs, paths,
|
|
42
|
+
// and numbers, so "recurring finding" has count 3 and "second dead end" has
|
|
43
|
+
// count 2. The distinct counts keep sort order stable.
|
|
45
44
|
arch := t.TempDir()
|
|
46
45
|
writeFile(t, arch, filepath.Join(".devrites", "archive", "feat-a", "decisions.md"),
|
|
47
46
|
"# decisions for feat-a\n"+
|
|
@@ -55,7 +54,7 @@ func TestParityLearnings(t *testing.T) {
|
|
|
55
54
|
"- second dead end: retry backoff exceeded 9 attempts\n"+
|
|
56
55
|
"- a one-off dismiss note about the flaky linter run\n")
|
|
57
56
|
|
|
58
|
-
//
|
|
57
|
+
// Both implementations resolve the default archive to the same directory.
|
|
59
58
|
t.Run("mine", func(t *testing.T) {
|
|
60
59
|
(parityCase{
|
|
61
60
|
workdir: arch, env: libRootEnv(arch),
|
|
@@ -63,8 +62,8 @@ func TestParityLearnings(t *testing.T) {
|
|
|
63
62
|
}).assertEqual(t)
|
|
64
63
|
})
|
|
65
64
|
|
|
66
|
-
//
|
|
67
|
-
//
|
|
65
|
+
// Both implementations resolve an explicit relative path against workdir, so
|
|
66
|
+
// the missing path in the message is identical.
|
|
68
67
|
t.Run("mine-no-archive", func(t *testing.T) {
|
|
69
68
|
(parityCase{
|
|
70
69
|
workdir: arch, env: libRootEnv(arch),
|
|
@@ -72,7 +71,7 @@ func TestParityLearnings(t *testing.T) {
|
|
|
72
71
|
}).assertEqual(t)
|
|
73
72
|
})
|
|
74
73
|
|
|
75
|
-
//
|
|
74
|
+
// Two features, three occurrences, and no review marker produce a nudge.
|
|
76
75
|
t.Run("nudge", func(t *testing.T) {
|
|
77
76
|
(parityCase{
|
|
78
77
|
workdir: arch, env: libRootEnv(arch),
|
|
@@ -80,7 +79,7 @@ func TestParityLearnings(t *testing.T) {
|
|
|
80
79
|
}).assertEqual(t)
|
|
81
80
|
})
|
|
82
81
|
|
|
83
|
-
//
|
|
82
|
+
// An unknown command writes usage to stderr and exits 2 without stdout.
|
|
84
83
|
t.Run("unknown", func(t *testing.T) {
|
|
85
84
|
(parityCase{
|
|
86
85
|
workdir: arch, env: libRootEnv(arch),
|
|
@@ -2,14 +2,15 @@ package main_test
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"fmt"
|
|
5
|
+
"strings"
|
|
5
6
|
"testing"
|
|
6
7
|
)
|
|
7
8
|
|
|
8
9
|
// TestParityReconcile checks reconcile against the golden snapshots: snapshot
|
|
9
|
-
// captures the worktree as a tree object, check diffs it and flags
|
|
10
|
-
// outside the
|
|
11
|
-
//
|
|
12
|
-
//
|
|
10
|
+
// captures the worktree as a tree object, check diffs it and flags changes
|
|
11
|
+
// outside the orchestrator-authored allowlist, and close ends the retained
|
|
12
|
+
// post-slice baseline. It runs Git in a real repository, so stdout and exit are
|
|
13
|
+
// captured from the live command.
|
|
13
14
|
func TestParityReconcile(t *testing.T) {
|
|
14
15
|
requireGit(t)
|
|
15
16
|
|
|
@@ -25,7 +26,12 @@ func TestParityReconcile(t *testing.T) {
|
|
|
25
26
|
}
|
|
26
27
|
// snapshot is also a setup step for the check-* cases, so it snapshots under a
|
|
27
28
|
// distinct key to avoid colliding with check's golden in the same subtest.
|
|
28
|
-
snapshot := func(t *testing.T, work string) {
|
|
29
|
+
snapshot := func(t *testing.T, work string, allowed ...string) {
|
|
30
|
+
body := ""
|
|
31
|
+
if len(allowed) > 0 {
|
|
32
|
+
body = strings.Join(allowed, "\n") + "\n"
|
|
33
|
+
}
|
|
34
|
+
writeFeatureFile(t, work, "feat", ".wright-allowlist", body)
|
|
29
35
|
out, code := runArgv(t, work, libRootEnv(work), "", binPath, "reconcile", "snapshot", "feat")
|
|
30
36
|
assertGoldenKey(t, t.Name()+"/snapshot", fmt.Sprintf("exit %d\n%s", code, out))
|
|
31
37
|
}
|
|
@@ -38,38 +44,35 @@ func TestParityReconcile(t *testing.T) {
|
|
|
38
44
|
|
|
39
45
|
t.Run("check-clean", func(t *testing.T) {
|
|
40
46
|
work := newRepo(t)
|
|
41
|
-
snapshot(t, work)
|
|
47
|
+
snapshot(t, work, "src/a.js")
|
|
42
48
|
writeFile(t, work, "src/a.js", "console.log(999)\n") // the wright's change
|
|
43
|
-
writeFeatureFile(t, work, "feat", ".reconcile-claimed", "src/a.js\n")
|
|
44
49
|
check(t, work)
|
|
45
50
|
})
|
|
46
51
|
|
|
47
52
|
t.Run("check-violation", func(t *testing.T) {
|
|
48
53
|
work := newRepo(t)
|
|
49
|
-
snapshot(t, work)
|
|
54
|
+
snapshot(t, work, "src/a.js")
|
|
50
55
|
writeFile(t, work, "src/a.js", "console.log(999)\n")
|
|
51
|
-
writeFile(t, work, "src/b.js", "console.log(888)\n") //
|
|
52
|
-
writeFeatureFile(t, work, "feat", ".reconcile-claimed", "src/a.js\n")
|
|
56
|
+
writeFile(t, work, "src/b.js", "console.log(888)\n") // Outside the allowlist; an A1 breach.
|
|
53
57
|
check(t, work)
|
|
54
58
|
})
|
|
55
59
|
|
|
56
60
|
t.Run("check-no-base", func(t *testing.T) {
|
|
57
61
|
work := newRepo(t)
|
|
58
|
-
|
|
59
|
-
check(t, work) // no snapshot -> exit 6
|
|
62
|
+
check(t, work) // No snapshot, so exit 6.
|
|
60
63
|
})
|
|
61
64
|
|
|
62
|
-
t.Run("
|
|
65
|
+
t.Run("snapshot-no-allowlist", func(t *testing.T) {
|
|
63
66
|
work := newRepo(t)
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
out, code := runArgv(t, work, libRootEnv(work), "", binPath, "reconcile", "snapshot", "feat")
|
|
68
|
+
assertGolden(t, out, code)
|
|
66
69
|
})
|
|
67
70
|
|
|
68
71
|
t.Run("inline-fallback", func(t *testing.T) {
|
|
69
72
|
work := newRepo(t)
|
|
70
73
|
snapshot(t, work)
|
|
71
|
-
|
|
72
|
-
|
|
74
|
+
out, code := runArgv(t, work, libRootEnv(work), "", binPath, "reconcile", "close", "feat")
|
|
75
|
+
assertGolden(t, out, code)
|
|
73
76
|
})
|
|
74
77
|
|
|
75
78
|
t.Run("not-git", func(t *testing.T) {
|
|
@@ -7,8 +7,8 @@ import (
|
|
|
7
7
|
"testing"
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
// Golden
|
|
11
|
-
//
|
|
10
|
+
// Golden snapshots for resolve include its changes to questions.md and state.md.
|
|
11
|
+
// Each case records stdout and the exit code. Mutating cases also record the
|
|
12
12
|
// resulting file bytes. The two nondeterministic timestamp fields (answered_at
|
|
13
13
|
// and the Log entry) are masked out before the file content is snapshotted so the
|
|
14
14
|
// golden is deterministic across runs.
|
|
@@ -45,8 +45,8 @@ const resolveState = `- Status: awaiting_human
|
|
|
45
45
|
`
|
|
46
46
|
|
|
47
47
|
func TestParityResolve(t *testing.T) {
|
|
48
|
-
// setup writes
|
|
49
|
-
//
|
|
48
|
+
// setup writes fixtures under .devrites/features/feat and returns the
|
|
49
|
+
// workspace root.
|
|
50
50
|
setup := func(t *testing.T, questions, state string) (gwork string) {
|
|
51
51
|
t.Helper()
|
|
52
52
|
gwork = t.TempDir()
|
|
@@ -55,7 +55,7 @@ func TestParityResolve(t *testing.T) {
|
|
|
55
55
|
writeFile(t, gwork, filepath.Join(".devrites", "ACTIVE"), "feat\n")
|
|
56
56
|
return gwork
|
|
57
57
|
}
|
|
58
|
-
// run executes resolve in gwork and snapshots
|
|
58
|
+
// run executes resolve in gwork and snapshots stdout and the exit code under the
|
|
59
59
|
// current subtest's golden.
|
|
60
60
|
run := func(t *testing.T, gwork string, args ...string) {
|
|
61
61
|
t.Helper()
|
|
@@ -124,16 +124,17 @@ answer: prior
|
|
|
124
124
|
})
|
|
125
125
|
|
|
126
126
|
t.Run("no-workspace", func(t *testing.T) {
|
|
127
|
-
//
|
|
127
|
+
// A bare tree with no explicit root, ACTIVE, or questions.md exits 2.
|
|
128
|
+
// Pointing DEVRITES_ROOT at the nonexistent .devrites child would instead
|
|
129
|
+
// be an explicit unsafe-root refusal, which is a different contract.
|
|
128
130
|
gwork := t.TempDir()
|
|
129
|
-
|
|
131
|
+
out, code := runArgv(t, gwork, libEnv, "", binPath, "resolve", "q-1", "x")
|
|
132
|
+
assertGolden(t, out, code)
|
|
130
133
|
})
|
|
131
134
|
|
|
132
135
|
t.Run("next-qid", func(t *testing.T) {
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
// boundaries: without it the qid tracks the real date and the snapshot
|
|
136
|
-
// fails every day but the one it was recorded on (ADR-0006, clock seam).
|
|
136
|
+
// DEVRITES_NOW fixes the date used by next-qid so the snapshot stays stable.
|
|
137
|
+
// See ADR-0006.
|
|
137
138
|
dir := t.TempDir()
|
|
138
139
|
writeFile(t, dir, "questions.md", "## q-2024-01-01-001\nstatus: open\n")
|
|
139
140
|
qpath := filepath.Join(dir, "questions.md")
|