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
package/docs/usage.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
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. `/rite-upgrade [slug]` is the
|
|
9
|
+
conditional maintenance route for an active workspace planned under older
|
|
10
|
+
DevRites rules.
|
|
8
11
|
|
|
9
12
|
- **Full command reference** → [`command-map.md`](command-map.md)
|
|
10
13
|
- **Flow diagrams** → [`flow.md`](flow.md)
|
|
@@ -14,15 +17,16 @@ Workspace-operating phases read the active workspace (`.devrites/ACTIVE` →
|
|
|
14
17
|
## The workspace
|
|
15
18
|
|
|
16
19
|
`/rite-spec` creates `.devrites/work/<slug>/` and writes the spec.
|
|
17
|
-
`/rite-define` adds the
|
|
18
|
-
|
|
19
|
-
sessions:
|
|
20
|
+
`/rite-clarify` adds decision coverage, `/rite-define` adds the plan, and
|
|
21
|
+
`/rite-vet` adds implementation readiness. These human-readable files preserve
|
|
22
|
+
the work across compaction and new sessions:
|
|
20
23
|
|
|
21
24
|
| File | Created by | Holds |
|
|
22
25
|
|---|---|---|
|
|
23
26
|
| `README.md` / `index.md` / `feature.md` | `/rite-spec` | compact workspace map: phase, status, next action, artifact map, read-next table, gates |
|
|
24
27
|
| `brief.md` | `/rite-spec` | one-line objective + definition of done |
|
|
25
28
|
| `spec.md` | `/rite-spec` | product WHAT/WHY, requirements, acceptance, boundaries, measurable success |
|
|
29
|
+
| `decision-coverage.md` | `/rite-clarify` | topology-first coverage plus semantic `CLEAR` verdict bound to all decision inputs and the current readiness-artifact contract |
|
|
26
30
|
| `architecture.md` | `/rite-define` | owning module/layer, integration points, data/API/events, dependencies, risks |
|
|
27
31
|
| `flows.md` | `/rite-spec` or `/rite-define` | optional Mermaid diagrams when sequence/state/data flow clarifies behavior |
|
|
28
32
|
| `references/` + `references.md` | `/rite-spec` | saved design refs: screenshots, Figma, video, links |
|
|
@@ -30,9 +34,11 @@ sessions:
|
|
|
30
34
|
| `plan.md` | `/rite-define` | approach, dependency graph, checkpoints, rollback |
|
|
31
35
|
| `tasks.md` | `/rite-define` | ordered `SLICE-###` vertical slices, each mapped to `AC-###` and tagged `Mode: AFK \| HITL` + gate fields |
|
|
32
36
|
| `traceability.md` | `/rite-define` | AC/REQ → slices → tests/proofs → evidence → touched files matrix |
|
|
33
|
-
| `eng-review.md` | `/rite-vet` | mandatory engineering
|
|
34
|
-
| `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
|
+
| `eng-review.md` | `/rite-vet` | mandatory engineering review with semantic, input-digest-bound readiness verdict and readiness-artifact contract |
|
|
38
|
+
| `test-plan.md` | `/rite-vet` | build-readable coverage target and readiness-artifact contract: coverage diagram, per-gap test requirements, acceptance→test map (read by `/rite-build` + `/rite-prove`) |
|
|
39
|
+
| `state.md` | every phase | working cursor: phase, status, next action, slice, AFK budget, durable clarification return fields, and `Awaiting human` only when paused |
|
|
40
|
+
| `recovery-attempts.jsonl` | technical recovery | durable three-failure budget per root-cause fingerprint |
|
|
41
|
+
| `.wright-allowlist` | `/rite-build` root | exact normalized source/test paths the sole wright may change |
|
|
36
42
|
| `status.md` | every phase | compatibility alias for the canonical `state.md` cursor |
|
|
37
43
|
| `questions.md` | every phase | append-only Q&A: qid, slice, gate, status (`open` / `answered` / `dropped`), proposed answer, raised/answered timestamps |
|
|
38
44
|
| `decisions.md` / `assumptions.md` | every phase | running logs |
|
|
@@ -49,14 +55,19 @@ sessions:
|
|
|
49
55
|
|
|
50
56
|
When `/rite-ship` closes the task, it archives the whole workspace from
|
|
51
57
|
`.devrites/work/<slug>/` to `.devrites/archive/<slug>/` and clears
|
|
52
|
-
`.devrites/ACTIVE`.
|
|
53
|
-
|
|
58
|
+
`.devrites/ACTIVE`. Every Markdown file remains in
|
|
59
|
+
`.devrites/archive/<slug>/` as an audit trail.
|
|
54
60
|
|
|
55
61
|
Backward compatibility: older `.devrites/features/<slug>/` workspaces remain
|
|
56
62
|
readable; migration should add the canonical `.devrites/work` shape without
|
|
57
63
|
deleting the old files. `feature.md`/`index.md` can still act as the workspace
|
|
58
64
|
map, `status.md` as the cursor alias for `state.md`, and `proof.md` as the proof
|
|
59
|
-
alias for `evidence.md`.
|
|
65
|
+
alias for `evidence.md`. Workspace maps use schema v2; migration upgrades
|
|
66
|
+
compatible declarations but never fabricates clarification, readiness, or proof
|
|
67
|
+
evidence. That structural schema is separate from the semantic planning
|
|
68
|
+
contract. `/rite-upgrade` reconciles active unfinished planning with
|
|
69
|
+
`devrites.readiness-artifacts.v2`; it does not rewrite current, completed, or
|
|
70
|
+
archived workspaces.
|
|
60
71
|
|
|
61
72
|
Project-root sentinel (outside the workspace):
|
|
62
73
|
|
|
@@ -81,6 +92,10 @@ You: I want some kind of reporting thing for admins.
|
|
|
81
92
|
→ gathers any design references you give
|
|
82
93
|
→ writes spec.md (creates the workspace)
|
|
83
94
|
|
|
95
|
+
/rite-clarify
|
|
96
|
+
→ scans the full topology; asks zero questions when the contract is complete
|
|
97
|
+
→ writes fresh Decision coverage: CLEAR
|
|
98
|
+
|
|
84
99
|
/rite-define
|
|
85
100
|
→ reads the approved spec
|
|
86
101
|
→ writes plan.md + vertical task slices + state
|
|
@@ -95,7 +110,8 @@ You: I want some kind of reporting thing for admins.
|
|
|
95
110
|
|
|
96
111
|
```text
|
|
97
112
|
/rite-spec add-csv-export # investigate → spec.md
|
|
98
|
-
/rite-
|
|
113
|
+
/rite-clarify # topology scan → Decision coverage: CLEAR
|
|
114
|
+
/rite-define # clarified spec → plan + vertical slices + state
|
|
99
115
|
/rite-vet # mandatory plan review; light or full based on stakes
|
|
100
116
|
/rite-build # slice 1 ("export endpoint returns CSV"); stops with evidence
|
|
101
117
|
/rite-build # slice 2 ("download button + states"); repeat for each slice
|
|
@@ -106,10 +122,34 @@ You: I want some kind of reporting thing for admins.
|
|
|
106
122
|
/rite-ship # type-GO + irreversible git ladder + close the task (archive + clear ACTIVE)
|
|
107
123
|
```
|
|
108
124
|
|
|
109
|
-
`/rite-build` never
|
|
125
|
+
`/rite-build` never starts the next slice automatically; you decide when it
|
|
126
|
+
runs. For each slice, the root writes an exact `.wright-allowlist`. The snapshot,
|
|
127
|
+
reconciliation check, test/package integrity, and close steps use the same
|
|
128
|
+
original baseline. A retry snapshot refreshes only the dispatch boundary.
|
|
110
129
|
`/rite-seal` **decides**; `/rite-ship` **executes + closes**. To run the whole
|
|
111
130
|
sequence unattended, see `/rite-autocomplete` (§11).
|
|
112
131
|
|
|
132
|
+
## 2a) Continue a workspace planned under older rules
|
|
133
|
+
|
|
134
|
+
Run the upgrade after updating DevRites when build readiness reports code `8`,
|
|
135
|
+
or invoke it directly for an older active workspace:
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
/rite-upgrade ark-panda-redesign
|
|
139
|
+
→ a fresh read-only devrites-upgrade-planner compares the active unfinished
|
|
140
|
+
planning surface with devrites.readiness-artifacts.v2
|
|
141
|
+
→ completed source, slices, decisions, and evidence stay unchanged
|
|
142
|
+
→ stale old-engine proof recipes and machine-local command wrappers leave the
|
|
143
|
+
active canonical plan
|
|
144
|
+
→ current coverage and engineering-readiness gates run again
|
|
145
|
+
→ an already-current workspace that passes readiness is a no-op; completed
|
|
146
|
+
workspaces and archives are also left alone
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
This is not the same as `devrites-engine update`, which refreshes the installed
|
|
150
|
+
engine and pack, or `devrites-engine migrate`, which normalizes workspace layout
|
|
151
|
+
and structural state schema.
|
|
152
|
+
|
|
113
153
|
## 3) Spec drift mid-build
|
|
114
154
|
|
|
115
155
|
```text
|
|
@@ -133,7 +173,7 @@ sequence unattended, see `/rite-autocomplete` (§11).
|
|
|
133
173
|
You: 2
|
|
134
174
|
|
|
135
175
|
/rite-plan repair # updates spec/plan/tasks to per-session, marks drift resolved
|
|
136
|
-
/rite-
|
|
176
|
+
/rite-vet # rechecks the repaired plan before build
|
|
137
177
|
```
|
|
138
178
|
|
|
139
179
|
## 4) UI feature with Playwright MCP
|
|
@@ -170,14 +210,16 @@ You: 2
|
|
|
170
210
|
/rite-ship
|
|
171
211
|
```
|
|
172
212
|
|
|
173
|
-
If
|
|
174
|
-
|
|
213
|
+
If browser tooling is unavailable, the proof records exact manual steps and a
|
|
214
|
+
status of **pending (manual)**. The seal then accounts for the remaining UI
|
|
215
|
+
risk.
|
|
175
216
|
|
|
176
217
|
## 5) Backend-only feature
|
|
177
218
|
|
|
178
219
|
```text
|
|
179
220
|
/rite-spec rate-limit-api # investigate → spec.md (no UI)
|
|
180
|
-
/rite-
|
|
221
|
+
/rite-clarify # topology scan; zero questions when already complete
|
|
222
|
+
/rite-define # clarified spec → plan + slices
|
|
181
223
|
/rite-vet # mandatory plan review; checks architecture, tests, perf
|
|
182
224
|
/rite-build # no UI → no frontend craft / browser proof
|
|
183
225
|
/rite-prove # targeted tests + build/typecheck; runtime check of the limiter
|
|
@@ -225,7 +267,7 @@ Other modes: `quieter` · `distill` · `harden`.
|
|
|
225
267
|
→ the next session (or a fresh agent) reads the workspace alone
|
|
226
268
|
```
|
|
227
269
|
|
|
228
|
-
Run before `/clear`
|
|
270
|
+
Run this before `/clear` or a break of more than a few hours.
|
|
229
271
|
|
|
230
272
|
## 9) HITL gate: pre-code pause and resume
|
|
231
273
|
|
|
@@ -234,17 +276,17 @@ Run before `/clear` if leaving for > a few hours.
|
|
|
234
276
|
→ reads tasks.md slice 03; Mode: HITL, Gate: blocking
|
|
235
277
|
→ STOPS before writing any code:
|
|
236
278
|
|
|
237
|
-
SLICE-003:
|
|
238
|
-
Checkpoint:
|
|
239
|
-
Proposed approach:
|
|
240
|
-
|
|
241
|
-
|
|
279
|
+
SLICE-003: export policy is HITL (blocking, SLA 15m).
|
|
280
|
+
Checkpoint: Should deactivated users appear in the admin export?
|
|
281
|
+
Proposed approach: exclude them by default and expose an explicit
|
|
282
|
+
include-deactivated filter; this changes visible product behavior.
|
|
283
|
+
Product decision needed before this slice can build.
|
|
242
284
|
Resume: /rite-resolve q-2026-05-28-001 "<answer>"
|
|
243
285
|
|
|
244
286
|
→ appends q-...-001 to questions.md (status: open, gate: blocking)
|
|
245
287
|
→ writes `Awaiting human` block to state.md, sets Status: awaiting_human
|
|
246
288
|
|
|
247
|
-
You: /rite-resolve q-2026-05-28-001 "
|
|
289
|
+
You: /rite-resolve q-2026-05-28-001 "exclude by default; add the filter"
|
|
248
290
|
|
|
249
291
|
/rite-resolve
|
|
250
292
|
→ flips q-...-001 status → answered (with answered_at + answer)
|
|
@@ -288,9 +330,12 @@ EOF
|
|
|
288
330
|
/rite-build # continue
|
|
289
331
|
```
|
|
290
332
|
|
|
291
|
-
The loop
|
|
292
|
-
|
|
293
|
-
|
|
333
|
+
The loop does not mark a slice `built` while tests, type checks, or lint are
|
|
334
|
+
red. It uses the same wright and durable three-failure recovery budget for each
|
|
335
|
+
root-cause fingerprint. If the budget runs out, it records a blocker with the
|
|
336
|
+
reproduction and unsuccessful approaches instead of asking for retry approval.
|
|
337
|
+
AFK never silently accepts
|
|
338
|
+
genuine product, risk, or access decisions; see
|
|
294
339
|
[`pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md`](../pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md) for the
|
|
295
340
|
full list.
|
|
296
341
|
|
|
@@ -298,9 +343,9 @@ full list.
|
|
|
298
343
|
|
|
299
344
|
```text
|
|
300
345
|
/rite-autocomplete "add CSV export for admins" --max-slices 8
|
|
301
|
-
→ vague idea → runs devrites-interview
|
|
302
|
-
|
|
303
|
-
→ arms AFK, then drives
|
|
346
|
+
→ vague idea → runs devrites-interview, then /rite-spec + /rite-clarify in
|
|
347
|
+
the only interactive window
|
|
348
|
+
→ Decision coverage: CLEAR → arms AFK, then drives: /rite-temper →
|
|
304
349
|
/rite-define → /rite-vet → /rite-build ×N → /rite-prove → /rite-polish →
|
|
305
350
|
/rite-review → /rite-seal (→ /rite-ship too when --ship is set)
|
|
306
351
|
→ at each soft gate, picks the option the relevant specialist/reviewer
|
|
@@ -311,12 +356,12 @@ full list.
|
|
|
311
356
|
You: GO # → commit · push · tag, then archive + clear ACTIVE
|
|
312
357
|
```
|
|
313
358
|
|
|
314
|
-
Add `--ship` (alias `--yolo`) to
|
|
315
|
-
|
|
316
|
-
pauses
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
359
|
+
Add `--ship` (alias `--yolo`) to confirm the final type-`GO` automatically.
|
|
360
|
+
Autocomplete then proceeds directly to `/rite-ship` without another prompt. It
|
|
361
|
+
still pauses for genuine product/scope/policy decisions, irreversible risk,
|
|
362
|
+
human-only access/actions, a NO-GO, exhausted `max_slices`, or low confidence.
|
|
363
|
+
Objective red checks use bounded recovery instead. Args:
|
|
364
|
+
`[idea] [--ship|--yolo] [--max-slices N]`.
|
|
320
365
|
|
|
321
366
|
## Checking in
|
|
322
367
|
|
|
@@ -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
|
+
}
|