devrites 3.0.7 → 3.1.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 +12 -0
- package/README.md +67 -47
- 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/README.md +3 -0
- package/docs/agents/triage-labels.md +7 -7
- package/docs/architecture.md +157 -140
- package/docs/cli.md +41 -12
- package/docs/command-map.md +49 -35
- package/docs/engine/agent-contract.md +92 -15
- package/docs/engine/commands.md +242 -72
- package/docs/engine/state-schema.md +52 -23
- package/docs/engine/workspace-schema.md +94 -15
- package/docs/extensions.md +1 -1
- package/docs/flow.md +80 -50
- package/docs/harness-compliance.md +29 -5
- package/docs/orchestration.md +107 -79
- package/docs/quick-reference.md +7 -3
- package/docs/release.md +4 -3
- package/docs/skills.md +64 -38
- package/docs/usage.md +57 -38
- 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 +35 -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 +111 -0
- package/engine/internal/lib/readinessartifact.go +510 -0
- package/engine/internal/lib/readinessartifact_test.go +321 -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=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 +141 -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 +71 -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/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 +11 -9
- package/pack/.claude/skills/devrites-lib/reference/intent-map.md +3 -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 +198 -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 +23 -10
- package/pack/.claude/skills/devrites-source-driven/SKILL.md +23 -22
- package/pack/.claude/skills/rite/SKILL.md +8 -6
- package/pack/.claude/skills/rite/reference/menu.md +8 -6
- 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 +38 -38
- 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/wright-dispatch.md +129 -134
- package/pack/.claude/skills/rite-clarify/SKILL.md +89 -0
- package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +59 -0
- package/pack/.claude/skills/rite-converge/SKILL.md +35 -25
- package/pack/.claude/skills/rite-define/SKILL.md +57 -32
- package/pack/.claude/skills/rite-define/reference/gates.md +16 -15
- package/pack/.claude/skills/rite-define/reference/plan-template.md +16 -8
- package/pack/.claude/skills/rite-frame/reference/failure-modes.md +22 -24
- package/pack/.claude/skills/rite-plan/SKILL.md +44 -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-vet/SKILL.md +110 -113
- package/pack/.claude/skills/rite-vet/reference/artifacts.md +42 -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 +71 -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/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 +11 -9
- package/pack/generated/claude/skills/devrites-lib/reference/intent-map.md +3 -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 +198 -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 +23 -10
- package/pack/generated/claude/skills/devrites-source-driven/SKILL.md +23 -22
- package/pack/generated/claude/skills/rite/SKILL.md +8 -6
- package/pack/generated/claude/skills/rite/reference/menu.md +8 -6
- 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 +38 -38
- 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/wright-dispatch.md +129 -134
- package/pack/generated/claude/skills/rite-clarify/SKILL.md +89 -0
- package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +59 -0
- package/pack/generated/claude/skills/rite-converge/SKILL.md +35 -25
- package/pack/generated/claude/skills/rite-define/SKILL.md +57 -32
- package/pack/generated/claude/skills/rite-define/reference/gates.md +16 -15
- package/pack/generated/claude/skills/rite-define/reference/plan-template.md +16 -8
- package/pack/generated/claude/skills/rite-frame/reference/failure-modes.md +22 -24
- package/pack/generated/claude/skills/rite-plan/SKILL.md +44 -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-vet/SKILL.md +110 -113
- package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +42 -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 +77 -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/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 +18 -12
- package/pack/generated/codex/skills/devrites-lib/reference/intent-map.md +3 -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 +198 -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 +23 -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 +19 -13
- package/pack/generated/codex/skills/rite/reference/menu.md +8 -6
- 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 +38 -38
- 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/wright-dispatch.md +129 -134
- package/pack/generated/codex/skills/rite-clarify/SKILL.md +105 -0
- package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +59 -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 +64 -35
- package/pack/generated/codex/skills/rite-define/reference/gates.md +16 -15
- package/pack/generated/codex/skills/rite-define/reference/plan-template.md +16 -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 +51 -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-vet/SKILL.md +117 -116
- package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +42 -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 +414 -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
package/docs/usage.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Using DevRites
|
|
2
2
|
|
|
3
|
-
These examples
|
|
4
|
-
|
|
5
|
-
`/rite-quick` and `/rite-frame` handle bounded work outside the full feature
|
|
6
|
-
Workspace
|
|
7
|
-
`.devrites/work/<slug
|
|
3
|
+
These examples cover the common DevRites workflows. Start a new feature with
|
|
4
|
+
`/rite-spec` and bring an existing codebase in with `/rite-adopt`.
|
|
5
|
+
`/rite-quick` and `/rite-frame` handle bounded work outside the full feature
|
|
6
|
+
lifecycle. Workspace phases first read the active workspace from
|
|
7
|
+
`.devrites/ACTIVE` and `.devrites/work/<slug>/`. If none exists, they report the
|
|
8
|
+
command that can create or select one.
|
|
8
9
|
|
|
9
10
|
- **Full command reference** → [`command-map.md`](command-map.md)
|
|
10
11
|
- **Flow diagrams** → [`flow.md`](flow.md)
|
|
@@ -14,15 +15,16 @@ Workspace-operating phases read the active workspace (`.devrites/ACTIVE` →
|
|
|
14
15
|
## The workspace
|
|
15
16
|
|
|
16
17
|
`/rite-spec` creates `.devrites/work/<slug>/` and writes the spec.
|
|
17
|
-
`/rite-define` adds the
|
|
18
|
-
|
|
19
|
-
sessions:
|
|
18
|
+
`/rite-clarify` adds decision coverage, `/rite-define` adds the plan, and
|
|
19
|
+
`/rite-vet` adds implementation readiness. These human-readable files preserve
|
|
20
|
+
the work across compaction and new sessions:
|
|
20
21
|
|
|
21
22
|
| File | Created by | Holds |
|
|
22
23
|
|---|---|---|
|
|
23
24
|
| `README.md` / `index.md` / `feature.md` | `/rite-spec` | compact workspace map: phase, status, next action, artifact map, read-next table, gates |
|
|
24
25
|
| `brief.md` | `/rite-spec` | one-line objective + definition of done |
|
|
25
26
|
| `spec.md` | `/rite-spec` | product WHAT/WHY, requirements, acceptance, boundaries, measurable success |
|
|
27
|
+
| `decision-coverage.md` | `/rite-clarify` | topology-first coverage plus semantic `CLEAR` verdict bound to all decision inputs |
|
|
26
28
|
| `architecture.md` | `/rite-define` | owning module/layer, integration points, data/API/events, dependencies, risks |
|
|
27
29
|
| `flows.md` | `/rite-spec` or `/rite-define` | optional Mermaid diagrams when sequence/state/data flow clarifies behavior |
|
|
28
30
|
| `references/` + `references.md` | `/rite-spec` | saved design refs: screenshots, Figma, video, links |
|
|
@@ -30,9 +32,11 @@ sessions:
|
|
|
30
32
|
| `plan.md` | `/rite-define` | approach, dependency graph, checkpoints, rollback |
|
|
31
33
|
| `tasks.md` | `/rite-define` | ordered `SLICE-###` vertical slices, each mapped to `AC-###` and tagged `Mode: AFK \| HITL` + gate fields |
|
|
32
34
|
| `traceability.md` | `/rite-define` | AC/REQ → slices → tests/proofs → evidence → touched files matrix |
|
|
33
|
-
| `eng-review.md` | `/rite-vet` | mandatory engineering
|
|
35
|
+
| `eng-review.md` | `/rite-vet` | mandatory engineering review with semantic, input-digest-bound readiness verdict |
|
|
34
36
|
| `test-plan.md` | `/rite-vet` | build-readable coverage target: coverage diagram, per-gap test requirements, acceptance→test map (read by `/rite-build` + `/rite-prove`) |
|
|
35
|
-
| `state.md` | every phase | working
|
|
37
|
+
| `state.md` | every phase | working cursor: phase, status, next action, slice, AFK budget, durable clarification return fields, and `Awaiting human` only when paused |
|
|
38
|
+
| `recovery-attempts.jsonl` | technical recovery | durable three-failure budget per root-cause fingerprint |
|
|
39
|
+
| `.wright-allowlist` | `/rite-build` root | exact normalized source/test paths the sole wright may change |
|
|
36
40
|
| `status.md` | every phase | compatibility alias for the canonical `state.md` cursor |
|
|
37
41
|
| `questions.md` | every phase | append-only Q&A: qid, slice, gate, status (`open` / `answered` / `dropped`), proposed answer, raised/answered timestamps |
|
|
38
42
|
| `decisions.md` / `assumptions.md` | every phase | running logs |
|
|
@@ -49,14 +53,16 @@ sessions:
|
|
|
49
53
|
|
|
50
54
|
When `/rite-ship` closes the task, it archives the whole workspace from
|
|
51
55
|
`.devrites/work/<slug>/` to `.devrites/archive/<slug>/` and clears
|
|
52
|
-
`.devrites/ACTIVE`.
|
|
53
|
-
|
|
56
|
+
`.devrites/ACTIVE`. Every Markdown file remains in
|
|
57
|
+
`.devrites/archive/<slug>/` as an audit trail.
|
|
54
58
|
|
|
55
59
|
Backward compatibility: older `.devrites/features/<slug>/` workspaces remain
|
|
56
60
|
readable; migration should add the canonical `.devrites/work` shape without
|
|
57
61
|
deleting the old files. `feature.md`/`index.md` can still act as the workspace
|
|
58
62
|
map, `status.md` as the cursor alias for `state.md`, and `proof.md` as the proof
|
|
59
|
-
alias for `evidence.md`.
|
|
63
|
+
alias for `evidence.md`. Workspace maps use schema v2; migration upgrades
|
|
64
|
+
compatible declarations but never fabricates clarification, readiness, or proof
|
|
65
|
+
evidence.
|
|
60
66
|
|
|
61
67
|
Project-root sentinel (outside the workspace):
|
|
62
68
|
|
|
@@ -81,6 +87,10 @@ You: I want some kind of reporting thing for admins.
|
|
|
81
87
|
→ gathers any design references you give
|
|
82
88
|
→ writes spec.md (creates the workspace)
|
|
83
89
|
|
|
90
|
+
/rite-clarify
|
|
91
|
+
→ scans the full topology; asks zero questions when the contract is complete
|
|
92
|
+
→ writes fresh Decision coverage: CLEAR
|
|
93
|
+
|
|
84
94
|
/rite-define
|
|
85
95
|
→ reads the approved spec
|
|
86
96
|
→ writes plan.md + vertical task slices + state
|
|
@@ -95,7 +105,8 @@ You: I want some kind of reporting thing for admins.
|
|
|
95
105
|
|
|
96
106
|
```text
|
|
97
107
|
/rite-spec add-csv-export # investigate → spec.md
|
|
98
|
-
/rite-
|
|
108
|
+
/rite-clarify # topology scan → Decision coverage: CLEAR
|
|
109
|
+
/rite-define # clarified spec → plan + vertical slices + state
|
|
99
110
|
/rite-vet # mandatory plan review; light or full based on stakes
|
|
100
111
|
/rite-build # slice 1 ("export endpoint returns CSV"); stops with evidence
|
|
101
112
|
/rite-build # slice 2 ("download button + states"); repeat for each slice
|
|
@@ -106,7 +117,10 @@ You: I want some kind of reporting thing for admins.
|
|
|
106
117
|
/rite-ship # type-GO + irreversible git ladder + close the task (archive + clear ACTIVE)
|
|
107
118
|
```
|
|
108
119
|
|
|
109
|
-
`/rite-build` never
|
|
120
|
+
`/rite-build` never starts the next slice automatically; you decide when it
|
|
121
|
+
runs. For each slice, the root writes an exact `.wright-allowlist`. The snapshot,
|
|
122
|
+
reconciliation check, test/package integrity, and close steps use the same
|
|
123
|
+
original baseline. A retry snapshot refreshes only the dispatch boundary.
|
|
110
124
|
`/rite-seal` **decides**; `/rite-ship` **executes + closes**. To run the whole
|
|
111
125
|
sequence unattended, see `/rite-autocomplete` (§11).
|
|
112
126
|
|
|
@@ -133,7 +147,7 @@ sequence unattended, see `/rite-autocomplete` (§11).
|
|
|
133
147
|
You: 2
|
|
134
148
|
|
|
135
149
|
/rite-plan repair # updates spec/plan/tasks to per-session, marks drift resolved
|
|
136
|
-
/rite-
|
|
150
|
+
/rite-vet # rechecks the repaired plan before build
|
|
137
151
|
```
|
|
138
152
|
|
|
139
153
|
## 4) UI feature with Playwright MCP
|
|
@@ -170,14 +184,16 @@ You: 2
|
|
|
170
184
|
/rite-ship
|
|
171
185
|
```
|
|
172
186
|
|
|
173
|
-
If
|
|
174
|
-
|
|
187
|
+
If browser tooling is unavailable, the proof records exact manual steps and a
|
|
188
|
+
status of **pending (manual)**. The seal then accounts for the remaining UI
|
|
189
|
+
risk.
|
|
175
190
|
|
|
176
191
|
## 5) Backend-only feature
|
|
177
192
|
|
|
178
193
|
```text
|
|
179
194
|
/rite-spec rate-limit-api # investigate → spec.md (no UI)
|
|
180
|
-
/rite-
|
|
195
|
+
/rite-clarify # topology scan; zero questions when already complete
|
|
196
|
+
/rite-define # clarified spec → plan + slices
|
|
181
197
|
/rite-vet # mandatory plan review; checks architecture, tests, perf
|
|
182
198
|
/rite-build # no UI → no frontend craft / browser proof
|
|
183
199
|
/rite-prove # targeted tests + build/typecheck; runtime check of the limiter
|
|
@@ -225,7 +241,7 @@ Other modes: `quieter` · `distill` · `harden`.
|
|
|
225
241
|
→ the next session (or a fresh agent) reads the workspace alone
|
|
226
242
|
```
|
|
227
243
|
|
|
228
|
-
Run before `/clear`
|
|
244
|
+
Run this before `/clear` or a break of more than a few hours.
|
|
229
245
|
|
|
230
246
|
## 9) HITL gate: pre-code pause and resume
|
|
231
247
|
|
|
@@ -234,17 +250,17 @@ Run before `/clear` if leaving for > a few hours.
|
|
|
234
250
|
→ reads tasks.md slice 03; Mode: HITL, Gate: blocking
|
|
235
251
|
→ STOPS before writing any code:
|
|
236
252
|
|
|
237
|
-
SLICE-003:
|
|
238
|
-
Checkpoint:
|
|
239
|
-
Proposed approach:
|
|
240
|
-
|
|
241
|
-
|
|
253
|
+
SLICE-003: export policy is HITL (blocking, SLA 15m).
|
|
254
|
+
Checkpoint: Should deactivated users appear in the admin export?
|
|
255
|
+
Proposed approach: exclude them by default and expose an explicit
|
|
256
|
+
include-deactivated filter; this changes visible product behavior.
|
|
257
|
+
Product decision needed before this slice can build.
|
|
242
258
|
Resume: /rite-resolve q-2026-05-28-001 "<answer>"
|
|
243
259
|
|
|
244
260
|
→ appends q-...-001 to questions.md (status: open, gate: blocking)
|
|
245
261
|
→ writes `Awaiting human` block to state.md, sets Status: awaiting_human
|
|
246
262
|
|
|
247
|
-
You: /rite-resolve q-2026-05-28-001 "
|
|
263
|
+
You: /rite-resolve q-2026-05-28-001 "exclude by default; add the filter"
|
|
248
264
|
|
|
249
265
|
/rite-resolve
|
|
250
266
|
→ flips q-...-001 status → answered (with answered_at + answer)
|
|
@@ -288,9 +304,12 @@ EOF
|
|
|
288
304
|
/rite-build # continue
|
|
289
305
|
```
|
|
290
306
|
|
|
291
|
-
The loop
|
|
292
|
-
|
|
293
|
-
|
|
307
|
+
The loop does not mark a slice `built` while tests, type checks, or lint are
|
|
308
|
+
red. It uses the same wright and durable three-failure recovery budget for each
|
|
309
|
+
root-cause fingerprint. If the budget runs out, it records a blocker with the
|
|
310
|
+
reproduction and unsuccessful approaches instead of asking for retry approval.
|
|
311
|
+
AFK never silently accepts
|
|
312
|
+
genuine product, risk, or access decisions; see
|
|
294
313
|
[`pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md`](../pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md) for the
|
|
295
314
|
full list.
|
|
296
315
|
|
|
@@ -298,9 +317,9 @@ full list.
|
|
|
298
317
|
|
|
299
318
|
```text
|
|
300
319
|
/rite-autocomplete "add CSV export for admins" --max-slices 8
|
|
301
|
-
→ vague idea → runs devrites-interview
|
|
302
|
-
|
|
303
|
-
→ arms AFK, then drives
|
|
320
|
+
→ vague idea → runs devrites-interview, then /rite-spec + /rite-clarify in
|
|
321
|
+
the only interactive window
|
|
322
|
+
→ Decision coverage: CLEAR → arms AFK, then drives: /rite-temper →
|
|
304
323
|
/rite-define → /rite-vet → /rite-build ×N → /rite-prove → /rite-polish →
|
|
305
324
|
/rite-review → /rite-seal (→ /rite-ship too when --ship is set)
|
|
306
325
|
→ at each soft gate, picks the option the relevant specialist/reviewer
|
|
@@ -311,12 +330,12 @@ full list.
|
|
|
311
330
|
You: GO # → commit · push · tag, then archive + clear ACTIVE
|
|
312
331
|
```
|
|
313
332
|
|
|
314
|
-
Add `--ship` (alias `--yolo`) to
|
|
315
|
-
|
|
316
|
-
pauses
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
333
|
+
Add `--ship` (alias `--yolo`) to confirm the final type-`GO` automatically.
|
|
334
|
+
Autocomplete then proceeds directly to `/rite-ship` without another prompt. It
|
|
335
|
+
still pauses for genuine product/scope/policy decisions, irreversible risk,
|
|
336
|
+
human-only access/actions, a NO-GO, exhausted `max_slices`, or low confidence.
|
|
337
|
+
Objective red checks use bounded recovery instead. Args:
|
|
338
|
+
`[idea] [--ship|--yolo] [--max-slices N]`.
|
|
320
339
|
|
|
321
340
|
## Checking in
|
|
322
341
|
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// Command releasepack writes a deterministic tar.gz from a staged release tree.
|
|
2
|
+
package main
|
|
3
|
+
|
|
4
|
+
import (
|
|
5
|
+
"archive/tar"
|
|
6
|
+
"compress/gzip"
|
|
7
|
+
"errors"
|
|
8
|
+
"flag"
|
|
9
|
+
"fmt"
|
|
10
|
+
"io"
|
|
11
|
+
"math"
|
|
12
|
+
"os"
|
|
13
|
+
"path"
|
|
14
|
+
"path/filepath"
|
|
15
|
+
"sort"
|
|
16
|
+
"strconv"
|
|
17
|
+
"strings"
|
|
18
|
+
"time"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
type archiveEntry struct {
|
|
22
|
+
archiveName string
|
|
23
|
+
sourcePath string
|
|
24
|
+
info os.FileInfo
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func main() {
|
|
28
|
+
root := flag.String("root", "", "staged release tree")
|
|
29
|
+
output := flag.String("output", "", "output .tar.gz")
|
|
30
|
+
prefix := flag.String("prefix", "", "archive top-level directory")
|
|
31
|
+
epochText := flag.String("epoch", "0", "SOURCE_DATE_EPOCH")
|
|
32
|
+
flag.Parse()
|
|
33
|
+
|
|
34
|
+
epoch, err := strconv.ParseUint(*epochText, 10, 32)
|
|
35
|
+
if err != nil {
|
|
36
|
+
exitf("invalid epoch %q: %v", *epochText, err)
|
|
37
|
+
}
|
|
38
|
+
if *root == "" || *output == "" || *prefix == "" {
|
|
39
|
+
exitf("-root, -output, and -prefix are required")
|
|
40
|
+
}
|
|
41
|
+
if err := writeArchive(*root, *output, *prefix, time.Unix(int64(epoch), 0).UTC()); err != nil {
|
|
42
|
+
exitf("%v", err)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func exitf(format string, args ...any) {
|
|
47
|
+
fmt.Fprintf(os.Stderr, "releasepack: "+format+"\n", args...)
|
|
48
|
+
os.Exit(1)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
func writeArchive(root, output, prefix string, epoch time.Time) error {
|
|
52
|
+
if err := validatePrefix(prefix); err != nil {
|
|
53
|
+
return err
|
|
54
|
+
}
|
|
55
|
+
if epoch.Unix() < 0 || epoch.Unix() > math.MaxUint32 {
|
|
56
|
+
return fmt.Errorf("epoch must fit the gzip timestamp field")
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
canonicalRoot, err := filepath.EvalSymlinks(root)
|
|
60
|
+
if err != nil {
|
|
61
|
+
return fmt.Errorf("resolve root: %w", err)
|
|
62
|
+
}
|
|
63
|
+
canonicalRoot, err = filepath.Abs(canonicalRoot)
|
|
64
|
+
if err != nil {
|
|
65
|
+
return fmt.Errorf("resolve root: %w", err)
|
|
66
|
+
}
|
|
67
|
+
outputDir, err := filepath.EvalSymlinks(filepath.Dir(output))
|
|
68
|
+
if err != nil {
|
|
69
|
+
return fmt.Errorf("resolve output: %w", err)
|
|
70
|
+
}
|
|
71
|
+
output, err = filepath.Abs(filepath.Join(outputDir, filepath.Base(output)))
|
|
72
|
+
if err != nil {
|
|
73
|
+
return fmt.Errorf("resolve output: %w", err)
|
|
74
|
+
}
|
|
75
|
+
if within(canonicalRoot, output) {
|
|
76
|
+
return errors.New("output must be outside the staged release tree")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
entries, err := collectEntries(canonicalRoot, prefix)
|
|
80
|
+
if err != nil {
|
|
81
|
+
return err
|
|
82
|
+
}
|
|
83
|
+
if err := os.MkdirAll(filepath.Dir(output), 0o755); err != nil {
|
|
84
|
+
return fmt.Errorf("create output directory: %w", err)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
tmp, err := os.CreateTemp(filepath.Dir(output), "."+filepath.Base(output)+".tmp-*")
|
|
88
|
+
if err != nil {
|
|
89
|
+
return fmt.Errorf("create temporary archive: %w", err)
|
|
90
|
+
}
|
|
91
|
+
tmpName := tmp.Name()
|
|
92
|
+
defer os.Remove(tmpName)
|
|
93
|
+
if err := tmp.Chmod(0o644); err != nil {
|
|
94
|
+
return errors.Join(fmt.Errorf("set archive mode: %w", err), tmp.Close())
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
gz, err := gzip.NewWriterLevel(tmp, gzip.BestCompression)
|
|
98
|
+
if err != nil {
|
|
99
|
+
return errors.Join(fmt.Errorf("create gzip writer: %w", err), tmp.Close())
|
|
100
|
+
}
|
|
101
|
+
gz.Header.ModTime = epoch
|
|
102
|
+
gz.Header.OS = 255
|
|
103
|
+
tw := tar.NewWriter(gz)
|
|
104
|
+
|
|
105
|
+
writeErr := writeEntries(tw, entries, epoch)
|
|
106
|
+
if err := tw.Close(); writeErr == nil {
|
|
107
|
+
writeErr = err
|
|
108
|
+
}
|
|
109
|
+
if err := gz.Close(); writeErr == nil {
|
|
110
|
+
writeErr = err
|
|
111
|
+
}
|
|
112
|
+
if err := tmp.Close(); writeErr == nil {
|
|
113
|
+
writeErr = err
|
|
114
|
+
}
|
|
115
|
+
if writeErr != nil {
|
|
116
|
+
return fmt.Errorf("write archive: %w", writeErr)
|
|
117
|
+
}
|
|
118
|
+
if err := os.Remove(output); err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
119
|
+
return fmt.Errorf("replace output: %w", err)
|
|
120
|
+
}
|
|
121
|
+
if err := os.Rename(tmpName, output); err != nil {
|
|
122
|
+
return fmt.Errorf("publish archive: %w", err)
|
|
123
|
+
}
|
|
124
|
+
return nil
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
func validatePrefix(prefix string) error {
|
|
128
|
+
if prefix == "" || prefix == "." || path.IsAbs(prefix) || path.Clean(prefix) != prefix || strings.ContainsAny(prefix, `/\`) {
|
|
129
|
+
return fmt.Errorf("unsafe archive prefix %q", prefix)
|
|
130
|
+
}
|
|
131
|
+
return nil
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
func within(root, candidate string) bool {
|
|
135
|
+
rel, err := filepath.Rel(root, candidate)
|
|
136
|
+
return err == nil && (rel == "." || filepath.IsLocal(rel))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
func collectEntries(root, prefix string) ([]archiveEntry, error) {
|
|
140
|
+
var entries []archiveEntry
|
|
141
|
+
err := filepath.Walk(root, func(sourcePath string, info os.FileInfo, walkErr error) error {
|
|
142
|
+
if walkErr != nil {
|
|
143
|
+
return walkErr
|
|
144
|
+
}
|
|
145
|
+
if sourcePath == root {
|
|
146
|
+
entries = append(entries, archiveEntry{archiveName: prefix + "/", sourcePath: root, info: info})
|
|
147
|
+
return nil
|
|
148
|
+
}
|
|
149
|
+
rel, err := filepath.Rel(root, sourcePath)
|
|
150
|
+
if err != nil || !filepath.IsLocal(rel) {
|
|
151
|
+
return fmt.Errorf("path escapes staged release tree: %q", sourcePath)
|
|
152
|
+
}
|
|
153
|
+
if info.Mode()&os.ModeSymlink != 0 {
|
|
154
|
+
return fmt.Errorf("symlink is not allowed in release payload: %s", filepath.ToSlash(rel))
|
|
155
|
+
}
|
|
156
|
+
if !info.Mode().IsRegular() && !info.IsDir() {
|
|
157
|
+
return fmt.Errorf("unsupported release payload entry: %s (%s)", filepath.ToSlash(rel), info.Mode())
|
|
158
|
+
}
|
|
159
|
+
archiveRel := filepath.ToSlash(rel)
|
|
160
|
+
if strings.Contains(archiveRel, `\`) {
|
|
161
|
+
return fmt.Errorf("non-portable release payload path: %s", archiveRel)
|
|
162
|
+
}
|
|
163
|
+
name := path.Join(prefix, archiveRel)
|
|
164
|
+
if info.IsDir() {
|
|
165
|
+
name += "/"
|
|
166
|
+
}
|
|
167
|
+
entries = append(entries, archiveEntry{archiveName: name, sourcePath: sourcePath, info: info})
|
|
168
|
+
return nil
|
|
169
|
+
})
|
|
170
|
+
if err != nil {
|
|
171
|
+
return nil, fmt.Errorf("collect release payload: %w", err)
|
|
172
|
+
}
|
|
173
|
+
sort.Slice(entries, func(i, j int) bool {
|
|
174
|
+
return entries[i].archiveName < entries[j].archiveName
|
|
175
|
+
})
|
|
176
|
+
return entries, nil
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func writeEntries(tw *tar.Writer, entries []archiveEntry, epoch time.Time) error {
|
|
180
|
+
for _, entry := range entries {
|
|
181
|
+
mode := int64(0o644)
|
|
182
|
+
typeflag := byte(tar.TypeReg)
|
|
183
|
+
size := entry.info.Size()
|
|
184
|
+
if entry.info.IsDir() {
|
|
185
|
+
mode, typeflag, size = 0o755, tar.TypeDir, 0
|
|
186
|
+
} else if entry.info.Mode().Perm()&0o111 != 0 || path.Ext(entry.archiveName) == ".sh" {
|
|
187
|
+
mode = 0o755
|
|
188
|
+
}
|
|
189
|
+
header := &tar.Header{
|
|
190
|
+
Name: entry.archiveName,
|
|
191
|
+
Mode: mode,
|
|
192
|
+
Size: size,
|
|
193
|
+
ModTime: epoch,
|
|
194
|
+
AccessTime: epoch,
|
|
195
|
+
ChangeTime: epoch,
|
|
196
|
+
Typeflag: typeflag,
|
|
197
|
+
Format: tar.FormatPAX,
|
|
198
|
+
}
|
|
199
|
+
if err := tw.WriteHeader(header); err != nil {
|
|
200
|
+
return err
|
|
201
|
+
}
|
|
202
|
+
if typeflag != tar.TypeReg {
|
|
203
|
+
continue
|
|
204
|
+
}
|
|
205
|
+
file, err := os.Open(entry.sourcePath)
|
|
206
|
+
if err != nil {
|
|
207
|
+
return err
|
|
208
|
+
}
|
|
209
|
+
_, copyErr := io.Copy(tw, file)
|
|
210
|
+
closeErr := file.Close()
|
|
211
|
+
if copyErr != nil {
|
|
212
|
+
return copyErr
|
|
213
|
+
}
|
|
214
|
+
if closeErr != nil {
|
|
215
|
+
return closeErr
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return nil
|
|
219
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"archive/tar"
|
|
5
|
+
"bytes"
|
|
6
|
+
"compress/gzip"
|
|
7
|
+
"io"
|
|
8
|
+
"os"
|
|
9
|
+
"path/filepath"
|
|
10
|
+
"reflect"
|
|
11
|
+
"strings"
|
|
12
|
+
"testing"
|
|
13
|
+
"time"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
func TestWriteArchiveIsDeterministic(t *testing.T) {
|
|
17
|
+
t.Parallel()
|
|
18
|
+
epoch := time.Unix(1_700_000_000, 0).UTC()
|
|
19
|
+
firstRoot := makeTree(t, time.Unix(100, 0))
|
|
20
|
+
secondRoot := makeTree(t, time.Unix(2_000_000_000, 0))
|
|
21
|
+
firstArchive := filepath.Join(t.TempDir(), "release.tar.gz")
|
|
22
|
+
secondArchive := filepath.Join(t.TempDir(), "release.tar.gz")
|
|
23
|
+
|
|
24
|
+
if err := writeArchive(firstRoot, firstArchive, "devrites-v1.2.3", epoch); err != nil {
|
|
25
|
+
t.Fatal(err)
|
|
26
|
+
}
|
|
27
|
+
if err := writeArchive(secondRoot, secondArchive, "devrites-v1.2.3", epoch); err != nil {
|
|
28
|
+
t.Fatal(err)
|
|
29
|
+
}
|
|
30
|
+
firstBytes, err := os.ReadFile(firstArchive)
|
|
31
|
+
if err != nil {
|
|
32
|
+
t.Fatal(err)
|
|
33
|
+
}
|
|
34
|
+
secondBytes, err := os.ReadFile(secondArchive)
|
|
35
|
+
if err != nil {
|
|
36
|
+
t.Fatal(err)
|
|
37
|
+
}
|
|
38
|
+
if !bytes.Equal(firstBytes, secondBytes) {
|
|
39
|
+
t.Fatal("archives differ across source roots and mtimes")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
got := readArchive(t, firstArchive, epoch)
|
|
43
|
+
wantNames := []string{
|
|
44
|
+
"devrites-v1.2.3/",
|
|
45
|
+
"devrites-v1.2.3/README.md",
|
|
46
|
+
"devrites-v1.2.3/install.sh",
|
|
47
|
+
"devrites-v1.2.3/nested/",
|
|
48
|
+
"devrites-v1.2.3/nested/data.txt",
|
|
49
|
+
}
|
|
50
|
+
if !reflect.DeepEqual(got.names, wantNames) {
|
|
51
|
+
t.Fatalf("archive names = %#v, want %#v", got.names, wantNames)
|
|
52
|
+
}
|
|
53
|
+
if got.modes["devrites-v1.2.3/"] != 0o755 ||
|
|
54
|
+
got.modes["devrites-v1.2.3/install.sh"] != 0o755 ||
|
|
55
|
+
got.modes["devrites-v1.2.3/README.md"] != 0o644 {
|
|
56
|
+
t.Fatalf("archive modes = %#v", got.modes)
|
|
57
|
+
}
|
|
58
|
+
if got.contents["devrites-v1.2.3/install.sh"] != "#!/bin/sh\nexit 0\n" ||
|
|
59
|
+
got.contents["devrites-v1.2.3/nested/data.txt"] != "payload\n" {
|
|
60
|
+
t.Fatalf("archive contents = %#v", got.contents)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func TestWriteArchiveRejectsUnsafePaths(t *testing.T) {
|
|
65
|
+
t.Parallel()
|
|
66
|
+
root := t.TempDir()
|
|
67
|
+
if err := os.WriteFile(filepath.Join(root, "file"), []byte("safe"), 0o644); err != nil {
|
|
68
|
+
t.Fatal(err)
|
|
69
|
+
}
|
|
70
|
+
output := filepath.Join(t.TempDir(), "release.tar.gz")
|
|
71
|
+
|
|
72
|
+
if err := writeArchive(root, filepath.Join(root, "release.tar.gz"), "devrites-v1", time.Unix(0, 0)); err == nil {
|
|
73
|
+
t.Fatal("output inside the staged tree was accepted")
|
|
74
|
+
}
|
|
75
|
+
if err := writeArchive(root, output, "../escape", time.Unix(0, 0)); err == nil {
|
|
76
|
+
t.Fatal("escaping archive prefix was accepted")
|
|
77
|
+
}
|
|
78
|
+
if err := writeArchive(root, output, `devrites-v1\escape`, time.Unix(0, 0)); err == nil {
|
|
79
|
+
t.Fatal("non-portable archive prefix was accepted")
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
link := filepath.Join(root, "unsafe-link")
|
|
83
|
+
if err := os.Symlink(filepath.Join(t.TempDir(), "outside"), link); err != nil {
|
|
84
|
+
t.Skipf("symlinks unavailable: %v", err)
|
|
85
|
+
}
|
|
86
|
+
err := writeArchive(root, output, "devrites-v1", time.Unix(0, 0))
|
|
87
|
+
if err == nil || !strings.Contains(err.Error(), "symlink is not allowed") {
|
|
88
|
+
t.Fatalf("symlink error = %v", err)
|
|
89
|
+
}
|
|
90
|
+
if _, statErr := os.Stat(output); !os.IsNotExist(statErr) {
|
|
91
|
+
t.Fatalf("unsafe archive output exists: %v", statErr)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
func makeTree(t *testing.T, mtime time.Time) string {
|
|
96
|
+
t.Helper()
|
|
97
|
+
root := t.TempDir()
|
|
98
|
+
files := map[string]struct {
|
|
99
|
+
content string
|
|
100
|
+
mode os.FileMode
|
|
101
|
+
}{
|
|
102
|
+
"README.md": {"read me\n", 0o644},
|
|
103
|
+
"install.sh": {"#!/bin/sh\nexit 0\n", 0o644},
|
|
104
|
+
"nested/data.txt": {"payload\n", 0o644},
|
|
105
|
+
}
|
|
106
|
+
for name, file := range files {
|
|
107
|
+
fullPath := filepath.Join(root, name)
|
|
108
|
+
if err := os.MkdirAll(filepath.Dir(fullPath), 0o755); err != nil {
|
|
109
|
+
t.Fatal(err)
|
|
110
|
+
}
|
|
111
|
+
if err := os.WriteFile(fullPath, []byte(file.content), file.mode); err != nil {
|
|
112
|
+
t.Fatal(err)
|
|
113
|
+
}
|
|
114
|
+
if err := os.Chtimes(fullPath, mtime, mtime); err != nil {
|
|
115
|
+
t.Fatal(err)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return root
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type archiveContents struct {
|
|
122
|
+
names []string
|
|
123
|
+
modes map[string]int64
|
|
124
|
+
contents map[string]string
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
func readArchive(t *testing.T, archivePath string, epoch time.Time) archiveContents {
|
|
128
|
+
t.Helper()
|
|
129
|
+
file, err := os.Open(archivePath)
|
|
130
|
+
if err != nil {
|
|
131
|
+
t.Fatal(err)
|
|
132
|
+
}
|
|
133
|
+
defer file.Close()
|
|
134
|
+
gz, err := gzip.NewReader(file)
|
|
135
|
+
if err != nil {
|
|
136
|
+
t.Fatal(err)
|
|
137
|
+
}
|
|
138
|
+
defer gz.Close()
|
|
139
|
+
if !gz.ModTime.Equal(epoch) || gz.OS != 255 || gz.Name != "" || gz.Comment != "" || len(gz.Extra) != 0 {
|
|
140
|
+
t.Fatalf("gzip header is not normalized: %#v", gz.Header)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
got := archiveContents{modes: map[string]int64{}, contents: map[string]string{}}
|
|
144
|
+
tr := tar.NewReader(gz)
|
|
145
|
+
for {
|
|
146
|
+
header, err := tr.Next()
|
|
147
|
+
if err == io.EOF {
|
|
148
|
+
break
|
|
149
|
+
}
|
|
150
|
+
if err != nil {
|
|
151
|
+
t.Fatal(err)
|
|
152
|
+
}
|
|
153
|
+
got.names = append(got.names, header.Name)
|
|
154
|
+
got.modes[header.Name] = header.Mode
|
|
155
|
+
if header.Uid != 0 || header.Gid != 0 || header.Uname != "" || header.Gname != "" {
|
|
156
|
+
t.Fatalf("%s ownership is not normalized: %#v", header.Name, header)
|
|
157
|
+
}
|
|
158
|
+
if !header.ModTime.Equal(epoch) || !header.AccessTime.Equal(epoch) || !header.ChangeTime.Equal(epoch) {
|
|
159
|
+
t.Fatalf("%s timestamps are not normalized: %#v", header.Name, header)
|
|
160
|
+
}
|
|
161
|
+
if header.Typeflag == tar.TypeReg {
|
|
162
|
+
content, err := io.ReadAll(tr)
|
|
163
|
+
if err != nil {
|
|
164
|
+
t.Fatal(err)
|
|
165
|
+
}
|
|
166
|
+
got.contents[header.Name] = string(content)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return got
|
|
170
|
+
}
|