thoth-agents 0.5.1 → 0.7.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.
Files changed (62) hide show
  1. package/README.md +88 -11
  2. package/dist/agents/prompt-dialects.d.ts +1 -0
  3. package/dist/{chunk-MRFCA3U2.js → chunk-3MHJGWS4.js} +2 -1
  4. package/dist/{chunk-V7HSGRMB.js → chunk-P3GDM5RH.js} +70 -174
  5. package/dist/{chunk-OW6I7ZUU.js → chunk-QOIZYJ5C.js} +322 -151
  6. package/dist/{chunk-VUNYH263.js → chunk-W5TSNGEE.js} +263 -44
  7. package/dist/cli/index.js +4 -4
  8. package/dist/cli/pi-install.d.ts +35 -67
  9. package/dist/cli/pi-tool-config.d.ts +19 -0
  10. package/dist/cli/tui/index.js +3 -3
  11. package/dist/config/constants.d.ts +30 -3
  12. package/dist/config/schema.d.ts +4 -0
  13. package/dist/harness/adapters/claude-code.d.ts +1 -1
  14. package/dist/harness/core/agent-pack.d.ts +6 -2
  15. package/dist/harness/core/result-contract.d.ts +366 -0
  16. package/dist/harness/core/sdd.d.ts +1 -1
  17. package/dist/harness/writers/pi-agent.d.ts +1 -0
  18. package/dist/index.js +2 -2
  19. package/dist/pi.d.ts +6 -35
  20. package/dist/pi.js +37 -433
  21. package/package.json +5 -3
  22. package/pi/.thoth-agents-assets.json +5 -5
  23. package/pi/agents/thoth-designer.md +15 -20
  24. package/pi/agents/thoth-explorer.md +15 -19
  25. package/pi/agents/thoth-librarian.md +15 -19
  26. package/pi/agents/thoth-oracle.md +30 -22
  27. package/pi/agents/thoth-worker.md +13 -18
  28. package/plugin/.claude-plugin/.thoth-agents-plugin-assets.json +6 -6
  29. package/plugin/.claude-plugin/plugin.json +1 -1
  30. package/plugin/.codex-plugin/plugin.json +1 -1
  31. package/plugin/agents/designer.md +9 -14
  32. package/plugin/agents/explorer.md +10 -14
  33. package/plugin/agents/librarian.md +9 -13
  34. package/plugin/agents/oracle.md +24 -18
  35. package/plugin/agents/orchestrator.md +38 -61
  36. package/plugin/agents/worker.md +9 -14
  37. package/plugin/skills/plan-reviewer/SKILL.md +16 -8
  38. package/plugin/skills/thoth-archive/SKILL.md +2 -1
  39. package/plugin/skills/thoth-constitution/SKILL.md +1 -1
  40. package/plugin/skills/thoth-constitution/templates/constitution.md +1 -1
  41. package/plugin/skills/thoth-init/SKILL.md +1 -1
  42. package/plugin/skills/thoth-sdd/SKILL.md +67 -2
  43. package/plugin/skills/thoth-sdd/references/phases/verify.md +11 -1
  44. package/plugin/skills/thoth-sdd/scripts/result-contract.json +210 -0
  45. package/plugin/skills/thoth-sdd/scripts/validate-result.d.mts +47 -0
  46. package/plugin/skills/thoth-sdd/scripts/validate-result.mjs +390 -0
  47. package/plugin/skills/thoth-sdd/scripts/validate.mjs +213 -8
  48. package/plugin/skills/thoth-sdd/templates/change.md +8 -0
  49. package/skills/plan-reviewer/SKILL.md +16 -8
  50. package/skills/thoth-archive/SKILL.md +2 -1
  51. package/skills/thoth-constitution/SKILL.md +1 -1
  52. package/skills/thoth-constitution/templates/constitution.md +1 -1
  53. package/skills/thoth-init/SKILL.md +1 -1
  54. package/skills/thoth-sdd/SKILL.md +67 -2
  55. package/skills/thoth-sdd/references/phases/verify.md +11 -1
  56. package/skills/thoth-sdd/scripts/result-contract.json +210 -0
  57. package/skills/thoth-sdd/scripts/validate-result.d.mts +47 -0
  58. package/skills/thoth-sdd/scripts/validate-result.mjs +390 -0
  59. package/skills/thoth-sdd/scripts/validate.mjs +213 -8
  60. package/skills/thoth-sdd/templates/change.md +8 -0
  61. package/thoth-agents.schema.json +14 -0
  62. package/dist/pi/tools-panel.d.ts +0 -51
