kushi-agents 3.4.2 → 3.12.1
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/README.md +33 -0
- package/package.json +15 -3
- package/plugin/agents/kushi.agent.md +155 -147
- package/plugin/instructions/ado-bootstrap-discovery.instructions.md +111 -0
- package/plugin/instructions/ado-engagement-tree.instructions.md +73 -0
- package/plugin/instructions/answer-from-evidence.instructions.md +1 -1
- package/plugin/instructions/auth-and-retry.instructions.md +51 -16
- package/plugin/instructions/azure-auth-patterns.instructions.md +13 -6
- package/plugin/instructions/bootstrap-status-format.instructions.md +113 -0
- package/plugin/instructions/capture-learnings.instructions.md +95 -0
- package/plugin/instructions/cleanup-on-resolution.instructions.md +69 -0
- package/plugin/instructions/crm-bootstrap-discovery.instructions.md +79 -0
- package/plugin/instructions/crm-internal-vs-confirmed.instructions.md +79 -0
- package/plugin/instructions/evidence-confidence-ladder.instructions.md +66 -0
- package/plugin/instructions/evidence-layout-canonical.instructions.md +115 -0
- package/plugin/instructions/evidence-thoroughness.instructions.md +82 -12
- package/plugin/instructions/full-view-gate.instructions.md +91 -0
- package/plugin/instructions/m365-id-registry.instructions.md +134 -0
- package/plugin/instructions/meetings-verbatim-required.instructions.md +176 -0
- package/plugin/instructions/run-reports.instructions.md +129 -0
- package/plugin/instructions/scope-boundaries.instructions.md +218 -0
- package/plugin/instructions/snapshot-vs-stream.instructions.md +2 -0
- package/plugin/instructions/update-ledger.instructions.md +132 -0
- package/plugin/instructions/verbatim-by-default.instructions.md +73 -0
- package/plugin/instructions/workiq-first.instructions.md +15 -31
- package/plugin/instructions/workiq-only.instructions.md +193 -0
- package/plugin/learnings/README.md +50 -0
- package/plugin/learnings/ado.md +45 -0
- package/plugin/learnings/crm.md +96 -0
- package/plugin/learnings/cross-cutting.md +36 -0
- package/plugin/learnings/email.md +33 -0
- package/plugin/learnings/meetings.md +30 -0
- package/plugin/learnings/misc.md +46 -0
- package/plugin/learnings/onenote.md +215 -0
- package/plugin/learnings/sharepoint.md +5 -0
- package/plugin/learnings/teams.md +5 -0
- package/plugin/plugin.json +22 -2
- package/plugin/prompts/apply-ado.prompt.md +14 -0
- package/plugin/prompts/propose-ado.prompt.md +12 -0
- package/plugin/reference-packs/fde/crm-field-manifest.md +165 -0
- package/plugin/skills/apply-ado-update/SKILL.md +125 -0
- package/plugin/skills/ask-project/SKILL.md +2 -0
- package/plugin/skills/bootstrap-project/SKILL.md +81 -3
- package/plugin/skills/propose-ado-update/SKILL.md +108 -0
- package/plugin/skills/pull-ado/SKILL.md +173 -23
- package/plugin/skills/pull-crm/SKILL.md +168 -15
- package/plugin/skills/pull-email/SKILL.md +139 -22
- package/plugin/skills/pull-meetings/SKILL.md +109 -25
- package/plugin/skills/pull-misc/README.md +84 -0
- package/plugin/skills/pull-misc/SKILL.md +257 -0
- package/plugin/skills/pull-misc/runner.mjs +280 -0
- package/plugin/skills/pull-onenote/README.md +90 -0
- package/plugin/skills/pull-onenote/SKILL.md +400 -51
- package/plugin/skills/pull-onenote/runner.mjs +356 -0
- package/plugin/skills/pull-onenote/scripts/recapture-section-url.mjs +295 -0
- package/plugin/skills/pull-onenote/write-snapshot.mjs +271 -0
- package/plugin/skills/pull-sharepoint/SKILL.md +44 -12
- package/plugin/skills/pull-teams/SKILL.md +40 -11
- package/plugin/skills/refresh-project/SKILL.md +33 -2
- package/plugin/skills/self-check/run.ps1 +186 -4
- package/plugin/templates/ado-update/discussion-comment.template.md +26 -0
- package/plugin/templates/ado-update/integrations-ado-writes.example.yml +49 -0
- package/plugin/templates/ado-update/proposed.template.md +78 -0
- package/plugin/templates/init/external-links.template.txt +30 -0
- package/plugin/templates/init/project-integrations.template.yml +57 -2
- package/plugin/templates/snapshot/meeting-verbatim.template.md +110 -0
- package/plugin/templates/snapshot/meetings-series-index.template.md +3 -1
- package/plugin/templates/snapshot/onenote-page.template.md +92 -23
- package/plugin/templates/weekly/meetings-stream.template.md +11 -6
|
@@ -67,7 +67,7 @@ Inventing, smoothing-over, or guessing is forbidden.
|
|
|
67
67
|
## Interplay with other doctrine
|
|
68
68
|
|
|
69
69
|
- **`citation-ledger.instructions.md`** — citation format authority. This doctrine adds the "per-assertion" rule.
|
|
70
|
-
- **`workiq-
|
|
70
|
+
- **`workiq-only.instructions.md`** — does NOT apply at answer time (read-only; the producer skills already enforced it during the pull).
|
|
71
71
|
- **`evidence-thoroughness.instructions.md`** — applies to producer skills only; `ask-project` consumes whatever depth the producers wrote.
|
|
72
72
|
- **`snapshot-vs-stream.instructions.md`** — `ask-project` reads both shapes; the load order above respects the snapshot/stream split.
|
|
73
73
|
- **`engagement-root-resolution.instructions.md`** — used by Step 1 (project resolution).
|
|
@@ -17,11 +17,11 @@ Before the first call to a given service in a run, run the matching pre-flight.
|
|
|
17
17
|
|
|
18
18
|
| Service | Pre-flight |
|
|
19
19
|
|---|---|
|
|
20
|
-
| WorkIQ | `Get-Command workiq -ErrorAction SilentlyContinue`. If missing → record `workiq-not-on-path`, fall back to
|
|
21
|
-
| Graph / `m365_*` |
|
|
20
|
+
| WorkIQ | `Get-Command workiq -ErrorAction SilentlyContinue`. If missing → record `workiq-not-on-path`, write evidence file pointing at `docs/getting-started/install-workiq.md`, STOP this source (do NOT fall back to Graph; in-scope M365 sources are WorkIQ-only per `workiq-only.instructions.md`). Then probe with a trivial `workiq ask -q "ping"`; if output contains `accept the End User License Agreement` → run `workiq accept-eula` once and continue. |
|
|
21
|
+
| Graph / `m365_*` | Used ONLY for: (a) CRM/ADO direct REST (out of WorkIQ scope), (b) the `m365_list_chat_messages` parallel structured-data dump in `pull-teams` / `pull-meetings`, and (c) the `m365_download_file` binary carve-out for `recording.mp4` and chat attachments in `pull-meetings`. For these cases only: call `m_m365_status`; if `signedIn != true` → record `m365-not-signed-in`, suggest `m_m365_sign_in` to user, skip the parallel dump (the WorkIQ artifact still stands). |
|
|
22
22
|
| CRM / Dataverse | `az account show`. If non-zero → suggest `az login --tenant 72f988bf-86f1-41af-91ab-2d7cd011db47`, skip CRM (per `az-auth-conditional`). |
|
|
23
23
|
| ADO | `az account show` AND tenant must be in allowed list (`72f988bf-86f1-41af-91ab-2d7cd011db47`). If wrong tenant → suggest re-login, skip ADO. |
|
|
24
|
-
| SharePoint (host-specific) |
|
|
24
|
+
| SharePoint (host-specific, CRM/ADO-adjacent only) | Used only when CRM/ADO REST needs to read a SharePoint-hosted attachment. For pull-sharepoint content extraction, this entire row is FORBIDDEN — use WorkIQ. |
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
@@ -83,25 +83,60 @@ The skill MUST set `last_status` based on errors:
|
|
|
83
83
|
|
|
84
84
|
## 5. Path-cascade contract (per source)
|
|
85
85
|
|
|
86
|
-
Each `pull-<source>` skill tries paths in order. On each failure, append `errors[]` entry, then try next path. If all paths fail, write evidence file with `❌ all paths failed` marker and the actionable next step.
|
|
86
|
+
Each `pull-<source>` skill tries paths in order. On each failure, append `errors[]` entry, then try the next path. If all paths fail, write evidence file with `❌ all paths failed` marker and the actionable next step.
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|---|---|---|---|---|
|
|
90
|
-
| email | WorkIQ | `m365_search_emails` / `m365_list_emails` | Graph REST | ask user |
|
|
91
|
-
| teams | WorkIQ | `m365_list_chat_messages` (per chat ID) | Graph REST | ask user |
|
|
92
|
-
| onenote | **WorkIQ-only per workspace policy** (see `workiq-first.instructions.md`) | n/a — Graph for OneNote is unreliable; do not attempt | n/a | ask user to paste page text |
|
|
93
|
-
| sharepoint | WorkIQ | `m365_list_files` / `m365_search_files` | Graph `shares/{id}/driveItem` (for share links) or SharePoint REST `_api/web/GetFileByServerRelativePath` (for direct paths) | ask user |
|
|
94
|
-
| meetings | WorkIQ (transcript) | `m365_get_transcript` | reconstruct from meeting chat (`m365_list_chat_messages`) + Copilot recap message | ask user |
|
|
95
|
-
| crm | WorkIQ | Dataverse REST | n/a | ask user |
|
|
96
|
-
| ado | WorkIQ | ADO REST WIQL | n/a | ask user |
|
|
88
|
+
**M365 sources are WorkIQ-only** per `workiq-only.instructions.md` (v3.11.0+). Graph REST and `m365_*` host tools are FORBIDDEN as fallbacks for in-scope M365 sources. The single allowed exception is `m365_list_chat_messages` as a parallel structured-data dump (`chat-messages.json`) — NEVER a substitute for the WorkIQ pull.
|
|
97
89
|
|
|
98
|
-
|
|
90
|
+
| Source | Path 1 | Path 2 | Path 3 |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| email | WorkIQ (enumerate + per-message body) | doubled-strict WorkIQ retry | ask user to paste |
|
|
93
|
+
| teams | WorkIQ (thread reproduction) + `m365_list_chat_messages` in parallel (structured-data dump only) | doubled-strict WorkIQ retry | ask user to paste |
|
|
94
|
+
| onenote | Playwright browser-scrape (PRIMARY, see `pull-onenote/SKILL.md`) | WorkIQ tier-C per-page | ask user to paste |
|
|
95
|
+
| sharepoint | WorkIQ (content extraction) + local synced folder walk in parallel (metadata; filesystem, not API) | doubled-strict WorkIQ retry | ask user to paste |
|
|
96
|
+
| meetings | WorkIQ transcript pull + `m365_list_chat_messages` in parallel + WorkIQ recap + WorkIQ recording-URL discovery | doubled-strict WorkIQ retry | ask user to paste |
|
|
97
|
+
| calendar discovery | WorkIQ meeting-discovery prompt | doubled-strict WorkIQ retry | ask user to paste joinUrl |
|
|
98
|
+
| crm (NOT in workiq scope) | Dataverse REST per `pull-crm/SKILL.md` | WorkIQ supplementary | ask user |
|
|
99
|
+
| ado (NOT in workiq scope) | ADO REST WIQL per `pull-ado/SKILL.md` | WorkIQ supplementary | ask user |
|
|
100
|
+
|
|
101
|
+
**Forbidden** as cascade steps for M365 sources (in-scope): `m365_get_email`, `m365_search_emails`, `m365_list_emails`, `m365_list_mail_folders`, `m365_list_chats`, `m365_search_chats`, `m365_get_transcript`, `m365_get_facilitator_notes`, `m365_list_meetings`, `m365_list_events`, `m365_search_files`, `m365_list_files`, `m365_get_recent_files`, `m365_download_file` (for content; binary downloads in pull-meetings for `recording.mp4`/attachments are a separate carve-out), and any Graph REST URL for those resources. Calling them is a defect; coverage.md must NOT show them in the attempt trail.
|
|
102
|
+
|
|
103
|
+
For meetings specifically: **transcripts may legitimately not exist** (transcription was off). If WorkIQ returns "not found" / empty after the doubled-strict retry → reconstruct from the meeting chat (`m365_list_chat_messages` for the meeting's chat ID — already captured during teams pull, allowed as structured-data dump). This is "evidence reconstructed from chat" not "no evidence". Record `transcripts-not-generated` in errors with `action_taken: reconstructed-from-chat`.
|
|
99
104
|
|
|
100
105
|
---
|
|
101
106
|
|
|
102
|
-
## 6. Try-again UX
|
|
107
|
+
## 6. Try-again UX + auto-retry from run-log (HARD RULE v3.12.0+)
|
|
108
|
+
|
|
109
|
+
**Failure surface is part of the run summary, every time.** Every orchestrator verb (`bootstrap`, `refresh`, `aggregate`) MUST:
|
|
110
|
+
|
|
111
|
+
1. **At the end of the run**, read `Evidence/run-log.yml` and compute a per-source summary table including `last_status`, `signature`, `items_pulled`, and `next_step`.
|
|
112
|
+
2. **If ANY source has `last_status` in {`failed`, `partial`, `skipped-auth`} with a retryable `signature`**, auto-surface a retry prompt to the user with two options:
|
|
113
|
+
- **Retry now (failed sources only)** — re-invokes only the per-source pull-* skills whose run-log entries are retryable, scoped to the same boundary and window as the original run.
|
|
114
|
+
- **Skip retry (continue)** — leaves the failure markers in place. Run-log keeps the error for next-run pickup.
|
|
115
|
+
|
|
116
|
+
The prompt MUST display the per-source signatures so the user can decide. Example:
|
|
117
|
+
```
|
|
118
|
+
⚠️ 2 sources failed last run:
|
|
119
|
+
- email partial signature: workiq-empty-after-retry items: 0
|
|
120
|
+
- meetings failed signature: transient-server-error items: 0
|
|
121
|
+
Retry these now? [Y/n]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
3. **Retryable signatures** (auto-prompt to retry):
|
|
125
|
+
- `tool-error`, `transient-server-error`, `workiq-empty-after-retry` (first-time only), `workiq-eula-required` (after `workiq accept-eula`), `token-401-after-reacquire` (after re-auth), `auth-required` (OneNote, after re-bootstrap), `notebook-unavailable` (OneNote, after user re-syncs).
|
|
126
|
+
|
|
127
|
+
4. **Non-retryable signatures** (do NOT auto-retry — surface guidance only):
|
|
128
|
+
- `transcripts-not-generated` (recording was off; need user action to re-record),
|
|
129
|
+
- `no-match` (boundary too narrow; need user to widen `integrations.yml boundaries:`),
|
|
130
|
+
- `accessDenied` / `403` (need permission grant from owner),
|
|
131
|
+
- `Sorry, I can't` (copyright/blocked content),
|
|
132
|
+
- `workiq-not-on-path` (need install/repair WorkIQ),
|
|
133
|
+
- `<source>-boundary-missing` (need user to populate integrations.yml).
|
|
134
|
+
|
|
135
|
+
5. **"try again" / "refresh failed" / "retry errors" user message** → read `Evidence/run-log.yml errors[]`, retry only the entries where `signature` is in the retryable set. Surface a one-line skip notice per non-retryable entry with the actionable next step. Do NOT silently skip — the user must see what was skipped and why.
|
|
136
|
+
|
|
137
|
+
6. **Auto-retry budget**: a single source can be auto-retried at most **once per orchestrator run**. If the retried call fails again with a retryable signature, the orchestrator MUST stop retrying that source for the run and surface the failure for user follow-up (do not loop).
|
|
103
138
|
|
|
104
|
-
|
|
139
|
+
This codifies the user-asked feature: "is there a way to check the failure report and redo if failed automatically or at least ask about what failed and redo?" — yes, every run ends with the retry prompt; non-retryable failures surface actionable guidance instead.
|
|
105
140
|
|
|
106
141
|
---
|
|
107
142
|
|
|
@@ -9,7 +9,7 @@ This file is the **concrete** companion to:
|
|
|
9
9
|
|
|
10
10
|
- `auth-and-retry.instructions.md` — pre-flight, token reuse, retry, error-log schema, path cascade.
|
|
11
11
|
- `az-auth-conditional.instructions.md` — when to require `az login` (only if CRM/ADO are configured).
|
|
12
|
-
- `workiq-
|
|
12
|
+
- `workiq-only.instructions.md` — WorkIQ is the ONLY path for in-scope M365 sources (supersedes the deprecated `workiq-first.instructions.md`).
|
|
13
13
|
|
|
14
14
|
Where those files describe **what** to do, this one shows **how** in PowerShell. Skill authors implementing `pull-crm`, `pull-ado`, `pull-sharepoint`, and any other external-service caller MUST follow the patterns here. Silent 401 loops and "no evidence found" misreports almost always come from skipping one of these.
|
|
15
15
|
|
|
@@ -99,18 +99,25 @@ A raw browser-facing SharePoint URL is often the **wrong endpoint** for bearer-t
|
|
|
99
99
|
- **For direct file paths** under `/personal/.../Documents/...` → prefer SharePoint REST `_api/web/GetFileByServerRelativePath(...)` on the exact host.
|
|
100
100
|
- If the canonical API then returns `403 accessDenied` or SharePoint `UnauthorizedAccessException`, treat it as a **real permission / sharing problem** — do not chase it as a token-host mismatch. Record `errors[]` with `signature: blocked-host-or-permissions-401` per `auth-and-retry.instructions.md §4`.
|
|
101
101
|
|
|
102
|
-
### 2.4 Microsoft Graph /
|
|
102
|
+
### 2.4 Microsoft Graph / `m365_*` proxies — narrow carve-outs ONLY
|
|
103
103
|
|
|
104
|
-
**Do not use Microsoft Graph for OneNote
|
|
104
|
+
**Do not use Microsoft Graph or `m365_*` host tools for in-scope M365 sources** (Email / Teams human-readable threads / OneNote bodies / SharePoint content / meeting transcripts / calendar discovery). Per `workiq-only.instructions.md` (v3.11.0+), these are WorkIQ-only. Graph / `m365_*` have a near-100% failure rate in this workspace and pollute the coverage trail.
|
|
105
|
+
|
|
106
|
+
The ONLY allowed Graph / `m365_*` calls inside kushi pull-* skills are:
|
|
107
|
+
|
|
108
|
+
1. **`m365_list_chat_messages(chatId)`** — parallel structured-data dump in `pull-teams` and `pull-meetings`. Writes `chat-messages.json`. Runs in parallel with the WorkIQ human-readable thread pull; NEVER a substitute. If it fails, the WorkIQ artifact still stands and the JSON dump is skipped.
|
|
109
|
+
2. **`m365_download_file(itemId)`** for **binary media only** in `pull-meetings`: `recording.mp4` (when a SharePoint Stream URL is found and size < 200MB) and chat `attachments/<original-name>`. WorkIQ does not return binaries, so this carve-out is required for media survival.
|
|
110
|
+
3. **CRM / ADO** — direct REST via Azure CLI tokens (sections 2.1 and 2.2 of this file). Out of WorkIQ scope.
|
|
105
111
|
|
|
106
112
|
```powershell
|
|
107
113
|
if (-not (Get-Command workiq -ErrorAction SilentlyContinue)) {
|
|
108
|
-
throw "workiq CLI not found on PATH.
|
|
114
|
+
throw "workiq CLI not found on PATH. M365 source queries cannot proceed. See: https://gim-home.github.io/kushi/getting-started/install-workiq/"
|
|
109
115
|
}
|
|
110
|
-
# Prefer
|
|
116
|
+
# Prefer the canonical WorkIQ prompts codified in workiq-only.instructions.md.
|
|
117
|
+
# Do NOT improvise. Do NOT fall back to m365_* for in-scope sources.
|
|
111
118
|
```
|
|
112
119
|
|
|
113
|
-
For
|
|
120
|
+
For the allowed carve-outs (`m365_list_chat_messages`, `m365_download_file` for binaries): no `az` token is needed — these go through the Clawpilot M365 proxy authenticated via `m_m365_status` / `m_m365_sign_in`.
|
|
114
121
|
|
|
115
122
|
---
|
|
116
123
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**"
|
|
3
|
+
excludeAgent: "code-review"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Bootstrap Status Artifact — Format Contract
|
|
7
|
+
|
|
8
|
+
When `bootstrap-project` (or any full refresh / retry workflow) finishes a project run, it MUST write `<project>/bootstrap-status.md` using the format below. This file is the **fast orientation artifact** for the project — what was bootstrapped, what durable context now exists, what stage the engagement is in, what gaps remain. It is NOT a transcript of the run.
|
|
9
|
+
|
|
10
|
+
## Required section order
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
# Bootstrap Status
|
|
14
|
+
|
|
15
|
+
- Bootstrap Date: YYYY-MM-DD HH:MM TZ
|
|
16
|
+
- Project: <name>
|
|
17
|
+
- Customer Hint: <token used to resolve>
|
|
18
|
+
- Mode: bootstrap | refresh | retry | force
|
|
19
|
+
- Lookback Window: <days>
|
|
20
|
+
|
|
21
|
+
## Preflight Checks
|
|
22
|
+
|
|
23
|
+
| Check | Status | Notes |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `.project-evidence/ado/config.yml` filled | resolved \| blocked-auth \| missing | ... |
|
|
26
|
+
| `.project-evidence/crm/config.yml` filled | ... | ... |
|
|
27
|
+
| `<project>/integrations.yml` boundaries present | ... | ... |
|
|
28
|
+
| `az` CLI tenant matches | cli-available \| blocked-auth | ... |
|
|
29
|
+
|
|
30
|
+
## Context Artifact Status
|
|
31
|
+
|
|
32
|
+
| Artifact | Status | Notes |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `crm/snapshot/<entity>/<id>.md` | populated \| unsynced \| degraded \| partial-template | <annotation count> |
|
|
35
|
+
| `ado/snapshot/engagement-<id>.md` | populated \| ado-not-complete | <tree size> |
|
|
36
|
+
| `ado/snapshot/items/*.md` | populated \| skipped \| ado-not-complete | <N items> |
|
|
37
|
+
| `onenote/snapshot/<section>/*.md` | populated \| degraded | <pages enumerated/failed> |
|
|
38
|
+
| `email/_index/<week>_message-index.md` | populated \| degraded-list-only \| throttled-tooManyRequests | <N enumerated> |
|
|
39
|
+
| `email/stream/<week>_email-stream.md` | populated \| degraded-list-only | <N threads> |
|
|
40
|
+
| `teams/...` | ... | ... |
|
|
41
|
+
|
|
42
|
+
## Current Bootstrap Outcome
|
|
43
|
+
|
|
44
|
+
- One-line current state per source.
|
|
45
|
+
- CRM stage: <plain-language interpretation of statuscode> (`internal-only` per `evidence-confidence-ladder`).
|
|
46
|
+
- ADO linkage: pinned engagement <id> | pending pick from N candidates | `ado-not-complete`.
|
|
47
|
+
- Notable gaps: ...
|
|
48
|
+
|
|
49
|
+
## Access Limitations
|
|
50
|
+
|
|
51
|
+
| System | Status | Reason | Workaround |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| ADO | resolved | — | — |
|
|
54
|
+
| CRM | blocked-auth | tenant mismatch | `az login --tenant <id>` |
|
|
55
|
+
| Email | throttled-tooManyRequests | WorkIQ rate-limited | retry next refresh |
|
|
56
|
+
|
|
57
|
+
## Bootstrap Status
|
|
58
|
+
|
|
59
|
+
ONE final line, normalized:
|
|
60
|
+
- `bootstrap-complete`
|
|
61
|
+
- `bootstrap-complete-with-coverage-gaps`
|
|
62
|
+
- `bootstrap-blocked — <primary reason>`
|
|
63
|
+
- `refresh-complete`
|
|
64
|
+
- `refresh-complete-with-coverage-gaps`
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Normalized status vocabulary
|
|
68
|
+
|
|
69
|
+
Use these exact strings everywhere (table cells, run-log, narrative):
|
|
70
|
+
|
|
71
|
+
- `resolved` — check passed
|
|
72
|
+
- `cli-available` — required CLI is installed and authenticated
|
|
73
|
+
- `blocked-auth` — auth missing/failed
|
|
74
|
+
- `partial-template` — file exists but only template scaffolding written
|
|
75
|
+
- `unsynced` — file does not contain real data yet
|
|
76
|
+
- `populated` — file contains real fetched data
|
|
77
|
+
- `degraded` / `degraded-list-only` — partial fetch (e.g. email body-unavailable for some messages)
|
|
78
|
+
- `throttled-tooManyRequests` — source rate-limited
|
|
79
|
+
- `ado-not-complete` — engagement record not found yet OR ADO linkage missing
|
|
80
|
+
- `completed-with-coverage-gaps` — final outcome with explicit gaps recorded
|
|
81
|
+
|
|
82
|
+
## Sections to AVOID in bootstrap-status
|
|
83
|
+
|
|
84
|
+
Do NOT keep these in `bootstrap-status.md` (they belong elsewhere or become stale):
|
|
85
|
+
|
|
86
|
+
- `Fallback Inputs Used` → run-log only
|
|
87
|
+
- `Evidence & Current Context` → State files
|
|
88
|
+
- `FDE Fitness Assessment` → State/00_overview.md
|
|
89
|
+
- `Source Coverage` → already covered by Access Limitations
|
|
90
|
+
- `Recommended Actions` → State/05_action-items.md or Open Questions/
|
|
91
|
+
- long historical retry logs → run-log only
|
|
92
|
+
|
|
93
|
+
## Stable-summary test
|
|
94
|
+
|
|
95
|
+
When deciding whether a detail belongs in `bootstrap-status.md`, ask: **"Does this help a future reader understand the current durable project state?"** If it's mainly describing how this one run unfolded, push it to `update-status.md` (per-run history) or the run-log instead.
|
|
96
|
+
|
|
97
|
+
## ADO-not-complete note
|
|
98
|
+
|
|
99
|
+
When a bootstrap cannot resolve the ADO Engagement WI, include in `## Current Bootstrap Outcome`:
|
|
100
|
+
|
|
101
|
+
> ADO context sync pending: engagement record not found yet; bootstrap is usable with CRM/transcript context and should be revisited after ADO engagement creation or when the candidate WI is pinned to `integrations.yml#ado.engagement_id`.
|
|
102
|
+
|
|
103
|
+
And reflect `ado-not-complete` in the relevant Context Artifact Status rows.
|
|
104
|
+
|
|
105
|
+
## Relationship to other artifacts
|
|
106
|
+
|
|
107
|
+
- Detailed CRM content → `crm-context/record-profile.md` + `crm/snapshot/`
|
|
108
|
+
- Detailed ADO tree → `ado/snapshot/tree.md` + per-item files
|
|
109
|
+
- Detailed transcripts → `meeting-transcripts/index.md`
|
|
110
|
+
- Per-run history → `update-status.md` (project-local)
|
|
111
|
+
- Cross-source synthesis → `State/`
|
|
112
|
+
|
|
113
|
+
`bootstrap-status.md` summarizes; it never duplicates these artifacts.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**"
|
|
3
|
+
description: "Capture-learnings loop — every fix, quirk, or workaround discovered mid-run must be written back into doctrine in the same turn it is learned."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Capture-learnings loop (HARD RULE)
|
|
7
|
+
|
|
8
|
+
Every kushi skill is a learning agent. When the agent discovers a new fact, fixes a bug, hits an API quirk, or finds a workaround — that lesson MUST be persisted back to doctrine **in the same run, before the skill exits**. Otherwise the next run repeats the same mistake.
|
|
9
|
+
|
|
10
|
+
This is the difference between a skilled engineer (writes the runbook entry as soon as they finish the fix) and an amateur (fixes it in their head and forgets next month).
|
|
11
|
+
|
|
12
|
+
## What counts as a "learning"
|
|
13
|
+
|
|
14
|
+
Capture all of these:
|
|
15
|
+
|
|
16
|
+
- **API quirks** — undocumented limits (`$top` max, mandatory headers, navigation properties that don't exist on custom entities), required preview API versions, encoding gotchas.
|
|
17
|
+
- **Auth fixes** — tenant IDs, audience strings, env overrides per project.
|
|
18
|
+
- **Schema surprises** — fields that don't exist where you'd expect, entity-set name plurals, custom-field naming conventions.
|
|
19
|
+
- **Resolution misses** — "the title-substring probe missed this project because…", "the default folder fast-path didn't apply here because…".
|
|
20
|
+
- **Workarounds** — pagination switch from one endpoint to another, separate filtered query instead of `$expand`, fallback ordering changes.
|
|
21
|
+
- **User pushback** — any time the user corrects scope, identity, or interpretation, that correction is doctrine.
|
|
22
|
+
|
|
23
|
+
Don't capture: one-off transient errors (network blip, expired token), or things already in the doctrine you just didn't read.
|
|
24
|
+
|
|
25
|
+
## Where learnings live
|
|
26
|
+
|
|
27
|
+
| File | Purpose |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `<KUSHI_ROOT>/plugin/learnings/<source>.md` | Per-source register: `ado.md`, `crm.md`, `email.md`, `teams.md`, `onenote.md`, `sharepoint.md`, `meetings.md`. Owned by the matching `pull-<source>` skill. |
|
|
30
|
+
| `<KUSHI_ROOT>/plugin/learnings/cross-cutting.md` | Lessons that span multiple sources (auth, encoding, host-tool quirks). |
|
|
31
|
+
| `<KUSHI_ROOT>/plugin/learnings/README.md` | Index + how-to-add-an-entry. |
|
|
32
|
+
|
|
33
|
+
## Entry format (one per learning)
|
|
34
|
+
|
|
35
|
+
```markdown
|
|
36
|
+
### YYYY-MM-DD — short title
|
|
37
|
+
|
|
38
|
+
**Symptom**: what broke or what was confusing (one sentence, verbatim error if applicable).
|
|
39
|
+
|
|
40
|
+
**Root cause**: why it happened.
|
|
41
|
+
|
|
42
|
+
**Fix / workaround**: the exact thing that worked (code snippet or 1–2 sentences).
|
|
43
|
+
|
|
44
|
+
**Doctrine impact**: which SKILL.md, instructions file, or template was updated in the same commit. Link by relative path. If "none yet — register only", say so explicitly and open a TODO.
|
|
45
|
+
|
|
46
|
+
**Discovered during**: project name + skill that hit it (e.g. `HCA / pull-crm`).
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Newest entry on top. Never delete — only mark superseded with a one-liner.
|
|
50
|
+
|
|
51
|
+
## When the loop runs (every skill, every time)
|
|
52
|
+
|
|
53
|
+
### Preflight (start of run)
|
|
54
|
+
1. Read `plugin/learnings/<source>.md` for the skill being run.
|
|
55
|
+
2. Apply known workarounds without re-discovering them. If a learning says "use `$top=200` not `$top=500`", use it.
|
|
56
|
+
|
|
57
|
+
### Mid-run (the moment a fix lands)
|
|
58
|
+
1. Stop. Don't move on yet.
|
|
59
|
+
2. Append a new entry to the appropriate `learnings/<source>.md` (or `cross-cutting.md`).
|
|
60
|
+
3. If the fix changes how the skill should always behave, also edit the relevant SKILL.md or instructions file in the same edit batch.
|
|
61
|
+
4. Then resume.
|
|
62
|
+
|
|
63
|
+
### Postflight (end of run)
|
|
64
|
+
1. If any learnings were appended, the run summary MUST list them with file path + entry title.
|
|
65
|
+
2. If a doctrine file was updated, the run summary MUST mention the version bump or commit pending.
|
|
66
|
+
|
|
67
|
+
## Doctrine vs register: when to upgrade
|
|
68
|
+
|
|
69
|
+
A `learnings/<source>.md` entry is **the proven workaround**. If the same learning hits twice (same project re-run, or a different project), promote it from register to first-class doctrine:
|
|
70
|
+
|
|
71
|
+
- Move the rule into the matching SKILL.md or a focused `*.instructions.md`.
|
|
72
|
+
- Leave a one-liner in the register: `→ promoted to plugin/instructions/<file>.md on YYYY-MM-DD`.
|
|
73
|
+
|
|
74
|
+
Don't pre-promote — wait for the second sighting. Otherwise the SKILL.md balloons with one-off fixes.
|
|
75
|
+
|
|
76
|
+
## Self-check enforcement
|
|
77
|
+
|
|
78
|
+
`plugin/skills/self-check/run.ps1` deep-mode rule **D7** verifies:
|
|
79
|
+
- `plugin/learnings/` exists with `README.md` + at least the per-source files for `pull-*` skills.
|
|
80
|
+
- Each `pull-*` SKILL.md references this instruction file (`capture-learnings.instructions.md`) by relative path in its frontmatter or body.
|
|
81
|
+
- Each `learnings/<source>.md` has the standard entry format header.
|
|
82
|
+
|
|
83
|
+
A missing register file or unreferenced skill is a hard fail.
|
|
84
|
+
|
|
85
|
+
## Why this matters
|
|
86
|
+
|
|
87
|
+
Without this loop:
|
|
88
|
+
- Same Dataverse `$expand=Annotations` 500 hits us every quarter.
|
|
89
|
+
- Same `$top=500` ADO updates 400-error gets re-discovered every refresh.
|
|
90
|
+
- Same per-project env override (iscrm vs microsoftit) gets re-debugged from scratch.
|
|
91
|
+
|
|
92
|
+
With it:
|
|
93
|
+
- The agent gets smarter every run.
|
|
94
|
+
- The next contributor reads `learnings/crm.md` once and skips a half-day of debugging.
|
|
95
|
+
- Doctrine stays small (only proven, recurring rules) and the register catches everything else.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**"
|
|
3
|
+
description: "Cleanup-on-resolution rule — when a probe resolves a real ID/match, prune the stale 'no-match' / 'probe-trail' notes left by previous failed attempts. Don't accumulate audit cruft next to a resolved fact."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cleanup-on-resolution (HARD RULE)
|
|
7
|
+
|
|
8
|
+
When a `pull-*` or `bootstrap-project` skill resolves a previously-unknown ID, folder, section, or record (e.g. ADO engagement WI, CRM record, OneNote section, email folder, Teams chat) — the skill MUST prune the stale "didn't find it" notes left by earlier failed attempts in the **same turn** the success lands.
|
|
9
|
+
|
|
10
|
+
## Why
|
|
11
|
+
|
|
12
|
+
Without cleanup, every project's `integrations.yml`, `m365-mutable.json`, run-log, and `bootstrap-status.md` slowly accumulate:
|
|
13
|
+
|
|
14
|
+
- `last_discovery_result: 'no-match'` next to a now-resolved ID
|
|
15
|
+
- A list of probe attempts ("tried query X — 0 hits", "tried query Y — TF51005") next to the proven-correct query
|
|
16
|
+
- "❌ ado-not-complete" status notes next to a now-resolved engagement WI
|
|
17
|
+
- "⚠️ folder hint missing — root-fallback used" warnings next to a now-pinned `emailContext.folder`
|
|
18
|
+
|
|
19
|
+
The audit trail becomes noise. The user can't tell what's the current state vs what's historic failure.
|
|
20
|
+
|
|
21
|
+
## What to clean (per surface)
|
|
22
|
+
|
|
23
|
+
When a resolution succeeds, in the same turn, prune:
|
|
24
|
+
|
|
25
|
+
### `<project>/integrations.yml`
|
|
26
|
+
- Replace `<source>.last_discovery_result: 'no-match'` (or `'partial'`, `'ambiguous'`) with `'resolved'`.
|
|
27
|
+
- Remove any `<source>.probe_attempts` / `<source>.probe_history` arrays — those were debugging breadcrumbs, not configuration.
|
|
28
|
+
- Remove inline comments like `# TODO: find this`, `# could not resolve as of YYYY-MM-DD`.
|
|
29
|
+
- Keep `pinned_on` + `pinned_by` (those are durable provenance).
|
|
30
|
+
|
|
31
|
+
### `<engagement-root>/.project-evidence/m365/m365-mutable.json`
|
|
32
|
+
- Remove entries under `m365Mutable.unresolved.<project>.<source>` if the same key was just resolved into `m365Mutable.knownSections.<project>.<source>`.
|
|
33
|
+
- Replace any `confidence: 'low'` entry with the new `confidence: 'high'` entry on resolution; do not keep both.
|
|
34
|
+
|
|
35
|
+
### `<engagement-root>/<project>/Evidence/run-log.yml`
|
|
36
|
+
- Update `sources.<src>.coverage_state` from `degraded-list-only` / `unresolved` / `throttled-tooManyRequests` to the new healthy state on the run that succeeded.
|
|
37
|
+
- Keep historical run entries in `runs:` (those are durable history) — but the current `sources.<src>` summary block must reflect TODAY's resolved state, not last run's failure.
|
|
38
|
+
|
|
39
|
+
### `<project>/bootstrap-status.md`
|
|
40
|
+
- Per the bootstrap-status format contract, status tables show CURRENT durable state. When a resolution fixes a previously-blocked check, update the matching row in `## Preflight Checks` / `## Context Artifact Status` / `## Access Limitations` to `resolved` / `populated` / `cli-available` and remove the previous "blocked" row (don't keep both).
|
|
41
|
+
- Specifically: when an ADO engagement is resolved, change `ado-not-complete` to `resolved` AND delete the `## Current Bootstrap Outcome` note that said `ADO context sync pending: engagement record not found yet`.
|
|
42
|
+
|
|
43
|
+
## What to KEEP
|
|
44
|
+
|
|
45
|
+
Cleanup-on-resolution is about pruning **stale state**, not history. The following are durable and never pruned:
|
|
46
|
+
|
|
47
|
+
- `runs:` array in `run-log.yml` — full run history (timestamp, mode, outcome).
|
|
48
|
+
- Per-user `refresh-reports/<timestamp>_<mode>.md` files — per-run reports per `run-reports.instructions.md`.
|
|
49
|
+
- `learnings/<source>.md` entries — register entries persist; they document the fix, not the failure.
|
|
50
|
+
- `pinned_on` + `pinned_by` audit fields on resolved IDs.
|
|
51
|
+
- Coverage Notes inside evidence files for runs where the boundary truly was empty.
|
|
52
|
+
|
|
53
|
+
## When NOT to clean
|
|
54
|
+
|
|
55
|
+
If the user explicitly pinned a `last_discovery_result: 'no-match'` themselves (they said "this project genuinely has no CRM record, stop probing") — leave it. The skill should detect explicit user-set state and not auto-clean.
|
|
56
|
+
|
|
57
|
+
Heuristic: if `<key>.pinned_by` matches the current user alias and the entry is older than 1 day, treat it as user-authoritative. If it was written by the skill itself in a previous run, it's prune-eligible.
|
|
58
|
+
|
|
59
|
+
## Self-check enforcement
|
|
60
|
+
|
|
61
|
+
`plugin/skills/self-check/run.ps1` deep-mode rule **D9** (added v3.7.6):
|
|
62
|
+
- Warns if `<project>/integrations.yml` has both a resolved ID (`<source>.engagement_id` / `record_id` / `section_id`) AND a stale `<source>.last_discovery_result: 'no-match'`. That combination is impossible after cleanup.
|
|
63
|
+
- Warns if `bootstrap-status.md` shows `ado-not-complete` while `integrations.yml` has `ado.engagement_id` populated.
|
|
64
|
+
|
|
65
|
+
A flagged file is a doctrine miss to be fixed in the next run, not a hard fail.
|
|
66
|
+
|
|
67
|
+
## Apply across all pull-* skills
|
|
68
|
+
|
|
69
|
+
Every `pull-<source>` skill's "Mutable hints to upsert" section MUST also reference this instruction file by relative path. The cleanup is part of the upsert, not a separate phase.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/skills/bootstrap-project/**, **/skills/pull-crm/**, **/skills/refresh-project/**"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# CRM bootstrap discovery — HARD rule (kushi v3.11.0+)
|
|
6
|
+
|
|
7
|
+
## The defect this rule exists to prevent
|
|
8
|
+
|
|
9
|
+
Bootstrap runs that wrote `boundaries.crm.disabled: true` after a single shallow probe (e.g. WorkIQ-only, or no live Dataverse REST call at all) — when in fact a live `contains(new_title, '<token>')` query would have resolved the record instantly. The result: pull-crm is then never dispatched on subsequent refreshes, the project Evidence/crm/ folder stays empty, and the CRM record drifts unsynced. Discovered 2026-05-18 on the John Deere bootstrap — FE-2026-001791 was missed because the title-first REST probe was never issued.
|
|
10
|
+
|
|
11
|
+
## The rule
|
|
12
|
+
|
|
13
|
+
Before `bootstrap-project` (or `refresh-project` on first CRM pull) is allowed to write `boundaries.crm.disabled: true`, the FULL 4-step Dataverse REST resolution sequence from `plugin/skills/pull-crm/SKILL.md#resolution-order-when-crmrecordid-is-unset` MUST be attempted with live tokens against the configured `iscrm.crm.dynamics.com` (or equivalent) endpoint. `disabled: true` is ONLY legitimate when:
|
|
14
|
+
|
|
15
|
+
1. **Steps 1–4 all returned 0 results** (logged with the exact OData URLs attempted, counts, and timestamps), AND
|
|
16
|
+
2. **Step 5 (ask user)** was actually presented to the user and the user confirmed there is no CRM record, OR the user is unreachable and the project owner explicitly opted to defer.
|
|
17
|
+
|
|
18
|
+
Any other path that writes `disabled: true` is a defect. The correct fallback for "couldn't reach Dataverse" or "auth failed" is to leave the boundary empty (NOT `disabled: true`) with `reason: 'crm-auth-unavailable-YYYY-MM-DD'` so the next run retries.
|
|
19
|
+
|
|
20
|
+
## Required execution at bootstrap time
|
|
21
|
+
|
|
22
|
+
```powershell
|
|
23
|
+
# 1. Acquire Dataverse token (per pull-crm Step Auth)
|
|
24
|
+
$config = Get-Content "<engagement-root>/.project-evidence/crm/config.yml" | ConvertFrom-Yaml
|
|
25
|
+
$token = (az account get-access-token --tenant $config.tenant_id --resource $config.base_url --query accessToken -o tsv --only-show-errors).Trim()
|
|
26
|
+
$headers = @{
|
|
27
|
+
Authorization = "Bearer $token"
|
|
28
|
+
Accept = 'application/json'
|
|
29
|
+
'OData-Version' = '4.0'
|
|
30
|
+
'OData-MaxVersion' = '4.0'
|
|
31
|
+
Prefer = 'odata.include-annotations="OData.Community.Display.V1.FormattedValue"'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# 2. Step 1 — Title-first (REQUIRED)
|
|
35
|
+
$url = "$($config.base_url)/api/data/v9.2/$($config.entity.entitySetName)?`$select=$($config.entity.primary_id_attribute),$($config.entity.primary_name_attribute),$($config.entity.request_id_attribute),statecode,statuscode,createdon,modifiedon,_new_customer_value&`$filter=contains($($config.entity.primary_name_attribute),'<token>')&`$top=20"
|
|
36
|
+
# If results >= 1 → present candidates, persist chosen record_id, STOP.
|
|
37
|
+
|
|
38
|
+
# 3. Step 2 — Account(s) fallback (REQUIRED if Step 1 returns 0)
|
|
39
|
+
# Resolve customer in accounts entity, then for EACH matching account query engagement records.
|
|
40
|
+
# Multiple Deere-style accounts (e.g. JOHN DEERE, DEERE COMPANY, JOHN DEERE COASTRUCTION) MUST all be tried.
|
|
41
|
+
|
|
42
|
+
# 4. Step 3 — Wide-text fallback (REQUIRED if Step 2 returns 0)
|
|
43
|
+
# contains() on new_businessscenariotechnicalblocker, new_engagedwith, new_engagementobjectives.
|
|
44
|
+
|
|
45
|
+
# 5. Step 4 — Recent-slice client-rank (REQUIRED if Step 3 returns 0)
|
|
46
|
+
# Pull top 200 by modifiedon desc, rank client-side by token overlap.
|
|
47
|
+
|
|
48
|
+
# 6. Step 5 — Present top 5 to user; never auto-pick on multi-match.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Required logging
|
|
52
|
+
|
|
53
|
+
Every bootstrap (and first-refresh) CRM-discovery run MUST write the attempt trail to `<project>/Evidence/<alias>/refresh-reports/<ts>_bootstrap.md` under a `## CRM resolution attempts` section, including:
|
|
54
|
+
|
|
55
|
+
| Step | Query | Result count | Outcome |
|
|
56
|
+
|---|---|---|---|
|
|
57
|
+
| 1 | `contains(new_title,'<token>')` | N | resolved / 0-results |
|
|
58
|
+
| 2 | accounts `contains(name,'<token>')` → FE per account | N1+N2+… | resolved / 0-results |
|
|
59
|
+
| 3 | `contains(new_businessscenariotechnicalblocker,'<token>')` etc | N | resolved / 0-results |
|
|
60
|
+
| 4 | recent-slice top 200 client-rank | N | top match score / 0-results |
|
|
61
|
+
| 5 | user presented top 5 candidates | yes/no | picked / declined / deferred |
|
|
62
|
+
|
|
63
|
+
This is non-negotiable. The trail is the audit that justifies whichever value lands in `boundaries.crm` (`record_ids: [...]` OR empty-with-reason OR `disabled: true`).
|
|
64
|
+
|
|
65
|
+
## Anti-patterns
|
|
66
|
+
|
|
67
|
+
1. **Setting `boundaries.crm.disabled: true` without trying live Dataverse REST.** Defect — pull-crm will never run again.
|
|
68
|
+
2. **Trying only WorkIQ for CRM resolution.** WorkIQ summarizes and may miss records; REST is the canonical path.
|
|
69
|
+
3. **Filtering by `statecode` during candidate search.** Hides closed / withdrawn / inactive records. See pull-crm Rule 5.
|
|
70
|
+
4. **Filtering by `new_companyname`.** Not a valid attribute on `new_frontierengineeringtriage`. Customer is `_new_customer_value` lookup. Always returns 0; looks like a permissions problem but is a schema problem.
|
|
71
|
+
5. **Stopping at first account match in Step 2.** Multiple accounts can share a token (Deere example). Iterate ALL.
|
|
72
|
+
6. **Silent fallback to "narrate CRM from email".** Forbidden by `scope-boundaries.instructions.md` Rule 3 and pull-crm hard-prereq.
|
|
73
|
+
|
|
74
|
+
## Cross-references
|
|
75
|
+
|
|
76
|
+
- `plugin/skills/pull-crm/SKILL.md#resolution-order-when-crmrecordid-is-unset` — the canonical 4-step sequence (now 5 with user-ask).
|
|
77
|
+
- `plugin/skills/bootstrap-project/SKILL.md` Step 4a — must dispatch this discovery before deciding `disabled`.
|
|
78
|
+
- `plugin/instructions/crm-internal-vs-confirmed.instructions.md` — once resolved, do not over-claim from CRM-only fields.
|
|
79
|
+
- `plugin/instructions/cleanup-on-resolution.instructions.md` — when this discovery resolves a record, prune stale `disabled: true` notes in the same turn.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# CRM field values vs confirmed facts — HARD rule (kushi v3.11.0+)
|
|
6
|
+
|
|
7
|
+
## The rule
|
|
8
|
+
|
|
9
|
+
**A CRM field value is NEVER automatically a confirmed fact.** A Dataverse field update records an internal decision; it does not prove the decision has been (a) communicated to the customer, (b) approved by deal desk / finance / legal, or (c) confirmed in a customer-facing transcript, note, email, or meeting artifact.
|
|
10
|
+
|
|
11
|
+
Adapted into kushi from Nova doctrine (see `fde-grounding.instructions.md > CRITICAL: CRM Field Values vs. Confirmed Facts`).
|
|
12
|
+
|
|
13
|
+
## Three states every CRM-sourced assertion must be classified into
|
|
14
|
+
|
|
15
|
+
1. **Internal-only decision** — team recorded a direction in a CRM field, but no customer-facing or external-stakeholder evidence confirms it. Status fields commonly look like this (e.g. `Not Yet Requested`, `Pending`, `Evaluating`, `TBD`). **DO NOT** write this as a settled fact in State/, FDE reports, or 6Q.
|
|
16
|
+
2. **Communicated to customer** — there exists a customer-facing transcript / note / email / meeting that postdates the CRM field update and references the decision. Still not final — typically still pending commercial / deal-desk approval.
|
|
17
|
+
3. **Confirmed with all stakeholders** — customer agreement + commercial approval + (where applicable) legal sign-off / signed artifact. Only this state is a settled fact and may be reported as such.
|
|
18
|
+
|
|
19
|
+
## How to apply recency precedence correctly to CRM fields
|
|
20
|
+
|
|
21
|
+
- The CRM field's `modifiedon` timestamp shows when the record was **updated**, NOT when the decision was **confirmed**.
|
|
22
|
+
- For every materially important CRM field claim (funding model, scope decision, owner, timeline gate, SI lane, ECIF / ESIF state), **cross-check against the latest customer-facing artifact** in `Evidence/<alias>/{meetings,email,onenote,teams,sharepoint}/` (use `meetings/verbatim/*/transcript.*` first per `meetings-verbatim-required.instructions.md`).
|
|
23
|
+
- If the latest customer-facing artifact predates the CRM field update AND no post-update customer-facing artifact confirms the decision → state explicitly as `internal decision recorded in CRM (<date>), pending customer/deal-desk confirmation (no confirming artifact found post-<date>)`.
|
|
24
|
+
- If a post-update artifact confirms → cite both (CRM date + confirming artifact + date).
|
|
25
|
+
- If a post-update artifact contradicts → mark `Conflicting evidence` and surface to `<project>/State/09_open-questions.md` (full profile) or `<project>/OPEN-QUESTIONS-DRAFT.md` (standard profile).
|
|
26
|
+
|
|
27
|
+
## Required output classification for State/, FDE reports, consolidation, ask-project answers
|
|
28
|
+
|
|
29
|
+
Every materially important CRM-sourced assertion in any kushi-generated artifact must be tagged as one of:
|
|
30
|
+
|
|
31
|
+
- `CRM-only` — internal signal, no external confirmation
|
|
32
|
+
- `Cross-verified` — confirmed by ≥ 1 non-CRM artifact (cite both)
|
|
33
|
+
- `Conflicting evidence` — non-CRM source contradicts CRM/form (cite both, list in open questions)
|
|
34
|
+
|
|
35
|
+
Acceptable non-CRM confirmation sources (in priority order per kushi precedence):
|
|
36
|
+
|
|
37
|
+
1. Meeting transcripts (`Evidence/<alias>/meetings/verbatim/*/transcript.*`)
|
|
38
|
+
2. Curated meeting stream notes (`Evidence/<alias>/meetings/stream/*.md`)
|
|
39
|
+
3. OneNote pages
|
|
40
|
+
4. ADO work-item discussions / comments
|
|
41
|
+
5. Emails (sender-domain matching customer)
|
|
42
|
+
6. Teams chats / channels
|
|
43
|
+
7. Approved shared artifacts (SharePoint / Loop / docs)
|
|
44
|
+
|
|
45
|
+
## Citation format
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
[source: CRM record FE-XXX field <field-name> · YYYY-MM-DD (internal-only)]
|
|
49
|
+
[source: CRM record FE-XXX field <field-name> · YYYY-MM-DD; cross-verified by Evidence/<alias>/meetings/verbatim/<dir>/transcript.vtt · YYYY-MM-DD]
|
|
50
|
+
[source: CRM record FE-XXX field <field-name> · YYYY-MM-DD; conflicts with Evidence/<alias>/email/snapshot/<file>.md · YYYY-MM-DD — see open questions]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Worked example
|
|
54
|
+
|
|
55
|
+
- 2026-03-20 transcript: team exploring funding options.
|
|
56
|
+
- 2026-03-23 transcript: alternative under discussion.
|
|
57
|
+
- 2026-03-26: CRM `new_ecifstatus` updated to `Not Yet Requested`.
|
|
58
|
+
- 2026-04-08 (today): no post-3/26 transcript confirms ECIF with customer or deal desk.
|
|
59
|
+
|
|
60
|
+
**Correct write-up:**
|
|
61
|
+
> Internal team decision favors ECIF (per CRM 3/26 update) but formal approval from deal desk and customer confirmation are still pending. Latest customer-facing transcript (3/23) predates the CRM decision; no post-decision confirmation found. `[source: CRM record FE-XXX field new_ecifstatus · 2026-03-26 (internal-only)]`
|
|
62
|
+
|
|
63
|
+
**Incorrect write-up (forbidden):**
|
|
64
|
+
> ECIF is the selected funding model. `[source: CRM record FE-XXX field new_ecifstatus · 2026-03-26]`
|
|
65
|
+
|
|
66
|
+
## Where this rule binds
|
|
67
|
+
|
|
68
|
+
- `skills/build-state/` — every CRM-sourced row in `State/01_decisions.md`, `State/05_action-items.md`, `State/06_risks-and-issues.md`, `State/07_timeline-and-milestones.md` must carry the 3-state tag and the cross-check citation chain.
|
|
69
|
+
- `skills/ask-project/` — answers grounded in CRM fields must explicitly distinguish internal-only vs cross-verified; never collapse into a bare assertion.
|
|
70
|
+
- `skills/fde-report/` / `skills/fde-triage/` — FDE Triage Living Reports follow this rule; the `Verification Evidence` section is required for any CRM-sourced gate.
|
|
71
|
+
- `skills/consolidate-evidence/` — when merging across contributors, conflicting CRM-vs-non-CRM evidence becomes a `Conflicting evidence` row, never silently resolved.
|
|
72
|
+
|
|
73
|
+
## Anti-patterns
|
|
74
|
+
|
|
75
|
+
1. Treating a CRM `Status` field as proof of customer commitment.
|
|
76
|
+
2. Reading CRM `modifiedon` as the decision-confirmation date.
|
|
77
|
+
3. Claiming "ECIF selected" / "Lane X chosen" / "Customer signed off" from CRM alone with no post-date customer-facing artifact.
|
|
78
|
+
4. Blending CRM internal decision and older customer-facing context into one averaged narrative without flagging the gap.
|
|
79
|
+
5. Dropping the `(internal-only)` tag in citations because it "reads cleaner".
|