devrites 5.14.4 → 6.0.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 +17 -0
- package/NOTICE.md +6 -4
- package/README.md +77 -16
- package/SECURITY.md +25 -11
- package/bin/devrites.mjs +49 -15
- package/docs/adr/0001-go-engine-as-control-plane.md +6 -3
- package/docs/adr/0029-v5-workspace-schema-and-native-migration.md +9 -0
- package/docs/adr/README.md +3 -2
- package/docs/agents/issue-tracker.md +1 -1
- package/docs/architecture.md +6 -3
- package/docs/cli.md +32 -9
- package/docs/command-map.md +5 -3
- package/docs/engine/state-schema.md +1 -1
- package/docs/flow.md +1 -1
- package/docs/harness-compliance.md +2 -2
- package/docs/release.md +15 -11
- package/docs/usage.md +1 -1
- package/engine/commands.go +1 -1
- package/engine/go.mod +1 -1
- package/engine/help.go +41 -15
- package/engine/help_test.go +134 -0
- package/engine/internal/acceptance/acceptance_test.go +298 -7
- package/engine/internal/acceptance/approve.go +7 -2
- package/engine/internal/acceptance/cli.go +3 -0
- package/engine/internal/acceptance/evidence.go +69 -5
- package/engine/internal/acceptance/lint.go +1 -1
- package/engine/internal/acceptance/run.go +5 -3
- package/engine/internal/acceptance/scaffold.go +5 -16
- package/engine/internal/devritespaths/paths.go +7 -6
- package/engine/internal/devritespaths/paths_test.go +18 -0
- package/engine/internal/fsutil/copy.go +83 -49
- package/engine/internal/fsutil/copy_test.go +70 -109
- package/engine/internal/gate/gate.go +89 -16
- package/engine/internal/gate/gate_test.go +101 -0
- package/engine/internal/hostpack/hostpack.go +52 -2
- package/engine/internal/hostpack/hostpack_test.go +83 -2
- package/engine/internal/install/apply.go +59 -16
- package/engine/internal/install/binary.go +10 -1
- package/engine/internal/install/install_test.go +428 -0
- package/engine/internal/install/merge.go +69 -38
- package/engine/internal/install/preflight.go +7 -0
- package/engine/internal/install/uninstall.go +43 -4
- package/engine/internal/lib/claims.go +25 -4
- package/engine/internal/lib/claims_test.go +57 -0
- package/engine/internal/lib/closeout.go +41 -3
- package/engine/internal/lib/closeout_test.go +144 -0
- package/engine/internal/lib/context.go +8 -4
- package/engine/internal/lib/context_next_test.go +100 -0
- package/engine/internal/lib/detect.go +1 -1
- package/engine/internal/lib/detect_test.go +13 -0
- package/engine/internal/lib/diffscope.go +19 -9
- package/engine/internal/lib/dispatch.go +7 -0
- package/engine/internal/lib/dup.go +40 -37
- package/engine/internal/lib/dup_test.go +178 -0
- package/engine/internal/lib/manifest_union.go +4 -1
- package/engine/internal/lib/manifest_union_test.go +37 -0
- package/engine/internal/lib/metrics.go +4 -0
- package/engine/internal/lib/metrics_test.go +28 -0
- package/engine/internal/lib/migrate_test.go +59 -0
- package/engine/internal/lib/observe_budgets.go +25 -9
- package/engine/internal/lib/observe_budgets_test.go +254 -0
- package/engine/internal/lib/observe_summary.go +23 -2
- package/engine/internal/lib/open_visual.go +4 -2
- package/engine/internal/lib/open_visual_test.go +11 -0
- package/engine/internal/lib/regression.go +62 -23
- package/engine/internal/lib/regression_test.go +103 -0
- package/engine/internal/lib/resolve.go +36 -17
- package/engine/internal/lib/resolve_remediation_test.go +132 -0
- package/engine/internal/lib/skilltrust.go +0 -11
- package/engine/internal/lib/slicecheck.go +7 -5
- package/engine/internal/lib/slicecheck_test.go +18 -0
- package/engine/internal/lib/triggers.go +9 -3
- package/engine/internal/lib/triggers_test.go +23 -0
- package/engine/internal/lib/util.go +17 -3
- package/engine/internal/lib/util_test.go +104 -0
- package/engine/internal/lib/visual_outline.go +7 -3
- package/engine/internal/lib/visual_outline_test.go +28 -0
- package/engine/internal/lib/windows.go +13 -9
- package/engine/internal/lib/windows_test.go +98 -0
- package/engine/internal/lib/workspace_read.go +2 -11
- package/engine/internal/lib/workspace_read_test.go +102 -0
- package/engine/internal/markdowntext/markdowntext.go +194 -11
- package/engine/internal/markdowntext/testdata/structural.json +250 -0
- package/engine/internal/notes/cli.go +30 -12
- package/engine/internal/notes/notes.go +242 -39
- package/engine/internal/notes/notes_test.go +372 -0
- package/engine/internal/overhaul/admit/packet.go +89 -0
- package/engine/internal/overhaul/admit/packet_test.go +223 -0
- package/engine/internal/overhaul/admit/run.go +4 -0
- package/engine/internal/overhaul/bench/run.go +6 -0
- package/engine/internal/overhaul/bench/run_test.go +46 -0
- package/engine/internal/overhaul/overhaul.go +6 -1
- package/engine/internal/overhaul/ovio/ovio.go +10 -3
- package/engine/internal/overhaul/ovio/ovio_test.go +75 -0
- package/engine/internal/overhaul/packet/packet.go +208 -0
- package/engine/internal/overhaul/packet/packet_test.go +263 -0
- package/engine/internal/overhaul/records/check.go +6 -0
- package/engine/internal/overhaul/records/init.go +16 -5
- package/engine/internal/overhaul/records/records_test.go +4 -0
- package/engine/internal/overhaul/records/run.go +66 -0
- package/engine/internal/overhaul/records/run_test.go +77 -0
- package/engine/internal/overhaul/render/run.go +15 -11
- package/engine/internal/overhaul/render/run_test.go +463 -1
- package/engine/internal/overhaul/render/visual.go +95 -33
- package/engine/internal/overhaul/score/run.go +20 -0
- package/engine/internal/overhaul/score/run_test.go +156 -1
- package/engine/internal/overhaul/snapshot/run.go +78 -21
- package/engine/internal/overhaul/snapshot/run_test.go +344 -8
- package/engine/internal/parallel/cli.go +33 -20
- package/engine/internal/parallel/cli_test.go +59 -0
- package/engine/internal/parallel/git.go +39 -1
- package/engine/internal/parallel/ops.go +101 -11
- package/engine/internal/parallel/ops_test.go +552 -69
- package/engine/internal/parallel/parallel_test.go +31 -1
- package/engine/internal/parallel/pathdisjoint.go +19 -1
- package/engine/internal/parallel/pathdisjoint_test.go +72 -0
- package/engine/internal/parallel/select.go +6 -2
- package/engine/internal/release/release.go +13 -3
- package/engine/internal/release/release_test.go +208 -3
- package/engine/internal/rootfacts/facts.go +9 -0
- package/engine/internal/rootfacts/facts_test.go +38 -0
- package/engine/internal/state/acceptance.go +7 -1
- package/engine/internal/state/budgets.go +11 -10
- package/engine/internal/state/budgets_test.go +93 -0
- package/engine/internal/state/cursor.go +19 -8
- package/engine/internal/state/cursor_test.go +120 -0
- package/engine/internal/state/lock_unix.go +7 -1
- package/engine/internal/state/lock_windows.go +7 -1
- package/engine/internal/state/state_test.go +49 -18
- package/engine/internal/state/taskgraph.go +18 -4
- package/engine/internal/state/taskgraph_test.go +43 -0
- package/engine/internal/state/workspaceschema.go +16 -2
- package/engine/internal/state/workspaceschema_test.go +34 -0
- package/engine/internal/state/write.go +67 -6
- package/engine/internal/state/write_test.go +136 -0
- package/engine/internal/version/version_test.go +2 -0
- package/engine/main.go +8 -1
- package/engine/observation_contract_test.go +1 -1
- package/engine/root_routing_test.go +23 -1
- package/install.sh +132 -12
- package/pack/.claude/agents/devrites-spec-reviewer.md +2 -2
- package/pack/.claude/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/.claude/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/.claude/skills/devrites-interview/SKILL.md +4 -4
- package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +3 -2
- package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/.claude/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/.claude/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/.claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/.claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/.claude/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/.claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/.claude/skills/overhaul/SKILL.md +1 -1
- package/pack/.claude/skills/overhaul/references/orchestration.md +5 -3
- package/pack/.claude/skills/overhaul/references/records.md +39 -0
- package/pack/.claude/skills/overhaul/references/scoring.md +14 -4
- package/pack/.claude/skills/rite/reference/menu.md +1 -1
- package/pack/.claude/skills/rite-adopt/SKILL.md +8 -2
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/.claude/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/.claude/skills/rite-build/SKILL.md +2 -1
- package/pack/.claude/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/.claude/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/.claude/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/.claude/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +3 -2
- package/pack/.claude/skills/rite-clarify/SKILL.md +5 -4
- package/pack/.claude/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/.claude/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/.claude/skills/rite-converge/SKILL.md +2 -0
- package/pack/.claude/skills/rite-customize/SKILL.md +6 -4
- package/pack/.claude/skills/rite-define/SKILL.md +2 -0
- package/pack/.claude/skills/rite-define/reference/gates.md +8 -7
- package/pack/.claude/skills/rite-explain/SKILL.md +1 -1
- package/pack/.claude/skills/rite-explain/reference/intake.md +1 -1
- package/pack/.claude/skills/rite-fast/SKILL.md +1 -1
- package/pack/.claude/skills/rite-plan/SKILL.md +4 -3
- package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/.claude/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/.claude/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/.claude/skills/rite-resolve/SKILL.md +3 -3
- package/pack/.claude/skills/rite-seal/SKILL.md +4 -3
- package/pack/.claude/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/.claude/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/.claude/skills/rite-ship/SKILL.md +4 -2
- package/pack/.claude/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/.claude/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/.claude/skills/rite-spec/SKILL.md +2 -2
- package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/.claude/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/.claude/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/.claude/skills/rite-temper/SKILL.md +12 -9
- package/pack/.claude/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/.claude/skills/rite-temper/reference/significance.md +10 -3
- package/pack/.claude/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/.claude/skills/rite-vet/SKILL.md +4 -3
- package/pack/.claude/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/.claude/workflows/devrites-readonly-review.js +5 -4
- package/pack/generated/claude/agents/devrites-spec-reviewer.md +2 -2
- package/pack/generated/claude/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/claude/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/claude/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/claude/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +3 -2
- package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/claude/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/claude/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/claude/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/claude/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/claude/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/claude/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/claude/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/claude/skills/overhaul/references/records.md +39 -0
- package/pack/generated/claude/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/claude/skills/rite/reference/menu.md +1 -1
- package/pack/generated/claude/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/claude/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/claude/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/claude/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +3 -2
- package/pack/generated/claude/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/claude/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/claude/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/claude/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/claude/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/claude/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/claude/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/claude/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/claude/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/claude/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/claude/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/claude/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/claude/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/claude/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/claude/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/claude/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/claude/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/claude/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/claude/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/claude/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/claude/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/claude/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/claude/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/claude/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/claude/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/claude/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/claude/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/generated/claude/workflows/devrites-readonly-review.js +5 -4
- package/pack/generated/codex/AGENTS.md +1 -1
- package/pack/generated/codex/agents/devrites-spec-reviewer.toml +2 -2
- package/pack/generated/codex/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/codex/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/codex/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/codex/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +3 -2
- package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/codex/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/codex/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/codex/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/codex/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/codex/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/codex/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/codex/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/codex/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/codex/skills/overhaul/references/records.md +39 -0
- package/pack/generated/codex/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/codex/skills/rite/reference/menu.md +1 -1
- package/pack/generated/codex/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/codex/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/codex/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/codex/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +3 -2
- package/pack/generated/codex/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/codex/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/codex/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/codex/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/codex/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/codex/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/codex/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/codex/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/codex/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/codex/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/codex/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/codex/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/codex/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/codex/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/codex/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/codex/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/codex/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/codex/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/codex/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/codex/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/codex/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/codex/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/codex/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/codex/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/codex/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/codex/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/codex/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/generated/devin/AGENTS.md +1 -1
- package/pack/generated/devin/agents/devrites-spec-reviewer.md +2 -2
- package/pack/generated/devin/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/devin/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/devin/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/devin/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +3 -2
- package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/devin/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/devin/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/devin/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/devin/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/devin/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/devin/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/devin/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/devin/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/devin/skills/overhaul/references/records.md +39 -0
- package/pack/generated/devin/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/devin/skills/rite/reference/menu.md +1 -1
- package/pack/generated/devin/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/devin/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/devin/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/devin/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/devin/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/devin/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +3 -2
- package/pack/generated/devin/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/devin/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/devin/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/devin/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/devin/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/devin/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/devin/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/devin/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/devin/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/devin/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/devin/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/devin/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/devin/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/devin/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/devin/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/devin/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/devin/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/devin/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/devin/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/devin/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/devin/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/devin/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/devin/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/devin/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/devin/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/devin/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/devin/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/devin/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/devin/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/generated/omp/agents/devrites-spec-reviewer.md +2 -2
- package/pack/generated/omp/commands/rite-define.md +1 -1
- package/pack/generated/omp/commands/rite-handoff.md +1 -1
- package/pack/generated/omp/commands/rite-plan.md +1 -1
- package/pack/generated/omp/commands/rite-pressure-test.md +1 -1
- package/pack/generated/omp/commands/rite-quick.md +1 -1
- package/pack/generated/omp/commands/rite-status.md +1 -1
- package/pack/generated/omp/commands/rite-temper.md +1 -1
- package/pack/generated/omp/commands/rite-zoom-out.md +1 -1
- package/pack/generated/omp/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/omp/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/omp/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/omp/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +3 -2
- package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/omp/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/omp/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/omp/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/omp/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/omp/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/omp/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/omp/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/omp/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/omp/skills/overhaul/references/records.md +39 -0
- package/pack/generated/omp/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/omp/skills/rite/reference/menu.md +1 -1
- package/pack/generated/omp/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/omp/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/omp/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/omp/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/omp/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +3 -2
- package/pack/generated/omp/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/omp/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/omp/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/omp/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/omp/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/omp/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/omp/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/omp/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/omp/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/omp/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/omp/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/omp/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/omp/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/omp/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/omp/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/omp/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/omp/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/omp/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/omp/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/omp/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/omp/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/omp/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/omp/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/omp/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/omp/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/omp/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/omp/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/omp/skills/rite-vet/reference/artifacts.md +1 -1
- package/pack/generated/pi/AGENTS.md +1 -1
- package/pack/generated/pi/agents/devrites-spec-reviewer.md +2 -2
- package/pack/generated/pi/prompts/rite-define.md +1 -1
- package/pack/generated/pi/prompts/rite-handoff.md +1 -1
- package/pack/generated/pi/prompts/rite-plan.md +1 -1
- package/pack/generated/pi/prompts/rite-pressure-test.md +1 -1
- package/pack/generated/pi/prompts/rite-quick.md +1 -1
- package/pack/generated/pi/prompts/rite-status.md +1 -1
- package/pack/generated/pi/prompts/rite-temper.md +1 -1
- package/pack/generated/pi/prompts/rite-zoom-out.md +1 -1
- package/pack/generated/pi/skills/devrites-browser-proof/SKILL.md +2 -2
- package/pack/generated/pi/skills/devrites-frontend-craft/reference/design-references.md +18 -18
- package/pack/generated/pi/skills/devrites-frontend-craft/reference/quality-standards.md +6 -4
- package/pack/generated/pi/skills/devrites-interview/SKILL.md +4 -4
- package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +9 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +3 -2
- package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +6 -5
- package/pack/generated/pi/skills/devrites-lib/reference/standards/spec-grammar.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/verification-methods.md +3 -3
- package/pack/generated/pi/skills/devrites-lib/reference/standards/windows.md +3 -3
- package/pack/generated/pi/skills/devrites-lib/reference/standards/workflow-artifacts.md +2 -2
- package/pack/generated/pi/skills/devrites-lib/reference/visual-playbooks/outline-template.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +4 -4
- package/pack/generated/pi/skills/devrites-ux-shape/SKILL.md +11 -12
- package/pack/generated/pi/skills/devrites-ux-shape/reference/visual-direction-probe.md +3 -1
- package/pack/generated/pi/skills/overhaul/SKILL.md +1 -1
- package/pack/generated/pi/skills/overhaul/references/orchestration.md +5 -3
- package/pack/generated/pi/skills/overhaul/references/records.md +39 -0
- package/pack/generated/pi/skills/overhaul/references/scoring.md +14 -4
- package/pack/generated/pi/skills/rite/reference/menu.md +1 -1
- package/pack/generated/pi/skills/rite-adopt/SKILL.md +8 -2
- package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +11 -6
- package/pack/generated/pi/skills/rite-autocomplete/reference/decision-policy.md +3 -2
- package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +1 -1
- package/pack/generated/pi/skills/rite-autocomplete/reference/stop-conditions.md +6 -3
- package/pack/generated/pi/skills/rite-build/SKILL.md +2 -1
- package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/pi/skills/rite-build/reference/checkpoint-protocol.md +1 -1
- package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +5 -0
- package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +2 -2
- package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +3 -2
- package/pack/generated/pi/skills/rite-clarify/SKILL.md +5 -4
- package/pack/generated/pi/skills/rite-clarify/reference/anti-patterns.md +2 -2
- package/pack/generated/pi/skills/rite-clarify/reference/decision-coverage.md +3 -2
- package/pack/generated/pi/skills/rite-converge/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-customize/SKILL.md +6 -4
- package/pack/generated/pi/skills/rite-define/SKILL.md +2 -0
- package/pack/generated/pi/skills/rite-define/reference/gates.md +8 -7
- package/pack/generated/pi/skills/rite-explain/SKILL.md +1 -1
- package/pack/generated/pi/skills/rite-explain/reference/intake.md +1 -1
- package/pack/generated/pi/skills/rite-fast/SKILL.md +1 -1
- package/pack/generated/pi/skills/rite-plan/SKILL.md +4 -3
- package/pack/generated/pi/skills/rite-plan/reference/replan-and-repair.md +4 -4
- package/pack/generated/pi/skills/rite-polish/reference/anti-ai-slop.md +1 -1
- package/pack/generated/pi/skills/rite-prove/reference/browser-proof.md +5 -5
- package/pack/generated/pi/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/pi/skills/rite-seal/SKILL.md +4 -3
- package/pack/generated/pi/skills/rite-seal/reference/phase-contract.md +3 -2
- package/pack/generated/pi/skills/rite-seal/reference/seal-template.md +2 -0
- package/pack/generated/pi/skills/rite-ship/SKILL.md +4 -2
- package/pack/generated/pi/skills/rite-ship/reference/git-ship.md +8 -2
- package/pack/generated/pi/skills/rite-ship/reference/ship-template.md +2 -1
- package/pack/generated/pi/skills/rite-spec/SKILL.md +2 -2
- package/pack/generated/pi/skills/rite-spec/reference/spec-checklists.md +1 -1
- package/pack/generated/pi/skills/rite-spec/reference/spec-template.md +7 -3
- package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +2 -0
- package/pack/generated/pi/skills/rite-temper/SKILL.md +12 -9
- package/pack/generated/pi/skills/rite-temper/reference/scope-modes.md +1 -1
- package/pack/generated/pi/skills/rite-temper/reference/significance.md +10 -3
- package/pack/generated/pi/skills/rite-temper/reference/strategy-template.md +13 -2
- package/pack/generated/pi/skills/rite-vet/SKILL.md +4 -3
- package/pack/generated/pi/skills/rite-vet/reference/artifacts.md +1 -1
- package/package.json +5 -4
- package/scripts/build-host-artifacts.sh +15 -0
- package/scripts/codex-generate.sh +1 -1
- package/scripts/devin-generate.sh +1 -1
- package/scripts/expand-includes.py +46 -0
- package/scripts/install-lib.sh +42 -7
- package/scripts/omp-generate.sh +11 -0
- package/scripts/pi-generate.sh +12 -1
- package/update.sh +1 -2
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/README.md +0 -7
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/architecture.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/assumptions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/brief.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decision-coverage.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/decisions.md +0 -4
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/eng-review.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/gates.md +0 -4
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/plan.md +0 -5
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/questions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/spec.md +0 -6
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/state.md +0 -8
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/tasks.md +0 -1
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/test-plan.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/auth-tokens/traceability.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/README.md +0 -7
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/assumptions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/brief.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/decisions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/questions.md +0 -3
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/spec.md +0 -6
- package/engine/testdata/fixtures/basic/devrites-root/work/search-ranking/state.md +0 -3
- package/engine/testdata/golden/TestParityCloseOut/active_pointed_elsewhere.golden +0 -2
- package/engine/testdata/golden/TestParityCloseOut/active_slug_cleared.golden +0 -2
- package/engine/testdata/golden/TestParityCloseOut/archive_clobber.golden +0 -1
- package/engine/testdata/golden/TestParityCloseOut/missing_slug.golden +0 -1
- package/engine/testdata/golden/TestParityCloseOut/missing_workspace.golden +0 -1
- package/engine/testdata/golden/TestParityLearnings/add.golden +0 -2
- package/engine/testdata/golden/TestParityLearnings/list.golden +0 -5
- package/engine/testdata/golden/TestParityLearnings/mine-no-archive.golden +0 -2
- package/engine/testdata/golden/TestParityLearnings/mine.golden +0 -5
- package/engine/testdata/golden/TestParityLearnings/nudge.golden +0 -2
- package/engine/testdata/golden/TestParityLearnings/unknown.golden +0 -1
- package/engine/testdata/golden/TestParityPackageExistence/ghost-workspace.golden +0 -1
- package/engine/testdata/golden/TestParityPackageExistence/no-manifest.golden +0 -1
- package/engine/testdata/golden/TestParityPackageExistence/not-git.golden +0 -1
- package/engine/testdata/golden/TestParityPackageExistence/undeclared.golden +0 -1
- package/engine/testdata/golden/TestParityPreamble/afk/a.golden +0 -14
- package/engine/testdata/golden/TestParityPreamble/hitl/active.golden +0 -18
- package/engine/testdata/golden/TestParityPreamble/hitl/bare.golden +0 -10
- package/engine/testdata/golden/TestParityPreamble/hitl/full.golden +0 -18
- package/engine/testdata/golden/TestParityPreamble/hitl/ghost.golden +0 -2
- package/engine/testdata/golden/TestParityPreamble/hitl/nonl.golden +0 -11
- package/engine/testdata/golden/TestParityPreamble/hitl/openend.golden +0 -13
- package/engine/testdata/golden/TestParityProgress/arg=allbuilt.golden +0 -4
- package/engine/testdata/golden/TestParityProgress/arg=done.golden +0 -3
- package/engine/testdata/golden/TestParityProgress/arg=ghost.golden +0 -1
- package/engine/testdata/golden/TestParityProgress/arg=mid.golden +0 -4
- package/engine/testdata/golden/TestParityProgress/arg=nophase.golden +0 -3
- package/engine/testdata/golden/TestParityProgress/arg=noslice.golden +0 -3
- package/engine/testdata/golden/TestParityProgress/arg=plan.golden +0 -4
- package/engine/testdata/golden/TestParityProgress/arg=seal.golden +0 -3
- package/engine/testdata/golden/TestParityResolve/answer/questions.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/answer/state.md.golden +0 -7
- package/engine/testdata/golden/TestParityResolve/answer.golden +0 -4
- package/engine/testdata/golden/TestParityResolve/batch/questions.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/batch-unterminated/questions.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/batch-unterminated.golden +0 -2
- package/engine/testdata/golden/TestParityResolve/batch.golden +0 -3
- package/engine/testdata/golden/TestParityResolve/drop/questions.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/drop/state.md.golden +0 -9
- package/engine/testdata/golden/TestParityResolve/drop.golden +0 -4
- package/engine/testdata/golden/TestParityResolve/missing-answer.golden +0 -1
- package/engine/testdata/golden/TestParityResolve/no-workspace.golden +0 -1
- package/engine/testdata/golden/TestParityResolve/not-found.golden +0 -1
- package/engine/testdata/golden/TestParityResolve/not-open.golden +0 -1
- package/engine/testdata/golden/TestStatusLiveWorkspace.golden +0 -10
- package/engine/testdata/golden/status/auth-tokens.txt +0 -9
- package/engine/testdata/golden/status/search-ranking.txt +0 -9
- package/engine/testdata/visual/open-visual-smoke.html +0 -675
- package/engine/testdata/visual/open-visual-smoke.outline.md +0 -54
- package/engine/tests/adr_0003_gate_exit_code_test.go +0 -32
- package/engine/tests/adr_0004_required_by_phase_test.go +0 -54
- package/engine/tests/adr_0011_define_plan_test.go +0 -32
- package/engine/tests/adr_0027_readiness_binding_test.go +0 -107
- package/engine/tests/cli_test.go +0 -126
- package/engine/tests/gate_test.go +0 -669
- package/engine/tests/meta_test.go +0 -37
- package/engine/tests/parity_closeout_test.go +0 -105
- package/engine/tests/parity_githelpers_test.go +0 -41
- package/engine/tests/parity_resolve_test.go +0 -136
- package/engine/tests/parity_test.go +0 -86
- package/engine/tests/workspace_observation_migration_test.go +0 -1069
|
@@ -2,6 +2,8 @@ package state
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"strings"
|
|
5
|
+
|
|
6
|
+
"slices"
|
|
5
7
|
"testing"
|
|
6
8
|
)
|
|
7
9
|
|
|
@@ -39,4 +41,95 @@ func TestHasBudgetOverrideIgnoresFencedExamples(t *testing.T) {
|
|
|
39
41
|
if !HasBudgetOverride([]byte(indented)) {
|
|
40
42
|
t.Fatal("leading whitespace must not hide a real override line")
|
|
41
43
|
}
|
|
44
|
+
for _, bare := range []string{"x\nBudget override:\n", "x\nBudget override: \n", "x\n Budget override:\t\n"} {
|
|
45
|
+
if HasBudgetOverride([]byte(bare)) {
|
|
46
|
+
t.Fatalf("an override line with no reason must not count: %q", bare)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Every fence style that opens a CommonMark fenced block must reach the same
|
|
52
|
+
// fenced-code guard, so a quoted example can never record an override.
|
|
53
|
+
func TestHasBudgetOverrideMasksEveryFenceStyle(t *testing.T) {
|
|
54
|
+
for _, fence := range []string{"```", "~~~", "````", "~~~markdown", " ~~~"} {
|
|
55
|
+
t.Run(fence, func(t *testing.T) {
|
|
56
|
+
closer := strings.TrimRight(fence, "abcdefghijklmnopqrstuvwxyz")
|
|
57
|
+
closed := "Intro paragraph.\n\n" + fence + "\nBudget override: <reason>\n" + closer + "\n\nClosing prose.\n"
|
|
58
|
+
if HasBudgetOverride([]byte(closed)) {
|
|
59
|
+
t.Fatalf("fence %q: a closed fenced example is not a structural override", fence)
|
|
60
|
+
}
|
|
61
|
+
unterminated := "Intro paragraph.\n\n" + fence + "\nBudget override: <reason>\n\nStill open.\n"
|
|
62
|
+
if HasBudgetOverride([]byte(unterminated)) {
|
|
63
|
+
t.Fatalf("fence %q: an unterminated fence masks to end of artifact", fence)
|
|
64
|
+
}
|
|
65
|
+
after := "Intro paragraph.\n\n" + fence + "\nSchema reference.\n" + closer + "\n\nBudget override: relocation pending\n"
|
|
66
|
+
if !HasBudgetOverride([]byte(after)) {
|
|
67
|
+
t.Fatalf("fence %q: the guard must close and a later real override line still counts", fence)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func TestHasBudgetOverrideFenceStyleIsNotOutcomeBearing(t *testing.T) {
|
|
74
|
+
bodies := []string{
|
|
75
|
+
"Budget override: relocation pending\n",
|
|
76
|
+
"text\nBudget override: <reason>\n```\nmore\n```\nBudget override: second\n",
|
|
77
|
+
}
|
|
78
|
+
for _, body := range bodies {
|
|
79
|
+
backtick := "```\n" + body + "```\n"
|
|
80
|
+
tilde := "~~~\n" + body + "~~~\n"
|
|
81
|
+
if got, want := HasBudgetOverride([]byte(tilde)), HasBudgetOverride([]byte(backtick)); got != want {
|
|
82
|
+
t.Fatalf("fence style changed the outcome for %q: tilde=%v backtick=%v", body, got, want)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
func TestHasBudgetOverrideNestedAndIndentedFences(t *testing.T) {
|
|
88
|
+
cases := []struct {
|
|
89
|
+
name string
|
|
90
|
+
raw string
|
|
91
|
+
want bool
|
|
92
|
+
}{
|
|
93
|
+
{"backtick block quoted inside tilde fence", "~~~markdown\n```\nBudget override: <reason>\n```\n~~~\n", false},
|
|
94
|
+
{"tilde block quoted inside backtick fence", "```markdown\n~~~\nBudget override: <reason>\n~~~\n```\n", false},
|
|
95
|
+
{"four-space indent is not a fence", " ~~~\nBudget override: real\n", true},
|
|
96
|
+
{"malformed markdown has no structural override", "Budget override: real\n\x00", false},
|
|
97
|
+
}
|
|
98
|
+
for _, c := range cases {
|
|
99
|
+
if got := HasBudgetOverride([]byte(c.raw)); got != c.want {
|
|
100
|
+
t.Errorf("%s: got %v want %v", c.name, got, c.want)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
func TestAcceptanceSectionIgnoresFencedExamples(t *testing.T) {
|
|
106
|
+
spec := []byte("# Spec\n\nHere is the shape we want:\n\n```markdown\n## Acceptance criteria\n- AC-900: phantom\n```\n\nNo real section exists.\n")
|
|
107
|
+
got := ParseAcceptanceMap(spec, []byte("no ids here"), []byte("no ids here"), true, true)
|
|
108
|
+
if len(got.SpecIDs) != 0 {
|
|
109
|
+
t.Fatalf("a fenced example must not fabricate acceptance ids: ids=%v", got.SpecIDs)
|
|
110
|
+
}
|
|
111
|
+
if len(got.Problems) != 0 {
|
|
112
|
+
t.Fatalf("no real section means no required ids: problems=%v", got.Problems)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func TestAcceptanceSectionKeepsRealSectionPastFencedHeadings(t *testing.T) {
|
|
117
|
+
spec := []byte("# Spec\n\n## Acceptance criteria\n\n```markdown\n## Non-goals\n- AC-900: phantom\n```\n\n- AC-001: export CSV\n\n## Non-goals\n- AC-998: outside\n")
|
|
118
|
+
tasks := []byte("Satisfies: AC-001\n")
|
|
119
|
+
plan := []byte("AC-001\n")
|
|
120
|
+
got := ParseAcceptanceMap(spec, tasks, plan, true, true)
|
|
121
|
+
if !slices.Equal(got.SpecIDs, []string{"AC-001"}) {
|
|
122
|
+
t.Fatalf("a fenced heading must not truncate the real section: ids=%v", got.SpecIDs)
|
|
123
|
+
}
|
|
124
|
+
if len(got.Problems) != 0 {
|
|
125
|
+
t.Fatalf("problems=%v", got.Problems)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
func TestAcceptanceSectionIgnoresMalformedMarkdown(t *testing.T) {
|
|
130
|
+
spec := []byte("## Acceptance criteria\n- AC-001: export CSV\n\x00")
|
|
131
|
+
got := ParseAcceptanceMap(spec, []byte("no ids here"), []byte("no ids here"), true, true)
|
|
132
|
+
if len(got.SpecIDs) != 0 || len(got.Problems) != 0 {
|
|
133
|
+
t.Fatalf("malformed input carries no usable section: ids=%v problems=%v", got.SpecIDs, got.Problems)
|
|
134
|
+
}
|
|
42
135
|
}
|
|
@@ -216,10 +216,15 @@ func DeleteCursorField(lines []string, key string) []string {
|
|
|
216
216
|
|
|
217
217
|
// CursorForm reports the presentation of the state.md cursor: "table" when a
|
|
218
218
|
// canonical table row exists, "legacy" when only bullet fields exist, and
|
|
219
|
-
// "none" when neither is present.
|
|
219
|
+
// "none" when neither is present. Fenced blocks are not structural, so a
|
|
220
|
+
// cursor row inside one is not a cursor row.
|
|
220
221
|
func CursorForm(lines []string) string {
|
|
222
|
+
structural, ok := structuralCursorLines(lines)
|
|
223
|
+
if !ok {
|
|
224
|
+
return "none"
|
|
225
|
+
}
|
|
221
226
|
form := "none"
|
|
222
|
-
for _, line := range
|
|
227
|
+
for _, line := range structural {
|
|
223
228
|
_, _, kind, ok := parseCursorLine(line)
|
|
224
229
|
if !ok {
|
|
225
230
|
continue
|
|
@@ -237,14 +242,19 @@ func CursorForm(lines []string) string {
|
|
|
237
242
|
// ConvertCursorToTable rewrites legacy bullet cursor fields into canonical
|
|
238
243
|
// table rows in place. A bullet whose key resolves to a canonical cursor key
|
|
239
244
|
// is a cursor field wherever it appears — the same rule CursorField uses to
|
|
240
|
-
// read — so such a bullet is converted even inside prose sections.
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
245
|
+
// read — so such a bullet is converted even inside prose sections. Fenced
|
|
246
|
+
// blocks are not structural, so their bullets are left exactly as written.
|
|
247
|
+
// Prose without a canonical cursor key is preserved, and a value carrying a
|
|
248
|
+
// raw pipe keeps its bullet form because a table cell cannot represent it. It
|
|
249
|
+
// reports whether any line changed.
|
|
244
250
|
func ConvertCursorToTable(lines []string) ([]string, bool) {
|
|
251
|
+
structural, ok := structuralCursorLines(lines)
|
|
252
|
+
if !ok {
|
|
253
|
+
return append([]string(nil), lines...), false
|
|
254
|
+
}
|
|
245
255
|
changed := false
|
|
246
256
|
out := append([]string(nil), lines...)
|
|
247
|
-
for i, line := range
|
|
257
|
+
for i, line := range structural {
|
|
248
258
|
key, value, kind, ok := parseCursorLine(line)
|
|
249
259
|
if !ok || kind != cursorLineLegacy {
|
|
250
260
|
continue
|
|
@@ -259,7 +269,8 @@ func ConvertCursorToTable(lines []string) ([]string, bool) {
|
|
|
259
269
|
if !ok {
|
|
260
270
|
continue
|
|
261
271
|
}
|
|
262
|
-
|
|
272
|
+
original := out[i]
|
|
273
|
+
indent := original[:len(original)-len(strings.TrimLeft(original, " \t"))]
|
|
263
274
|
out[i] = indent + "| " + spelling + " | " + value + " |"
|
|
264
275
|
changed = true
|
|
265
276
|
}
|
|
@@ -154,3 +154,123 @@ func TestCursorHelpersRejectCorruptTextWithoutMutation(t *testing.T) {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
+
|
|
158
|
+
// ConvertCursorToTable and CursorForm must obtain their
|
|
159
|
+
// structural lines through structuralCursorLines (markdowntext.Structural), the
|
|
160
|
+
// same way CursorField, SetCursorField, UpsertCursorField and DeleteCursorField
|
|
161
|
+
// do. The cases below separate "the fence was masked" from "the call site never
|
|
162
|
+
// consulted the masker at all".
|
|
163
|
+
|
|
164
|
+
const ledgerWithFencedExample = `# State
|
|
165
|
+
|
|
166
|
+
## Recovery note
|
|
167
|
+
|
|
168
|
+
The pre-v5 ledger looked like this:
|
|
169
|
+
|
|
170
|
+
~~~md
|
|
171
|
+
- Phase: build
|
|
172
|
+
- Status: running
|
|
173
|
+
~~~
|
|
174
|
+
|
|
175
|
+
## Cursor
|
|
176
|
+
|
|
177
|
+
- Phase: build
|
|
178
|
+
- Status: running
|
|
179
|
+
`
|
|
180
|
+
|
|
181
|
+
// Fenced-only legacy bullets and a live table row: a ledger whose only legacy
|
|
182
|
+
// bullets sit inside a fence. Nothing here is structural, so nothing may change.
|
|
183
|
+
func TestConvertCursorToTableIsByteIdenticalOnFencedOnlyLedger(t *testing.T) {
|
|
184
|
+
lines := strings.Split("# State\n\n~~~md\n- Phase: build\n~~~\n\n## Cursor\n| phase | spec |", "\n")
|
|
185
|
+
original := strings.Join(lines, "\n")
|
|
186
|
+
out, changed := ConvertCursorToTable(lines)
|
|
187
|
+
if changed {
|
|
188
|
+
t.Fatalf("ConvertCursorToTable reported a change for a fenced-only ledger:\n%s", strings.Join(out, "\n"))
|
|
189
|
+
}
|
|
190
|
+
if got := strings.Join(out, "\n"); got != original {
|
|
191
|
+
t.Fatalf("ConvertCursorToTable mutated a fenced-only ledger:\ngot %q\nwant %q", got, original)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// The discriminating case: one document, the same key spelling inside and
|
|
196
|
+
// outside a fence. The fenced bullet must survive untouched while the live
|
|
197
|
+
// bullet is still converted, which neither "convert nothing" nor "convert
|
|
198
|
+
// everything" can satisfy.
|
|
199
|
+
func TestConvertCursorToTableConvertsLiveBulletsAndLeavesFencedOnes(t *testing.T) {
|
|
200
|
+
lines := strings.Split(ledgerWithFencedExample, "\n")
|
|
201
|
+
out, changed := ConvertCursorToTable(lines)
|
|
202
|
+
if !changed {
|
|
203
|
+
t.Fatalf("ConvertCursorToTable converted nothing; the live bullets must still convert:\n%s", strings.Join(out, "\n"))
|
|
204
|
+
}
|
|
205
|
+
if out[7] != "- Phase: build" || out[8] != "- Status: running" {
|
|
206
|
+
t.Fatalf("ConvertCursorToTable rewrote the fenced example:\n%s", strings.Join(out, "\n"))
|
|
207
|
+
}
|
|
208
|
+
if out[13] != "| phase | build |" || out[14] != "| status | running |" {
|
|
209
|
+
t.Fatalf("ConvertCursorToTable did not convert the live bullets:\n%s", strings.Join(out, "\n"))
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// A fence that is still open masks the rest of the document, which is what
|
|
214
|
+
// markdowntext.Structural does. The bullet after the unclosed fence is not converted.
|
|
215
|
+
func TestConvertCursorToTableTreatsAnUnclosedFenceAsStructuralMasking(t *testing.T) {
|
|
216
|
+
lines := strings.Split("~~~md\n- Phase: build\n\n- Phase: build\n", "\n")
|
|
217
|
+
out, changed := ConvertCursorToTable(lines)
|
|
218
|
+
if changed {
|
|
219
|
+
t.Fatalf("ConvertCursorToTable converted content after an unclosed fence:\n%s", strings.Join(out, "\n"))
|
|
220
|
+
}
|
|
221
|
+
if out[1] != "- Phase: build" || out[3] != "- Phase: build" {
|
|
222
|
+
t.Fatalf("ConvertCursorToTable rewrote content after an unclosed fence:\n%s", strings.Join(out, "\n"))
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// CursorForm must report the presentation of the structural document only.
|
|
227
|
+
func TestCursorFormIgnoresFencedTableRows(t *testing.T) {
|
|
228
|
+
fenced := []string{"~~~md", "| phase | x |", "~~~"}
|
|
229
|
+
if got := CursorForm(fenced); got != "none" {
|
|
230
|
+
t.Fatalf("CursorForm(fenced-only table) = %q, want none", got)
|
|
231
|
+
}
|
|
232
|
+
if got := CursorForm([]string{"| phase | x |"}); got != "table" {
|
|
233
|
+
t.Fatalf("CursorForm(live table) = %q, want table", got)
|
|
234
|
+
}
|
|
235
|
+
if got := CursorForm([]string{"~~~md", "- phase: build", "~~~", "- Phase: build"}); got != "legacy" {
|
|
236
|
+
t.Fatalf("CursorForm(fenced bullet plus live bullet) = %q, want legacy", got)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Proves the masker is consulted rather than the outcome being right by some
|
|
241
|
+
// other route. markdowntext.Structural is the only thing in this package that
|
|
242
|
+
// rejects NUL bytes, so a document that carries a valid, unfenced cursor bullet
|
|
243
|
+
// next to one NUL byte must be declined whole: ConvertCursorToTable returns
|
|
244
|
+
// changed=false and CursorForm reports "none". A parser that never calls the
|
|
245
|
+
// masker reports changed=true / "table" on exactly this input.
|
|
246
|
+
func TestCursorFormAndConvertConsultTheFenceMasker(t *testing.T) {
|
|
247
|
+
corrupt := []string{"- Phase: build", "- Status: run\x00ning"}
|
|
248
|
+
out, changed := ConvertCursorToTable(corrupt)
|
|
249
|
+
if changed {
|
|
250
|
+
t.Fatalf("ConvertCursorToTable converted a document the masker must decline:\n%q", strings.Join(out, "\n"))
|
|
251
|
+
}
|
|
252
|
+
if strings.Join(out, "\n") != strings.Join(corrupt, "\n") {
|
|
253
|
+
t.Fatalf("ConvertCursorToTable mutated a document the masker must decline:\n%q", strings.Join(out, "\n"))
|
|
254
|
+
}
|
|
255
|
+
if got := CursorForm([]string{"| phase | build |", "- Status: run\x00ning"}); got != "none" {
|
|
256
|
+
t.Fatalf("CursorForm(corrupt table) = %q, want none: the masker was not consulted", got)
|
|
257
|
+
}
|
|
258
|
+
if got := CursorForm([]string{"- Phase: build", "- Status: run\xffning"}); got != "none" {
|
|
259
|
+
t.Fatalf("CursorForm(corrupt legacy) = %q, want none: the masker was not consulted", got)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Bullets in prose sections outside any fence still convert.
|
|
264
|
+
func TestConvertCursorToTableStillConvertsProseSections(t *testing.T) {
|
|
265
|
+
lines := strings.Split("# State\n\n## Notes\n\n- Phase: build\n- owner: platform\n", "\n")
|
|
266
|
+
out, changed := ConvertCursorToTable(lines)
|
|
267
|
+
if !changed {
|
|
268
|
+
t.Fatalf("ConvertCursorToTable converted nothing:\n%s", strings.Join(out, "\n"))
|
|
269
|
+
}
|
|
270
|
+
if out[4] != "| phase | build |" {
|
|
271
|
+
t.Fatalf("ConvertCursorToTable did not convert the prose-section bullet:\n%s", strings.Join(out, "\n"))
|
|
272
|
+
}
|
|
273
|
+
if out[5] != "- owner: platform" {
|
|
274
|
+
t.Fatalf("ConvertCursorToTable converted a non-cursor bullet:\n%s", strings.Join(out, "\n"))
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -19,13 +19,19 @@ func acquireLock(path string) (*fileLock, error) {
|
|
|
19
19
|
if err != nil {
|
|
20
20
|
return nil, fmt.Errorf("acquire lock: %w", err)
|
|
21
21
|
}
|
|
22
|
+
return lockOpened(f, path)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// lockOpened takes the flock on f, an already-open handle on path, and confirms
|
|
26
|
+
// the lock is still the file at path.
|
|
27
|
+
func lockOpened(f *os.File, path string) (*fileLock, error) {
|
|
22
28
|
// LOCK_EX blocks until the lock is available; contending devrites-engine processes
|
|
23
29
|
// queue here rather than racing the read-modify-write.
|
|
24
30
|
if err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
|
|
25
31
|
_ = f.Close()
|
|
26
32
|
return nil, fmt.Errorf("flock %s: %w", path, err)
|
|
27
33
|
}
|
|
28
|
-
return &fileLock{f: f},
|
|
34
|
+
return confirmLock(&fileLock{f: f}, path)
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
func (l *fileLock) release() error {
|
|
@@ -26,6 +26,12 @@ func acquireLock(path string) (*fileLock, error) {
|
|
|
26
26
|
if err != nil {
|
|
27
27
|
return nil, fmt.Errorf("acquire lock: %w", err)
|
|
28
28
|
}
|
|
29
|
+
return lockOpened(f, path)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// lockOpened takes the LockFileEx lock on f, an already-open handle on path, and
|
|
33
|
+
// confirms the lock is still the file at path.
|
|
34
|
+
func lockOpened(f *os.File, path string) (*fileLock, error) {
|
|
29
35
|
l := &fileLock{f: f}
|
|
30
36
|
if ok, _, callErr := lockFileEx.Call(
|
|
31
37
|
f.Fd(),
|
|
@@ -38,7 +44,7 @@ func acquireLock(path string) (*fileLock, error) {
|
|
|
38
44
|
_ = f.Close()
|
|
39
45
|
return nil, fmt.Errorf("lock file %s: %w", path, callErr)
|
|
40
46
|
}
|
|
41
|
-
return l,
|
|
47
|
+
return confirmLock(l, path)
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
func (l *fileLock) release() error {
|
|
@@ -624,17 +624,6 @@ func writeStatusRequiredArtifacts(t *testing.T, root, slug string, phase Phase)
|
|
|
624
624
|
}
|
|
625
625
|
}
|
|
626
626
|
|
|
627
|
-
func writeSection(t *testing.T, root, slug, name, body string) {
|
|
628
|
-
t.Helper()
|
|
629
|
-
dir := filepath.Join(root, "work", slug)
|
|
630
|
-
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
631
|
-
t.Fatal(err)
|
|
632
|
-
}
|
|
633
|
-
if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0o644); err != nil {
|
|
634
|
-
t.Fatal(err)
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
627
|
func writeWorkSection(t *testing.T, root, slug, name, body string) {
|
|
639
628
|
t.Helper()
|
|
640
629
|
dir := filepath.Join(root, "work", slug)
|
|
@@ -651,12 +640,12 @@ func writeWorkSection(t *testing.T, root, slug, name, body string) {
|
|
|
651
640
|
// evidence.md/state.md. The engine must load, list, and report it anyway.
|
|
652
641
|
func TestStatusFromOfficialBulletLedger(t *testing.T) {
|
|
653
642
|
root := filepath.Join(t.TempDir(), ".devrites")
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
643
|
+
writeWorkSection(t, root, "live", "state.md", "- Phase: prove\n- Status: running\n")
|
|
644
|
+
writeWorkSection(t, root, "live", "spec.md", "# Spec\n\nDo the thing.\n")
|
|
645
|
+
writeWorkSection(t, root, "live", "plan.md", "# Plan\n\nApproach.\n")
|
|
646
|
+
writeWorkSection(t, root, "live", "decisions.md", "# Decisions\n\nChose X.\n")
|
|
647
|
+
writeWorkSection(t, root, "live", "tasks.md", "# Tasks\n\n- [x] slice 1\n")
|
|
648
|
+
writeWorkSection(t, root, "live", "evidence.md", "# Evidence\n\nTests pass.\n")
|
|
660
649
|
|
|
661
650
|
rep, err := Status(root, "live")
|
|
662
651
|
if err != nil {
|
|
@@ -788,7 +777,7 @@ func TestStatusCursorCannotStandInForPhase(t *testing.T) {
|
|
|
788
777
|
// clear error rather than silently falling back or mis-loading.
|
|
789
778
|
func TestLedgerPhaseRejectsUnknownWord(t *testing.T) {
|
|
790
779
|
root := filepath.Join(t.TempDir(), ".devrites")
|
|
791
|
-
|
|
780
|
+
writeWorkSection(t, root, "bogus", "state.md", "- Phase: building\n")
|
|
792
781
|
if _, err := Status(root, "bogus"); err == nil {
|
|
793
782
|
t.Error("Status on a ledger with an unknown phase word = nil error, want an error")
|
|
794
783
|
}
|
|
@@ -953,3 +942,45 @@ func TestListFeaturesIgnoresAllOperationalRemnants(t *testing.T) {
|
|
|
953
942
|
t.Fatalf("ListFeatures() = %v, want [live]; operational remnants became workspaces", got)
|
|
954
943
|
}
|
|
955
944
|
}
|
|
945
|
+
|
|
946
|
+
func TestRequireWorkspaceSchemaRefusesUnsafeStateFile(t *testing.T) {
|
|
947
|
+
tests := []struct {
|
|
948
|
+
name string
|
|
949
|
+
setup func(t *testing.T, statePath string)
|
|
950
|
+
want string
|
|
951
|
+
}{
|
|
952
|
+
{"symlink", func(t *testing.T, statePath string) {
|
|
953
|
+
outside := filepath.Join(t.TempDir(), "outside.md")
|
|
954
|
+
if err := os.WriteFile(outside, []byte("- schema: 4\n"), 0o644); err != nil {
|
|
955
|
+
t.Fatal(err)
|
|
956
|
+
}
|
|
957
|
+
if err := os.Symlink(outside, statePath); err != nil {
|
|
958
|
+
t.Skipf("symlinks unavailable: %v", err)
|
|
959
|
+
}
|
|
960
|
+
}, string(DiagnosticFinalSymlink)},
|
|
961
|
+
{"directory", func(t *testing.T, statePath string) {
|
|
962
|
+
if err := os.Mkdir(statePath, 0o755); err != nil {
|
|
963
|
+
t.Fatal(err)
|
|
964
|
+
}
|
|
965
|
+
}, string(DiagnosticNonRegular)},
|
|
966
|
+
{"oversize", func(t *testing.T, statePath string) {
|
|
967
|
+
if err := os.WriteFile(statePath, make([]byte, maxArtifactBytes+1), 0o644); err != nil {
|
|
968
|
+
t.Fatal(err)
|
|
969
|
+
}
|
|
970
|
+
}, string(DiagnosticFileTooLarge)},
|
|
971
|
+
}
|
|
972
|
+
for _, tt := range tests {
|
|
973
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
974
|
+
root := t.TempDir()
|
|
975
|
+
dir := featureDir(root, "demo")
|
|
976
|
+
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
977
|
+
t.Fatal(err)
|
|
978
|
+
}
|
|
979
|
+
tt.setup(t, filepath.Join(dir, LedgerFile))
|
|
980
|
+
err := RequireWorkspaceSchema(root, "demo")
|
|
981
|
+
if err == nil || !strings.Contains(err.Error(), tt.want) {
|
|
982
|
+
t.Fatalf("RequireWorkspaceSchema err=%v, want it to mention %s", err, tt.want)
|
|
983
|
+
}
|
|
984
|
+
})
|
|
985
|
+
}
|
|
986
|
+
}
|
|
@@ -5,6 +5,8 @@ import (
|
|
|
5
5
|
"regexp"
|
|
6
6
|
"strings"
|
|
7
7
|
"unicode"
|
|
8
|
+
|
|
9
|
+
"github.com/devrites/devrites/internal/markdowntext"
|
|
8
10
|
)
|
|
9
11
|
|
|
10
12
|
// TaskSlice is one SLICE-### block parsed from tasks.md.
|
|
@@ -37,11 +39,12 @@ func ValidSliceID(id string) bool { return sliceIDValidRE.MatchString(id) }
|
|
|
37
39
|
// one slice instead of the whole file.
|
|
38
40
|
func ExtractTaskSlice(tasksMarkdown []byte, id string) (string, bool) {
|
|
39
41
|
text := string(tasksMarkdown)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
masked := structuralTaskText(tasksMarkdown)
|
|
43
|
+
for _, match := range sliceHeaderRE.FindAllStringSubmatchIndex(masked, -1) {
|
|
44
|
+
if masked[match[2]:match[3]] != id {
|
|
42
45
|
continue
|
|
43
46
|
}
|
|
44
|
-
rest :=
|
|
47
|
+
rest := masked[match[1]:]
|
|
45
48
|
end := len(text)
|
|
46
49
|
if next := anyH2HeaderRE.FindStringIndex(rest); next != nil {
|
|
47
50
|
end = match[1] + next[0]
|
|
@@ -53,7 +56,7 @@ func ExtractTaskSlice(tasksMarkdown []byte, id string) (string, bool) {
|
|
|
53
56
|
|
|
54
57
|
// ParseTaskGraph reads tasks.md content and validates the slice dependency DAG.
|
|
55
58
|
func ParseTaskGraph(tasksMarkdown []byte) TaskGraphResult {
|
|
56
|
-
text :=
|
|
59
|
+
text := structuralTaskText(tasksMarkdown)
|
|
57
60
|
result := TaskGraphResult{}
|
|
58
61
|
if strings.TrimSpace(text) == "" {
|
|
59
62
|
result.Problems = append(result.Problems, "tasks.md is empty")
|
|
@@ -107,6 +110,17 @@ func ParseTaskGraph(tasksMarkdown []byte) TaskGraphResult {
|
|
|
107
110
|
return result
|
|
108
111
|
}
|
|
109
112
|
|
|
113
|
+
// structuralTaskText blanks fenced code blocks, keeping byte offsets aligned, so
|
|
114
|
+
// an example inside a fence is never read as slice structure. Input that cannot
|
|
115
|
+
// be masked (malformed UTF-8, NUL) is parsed as written.
|
|
116
|
+
func structuralTaskText(tasksMarkdown []byte) string {
|
|
117
|
+
masked, err := markdowntext.Structural(tasksMarkdown)
|
|
118
|
+
if err != nil {
|
|
119
|
+
return string(tasksMarkdown)
|
|
120
|
+
}
|
|
121
|
+
return string(masked)
|
|
122
|
+
}
|
|
123
|
+
|
|
110
124
|
func parseSliceGraph(id, block string) ([]string, []string) {
|
|
111
125
|
var problems []string
|
|
112
126
|
depsLine := firstLineValue(dependenciesRE, block)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package state
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strings"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
const fenceLive = "## SLICE-001\nDependencies: SLICE-002\n\n## SLICE-002\nDependencies: none\n"
|
|
9
|
+
|
|
10
|
+
const fenceDoc = "## SLICE-001\nDependencies: SLICE-002\n\nExample layout:\n\n```markdown\n## SLICE-002\nDependencies: none\n```\n"
|
|
11
|
+
|
|
12
|
+
func TestParseTaskGraphUnfencedControlYieldsTwoSlices(t *testing.T) {
|
|
13
|
+
got := ParseTaskGraph([]byte(fenceLive))
|
|
14
|
+
if len(got.Slices) != 2 || len(got.Unknown) != 0 {
|
|
15
|
+
t.Fatalf("slices=%v unknown=%v, want two slices and no unknown", got.Slices, got.Unknown)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func TestParseTaskGraphIgnoresFencedSliceHeader(t *testing.T) {
|
|
20
|
+
got := ParseTaskGraph([]byte(fenceDoc))
|
|
21
|
+
if len(got.Slices) != 1 || got.Slices[0].ID != "SLICE-001" {
|
|
22
|
+
t.Fatalf("slices=%v, want only SLICE-001", got.Slices)
|
|
23
|
+
}
|
|
24
|
+
if len(got.Unknown) != 1 || got.Unknown[0] != "SLICE-002" {
|
|
25
|
+
t.Fatalf("unknown=%v, want the dangling SLICE-002 reported", got.Unknown)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func TestExtractTaskSliceIgnoresFencedSliceHeader(t *testing.T) {
|
|
30
|
+
if _, ok := ExtractTaskSlice([]byte(fenceDoc), "SLICE-002"); ok {
|
|
31
|
+
t.Fatal("fenced SLICE-002 reported as a live slice")
|
|
32
|
+
}
|
|
33
|
+
block, ok := ExtractTaskSlice([]byte(fenceDoc), "SLICE-001")
|
|
34
|
+
if !ok {
|
|
35
|
+
t.Fatal("live SLICE-001 not found")
|
|
36
|
+
}
|
|
37
|
+
if !strings.Contains(block, "```markdown") || !strings.Contains(block, "## SLICE-002") {
|
|
38
|
+
t.Fatalf("live slice must keep its fenced example verbatim, got %q", block)
|
|
39
|
+
}
|
|
40
|
+
if got, ok := ExtractTaskSlice([]byte(fenceLive), "SLICE-002"); !ok || !strings.HasPrefix(got, "## SLICE-002") {
|
|
41
|
+
t.Fatalf("unfenced control: got %q ok=%v", got, ok)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -21,7 +21,21 @@ const workspaceSchemaKey = CursorSchema
|
|
|
21
21
|
// WorkspaceSchema reports the schema version declared by the feature's
|
|
22
22
|
// state.md cursor. A missing row means the pre-v5 (schema 2) contract.
|
|
23
23
|
func WorkspaceSchema(root, slug string) (int, error) {
|
|
24
|
-
|
|
24
|
+
statePath := filepath.Join(featureDir(root, slug), LedgerFile)
|
|
25
|
+
info, err := os.Lstat(statePath)
|
|
26
|
+
if err != nil {
|
|
27
|
+
return 0, fmt.Errorf("read workspace schema for %s: %w", slug, err)
|
|
28
|
+
}
|
|
29
|
+
switch {
|
|
30
|
+
case info.Mode()&os.ModeSymlink != 0:
|
|
31
|
+
return 0, fmt.Errorf("read workspace schema for %s: state.md is unsafe (%s)", slug, DiagnosticFinalSymlink)
|
|
32
|
+
case !info.Mode().IsRegular():
|
|
33
|
+
return 0, fmt.Errorf("read workspace schema for %s: state.md is unsafe (%s)", slug, DiagnosticNonRegular)
|
|
34
|
+
case info.Size() > maxArtifactBytes:
|
|
35
|
+
return 0, fmt.Errorf("read workspace schema for %s: state.md is unsafe (%s)", slug, DiagnosticFileTooLarge)
|
|
36
|
+
}
|
|
37
|
+
// #nosec G304 -- fixed state.md under the engine-resolved feature workspace, checked above to be a regular non-symlink file within the size cap
|
|
38
|
+
raw, err := os.ReadFile(statePath)
|
|
25
39
|
if err != nil {
|
|
26
40
|
return 0, fmt.Errorf("read workspace schema for %s: %w", slug, err)
|
|
27
41
|
}
|
|
@@ -37,7 +51,7 @@ func RequireWorkspaceSchema(root, slug string) error {
|
|
|
37
51
|
return err
|
|
38
52
|
}
|
|
39
53
|
if version < SchemaVersion {
|
|
40
|
-
return fmt.Errorf("%w: workspace %s predates the
|
|
54
|
+
return fmt.Errorf("%w: workspace %s predates the current workspace schema (schema %d, engine requires %d); run devrites-engine migrate %s", ErrWorkspaceSchemaRefused, slug, version, SchemaVersion, slug)
|
|
41
55
|
}
|
|
42
56
|
if version > SchemaVersion {
|
|
43
57
|
return fmt.Errorf("%w: workspace %s declares schema %d, newer than this engine's %d; upgrade devrites", ErrWorkspaceSchemaRefused, slug, version, SchemaVersion)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
package state
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"fmt"
|
|
4
5
|
"os"
|
|
5
6
|
"path/filepath"
|
|
7
|
+
"regexp"
|
|
6
8
|
"strings"
|
|
7
9
|
"testing"
|
|
8
10
|
)
|
|
@@ -65,3 +67,35 @@ func TestWorkspaceSchemaMissingLedgerIsRefused(t *testing.T) {
|
|
|
65
67
|
t.Fatal("missing workspace must be refused")
|
|
66
68
|
}
|
|
67
69
|
}
|
|
70
|
+
|
|
71
|
+
func TestRefusalMessagesFormatSchemaVersionWithoutVersionLabel(t *testing.T) {
|
|
72
|
+
root, slug := writeSchemaWorkspace(t, "| phase | build |\n| schema | 2 |\n")
|
|
73
|
+
older := RequireWorkspaceSchema(root, slug)
|
|
74
|
+
root, slug = writeSchemaWorkspace(t, fmt.Sprintf("| phase | build |\n| schema | %d |\n", SchemaVersion+1))
|
|
75
|
+
newer := RequireWorkspaceSchema(root, slug)
|
|
76
|
+
for name, err := range map[string]error{"older": older, "newer": newer} {
|
|
77
|
+
if err == nil {
|
|
78
|
+
t.Fatalf("%s schema must be refused", name)
|
|
79
|
+
}
|
|
80
|
+
if strings.Contains(err.Error(), "v5") {
|
|
81
|
+
t.Fatalf("%s refusal hardcodes a version label: %v", name, err)
|
|
82
|
+
}
|
|
83
|
+
if want := fmt.Sprintf("%d", SchemaVersion); !strings.Contains(err.Error(), want) {
|
|
84
|
+
t.Fatalf("%s refusal must format SchemaVersion %s: %v", name, want, err)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func TestStateTemplateSchemaCellMatchesEngine(t *testing.T) {
|
|
90
|
+
raw, err := os.ReadFile(filepath.Join("..", "..", "..", "pack", ".claude", "skills", "rite-spec", "reference", "state-workspace.md"))
|
|
91
|
+
if err != nil {
|
|
92
|
+
t.Fatal(err)
|
|
93
|
+
}
|
|
94
|
+
m := regexp.MustCompile(`(?m)^\|\s*schema\s*\|\s*(\d+)\s*\|`).FindSubmatch(raw)
|
|
95
|
+
if m == nil {
|
|
96
|
+
t.Fatal("template has no schema cell")
|
|
97
|
+
}
|
|
98
|
+
if want := fmt.Sprintf("%d", SchemaVersion); string(m[1]) != want {
|
|
99
|
+
t.Fatalf("template schema cell=%s, engine SchemaVersion=%s", m[1], want)
|
|
100
|
+
}
|
|
101
|
+
}
|