@event4u/agent-config 14.15.0 → 14.16.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 (37) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +58 -0
  5. package/dist/agent-src/rules/security-sensitive-stop.md +7 -5
  6. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +20 -2
  7. package/dist/agent-src/skills/design-intelligence/data/ux-guidelines.csv +99 -99
  8. package/dist/agent-src/skills/fe-design/SKILL.md +6 -3
  9. package/dist/agent-src/skills/fe-design/references/design-patterns.md +28 -0
  10. package/dist/agent-src/skills/iconography/SKILL.md +37 -6
  11. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  12. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  13. package/dist/cli-delegate/cmd_conformance.js +158 -33
  14. package/dist/discovery/deprecation-report.md +1 -1
  15. package/dist/discovery/discovery-manifest.json +7 -7
  16. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  17. package/dist/discovery/discovery-manifest.summary.md +1 -1
  18. package/dist/discovery/dormancy-report.md +1 -1
  19. package/dist/discovery/orphan-report.md +1 -1
  20. package/dist/discovery/packs.json +2 -2
  21. package/dist/discovery/trust-report.md +1 -1
  22. package/dist/discovery/workspaces.json +2 -2
  23. package/dist/hooks/dispatch.js +169 -41
  24. package/dist/mcp/registry-manifest.json +2 -2
  25. package/dist/mcp/server.json +2 -2
  26. package/dist/mcp/server.mjs +160 -35
  27. package/dist/router.json +1 -1
  28. package/docs/guidelines/design-antipatterns.md +10 -2
  29. package/package.json +1 -1
  30. package/src/config/gate-violation-baselines.json +2 -2
  31. package/src/scripts/design_slop_rules.ts +19 -9
  32. package/src/scripts/git_authorization_hook.ts +257 -35
  33. package/src/scripts/hooks/block_unauthorized_git.ts +16 -4
  34. package/src/scripts/hooks/merge_impact.ts +68 -0
  35. package/src/scripts/release.ts +4 -17
  36. package/src/scripts/release_drill.ts +154 -1
  37. package/src/scripts/release_publication.ts +91 -0