@@ -17,6 +17,7 @@ import {
17
17
  parseRequirementDelta,
18
18
  preflightRequirementDeltas,
19
19
  } from './durable-deltas.mjs';
20
+ import { validateResult } from './validate-result.mjs';
20
21
 
21
22
  const sha = (bytes) => createHash('sha256').update(bytes).digest('hex');
22
23
  const gates = [
@@ -261,10 +262,16 @@ function preflightDeltas(root, deltas, errors, warnings, recordName) {
261
262
  }
262
263
 
263
264
  function settled(text) {
264
- return (
265
- Boolean(text?.trim()) &&
266
- !/\b(?:pending|unresolved|unknown|ask|tbd|todo)\b/i.test(text)
267
- );
265
+ if (!text?.trim() || /\bTBD\b/.test(text)) return false;
266
+ return !text.split(/\r?\n/).some((line) => {
267
+ const content = line
268
+ .replace(/\*\*|__/g, '')
269
+ .trim()
270
+ .replace(/^(?:[-+*]|\d+[.)])\s+/, '')
271
+ .replace(/^\[[ xX]\]\s*/, '')
272
+ .replace(/^AC-\d+:\s*/, '');
273
+ return /^(?:TBD|PENDING)(?=:|\s*$)/i.test(content);
274
+ });
268
275
  }
269
276
 
