@namewta/speculo 1.0.19 → 1.0.21

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 (194) hide show
  1. package/README.md +8 -7
  2. package/THIRD-PARTY-NOTICES.md +33 -0
  3. package/dist/src/agent-files.js +2 -2
  4. package/dist/src/agent-files.js.map +1 -1
  5. package/dist/src/agent-skills.d.ts +81 -0
  6. package/dist/src/agent-skills.js +530 -0
  7. package/dist/src/agent-skills.js.map +1 -0
  8. package/dist/src/cli.js +11 -3
  9. package/dist/src/cli.js.map +1 -1
  10. package/dist/src/config.js +5 -3
  11. package/dist/src/config.js.map +1 -1
  12. package/dist/src/doctor.js +7 -2
  13. package/dist/src/doctor.js.map +1 -1
  14. package/dist/src/index.d.ts +8 -0
  15. package/dist/src/index.js +23 -3
  16. package/dist/src/index.js.map +1 -1
  17. package/dist/src/manifest.d.ts +9 -0
  18. package/dist/src/manifest.js +45 -7
  19. package/dist/src/manifest.js.map +1 -1
  20. package/dist/src/refresh.js +40 -0
  21. package/dist/src/refresh.js.map +1 -1
  22. package/dist/src/structured.js +15 -4
  23. package/dist/src/structured.js.map +1 -1
  24. package/dist/src/transaction.d.ts +24 -3
  25. package/dist/src/transaction.js +191 -12
  26. package/dist/src/transaction.js.map +1 -1
  27. package/package.json +7 -4
  28. package/scripts/validate-skills.mjs +56 -0
  29. package/template/AGENTS.md +1 -1
  30. package/template/CLAUDE.md +1 -1
  31. package/template/canonical/canonical-specdev-goal-plan.md +156 -28
  32. package/template/canonical/canonical-specdev-grill-with-docs.md +153 -31
  33. package/template/canonical/canonical-specdev-spec.md +153 -27
  34. package/template/canonical/canonical-specdev-tickets.md +153 -27
  35. package/template/canonical/canonical-specdev-wayfinder.md +142 -27
  36. package/template/commands/retro.md +11 -9
  37. package/template/skills/archive-and-consolidate/SKILL.md +163 -7
  38. package/template/skills/archive-and-consolidate/references/cleanup-rules.md +1 -1
  39. package/template/skills/docs-sync/references/agents/claude-redirect.md +8 -8
  40. package/template/skills/docs-sync/references/agents/content-contract.md +1 -1
  41. package/template/skills/docs-sync/references/agents/manifest-discovery.md +7 -7
  42. package/template/skills/docs-sync/references/agents/role-classification.md +4 -4
  43. package/template/skills/docs-sync/references/agents-contract.md +1 -1
  44. package/template/skills/engineering-standards-builder/SKILL.md +149 -9
  45. package/template/skills/engineering-standards-builder/agents/openai.yaml +2 -0
  46. package/template/skills/engineering-standards-builder/manifest.txt +2 -1
  47. package/template/skills/engineering-standards-builder/references/rules/09-mechanical-guardrails.md +9 -0
  48. package/template/skills/engineering-standards-builder/scripts/validate-builder.mjs +4 -7
  49. package/template/skills/git-history-squash/SKILL.md +87 -11
  50. package/template/skills/git-history-squash/agents/openai.yaml +2 -0
  51. package/template/skills/optimize-codex-config/SKILL.md +71 -11
  52. package/template/skills/{speculo-retro/references/entry-procedure.md → retrospective/SKILL.md} +12 -8
  53. package/template/skills/{speculo-retro → retrospective}/references/friction-taxonomy.md +22 -13
  54. package/template/skills/{speculo-retro → retrospective}/references/issue-drafting-sop.md +10 -20
  55. package/template/skills/source-code-zip/SKILL.md +44 -8
  56. package/template/skills/source-code-zip/references/{entry-procedure.md → cli-reference.md} +0 -43
  57. package/template/skills/upstream-fork-sync/SKILL.md +71 -8
  58. package/template/skills/{writing-great-skills → writing-for-agents}/GLOSSARY.md +1 -1
  59. package/template/skills/writing-for-agents/SKILL.md +22 -0
  60. package/template/skills/writing-for-agents/agents/openai.yaml +2 -0
  61. package/template/skills/{writing-great-skills/references/entry-procedure.md → writing-for-agents/references/authoring-principles.md} +2 -9
  62. package/template/workflows/ops/D-project-deploy/D-project-deploy.md +1 -1
  63. package/template/workflows/ops/H-host-manage/H-host-manage.md +4 -0
  64. package/template/workflows/ops/H-host-manage/references/host-profiles.md +4 -0
  65. package/template/workflows/ops/I-initialize/I-initialize.md +1 -1
  66. package/template/workflows/ops/INDEX.md +2 -0
  67. package/template/workflows/ops/README.md +7 -3
  68. package/template/workflows/ops/S-server-connect/S-server-connect.md +5 -5
  69. package/template/workflows/ops/V-inventory-view/V-inventory-view.md +2 -0
  70. package/template/workflows/ops/common/CAPABILITIES.md +2 -0
  71. package/template/workflows/ops/common/USAGE.md +5 -5
  72. package/template/workflows/ops/common/WORKSPACE-USAGE.md +29 -2
  73. package/template/workflows/ops/common/examples/README.md +1 -1
  74. package/template/workflows/ops/common/examples/register.example.json +7 -3
  75. package/template/workflows/ops/common/examples/server-connection.example.json +11 -0
  76. package/template/workflows/ops/common/rules/deployment-layout.md +1 -1
  77. package/template/workflows/ops/common/rules/host-root-and-onboarding.md +47 -0
  78. package/template/workflows/ops/common/rules/persistence-and-secrets.md +1 -1
  79. package/template/workflows/ops/common/rules/research-and-decisions.md +8 -0
  80. package/template/workflows/ops/common/rules/server-onboarding.md +3 -3
  81. package/template/workflows/ops/common/rules/workspace-and-authorization.md +2 -2
  82. package/template/workflows/ops/common/schemas/fleet-view.schema.json +64 -0
  83. package/template/workflows/ops/common/schemas/host.schema.json +19 -0
  84. package/template/workflows/ops/common/schemas/plan.schema.json +57 -0
  85. package/template/workflows/ops/common/schemas/root-confirmation.schema.json +118 -0
  86. package/template/workflows/ops/common/schemas/server-connection.schema.json +67 -0
  87. package/template/workflows/ops/common/schemas/server-discovery.schema.json +171 -0
  88. package/template/workflows/ops/common/schemas/spec.schema.json +19 -0
  89. package/template/workflows/ops/common/schemas/status.schema.json +19 -0
  90. package/template/workflows/ops/common/templates/FLEET.html +1 -1
  91. package/template/workflows/ops/common/templates/HOST-README.md +3 -1
  92. package/template/workflows/ops/common/tests/test_ops.mjs +8 -11
  93. package/template/workflows/ops/common/tests/test_ops_bootstrap.mjs +101 -16
  94. package/template/workflows/ops/common/tests/test_ops_onboarding.mjs +225 -0
  95. package/template/workflows/ops/common/tests/test_ops_workspace.mjs +17 -8
  96. package/template/workflows/ops/common/tools/demo-local.mjs +4 -0
  97. package/template/workflows/ops/common/tools/opslib/agent.mjs +26 -0
  98. package/template/workflows/ops/common/tools/opslib/bootstrap.mjs +52 -26
  99. package/template/workflows/ops/common/tools/opslib/cli.mjs +1 -0
  100. package/template/workflows/ops/common/tools/opslib/core.mjs +1 -1
  101. package/template/workflows/ops/common/tools/opslib/docs.mjs +1 -0
  102. package/template/workflows/ops/common/tools/opslib/execution.mjs +4 -0
  103. package/template/workflows/ops/common/tools/opslib/fleet.mjs +26 -4
  104. package/template/workflows/ops/common/tools/opslib/host_recipes.mjs +34 -0
  105. package/template/workflows/ops/common/tools/opslib/model.mjs +6 -0
  106. package/template/workflows/ops/common/tools/opslib/onboarding.mjs +215 -0
  107. package/template/workflows/ops/common/tools/opslib/planner.mjs +3 -0
  108. package/template/workflows/ops/common/tools/opslib/transport.mjs +10 -6
  109. package/template/workflows/ops/common/tools/opslib/workspace_cli.mjs +20 -1
  110. package/template/workflows/ops/common/tools/server-discover.sh +65 -0
  111. package/template/workflows/ops/common/tools/validate-ops.mjs +1 -1
  112. package/template/workflows/ops/manifest.json +12 -5
  113. package/template/workflows/specdev/A-archive-and-consolidate/consolidation-interview.md +3 -3
  114. package/template/workflows/specdev/C-code-review/C-code-review.md +1 -1
  115. package/template/workflows/specdev/D-diagnose-bugs/D-diagnose-bugs.md +6 -0
  116. package/template/workflows/specdev/G-grill-with-docs/references/interview-procedure.md +6 -6
  117. package/template/workflows/specdev/I-implement/references/implementation-procedure.md +1 -1
  118. package/template/workflows/specdev/I-implement/tdd-rules.md +4 -0
  119. package/template/workflows/specdev/I-init-setup/config-template.json +5 -1
  120. package/template/workflows/specdev/INDEX.md +2 -2
  121. package/template/workflows/specdev/P-goal-plan/planning-modes.md +1 -1
  122. package/template/workflows/specdev/P-prototype/P-prototype.md +7 -3
  123. package/template/workflows/specdev/P-prototype/logic-protocol.md +11 -0
  124. package/template/workflows/specdev/P-prototype/logic-template.md +27 -0
  125. package/template/workflows/specdev/P-prototype/project-preview-protocol.md +9 -0
  126. package/template/workflows/specdev/R-retro/R-retro.md +26 -0
  127. package/template/workflows/specdev/R-retro/retro-template.md +27 -0
  128. package/template/workflows/specdev/R-review-architecture/references/selected-design.md +1 -1
  129. package/template/workflows/specdev/README.md +13 -2
  130. package/template/workflows/specdev/S-spec/S-spec.md +4 -0
  131. package/template/workflows/specdev/T-tickets/T-tickets.md +4 -0
  132. package/template/workflows/specdev/T-triage/T-triage.md +31 -25
  133. package/template/workflows/specdev/T-triage/capture-protocol.md +1 -1
  134. package/template/workflows/specdev/T-triage/ci-security-protocol.md +11 -0
  135. package/template/workflows/specdev/T-triage/intake-protocol.md +10 -4
  136. package/template/workflows/specdev/T-triage/pr-delivery-protocol.md +13 -0
  137. package/template/workflows/specdev/T-triage/pr-record-template.md +39 -0
  138. package/template/workflows/specdev/T-triage/publish-protocol.md +1 -1
  139. package/template/workflows/specdev/T-triage/queue-protocol.md +7 -0
  140. package/template/workflows/specdev/T-triage/reconcile-protocol.md +1 -1
  141. package/template/workflows/specdev/T-triage/references/issue-pr-policy.md +23 -0
  142. package/template/workflows/specdev/T-triage/references/release-authentication.md +9 -0
  143. package/template/workflows/specdev/T-triage/references/release-notes-injection.md +21 -0
  144. package/template/workflows/specdev/T-triage/references/workflow-yaml-reference.md +37 -0
  145. package/template/workflows/specdev/T-triage/release-preflight.md +13 -0
  146. package/template/workflows/specdev/T-triage/release-protocol.md +12 -0
  147. package/template/workflows/specdev/T-triage/release-recovery.md +18 -0
  148. package/template/workflows/specdev/T-triage/remote-operations.md +25 -0
  149. package/template/workflows/specdev/T-triage/scripts/github-transport.mjs +208 -0
  150. package/template/workflows/specdev/T-triage/source-template.md +7 -0
  151. package/template/workflows/specdev/T-triage/triage-run-template.md +34 -0
  152. package/template/workflows/specdev/T-triage/triage-template.md +4 -1
  153. package/template/workflows/specdev/common/rules/artifact-contract.md +7 -0
  154. package/template/workflows/specdev/common/rules/change-completion.md +6 -0
  155. package/template/workflows/specdev/common/rules/workflow-routing.md +6 -0
  156. package/template/workflows/specdev/common/rules/workflow-state-and-lifecycle.md +1 -1
  157. package/template/workflows/specdev/common/schemas/config.schema.json +137 -26
  158. package/template/workflows/specdev/common/schemas/logic-prototype.schema.json +62 -0
  159. package/template/workflows/specdev/common/schemas/pull-request.schema.json +90 -0
  160. package/template/workflows/specdev/common/schemas/retrospective.schema.json +58 -0
  161. package/template/workflows/specdev/common/schemas/triage-run.schema.json +149 -0
  162. package/template/workflows/specdev/common/schemas/triage.schema.json +117 -15
  163. package/template/workflows/specdev/common/tools/delivery-artifacts.mjs +95 -0
  164. package/template/workflows/specdev/common/tools/validate-specdev.mjs +60 -19
  165. package/template/workflows/specdev/runtime-contract.json +4 -2
  166. package/template/skills/archive-and-consolidate/references/entry-procedure.md +0 -178
  167. package/template/skills/docs-sync/references/entry-procedure.md +0 -3
  168. package/template/skills/engineering-standards-builder/references/entry-procedure.md +0 -154
  169. package/template/skills/git-history-squash/references/entry-procedure.md +0 -94
  170. package/template/skills/github-npm-ops/SKILL.md +0 -19
  171. package/template/skills/github-npm-ops/references/ci-and-security-ops.md +0 -178
  172. package/template/skills/github-npm-ops/references/entry-procedure.md +0 -25
  173. package/template/skills/github-npm-ops/references/failure-recovery.md +0 -123
  174. package/template/skills/github-npm-ops/references/issue-pr-triage.md +0 -227
  175. package/template/skills/github-npm-ops/references/issue-transport.md +0 -26
  176. package/template/skills/github-npm-ops/references/package-json-checklist.md +0 -171
  177. package/template/skills/github-npm-ops/references/preflight-checklist.md +0 -39
  178. package/template/skills/github-npm-ops/references/publish-detection.md +0 -68
  179. package/template/skills/github-npm-ops/references/release-notes-injection.md +0 -238
  180. package/template/skills/github-npm-ops/references/release-pipeline.md +0 -108
  181. package/template/skills/github-npm-ops/references/setup-npm-token.md +0 -63
  182. package/template/skills/github-npm-ops/references/troubleshooting-playbook.md +0 -293
  183. package/template/skills/github-npm-ops/references/version-bump-flow.md +0 -217
  184. package/template/skills/github-npm-ops/references/workflow-yaml-reference.md +0 -268
  185. package/template/skills/github-npm-ops/scripts/issue-transport.mjs +0 -227
  186. package/template/skills/optimize-codex-config/references/entry-procedure.md +0 -78
  187. package/template/skills/speculo-retro/SKILL.md +0 -19
  188. package/template/skills/upstream-fork-sync/references/entry-procedure.md +0 -78
  189. package/template/skills/writing-great-skills/SKILL.md +0 -23
  190. /package/template/skills/{writing-great-skills → writing-for-agents}/references/document-contract.md +0 -0
  191. /package/template/workflows/specdev/{G-grill-with-docs → common/rules}/adr-format.md +0 -0
  192. /package/template/workflows/specdev/{G-grill-with-docs → common/rules}/context-format.md +0 -0
  193. /package/template/workflows/specdev/{I-implement → common/rules}/design-it-twice.md +0 -0
  194. /package/template/workflows/specdev/{G-grill-with-docs/domain-modeling-rules.md → common/rules/domain-modeling.md} +0 -0