@@ -807,20 +807,22 @@ var PHRASES = [
807
807
  // "never auto-merge" each returned ["pr-merge"] — a prompt saying DO NOT
808
808
  // MERGE authorized a merge. The noun-sense lookahead was never a negator.
809
809
  //
810
- // The lookBEHIND is line-scoped by `[^.!?\n]` on purpose, the same scoping
811
- // `turn_end_gate_hook.ts` uses for its own negation exclusion (`:330`) and
812
- // its negated-claim window (`:490-493`). A sentence boundary ends a
813
- // negation's reach: "Do not push. Merge PR #12." is two instructions, and a
814
- // guard that let the first suppress the second would silently stop
815
- // authorizing merges the user DID order — the failure mode that is worse
816
- // than the defect, because nothing happens and nothing says why.
817
- //
818
- // Reusing that vocabulary rather than inventing a third is deliberate: two
810
+ // The inline negative lookBEHIND that used to live in this pattern was
811
+ // REMOVED on 2026-09-03, and its own comment is why. It warned that "two
819
812
  // negation vocabularies in one tree drift, and the drift is invisible until
820
- // a prompt lands in the gap between them.
813
+ // a prompt lands in the gap between them" — and by then they had drifted:
814
+ // `negatedBefore` became clause-scanned in both directions while this
815
+ // lookbehind stayed a blind 30-character window with no forward half. The
816
+ // prompt that landed in the gap is `"nicht pushen, aber mergen"`, which the
817
+ // lookbehind refused (13 characters, inside its window, across a contrast
818
+ // cue it could not see) while the clause scan correctly authorizes it.
819
+ //
820
+ // Every phrase match already passes through `negatedBefore` at the call
821
+ // site, so the guard is not weakened by the removal — it is applied once,
822
+ // by the one vocabulary this file's comment asked for.
821
823
  {
822
824
  op: "pr-merge",
823
- re: /(?<!\b(nicht|nichts|kein(e|en|em|er|es)?|niemals|nie|no|not|dont|don't|never|without|ohne)\b[^.!?\n]{0,30})\b(merge|merg(e|en|st|t)|zusammenf(ü|ue)hren|reinmergen)\b(?!\s*[- ]?(conflict|konflikt|commit|base|queue|state|status))/i
825
+ re: /\b(merge|merg(e|en|st|t)|zusammenf(ü|ue)hren|reinmergen)\b(?!\s*[- ]?(conflict|konflikt|commit|base|queue|state|status))/i
824
826
  },
825
827
  // A tag is an ACTION here — bare "Tag" is the German word for day, and
826
828
  // "Version" is an ordinary noun. Both authorized a BLOCK op before this.
@@ -942,13 +944,16 @@ function isInterrogative(prose) {
942
944
  if (!t) {
943
945
  return false;
944
946
  }
945
- const hasImperative = /\b(mach|mache|bitte|leg|lege|erstell|erstelle|f(ü|ue)hr|f(ü|ue)hre|setz|setze|starte|los|jetzt|go ahead|do it|ja[,.]?\s|ok[,.]?\s)\b/i.test(
947
+ if (/\?\s*$/.test(t)) {
948
+ return true;
949
+ }
950
+ const hasImperative = /\b(mach|mache|bitte|leg|lege|erstell|erstelle|f(ü|ue)hr|f(ü|ue)hre|setz|setze|starte|los|jetzt|now|asap|go ahead|do it|ja[,.]?\s|ok[,.]?\s)\b/i.test(
946
951
  t
947
952
  );
948
953
  if (hasImperative) {
949
954
  return false;
950
955
  }
951
- return /\?\s*$/.test(t) || /^(was|wie|warum|wieso|weshalb|wann|wer|welche[rs]?|wo|ist|sind|kann|kannst|k(ö|oe)nnen|soll|sollen|darf|d(ü|ue)rfen|why|what|how|when|which|who|is|are|can|could|should|does|do)\b/i.test(
956
+ return /^(was|wie|warum|wieso|weshalb|wann|wer|welche[rs]?|wo|ist|sind|kann|kannst|k(ö|oe)nnen|soll|sollen|darf|d(ü|ue)rfen|why|what|how|when|which|who|is|are|can|could|should|does|do)\b/i.test(
952
957
  t
953
958
  );
954
959
  }
@@ -995,13 +1000,18 @@ function splitFences(prompt) {
995
1000
  function _commandLines(fence) {
996
1001
  return fence.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).filter((l) => !/^(remote:|error:|hint:|fatal:|warning:|To |!\s|\s*\^)/i.test(l)).map((l) => l.replace(/^[$>#]\s*/, "")).filter((l) => /^(git|gh|npm|pnpm|yarn|task)\b/.test(l));
997
1002
  }
1003
+ function _errText(err) {
1004
+ const t = err instanceof Error ? err.message : String(err);
1005
+ return t.replace(/\s+/g, " ").trim().slice(0, 200);
1006
+ }
1007
+ var PR_NUMBER_MAX = 2147483647;
998
1008
  function extractMergeTargets(prompt) {
999
1009
  const out = /* @__PURE__ */ new Set();
1000
- const re = /(?:#|\bpr[- ]?|\bpull[- ]request\s+#?)(\d{1,7})\b/giu;
1010
+ const re = /(?:#|\bpr[- ]?|\bpull[- ]request\s+#?)(\d{1,10})\b/giu;
1001
1011
  let m;
1002
1012
  while ((m = re.exec(prompt)) !== null) {
1003
1013
  const n = Number.parseInt(m[1], 10);
1004
- if (Number.isSafeInteger(n) && n > 0) {
1014
+ if (Number.isSafeInteger(n) && n > 0 && n <= PR_NUMBER_MAX) {
1005
1015
  out.add(n);
1006
1016
  }
1007
1017
  }
@@ -1045,27 +1055,109 @@ function foldGrants(prior, prompt, authorized, session_id, now) {
1045
1055
  ];
1046
1056
  }
1047
1057
  var NEGATION_WORD = /\b(nicht|nichts|kein(e|en|em|er|es)?|niemals|nie|no|not|dont|don't|never|without|ohne)\b/i;
1048
- function negatedBefore(text, index, matched = "") {
1058
+ var CONTRAST_CUE = /\b(aber|sondern|jedoch|but|however|instead)\b/gi;
1059
+ var ABBREVIATION_BEFORE_DOT = /(?:^|[\s("'\u2018\u201c])(?:[a-z]|z\.b|bzw|ca|usw|d\.h|u\.a|evtl|ggf|inkl|max|min|nr|abb|e\.g|i\.e|etc|vs|approx|fig|no|st|dr|prof)\.$/i;
1060
+ function isSentenceBoundary(text, at) {
1061
+ const mark = text[at];
1062
+ if (mark !== ".") {
1063
+ return true;
1064
+ }
1065
+ if (/\d/.test(text[at - 1] ?? "") && /\d/.test(text[at + 1] ?? "")) {
1066
+ return false;
1067
+ }
1068
+ return !ABBREVIATION_BEFORE_DOT.test(text.slice(0, at + 1));
1069
+ }
1070
+ function sentenceBounds(text, index) {
1049
1071
  let start = 0;
1050
- for (const mark of [".", "!", "?", "\n"]) {
1051
- const at = text.lastIndexOf(mark, index - 1);
1052
- if (at + 1 > start) {
1053
- start = at + 1;
1072
+ for (let i = index - 1; i >= 0; i -= 1) {
1073
+ const c = text[i];
1074
+ if ((c === "." || c === "!" || c === "?" || c === "\n") && isSentenceBoundary(text, i)) {
1075
+ start = i + 1;
1076
+ break;
1054
1077
  }
1055
1078
  }
1056
- const before = text.slice(Math.max(start, index - 30), index);
1057
- return NEGATION_WORD.test(before) || NEGATION_WORD.test(matched);
1079
+ let end = text.length;
1080
+ for (let i = index; i < text.length; i += 1) {
1081
+ const c = text[i];
1082
+ if ((c === "." || c === "!" || c === "?" || c === "\n") && isSentenceBoundary(text, i)) {
1083
+ end = i;
1084
+ break;
1085
+ }
1086
+ }
1087
+ return { start, end };
1088
+ }
1089
+ function _sentences(text) {
1090
+ const out = [];
1091
+ let from = 0;
1092
+ for (let i = 0; i < text.length; i += 1) {
1093
+ const c = text[i];
1094
+ if ((c === "." || c === "!" || c === "?" || c === "\n") && isSentenceBoundary(text, i)) {
1095
+ out.push(text.slice(from, i + 1));
1096
+ from = i + 1;
1097
+ }
1098
+ }
1099
+ if (from < text.length) {
1100
+ out.push(text.slice(from));
1101
+ }
1102
+ return out.filter((t) => t.trim() !== "");
1103
+ }
1104
+ function clauseStart(text, from, to) {
1105
+ let start = from;
1106
+ const seg = text.slice(from, to);
1107
+ for (let i = seg.length - 1; i >= 0; i -= 1) {
1108
+ const c = seg[i];
1109
+ if (c === "," || c === ";" || c === ":") {
1110
+ start = from + i + 1;
1111
+ break;
1112
+ }
1113
+ }
1114
+ CONTRAST_CUE.lastIndex = 0;
1115
+ let m;
1116
+ while ((m = CONTRAST_CUE.exec(seg)) !== null) {
1117
+ const after = from + m.index + m[0].length;
1118
+ if (after > start) {
1119
+ start = after;
1120
+ }
1121
+ }
1122
+ return start;
1123
+ }
1124
+ function clauseEnd(text, from, to) {
1125
+ const seg = text.slice(from, to);
1126
+ let end = to;
1127
+ const punct = seg.search(/[,;:]/);
1128
+ if (punct !== -1) {
1129
+ end = from + punct;
1130
+ }
1131
+ CONTRAST_CUE.lastIndex = 0;
1132
+ const m = CONTRAST_CUE.exec(seg);
1133
+ if (m !== null && from + m.index < end) {
1134
+ end = from + m.index;
1135
+ }
1136
+ return end;
1137
+ }
1138
+ function negatedBefore(text, index, matched = "") {
1139
+ const { start, end } = sentenceBounds(text, index);
1140
+ const before = text.slice(clauseStart(text, start, index), index);
1141
+ const afterFrom = index + matched.length;
1142
+ const after = afterFrom < end ? text.slice(afterFrom, clauseEnd(text, afterFrom, end)) : "";
1143
+ return NEGATION_WORD.test(before) || NEGATION_WORD.test(matched) || NEGATION_WORD.test(after);
1058
1144
  }
1059
1145
  function classifyAuthorization(prompt) {
1060
1146
  const { prose, fences } = splitFences(prompt);
1061
1147
  const authorized = /* @__PURE__ */ new Set();
1062
1148
  const evidence = {};
1063
1149
  const instruction = prose.split("\n").filter((l) => !OUTPUT_LINE.test(l)).join("\n");
1064
- for (const { op, re } of isInterrogative(instruction) ? [] : PHRASES) {
1065
- const m = re.exec(instruction);
1066
- if (m && !negatedBefore(instruction, m.index, m[0])) {
1067
- authorized.add(op);
1068
- evidence[op] = `prose: "${m[0]}"`;
1150
+ for (const { op, re } of PHRASES) {
1151
+ for (const sentence of _sentences(instruction)) {
1152
+ if (isInterrogative(sentence)) {
1153
+ continue;
1154
+ }
1155
+ const m = re.exec(sentence);
1156
+ if (m && !negatedBefore(sentence, m.index, m[0])) {
1157
+ authorized.add(op);
1158
+ evidence[op] = `prose: "${m[0]}"`;
1159
+ break;
1160
+ }
1069
1161
  }
1070
1162
  }
1071
1163
  for (const fence of fences) {
@@ -1143,7 +1235,11 @@ function consumeGrantTarget(consumer_root, session_id, target) {
1143
1235
  if (touched) {
1144
1236
  try {
1145
1237
  atomic_write_json(file, decoded);
1146
- } catch {
1238
+ } catch (err) {
1239
+ process.stderr.write(
1240
+ `git-authorization: grant-consumption write failed (${_errText(err)}) \u2014 the target stays UNSPENT, so one further merge of a PR the user named will still be authorized. Authorization outcome unchanged.
1241
+ `
1242
+ );
1147
1243
  }
1148
1244
  }
1149
1245
  }
@@ -1236,7 +1332,11 @@ function run2(stdin_text, options) {
1236
1332
  };
1237
1333
  try {
1238
1334
  atomic_write_json(path2.join(options.consumer_root, ledgerFileFor(session)), ledger);
1239
- } catch {
1335
+ } catch (err) {
1336
+ process.stderr.write(
1337
+ `git-authorization: session-ledger write failed (${_errText(err)}) \u2014 the gate degrades to "no ledger" for this session, which denies the irreversible subset and warns on the rest. Authorization outcome unchanged.
1338
+ `
1339
+ );
1240
1340
  }
1241
1341
  return EXIT_ALLOW2;
1242
1342
  }
@@ -1300,6 +1400,24 @@ var DESTRUCTIVE_MARKERS = [
1300
1400
  { label: "a route or endpoint was removed", re: /^-.*\b(Route::(get|post|put|patch|delete)|@(Get|Post|Put|Patch|Delete)Mapping|app\.(get|post|put|patch|delete)\s*\()/m },
1301
1401
  { label: "a whole file was deleted", re: /^deleted file mode /m }
1302
1402
  ];
1403
+ var SCHEMA_REMOVAL_BODY = /\b(dropColumn|dropTable|dropIfExists|removeColumn|drop_column|drop_table|DROP\s+(TABLE|COLUMN|INDEX|CONSTRAINT)|TRUNCATE\s+TABLE)\b/i;
1404
+ var RENAME_METADATA = /^rename (?:from|to) /m;
1405
+ function fileBlocks(patch) {
1406
+ return patch.split(/^(?=diff --git )/m).filter((b) => b.startsWith("diff --git "));
1407
+ }
1408
+ function renamedSchemaRemoval(patch) {
1409
+ for (const block of fileBlocks(patch)) {
1410
+ if (!RENAME_METADATA.test(block)) {
1411
+ continue;
1412
+ }
1413
+ for (const line of block.split("\n")) {
1414
+ if (line.startsWith("-") && !line.startsWith("---") && SCHEMA_REMOVAL_BODY.test(line)) {
1415
+ return true;
1416
+ }
1417
+ }
1418
+ }
1419
+ return false;
1420
+ }
1303
1421
  var MAJOR_BUMP = /^-\s*"version"\s*:\s*"(\d+)\.[^"]*"[\s\S]{0,200}?^\+\s*"version"\s*:\s*"(\d+)\./m;
1304
1422
  function classifyDiff(patch) {
1305
1423
  if (patch.trim() === "") {
@@ -1311,6 +1429,9 @@ function classifyDiff(patch) {
1311
1429
  markers.push(label);
1312
1430
  }
1313
1431
  }
1432
+ if (renamedSchemaRemoval(patch)) {
1433
+ markers.push("a renamed file drops a column or table");
1434
+ }
1314
1435
  const bump = MAJOR_BUMP.exec(patch);
1315
1436
  if (bump && bump[1] !== bump[2]) {
1316
1437
  markers.push(`major version bump ${bump[1]}.x to ${bump[2]}.x`);
@@ -1732,12 +1853,16 @@ function commandOp(command) {
1732
1853
  return found;
1733
1854
  }
1734
1855
  function mergeTargetOf(command) {
1735
- const gh = /\bgh\s+pr\s+merge\s+(?:-{1,2}\S+\s+)*?(\d{1,7})\b/i.exec(command);
1856
+ const gh = /\bgh\s+pr\s+merge\s+(?:-{1,2}\S+\s+)*?(\d{1,10})\b/i.exec(command);
1736
1857
  if (gh) {
1737
- return Number.parseInt(gh[1], 10);
1858
+ return _boundedTarget(gh[1]);
1738
1859
  }
1739
- const api = /\/pulls\/(\d{1,7})\/merge\b/i.exec(command);
1740
- return api ? Number.parseInt(api[1], 10) : null;
1860
+ const api = /\/pulls\/(\d{1,10})\/merge\b/i.exec(command);
1861
+ return api ? _boundedTarget(api[1]) : null;
1862
+ }
1863
+ function _boundedTarget(digits) {
1864
+ const n = Number.parseInt(digits, 10);
1865
+ return Number.isSafeInteger(n) && n > 0 && n <= PR_NUMBER_MAX ? n : null;
1741
1866
  }
1742
1867
  function grantCovers(grants, op, target) {
1743
1868
  if (op !== "pr-merge" || target === null) {
@@ -1,6 +1,6 @@
1
1
  # Discovery — Deprecation Report
2
2
 
3
- - Generated: `2026-09-03T13:00:38Z`
3
+ - Generated: `2026-09-04T03:43:39Z`
4
4
  - Deprecated artefacts: **0**
5
5
 
6
6
  _None. Tree is clean._
@@ -7533,7 +7533,7 @@
7533
7533
  },
7534
7534
  {
7535
7535
  "category": "rule",
7536
- "checksum": "sha256:4b7bde90e07a74e274fc2c68fdd6afc5862549a8116553f207f907d3fdbe34c4",
7536
+ "checksum": "sha256:ce1cb5a8edb4d7795812ee40d79ad6d65b12d4115c5ad08d405088ceb182b96d",
7537
7537
  "install": {
7538
7538
  "default": true,
7539
7539
  "removable": false
@@ -8159,7 +8159,7 @@
8159
8159
  },
8160
8160
  {
8161
8161
  "category": "skill",
8162
- "checksum": "sha256:6c28aee3cab7bc6b89e66dcb3e64034d7a3722ab59508715b7fd58d8bc2d6c45",
8162
+ "checksum": "sha256:43e583f67648601be4b58d13b7e37a406a543adae9723d6aeeb0d977b4d5d32b",
8163
8163
  "install": {
8164
8164
  "default": true,
8165
8165
  "removable": false
@@ -10117,7 +10117,7 @@
10117
10117
  },
10118
10118
  {
10119
10119
  "category": "skill",
10120
- "checksum": "sha256:190b44d9a43e1ab3d556ed0ce5d3a728813762129487105c86dd5084eae24b54",
10120
+ "checksum": "sha256:67b216c8bbadb98f913d974c4b4577b65877b06b17c4c3a42e4ebabbf2c7ab30",
10121
10121
  "install": {
10122
10122
  "default": true,
10123
10123
  "removable": false
@@ -10601,7 +10601,7 @@
10601
10601
  },
10602
10602
  {
10603
10603
  "category": "skill",
10604
- "checksum": "sha256:a6fa1458478db10bda583b341b2d7bcb361187fb57e3df918109834d04fb5798",
10604
+ "checksum": "sha256:b5fbbb739c3aac24877c314bde4be904f9cd672613f51242ed97b21e84888330",
10605
10605
  "install": {
10606
10606
  "default": true,
10607
10607
  "removable": true
@@ -12983,7 +12983,7 @@
12983
12983
  },
12984
12984
  {
12985
12985
  "category": "skill",
12986
- "checksum": "sha256:b418af0901b1ca9696cca805079ffa5ff0bf730e9b877497417a8e9b32ca3765",
12986
+ "checksum": "sha256:ed5fd6e152267b152c1a8e0719c8cf9fe3303c4b1662a8eb1e78cb060d18948d",
12987
12987
  "install": {
12988
12988
  "default": false,
12989
12989
  "removable": true
@@ -14760,7 +14760,7 @@
14760
14760
  "workspaces": []
14761
14761
  }
14762
14762
  ],
14763
- "checksum": "sha256:9aca1f614f7add7d67778fa6a96e9d0f003607832be5cd432d07759474a8d08f",
14763
+ "checksum": "sha256:dd8fabe64f8d77c0d267127d1797192fba713fa8498e4b5883701c84fff20e6e",
14764
14764
  "deprecations": [
14765
14765
  {
14766
14766
  "key": "tier",
@@ -14909,7 +14909,7 @@
14909
14909
  "reason": "scaffold template for ticket-bundle tickets (ADR-101); carries no runtime frontmatter — emit-tickets fills it in per ticket"
14910
14910
  }
14911
14911
  ],
14912
- "generated_at": "2026-09-03T13:00:38Z",
14912
+ "generated_at": "2026-09-04T03:43:39Z",
14913
14913
  "packs": [
14914
14914
  {
14915
14915
  "artefact_count": 128,
@@ -1 +1 @@
1
- 05ba9a2538875c8dbca0017cbf440896be64d6f737bfca1f5047a6835b75a5ea discovery-manifest.json
1
+ 39bbab4136c262fec6b632f6019ca5269b010e6a49c660c6325014a2e72e304f discovery-manifest.json
@@ -1,6 +1,6 @@
1
1
  # Discovery Manifest — Summary
2
2
 
3
- - Generated: `2026-09-03T13:00:38Z`
3
+ - Generated: `2026-09-04T03:43:39Z`
4
4
  - Scanner: `de0a22b4ac4c`
5
5
  - Artefacts: **623**
6
6
  - Unassigned: **0**
@@ -1,6 +1,6 @@
1
1
  # Discovery — Dormancy Report
2
2
 
3
- - Generated: `2026-09-03T13:00:38Z`
3
+ - Generated: `2026-09-04T03:43:39Z`
4
4
  - Window: **6 months** without a commit
5
5
 
6
6
  > Dormancy triggers **review, never auto-deprecation**
@@ -1,6 +1,6 @@
1
1
  # Discovery — Orphan Report
2
2
 
3
- - Generated: `2026-09-03T13:00:38Z`
3
+ - Generated: `2026-09-04T03:43:39Z`
4
4
  - Orphan artefacts: **0**
5
5
 
6
6
  > An orphan is an artefact whose declared pack has no other members.
@@ -1,6 +1,6 @@
1
1
  {
2
- "checksum": "sha256:9aca1f614f7add7d67778fa6a96e9d0f003607832be5cd432d07759474a8d08f",
3
- "generated_at": "2026-09-03T13:00:38Z",
2
+ "checksum": "sha256:dd8fabe64f8d77c0d267127d1797192fba713fa8498e4b5883701c84fff20e6e",
3
+ "generated_at": "2026-09-04T03:43:39Z",
4
4
  "packs": [
5
5
  {
6
6
  "always_on": false,
@@ -1,6 +1,6 @@
1
1
  # Discovery — Trust Report
2
2
 
3
- - Generated: `2026-09-03T13:00:38Z`
3
+ - Generated: `2026-09-04T03:43:39Z`
4
4
  - Workspaces tracked: **10**
5
5
  - Human-review-required artefacts: **3**
6
6
 
@@ -1,6 +1,6 @@
1
1
  {
2
- "checksum": "sha256:9aca1f614f7add7d67778fa6a96e9d0f003607832be5cd432d07759474a8d08f",
3
- "generated_at": "2026-09-03T13:00:38Z",
2
+ "checksum": "sha256:dd8fabe64f8d77c0d267127d1797192fba713fa8498e4b5883701c84fff20e6e",
3
+ "generated_at": "2026-09-04T03:43:39Z",
4
4
  "scanner_version": "de0a22b4ac4c",
5
5
  "workspaces": [
6
6
  {