devrites 6.8.1 → 6.9.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 +6 -0
- package/README.md +1 -1
- package/docs/engine/commands.md +1 -1
- package/engine/internal/acceptance/cli.go +32 -6
- package/engine/internal/acceptance/run.go +13 -1
- package/engine/internal/acceptance/transcript.go +116 -0
- package/engine/internal/lib/secretscan.go +6 -15
- package/engine/internal/secretpattern/secretpattern.go +37 -0
- package/engine/main.go +9 -0
- package/pack/.claude/agents/devrites-proof-runner.md +6 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +6 -1
- package/pack/.claude/skills/rite-prove/SKILL.md +7 -4
- package/pack/.claude/skills/rite-seal/SKILL.md +3 -1
- package/pack/generated/claude/agents/devrites-proof-runner.md +6 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +6 -1
- package/pack/generated/claude/skills/rite-prove/SKILL.md +7 -4
- package/pack/generated/claude/skills/rite-seal/SKILL.md +3 -1
- package/pack/generated/codex/agents/devrites-proof-runner.toml +6 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +6 -1
- package/pack/generated/codex/skills/rite-prove/SKILL.md +7 -4
- package/pack/generated/codex/skills/rite-seal/SKILL.md +3 -1
- package/pack/generated/devin/agents/devrites-proof-runner.md +6 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +6 -1
- package/pack/generated/devin/skills/rite-prove/SKILL.md +7 -4
- package/pack/generated/devin/skills/rite-seal/SKILL.md +3 -1
- package/pack/generated/omp/agents/devrites-proof-runner.md +6 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +6 -1
- package/pack/generated/omp/skills/rite-prove/SKILL.md +7 -4
- package/pack/generated/omp/skills/rite-seal/SKILL.md +3 -1
- package/pack/generated/pi/agents/devrites-proof-runner.md +6 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +6 -1
- package/pack/generated/pi/skills/rite-prove/SKILL.md +7 -4
- package/pack/generated/pi/skills/rite-seal/SKILL.md +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to DevRites are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and DevRites adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Releases are generated automatically by [semantic-release](https://semantic-release.gitbook.io/) from Conventional Commits on `main`.
|
|
4
4
|
|
|
5
|
+
## [6.9.0](https://github.com/ViktorsBaikers/DevRites/compare/v6.8.1...v6.9.0) (2026-10-18)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
* **devrites:** write candidate-bound gate transcripts ([#131](https://github.com/ViktorsBaikers/DevRites/issues/131)) ([4e7f2ef](https://github.com/ViktorsBaikers/DevRites/commit/4e7f2ef8393754b53f794f9dfabdd7e69a5bd16c))
|
|
10
|
+
|
|
5
11
|
## [6.8.1](https://github.com/ViktorsBaikers/DevRites/compare/v6.8.0...v6.8.1) (2026-10-18)
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ history can't lose it. After you clear the conversation, switch hosts, or hand
|
|
|
31
31
|
the feature to another engineer, the next session reads the same plan,
|
|
32
32
|
decisions, and evidence before it continues.
|
|
33
33
|
|
|
34
|
-
**Status:** [`v6.
|
|
34
|
+
**Status:** [`v6.9.0`](https://github.com/ViktorsBaikers/DevRites/releases/tag/v6.9.0): see [`CHANGELOG.md`](CHANGELOG.md) for release notes.
|
|
35
35
|
|
|
36
36
|
This is the latest published release; `main` may contain unreleased work.
|
|
37
37
|
|
package/docs/engine/commands.md
CHANGED
|
@@ -39,7 +39,7 @@ workflow strategy.
|
|
|
39
39
|
| `metrics summary [slug] [--by-slice]` | Reduce `metrics.jsonl` into a per-phase roll-up. `--by-slice` reads `dispatch.json` instead: per slice, build wright rounds, slice-bound Vet rechecks, and agent-minutes (role start to `returned_at`; abandoned waves excluded). |
|
|
40
40
|
| `claim <add\|release\|list\|check>` | Advisory session-scoped file claims in `.devrites/claims.jsonl` (append-only). `add` records intent to write a path set with a TTL (1–240 min, default 30); a live claim by another session exits `3` and names the holder. `release` appends a release event owned by the claiming session. `list` shows live claims (`--all` includes expired/released); a claim whose holding session has provably exited on this host shows `dead` and no longer conflicts. `check` is the read-only preflight for a path set. Coordination aid only — never a substitute for one-writer-per-worktree. |
|
|
41
41
|
| `note <add\|list\|check\|rm> <slug> ...` | Anchored workspace notes in `notes.md`: `add <slug> <subject> <quote> <title> [body]` binds a note to a verbatim quote in one repository file and assigns `NOTE-###`; `list` and `check` regrade each anchor `exact`/`moved`/`stale`/`ambiguous`/`lost` by searching the repo for the quote (dependency and workspace trees excluded); `check --repair` rewrites a `moved` subject to its new file; `rm` deletes by ID. `check seal` refuses a malformed `notes.md` and any non-`exact` anchor. |
|
|
42
|
-
| `gates <scaffold\|status\|run\|reverify\|lint\|attest\|abandon> <slug>` | Operate the `gates.md` acceptance ledger: seed per-AC gates, execute runnable gates bound to `test-plan.md` preflight rows, attest manual gates, and reduce to `all-met`/`not-met`/`handoff`/`malformed`. A gate with `INPUTS:` records its files' content digest and is reused by `run` and `reverify` while they are unchanged. |
|
|
42
|
+
| `gates <scaffold\|status\|run\|reverify\|lint\|attest\|abandon> <slug>` | Operate the `gates.md` acceptance ledger: seed per-AC gates, execute runnable gates bound to `test-plan.md` preflight rows, attest manual gates, and reduce to `all-met`/`not-met`/`handoff`/`malformed`. A gate with `INPUTS:` records its files' content digest and is reused by `run` and `reverify` while they are unchanged. `run`/`reverify --transcripts` writes a redacted, candidate-bound transcript per executed or reused gate under `references/gates/<gate-id>/`. |
|
|
43
43
|
| `state resolve <qid> "<answer>"` | Resolve an open question and update `questions.md` plus `state.md` atomically. |
|
|
44
44
|
| `state merge-manifest <slug> [pred...]` | Fold the recorded predecessor chain's manifests into the release candidate manifest. |
|
|
45
45
|
| `state close <slug>` | Archive a shipped workspace and clear matching `ACTIVE`. |
|
|
@@ -26,8 +26,12 @@ const gatesUsage = `usage: devrites-engine gates <subcommand> <slug>
|
|
|
26
26
|
Subcommands:
|
|
27
27
|
scaffold <slug> Create gates.md from spec.md AC ids (only when absent)
|
|
28
28
|
status <slug> Reduce the ledger without executing; exit 3 unless ALL MET
|
|
29
|
-
run <slug> [--timeout N]
|
|
30
|
-
|
|
29
|
+
run <slug> [--timeout N] [--transcripts]
|
|
30
|
+
Execute unmet runnable gates and record evidence
|
|
31
|
+
reverify <slug> [--timeout N] [--transcripts]
|
|
32
|
+
Re-execute every runnable gate, demoting stale passes
|
|
33
|
+
(--transcripts writes one redacted, candidate-bound
|
|
34
|
+
file per gate under references/gates/<gate-id>/)
|
|
31
35
|
lint <slug> [--strict] Audit oracle quality without executing
|
|
32
36
|
attest <slug> <id> <note> Record human evidence on a manual gate
|
|
33
37
|
abandon <slug> <id> <why> Record a terminal ABANDON handoff on a gate
|
|
@@ -216,7 +220,12 @@ func cmdRun(root string, args []string, reverify bool, stdout, stderr io.Writer)
|
|
|
216
220
|
var slug string
|
|
217
221
|
timeout := DefaultTimeout
|
|
218
222
|
positional := 0
|
|
223
|
+
transcripts := false
|
|
219
224
|
for i := 0; i < len(args); i++ {
|
|
225
|
+
if args[i] == "--transcripts" {
|
|
226
|
+
transcripts = true
|
|
227
|
+
continue
|
|
228
|
+
}
|
|
220
229
|
if args[i] == "--timeout" {
|
|
221
230
|
if i+1 >= len(args) {
|
|
222
231
|
fmt.Fprintf(stderr, "gates %s: --timeout requires seconds\n", verb)
|
|
@@ -232,21 +241,27 @@ func cmdRun(root string, args []string, reverify bool, stdout, stderr io.Writer)
|
|
|
232
241
|
continue
|
|
233
242
|
}
|
|
234
243
|
if strings.HasPrefix(args[i], "-") || positional > 0 {
|
|
235
|
-
fmt.Fprintf(stderr, "usage: devrites-engine gates %s <slug> [--timeout N]\n", verb)
|
|
244
|
+
fmt.Fprintf(stderr, "usage: devrites-engine gates %s <slug> [--timeout N] [--transcripts]\n", verb)
|
|
236
245
|
return ExitUsage
|
|
237
246
|
}
|
|
238
247
|
slug = args[i]
|
|
239
248
|
positional++
|
|
240
249
|
}
|
|
241
250
|
if slug == "" {
|
|
242
|
-
fmt.Fprintf(stderr, "usage: devrites-engine gates %s <slug> [--timeout N]\n", verb)
|
|
251
|
+
fmt.Fprintf(stderr, "usage: devrites-engine gates %s <slug> [--timeout N] [--transcripts]\n", verb)
|
|
243
252
|
return ExitUsage
|
|
244
253
|
}
|
|
245
|
-
|
|
254
|
+
work, ledgerPath, testPlanPath, project, err := featurePaths(root, slug)
|
|
246
255
|
if err != nil {
|
|
247
256
|
fmt.Fprintf(stderr, "gates %s: %v\n", verb, err)
|
|
248
257
|
return ExitBlocked
|
|
249
258
|
}
|
|
259
|
+
before := ""
|
|
260
|
+
if transcripts {
|
|
261
|
+
before = candidateLabel(root, slug)
|
|
262
|
+
}
|
|
263
|
+
var ran []GateResult
|
|
264
|
+
var ranDoc *Document
|
|
250
265
|
|
|
251
266
|
// The gates lock serializes check execution; the feature lock is held only
|
|
252
267
|
// to read inputs and per writeback, so dispatch and other workspace writers
|
|
@@ -270,7 +285,8 @@ func cmdRun(root string, args []string, reverify bool, stdout, stderr io.Writer)
|
|
|
270
285
|
}
|
|
271
286
|
return nil
|
|
272
287
|
}
|
|
273
|
-
|
|
288
|
+
ran, ranDoc = RunGates(context.Background(), project, ledgerPath, doc, approved, reverify, timeout, featureLock), doc
|
|
289
|
+
for _, result := range ran {
|
|
274
290
|
switch {
|
|
275
291
|
case !result.Ran:
|
|
276
292
|
fmt.Fprintf(stdout, "gate %s: skipped (%s)\n", result.ID, result.Detail)
|
|
@@ -286,6 +302,16 @@ func cmdRun(root string, args []string, reverify bool, stdout, stderr io.Writer)
|
|
|
286
302
|
fmt.Fprintf(stderr, "gates %s: %v\n", verb, lockErr)
|
|
287
303
|
return ExitBlocked
|
|
288
304
|
}
|
|
305
|
+
if transcripts && ranDoc != nil {
|
|
306
|
+
paths, err := writeTranscripts(work, ranDoc, ran, before, candidateLabel(root, slug))
|
|
307
|
+
for _, path := range paths {
|
|
308
|
+
fmt.Fprintf(stdout, "transcript: %s\n", path)
|
|
309
|
+
}
|
|
310
|
+
if err != nil {
|
|
311
|
+
fmt.Fprintf(stderr, "gates %s: transcript: %v\n", verb, err)
|
|
312
|
+
return ExitBlocked
|
|
313
|
+
}
|
|
314
|
+
}
|
|
289
315
|
fmt.Fprintln(stdout, "---")
|
|
290
316
|
return reportStatus(slug, ledgerPath, testPlanPath, stdout, stderr)
|
|
291
317
|
}
|
|
@@ -30,6 +30,12 @@ type GateResult struct {
|
|
|
30
30
|
Detail string // exit/match/timeout/approval diagnostic
|
|
31
31
|
Discarded bool // result dropped: ledger changed under the run
|
|
32
32
|
WriteErr error // evidence writeback failed for a reason other than drift
|
|
33
|
+
Reused bool // met gate kept because its INPUTS are unchanged
|
|
34
|
+
Inputs string // INPUTS content digest at run time, when declared
|
|
35
|
+
// Outcome, Started and Ended describe the execution this result judged;
|
|
36
|
+
// they are zero when the gate did not execute.
|
|
37
|
+
Outcome RunOutcome
|
|
38
|
+
Started, Ended time.Time
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
var (
|
|
@@ -72,6 +78,7 @@ func ReadLedgerFile(ledgerPath string) (string, error) {
|
|
|
72
78
|
func RunGates(ctx context.Context, root, ledgerPath string, doc *Document, approved []ApprovedCommand, reverify bool, timeout time.Duration, writeLock func(func() error) error) []GateResult {
|
|
73
79
|
var results []GateResult
|
|
74
80
|
outcomes := map[string]RunOutcome{}
|
|
81
|
+
spans := map[string][2]time.Time{}
|
|
75
82
|
write := func(gate *Gate, evidence string, checked bool) error {
|
|
76
83
|
if writeLock == nil {
|
|
77
84
|
return writeResult(ledgerPath, gate, evidence, checked)
|
|
@@ -100,7 +107,7 @@ func RunGates(ctx context.Context, root, ledgerPath string, doc *Document, appro
|
|
|
100
107
|
// A gate that declares INPUTS is reused, under run and reverify alike,
|
|
101
108
|
// exactly while the files it depends on are byte-identical; any change re-executes it.
|
|
102
109
|
if inputs != "" && inputs == recordedInputs(gate) {
|
|
103
|
-
results = append(results, GateResult{ID: gate.ID, Passed: true, Detail: "reused: inputs unchanged"})
|
|
110
|
+
results = append(results, GateResult{ID: gate.ID, Passed: true, Reused: true, Inputs: inputs, Detail: "reused: inputs unchanged"})
|
|
104
111
|
continue
|
|
105
112
|
}
|
|
106
113
|
}
|
|
@@ -120,9 +127,12 @@ func RunGates(ctx context.Context, root, ledgerPath string, doc *Document, appro
|
|
|
120
127
|
key := gate.Check + "\x00" + cwd
|
|
121
128
|
outcome, ran := outcomes[key]
|
|
122
129
|
if !ran {
|
|
130
|
+
started := time.Now().UTC()
|
|
123
131
|
outcome = Execute(ctx, gate.Check, cwd, timeout)
|
|
124
132
|
outcomes[key] = outcome
|
|
133
|
+
spans[key] = [2]time.Time{started, time.Now().UTC()}
|
|
125
134
|
}
|
|
135
|
+
span := spans[key]
|
|
126
136
|
if outcome.Err == nil && outcome.ExitCode == 0 && expectation.Matches(outcome.Output) {
|
|
127
137
|
evidence := withInputs(FormatEvidence(gate, OutputDigest(outcome.Output), outcome.OutputBytes, time.Now().UTC().Format(time.RFC3339)), inputs)
|
|
128
138
|
writeErr := write(gate, evidence, true)
|
|
@@ -130,6 +140,7 @@ func RunGates(ctx context.Context, root, ledgerPath string, doc *Document, appro
|
|
|
130
140
|
ID: gate.ID, Ran: true, Passed: true,
|
|
131
141
|
Discarded: errors.Is(writeErr, ErrOracleMoved), WriteErr: writeErr,
|
|
132
142
|
Detail: resultDetail(writeErr, "pass"),
|
|
143
|
+
Inputs: inputs, Outcome: outcome, Started: span[0], Ended: span[1],
|
|
133
144
|
})
|
|
134
145
|
} else {
|
|
135
146
|
writeErr := write(gate, "pending", false)
|
|
@@ -137,6 +148,7 @@ func RunGates(ctx context.Context, root, ledgerPath string, doc *Document, appro
|
|
|
137
148
|
ID: gate.ID, Ran: true,
|
|
138
149
|
Discarded: errors.Is(writeErr, ErrOracleMoved), WriteErr: writeErr,
|
|
139
150
|
Detail: resultDetail(writeErr, failDetail(outcome, expectation)),
|
|
151
|
+
Inputs: inputs, Outcome: outcome, Started: span[0], Ended: span[1],
|
|
140
152
|
})
|
|
141
153
|
}
|
|
142
154
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
package acceptance
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"os"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"regexp"
|
|
8
|
+
"strings"
|
|
9
|
+
"time"
|
|
10
|
+
|
|
11
|
+
"github.com/devrites/devrites/internal/secretpattern"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
// CandidateDigest computes the feature's candidate identity. main wires it to
|
|
15
|
+
// the candidate hash in package lib, which imports this package; nil reports
|
|
16
|
+
// the identity as unavailable.
|
|
17
|
+
var CandidateDigest func(root, slug string) (string, error)
|
|
18
|
+
|
|
19
|
+
// maxTranscriptOutput caps the redacted output a transcript keeps.
|
|
20
|
+
const maxTranscriptOutput = 1 << 20
|
|
21
|
+
|
|
22
|
+
var unsafeNameRE = regexp.MustCompile(`[^A-Za-z0-9._-]`)
|
|
23
|
+
|
|
24
|
+
func candidateLabel(root, slug string) string {
|
|
25
|
+
if CandidateDigest == nil {
|
|
26
|
+
return "unavailable: no candidate identity"
|
|
27
|
+
}
|
|
28
|
+
digest, err := CandidateDigest(root, slug)
|
|
29
|
+
if err != nil {
|
|
30
|
+
return "unavailable: " + oneLine(err.Error())
|
|
31
|
+
}
|
|
32
|
+
return digest
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// writeTranscripts records one immutable file per executed or reused gate under
|
|
36
|
+
// <work>/references/gates/<gate-id>/, binding the exact command, cwd, attempt,
|
|
37
|
+
// exit, EXPECT verdict and redacted output to the candidate identity read
|
|
38
|
+
// before and after the run. OUTPUT_SHA256 equals the ledger evidence digest.
|
|
39
|
+
func writeTranscripts(work string, doc *Document, results []GateResult, before, after string) ([]string, error) {
|
|
40
|
+
gates := map[string]*Gate{}
|
|
41
|
+
for _, gate := range doc.Gates {
|
|
42
|
+
gates[gate.ID] = gate
|
|
43
|
+
}
|
|
44
|
+
prefix := "nodigest"
|
|
45
|
+
if len(before) >= 12 && !strings.HasPrefix(before, "unavailable") {
|
|
46
|
+
prefix = before[:12]
|
|
47
|
+
}
|
|
48
|
+
var paths []string
|
|
49
|
+
for _, result := range results {
|
|
50
|
+
gate := gates[result.ID]
|
|
51
|
+
if gate == nil || (!result.Ran && !result.Reused) {
|
|
52
|
+
continue
|
|
53
|
+
}
|
|
54
|
+
name := unsafeNameRE.ReplaceAllString(gate.ID, "_")
|
|
55
|
+
if name == "." || name == ".." {
|
|
56
|
+
name = "_"
|
|
57
|
+
}
|
|
58
|
+
dir := filepath.Join(work, "references", "gates", name)
|
|
59
|
+
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
60
|
+
return paths, err
|
|
61
|
+
}
|
|
62
|
+
var body strings.Builder
|
|
63
|
+
fmt.Fprintf(&body, "DEVRITES-GATE-TRANSCRIPT v1\nGATE: %s\nTITLE: %s\nCOMMAND: %s\nCWD: %s\n", gate.ID, gate.Title, gate.Check, valueOr(gate.Cwd, "."))
|
|
64
|
+
fmt.Fprintf(&body, "INPUTS: %s\nINPUTS_SHA256: %s\nCANDIDATE_BEFORE: %s\nCANDIDATE_AFTER: %s\n", valueOr(gate.Inputs, "none"), valueOr(result.Inputs, "none"), before, after)
|
|
65
|
+
var file string
|
|
66
|
+
if result.Reused {
|
|
67
|
+
file = filepath.Join(dir, prefix+"-reused.log")
|
|
68
|
+
fmt.Fprintf(&body, "RESULT: reused (inputs unchanged; not executed)\nPRIOR_EVIDENCE: %s\n", gate.Evidence)
|
|
69
|
+
} else {
|
|
70
|
+
attempt := 1
|
|
71
|
+
if entries, err := os.ReadDir(dir); err == nil {
|
|
72
|
+
for _, entry := range entries {
|
|
73
|
+
if strings.HasPrefix(entry.Name(), prefix+"-a") {
|
|
74
|
+
attempt++
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
file = filepath.Join(dir, fmt.Sprintf("%s-a%d.log", prefix, attempt))
|
|
79
|
+
output, masked := secretpattern.Redact(result.Outcome.Output)
|
|
80
|
+
truncated := len(output) > maxTranscriptOutput
|
|
81
|
+
if truncated {
|
|
82
|
+
output = output[:maxTranscriptOutput]
|
|
83
|
+
}
|
|
84
|
+
verdict := "fail"
|
|
85
|
+
if result.Passed {
|
|
86
|
+
verdict = "pass"
|
|
87
|
+
}
|
|
88
|
+
fmt.Fprintf(&body, "ATTEMPT: %d\nSTARTED: %s\nENDED: %s\nEXIT: %s\nEXPECT: %s\nRESULT: %s\n",
|
|
89
|
+
attempt, result.Started.Format(time.RFC3339Nano), result.Ended.Format(time.RFC3339Nano), exitLabel(result.Outcome), gate.Expect, verdict)
|
|
90
|
+
fmt.Fprintf(&body, "OUTPUT_SHA256: %s\nOUTPUT_BYTES: %d\nREDACTIONS: %d\nTRUNCATED: %t\n--- OUTPUT ---\n%s\n--- END OUTPUT ---\n",
|
|
91
|
+
OutputDigest(result.Outcome.Output), result.Outcome.OutputBytes, masked, truncated, output)
|
|
92
|
+
}
|
|
93
|
+
if err := os.WriteFile(file, []byte(body.String()), 0o644); err != nil {
|
|
94
|
+
return paths, err
|
|
95
|
+
}
|
|
96
|
+
paths = append(paths, file)
|
|
97
|
+
}
|
|
98
|
+
return paths, nil
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func exitLabel(outcome RunOutcome) string {
|
|
102
|
+
switch {
|
|
103
|
+
case outcome.TimedOut:
|
|
104
|
+
return "timeout"
|
|
105
|
+
case outcome.Err != nil:
|
|
106
|
+
return "error: " + oneLine(outcome.Err.Error())
|
|
107
|
+
}
|
|
108
|
+
return fmt.Sprint(outcome.ExitCode)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func valueOr(value, fallback string) string {
|
|
112
|
+
if value == "" {
|
|
113
|
+
return fallback
|
|
114
|
+
}
|
|
115
|
+
return value
|
|
116
|
+
}
|
|
@@ -8,10 +8,11 @@ import (
|
|
|
8
8
|
"io"
|
|
9
9
|
"os"
|
|
10
10
|
"path/filepath"
|
|
11
|
-
"regexp"
|
|
12
11
|
"sort"
|
|
13
12
|
"strconv"
|
|
14
13
|
"strings"
|
|
14
|
+
|
|
15
|
+
"github.com/devrites/devrites/internal/secretpattern"
|
|
15
16
|
)
|
|
16
17
|
|
|
17
18
|
type secretFinding struct {
|
|
@@ -71,17 +72,7 @@ func (w *boundedSecretScanBuffer) Len() int {
|
|
|
71
72
|
return w.buffer.Len()
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
var secretPatterns =
|
|
75
|
-
sev, kind string
|
|
76
|
-
re *regexp.Regexp
|
|
77
|
-
}{
|
|
78
|
-
{"HIGH", "private-key", regexp.MustCompile(`-----BEGIN (RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----`)},
|
|
79
|
-
{"HIGH", "aws-secret", regexp.MustCompile(`(?i)aws(.{0,20})?(secret|access).{0,20}[=:]\s*['\"]?[A-Za-z0-9/+=]{30,}`)},
|
|
80
|
-
{"HIGH", "github-token", regexp.MustCompile(`gh[pousr]_[A-Za-z0-9_]{30,}`)},
|
|
81
|
-
{"HIGH", "slack-token", regexp.MustCompile(`xox[baprs]-[A-Za-z0-9-]{20,}`)},
|
|
82
|
-
{"MEDIUM", "generic-secret", regexp.MustCompile(`(?i)(api[_-]?key|token|secret|password)\s*[:=]\s*['\"][^'\"\n]{16,}['\"]`)},
|
|
83
|
-
{"LOW", "placeholder-secret", regexp.MustCompile(`(?i)(api[_-]?key|token|secret|password).{0,20}(example|changeme|placeholder|dummy)`)},
|
|
84
|
-
}
|
|
75
|
+
var secretPatterns = secretpattern.Patterns
|
|
85
76
|
|
|
86
77
|
// SecretScan scans staged blobs, stdin, or touched files for credentials. HIGH exits 3.
|
|
87
78
|
func SecretScan(root string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
|
|
@@ -253,12 +244,12 @@ func scanCountedSecrets(path string, content []byte, budget *secretScanBudget) (
|
|
|
253
244
|
var out []secretFinding
|
|
254
245
|
source := secretSourceLabel(path)
|
|
255
246
|
for _, pattern := range secretPatterns {
|
|
256
|
-
matches := pattern.
|
|
247
|
+
matches := pattern.Re.FindAllIndex(content, budget.findingsRemaining+1)
|
|
257
248
|
if len(matches) > budget.findingsRemaining {
|
|
258
249
|
return nil, errSecretScanLimit
|
|
259
250
|
}
|
|
260
251
|
for _, match := range matches {
|
|
261
|
-
out = append(out, secretFinding{Severity: pattern.
|
|
252
|
+
out = append(out, secretFinding{Severity: pattern.Sev, Path: source, Kind: pattern.Kind, Offset: match[0]})
|
|
262
253
|
}
|
|
263
254
|
budget.findingsRemaining -= len(matches)
|
|
264
255
|
}
|
|
@@ -267,7 +258,7 @@ func scanCountedSecrets(path string, content []byte, budget *secretScanBudget) (
|
|
|
267
258
|
|
|
268
259
|
func secretSourceLabel(path string) string {
|
|
269
260
|
for _, pattern := range secretPatterns {
|
|
270
|
-
if pattern.
|
|
261
|
+
if pattern.Re.FindStringIndex(path) != nil {
|
|
271
262
|
return "<redacted-path>"
|
|
272
263
|
}
|
|
273
264
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Package secretpattern holds the credential patterns shared by the secret
|
|
2
|
+
// scanner and the gate transcript writer, so both mask the same shapes.
|
|
3
|
+
package secretpattern
|
|
4
|
+
|
|
5
|
+
import "regexp"
|
|
6
|
+
|
|
7
|
+
// Pattern is one credential shape with its scanner severity.
|
|
8
|
+
type Pattern struct {
|
|
9
|
+
Sev, Kind string
|
|
10
|
+
Re *regexp.Regexp
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Patterns are the credential shapes, most severe first.
|
|
14
|
+
var Patterns = []Pattern{
|
|
15
|
+
{"HIGH", "private-key", regexp.MustCompile(`-----BEGIN (RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----`)},
|
|
16
|
+
{"HIGH", "aws-secret", regexp.MustCompile(`(?i)aws(.{0,20})?(secret|access).{0,20}[=:]\s*['\"]?[A-Za-z0-9/+=]{30,}`)},
|
|
17
|
+
{"HIGH", "github-token", regexp.MustCompile(`gh[pousr]_[A-Za-z0-9_]{30,}`)},
|
|
18
|
+
{"HIGH", "slack-token", regexp.MustCompile(`xox[baprs]-[A-Za-z0-9-]{20,}`)},
|
|
19
|
+
{"MEDIUM", "generic-secret", regexp.MustCompile(`(?i)(api[_-]?key|token|secret|password)\s*[:=]\s*['\"][^'\"\n]{16,}['\"]`)},
|
|
20
|
+
{"LOW", "placeholder-secret", regexp.MustCompile(`(?i)(api[_-]?key|token|secret|password).{0,20}(example|changeme|placeholder|dummy)`)},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Redact masks every HIGH or MEDIUM match in text and returns the masked text
|
|
24
|
+
// and the number of masks. LOW placeholders are not credentials and stay.
|
|
25
|
+
func Redact(text string) (string, int) {
|
|
26
|
+
masked := 0
|
|
27
|
+
for _, pattern := range Patterns {
|
|
28
|
+
if pattern.Sev == "LOW" {
|
|
29
|
+
continue
|
|
30
|
+
}
|
|
31
|
+
text = pattern.Re.ReplaceAllStringFunc(text, func(string) string {
|
|
32
|
+
masked++
|
|
33
|
+
return "[REDACTED:" + pattern.Kind + "]"
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
return text, masked
|
|
37
|
+
}
|
package/engine/main.go
CHANGED
|
@@ -99,6 +99,15 @@ func main() {
|
|
|
99
99
|
os.Exit(run(os.Args[1:], os.Stdin, os.Stdout, os.Stderr))
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
func init() {
|
|
103
|
+
// acceptance cannot import lib (lib imports it), so gate transcripts get
|
|
104
|
+
// the candidate identity through this hook.
|
|
105
|
+
acceptance.CandidateDigest = func(root, slug string) (string, error) {
|
|
106
|
+
digest, _, err := lib.CandidateIdentity(root, slug)
|
|
107
|
+
return digest, err
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
102
111
|
// run is the testable entry point. It returns the process exit code.
|
|
103
112
|
func run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
|
|
104
113
|
if len(args) == 0 {
|
|
@@ -49,7 +49,12 @@ and only the orchestrator-supplied changed paths.
|
|
|
49
49
|
named blocker, never a pass. Otherwise use `cannot_verify`.
|
|
50
50
|
8. A manual gate whose `gates.md` note lacks the human's own words or source, is a
|
|
51
51
|
placeholder, or was runnable at Vet is `cannot_verify` ([`gates.md`](../skills/devrites-lib/reference/standards/gates.md)).
|
|
52
|
-
9.
|
|
52
|
+
9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v1` under `references/gates/`)
|
|
53
|
+
is immutable proof of its COMMAND, CWD, ATTEMPT, EXIT and output for the
|
|
54
|
+
candidate in CANDIDATE_BEFORE/AFTER. A `-reused.log` proves a gate for the
|
|
55
|
+
current candidate only when its INPUTS_SHA256 equals that of the gate's latest
|
|
56
|
+
executed, passing transcript.
|
|
57
|
+
10. Recheck supplied before/after candidate identities. A mismatch or unexpected
|
|
53
58
|
repository mutation fails the side-effect boundary.
|
|
54
59
|
|
|
55
60
|
## Rules
|
|
@@ -55,7 +55,12 @@ execute unreviewed code.
|
|
|
55
55
|
|
|
56
56
|
Execution contract: the command runs through the platform shell in the named
|
|
57
57
|
directory with a bounded timeout; pass requires exit 0 **and** output matching
|
|
58
|
-
EXPECT.
|
|
58
|
+
EXPECT. Without `--transcripts`, output is captured but never persisted, only its
|
|
59
|
+
digest. `--transcripts` writes one file per executed or reused gate under
|
|
60
|
+
`references/gates/<gate-id>/`. Each file holds the command, cwd, attempt, times,
|
|
61
|
+
exit, EXPECT verdict, the candidate digest read before and after the run, and the
|
|
62
|
+
output with known credential shapes masked and capped at 1 MiB. Its
|
|
63
|
+
`OUTPUT_SHA256` equals the ledger evidence digest.
|
|
59
64
|
|
|
60
65
|
After Vet READY the runnable set is fixed: converting a runnable gate to manual,
|
|
61
66
|
loosening EXPECT, changing CHECK or CWD, adding or narrowing INPUTS, or removing
|
|
@@ -84,10 +84,13 @@ test changes.
|
|
|
84
84
|
pass is `flaky` per [`testing.md`](../devrites-lib/reference/standards/testing.md#determinism-no-flaky-tests),
|
|
85
85
|
never green. Static gates prove only their named
|
|
86
86
|
static criterion.
|
|
87
|
-
Run the acceptance ledger
|
|
88
|
-
unmet runnable gate against the same approved
|
|
89
|
-
definition-bound evidence
|
|
90
|
-
|
|
87
|
+
Run the acceptance ledger with `--transcripts`: `devrites-engine gates run <slug>
|
|
88
|
+
--transcripts` executes every unmet runnable gate against the same approved
|
|
89
|
+
preflight rows, records definition-bound evidence, and writes one redacted,
|
|
90
|
+
candidate-bound transcript per gate under `references/gates/<gate-id>/`;
|
|
91
|
+
`gates reverify <slug> --transcripts` re-executes all of them when any prior
|
|
92
|
+
pass is in doubt. Hand the proof runner those transcripts, never hand-built
|
|
93
|
+
logs. Attest manual gates with `gates attest
|
|
91
94
|
<slug> <id> <note>` only against observed judgment whose note cites the
|
|
92
95
|
human's own words or source; placeholder notes are unmet and an AFK run never
|
|
93
96
|
self-attests. Only gates manual at Vet are attested; runnable-to-manual
|
|
@@ -82,7 +82,9 @@ Follow [`reference/phase-contract.md`](reference/phase-contract.md)
|
|
|
82
82
|
that is malformed, unmet,
|
|
83
83
|
stale, unapproved, or abandoned — a seal-side `gates status` reading anything
|
|
84
84
|
but `all-met` means Prove's evidence is not current; return there, never
|
|
85
|
-
attest past it.
|
|
85
|
+
attest past it. Before the Seal wave, run `devrites-engine gates reverify <slug>
|
|
86
|
+
--transcripts` on the frozen candidate, so every gate has a transcript bound to
|
|
87
|
+
this digest for the proof runner. It likewise refuses a malformed `notes.md` or any anchor
|
|
86
88
|
graded other than `exact`: `devrites-engine note check <slug> --repair`
|
|
87
89
|
re-anchors `moved` notes; `stale`/`ambiguous`/`lost` ones are corrected or
|
|
88
90
|
removed before GO.
|
|
@@ -55,7 +55,12 @@ and only the orchestrator-supplied changed paths.
|
|
|
55
55
|
named blocker, never a pass. Otherwise use `cannot_verify`.
|
|
56
56
|
8. A manual gate whose `gates.md` note lacks the human's own words or source, is a
|
|
57
57
|
placeholder, or was runnable at Vet is `cannot_verify` ([`gates.md`](../skills/devrites-lib/reference/standards/gates.md)).
|
|
58
|
-
9.
|
|
58
|
+
9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v1` under `references/gates/`)
|
|
59
|
+
is immutable proof of its COMMAND, CWD, ATTEMPT, EXIT and output for the
|
|
60
|
+
candidate in CANDIDATE_BEFORE/AFTER. A `-reused.log` proves a gate for the
|
|
61
|
+
current candidate only when its INPUTS_SHA256 equals that of the gate's latest
|
|
62
|
+
executed, passing transcript.
|
|
63
|
+
10. Recheck supplied before/after candidate identities. A mismatch or unexpected
|
|
59
64
|
repository mutation fails the side-effect boundary.
|
|
60
65
|
|
|
61
66
|
## Rules
|
|
@@ -55,7 +55,12 @@ execute unreviewed code.
|
|
|
55
55
|
|
|
56
56
|
Execution contract: the command runs through the platform shell in the named
|
|
57
57
|
directory with a bounded timeout; pass requires exit 0 **and** output matching
|
|
58
|
-
EXPECT.
|
|
58
|
+
EXPECT. Without `--transcripts`, output is captured but never persisted, only its
|
|
59
|
+
digest. `--transcripts` writes one file per executed or reused gate under
|
|
60
|
+
`references/gates/<gate-id>/`. Each file holds the command, cwd, attempt, times,
|
|
61
|
+
exit, EXPECT verdict, the candidate digest read before and after the run, and the
|
|
62
|
+
output with known credential shapes masked and capped at 1 MiB. Its
|
|
63
|
+
`OUTPUT_SHA256` equals the ledger evidence digest.
|
|
59
64
|
|
|
60
65
|
After Vet READY the runnable set is fixed: converting a runnable gate to manual,
|
|
61
66
|
loosening EXPECT, changing CHECK or CWD, adding or narrowing INPUTS, or removing
|
|
@@ -84,10 +84,13 @@ test changes.
|
|
|
84
84
|
pass is `flaky` per [`testing.md`](../devrites-lib/reference/standards/testing.md#determinism-no-flaky-tests),
|
|
85
85
|
never green. Static gates prove only their named
|
|
86
86
|
static criterion.
|
|
87
|
-
Run the acceptance ledger
|
|
88
|
-
unmet runnable gate against the same approved
|
|
89
|
-
definition-bound evidence
|
|
90
|
-
|
|
87
|
+
Run the acceptance ledger with `--transcripts`: `devrites-engine gates run <slug>
|
|
88
|
+
--transcripts` executes every unmet runnable gate against the same approved
|
|
89
|
+
preflight rows, records definition-bound evidence, and writes one redacted,
|
|
90
|
+
candidate-bound transcript per gate under `references/gates/<gate-id>/`;
|
|
91
|
+
`gates reverify <slug> --transcripts` re-executes all of them when any prior
|
|
92
|
+
pass is in doubt. Hand the proof runner those transcripts, never hand-built
|
|
93
|
+
logs. Attest manual gates with `gates attest
|
|
91
94
|
<slug> <id> <note>` only against observed judgment whose note cites the
|
|
92
95
|
human's own words or source; placeholder notes are unmet and an AFK run never
|
|
93
96
|
self-attests. Only gates manual at Vet are attested; runnable-to-manual
|
|
@@ -82,7 +82,9 @@ Follow [`reference/phase-contract.md`](reference/phase-contract.md)
|
|
|
82
82
|
that is malformed, unmet,
|
|
83
83
|
stale, unapproved, or abandoned — a seal-side `gates status` reading anything
|
|
84
84
|
but `all-met` means Prove's evidence is not current; return there, never
|
|
85
|
-
attest past it.
|
|
85
|
+
attest past it. Before the Seal wave, run `devrites-engine gates reverify <slug>
|
|
86
|
+
--transcripts` on the frozen candidate, so every gate has a transcript bound to
|
|
87
|
+
this digest for the proof runner. It likewise refuses a malformed `notes.md` or any anchor
|
|
86
88
|
graded other than `exact`: `devrites-engine note check <slug> --repair`
|
|
87
89
|
re-anchors `moved` notes; `stale`/`ambiguous`/`lost` ones are corrected or
|
|
88
90
|
removed before GO.
|
|
@@ -53,7 +53,12 @@ and only the orchestrator-supplied changed paths.
|
|
|
53
53
|
named blocker, never a pass. Otherwise use `cannot_verify`.
|
|
54
54
|
8. A manual gate whose `gates.md` note lacks the human's own words or source, is a
|
|
55
55
|
placeholder, or was runnable at Vet is `cannot_verify` ([`gates.md`](.agents/skills/devrites-lib/reference/standards/gates.md)).
|
|
56
|
-
9.
|
|
56
|
+
9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v1` under `references/gates/`)
|
|
57
|
+
is immutable proof of its COMMAND, CWD, ATTEMPT, EXIT and output for the
|
|
58
|
+
candidate in CANDIDATE_BEFORE/AFTER. A `-reused.log` proves a gate for the
|
|
59
|
+
current candidate only when its INPUTS_SHA256 equals that of the gate's latest
|
|
60
|
+
executed, passing transcript.
|
|
61
|
+
10. Recheck supplied before/after candidate identities. A mismatch or unexpected
|
|
57
62
|
repository mutation fails the side-effect boundary.
|
|
58
63
|
|
|
59
64
|
## Rules
|
|
@@ -55,7 +55,12 @@ execute unreviewed code.
|
|
|
55
55
|
|
|
56
56
|
Execution contract: the command runs through the platform shell in the named
|
|
57
57
|
directory with a bounded timeout; pass requires exit 0 **and** output matching
|
|
58
|
-
EXPECT.
|
|
58
|
+
EXPECT. Without `--transcripts`, output is captured but never persisted, only its
|
|
59
|
+
digest. `--transcripts` writes one file per executed or reused gate under
|
|
60
|
+
`references/gates/<gate-id>/`. Each file holds the command, cwd, attempt, times,
|
|
61
|
+
exit, EXPECT verdict, the candidate digest read before and after the run, and the
|
|
62
|
+
output with known credential shapes masked and capped at 1 MiB. Its
|
|
63
|
+
`OUTPUT_SHA256` equals the ledger evidence digest.
|
|
59
64
|
|
|
60
65
|
After Vet READY the runnable set is fixed: converting a runnable gate to manual,
|
|
61
66
|
loosening EXPECT, changing CHECK or CWD, adding or narrowing INPUTS, or removing
|
|
@@ -84,10 +84,13 @@ test changes.
|
|
|
84
84
|
pass is `flaky` per [`testing.md`](../devrites-lib/reference/standards/testing.md#determinism-no-flaky-tests),
|
|
85
85
|
never green. Static gates prove only their named
|
|
86
86
|
static criterion.
|
|
87
|
-
Run the acceptance ledger
|
|
88
|
-
unmet runnable gate against the same approved
|
|
89
|
-
definition-bound evidence
|
|
90
|
-
|
|
87
|
+
Run the acceptance ledger with `--transcripts`: `devrites-engine gates run <slug>
|
|
88
|
+
--transcripts` executes every unmet runnable gate against the same approved
|
|
89
|
+
preflight rows, records definition-bound evidence, and writes one redacted,
|
|
90
|
+
candidate-bound transcript per gate under `references/gates/<gate-id>/`;
|
|
91
|
+
`gates reverify <slug> --transcripts` re-executes all of them when any prior
|
|
92
|
+
pass is in doubt. Hand the proof runner those transcripts, never hand-built
|
|
93
|
+
logs. Attest manual gates with `gates attest
|
|
91
94
|
<slug> <id> <note>` only against observed judgment whose note cites the
|
|
92
95
|
human's own words or source; placeholder notes are unmet and an AFK run never
|
|
93
96
|
self-attests. Only gates manual at Vet are attested; runnable-to-manual
|
|
@@ -82,7 +82,9 @@ Follow [`reference/phase-contract.md`](reference/phase-contract.md)
|
|
|
82
82
|
that is malformed, unmet,
|
|
83
83
|
stale, unapproved, or abandoned — a seal-side `gates status` reading anything
|
|
84
84
|
but `all-met` means Prove's evidence is not current; return there, never
|
|
85
|
-
attest past it.
|
|
85
|
+
attest past it. Before the Seal wave, run `devrites-engine gates reverify <slug>
|
|
86
|
+
--transcripts` on the frozen candidate, so every gate has a transcript bound to
|
|
87
|
+
this digest for the proof runner. It likewise refuses a malformed `notes.md` or any anchor
|
|
86
88
|
graded other than `exact`: `devrites-engine note check <slug> --repair`
|
|
87
89
|
re-anchors `moved` notes; `stale`/`ambiguous`/`lost` ones are corrected or
|
|
88
90
|
removed before GO.
|
|
@@ -57,7 +57,12 @@ and only the orchestrator-supplied changed paths.
|
|
|
57
57
|
named blocker, never a pass. Otherwise use `cannot_verify`.
|
|
58
58
|
8. A manual gate whose `gates.md` note lacks the human's own words or source, is a
|
|
59
59
|
placeholder, or was runnable at Vet is `cannot_verify` ([`gates.md`](../skills/devrites-lib/reference/standards/gates.md)).
|
|
60
|
-
9.
|
|
60
|
+
9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v1` under `references/gates/`)
|
|
61
|
+
is immutable proof of its COMMAND, CWD, ATTEMPT, EXIT and output for the
|
|
62
|
+
candidate in CANDIDATE_BEFORE/AFTER. A `-reused.log` proves a gate for the
|
|
63
|
+
current candidate only when its INPUTS_SHA256 equals that of the gate's latest
|
|
64
|
+
executed, passing transcript.
|
|
65
|
+
10. Recheck supplied before/after candidate identities. A mismatch or unexpected
|
|
61
66
|
repository mutation fails the side-effect boundary.
|
|
62
67
|
|
|
63
68
|
## Rules
|
|
@@ -55,7 +55,12 @@ execute unreviewed code.
|
|
|
55
55
|
|
|
56
56
|
Execution contract: the command runs through the platform shell in the named
|
|
57
57
|
directory with a bounded timeout; pass requires exit 0 **and** output matching
|
|
58
|
-
EXPECT.
|
|
58
|
+
EXPECT. Without `--transcripts`, output is captured but never persisted, only its
|
|
59
|
+
digest. `--transcripts` writes one file per executed or reused gate under
|
|
60
|
+
`references/gates/<gate-id>/`. Each file holds the command, cwd, attempt, times,
|
|
61
|
+
exit, EXPECT verdict, the candidate digest read before and after the run, and the
|
|
62
|
+
output with known credential shapes masked and capped at 1 MiB. Its
|
|
63
|
+
`OUTPUT_SHA256` equals the ledger evidence digest.
|
|
59
64
|
|
|
60
65
|
After Vet READY the runnable set is fixed: converting a runnable gate to manual,
|
|
61
66
|
loosening EXPECT, changing CHECK or CWD, adding or narrowing INPUTS, or removing
|
|
@@ -83,10 +83,13 @@ test changes.
|
|
|
83
83
|
pass is `flaky` per [`testing.md`](../devrites-lib/reference/standards/testing.md#determinism-no-flaky-tests),
|
|
84
84
|
never green. Static gates prove only their named
|
|
85
85
|
static criterion.
|
|
86
|
-
Run the acceptance ledger
|
|
87
|
-
unmet runnable gate against the same approved
|
|
88
|
-
definition-bound evidence
|
|
89
|
-
|
|
86
|
+
Run the acceptance ledger with `--transcripts`: `devrites-engine gates run <slug>
|
|
87
|
+
--transcripts` executes every unmet runnable gate against the same approved
|
|
88
|
+
preflight rows, records definition-bound evidence, and writes one redacted,
|
|
89
|
+
candidate-bound transcript per gate under `references/gates/<gate-id>/`;
|
|
90
|
+
`gates reverify <slug> --transcripts` re-executes all of them when any prior
|
|
91
|
+
pass is in doubt. Hand the proof runner those transcripts, never hand-built
|
|
92
|
+
logs. Attest manual gates with `gates attest
|
|
90
93
|
<slug> <id> <note>` only against observed judgment whose note cites the
|
|
91
94
|
human's own words or source; placeholder notes are unmet and an AFK run never
|
|
92
95
|
self-attests. Only gates manual at Vet are attested; runnable-to-manual
|
|
@@ -81,7 +81,9 @@ Follow [`reference/phase-contract.md`](reference/phase-contract.md)
|
|
|
81
81
|
that is malformed, unmet,
|
|
82
82
|
stale, unapproved, or abandoned — a seal-side `gates status` reading anything
|
|
83
83
|
but `all-met` means Prove's evidence is not current; return there, never
|
|
84
|
-
attest past it.
|
|
84
|
+
attest past it. Before the Seal wave, run `devrites-engine gates reverify <slug>
|
|
85
|
+
--transcripts` on the frozen candidate, so every gate has a transcript bound to
|
|
86
|
+
this digest for the proof runner. It likewise refuses a malformed `notes.md` or any anchor
|
|
85
87
|
graded other than `exact`: `devrites-engine note check <slug> --repair`
|
|
86
88
|
re-anchors `moved` notes; `stale`/`ambiguous`/`lost` ones are corrected or
|
|
87
89
|
removed before GO.
|
|
@@ -54,7 +54,12 @@ and only the orchestrator-supplied changed paths.
|
|
|
54
54
|
named blocker, never a pass. Otherwise use `cannot_verify`.
|
|
55
55
|
8. A manual gate whose `gates.md` note lacks the human's own words or source, is a
|
|
56
56
|
placeholder, or was runnable at Vet is `cannot_verify` ([`gates.md`](skill://devrites-lib/reference/standards/gates.md)).
|
|
57
|
-
9.
|
|
57
|
+
9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v1` under `references/gates/`)
|
|
58
|
+
is immutable proof of its COMMAND, CWD, ATTEMPT, EXIT and output for the
|
|
59
|
+
candidate in CANDIDATE_BEFORE/AFTER. A `-reused.log` proves a gate for the
|
|
60
|
+
current candidate only when its INPUTS_SHA256 equals that of the gate's latest
|
|
61
|
+
executed, passing transcript.
|
|
62
|
+
10. Recheck supplied before/after candidate identities. A mismatch or unexpected
|
|
58
63
|
repository mutation fails the side-effect boundary.
|
|
59
64
|
|
|
60
65
|
## Rules
|
|
@@ -55,7 +55,12 @@ execute unreviewed code.
|
|
|
55
55
|
|
|
56
56
|
Execution contract: the command runs through the platform shell in the named
|
|
57
57
|
directory with a bounded timeout; pass requires exit 0 **and** output matching
|
|
58
|
-
EXPECT.
|
|
58
|
+
EXPECT. Without `--transcripts`, output is captured but never persisted, only its
|
|
59
|
+
digest. `--transcripts` writes one file per executed or reused gate under
|
|
60
|
+
`references/gates/<gate-id>/`. Each file holds the command, cwd, attempt, times,
|
|
61
|
+
exit, EXPECT verdict, the candidate digest read before and after the run, and the
|
|
62
|
+
output with known credential shapes masked and capped at 1 MiB. Its
|
|
63
|
+
`OUTPUT_SHA256` equals the ledger evidence digest.
|
|
59
64
|
|
|
60
65
|
After Vet READY the runnable set is fixed: converting a runnable gate to manual,
|
|
61
66
|
loosening EXPECT, changing CHECK or CWD, adding or narrowing INPUTS, or removing
|
|
@@ -84,10 +84,13 @@ test changes.
|
|
|
84
84
|
pass is `flaky` per [`testing.md`](skill://devrites-lib/reference/standards/testing.md#determinism-no-flaky-tests),
|
|
85
85
|
never green. Static gates prove only their named
|
|
86
86
|
static criterion.
|
|
87
|
-
Run the acceptance ledger
|
|
88
|
-
unmet runnable gate against the same approved
|
|
89
|
-
definition-bound evidence
|
|
90
|
-
|
|
87
|
+
Run the acceptance ledger with `--transcripts`: `devrites-engine gates run <slug>
|
|
88
|
+
--transcripts` executes every unmet runnable gate against the same approved
|
|
89
|
+
preflight rows, records definition-bound evidence, and writes one redacted,
|
|
90
|
+
candidate-bound transcript per gate under `references/gates/<gate-id>/`;
|
|
91
|
+
`gates reverify <slug> --transcripts` re-executes all of them when any prior
|
|
92
|
+
pass is in doubt. Hand the proof runner those transcripts, never hand-built
|
|
93
|
+
logs. Attest manual gates with `gates attest
|
|
91
94
|
<slug> <id> <note>` only against observed judgment whose note cites the
|
|
92
95
|
human's own words or source; placeholder notes are unmet and an AFK run never
|
|
93
96
|
self-attests. Only gates manual at Vet are attested; runnable-to-manual
|
|
@@ -82,7 +82,9 @@ Follow [`reference/phase-contract.md`](reference/phase-contract.md)
|
|
|
82
82
|
that is malformed, unmet,
|
|
83
83
|
stale, unapproved, or abandoned — a seal-side `gates status` reading anything
|
|
84
84
|
but `all-met` means Prove's evidence is not current; return there, never
|
|
85
|
-
attest past it.
|
|
85
|
+
attest past it. Before the Seal wave, run `devrites-engine gates reverify <slug>
|
|
86
|
+
--transcripts` on the frozen candidate, so every gate has a transcript bound to
|
|
87
|
+
this digest for the proof runner. It likewise refuses a malformed `notes.md` or any anchor
|
|
86
88
|
graded other than `exact`: `devrites-engine note check <slug> --repair`
|
|
87
89
|
re-anchors `moved` notes; `stale`/`ambiguous`/`lost` ones are corrected or
|
|
88
90
|
removed before GO.
|
|
@@ -55,7 +55,12 @@ and only the orchestrator-supplied changed paths.
|
|
|
55
55
|
named blocker, never a pass. Otherwise use `cannot_verify`.
|
|
56
56
|
8. A manual gate whose `gates.md` note lacks the human's own words or source, is a
|
|
57
57
|
placeholder, or was runnable at Vet is `cannot_verify` ([`gates.md`](../skills/devrites-lib/reference/standards/gates.md)).
|
|
58
|
-
9.
|
|
58
|
+
9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v1` under `references/gates/`)
|
|
59
|
+
is immutable proof of its COMMAND, CWD, ATTEMPT, EXIT and output for the
|
|
60
|
+
candidate in CANDIDATE_BEFORE/AFTER. A `-reused.log` proves a gate for the
|
|
61
|
+
current candidate only when its INPUTS_SHA256 equals that of the gate's latest
|
|
62
|
+
executed, passing transcript.
|
|
63
|
+
10. Recheck supplied before/after candidate identities. A mismatch or unexpected
|
|
59
64
|
repository mutation fails the side-effect boundary.
|
|
60
65
|
|
|
61
66
|
## Rules
|
|
@@ -55,7 +55,12 @@ execute unreviewed code.
|
|
|
55
55
|
|
|
56
56
|
Execution contract: the command runs through the platform shell in the named
|
|
57
57
|
directory with a bounded timeout; pass requires exit 0 **and** output matching
|
|
58
|
-
EXPECT.
|
|
58
|
+
EXPECT. Without `--transcripts`, output is captured but never persisted, only its
|
|
59
|
+
digest. `--transcripts` writes one file per executed or reused gate under
|
|
60
|
+
`references/gates/<gate-id>/`. Each file holds the command, cwd, attempt, times,
|
|
61
|
+
exit, EXPECT verdict, the candidate digest read before and after the run, and the
|
|
62
|
+
output with known credential shapes masked and capped at 1 MiB. Its
|
|
63
|
+
`OUTPUT_SHA256` equals the ledger evidence digest.
|
|
59
64
|
|
|
60
65
|
After Vet READY the runnable set is fixed: converting a runnable gate to manual,
|
|
61
66
|
loosening EXPECT, changing CHECK or CWD, adding or narrowing INPUTS, or removing
|
|
@@ -84,10 +84,13 @@ test changes.
|
|
|
84
84
|
pass is `flaky` per [`testing.md`](../devrites-lib/reference/standards/testing.md#determinism-no-flaky-tests),
|
|
85
85
|
never green. Static gates prove only their named
|
|
86
86
|
static criterion.
|
|
87
|
-
Run the acceptance ledger
|
|
88
|
-
unmet runnable gate against the same approved
|
|
89
|
-
definition-bound evidence
|
|
90
|
-
|
|
87
|
+
Run the acceptance ledger with `--transcripts`: `devrites-engine gates run <slug>
|
|
88
|
+
--transcripts` executes every unmet runnable gate against the same approved
|
|
89
|
+
preflight rows, records definition-bound evidence, and writes one redacted,
|
|
90
|
+
candidate-bound transcript per gate under `references/gates/<gate-id>/`;
|
|
91
|
+
`gates reverify <slug> --transcripts` re-executes all of them when any prior
|
|
92
|
+
pass is in doubt. Hand the proof runner those transcripts, never hand-built
|
|
93
|
+
logs. Attest manual gates with `gates attest
|
|
91
94
|
<slug> <id> <note>` only against observed judgment whose note cites the
|
|
92
95
|
human's own words or source; placeholder notes are unmet and an AFK run never
|
|
93
96
|
self-attests. Only gates manual at Vet are attested; runnable-to-manual
|
|
@@ -82,7 +82,9 @@ Follow [`reference/phase-contract.md`](reference/phase-contract.md)
|
|
|
82
82
|
that is malformed, unmet,
|
|
83
83
|
stale, unapproved, or abandoned — a seal-side `gates status` reading anything
|
|
84
84
|
but `all-met` means Prove's evidence is not current; return there, never
|
|
85
|
-
attest past it.
|
|
85
|
+
attest past it. Before the Seal wave, run `devrites-engine gates reverify <slug>
|
|
86
|
+
--transcripts` on the frozen candidate, so every gate has a transcript bound to
|
|
87
|
+
this digest for the proof runner. It likewise refuses a malformed `notes.md` or any anchor
|
|
86
88
|
graded other than `exact`: `devrites-engine note check <slug> --repair`
|
|
87
89
|
re-anchors `moved` notes; `stale`/`ambiguous`/`lost` ones are corrected or
|
|
88
90
|
removed before GO.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devrites",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.0",
|
|
4
4
|
"description": "DevRites: a disciplined senior-engineer workflow pack for Claude Code, Codex, omp, pi, and Devin CLI",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"homepage": "https://github.com/ViktorsBaikers/DevRites#readme",
|