@@ -0,0 +1,90 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:speculo:specdev:pull-request:v1",
4
+ "type": "object",
5
+ "required": [
6
+ "schema_version",
7
+ "artifact",
8
+ "change",
9
+ "id",
10
+ "requested",
11
+ "status",
12
+ "repo",
13
+ "base_sha",
14
+ "head_sha",
15
+ "body_sha256",
16
+ "verification",
17
+ "url",
18
+ "updated_at",
19
+ "delivery_target"
20
+ ],
21
+ "properties": {
22
+ "schema_version": {
23
+ "const": 1
24
+ },
25
+ "artifact": {
26
+ "const": "pull-request"
27
+ },
28
+ "change": {
29
+ "type": "string",
30
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"
31
+ },
32
+ "id": {
33
+ "type": "string",
34
+ "pattern": "^PR-[0-9]{3,}$"
35
+ },
36
+ "requested": {
37
+ "type": "boolean"
38
+ },
39
+ "status": {
40
+ "enum": [
41
+ "planned",
42
+ "draft",
43
+ "ready",
44
+ "failed",
45
+ "waived"
46
+ ]
47
+ },
48
+ "repo": {
49
+ "type": "string",
50
+ "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"
51
+ },
52
+ "base_sha": {
53
+ "type": "string",
54
+ "pattern": "^[a-f0-9]{40,64}$"
55
+ },
56
+ "head_sha": {
57
+ "type": "string",
58
+ "pattern": "^[a-f0-9]{40,64}$"
59
+ },
60
+ "body_sha256": {
61
+ "type": "string",
62
+ "pattern": "^[a-f0-9]{64}$"
63
+ },
64
+ "verification": {
65
+ "enum": [
66
+ "pending",
67
+ "passed",
68
+ "failed",
69
+ "unknown"
70
+ ]
71
+ },
72
+ "url": {
73
+ "type": [
74
+ "string",
75
+ "null"
76
+ ]
77
+ },
78
+ "updated_at": {
79
+ "type": "string",
80
+ "format": "date-time"
81
+ },
82
+ "delivery_target": {
83
+ "enum": [
84
+ "draft",
85
+ "ready"
86
+ ]
87
+ }
88
+ },
89
+ "additionalProperties": false
90
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:speculo:specdev:retrospective:v1",
4
+ "type": "object",
5
+ "required": [
6
+ "schema_version",
7
+ "artifact",
8
+ "change",
9
+ "id",
10
+ "status",
11
+ "outcome",
12
+ "sources",
13
+ "updated_at"
14
+ ],
15
+ "properties": {
16
+ "schema_version": {
17
+ "const": 1
18
+ },
19
+ "artifact": {
20
+ "const": "retrospective"
21
+ },
22
+ "change": {
23
+ "type": "string",
24
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"
25
+ },
26
+ "id": {
27
+ "type": "string",
28
+ "pattern": "^RETRO-[0-9]{3,}$"
29
+ },
30
+ "status": {
31
+ "enum": [
32
+ "draft",
33
+ "blocked",
34
+ "completed"
35
+ ]
36
+ },
37
+ "outcome": {
38
+ "enum": [
39
+ "findings",
40
+ "no-findings",
41
+ "insufficient-evidence"
42
+ ]
43
+ },
44
+ "sources": {
45
+ "type": "array",
46
+ "minItems": 1,
47
+ "items": {
48
+ "type": "string",
49
+ "minLength": 1
50
+ }
51
+ },
52
+ "updated_at": {
53
+ "type": "string",
54
+ "format": "date-time"
55
+ }
56
+ },
57
+ "additionalProperties": false
58
+ }
@@ -0,0 +1,149 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "urn:speculo:specdev:triage-run:v1",
4
+ "type": "object",
5
+ "required": [
6
+ "schema_version",
7
+ "artifact",
8
+ "id",
9
+ "mode",
10
+ "status",
11
+ "repo",
12
+ "change",
13
+ "commit_sha",
14
+ "npm_target",
15
+ "updated_at",
16
+ "targets"
17
+ ],
18
+ "properties": {
19
+ "schema_version": {
20
+ "const": 1
21
+ },
22
+ "artifact": {
23
+ "const": "triage-run"
24
+ },
25
+ "id": {
26
+ "type": "string",
27
+ "pattern": "^TRI-[0-9]{3,}$"
28
+ },
29
+ "mode": {
30
+ "enum": [
31
+ "ci-security",
32
+ "release-preflight",
33
+ "release"
34
+ ]
35
+ },
36
+ "status": {
37
+ "enum": [
38
+ "planned",
39
+ "blocked",
40
+ "failed",
41
+ "completed"
42
+ ]
43
+ },
44
+ "repo": {
45
+ "type": "string",
46
+ "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"
47
+ },
48
+ "change": {
49
+ "anyOf": [
50
+ {
51
+ "type": "null"
52
+ },
53
+ {
54
+ "type": "string",
55
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"
56
+ }
57
+ ]
58
+ },
59
+ "commit_sha": {
60
+ "anyOf": [
61
+ {
62
+ "type": "null"
63
+ },
64
+ {
65
+ "type": "string",
66
+ "pattern": "^[a-f0-9]{40,64}$"
67
+ }
68
+ ]
69
+ },
70
+ "npm_target": {
71
+ "enum": [
72
+ "required",
73
+ "not-required",
74
+ "unknown"
75
+ ]
76
+ },
77
+ "updated_at": {
78
+ "type": "string",
79
+ "format": "date-time"
80
+ },
81
+ "targets": {
82
+ "type": "array",
83
+ "items": {
84
+ "type": "object",
85
+ "required": [
86
+ "kind",
87
+ "identity",
88
+ "required",
89
+ "version",
90
+ "registry",
91
+ "dist_tag",
92
+ "observed",
93
+ "receipt"
94
+ ],
95
+ "properties": {
96
+ "kind": {
97
+ "enum": [
98
+ "npm",
99
+ "github-release",
100
+ "ci",
101
+ "security"
102
+ ]
103
+ },
104
+ "identity": {
105
+ "type": "string",
106
+ "minLength": 1
107
+ },
108
+ "required": {
109
+ "type": "boolean"
110
+ },
111
+ "version": {
112
+ "type": [
113
+ "string",
114
+ "null"
115
+ ]
116
+ },
117
+ "registry": {
118
+ "type": [
119
+ "string",
120
+ "null"
121
+ ]
122
+ },
123
+ "dist_tag": {
124
+ "type": [
125
+ "string",
126
+ "null"
127
+ ]
128
+ },
129
+ "observed": {
130
+ "enum": [
131
+ "pending",
132
+ "verified",
133
+ "failed",
134
+ "unknown"
135
+ ]
136
+ },
137
+ "receipt": {
138
+ "type": [
139
+ "string",
140
+ "null"
141
+ ]
142
+ }
143
+ },
144
+ "additionalProperties": false
145
+ }
146
+ }
147
+ },
148
+ "additionalProperties": false
149
+ }
@@ -1,23 +1,125 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "urn:speculo:specdev:triage:v1",
3
+ "$id": "urn:speculo:specdev:triage:v2",
4
4
  "title": "SpecDev Triage Frontmatter",
