@fro.bot/systematic 3.13.6 → 3.14.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/dist/cli.js CHANGED
@@ -1991,7 +1991,8 @@ var REVIEW_ARTIFACT_CUSTOM_MESSAGES = [
1991
1991
  "filtered findings require a validation reason",
1992
1992
  "risk-critical dispatches require a non-empty selection surface",
1993
1993
  "satisfied risk coverage requires a citing input finding ID",
1994
- "unsatisfied risk coverage must not cite an input finding ID"
1994
+ "unsatisfied risk coverage must not cite an input finding ID",
1995
+ "passed validation must not include a reason; non-passed validation requires a reason"
1995
1996
  ];
1996
1997
  var boundedText = (maxLength) => exports_external.string().min(1).max(maxLength).regex(/\S/);
1997
1998
  var DispatchOutcomeSchema = exports_external.enum([
@@ -2142,6 +2143,30 @@ var DeclinedMergeSchema = exports_external.object({
2142
2143
  input_finding_ids: exports_external.array(boundedText(MAX_INPUT_ID_LENGTH)).min(2).max(MAX_FINDINGS),
2143
2144
  reason: ReasonSchema
2144
2145
  }).strict();
2146
+ var ValidationSchema = exports_external.object({
2147
+ status: exports_external.enum([
2148
+ "passed",
2149
+ "failed",
2150
+ "unavailable",
2151
+ "not_attempted"
2152
+ ]),
2153
+ reason: ReasonSchema.optional()
2154
+ }).strict().superRefine((validation, ctx) => {
2155
+ if (validation.status === "passed" && validation.reason !== undefined) {
2156
+ ctx.addIssue({
2157
+ code: "custom",
2158
+ path: ["reason"],
2159
+ message: REVIEW_ARTIFACT_CUSTOM_MESSAGES[5]
2160
+ });
2161
+ }
2162
+ if (validation.status !== "passed" && validation.reason === undefined) {
2163
+ ctx.addIssue({
2164
+ code: "custom",
2165
+ path: ["reason"],
2166
+ message: REVIEW_ARTIFACT_CUSTOM_MESSAGES[5]
2167
+ });
2168
+ }
2169
+ });
2145
2170
  var RiskCoverageSchema = exports_external.object({
2146
2171
  persona: RiskCriticalPersonaSchema,
2147
2172
  satisfied: exports_external.boolean(),
@@ -2186,7 +2211,8 @@ var ReviewArtifactSchema = exports_external.object({
2186
2211
  applied_fixes: exports_external.array(ReasonSchema).max(MAX_FINDINGS),
2187
2212
  residual_actionable_work: exports_external.array(ReasonSchema).max(MAX_FINDINGS),
2188
2213
  advisory_outputs: exports_external.array(ReasonSchema).max(MAX_FINDINGS),
2189
- coverage: CoverageSchema
2214
+ coverage: CoverageSchema,
2215
+ validation: ValidationSchema.optional()
2190
2216
  }).strict();
2191
2217
 
2192
2218
  // src/lib/setup.ts
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- export declare const REVIEW_ARTIFACT_CUSTOM_MESSAGES: readonly ['severity count must match rejected finding count', 'filtered findings require a validation reason', 'risk-critical dispatches require a non-empty selection surface', 'satisfied risk coverage requires a citing input finding ID', 'unsatisfied risk coverage must not cite an input finding ID'];
2
+ export declare const REVIEW_ARTIFACT_CUSTOM_MESSAGES: readonly ['severity count must match rejected finding count', 'filtered findings require a validation reason', 'risk-critical dispatches require a non-empty selection surface', 'satisfied risk coverage requires a citing input finding ID', 'unsatisfied risk coverage must not cite an input finding ID', 'passed validation must not include a reason; non-passed validation requires a reason'];
3
3
  export declare const DispatchOutcomeSchema: z.ZodEnum<{
4
4
  empty: "empty";
5
5
  findings: "findings";
@@ -255,6 +255,15 @@ export declare const ReviewArtifactSchema: z.ZodObject<{
255
255
  validator_failures: z.ZodArray<z.ZodString>;
256
256
  intent_uncertainty: z.ZodArray<z.ZodString>;
257
257
  }, z.core.$strict>;
258
+ validation: z.ZodOptional<z.ZodObject<{
259
+ status: z.ZodEnum<{
260
+ failed: "failed";
261
+ not_attempted: "not_attempted";
262
+ passed: "passed";
263
+ unavailable: "unavailable";
264
+ }>;
265
+ reason: z.ZodOptional<z.ZodString>;
266
+ }, z.core.$strict>>;
258
267
  }, z.core.$strict>;
259
268
  export type ReviewArtifact = z.infer<typeof ReviewArtifactSchema>;
260
269
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fro.bot/systematic",
3
- "version": "3.13.6",
3
+ "version": "3.14.0",
4
4
  "description": "Compound-engineering loops for OpenCode, Pi, and Claude Code",
5
5
  "type": "module",
6
6
  "homepage": "https://fro.bot/systematic",
@@ -52,7 +52,7 @@ tags: [keyword-one, keyword-two]
52
52
 
53
53
  ## Knowledge Track Template
54
54
 
55
- Use for: `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`
55
+ Use for: `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`, `architecture_pattern`, `design_pattern`, `tooling_decision`, `convention`
56
56
 
57
57
  ```markdown
58
58
  ---
@@ -52,7 +52,7 @@ tags: [keyword-one, keyword-two]
52
52
 
53
53
  ## Knowledge Track Template
54
54
 
55
- Use for: `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`
55
+ Use for: `best_practice`, `documentation_gap`, `workflow_issue`, `developer_experience`, `architecture_pattern`, `design_pattern`, `tooling_decision`, `convention`
56
56
 
57
57
  ```markdown
58
58
  ---
@@ -606,6 +606,23 @@
606
606
  "intent_uncertainty"
607
607
  ],
608
608
  "additionalProperties": false
609
+ },
610
+ "validation": {
611
+ "type": "object",
612
+ "properties": {
613
+ "status": {
614
+ "type": "string",
615
+ "enum": ["passed", "failed", "unavailable", "not_attempted"]
616
+ },
617
+ "reason": {
618
+ "type": "string",
619
+ "minLength": 1,
620
+ "maxLength": 2048,
621
+ "pattern": "\\S"
622
+ }
623
+ },
624
+ "required": ["status"],
625
+ "additionalProperties": false
609
626
  }
610
627
  },
611
628
  "required": [
@@ -210,11 +210,24 @@ validating it. This ordering makes the artifact validatable at all: without
210
210
  `schema_version`, the validator reports the legacy status (exit 3) rather than
211
211
  a real validation result.
212
212
 
213
- After writing `review-summary.json`, the parent runs
214
- `systematic validate-review-artifact <path>` against it. A nonzero exit means
215
- the run is not complete. The [executable schema](./review-summary-schema.json)
216
- is generated from a Zod source and is the machine-checkable form of the shape
217
- described here.
213
+ After writing `review-summary.json`, the parent checks whether the
214
+ `systematic` executable is available on the invoking environment's `PATH`.
215
+ When it is available, the parent runs
216
+ `systematic validate-review-artifact <path>` against it. The executable ships
217
+ through the npm package's `bin` entry; a harness that installs bundled
218
+ markdown without that package will not have it. When it is unavailable, the
219
+ parent records `validation.status: "unavailable"` and a `validation.reason` in
220
+ the run record. When the executable is available and the parent does not run
221
+ it, that is `validation.status: "not_attempted"`, also with a reason. The
222
+ `validation.status` values are `passed`, `failed`, `unavailable`, and
223
+ `not_attempted`; `validation.reason` is required for every status except
224
+ `passed`, where it is forbidden.
225
+
226
+ Unavailable validation is distinct from skipped validation — `unavailable`
227
+ versus `not_attempted` — and in neither case does the parent represent the
228
+ artifact as validated. A nonzero exit means the run is not complete. The
229
+ [executable schema](./review-summary-schema.json) is generated from a Zod
230
+ source and is the machine-checkable form of the shape described here.
218
231
 
219
232
  On validation failure, the parent repairs the artifact and re-runs the
220
233
  validator. It does not report a verdict over an artifact that failed
@@ -226,7 +239,13 @@ This is enforcement by visible failure, not by containment. An agent that
226
239
  never runs the command can still finalize an artifact, but produces no evidence
227
240
  in either direction. That is why the command exists as an independently
228
241
  runnable check rather than as a self-validation instruction, and why its result
229
- belongs in the run record.
242
+ belongs in the run record. An unavailable validator is recorded as unavailable,
243
+ not as skipped or validated.
244
+ The `validation` field is self-reported: an agent can write `status: passed`
245
+ without running anything, so it is a claim rather than evidence. Its value is
246
+ that it distinguishes states that were previously one indistinguishable
247
+ silence: a check that passed, one that failed, one that could not run, and one
248
+ that was skipped.
230
249
 
231
250
  `mode:report-only` writes no artifact and therefore performs no validation.
232
251