kushi-agents 4.4.4 → 4.7.4

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 (94) hide show
  1. package/README.md +3 -0
  2. package/package.json +4 -4
  3. package/plugin/agents/kushi.agent.md +29 -15
  4. package/plugin/config/studios.json +37 -0
  5. package/plugin/config/studios.schema.json +45 -0
  6. package/plugin/instructions/auth-and-retry.instructions.md +268 -1
  7. package/plugin/instructions/engagement-root-resolution.instructions.md +5 -1
  8. package/plugin/instructions/evidence-thoroughness.instructions.md +103 -1
  9. package/plugin/instructions/fuzzy-disambiguation.instructions.md +97 -0
  10. package/plugin/instructions/identity-resolution.instructions.md +76 -0
  11. package/plugin/instructions/issue-recovery.instructions.md +58 -0
  12. package/plugin/instructions/kushi-config-root.instructions.md +66 -0
  13. package/plugin/instructions/loop-bootstrap-discovery.instructions.md +105 -0
  14. package/plugin/instructions/m365-id-registry.instructions.md +1 -1
  15. package/plugin/instructions/onedrive-pin-policy.instructions.md +132 -0
  16. package/plugin/instructions/per-source-verification-gate.instructions.md +193 -0
  17. package/plugin/instructions/sharepoint-to-onedrive-sync.instructions.md +116 -0
  18. package/plugin/instructions/status-color-rule.instructions.md +62 -0
  19. package/plugin/instructions/studio-registry.instructions.md +48 -0
  20. package/plugin/instructions/update-ledger.instructions.md +1 -1
  21. package/plugin/instructions/verbatim-by-default.instructions.md +1 -1
  22. package/plugin/instructions/vertex-emit.instructions.md +120 -0
  23. package/plugin/instructions/workiq-input-sanitization.instructions.md +43 -0
  24. package/plugin/instructions/workiq-onenote-query-shape.instructions.md +79 -0
  25. package/plugin/instructions/workiq-only.instructions.md +13 -7
  26. package/plugin/learnings/loop.md +11 -0
  27. package/plugin/learnings/onenote.md +27 -1
  28. package/plugin/lib/Get-KushiConfig.ps1 +22 -9
  29. package/plugin/lib/detect-vertex-repo.mjs +96 -0
  30. package/plugin/lib/render-vertex.mjs +249 -0
  31. package/plugin/lib/sanitize-workiq-input.mjs +72 -0
  32. package/plugin/lib/studio-registry.mjs +39 -0
  33. package/plugin/lib/vertex-validate.mjs +121 -0
  34. package/plugin/plugin.json +13 -6
  35. package/plugin/prompts/bootstrap.prompt.md +9 -7
  36. package/plugin/prompts/emit-vertex.prompt.md +33 -0
  37. package/plugin/prompts/setup.prompt.md +1 -1
  38. package/plugin/prompts/vertex-link.prompt.md +27 -0
  39. package/plugin/skills/aggregate-project/SKILL.md +24 -2
  40. package/plugin/skills/apply-ado-update/SKILL.md +9 -4
  41. package/plugin/skills/ask-project/SKILL.md +4 -0
  42. package/plugin/skills/bootstrap-project/SKILL.md +67 -37
  43. package/plugin/skills/consolidate-evidence/SKILL.md +5 -1
  44. package/plugin/skills/emit-vertex/README.md +37 -0
  45. package/plugin/skills/emit-vertex/SKILL.md +173 -0
  46. package/plugin/skills/intro/SKILL.md +2 -0
  47. package/plugin/skills/propose-ado-update/SKILL.md +8 -3
  48. package/plugin/skills/pull-ado/SKILL.md +11 -1
  49. package/plugin/skills/pull-crm/SKILL.md +12 -2
  50. package/plugin/skills/pull-email/SKILL.md +11 -1
  51. package/plugin/skills/pull-loop/README.md +64 -0
  52. package/plugin/skills/pull-loop/SKILL.md +180 -0
  53. package/plugin/skills/pull-loop/runner.mjs +261 -0
  54. package/plugin/skills/pull-loop/write-snapshot.mjs +181 -0
  55. package/plugin/skills/pull-meetings/SKILL.md +11 -1
  56. package/plugin/skills/pull-misc/README.md +4 -4
  57. package/plugin/skills/pull-misc/SKILL.md +18 -12
  58. package/plugin/skills/pull-onenote/SKILL.md +71 -19
  59. package/plugin/skills/pull-sharepoint/SKILL.md +11 -2
  60. package/plugin/skills/pull-teams/SKILL.md +11 -2
  61. package/plugin/skills/refresh-project/SKILL.md +38 -7
  62. package/plugin/skills/self-check/SKILL.md +14 -1
  63. package/plugin/skills/self-check/run.ps1 +442 -20
  64. package/plugin/skills/setup/SKILL.md +289 -86
  65. package/plugin/skills/vertex-link/SKILL.md +143 -0
  66. package/plugin/templates/init/m365-auth.template.json +10 -4
  67. package/plugin/templates/init/project-evidence.template.yml +4 -1
  68. package/plugin/templates/init/project-integrations.template.yml +5 -0
  69. package/plugin/templates/snapshot/ado-item.template.md +1 -1
  70. package/plugin/templates/snapshot/crm-record.template.md +1 -1
  71. package/plugin/templates/snapshot/meetings-series-index.template.md +1 -1
  72. package/plugin/templates/snapshot/onenote-page.template.md +1 -1
  73. package/plugin/templates/snapshot/sharepoint-file.template.md +1 -1
  74. package/plugin/templates/snapshot/sharepoint-tree.template.md +1 -1
  75. package/plugin/templates/snapshot/teams-roster.template.md +1 -1
  76. package/plugin/templates/weekly/ado-stream.template.md +1 -1
  77. package/plugin/templates/weekly/crm-stream.template.md +1 -1
  78. package/plugin/templates/weekly/email-stream.template.md +1 -1
  79. package/plugin/templates/weekly/meetings-stream.template.md +1 -1
  80. package/plugin/templates/weekly/onenote-stream.template.md +1 -1
  81. package/plugin/templates/weekly/sharepoint-stream.template.md +1 -1
  82. package/plugin/templates/weekly/teams-stream.template.md +1 -1
  83. package/src/check-workiq.mjs +48 -15
  84. package/src/config-loader.mjs +71 -13
  85. package/src/config-root-resolve.test.mjs +137 -0
  86. package/src/detect-vertex-repo.test.mjs +128 -0
  87. package/src/emit-vertex.e2e.test.mjs +308 -0
  88. package/src/forbidden-workiq-phrasings.test.mjs +111 -0
  89. package/src/sanitize-workiq-input.test.mjs +45 -0
  90. package/src/vertex-validate.test.mjs +142 -0
  91. package/plugin/instructions/az-auth-conditional.instructions.md +0 -39
  92. package/plugin/instructions/azure-auth-patterns.instructions.md +0 -233
  93. package/plugin/instructions/thoroughness-detector.instructions.md +0 -105
  94. package/plugin/instructions/workiq-first.instructions.md +0 -31
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ // pull-loop write-snapshot wrapper. Drives runner.mjs, writes canonical layout, upserts
3
+ // m365-mutable.json#knownSections.<project>.loop.workspaces[].loop_pages[], emits run report.
4
+ // Per pull-loop SKILL.md v1.0.0.
5
+
6
+ import { spawnSync } from 'node:child_process';
7
+ import fs from 'node:fs';
8
+ import path from 'node:path';
9
+ import process from 'node:process';
10
+
11
+ const args = Object.fromEntries(
12
+ process.argv.slice(2).reduce((acc, cur, idx, arr) => {
13
+ if (cur.startsWith('--')) {
14
+ const key = cur.replace(/^--/, '');
15
+ const next = arr[idx + 1];
16
+ acc.push([key, next && !next.startsWith('--') ? next : true]);
17
+ }
18
+ return acc;
19
+ }, [])
20
+ );
21
+
22
+ const PROJECT = args.project;
23
+ const WORKSPACE_URL = args['workspace-url'];
24
+ const ENG_ROOT = args['engagement-root'];
25
+ const ALIAS = args.alias;
26
+ const HEADLESS = !!args.headless;
27
+ const TITLES = args.titles || null;
28
+
29
+ if (!PROJECT || !WORKSPACE_URL || !ENG_ROOT || !ALIAS) {
30
+ console.error('Usage: --project <name> --workspace-url <url> --engagement-root <path> --alias <alias> [--headless] [--titles "a,b"]');
31
+ process.exit(2);
32
+ }
33
+
34
+ const slugify = (s) => String(s || '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 80) || 'untitled';
35
+ const isoStamp = () => new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
36
+
37
+ const runnerArgs = ['plugin/skills/pull-loop/runner.mjs', '--project', PROJECT, '--workspace-url', WORKSPACE_URL];
38
+ if (HEADLESS) runnerArgs.push('--headless');
39
+ if (TITLES) runnerArgs.push('--titles', TITLES);
40
+
41
+ const result = spawnSync(process.execPath, runnerArgs, { encoding: 'utf8' });
42
+ let payload;
43
+ try {
44
+ payload = JSON.parse(result.stdout || '{}');
45
+ } catch {
46
+ console.error('Runner did not return JSON. stderr:\n' + result.stderr);
47
+ process.exit(5);
48
+ }
49
+
50
+ const { pages = [], runStatus = 'workspace-unavailable', authRequiredCount = 0, preflight } = payload;
51
+
52
+ function workspaceSlugFromUrl(url) {
53
+ try {
54
+ const m = String(url).match(/\/loop\/p\/([^/]+)/i);
55
+ return slugify((m && m[1]) || 'workspace');
56
+ } catch { return 'workspace'; }
57
+ }
58
+ const wsSlug = workspaceSlugFromUrl(WORKSPACE_URL);
59
+
60
+ const snapDir = path.join(ENG_ROOT, PROJECT, 'Evidence', ALIAS, 'loop', 'snapshot', wsSlug);
61
+ fs.mkdirSync(snapDir, { recursive: true });
62
+
63
+ const workspaceMd = [
64
+ '---',
65
+ `source: loop`,
66
+ `project: ${PROJECT}`,
67
+ `workspace_url: ${WORKSPACE_URL}`,
68
+ `captured_at: ${new Date().toISOString()}`,
69
+ `evidence_source_kind: tree-only`,
70
+ '---',
71
+ '',
72
+ `# Loop workspace — ${wsSlug}`,
73
+ '',
74
+ `Source URL: ${WORKSPACE_URL}`,
75
+ `Captured: ${new Date().toISOString()}`,
76
+ `Pages enumerated: ${pages.length}`,
77
+ '',
78
+ '## Pages',
79
+ '',
80
+ ...pages.map(p => `- [${p.pageTitle || '(untitled)'}](${p.pageUrl}) — last_status: \`${p.last_status}\``),
81
+ ''
82
+ ].join('\n');
83
+ fs.writeFileSync(path.join(snapDir, '_workspace.md'), workspaceMd, 'utf8');
84
+
85
+ for (const p of pages) {
86
+ const pSlug = slugify(p.pageTitle || p.pageUrl);
87
+ const md = [
88
+ '---',
89
+ `source: loop`,
90
+ `project: ${PROJECT}`,
91
+ `workspace_url: ${WORKSPACE_URL}`,
92
+ `page_url: ${p.pageUrl}`,
93
+ `page_title: ${JSON.stringify(p.pageTitle || '')}`,
94
+ `captured_at: ${p.capturedAt || new Date().toISOString()}`,
95
+ `captured_via: ${p.captured_via || 'playwright'}`,
96
+ `last_status: ${p.last_status}`,
97
+ `evidence_source_kind: ${p.evidence_source_kind || (p.bodyLen > 0 ? 'page-body' : 'page-body-unavailable')}`,
98
+ '---',
99
+ '',
100
+ `# ${p.pageTitle || '(untitled)'}`,
101
+ '',
102
+ `Source: ${p.pageUrl}`,
103
+ '',
104
+ p.body || '_(body unavailable — see coverage notes)_',
105
+ ''
106
+ ].join('\n');
107
+ fs.writeFileSync(path.join(snapDir, `${pSlug}.md`), md, 'utf8');
108
+ }
109
+
110
+ function findMutableJson() {
111
+ const candidates = [
112
+ path.resolve('.kushi', 'config', 'user', 'm365-mutable.json'),
113
+ path.join(process.env.USERPROFILE || process.env.HOME || '', '.copilot', 'm-skills', 'kushi', 'config', 'user', 'm365-mutable.json')
114
+ ];
115
+ for (const c of candidates) {
116
+ if (fs.existsSync(c)) return c;
117
+ }
118
+ return null;
119
+ }
120
+
121
+ const mutPath = findMutableJson();
122
+ if (mutPath) {
123
+ try {
124
+ const mut = JSON.parse(fs.readFileSync(mutPath, 'utf8'));
125
+ mut.knownSections = mut.knownSections || {};
126
+ mut.knownSections[PROJECT] = mut.knownSections[PROJECT] || {};
127
+ mut.knownSections[PROJECT].loop = mut.knownSections[PROJECT].loop || { workspaces: [] };
128
+ let ws = mut.knownSections[PROJECT].loop.workspaces.find(w => w.workspaceUrl === WORKSPACE_URL);
129
+ if (!ws) {
130
+ ws = { workspaceUrl: WORKSPACE_URL, loop_pages: [] };
131
+ mut.knownSections[PROJECT].loop.workspaces.push(ws);
132
+ }
133
+ ws.loop_pages = ws.loop_pages || [];
134
+ for (const p of pages) {
135
+ let existing = ws.loop_pages.find(x => x.pageUrl === p.pageUrl);
136
+ if (!existing) {
137
+ existing = { pageUrl: p.pageUrl };
138
+ ws.loop_pages.push(existing);
139
+ }
140
+ existing.pageTitle = p.pageTitle || existing.pageTitle;
141
+ existing.last_status = p.last_status;
142
+ existing.last_captured_at = p.capturedAt;
143
+ existing.captured_via = p.captured_via;
144
+ }
145
+ fs.writeFileSync(mutPath, JSON.stringify(mut, null, 2), 'utf8');
146
+ } catch (e) {
147
+ console.error('Upsert m365-mutable.json failed:', e?.message || e);
148
+ }
149
+ }
150
+
151
+ const reportDir = path.join(ENG_ROOT, PROJECT, 'Evidence', ALIAS, 'refresh-reports');
152
+ fs.mkdirSync(reportDir, { recursive: true });
153
+ const reportPath = path.join(reportDir, `${isoStamp()}_loop.md`);
154
+ const okCount = pages.filter(p => p.last_status === 'ok').length;
155
+ const report = [
156
+ `# pull-loop run — ${PROJECT} — ${new Date().toISOString()}`,
157
+ '',
158
+ `Workspace: ${WORKSPACE_URL}`,
159
+ `Run status: \`${runStatus}\``,
160
+ `Pages: ${pages.length} (ok: ${okCount}; auth-required: ${authRequiredCount})`,
161
+ preflight ? `Preflight: ${JSON.stringify(preflight)}` : '',
162
+ '',
163
+ '## Per-page outcomes',
164
+ '',
165
+ '| Title | Status | Source-kind | Bytes |',
166
+ '|---|---|---|---:|',
167
+ ...pages.map(p => `| ${(p.pageTitle || '(untitled)').replace(/\|/g, '\\|')} | ${p.last_status} | ${p.evidence_source_kind} | ${p.bodyLen || 0} |`),
168
+ ''
169
+ ].filter(Boolean).join('\n');
170
+ fs.writeFileSync(reportPath, report, 'utf8');
171
+
172
+ console.log(JSON.stringify({
173
+ project: PROJECT,
174
+ workspaceUrl: WORKSPACE_URL,
175
+ snapshotDir: snapDir,
176
+ reportPath,
177
+ runStatus,
178
+ pagesWritten: pages.length,
179
+ okCount,
180
+ authRequiredCount
181
+ }, null, 2));
@@ -23,7 +23,7 @@ Pulls **meetings** evidence in three shapes per `snapshot-vs-stream.instructions
23
23
  - **stream/** — per-meeting curated blocks: attendees (req/opt/actual), agenda, **chronological transcript walk-through with verbatim quotes + timestamps**, decisions, actions, open questions, artifact links. Each block MUST cite the matching verbatim/ folder.
24
24
  - **verbatim/** (REQUIRED, NEW v2.2.0) — per-meeting subfolder `verbatim/<YYYY-MM-DD-HHMM>_<slug>/` containing the raw immutable capture: `captured-at.txt`, `chat-messages.json`, `chat-messages.md`, `transcript.vtt` or `transcript-source.md`, `recording-url.txt`, `recap-card.md`, `attachments/`, `coverage.md`. See `templates/snapshot/meeting-verbatim.template.md` for the contract.
25
25
 
26
- Auth + retry + error logging per `auth-and-retry.instructions.md`. WorkIQ-only per `workiq-only.instructions.md`. Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `thoroughness-detector.instructions.md`. Citations per `citation-ledger.instructions.md`.
26
+ Auth + retry + error logging per `auth-and-retry.instructions.md`. WorkIQ-only per `workiq-only.instructions.md`. Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `evidence-thoroughness.instructions.md`. Citations per `citation-ledger.instructions.md`.
27
27
 
28
28
  ## Inputs
29
29
 
@@ -159,3 +159,13 @@ After the pass:
159
159
  - A meeting has neither transcript NOR chat messages → write `verbatim/<dir>/coverage.md` documenting every failed path + write `❌ source-expired-or-unrecoverable` block in stream/, log error, continue.
160
160
  - All paths failed for ALL meetings in the window → mark source `failed`, write a single `❌ all paths failed` evidence file with actionable next step. Verbatim/ folders for each meeting still get created with captured-at.txt + coverage.md (the empty-folder audit trail is itself evidence).
161
161
  - A per-meeting block lacks a sibling `verbatim/<YYYY-MM-DD-HHMM>_<slug>/` directory → **defect** per `meetings-verbatim-required.instructions.md`. Re-run Half A immediately; do NOT ship the curated block alone.
162
+
163
+ ## References (v4.4.7)
164
+
165
+ - Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
166
+ - After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
167
+
168
+
169
+ ## Issue Recovery
170
+
171
+ When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
@@ -8,7 +8,7 @@ See `SKILL.md` for the full doctrine.
8
8
 
9
9
  ```pwsh
10
10
  # Install deps in the kushi repo
11
- cd C:\Usha\ISERepos\kushi
11
+ cd <kushi-repo-root>
12
12
  npm install playwright jsdom @mozilla/readability
13
13
  npx playwright install chromium
14
14
 
@@ -21,9 +21,9 @@ node plugin/skills/pull-onenote/runner.mjs --bootstrap
21
21
 
22
22
  ```pwsh
23
23
  node plugin/skills/pull-misc/runner.mjs `
24
- --project "ABN AMRO" `
25
- --links-file "C:\Users\ushak\OneDrive - Microsoft\ISE\Engagement Assets\ABN AMRO\external-links.txt" `
26
- --engagement-root "C:\Users\ushak\OneDrive - Microsoft\ISE\Engagement Assets" `
24
+ --project "<project>" `
25
+ --links-file "<engagement-root>/<project>/external-links.txt" `
26
+ --engagement-root "<engagement-root>" `
27
27
  --headless
28
28
  ```
29
29
 
@@ -12,7 +12,7 @@ description: "Pull miscellaneous evidence from a user-curated link list (<projec
12
12
  > - `capture-learnings.instructions.md` — every fix/discovery is logged to `plugin/learnings/misc.md`.
13
13
  > - `cleanup-on-resolution.instructions.md` — when a placeholder URL resolves, all stale unavailable-markers are upgraded in the same turn.
14
14
  > - `run-reports.instructions.md` — every refresh writes a per-user report under `Evidence/<alias>/refresh-reports/`.
15
- > - `thoroughness-detector.instructions.md` — the per-link retry registry IS this skill's thoroughness contract.
15
+ > - `evidence-thoroughness.instructions.md` — the per-link retry registry IS this skill's thoroughness contract.
16
16
 
17
17
  > **Canonical evidence layout** (HARD, kushi v3.12.1+): all artifacts produced by this skill MUST be written under `<project>/Evidence/<alias>/<source>/{snapshot,stream,...}/` — sibling folders under `<project>/` (e.g. `<project>/<source>-context/`, `<project>/<source>/`, `<project>/_Weekly Summaries/`) are FORBIDDEN. See `evidence-layout-canonical.instructions.md`.
18
18
 
@@ -48,7 +48,7 @@ Format:
48
48
  | `onenote` | pull-onenote | delegated |
49
49
  | `sharepoint` | pull-sharepoint | delegated |
50
50
  | `ado` | pull-ado | delegated |
51
- | `loop` **(new)** | pull-misc | browser (Playwright, OneNote profile) |
51
+ | `loop` | pull-loop | delegated (v4.6.0+ was inline-browser in v3.9.0–v4.5.x) |
52
52
  | `web` | pull-misc | http (fetch + readability) |
53
53
  | `confluence` | pull-misc | http (anonymous) — auth'd Confluence not yet supported |
54
54
  | `learn` | pull-misc | http |
@@ -105,15 +105,11 @@ For each project, the bootstrap step:
105
105
 
106
106
  The runner branches per `type`:
107
107
 
108
- ### B.1 `loop` — browser
108
+ ### B.1 `loop` — delegate (v4.6.0+)
109
109
 
110
- ```js
111
- // pages.goto(loopUrl); detect login redirect → auth-required.
112
- // Wait for primary canvas selector; for Loop, that's the Fluid container.
113
- // Read text via document.body.innerText after settle.
114
- ```
110
+ Skip fetch. Write registry entry with `captured_via: delegated`, `delegated_to: pull-loop`. The actual workspace/page capture happens in `pull-loop` (see `plugin/skills/pull-loop/SKILL.md`), which uses the canonical Loop boundary in `<project>/integrations.yml#boundaries.loop.workspace_ids[]` rather than free-text `external-links.txt` URLs.
115
111
 
116
- If login redirect detected: `last_status: auth-required`, `captured_via: browser`, exit early for this link.
112
+ If the Loop URL pasted into `external-links.txt` references a workspace NOT registered in `boundaries.loop.workspace_ids[]`, `pull-misc` records `last_status: unregistered-loop-workspace` and notes the URL in `<project>/OPEN-QUESTIONS-DRAFT.md` so the user can decide whether to register it via `@Kushi setup --reconfigure`.
117
113
 
118
114
  ### B.2 `web` / `confluence` / `learn` / `docs` / `github` / unknown — HTTP
119
115
 
@@ -134,9 +130,9 @@ If login redirect detected: `last_status: auth-required`, `captured_via: browser
134
130
  // Read text; if binary, mark last_status: skipped-binary (use a different pipeline if needed).
135
131
  ```
136
132
 
137
- ### B.4 `onenote` / `sharepoint` / `ado` — delegate
133
+ ### B.4 `onenote` / `sharepoint` / `ado` / `loop` — delegate
138
134
 
139
- Skip fetch. Write registry entry with `captured_via: delegated`, `delegated_to: pull-onenote|pull-sharepoint|pull-ado`. Per-skill captures already happen in their own pipelines.
135
+ Skip fetch. Write registry entry with `captured_via: delegated`, `delegated_to: pull-onenote|pull-sharepoint|pull-ado|pull-loop`. Per-skill captures already happen in their own pipelines.
140
136
 
141
137
  ## Per-link retry registry
142
138
 
@@ -151,7 +147,7 @@ Stored at `m365-mutable.json#knownSections.<projectKey>.misc_links[]`. Schema:
151
147
  "notes": "<as in external-links.txt>",
152
148
  "last_status": "captured | placeholder | auth-required | fetch-failed | skipped-binary | removed | not-yet-attempted | delegated",
153
149
  "captured_via": "browser | http | file | delegated",
154
- "delegated_to": "pull-onenote | pull-sharepoint | pull-ado", // only when captured_via=delegated
150
+ "delegated_to": "pull-onenote | pull-sharepoint | pull-ado | pull-loop", // only when captured_via=delegated
155
151
  "http_status": 200, // only for HTTP
156
152
  "content_type": "text/html", // only for HTTP
157
153
  "char_count": 12345,
@@ -255,3 +251,13 @@ Citations from misc evidence MUST follow:
255
251
  ```
256
252
 
257
253
  Example: `[source: misc/loop/ABN-Core-Team-Sync-2026-03-27 · 2026-05-14]`
254
+
255
+ ## References (v4.4.7)
256
+
257
+ - Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
258
+ - After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
259
+
260
+
261
+ ## Issue Recovery
262
+
263
+ When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
@@ -1,18 +1,21 @@
1
1
  ---
2
2
  name: "pull-onenote"
3
- version: "2.5.1"
4
- description: "Pull OneNote evidence (snapshot: full page bodies; stream: page-edit events). Browser-scrape (OneNote-for-Web via Playwright with persisted profile) is the PRIMARY capture path because it is the only mechanism that returns reliable, complete, verbatim page bodies in this tenant. WorkIQ remains the fallback when the browser auth profile expires (Conditional Access / MFA). Per-page retry registry persists both ID forms (browser webPageId + WorkIQ wdpartid) and tracks last_status across runs."
3
+ version: "2.7.0"
4
+ description: "Pull OneNote evidence (snapshot: full page bodies; stream: page-edit events). WorkIQ natural-language queries by display name are the PRIMARY capture path (per workiq-onenote-query-shape.instructions.md). Playwright browser-scrape is OPT-IN, RECOVERY-ONLY fallback never invoked unless the user has set m365Auth.oneNote.playwrightFallback: true AND the per-page retry registry shows persistent BODY-NOT-EXPOSED across multiple refreshes. Per-page retry registry persists both ID forms (browser webPageId + WorkIQ wdpartid) when both are observed; wdpartid alone is sufficient for WorkIQ-only operation."
5
5
  ---
6
6
 
7
7
  # Skill: pull-onenote
8
8
 
9
- > **v3.8.0 contracts**This skill operates under six HARD-rule doctrines:
9
+ > **v2.7.0 contract change (kushi v4.7.3, 2026-05-26):** Playwright is **demoted from PRIMARY to opt-in recovery-only fallback**. WorkIQ natural-language queries by display name are now the primary path. See `..\..\instructions\workiq-onenote-query-shape.instructions.md` for the working query shapes and the empirical record. The v3.8.0 pivot to Playwright-primary was driven by HCA body-retrieval rate (1/18 on 2026-05-14) but per-page retry registries + multi-refresh accumulation close that gap without forcing every contributor onto Edge + Conditional Access + bootstrap-profile complexity.
10
+
11
+ > **v2.7.0 contracts** — This skill operates under seven HARD-rule doctrines:
12
+ > - `workiq-onenote-query-shape.instructions.md` — **PRIMARY**. The only working WorkIQ phrasings for OneNote.
10
13
  > - `verbatim-by-default.instructions.md` — full bodies by default; no preview-grade pulls accepted.
11
- > - `m365-id-registry.instructions.md` — discover-once / consume-deterministically (section IDs, dual page-id schema).
14
+ > - `m365-id-registry.instructions.md` — discover-once / consume-deterministically (section IDs, dual page-id schema when both observed).
12
15
  > - `capture-learnings.instructions.md` — every fix/discovery is logged to `plugin/learnings/<source>.md`.
13
16
  > - `cleanup-on-resolution.instructions.md` — when a value resolves, all stale unavailable-markers are upgraded in the same turn.
14
17
  > - `run-reports.instructions.md` — every refresh writes a per-user report under `Evidence/<alias>/refresh-reports/`.
15
- > - `thoroughness-detector.instructions.md` — runtime detector + auto-retry + paste-prompt for any page where the primary path returns nothing or partial. The per-page retry registry IS this skill's thoroughness contract.
18
+ > - `evidence-thoroughness.instructions.md` — runtime detector + auto-retry + paste-prompt for any page where the primary path returns nothing or partial. The per-page retry registry IS this skill's thoroughness contract.
16
19
 
17
20
  > **Canonical evidence layout** (HARD, kushi v3.12.1+): all artifacts produced by this skill MUST be written under `<project>/Evidence/<alias>/<source>/{snapshot,stream,...}/` — sibling folders under `<project>/` (e.g. `<project>/<source>-context/`, `<project>/<source>/`, `<project>/_Weekly Summaries/`) are FORBIDDEN. See `evidence-layout-canonical.instructions.md`.
18
21
 
@@ -23,18 +26,56 @@ Pulls **onenote** evidence in two shapes per `snapshot-vs-stream.instructions.md
23
26
 
24
27
  ## Tools (in order)
25
28
 
26
- 1. **Playwright (browser-scrape, persisted profile)** — PRIMARY. Drives OneNote-for-Web to enumerate pages and read verbatim bodies via `#PageContentWrapper`. Profile lives at `~/.kushi/playwright-profile/onenote/` and is reused across runs. Implementation: `plugin/skills/pull-onenote/runner.mjs`.
27
- 2. **WorkIQ** — FALLBACK only. Used when the Playwright profile is auth-expired (`auth-required`) and for the stream/edit-event source. Always cite `m365-id-registry` doctrine when invoking; never use as primary for body retrieval (proven non-deterministic).
28
- 3. **Host (m365_*)** — not used (Graph `Notes.Read.All` denied admin consent in this tenant).
29
+ 1. **WorkIQ (natural-language by display name)** — **PRIMARY**. Use the approved query shapes from `workiq-onenote-query-shape.instructions.md`: one section per query, display names only, no enumeration verbs, no filter-syntax, no ID-lookup questions. Drives both section/page discovery and body retrieval. Pages that return `BODY-NOT-EXPOSED` are logged into `one_pages[].last_status` for retry on the next refresh — this multi-refresh accumulation is the thoroughness mechanism.
30
+ 2. **Playwright (browser-scrape, persisted profile)** — **OPT-IN RECOVERY-ONLY FALLBACK**. Only invoked when ALL of: (a) `m365Auth.oneNote.playwrightFallback: true`, (b) `one_pages[]` shows N pages with `last_status: BODY-NOT-EXPOSED` for 2 consecutive refreshes (N default 5, configurable via `m365-mutable.json#pullOnenote.playwrightThreshold`), (c) WorkIQ has been attempted in the current run. Profile lives at `~/.kushi/playwright-profile/onenote/`. Implementation: `plugin/skills/pull-onenote/runner.mjs`. See "Playwright fallback (optional)" section below.
31
+ 3. **Host (m365_*)** — not used (Graph `Notes.Read.All` denied admin consent in this tenant; also forbidden by kushi's WorkIQ-first doctrine).
29
32
 
30
- ## Canonical CLI invocations (do NOT re-derive — copy these exactly)
33
+ ## Canonical CLI invocations
31
34
 
32
- These are the empirically validated invocations as of kushi v3.11.3. The runner has surprising defaults (visible browser by default, 60s timeout, preflight required) that can derail a run. Use these recipes; do not improvise flags.
35
+ ### Primary path: WorkIQ natural-language (kushi v4.7.3+, default for all installs)
33
36
 
34
- ### Bootstrap (one-time per machine; ~3-5 days between runs as cookies expire)
37
+ Per `..\..\instructions\workiq-onenote-query-shape.instructions.md`. Resolves section IDs and pulls page bodies via display-name queries:
35
38
 
36
39
  ```pwsh
37
- cd C:\Usha\ISERepos\kushi
40
+ # Per-section discovery + page enumeration (also extracts wdpartid + wdsectionfileid from URL fragments):
41
+ workiq ask -q "In the OneNote notebook '<NOTEBOOK DISPLAY NAME>', show me the pages in the section named '<SECTION DISPLAY NAME>'. Return a flat table with: page title, last modified, web URL. No commentary. Do not truncate."
42
+
43
+ # Per-page body pull (one page at a time — narrow scope is mandatory):
44
+ workiq ask -q "Open the OneNote page titled '<PAGE TITLE>' in section '<SECTION>' of notebook '<NOTEBOOK>'. Return the verbatim page body, no summary, no truncation."
45
+
46
+ # Edit-event stream:
47
+ workiq ask -q "Show me OneNote page edits in section '<SECTION>' of notebook '<NOTEBOOK>' since <ISO-DATE>. For each edit: page title, edited by, edited at, brief change summary."
48
+ ```
49
+
50
+ Driver behavior:
51
+ 1. Run discovery query → parse `wdsectionfileid`, `wdpartid`, `sourcedoc` GUIDs out of the URL fragments in the response.
52
+ 2. Persist into `m365-mutable.json#knownSections.<projectKey>` per `m365-id-registry.instructions.md`. `webPageId` is left empty — it is only populated if/when Playwright fallback runs.
53
+ 3. For each enumerated page, run the body-pull query. Write snapshot files to the canonical layout. Populate `one_pages[].last_status`: `captured` on verbatim body return, `BODY-NOT-EXPOSED` on empty/partial, `workiq-degraded` on classified WorkIQ failure (per `fallback-status-reporting.instructions.md`).
54
+ 4. Pages with `BODY-NOT-EXPOSED` are surfaced in the run report and queued for retry on the next refresh. The per-page retry registry is the thoroughness mechanism — over multiple refreshes, transient non-determinism is absorbed.
55
+
56
+ ### Playwright fallback (OPT-IN, RECOVERY-ONLY — kushi v4.7.3+)
57
+
58
+ **Do NOT bootstrap a Playwright profile on a fresh install.** This path exists only as a recovery valve for contributors whose WorkIQ body-retrieval rate stays poor across multiple refreshes. Enable explicitly:
59
+
60
+ ```jsonc
61
+ // In <kushi-config-root>/user/m365-auth.json:
62
+ "oneNote": {
63
+ "enabled": true,
64
+ "defaultNotebookName": "...",
65
+ "playwrightFallback": true // OPT-IN — default false
66
+ }
67
+ ```
68
+
69
+ Once opted in, the driver auto-escalates to Playwright when `one_pages[]` shows ≥ N pages with `last_status: BODY-NOT-EXPOSED` for ≥ 2 consecutive refreshes (N default 5; configurable via `m365-mutable.json#pullOnenote.playwrightThreshold`). Until both thresholds are met, the driver MUST continue using WorkIQ. Never auto-bootstrap a profile — that is always a user-initiated action.
70
+
71
+ The Playwright invocations below remain valid (cookie surfaces, channel requirements, preflight three-way classification are all empirically unchanged) — they are simply the **fallback** path now, not the default.
72
+
73
+ These are the empirically validated invocations as of kushi v3.11.3 (still in force for the fallback path). The runner has surprising defaults (visible browser by default, 60s timeout, preflight required) that can derail a run. Use these recipes; do not improvise flags.
74
+
75
+ ### Bootstrap the Playwright profile (FALLBACK PATH ONLY — opt-in required)
76
+
77
+ ```pwsh
78
+ cd <kushi-repo-root>
38
79
  node plugin/skills/pull-onenote/runner.mjs --bootstrap
39
80
  ```
40
81
 
@@ -60,13 +101,13 @@ The bare `runner.mjs` emits JSON to stdout only. The driver (PowerShell or agent
60
101
  **HARD rule (kushi v3.11.5+):** drivers MUST call `write-snapshot.mjs`, which invokes the runner internally (child_process, no shell pipe), writes the snapshot in the canonical layout, upserts `m365Mutable.knownSections.<project>.one_pages[]`, and emits a run report. Never hand-write snapshot files from runner JSON.
61
102
 
62
103
  ```pwsh
63
- cd C:\Usha\ISERepos\kushi
104
+ cd <kushi-repo-root>
64
105
  $url = '<exact-section-url-from-m365-mutable.json#one_sectionWebUrl>'
65
106
  node plugin/skills/pull-onenote/write-snapshot.mjs `
66
107
  --section-url $url `
67
108
  --project "<project>" `
68
109
  --engagement-root "<engagement-root>" `
69
- --alias ushak
110
+ --alias <your-alias>
70
111
  ```
71
112
 
72
113
  Output structure (per `snapshot-vs-stream.instructions.md`):
@@ -130,13 +171,14 @@ await ctx.close();
130
171
 
131
172
  Run: `node plugin/skills/pull-onenote/diag.mjs "<section-url>"`. If you see `, Page. Selected.` but not `, page N of M, Page.` → single-page section, runner must be v3.11.3+.
132
173
 
133
- ## Empirical contract (what is true, validated 2026-05-13/14)
174
+ ## Empirical contract (what is true, validated 2026-05-13/14 + reframed 2026-05-26)
134
175
 
135
- These three facts are HARD-rule and supersede any earlier doctrine in this skill or in older learnings:
176
+ These facts are HARD-rule and supersede any earlier doctrine in this skill or in older learnings:
136
177
 
137
- 1. **Browser-scrape via OneNote-for-Web is the only reliable verbatim-body path.** Tested against HCA on 2026-05-14: 16 of 16 pages captured (~120KB), vs WorkIQ's 1 of 18 (~7KB) on the same section minutes earlier. Browser-scrape uses the same SharePoint-resident OneNote canvas the user sees, so what it returns IS the page.
138
- 2. **WorkIQ is non-deterministic for OneNote bodies and shall not be the primary path.** Same page returned a verbatim body and `BODY-NOT-EXPOSED` 6 minutes apart with no edits. WorkIQ is retained ONLY as the auth-degraded fallback (when the browser profile cannot complete sign-in) and as the source of stream/edit-event data.
139
- 3. **The OneNote-for-Web `pageid` and the WorkIQ `wdpartid` are different identifiers.** Both must be persisted per page (`webPageId` for browser navigation; `wdpartid` for WorkIQ correlation and stream events). Neither alone is sufficient.
178
+ 1. **WorkIQ natural-language by display name IS the primary, working path for OneNote.** Reframed v4.7.3 (2026-05-26) see `..\..\instructions\workiq-onenote-query-shape.instructions.md`. The only WorkIQ phrasings that work are: (a) narrow, single-section-by-display-name discovery queries; (b) single-page-by-title body pulls; (c) section-scoped edit-event stream queries. Forbidden: enumeration verbs, structured-field filter syntax, ID-lookup questions, broad "list my notebooks" probes. Those all empirically fail (WorkIQ punts to Graph Explorer or routes to summary mode).
179
+ 2. **WorkIQ body retrieval is non-deterministic, BUT per-page retry registries close the gap over multiple refreshes.** The v3.8.0 pivot to Playwright was driven by HCA's 1-of-18 body-retrieval rate on 2026-05-14. That rate is the snapshot of one refresh — the retry registry (`one_pages[].last_status`) is the durable mechanism that accumulates captures across refreshes. A page that returns `BODY-NOT-EXPOSED` today is retried tomorrow; over 3-5 refreshes the cumulative capture rate converges. This is acceptable for engagement evidence (which is time-windowed, not real-time). Playwright remains as the opt-in recovery valve for contributors who need faster convergence and have accepted the Edge + Conditional Access + bootstrap complexity.
180
+ 3. **The OneNote-for-Web `pageid` and the WorkIQ `wdpartid` are different identifiers.** Both should be persisted per page when both are observed (`webPageId` for browser navigation; `wdpartid` for WorkIQ correlation and stream events). For WorkIQ-only operation, `wdpartid` alone is sufficient — `webPageId` is only populated if/when Playwright fallback runs.
181
+ 4. **Browser-scrape via OneNote-for-Web returns higher-fidelity verbatim bodies when it works** — tested against HCA on 2026-05-14: 16 of 16 pages captured (~120KB) in one run. This is why Playwright remains as the opt-in fallback. It is NOT the default because: (a) it requires Edge + Conditional Access compliance — not all contributors have that; (b) it requires a per-machine bootstrap that expires every 3-5 days; (c) most engagements do not need real-time full-fidelity capture — multi-refresh WorkIQ converges adequately.
140
182
 
141
183
  ## Pre-flight
142
184
 
@@ -429,3 +471,13 @@ Every refresh writes `Evidence/<alias>/refresh-reports/<YYYY-MM-DD>-<HHMM>-oneno
429
471
  - Any short-suspect entries needing user verification
430
472
 
431
473
 
474
+
475
+ ## References (v4.4.7)
476
+
477
+ - Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
478
+ - After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
479
+
480
+
481
+ ## Issue Recovery
482
+
483
+ When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
@@ -21,7 +21,7 @@ Pulls **sharepoint** evidence in two shapes per `snapshot-vs-stream.instructions
21
21
  - **snapshot/** — tree.md (full folder tree) + files/<path>.md (key files with full extracted content)
22
22
  - **stream/** — file change events (created/modified/renamed/deleted) with author + size + brief content summary
23
23
 
24
- Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `thoroughness-detector.instructions.md`. Citations per `citation-ledger.instructions.md`. Side-by-side mutable hints written immediately on discovery per `side-by-side-config.instructions.md`.
24
+ Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `evidence-thoroughness.instructions.md`. Citations per `citation-ledger.instructions.md`. Side-by-side mutable hints written immediately on discovery per `side-by-side-config.instructions.md`.
25
25
 
26
26
  ## Inputs
27
27
 
@@ -114,4 +114,13 @@ Every snapshot file body starts with an **AI Narrative Summary (REQUIRED FIRST,
114
114
 
115
115
  - Hint missing AND fuzzy resolution returns 0 candidates → ask user once, persist answer to mutable, continue.
116
116
  - Multiple plausible candidates → ask user to pick, persist answer.
117
- - WorkIQ fails (after doubled-strict retry) AND user declines to paste → write evidence file with `❌ workiq-empty-after-retry` marker, log to run-log errors with `next_step: re-run after WorkIQ recovery or paste verbatim`, continue with rest of run. Do NOT fall through to Graph / `m365_*` — FORBIDDEN per workiq-only.
117
+ - WorkIQ fails (after doubled-strict retry) AND user declines to paste → write evidence file with `❌ workiq-empty-after-retry` marker, log to run-log errors with `next_step: re-run after WorkIQ recovery or paste verbatim`, continue with rest of run. Do NOT fall through to Graph / `m365_*` — FORBIDDEN per workiq-only.
118
+ ## References (v4.4.7)
119
+
120
+ - Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
121
+ - After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
122
+
123
+
124
+ ## Issue Recovery
125
+
126
+ When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
@@ -21,7 +21,7 @@ Pulls **teams** evidence in two shapes per `snapshot-vs-stream.instructions.md`:
21
21
  - **snapshot/** — chat roster + member list per chat the user is part of for this project
22
22
  - **stream/** — messages with full message-by-message reproduction — sender, timestamp, verbatim text, reactions, attachments, replies — grouped by thread
23
23
 
24
- Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `thoroughness-detector.instructions.md`. Citations per `citation-ledger.instructions.md`. Side-by-side mutable hints written immediately on discovery per `side-by-side-config.instructions.md`.
24
+ Thoroughness per `evidence-thoroughness.instructions.md`; runtime detector + auto-retry + paste-prompt per `evidence-thoroughness.instructions.md`. Citations per `citation-ledger.instructions.md`. Side-by-side mutable hints written immediately on discovery per `side-by-side-config.instructions.md`.
25
25
 
26
26
  ## Inputs
27
27
 
@@ -101,4 +101,13 @@ After successful pass:
101
101
 
102
102
  - Hint missing AND fuzzy resolution returns 0 candidates → ask user once, persist answer to mutable, continue.
103
103
  - Multiple plausible candidates → ask user to pick, persist answer.
104
- - WorkIQ fails (after doubled-strict retry) AND user declines to paste → write evidence file with `❌ workiq-empty-after-retry` marker, log to run-log errors with `next_step: re-run after WorkIQ recovery or paste verbatim`, continue with rest of run. Do NOT fall through to Graph / `m365_*` — FORBIDDEN per workiq-only.
104
+ - WorkIQ fails (after doubled-strict retry) AND user declines to paste → write evidence file with `❌ workiq-empty-after-retry` marker, log to run-log errors with `next_step: re-run after WorkIQ recovery or paste verbatim`, continue with rest of run. Do NOT fall through to Graph / `m365_*` — FORBIDDEN per workiq-only.
105
+ ## References (v4.4.7)
106
+
107
+ - Name → ID resolution follows ..\..\instructions\fuzzy-disambiguation.instructions.md (universal fuzzy contract).
108
+ - After this pull completes, the per-source verification gate runs: ..\..\instructions\per-source-verification-gate.instructions.md (retry once, then write FOLLOW-UPS.md).
109
+
110
+
111
+ ## Issue Recovery
112
+
113
+ When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: "refresh-project"
3
- version: "2.3.1"
3
+ version: "2.3.2"
4
4
  description: "Incremental refresh for an already-bootstrapped project. Reads run-log watermarks, pulls only what is new since last run per source, splits stream output by ISO week, replaces snapshots in place. Verbatim-by-default per `verbatim-by-default.instructions.md` — every enabled source MUST be dispatched, no silent skips. Writes per-user refresh report per `run-reports.instructions.md`. Cleans stale no-match notes on resolution per `cleanup-on-resolution.instructions.md`. Builds State/ only on `full` profile."
5
5
  ---
6
6
 
@@ -43,6 +43,7 @@ Profile is read from `kushi-install.json#profile` next to the agent file. Defaul
43
43
 
44
44
  ### Step 1 — Resolve project + read run-log
45
45
 
46
+ - **Sync-pending gate (v4.5.0):** before resolving, check `<workspace>/.kushi/config/user/project-evidence.yml#projects_root_status`. If `syncing` or `manual-sync-pending`, refuse: *"Engagement root sync still pending. Run `@Kushi setup --resume-sync` once OneDrive finishes."* Exit cleanly.
46
47
  - Fuzzy-match `<project>` per `engagement-root-resolution.instructions.md`.
47
48
  - Read `<engagement-root>/<project>/Evidence/run-log.yml`.
48
49
  - For each source, compute effective window:
@@ -86,10 +87,11 @@ Per-source pull skills (canonical order — refresh-project dispatches in this o
86
87
  2. `pull-teams`
87
88
  3. `pull-meetings`
88
89
  4. `pull-onenote`
89
- 5. `pull-sharepoint`
90
- 6. `pull-crm` (if enabled)
91
- 7. `pull-ado` (if enabled)
92
- 8. `pull-misc` (if `<project>/external-links.txt` exists)
90
+ 5. `pull-loop` (if enabled — boundary `boundaries.loop.workspace_ids[]` populated)
91
+ 6. `pull-sharepoint`
92
+ 7. `pull-crm` (if enabled)
93
+ 8. `pull-ado` (if enabled)
94
+ 9. `pull-misc` (if `<project>/external-links.txt` exists)
93
95
 
94
96
  Each `pull-*` skill is responsible for:
95
97
  - Snapshot pass (always re-fetch known entities).
@@ -97,6 +99,25 @@ Each `pull-*` skill is responsible for:
97
99
  - Updating `sources.<src>.watermark`, `sources.<src>.last_pulled`, `sources.<src>.item_count` in run-log.
98
100
  - Updating `weekly_files` index in run-log.
99
101
 
102
+ **Verification gate after each per-source dispatch (v4.4.8+, HARD):** Per `..\..\instructions\per-source-verification-gate.instructions.md`, immediately after each `pull-*` returns:
103
+
104
+ ```
105
+ gate = run_verification_gate(source, result)
106
+ if gate.status == "fail":
107
+ retry = dispatch(source, --window <same>, --retry)
108
+ gate2 = run_verification_gate(source, retry)
109
+ if gate2.status == "fail":
110
+ append_to_followups(<project>/FOLLOW-UPS.md, gate2) # 5-field shape (D19)
111
+ append_to_runlog(<project>/Evidence/run-log.yml,
112
+ source, status: "failed-gate",
113
+ gate_failures: gate2.failures,
114
+ process_audit: gate2.process_audit_failures)
115
+ append_to_tracking(gate2.process_audit_failures)
116
+ # do NOT abort the whole refresh — continue to next source
117
+ ```
118
+
119
+ Refresh is **never** aborted by a single source's gate failure. The gate's job is to surface — not to block.
120
+
100
121
  **pull-misc dispatch:** invoke as `node plugin/skills/pull-misc/runner.mjs --project <name> --links-file <engagement-root>/<project>/external-links.txt --engagement-root <engagement-root> --headless`. Parse the JSON output, write per-link snapshot files to `Evidence/<alias>/misc/snapshot/<safe-type>__<safe-title>.md`, and merge the `links[]` records into `m365-mutable.json#knownSections.<projectKey>.misc_links[]` (preserving prior `attempts`, bumping `last_attempt_at`).
101
122
 
102
123
  ### Step 3 — Consolidate (if multi-user)
@@ -112,9 +133,10 @@ If `standard` (or `core`) → **skip this step**. Note in the run summary: *"Sta
112
133
  ### Step 5 — Run summary
113
134
 
114
135
  Display:
115
- - Per-source table: items pulled, weeks affected, errors.
136
+ - Per-source table: items pulled, weeks affected, errors, **gate status** (pass / retried-pass / failed-followups-written).
116
137
  - Side-by-side mutable hints written this run (per `side-by-side-config.instructions.md`).
117
138
  - New Open Questions opened/resolved/staled.
139
+ - **Open follow-ups delta** — count of entries newly written to `<project>/FOLLOW-UPS.md` this run + count of entries auto-moved from Open → Resolved by `cleanup-on-resolution.instructions.md`.
118
140
 
119
141
  ## Watermark semantics
120
142
 
@@ -137,4 +159,13 @@ Re-running refresh with the same window is safe:
137
159
  - "update `<X>`"
138
160
  - "pull `<X>` since `<date>`"
139
161
  - "refresh `<X>` last `<N>` days"
140
- - "backfill `<X>` from `<from>` to `<to>`"
162
+ - "backfill `<X>` from `<from>` to `<to>`"
163
+ ## References (v4.4.7)
164
+
165
+ - Name → ID resolution (any source) follows `..\..\instructions\fuzzy-disambiguation.instructions.md`.
166
+ - After each per-source pull, run the gate per `..\..\instructions\per-source-verification-gate.instructions.md` (retry once → FOLLOW-UPS.md on failure).
167
+
168
+
169
+ ## Issue Recovery
170
+
171
+ When this skill exposes a reusable defect (auth pattern, doctrine gap, layout mismatch), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
@@ -46,7 +46,20 @@ Checks split into **core** (always run) and **deep** (opt-in).
46
46
  | D4 | Live install sync | if `~/.copilot/m-skills/kushi/` exists, its `SKILL.md` is byte-identical to `plugin/agents/kushi.agent.md` |
47
47
  | D5 | skills-metadata.json sync | if `~/.copilot/m-skills/skills-metadata.json` lists `kushi`, its description matches the live `SKILL.md` frontmatter |
48
48
  | D6 | Side-by-side rule cited | every SKILL.md that touches user config references `side-by-side-config.instructions.md` |
49
- | D7 | Live install manifest | if `~/.copilot/m-skills/kushi/kushi-install.json` exists, its skill list matches the resolved profile chain from `plugin.json` (no missing, no extras) |
49
+ | D15 | Legacy path regression | no `.project-evidence/{m365,crm,ado}` references outside CHANGELOG / learnings (v4.4.0+ moved per-user config to `<workspace>/.kushi/config/{user,shared}/`) |
50
+ | D16 | Cross-platform parity | every contributor-facing install/setup surface (setup/SKILL.md, install-workiq.md, check-workiq.mjs) addresses BOTH Windows (`winget` + `win32` branch) and macOS (`brew` + `darwin` branch). Also: self-check ships both `run.ps1` and `run.sh`. |
51
+ | D17 | Fuzzy disambiguation cited | every name→ID resolver (pull-onenote / pull-sharepoint / pull-teams / pull-crm / pull-ado / pull-email / ask-project / engagement-root-resolution) cites `fuzzy-disambiguation.instructions.md`. |
52
+ | D18 | Verification gate cited | every pull-* skill + bootstrap-project + refresh-project + aggregate-project cites `per-source-verification-gate.instructions.md`. |
53
+ | D19 | FOLLOW-UPS format | when `<project>/FOLLOW-UPS.md` exists, every `## Open follow-ups` entry has the 5 required fields (Gate failures / Next-time-do / Tracking / Run-log entry / Status). |
54
+ | D20 | README verbs coverage | every `plugin/prompts/<verb>.prompt.md` has a row in README's `## Verbs` table, and every row maps to a real prompt (or known alias). |
55
+ | D21 | Cross-platform .ps1 scripts | every `.ps1` in the repo runs on pwsh 7 cross-platform — Windows-only APIs (`Get-WmiObject`, `Win32_*`, COM, `HKLM:`) are gated with `if ($IsWindows)`. |
56
+ | D22 | Duplicate / overlap detection | flag pairs of `plugin/instructions/*.instructions.md` whose `description:` frontmatter has ≥ 60% word overlap — these are candidates for merge or scope-clarification. |
57
+ | D23 | Instructions map parity | every `plugin/instructions/*.instructions.md` is listed in `docs/reference/instructions-map.md`; every row in the map maps to a real file. |
58
+ | D24 | OneDrive pin policy applicable | when `projects_root` is INSIDE a OneDrive-managed path AND OneDrive is running, warn if own-alias `Evidence/<my-alias>/` exists but appears cloud-only (Windows: `attrib` shows `+U`; macOS: `xattr` lacks `com.microsoft.OneDrive.PinnedToDevice`). Surface as "may slow writes; re-run @Kushi setup --reconfigure to re-pin". Cited from `onedrive-pin-policy.instructions.md`. |
59
+ | D25 | Documentation coverage | every `plugin/instructions/*.instructions.md` is mentioned in EITHER `docs/reference/instructions-map.md` (mandatory via D23) AND at least one of: `CHANGELOG.md`, a `docs/concepts/*.md` doc, a `docs/reference/*.md` doc, or a `docs/how-to/*.md` doc. Catches new doctrines that landed without any user-facing prose. |
60
+ | D26 | Issue Recovery cite | every skill in the recovery-required set (`pull-*`, `aggregate-project`, `consolidate-evidence`, `bootstrap-project`, `refresh-project`, `apply-ado-update`, `propose-ado-update`) cites `issue-recovery.instructions.md` in its References section. Ensures the Issue Recovery Rule applies whenever an external service exposes a doctrine gap. |
61
+ | D27 | Personal-path leakage | no contributor-specific path / email / repo-local-path patterns (`OneDrive - Microsoft\ISE\Engagement Assets`, `C:\Users\<contributor>`, `<contributor>@microsoft.com`, etc.) appear in `plugin/`, `docs/getting-started/`, or `README.md`. Examples must use placeholders. Exemptions: `CHANGELOG.md`, `plugin/learnings/`, `plugin/reference-packs/`. |
62
+ | D28 | Predecessor-agent leakage | no current-doc file in `plugin/` or `docs/` references the historical predecessor agent by name. Use neutral language ('predecessor agent' / 'another internal agent'). Exemptions: `CHANGELOG.md` (historical commit notes), `plugin/learnings/`, `plugin/reference-packs/`, `docs/reference/instructions-map.md`. |
50
63
 
51
64
  ## Execution flow (agent path)
52
65