@mstar-harness/engine 3.8.2 → 3.8.3

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/engine.js CHANGED
@@ -5596,18 +5596,62 @@ function findEphemeralCitations(skillText) {
5596
5596
  return citations;
5597
5597
  }
5598
5598
  var TEST_FILE_PATH_RE = /[\w./-]+\.(?:test|spec)\.[a-z0-9]+/i;
5599
- var TEST_FILE_PHRASE_RE = /\btest files?\b/i;
5599
+ var TEST_FILE_PHRASE_RE = /\btest file(?:s|\(s\))?\s*:[ \t]*(.+)/i;
5600
5600
  var COMMAND_PROMPT_RE = /^\s*[$>]\s*\S/;
5601
5601
  var RUNNER_RE = /\b(?:bun|pnpm|npm|yarn|npx|bunx)\s+(?:test|run|exec)\b|\b(?:npx|bunx)\s+[\w./-]+\b|\b(?:tsc|vitest|jest|mocha|pytest)\b|\bgo\s+test\b|\bcargo\s+test\b/i;
5602
5602
  var OUTPUT_TOKEN_RE = /[\u2713\u2714\u2717\u2718]|\b(?:PASS|FAIL)\b|\b\d+\s+(?:pass(?:es|ed)?|fail(?:s|ed|ing)?|skipped|tests?|ok)\b|\bok\s+\d+\b|\ball\s+ok\b|exit(?:ed)?\s+(?:with\s+)?(?:code\s+)?\d+/i;