270
277
  function coverageErrors(text, ids, errors, recordName) {
@@ -293,6 +300,184 @@ function coverageErrors(text, ids, errors, recordName) {
293
300
  return rows;
294
301
  }
295
302
 
303
+ // Whole-file textual binding: Markdown containers never hide candidates or markers.
304
+ function scanOracleEnvelope(text) {
305
+ let offset = 0;
306
+ const lines = text.split(/(?<=\n)/).map((raw) => {
307
+ const entry = { raw, offset, line: raw.replace(/\r?\n$/, '') };
308
+ if (offset === 0) entry.line = entry.line.replace(/^\uFEFF/, '');
309
+ offset += raw.length;
310
+ return entry;
311
+ });
312
+ const markers = [];
313
+ const fences = [];
314
+ const authorization = lines.findIndex(
315
+ ({ line }) => line === '## Authorization',
316
+ );
317
+ const verification = lines.findIndex(
318
+ ({ line }) => line === '## Verification',
319
+ );
320
+ const closeout = lines.findIndex(
321
+ ({ line }, index) => index > verification && line === '## Closeout',
322
+ );
323
+ const verificationEnd = lines.findIndex(
324
+ ({ line }, index) => index > verification && line.startsWith('## '),
325
+ );
326
+ for (const [index, { line }] of lines.entries()) {
327
+ if (line.trim() === '**Oracle envelope**:') markers.push(index);
328
+ const opening =
329
+ /^(\s*)(?:[>*+-]\s*|\d+[.)]\s*)*(`{3,}|~{3,})\s*thoth-result/i.exec(line);
330
+ if (!opening) continue;
331
+ let end = index + 1;
332
+ for (; end < lines.length; end++) {
333
+ const closing = /^(\s*)(`{3,}|~{3,})[ \t]*$/.exec(lines[end].line);
334
+ if (
335
+ closing &&
336
+ closing[1] === opening[1] &&
337
+ closing[2][0] === opening[2][0] &&
338
+ closing[2].length >= opening[2].length
339
+ )
340
+ break;
341
+ }
342
+ fences.push({
343
+ index,
344
+ end,
345
+ closed: end < lines.length,
346
+ block: lines
347
+ .slice(index, end + 1)
348
+ .map(({ raw }) => raw)
349
+ .join(''),
350
+ });
351
+ }
352
+ let next = markers[0] + 1;
353
+ while (next < lines.length && !lines[next].line.trim()) next++;
354
+ const positioned =
355
+ verification >= 0 &&
356
+ closeout > verification &&
357
+ markers[0] > verification &&
358
+ markers[0] < verificationEnd &&
359
+ fences[0]?.index === next &&
360
+ next < verificationEnd &&
361
+ (!fences[0]?.closed || fences[0].end < verificationEnd);
362
+ return {
363
+ markers,
364
+ fences,
365
+ positioned,
366
+ authorizationOffset: lines[authorization]?.offset,
367
+ };
368
+ }
369
+
370
+ function validateOracleEnvelope({
371
+ extraction,
372
+ verificationFields,
373
+ recordSha256,
374
+ reviewedDigest,
375
+ expectedRecord,
376
+ errors,
377
+ recordName,
378
+ }) {
379
+ const { markers, fences, positioned } = extraction;
380
+ if (markers.length > 1 || fences.length > 1) {
381
+ errors.push(
382
+ issue(
383
+ 'SDD-ORACLE-ENVELOPE-DUPLICATE',
384
+ 'Exactly one Oracle envelope marker and block are required',
385
+ recordName,
386
+ ),
387
+ );
388
+ return;
389
+ }
390
+ if (!markers.length || !fences.length || !positioned) {
391
+ errors.push(
392
+ issue(
393
+ 'SDD-ORACLE-ENVELOPE-MISSING',
394
+ 'Oracle envelope marker followed by a final-verification block is required',
395
+ recordName,
396
+ ),
397
+ );
398
+ return;
399
+ }
400
+ if (!fences[0].closed) {
401
+ errors.push(
402
+ issue(
403
+ 'SDD-ORACLE-ENVELOPE-INVALID',
404
+ 'Oracle envelope fence is unclosed',
405
+ recordName,
406
+ ),
407
+ );
408
+ return;
409
+ }
410
+ // Preserve the original wrapper and line endings for shared-contract validation.
411
+ const result = validateResult(fences[0].block, {
412
+ reviewKind: 'final-verification',
413
+ recordSha256: recordSha256,
414
+ });
415
+ if (!result.valid) {
416
+ errors.push(
417
+ issue(
418
+ 'SDD-ORACLE-ENVELOPE-INVALID',
419
+ result.issues
420
+ .map((entry) => `${entry.code}: ${entry.message}`)
421
+ .join('; '),
422
+ recordName,
423
+ ),
424
+ );
425
+ if (
426
+ result.issues.some((entry) => entry.code === 'RECORD_DIGEST_MISMATCH')
427
+ ) {
428
+ errors.push(
429
+ issue(
430
+ 'SDD-ORACLE-ENVELOPE-DIGEST-MISMATCH',
431
+ 'Oracle envelope digest does not match the reviewed record prefix',
432
+ recordName,
433
+ ),
434
+ );
435
+ }
436
+ return;
437
+ }
438
+ const { review } = result.envelope;
439
+ if (review.verdict !== 'PASS') {
440
+ errors.push(
441
+ issue(
442
+ 'SDD-ORACLE-ENVELOPE-NOT-PASS',
443
+ 'Oracle final-verification verdict must be PASS',
444
+ recordName,
445
+ ),
446
+ );
447
+ }
448
+ if (review.reviewedRecord !== expectedRecord) {
449
+ errors.push(
450
+ issue(
451
+ 'SDD-ORACLE-ENVELOPE-RECORD-MISMATCH',
452
+ `Oracle envelope must review ${expectedRecord}`,
453
+ recordName,
454
+ ),
455
+ );
456
+ }
457
+ if (review.reviewedRecordSha256 !== reviewedDigest) {
458
+ errors.push(
459
+ issue(
460
+ 'SDD-ORACLE-ENVELOPE-DIGEST-MISMATCH',
461
+ 'Oracle envelope and Reviewed record SHA-256 field must agree',
462
+ recordName,
463
+ ),
464
+ );
465
+ }
466
+ const verdictLines = verificationFields.match(/^\*\*Verdict\*\*:.*$/gm) ?? [];
467
+ if (
468
+ verdictLines.length !== 1 ||
469
+ verdictLines[0] !== `**Verdict**: ${review.verdict}`
470
+ ) {
471
+ errors.push(
472
+ issue(
473
+ 'SDD-ORACLE-ENVELOPE-VERDICT-MISMATCH',
474
+ 'Oracle envelope and Verdict field must agree',
475
+ recordName,
476
+ ),
477
+ );
478
+ }
479
+ }
480
+
296
481
  export function validate({ change, through }) {
297
482
  if (!gates.includes(through)) throw new Error('Invalid SDD validation gate');
298
483
  const errors = [];
@@ -358,7 +543,7 @@ export function validate({ change, through }) {
358
543
  !new RegExp(
359
544
  `^# Change: ${id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*$`,
360
545
  'm',
361
- ).test(text) ||
546
+ ).test(text.replace(/^\uFEFF/, '')) ||
362
547
  !/^\*\*Classification\*\*: substantial$/m.test(text) ||
363
548
  !/^\*\*Scope\*\*: (?:local|coordinated|cross-cutting)$/m.test(text) ||
364
549
  !/^\*\*Uncertainty\*\*: (?:low|medium|high)$/m.test(text) ||
@@ -534,9 +719,18 @@ export function validate({ change, through }) {
534
719
  }
535
720
  const verificationText =
536
721
  section(text, 'Verification', { trim: false }) ?? '';
537
- const verified = verificationText.trim();
722
+ // Envelope contents are not record fields, AC rows, or reviewed source lines.
723
+ const extraction = scanOracleEnvelope(text);
724
+ const verificationFields =
725
+ through === 'closeout'
726
+ ? verificationText.replace(extraction.fences[0]?.block ?? '', '')
727
+ : verificationText;
728
+ const verified = verificationFields.trim();
538
729
  if (through === 'closeout') {
539
- const prefix = text.slice(0, authorizationHeading?.index ?? text.length);
730
+ const prefix = text.slice(
731
+ 0,
732
+ extraction.authorizationOffset ?? text.length,
733
+ );
540
734
  if (
541
735
  !/^\*\*Reviewer\*\*: oracle$/m.test(verified) ||
542
736
  !/^\*\*Independent from implementer\*\*: Yes$/m.test(verified) ||
@@ -551,7 +745,8 @@ export function validate({ change, through }) {
551
745
  );
552
746
  }
553
747
  const digestLines =
554
- verificationText.match(/^\*\*Reviewed record SHA-256\*\*:.*$/gm) ?? [];
748
+ verificationFields.match(/^\*\*Reviewed record SHA-256\*\*:.*$/gm) ??
749
+ [];
555
750
  const reviewedDigest =
556
751
  digestLines.length === 1
557
752
  ? /^\*\*Reviewed record SHA-256\*\*: ([a-f0-9]{64})$/.exec(
@@ -567,6 +762,16 @@ export function validate({ change, through }) {
567
762
  ),
568
763
  );
569
764
  }
765
+ validateOracleEnvelope({
766
+ extraction,
767
+ verificationFields,
768
+ recordSha256: sha(prefix),
769
+ reviewedDigest,
770
+ // Archived records retain the active path reviewed by the Oracle.
771
+ expectedRecord: `.thoth/changes/${id}/${id}.md`,
772
+ errors,
773
+ recordName,
774
+ });
570
775
  const rows = verified
571
776
  .split(/\r?\n/)
572
777
  .filter((line) => /^- AC-/.test(line));
@@ -82,6 +82,14 @@ exactly one SHA field line; put notes on separate lines below the fields.
82
82
  **Verdict**: PENDING
83
83
  **Reviewed record SHA-256**: PENDING
84
84
 
85
+ **Oracle envelope**:
86
+
87
+ ```thoth-result
88
+ PENDING
89
+ ```
90
+
91
+ After PASS, root pastes the Oracle's unchanged final-verification envelope here.
92
+
85
93
  - AC-1: PENDING | check | evidence
86
94
  - Source: relative/path | sha256:<actual-source-digest>
87
95
  - Source: .thoth/specs/<capability>/spec.md | sha256:<actual-source-digest>
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: plan-reviewer
3
- description: Independent blocker-only Oracle review of a ready substantial SDD plan before separate implementation authorization.
3
+ description: Provides independent, blocker-only Oracle review of a substantial SDD plan. Use only when plan review was selected at substantial ready; it does not authorize implementation.
4
4
  license: MIT
5
5
  compatibility: Requires the installed sibling thoth-sdd skill.
6
6
  metadata:
@@ -33,14 +33,22 @@ conflicting work. Do not require multiple reports, universal requirement IDs,
33
33
  workflow manifests, evidence directories, or a scheduler. Structural `ready` is
34
34
  necessary but not sufficient for semantic readiness.
35
35
 
36
- Return `[OKAY]` with concise evidence or `[REJECT]` with at most three actual
37
- execution blockers and smallest repairs; keep cautions separate. Root repairs
38
- same-intent blockers in the same record, revalidates affected gates, and uses a
39
- fresh Oracle for each round. A human-owned material blocker stops the round.
40
- Root records both review disposition and selection provenance without inventing
41
- approval. Accepted provenance is `EXPLICIT_REVIEW`, `EXPLICIT_SKIP`, or
36
+ Return exactly one fenced `thoth-result` JSON envelope as the entire final
37
+ message, following the Oracle gate contract: `role: "oracle"`,
38
+ `review.kind: "plan-review"`, and `review.verdict: "OKAY" | "REJECT"`.
39
+ Include concise evidence and at most three blocking risks for actual execution
40
+ blockers with smallest repairs; mark cautions nonblocking. An OKAY requires
41
+ `status: "complete"` and no blocking risks. Root validates the unchanged native
42
+ terminal result with `--review-kind plan-review` using the sibling
43
+ thoth-sdd skill's **Specialist result validation** procedure, including its shared
44
+ one-request format-only repair budget. Root records plan-review `OKAY` only from a validated envelope
45
+ and after judging the content; a malformed or missing envelope is not approval.
46
+ Root repairs same-intent blockers in the same record, revalidates affected gates,
47
+ and uses a fresh Oracle for each round. A human-owned material blocker stops the
48
+ round. Root records both review disposition and selection provenance without
49
+ inventing approval. Accepted provenance is `EXPLICIT_REVIEW`, `EXPLICIT_SKIP`, or
42
50
  `DEFAULT_REVIEW_AFTER_3`; `SKIPPED` requires explicit skip, while `OKAY` requires
43
- explicit review or the third-return review default. After `[OKAY]`, root preserves
51
+ explicit review or the third-return review default. After validated `OKAY`, root preserves
44
52
  the separate Implement (Recommended) / Stop choice and separately offers it,
45
53
  honoring prior explicit implementation authorization; an explicit later Stop
46
54
  supersedes it. That choice has its own per-question budget. Review never
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: thoth-archive
3
- description: Transactionally apply declared .thoth/specs deltas and archive independently verified substantial SDD changes.
3
+ description: Applies declared .thoth/specs deltas and archives independently verified substantial SDD changes. Use only after a substantial change has a fresh Oracle PASS and passes closeout; not for unverified or incomplete work.
4
4
  license: MIT
5
5
  compatibility: Requires Node.js >=22.19 and installed sibling thoth-sdd skill.
6
6
  metadata:
@@ -12,6 +12,7 @@ metadata:
12
12
 
13
13
  Root archives only after the implementation writer has terminated and a fresh
14
14
  independent Oracle PASS has covered the actual change, diff, checks, and risks.
15
+ Closeout requires a matching valid PASS final-verification envelope under `**Oracle envelope**:`.
15
16
  Structural closeout validation is not approval. The single record must have all
16
17
  tasks complete, explicit plan-review disposition and implementation authorization,
17
18
  every acceptance outcome's concrete PASS check/evidence, reviewed-record and
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: thoth-constitution
3
- description: Create or explicitly amend the active .thoth constitution with SemVer and sync-impact lifecycle validation.
3
+ description: Creates or amends the active .thoth constitution with versioned governance validation. Use only on an explicit constitution creation or amendment request, not for routine implementation or implicit governance changes.
4
4
  license: MIT
5
5
  compatibility: Requires Node.js >=22.19 for bundled validation.
6
6
  metadata:
@@ -50,7 +50,7 @@ Provider memory is independent of project records.
50
50
 
51
51
  Delegation depth is one and each mutable surface has one writer. Root accepts
52
52
  terminal dependency results before releasing consumers. At substantial `ready`,
53
- root always offers Oracle plan review (Recommended) or proceeding without review,
53
+ root always offers Oracle plan review (Recommended) or `Proceed without review`,
54
54
  even if implementation was authorized; an unanswered offer never means skip.
55
55
  After `[OKAY]`, root separately offers the Implement (Recommended) / Stop choice,
56
56
  honors prior explicit authorization, and lets explicit Stop supersede it. Record
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: thoth-init
3
- description: Initialize canonical offline .thoth governance without modifying existing project records.
3
+ description: Initializes canonical offline .thoth governance without modifying existing project records. Use only to initialize missing .thoth governance, not to amend or replace existing records.
4
4
  license: MIT
5
5
  compatibility: Requires Node.js >=22.19 and write access to target project.
6
6
  metadata:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: thoth-sdd
3
- description: Apply proportional understanding and risk-aware SDD classification, with one ID-named record for substantial changes.
3
+ description: Governs SDD changes, including the single ID-named record for substantial work. Use for any change requiring proportional understanding and risk-aware classification, whether small or substantial.
4
4
  license: MIT
5
5
  compatibility: Requires Node.js >=22.19 for bundled product validation.
6
6
  metadata:
@@ -74,7 +74,7 @@ At substantial `ready`, first show the user a concise plan summary (goal,
74
74
  acceptance, key decisions, units, risks, record path), then always offer
75
75
  `Review plan with Oracle (Recommended)` or `Proceed without review`, even when implementation was already authorized.
76
76
  Silence is never an explicit review skip; run a fresh read-only review only when
77
- selected. After a selected `[OKAY]`, separately offer `Implement (Recommended)` /
77
+ selected. After a validated plan-review `OKAY`, separately offer `Implement (Recommended)` /
78
78
  `Stop`; prior explicit authorization remains valid, while an explicit later
79
79
  `Stop` supersedes it. Record the plan-review selection as
80
80
  `EXPLICIT_REVIEW`, `EXPLICIT_SKIP`, or `DEFAULT_REVIEW_AFTER_3`; `SKIPPED`
@@ -88,6 +88,19 @@ independent review; never claim independent PASS or archive.
88
88
 
89
89
  ## Bounded execution
90
90
 
91
+ Root uses the harness progress tool (Pi `todo`, Claude `TodoWrite`, OpenCode
92
+ `todowrite`, Codex `update_plan`) to show SDD progress. Before implementation,
93
+ create one item per remaining applicable stage:
94
+ explore/specify/clarify/classify/plan/tasks/ready/plan review/authorization.
95
+ Pi `todo` may hold several in_progress items for concurrently active stages or
96
+ tasks (e.g. parallel delegated units); Claude `TodoWrite`, OpenCode `todowrite`
97
+ and Codex `update_plan` keep one in_progress item; complete each stage/task
98
+ immediately. At implementation, replace stage items with the record's task rows
99
+ plus final verification and archive (for small changes, use the settled work
100
+ steps plus verification). Keep one list per change; prefix items with the change
101
+ ID when several changes are active. This native progress view is not a sidecar
102
+ record and never replaces SDD gates or authorization.
103
+
91
104
  Apply these rules across all workflow stages. Each assignment names one
92
105
  independently acceptable outcome, exact known entrypoints and skill paths,
93
106
  concrete accepted inputs and dependencies, its produced result, owned writes and
@@ -143,12 +156,54 @@ parent. Read only the current phase under
143
156
  plan review and archive are sibling skill contracts. Use installed local assets
144
157
  only; do not provision skills or run a network installer mid-workflow.
145
158
 
159
+ ## Specialist result validation
160
+
161
+ Only Oracle gate assignments (plan-review and final-verification) return a
162
+ structured envelope. Before recording plan-review `OKAY` or final-verification
163
+ `PASS`, root resolves `<skill-dir>` from the installed thoth-sdd SKILL.md
164
+ directory, exactly as for `scripts/validate.mjs`, and runs:
165
+
166
+ ```text
167
+ node "<skill-dir>/scripts/validate-result.mjs" --review-kind <kind> [--record-sha256 <hex>] [--no-record] [--input <path>]
168
+ ```
169
+
170
+ Pass the unchanged native terminal result via stdin, or `--input <path>` when
171
+ piping is impractical; do not extract, rewrite, or wrap the envelope, or create
172
+ persisted evidence files. Set `--review-kind` to the assigned `plan-review` or
173
+ `final-verification`. For final verification of a substantial record, set
174
+ `--record-sha256` to the independently calculated expected SHA-256 of exact UTF-8
175
+ bytes before `## Authorization` (see the [verify phase](references/phases/verify.md)).
176
+ Confirm `reviewedRecord` identifies the assigned record.
177
+ For Oracle final verification of a small change without a record, root passes
178
+ `--no-record`; Oracle omits both `reviewedRecord` and `reviewedRecordSha256`.
179
+ Do not combine `--no-record` with `--record-sha256` or plan-review.
180
+ Without `--no-record`, final verification still requires both binding fields.
181
+
182
+ - Exit **0** means structurally valid only. Root still judges scope, evidence,
183
+ checks, freshness, provenance, independence, and content before recording any
184
+ approval, and presents accepted results to the user in readable prose.
185
+ - Exit **1** means no approval. Allow at most one format-only repair request per assignment,
186
+ shared with any runtime enforcement; it must not change findings or verdict.
187
+ Exhaustion is a contract failure reported truthfully, never converted into an Oracle `BLOCKED` judgment.
188
+ - Exit **2** or an unavailable skill/validator means validation cannot be completed:
189
+ report the error (missing assets are installation drift). This blocks only gate approvals;
190
+ ordinary delegations proceed. Do not provision replacements mid-workflow.
191
+
192
+ Other Thoth specialist returns use compact markdown fields and are judged on content,
193
+ not validated for format. User-defined custom agents retain their own free format;
194
+ neither ordinary specialist results nor custom agents are rejected for format or
195
+ count as approvals. Oracle `diagnosis` and `advice` never authorize implementation
196
+ or closeout and return compact markdown, not envelopes. Approval comes only from
197
+ the validated gate review field, never free text; validation itself is not user authorization.
198
+
146
199
  ## Gates and CLI
147
200
 
148
201
  ```text
149
202
  node "<skill-dir>/scripts/validate.mjs" --change .thoth/changes/<id> --through <explore|specify|clarify|plan|tasks|checklist|ready|verify|closeout> --json
150
203
  ```
151
204
 
205
+ Substantial records must not contain other `thoth-result` fences or `**Oracle envelope**:` marker lines anywhere in the file; write examples inline instead.
206
+
152
207
  The early gates validate the one record proportionally. `plan` validates without
153
208
  requiring tasks. `tasks` and `ready` require concrete coverage of every accepted
154
209
  outcome. `ready` requires settled material decisions before the mandatory
@@ -159,6 +214,16 @@ implementation authorization, and reviewed source digests/baselines. It permits
159
214
  final-review and Archive placeholders. `closeout` additionally requires a fresh
160
215
  independent Oracle PASS, every acceptance outcome with concrete PASS
161
216
  check/evidence, exactly one matching record SHA-256 field, and Archive READY.
217
+ Order: `verify` → fresh final Oracle → root validates and pastes → `closeout` → archive.
218
+ After accepting a validated PASS, root pastes the Oracle's unchanged
219
+ final-verification envelope under `**Oracle envelope**:` in the record's
220
+ Verification section (post-PASS bookkeeping in Verification; no new review).
221
+ Plan-review envelopes are not embedded. Closeout fails without exactly one valid
222
+ PASS envelope matching the record path and prefix digest, consistent with
223
+ `**Verdict**` and `**Reviewed record SHA-256**`. Preserve the envelope unchanged
224
+ when archiving; archived validation accepts its original active record path.
225
+ Historical archived records are not retrofitted or re-validated by this rule.
226
+
162
227
  The initial `PENDING` selection placeholder is allowed before `verify` only.
163
228
  `SKIPPED` requires `EXPLICIT_SKIP`; `OKAY` requires `EXPLICIT_REVIEW` or
164
229
  `DEFAULT_REVIEW_AFTER_3`. Every canonical spec affected by a durable delta must
@@ -2,6 +2,16 @@
2
2
 
3
3
  Every change requires final verification against accepted outcomes and actual execution evidence. Small low-risk work uses focused independent root checks; substantial or materially risky work requires a fresh read-only Oracle independent from the writer. Judge the actual diff, behavior, completeness, correctness, coherence, checks, and residual risks.
4
4
 
5
+ For Oracle final verification of a small change without a record, root passes `--no-record`; Oracle omits both `reviewedRecord` and `reviewedRecordSha256`. Do not combine `--no-record` with `--record-sha256` or plan-review. Otherwise final verification still requires both binding fields.
6
+
5
7
  Before requesting final Oracle for substantial work, run `node "<skill-dir>/scripts/validate.mjs" --change .thoth/changes/<id> --through verify --json`. This gate requires ready coverage, complete tasks, authorization disposition/provenance, and reviewed source digests/baselines; final-review fields, AC evidence rows, and Archive may remain placeholders. For each capability named by a durable delta, add exactly one `Source` entry for `.thoth/specs/<capability>/spec.md`: its reviewed SHA-256 when it exists, or `absent` only when no canonical file exists.
6
8
 
7
- After review, record each outcome's concrete PASS evidence, actual checks, source SHA-256 digests, and the hash of exact UTF-8 record bytes preceding the case-sensitive `## Authorization` heading. After PASS, edits confined to Authorization, Verification, or Closeout need no new review; any edit before `## Authorization` requires fresh independent review and a new digest. This allowance never waives structural checks, truthful provenance, stale-source rejection, or review of changed implementation. Recheck baselines after review; missing or stale digests/absence, missing evidence, or blockers prevent closeout and archive. Never create a verification report or evidence directory; route actionable findings to convergence.
9
+ Assign Oracle a `final-verification` review of the substantial record. Oracle returns exactly one fenced `thoth-result` JSON envelope as the entire final message, following the Oracle gate contract with `role: "oracle"`, `review.kind: "final-verification"`, and `review.verdict: "PASS" | "FAIL" | "BLOCKED"`. Its review includes `reviewedRecord` naming the reviewed record path and `reviewedRecordSha256` containing the 64 lowercase hex SHA-256 of exact UTF-8 record bytes preceding the case-sensitive `## Authorization` heading. PASS requires `status: "complete"` and no blocking risks. FAIL reports findings; BLOCKED is an actual inability to complete review, never a substitute for a malformed result or exhausted format repair.
10
+
11
+ Root validates the unchanged native terminal result using the thoth-sdd **Specialist result validation** procedure with `--review-kind final-verification --record-sha256 <hex>`, where `<hex>` is the independently calculated expected record-prefix digest. Confirm `reviewedRecord` identifies the assigned record. Root records `**Reviewer**: oracle`, `**Independent from implementer**: Yes`, `**Verdict**: PASS`, and `**Reviewed record SHA-256**` only from a validated PASS envelope whose digest matches the current record, after judging the content and confirming reviewer independence. Invalid results, FAIL, BLOCKED, and diagnosis/advice reviews do not authorize closeout or archive; route findings to convergence and report contract failures truthfully.
12
+
13
+ Substantial records must not contain other `thoth-result` fences or `**Oracle envelope**:` marker lines anywhere in the file; write examples inline instead.
14
+
15
+ Order: `verify` → fresh final Oracle → root validates and pastes → `closeout` → archive. After accepting a validated PASS, root pastes the Oracle's unchanged final-verification envelope under `**Oracle envelope**:` in the record's Verification section (post-PASS bookkeeping in Verification; no new review). Plan-review envelopes are not embedded. Closeout fails without exactly one valid PASS envelope matching the record path and prefix digest, consistent with `**Verdict**` and `**Reviewed record SHA-256**`. Preserve the envelope unchanged when archiving; archived validation accepts its original active record path. Historical archived records are not retrofitted or re-validated by this rule.
16
+
17
+ After accepted review, record each outcome's concrete PASS evidence, actual checks, source SHA-256 digests, and the matched record-prefix hash. After PASS, edits confined to Authorization, Verification, or Closeout need no new review; any edit before `## Authorization` requires fresh independent review and a new digest. This allowance never waives structural checks, truthful provenance, stale-source rejection, or review of changed implementation. Recheck baselines after review; missing or stale digests/absence, missing evidence, or blockers prevent closeout and archive. Never create a verification report or evidence directory; route actionable findings to convergence.