5
5
  "type": "object",
6
- "required": ["schema_version", "artifact", "change", "mode", "source", "classification", "risk", "route", "ready_for_implementation", "external_action", "updated_at"],
6
+ "required": [
7
+ "schema_version",
8
+ "artifact",
9
+ "change",
10
+ "mode",
11
+ "source",
12
+ "classification",
13
+ "risk",
14
+ "route",
15
+ "ready_for_implementation",
16
+ "external_action",
17
+ "updated_at",
18
+ "disposition",
19
+ "verification",
20
+ "remote_actions"
21
+ ],
7
22
  "properties": {
8
- "schema_version": {"const": 1},
9
- "artifact": {"const": "triage"},
10
- "change": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"},
11
- "mode": {"enum": ["intake", "reconcile", "publish"]},
12
- "source": {"type": "string", "minLength": 1},
13
- "classification": {"enum": ["bug", "feature", "refactor", "investigation", "operations", "documentation", "review", "mixed"]},
14
- "risk": {"enum": ["low", "medium", "high", "critical"]},
15
- "route": {"type": "string", "pattern": "^specdev/[a-z0-9]+(?:-[a-z0-9]+)*$"},
16
- "ready_for_implementation": {"type": "boolean"},
17
- "external_action": {"enum": ["not-applicable", "pending-close", "closed", "close-failed", "waived"]},
18
- "publish_action": {"enum": ["not-requested", "pending", "published", "publish-failed", "waived"]},
19
- "publish": {"type": ["string", "null"]},
20
- "updated_at": {"type": "string", "minLength": 1}
23
+ "schema_version": {
24
+ "const": 2
25
+ },
26
+ "artifact": {
27
+ "const": "triage"
28
+ },
29
+ "change": {
30
+ "type": "string",
31
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}-[a-z0-9]+(?:-[a-z0-9]+)*$"
32
+ },
33
+ "mode": {
34
+ "enum": [
35
+ "intake",
36
+ "reconcile",
37
+ "publish"
38
+ ]
39
+ },
40
+ "source": {
41
+ "type": "string",
42
+ "minLength": 1
43
+ },
44
+ "classification": {
45
+ "enum": [
46
+ "bug",
47
+ "feature",
48
+ "refactor",
49
+ "investigation",
50
+ "operations",
51
+ "documentation",
52
+ "review",
53
+ "mixed"
54
+ ]
55
+ },
56
+ "risk": {
57
+ "enum": [
58
+ "low",
59
+ "medium",
60
+ "high",
61
+ "critical"
62
+ ]
63
+ },
64
+ "route": {
65
+ "type": "string",
66
+ "pattern": "^specdev/[a-z0-9]+(?:-[a-z0-9]+)*$"
67
+ },
68
+ "ready_for_implementation": {
69
+ "type": "boolean"
70
+ },
71
+ "external_action": {
72
+ "enum": [
73
+ "not-applicable",
74
+ "pending-close",
75
+ "closed",
76
+ "close-failed",
77
+ "waived"
78
+ ]
79
+ },
80
+ "publish_action": {
81
+ "enum": [
82
+ "not-requested",
83
+ "pending",
84
+ "published",
85
+ "publish-failed",
86
+ "waived"
87
+ ]
88
+ },
89
+ "publish": {
90
+ "type": [
91
+ "string",
92
+ "null"
93
+ ]
94
+ },
95
+ "updated_at": {
96
+ "type": "string",
97
+ "minLength": 1
98
+ },
99
+ "disposition": {
100
+ "enum": [
101
+ "needs-triage",
102
+ "needs-info",
103
+ "ready-for-agent",
104
+ "ready-for-human",
105
+ "wontfix"
106
+ ]
107
+ },
108
+ "verification": {
109
+ "enum": [
110
+ "pending",
111
+ "passed",
112
+ "failed",
113
+ "unknown"
114
+ ]
115
+ },
116
+ "remote_actions": {
117
+ "type": "array",
118
+ "items": {
119
+ "type": "string"
120
+ },
121
+ "uniqueItems": true
122
+ }
21
123
  },