5603
+ function hasEvidenceDetail(value) {
5604
+ const detail = value.trim().replace(/^`+|`+$/g, "").trim();
5605
+ return detail.length > 0 && !/^(?:n\/a|none|tbd|todo|tba|unknown|skipped|not[- ]run|\.\.\.|\u2026|<[^>]+>)$/i.test(detail);
5606
+ }
5603
5607
  function assertSddTddTriple(reportText) {
5604
5608
  const violations = [];
5605
- const lines = reportText.split(/\r?\n/);
5609
+ const activeRound = [...reportText.matchAll(/^## Verification round:[ \t]*(.*)$/gm)].at(-1);
5610
+ if (activeRound && !hasEvidenceDetail(activeRound[1])) {
5611
+ return {
5612
+ ok: false,
5613
+ violations: [violation11("medium", "lint.sdd-evidence.invalid-round", "Verification round requires a concrete label.")]
5614
+ };
5615
+ }
5616
+ const activeText = activeRound ? reportText.slice(activeRound.index + activeRound[0].length) : reportText;
5617
+ const lines = activeText.split(/\r?\n/);
5618
+ const fields = new Map;
5619
+ for (const line of lines) {
5620
+ const match = line.match(/^\s*(Verification mode|Changed files|Tests|Reason|Check command|Check result):[ \t]*(.*)$/i);
5621
+ if (match) {
5622
+ const key = match[1].toLowerCase();
5623
+ fields.set(key, [...fields.get(key) ?? [], match[2].trim()]);
5624
+ }
5625
+ }
5626
+ const modes = fields.get("verification mode");
5627
+ if (modes) {
5628
+ if (modes.length !== 1 || modes[0] !== "scoped-check") {
5629
+ return {
5630
+ ok: false,
5631
+ violations: [violation11("medium", "lint.sdd-evidence.invalid-mode", "Use exactly one Verification mode: scoped-check declaration in the active round; unknown or duplicate modes are invalid.")]
5632
+ };
5633
+ }
5634
+ for (const key of ["changed files", "tests", "reason", "check command", "check result"]) {
5635
+ const values = fields.get(key) ?? [];
5636
+ const value = values[0] ?? "";
5637
+ const valid = values.length === 1 && (key === "tests" ? value === "N/A" : hasEvidenceDetail(value));
5638
+ if (!valid) {
5639
+ violations.push(violation11("medium", `lint.sdd-evidence.${key.replaceAll(" ", "-")}`, `scoped-check requires one concrete ${key} field${key === "tests" ? " with value N/A" : ""}; missing, duplicate, or placeholder evidence is invalid.`));
5640
+ }
5641
+ }
5642
+ return { ok: violations.length === 0, violations };
5643
+ }
5644
+ if (lines.some((line) => /^\s*(?:Tests|(?:Covering )?test file(?:s|\(s\))?):\s*`?N\/A`?\s*$/i.test(line))) {
5645
+ return {
5646
+ ok: false,
5647
+ violations: [violation11("medium", "lint.sdd-tdd.missing-tests", "Bare N/A is not test evidence; document/policy checks need an explicit, complete scoped-check declaration.")]
5648
+ };
5649
+ }
5606
5650
  let hasTests = false;
5607
5651
  let hasCommand = false;
5608
5652
  let hasOutput = false;
5609
5653
  for (const line of lines) {
5610
- if (!hasTests && (TEST_FILE_PATH_RE.test(line) || TEST_FILE_PHRASE_RE.test(line)))
5654
+ if (!hasTests && (TEST_FILE_PATH_RE.test(line) || hasEvidenceDetail(line.match(TEST_FILE_PHRASE_RE)?.[1] ?? "")))
5611
5655
  hasTests = true;
5612
5656
  if (!hasCommand && (COMMAND_PROMPT_RE.test(line) || RUNNER_RE.test(line)))
5613
5657
  hasCommand = true;
package/dist/lint.d.ts CHANGED
@@ -138,11 +138,12 @@ export type EphemeralCitation = {
138
138
  */
139
139
  export declare function findEphemeralCitations(skillText: string): EphemeralCitation[];
140
140
  /**
141
- * Assert the SDD TDD triple is present in a `task-N-report.md` text
142
- * (mstar-coding-behavior § Integration Notes "completion evidence must
143
- * include TDD triple test file(s), command, output in task-N-report.md";
144
- * mstar-sdd/references/file-handoffs.md fix subagents append covering test
145
- * file(s), command run, output).
141
+ * Validate task report evidence: an explicit scoped-check declaration for
142
+ * document/policy checks, otherwise the executable-change TDD triple.
143
+ * This checks structure, not whether the declared mode fits the actual diff
144
+ * or a command ran. PM/QC own applicability and evidence authenticity.
145
+ * Scoped check results may be arbitrary concrete static-tool output; the
146
+ * output-token heuristic below applies only to executable test triples.
146
147
  *
147
148
  * One violation per missing part:
148
149
  * - `lint.sdd-tdd.missing-tests` — no test file reference
@@ -150,9 +151,8 @@ export declare function findEphemeralCitations(skillText: string): EphemeralCita
150
151
  * - `lint.sdd-tdd.missing-output` — no output evidence
151
152
  *
152
153
  * Heuristics (documented, conservative — tuned so prose alone never counts):
153
- * - tests: a `.test.<ext>` / `.spec.<ext>` path, or the phrase "test file(s)"
154
- * (the handoff template's exact header). "I added tests" without a file or
155
- * the phrase does not count.
154
+ * - tests: a `.test.<ext>` / `.spec.<ext>` path, or a non-placeholder
155
+ * "test file(s): <reference>" field. Bare N/A is not test evidence.
156
156
  * - command: a `$`-prefixed line, or a known runner invocation (bun/pnpm/
157
157
  * npm/yarn/npx/bunx test|run|exec, npx/bunx exec, tsc/vitest/jest/mocha/
158
158
  * pytest/go test/cargo test). Prose "run the tests" names no runner and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mstar-harness/engine",
3
- "version": "3.8.2",
3
+ "version": "3.8.3",
4
4
  "description": "Morning Star Harness Workflow Engine — deterministic workflow enforcement library (path, status, lease, dispatch, sdd, iteration, lint gates).",
5
5
  "license": "MIT",
6
6
  "repository": {