22
124
  "additionalProperties": true
23
125
  }
@@ -0,0 +1,95 @@
1
+ import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
2
+ import { basename, dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { createHash } from "node:crypto";
5
+
6
+ const schemas = join(dirname(fileURLToPath(import.meta.url)), "..", "schemas");
7
+ function check(value, rule, at, errors) {
8
+ if (rule.anyOf) {
9
+ if (!rule.anyOf.some(r => { const e=[]; check(value,r,at,e); return !e.length; })) errors.push(at + ": invalid value");
10
+ return;
11
+ }
12
+ if (rule.const !== undefined && value !== rule.const) errors.push(at + ": invalid constant");
13
+ if (rule.enum && !rule.enum.includes(value)) errors.push(at + ": invalid enum");
14
+ if (rule.type) {
15
+ const types = Array.isArray(rule.type) ? rule.type : [rule.type];
16
+ const t = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
17
+ if (!types.includes(t)) { errors.push(at + ": invalid type"); return; }
18
+ }
19
+ if (typeof value === "string") {
20
+ if (rule.minLength && value.trim().length < rule.minLength) errors.push(at + ": empty");
21
+ if (rule.pattern && !new RegExp(rule.pattern).test(value)) errors.push(at + ": invalid format");
22
+ if (rule.format === "date-time" && (!/^\d{4}-\d{2}-\d{2}T/.test(value) || Number.isNaN(Date.parse(value)))) errors.push(at + ": invalid timestamp");
23
+ }
24
+ if (Array.isArray(value)) {
25
+ if (rule.minItems && value.length < rule.minItems) errors.push(at + ": missing entries");
26
+ if (rule.uniqueItems && new Set(value).size !== value.length) errors.push(at + ": duplicate entries");
27
+ value.forEach((v,i) => check(v,rule.items ?? {},at+"["+i+"]",errors));
28
+ } else if (value && typeof value === "object") {
29
+ for (const k of rule.required ?? []) if (!(k in value)) errors.push(at + ": missing " + k);
30
+ for (const [k,v] of Object.entries(value)) {
31
+ if (rule.properties?.[k]) check(v,rule.properties[k],at+"."+k,errors);
32
+ else if (rule.additionalProperties === false) errors.push(at + ": unknown " + k);
33
+ }
34
+ }
35
+ }
36
+ const specs = {
37
+ "pull-request": ["pull-request.schema.json", ["Summary","Evidence","Before / After","Merge Risk","Authorization","Receipt","Recovery"]],
38
+ retrospective: ["retrospective.schema.json", ["Scope","Evidence","Findings","Acceptance","Routes"]],
39
+ "logic-prototype": ["logic-prototype.schema.json", ["Model","Scenarios","Evidence","Decisions","Handoff"]],
40
+ "triage-run": ["triage-run.schema.json", ["Targets","Plan","Evidence","Authorization","Receipts","Recovery"]],
41
+ };
42
+ export function validateRecord(path, kind, parse, expectedChange = null) {
43
+ const errors = [];
44
+ if (!existsSync(path) || !lstatSync(path).isFile() || lstatSync(path).isSymbolicLink()) return { errors: [path + ": missing or unsafe record"], meta: {} };
45
+ const {meta, body} = parse(path), spec = specs[kind];
46
+ check(meta, JSON.parse(readFileSync(join(schemas,spec[0]),"utf8")), basename(path), errors);
47
+ if (expectedChange && meta.change !== expectedChange) errors.push(path + ": change mismatch");
48
+ if (kind === "logic-prototype" ? basename(dirname(path)) !== meta.id : basename(path) !== meta.id + ".md") errors.push(path + ": ID/path mismatch");
49
+ for (const heading of spec[1]) {
50
+ const section = new RegExp("^## " + heading.replace(/[.*+?^${}()|[\]\\]/g,"\\$&") + "\\r?\\n([\\s\\S]*?)(?=^## |$(?![\\s\\S]))","m").exec(body)?.[1];
51
+ if (!section?.trim()) errors.push(path + ": missing or empty section " + heading);
52
+ }
53
+ if (kind === "pull-request") {
54
+ if (meta.status === "ready" && meta.verification !== "passed") errors.push(path + ": ready PR requires passed verification");
55
+ if (["draft","ready"].includes(meta.status) && !new RegExp("^https://github\\.com/" + String(meta.repo).replaceAll(".","\\.") + "/pull/[1-9]\\d*$").test(meta.url ?? "")) errors.push(path + ": missing matching PR URL");
56
+ }
57
+ if (kind === "retrospective" && (meta.sources ?? []).some(s => typeof s !== "string" || !s.trim() || /(?:[A-Za-z]:[\\/]|\b(?:token|secret)=)/i.test(s))) errors.push(path + ": unsafe source");
58
+ if (kind === "triage-run" && meta.status === "completed" && meta.mode !== "ci-security") {
59
+ if (meta.npm_target === "unknown") errors.push(path + ": completed release target cannot be unknown");
60
+ if (!meta.commit_sha) errors.push(path + ": completed release requires fixed commit");
61
+ const targets = Array.isArray(meta.targets) ? meta.targets : [];
62
+ if (!targets.some(t => t.required)) errors.push(path + ": completed preflight/release requires explicit targets");
63
+ if (meta.npm_target === "required" && !targets.some(t => t.kind === "npm" && t.required)) errors.push(path + ": missing required npm target");
64
+ if (meta.npm_target === "not-required" && targets.some(t => t.kind === "npm" && t.required)) errors.push(path + ": conflicting npm target decision");
65
+ for (const target of targets.filter(t => t.required)) {
66
+ if (target.kind === "npm" && (!target.version || !target.registry || !target.dist_tag)) errors.push(path + ": incomplete npm target metadata");
67
+ if (meta.mode === "release" && (target.observed !== "verified" || !target.receipt?.trim())) errors.push(path + ": required target has no verified receipt");
68
+ }
69
+ }
70
+ if (kind === "logic-prototype") {
71
+ const htmlPath = join(dirname(path),"index.html");
72
+ if (!existsSync(htmlPath) || lstatSync(htmlPath).isSymbolicLink()) errors.push(path + ": missing or unsafe index.html");
73
+ else {
74
+ const html = readFileSync(htmlPath,"utf8");
75
+ if (/<(?:script|iframe)\b[^>]*\bsrc\s*=|<link\b[^>]*\bhref\s*=|\b(?:fetch|WebSocket|XMLHttpRequest|sendBeacon)\s*\(|@import\b|url\(\s*["']?(?:https?:|\/\/)|\b(?:src|href)\s*=\s*["'](?:https?:|\/\/)/i.test(html)) errors.push(path + ": logic prototype must be standalone and offline");
76
+ if (!/reset/i.test(html) || !/<script\b/i.test(html)) errors.push(path + ": missing reset or inline logic");
77
+ if (meta.status === "ready") {
78
+ if (meta.verification !== "passed") errors.push(path + ": ready logic requires browser verification");
79
+ if (meta.html_sha256 !== createHash("sha256").update(html).digest("hex")) errors.push(path + ": HTML digest mismatch");
80
+ }
81
+ }
82
+ }
83
+ return {errors,meta,body};
84
+ }
85
+ export function validateRecords(change, kind, parse) {
86
+ const folder = kind === "retrospective" ? "retro" : "pull-requests", root=join(change,folder);
87
+ const errors=[], records=[];
88
+ if (!existsSync(root)) return {errors,records};
89
+ if (lstatSync(root).isSymbolicLink() || !lstatSync(root).isDirectory()) return {errors:[root + ": unsafe directory"],records};
90
+ for (const file of readdirSync(root)) {
91
+ const result=validateRecord(join(root,file),kind,parse,basename(change));
92
+ errors.push(...result.errors); records.push(result);
93
+ }
94
+ return {errors,records};
95
+ }