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.
Files changed (69) hide show
  1. package/README.md +33 -0
  2. package/package.json +15 -3
  3. package/plugin/agents/kushi.agent.md +155 -147
  4. package/plugin/instructions/ado-bootstrap-discovery.instructions.md +111 -0
  5. package/plugin/instructions/ado-engagement-tree.instructions.md +73 -0
  6. package/plugin/instructions/answer-from-evidence.instructions.md +1 -1
  7. package/plugin/instructions/auth-and-retry.instructions.md +51 -16
  8. package/plugin/instructions/azure-auth-patterns.instructions.md +13 -6
  9. package/plugin/instructions/bootstrap-status-format.instructions.md +113 -0
  10. package/plugin/instructions/capture-learnings.instructions.md +95 -0
  11. package/plugin/instructions/cleanup-on-resolution.instructions.md +69 -0
  12. package/plugin/instructions/crm-bootstrap-discovery.instructions.md +79 -0
  13. package/plugin/instructions/crm-internal-vs-confirmed.instructions.md +79 -0
  14. package/plugin/instructions/evidence-confidence-ladder.instructions.md +66 -0
  15. package/plugin/instructions/evidence-layout-canonical.instructions.md +115 -0
  16. package/plugin/instructions/evidence-thoroughness.instructions.md +82 -12
  17. package/plugin/instructions/full-view-gate.instructions.md +91 -0
  18. package/plugin/instructions/m365-id-registry.instructions.md +134 -0
  19. package/plugin/instructions/meetings-verbatim-required.instructions.md +176 -0
  20. package/plugin/instructions/run-reports.instructions.md +129 -0
  21. package/plugin/instructions/scope-boundaries.instructions.md +218 -0
  22. package/plugin/instructions/snapshot-vs-stream.instructions.md +2 -0
  23. package/plugin/instructions/update-ledger.instructions.md +132 -0
  24. package/plugin/instructions/verbatim-by-default.instructions.md +73 -0
  25. package/plugin/instructions/workiq-first.instructions.md +15 -31
  26. package/plugin/instructions/workiq-only.instructions.md +193 -0
  27. package/plugin/learnings/README.md +50 -0
  28. package/plugin/learnings/ado.md +45 -0
  29. package/plugin/learnings/crm.md +96 -0
  30. package/plugin/learnings/cross-cutting.md +36 -0
  31. package/plugin/learnings/email.md +33 -0
  32. package/plugin/learnings/meetings.md +30 -0
  33. package/plugin/learnings/misc.md +46 -0
  34. package/plugin/learnings/onenote.md +215 -0
  35. package/plugin/learnings/sharepoint.md +5 -0
  36. package/plugin/learnings/teams.md +5 -0
  37. package/plugin/plugin.json +22 -2
  38. package/plugin/prompts/apply-ado.prompt.md +14 -0
  39. package/plugin/prompts/propose-ado.prompt.md +12 -0
  40. package/plugin/reference-packs/fde/crm-field-manifest.md +165 -0
  41. package/plugin/skills/apply-ado-update/SKILL.md +125 -0
  42. package/plugin/skills/ask-project/SKILL.md +2 -0
  43. package/plugin/skills/bootstrap-project/SKILL.md +81 -3
  44. package/plugin/skills/propose-ado-update/SKILL.md +108 -0
  45. package/plugin/skills/pull-ado/SKILL.md +173 -23
  46. package/plugin/skills/pull-crm/SKILL.md +168 -15
  47. package/plugin/skills/pull-email/SKILL.md +139 -22
  48. package/plugin/skills/pull-meetings/SKILL.md +109 -25
  49. package/plugin/skills/pull-misc/README.md +84 -0
  50. package/plugin/skills/pull-misc/SKILL.md +257 -0
  51. package/plugin/skills/pull-misc/runner.mjs +280 -0
  52. package/plugin/skills/pull-onenote/README.md +90 -0
  53. package/plugin/skills/pull-onenote/SKILL.md +400 -51
  54. package/plugin/skills/pull-onenote/runner.mjs +356 -0
  55. package/plugin/skills/pull-onenote/scripts/recapture-section-url.mjs +295 -0
  56. package/plugin/skills/pull-onenote/write-snapshot.mjs +271 -0
  57. package/plugin/skills/pull-sharepoint/SKILL.md +44 -12
  58. package/plugin/skills/pull-teams/SKILL.md +40 -11
  59. package/plugin/skills/refresh-project/SKILL.md +33 -2
  60. package/plugin/skills/self-check/run.ps1 +186 -4
  61. package/plugin/templates/ado-update/discussion-comment.template.md +26 -0
  62. package/plugin/templates/ado-update/integrations-ado-writes.example.yml +49 -0
  63. package/plugin/templates/ado-update/proposed.template.md +78 -0
  64. package/plugin/templates/init/external-links.template.txt +30 -0
  65. package/plugin/templates/init/project-integrations.template.yml +57 -2
  66. package/plugin/templates/snapshot/meeting-verbatim.template.md +110 -0
  67. package/plugin/templates/snapshot/meetings-series-index.template.md +3 -1
  68. package/plugin/templates/snapshot/onenote-page.template.md +92 -23
  69. package/plugin/templates/weekly/meetings-stream.template.md +11 -6
@@ -0,0 +1,66 @@
1
+ ---
2
+ applyTo: "**"
3
+ excludeAgent: "code-review"
4
+ ---
5
+
6
+ # Evidence Confidence Ladder — Always-On
7
+
8
+ When Kushi (or any consumer of Kushi evidence) makes a claim about a customer's decision, status, funding, scope, owner, or commitment, that claim must be tagged with one of three confidence states. Treat the lower two as provisional. **Do not collapse them into "decided" just because a structured field shows a value.**
9
+
10
+ ## The three states
11
+
12
+ ### 1. `internal-only` (lowest confidence)
13
+
14
+ A field, note, or status reflects an **internal team decision recorded in a system of record**. The customer has not been formally informed; deal-desk / commercial / legal approval is not in evidence.
15
+
16
+ - Examples: a CRM `statuscode` updated to `Not Yet Requested`, an option-set field flipped, an internal CRM annotation added by an MS team member.
17
+ - Render: `internal-only — recorded in CRM <date> by <owner>; no customer-facing confirmation in evidence`.
18
+
19
+ ### 2. `communicated` (medium confidence)
20
+
21
+ The decision has been **shared with the customer or external stakeholder** in a meeting, email, Teams chat, or shared artifact. Acknowledgment is on record. Commercial / legal / deal-desk approval may still be pending.
22
+
23
+ - Examples: latest meeting transcript shows the customer accepting the direction; an email from MS to customer + reply acknowledgment.
24
+ - Render: `communicated — confirmed in <transcript|email|teams> on <date>; commercial/legal approval pending`.
25
+
26
+ ### 3. `confirmed` (full confidence)
27
+
28
+ All required parties have agreed and the commitment is documented in a signed / approved / executed artifact (signed SOW, approved ECIF, executed amendment, deal-desk-approved record).
29
+
30
+ - Render: `confirmed — <artifact> dated <date>; signed/approved by <party>`.
31
+
32
+ ## How to assign the state
33
+
34
+ When synthesizing across sources, walk the cross-check:
35
+
36
+ 1. Is there a CRM/ADO field that asserts the claim? → at minimum `internal-only`.
37
+ 2. Is there a customer-facing transcript / email / Teams message **dated AFTER the field update** that confirms the same direction? → upgrade to `communicated`.
38
+ 3. Is there an executed/approved artifact (signed contract, deal-desk approval log, signed SOW) covering the claim? → upgrade to `confirmed`.
39
+
40
+ If the latest customer-facing evidence **predates** the CRM/ADO field update, you cannot upgrade past `internal-only` on that field alone — the team's internal direction has changed but no post-decision external confirmation is on record yet.
41
+
42
+ ## Examples (anti-patterns to avoid)
43
+
44
+ **Wrong:** "ECIF is the selected funding model." (based on CRM field flip dated 3/26 with no post-3/26 transcript).
45
+
46
+ **Right:** "Internal team decision favors ECIF (CRM field updated 3/26 — `internal-only`). Latest customer-facing transcript (3/23) predates this decision; no `communicated` evidence yet. Deal-desk approval is also not in evidence."
47
+
48
+ **Wrong:** "Solution architect is X." (based on a `_new_fdelead_value` lookup).
49
+
50
+ **Right:** "Solution architect assigned in CRM as X (`internal-only`, recorded 3/26). No transcript or email confirms X has met the customer in that role yet."
51
+
52
+ ## Where this shows up in Kushi outputs
53
+
54
+ - **`State/02_decisions.md`** — every row gets a `## Confidence` column with one of the three labels + the citing artifact for the upgrade (or absence thereof).
55
+ - **`State/03_funding.md`** (when present) — funding selections are particularly prone to `internal-only` masquerading as `confirmed`. Always show the ladder.
56
+ - **`State/06_risks.md`** — a risk that depends on a `confirmed` state but is currently `internal-only` or `communicated` should be flagged as such.
57
+ - **`Open Questions/`** — every claim that sits at `internal-only` or `communicated` and matters to a downstream gate should generate an Open Question for the next refresh window.
58
+ - **`ask-project` answers** — the model must surface the confidence label inline, never paraphrase a `communicated` decision as `final`.
59
+
60
+ ## Cross-reference with date-precedence
61
+
62
+ This doctrine is orthogonal to the date-recency precedence in `ado-engagement-tree.instructions.md` and `fde-grounding`-style precedence (newer dated source wins). Confidence is about **what kind of evidence exists**, not which is newest. A newer `internal-only` field flip does NOT supersede an older `communicated` confirmation of the same direction — it just adds a follow-up question: did the customer get re-confirmed after the latest internal change?
63
+
64
+ ## Always-on
65
+
66
+ This instruction applies to every Kushi skill that synthesizes across sources (`consolidate`, `state-update`, `ask-project`) and to any external consumer rendering Kushi evidence into a report.
@@ -0,0 +1,115 @@
1
+ ---
2
+ applyTo: "**"
3
+ description: "Evidence layout is CANONICAL — every per-source artifact lives under <engagement-root>/<project>/Evidence/<alias>/<source>/{snapshot,stream,_index,_legacy,refresh-reports}/. Writing source artifacts to any other path under <project>/ (e.g. <project>/email-context/, <project>/notes/, <project>/_Weekly Summaries/, <project>/email/) is a DEFECT."
4
+ ---
5
+
6
+ # Evidence Layout — Canonical (HARD RULE)
7
+
8
+ Multi-contributor projects depend on a **single, predictable, per-source, per-alias** evidence tree. The moment a pull skill writes to a sibling folder under `<project>/` (e.g. `<project>/email-context/`), four things break:
9
+
10
+ 1. **Multi-user collision** — another contributor's pull cannot find or merge it.
11
+ 2. **Consolidation breaks** — `consolidate-evidence` walks `Evidence/*/<source>/` and silently drops anything outside.
12
+ 3. **State rebuilds wrong** — `build-state` reads only the canonical tree; rogue folders become invisible.
13
+ 4. **Run-log drift** — `run-log.yml` watermarks point at the canonical path; a legacy folder makes the run "ok" but the data isn't where the doctrine says.
14
+
15
+ This file is the **hard rule** every pull-/refresh-/bootstrap- skill MUST honor.
16
+
17
+ ## The contract
18
+
19
+ ### Rule 1 — All per-source artifacts live under `Evidence/<alias>/<source>/`
20
+
21
+ For every project under `<engagement-root>/`:
22
+
23
+ ```
24
+ <engagement-root>/<project>/
25
+ Evidence/ # ← ALL contributor evidence lives here
26
+ contributors.yml
27
+ run-log.yml
28
+ _Consolidated/ # output of consolidate-evidence (cross-alias)
29
+ <alias>/ # one per contributor (e.g. "ushak/")
30
+ .settings.yml
31
+ refresh-reports/
32
+ open-questions/
33
+ ado/ { snapshot/ , stream/ }
34
+ crm/ { snapshot/ , stream/ }
35
+ email/ { snapshot/ , stream/ , _index/ , _legacy_*/ }
36
+ meetings/ { snapshot/ , stream/ , verbatim/ }
37
+ onenote/ { snapshot/ , stream/ , refresh-reports/ }
38
+ sharepoint/ { snapshot/ , stream/ }
39
+ teams/ { snapshot/ , stream/ }
40
+ State/ # rendered by build-state (read-only outcome)
41
+ Reports/ # rendered by aggregate / fde-report (read-only)
42
+ integrations.yml # per-project boundaries (scope-boundaries.instructions.md)
43
+ ```
44
+
45
+ `Evidence/` and `<alias>/` are the **only** levels a pull skill may create under `<project>/`. Nothing else.
46
+
47
+ ### Rule 2 — Sibling source-output folders under `<project>/` are FORBIDDEN
48
+
49
+ Concretely, a pull skill MUST NOT create or write to any of these (representative — list is illustrative, not exhaustive):
50
+
51
+ | Forbidden path | Canonical replacement |
52
+ |---|---|
53
+ | `<project>/email-context/` | `<project>/Evidence/<alias>/email/snapshot/` + `stream/` |
54
+ | `<project>/email/` (at project root) | `<project>/Evidence/<alias>/email/` |
55
+ | `<project>/notes/` | `<project>/Evidence/<alias>/onenote/snapshot/pages/` |
56
+ | `<project>/_Weekly Summaries/` | `<project>/Evidence/<alias>/<source>/stream/` |
57
+ | `<project>/Meetings/` (at project root) | `<project>/Evidence/<alias>/meetings/` |
58
+ | `<project>/Teams/` (at project root) | `<project>/Evidence/<alias>/teams/` |
59
+ | `<project>/SharePoint/` (at project root) | `<project>/Evidence/<alias>/sharepoint/` |
60
+ | `<project>/CRM/`, `<project>/ADO/` (at project root) | `<project>/Evidence/<alias>/{crm,ado}/` |
61
+ | any `<project>/<source>-context/`, `<project>/<source>-summary/`, etc. | `<project>/Evidence/<alias>/<source>/snapshot/` |
62
+
63
+ `State/`, `Reports/`, `integrations.yml` are the **only** top-level siblings of `Evidence/` that pull/refresh skills are allowed to leave alone (they are written by `build-state`, `aggregate-project`, and bootstrap respectively — not by pull-* skills).
64
+
65
+ ### Rule 3 — Legacy / pre-bootstrap folders are migrated, not deleted
66
+
67
+ When a pull or refresh skill encounters a non-canonical source-output folder under `<project>/`:
68
+
69
+ 1. **Move** the folder verbatim into `Evidence/<alias>/<source>/_legacy_<original-folder-name>_pre-bootstrap/` (preserve file mtimes; do not edit contents).
70
+ 2. **Log** the move in the contributor's `refresh-reports/<YYYY-MM-DD-HHMM>_refresh.md` under a `## Layout migrations` section: source path → destination path → file count.
71
+ 3. **Note** the migration as a `runs:` entry in `Evidence/run-log.yml` with `type: layout-migration` and `status: ok`.
72
+ 4. **Do not delete** anything until the user explicitly acks in the next session.
73
+
74
+ If alias is ambiguous (legacy folder pre-dates multi-user), default to the current contributor's alias and add a one-liner to `Evidence/<alias>/open-questions/layout.md` so the consolidation step can re-attribute later.
75
+
76
+ ### Rule 4 — `consolidate-evidence`, `build-state`, and `aggregate-project` only read the canonical tree
77
+
78
+ By contract, downstream skills walk:
79
+
80
+ - `Evidence/*/email/`, `Evidence/*/teams/`, `Evidence/*/meetings/`, `Evidence/*/onenote/`, `Evidence/*/sharepoint/`, `Evidence/*/crm/`, `Evidence/*/ado/`
81
+
82
+ Anything outside these paths is invisible to them — by design. The path IS the contract. There is no "also scan sibling folders" fallback.
83
+
84
+ ### Rule 5 — Self-check enforces the rule (`self-check D14`)
85
+
86
+ `plugin/skills/self-check/run.ps1` -Deep MUST detect any `<project>/<sibling>/` folder under engagement roots where:
87
+
88
+ - `<sibling>` is not in the allow-list `@('Evidence','State','Reports','.kushi','.kushi-reference','.project-evidence','.vscode')`, AND
89
+ - `<sibling>` contains markdown files matching the per-source patterns (`*-summary.md`, `*-stream.md`, `*-context*`, `current-state.md`, `index.md`, etc.).
90
+
91
+ When detected → emit a D14 finding with the canonical replacement path from Rule 2.
92
+
93
+ ## Why this is HARD, not "preferred"
94
+
95
+ Multi-contributor evidence only works if every pull writes to the **same path** another contributor's pull would write to. The instant one skill writes to `<project>/email-context/` and another writes to `Evidence/ushak/email/`, the project has two parallel realities — and `build-state` will quietly use only one of them. That's a citation-integrity defect, not a cosmetic one.
96
+
97
+ This rule is the layout half of the partial-determinism contract:
98
+
99
+ - `scope-boundaries.instructions.md` → user controls **what** is queried.
100
+ - `evidence-layout-canonical.instructions.md` (this file) → doctrine controls **where** the result lands.
101
+
102
+ Together they guarantee that two contributors running the same verb on the same project produce evidence in the same place, scoped to the same boundary, regardless of which one ran first.
103
+
104
+ ## Cross-references
105
+
106
+ - `snapshot-vs-stream.instructions.md` — the two shapes inside each `<source>/` folder.
107
+ - `scope-boundaries.instructions.md` — what each source is allowed to query (orthogonal: scope vs path).
108
+ - `side-by-side-config.instructions.md` — config files (mutable hints, integrations.yml) — also outside `<project>/`, but under `<engagement-root>/.project-evidence/`.
109
+ - `run-reports.instructions.md` — every layout-migration MUST appear in the refresh report.
110
+ - `cleanup-on-resolution.instructions.md` — once a legacy folder is migrated, all stale references in older summaries/notes get rewritten in the same turn.
111
+ - `bootstrap-project/SKILL.md` — creates the canonical tree on first run.
112
+ - `refresh-project/SKILL.md` — migrates any non-canonical folders it finds before pulling.
113
+ - All `pull-*/SKILL.md` — write ONLY under `Evidence/<alias>/<source>/`.
114
+ - `consolidate-evidence/SKILL.md`, `build-state/SKILL.md`, `aggregate-project/SKILL.md` — read ONLY from the canonical tree.
115
+ - `self-check/run.ps1` D14 — enforces detection.
@@ -7,14 +7,61 @@ description: "Evidence Thoroughness Standard — every per-source skill MUST cap
7
7
 
8
8
  Evidence files are the **system of record** that State files cite. They MUST be deep enough that a reader can fully reconstruct what happened without going back to Outlook / Teams / OneNote / SharePoint / CRM / ADO. **Headlines-only summaries are a defect.**
9
9
 
10
+ > **Orthogonal to scope:** depth (this file) and scope (`scope-boundaries.instructions.md`) are independent. Boundaries declare *where Kushi is allowed to look*; depth declares *how completely it captures what it found*. A skill must satisfy BOTH: refuse if the boundary is missing, then capture at full depth inside the boundary. Coverage Notes blocks at the bottom of every entity MUST enumerate which boundaries were applied (per Rule 4 of `scope-boundaries.instructions.md`).
11
+
12
+ ## Universal rule — AI Narrative Summary required FIRST
13
+
14
+ Every per-entity block (per meeting, per email thread, per Teams thread, per OneNote page, per SharePoint key file, per CRM/ADO record) MUST open with an **`### AI Narrative Summary`** sub-section before any structured sub-sections (Decisions / Actions / Risks / etc.).
15
+
16
+ The AI Narrative Summary:
17
+ - Is a **multi-paragraph prose summary** (minimum 3 paragraphs for any non-trivial entity; 5+ paragraphs for substantive meetings, threads, or pages) that captures **every detail discussed** — context, what was said by whom, the reasoning, the back-and-forth, side-tangents, soft commitments, sentiment, and any nuance — not just the outcomes.
18
+ - Reads like a thorough briefing for someone who wasn't there. A reader who only reads the AI Narrative Summary should be able to answer "what happened, why, who pushed which view, what's the tone, what's still unresolved?" without scrolling further.
19
+ - Is generated AFTER the full extraction (transcript / body / page content) is in hand, so it can faithfully cover **everything** — not summarized from headlines.
20
+ - Carries inline `[source: …]` citations to the same evidence the structured sub-sections cite. No uncited paragraphs.
21
+ - Is NOT a replacement for the structured sub-sections (Decisions, Action Items, Risks, etc.) or the verbatim transcript walk-through / message reproduction. It is **additional**, placed first, so a busy reader gets the full picture before drilling into structure.
22
+
23
+ A per-entity block that has structured sub-sections but no AI Narrative Summary is a defect. A 2-paragraph "summary" that only lists outcomes is a defect — it must capture the discussion, not just the result.
24
+
25
+ ## Universal rule — full discussion capture (HARD)
26
+
27
+ Beyond the narrative summary, every per-entity block MUST also explicitly capture, as separate named sub-sections, the following — even when some are empty (write `_None surfaced._` rather than omit the section, so a reader knows it was checked):
28
+
29
+ - **Questions Asked & Answered** — every question raised + the answer given (or "left open"), with who asked and who answered. Format as `Q: … — A: … [source: … · ts]`. Includes clarifying questions, challenge questions, status questions, asks for data, asks for opinion. **A meeting with zero captured Q&A is a defect** unless the meeting was a one-way readout (and even then, capture the Q&A from the Q&A portion at the end).
30
+ - **Discussion Points (Bulleted, with Detail)** — every distinct topic touched, as a bullet, with a 2–5-line nested detail block per bullet covering: what was said, by whom, what positions surfaced, what arguments were made, what was concluded (or "deferred"). Not a one-line list — every bullet has nested detail.
31
+ - **Decisions** — every decision with exact wording + who decided + supporting context + what was rejected.
32
+ - **Plans (Current State)** — the plan as it stands at the end of the entity (meeting / thread / page). What is intended to happen, by when, by whom.
33
+ - **Changes to Plans** — every adjustment to a previously-stated plan (whether stated earlier in the same meeting/thread or carried in from prior evidence): old plan → new plan + why it changed + who drove the change. Critical for tracing how an engagement evolves.
34
+ - **Next Steps** — forward-looking commitments that aren't yet hard action items. Distinct from Action Items (those have owner+due). Capture even soft signals: "team will look into X", "we'll circle back next week".
35
+ - **Action Items** — every commitment with owner + due + source-line.
36
+ - **Open Questions / Non-Decisions** — questions raised but not resolved, with who raised them and why deferred. Distinct from "Questions Asked & Answered" (which captures resolved Q&A in this entity).
37
+ - **Risks, Blockers, Dependencies** — surfaced or escalated.
38
+ - **Customer Asks** — explicit asks the customer made of Microsoft.
39
+
40
+ The existence of a section is mandatory; populating it is conditional on the source. **Empty sections must be written explicitly as `_None surfaced._`** so a reader can distinguish "checked and empty" from "skipped".
41
+
10
42
  ## Per-source minimum bar
11
43
 
12
44
  ### Meetings (stream/)
13
- For every meeting in the window — capture, **as separate named sections under each per-meeting block**:
45
+ For every meeting in the window — capture, **as separate named sections under each per-meeting block**, in this order (every section MUST be present; if empty, write `_None surfaced._`):
46
+ - **AI Narrative Summary** (REQUIRED FIRST per the universal rule above) — 5+ paragraphs covering the whole meeting end-to-end: context coming in, what was discussed in what order, who took which position, the reasoning behind each position, the back-and-forth, soft / forward-looking signals, sentiment, what landed and what stayed open. Cite the transcript timestamps inline.
14
47
  - Full attendee list (required + optional + actual + no-shows)
15
48
  - Agenda / stated purpose
16
- - **Detailed Discussion Summary** — multi-paragraph narrative of what was actually discussed end-to-end, not 3 bullet points
49
+ - **Detailed Discussion Summary** — multi-paragraph structured narrative of what was actually discussed end-to-end, organized by topic (the AI Narrative Summary is chronological/holistic; this section is topic-organized; both are required)
50
+ - **Discussion Points (Bulleted, with Detail)** — every distinct topic, as a bullet with nested 2–5-line detail block (positions, arguments, what was concluded)
51
+ - **Questions Asked & Answered** — every Q raised + the A given (or "left open"), `Q: … — A: …` format, with attribution
17
52
  - **Chronological transcript walk-through with verbatim quotes and timestamps** — every substantive exchange, not just 2 highlight quotes
53
+ - **Plans (Current State)** — the plan as it stands at end of meeting
54
+ - **Changes to Plans** — old plan → new plan + why + who drove the change
55
+ - **Key Decisions** — every decision with exact wording + who decided + supporting context + what was rejected
56
+ - **Open Questions / Non-Decisions** — questions raised but not resolved, with who raised them and why deferred
57
+ - **Next Steps** — REQUIRED dedicated section. Forward-looking commitments that aren't yet hard action items: "team will gather facts", "Mike will discuss with industry leads", "Microsoft to come back with proposal next week". These are distinct from `Action Items` (which have owner+due) and are critical to State/05_action-items + State/04_workshops-and-key-meetings rendering.
58
+ - **Action Items** — every commitment with owner + due + source-line
59
+ - **Risks, Blockers, Dependencies** — surfaced or escalated in this meeting
60
+ - **Customer Asks** — explicit asks the customer made of Microsoft (resourcing, decisions, timelines, escalations)
61
+ - Every artifact link / shared file / recording / transcript URL
62
+ - **Coverage Notes** — what was retrievable vs what wasn't (transcript missing, chat-only reconstruction, partial recap, etc.)
63
+
64
+ If transcript is unavailable, document why and pull chat transcript + Copilot recap + meeting chat thread to reconstruct. Per-meeting sub-section is mandatory; one block per meeting. **A 30-line meetings file for a week with 2 meetings is a defect — expect 400+ lines, with the structure above repeated per meeting.** A per-meeting block missing the explicit `Next Steps`, `Plans`, `Changes to Plans`, `Discussion Points`, or `Questions Asked & Answered` sections is a defect even if Action Items is present — they capture different things.
18
65
  - **Key Decisions** — every decision with exact wording + who decided + supporting context
19
66
  - **Open Questions / Non-Decisions** — questions raised but not resolved, with who raised them and why deferred
20
67
  - **Next Steps** — REQUIRED dedicated section. Forward-looking commitments that aren't yet hard action items: "team will gather facts", "Mike will discuss with industry leads", "Microsoft to come back with proposal next week". These are distinct from `Action Items` (which have owner+due) and are critical to State/05_action-items + State/04_workshops-and-key-meetings rendering.
@@ -27,25 +74,31 @@ For every meeting in the window — capture, **as separate named sections under
27
74
  If transcript is unavailable, document why and pull chat transcript + Copilot recap + meeting chat thread to reconstruct. Per-meeting sub-section is mandatory; one block per meeting. **A 30-line meetings file for a week with 2 meetings is a defect — expect 200+ lines, with the structure above repeated per meeting.** A per-meeting block missing the explicit `Next Steps` section is a defect even if Action Items is present — they capture different things.
28
75
 
29
76
  ### Teams chats (stream/)
30
- For every thread touched in the window — capture **full message-by-message reproduction** (sender · timestamp · verbatim message text or close paraphrase), not just an outcome line. Group by thread, not by day. Include reactions, file attachments, links, replies. If a thread has 30 messages, reproduce all 30 (collapse only routine acks like 👍 / "thanks").
77
+ For every thread touched in the window — capture, in this order per thread:
78
+ - **AI Narrative Summary** (REQUIRED FIRST) — 3+ paragraph prose covering what the thread is about, the conversation arc, who took which position, sentiment, what landed and what stayed open. Cite messages inline.
79
+ - **Full message-by-message reproduction** (sender · timestamp · verbatim message text or close paraphrase), not just an outcome line. Group by thread, not by day. Include reactions, file attachments, links, replies. If a thread has 30 messages, reproduce all 30 (collapse only routine acks like 👍 / "thanks").
80
+ - **Decisions / Action Items / Open Questions / Risks** captured by the thread.
31
81
 
32
82
  ### Emails (stream/)
33
- For every substantive thread — capture sender, recipients (to + cc), subject, **full body or close paraphrase**, attachments, and the chain of replies in order. Thread-level grouping. A one-line "X sent Y about Z" entry is insufficient — include enough body to convey what was actually said.
83
+ For every substantive thread — capture, in this order per thread:
84
+ - **AI Narrative Summary** (REQUIRED FIRST) — 3+ paragraph prose: what the thread is about, who's pushing what, the back-and-forth, what was decided / asked / committed / left open, tone. Cite messages inline.
85
+ - Sender, recipients (to + cc), subject, **full body or close paraphrase** for every message in the chain in order, attachments. Thread-level grouping. A one-line "X sent Y about Z" entry is insufficient — include enough body to convey what was actually said.
86
+ - **Decisions / Action Items / Open Questions / Risks** surfaced by the thread.
34
87
 
35
88
  ### OneNote (snapshot/ + stream/)
36
- - snapshot/pages/<page>.md — extract **full page bodies**, not just titles. Last-modified timestamp + author at the top.
37
- - stream/<week>.md — page-edit events with diff summary.
89
+ - `snapshot/pages/<page>.md`start with **AI Narrative Summary** (REQUIRED FIRST, 3+ paragraphs covering what the page is about, structure, key points, anything noteworthy), then extract **full page bodies**, not just titles. Last-modified timestamp + author at the top.
90
+ - `stream/<week>.md`for each page-edit event: a 1–2 paragraph **AI Narrative Summary** of what changed and why it matters, then the diff summary itself.
38
91
 
39
92
  If Graph delegated-token isn't available, ask the user to paste page content rather than skip.
40
93
 
41
94
  ### SharePoint (snapshot/ + stream/)
42
- - snapshot/tree.md — full folder tree (no truncation). Mark each entry `[key]` / `[recent]` / `[pin]` / `[skip]` / `[tree-only]` so readers can see why a file was or wasn't expanded.
43
- - snapshot/files/<path>.md — body summary for: (a) **curated key files** (architecture, decisions, ADRs, deliverables, proposals, SOWs, business cases, roadmaps, plans), PLUS (b) **top-N most-recently-modified files** where N = `sharepoint.snapshot.recent_n` (default 25), PLUS (c) any user pins from `sharepoint.snapshot.always_include`. Per file: full filename (no truncation), changed-by, change-type, size, last-modified, content summary at the same depth bar as a meeting transcript walk-through (decisions, risks, actions, owners, dates, key context).
44
- - stream/<week>.md — file change events that week.
95
+ - `snapshot/tree.md` — full folder tree (no truncation). Mark each entry `[key]` / `[recent]` / `[pin]` / `[skip]` / `[tree-only]` so readers can see why a file was or wasn't expanded.
96
+ - `snapshot/files/<path>.md`start with **AI Narrative Summary** (REQUIRED FIRST, 3+ paragraphs: what the file is, what it argues / proposes / records, key positions, audience, why it matters), then a body summary at the same depth bar as a meeting transcript walk-through (decisions, risks, actions, owners, dates, key context). Bodies for: (a) **curated key files** (architecture, decisions, ADRs, deliverables, proposals, SOWs, business cases, roadmaps, plans), PLUS (b) **top-N most-recently-modified files** where N = `sharepoint.snapshot.recent_n` (default 25), PLUS (c) any user pins from `sharepoint.snapshot.always_include`. Per file: full filename (no truncation), changed-by, change-type, size, last-modified.
97
+ - `stream/<week>.md` — file change events that week, each with a short **AI Narrative Summary** of what the change was and why it matters.
45
98
 
46
99
  ### CRM/ADO (snapshot/ + stream/)
47
- - snapshot/<id>.md — every field the API returns, every value.
48
- - stream/<id>/<week>.md — every field-level change with old → new + actor + timestamp, every comment/discussion verbatim.
100
+ - `snapshot/<id>.md`start with **AI Narrative Summary** (REQUIRED FIRST, 3+ paragraphs: the engagement / work item story so far, current stage, who owns it, what's at stake, latest status note in plain prose), then every field the API returns, every value.
101
+ - `stream/<id>/<week>.md`for the week as a whole: an **AI Narrative Summary** (REQUIRED FIRST) of what changed and what it means, then every field-level change with old → new + actor + timestamp, every comment / discussion verbatim.
49
102
 
50
103
  ## Volume guidance
51
104
 
@@ -59,4 +112,21 @@ Every paragraph still needs `[source: …]` citations — thoroughness does NOT
59
112
 
60
113
  ## Fix-up loop
61
114
 
62
- If the user reads an evidence file and says "this is too light", the skill MUST re-pull from source with deeper extraction and rewrite the file in the same fix-up turn — never defend a thin summary.
115
+ If the user reads an evidence file and says "this is too light" or "I don't like the depth" or "more detail" or "full AI summary" — the skill MUST re-pull from source with deeper extraction and rewrite the file in the same fix-up turn — never defend a thin summary. Specifically: if the fix-up complaint is about the AI Narrative Summary being thin, expand it to 5+ paragraphs with full discussion coverage, not just outcomes.
116
+
117
+ ## Pre-write checklist (every per-source skill)
118
+
119
+ Before writing any per-entity block (meeting / thread / email / page / file / record), confirm:
120
+
121
+ - [ ] AI Narrative Summary is the FIRST sub-section
122
+ - [ ] It is multi-paragraph (3+ for non-trivial; 5+ for substantive meetings/threads/pages)
123
+ - [ ] It captures discussion + reasoning + sentiment, not just outcomes
124
+ - [ ] It carries inline `[source: …]` citations
125
+ - [ ] **Questions Asked & Answered** section is present (populated or `_None surfaced._`)
126
+ - [ ] **Discussion Points (Bulleted, with Detail)** section is present — each bullet has nested 2–5-line detail
127
+ - [ ] **Plans (Current State)** section is present
128
+ - [ ] **Changes to Plans** section is present
129
+ - [ ] **Next Steps** section is present (distinct from Action Items)
130
+ - [ ] All other structured sub-sections (Decisions / Action Items / Risks / Open Questions / Customer Asks) come AFTER, not instead of
131
+ - [ ] Verbatim transcript / message reproduction / page body is still present (the AI summary does not replace it)
132
+ - [ ] Empty sections explicitly say `_None surfaced._`, never omitted
@@ -0,0 +1,91 @@
1
+ ---
2
+ applyTo: "**"
3
+ excludeAgent: "code-review"
4
+ ---
5
+
6
+ # Full-View Gate — Always-On
7
+
8
+ When a prompt asks Kushi to characterize a project's current state — analysis, synthesis, summary, status, risks, recommendations, next steps, readiness, or "what's going on with X" — Kushi MUST first walk the standard source set and record the disposition of each category in the current session. Do not answer from partial local context if a broader retrieval path exists for that project.
9
+
10
+ ## Scope
11
+
12
+ This gate applies whenever the question is about a project / customer / engagement under the engagement root, including prompts that don't explicitly say "refresh" or "report":
13
+
14
+ - "what's the status of HCA"
15
+ - "summarize ABN AMRO"
16
+ - "what are the risks on Hovnanian"
17
+ - "what's been decided about funding for Lilly"
18
+ - "next steps for AGCO"
19
+ - "what did the customer say in the last meeting about X"
20
+ - any `/kushi ask-project <project> <question>` invocation
21
+
22
+ It does NOT apply to:
23
+ - generic code questions
24
+ - repository maintenance
25
+ - requests scoped explicitly to a single artifact ("read this one file and summarize")
26
+
27
+ ## The standard source set
28
+
29
+ For every applicable project, walk this set and record one disposition per category:
30
+
31
+ 1. **CRM** (Dataverse — see `pull-crm`)
32
+ 2. **ADO** (engagement tree — see `pull-ado` + `ado-engagement-tree.instructions.md`)
33
+ 3. **Email**
34
+ 4. **Teams chats**
35
+ 5. **OneNote**
36
+ 6. **SharePoint / external linked artifacts**
37
+ 7. **Meeting transcripts**
38
+
39
+ ## Accepted dispositions
40
+
41
+ Each category in the session output must carry one of:
42
+
43
+ - `retrieved` — pulled in this session (or read from fresh evidence written in the last refresh window)
44
+ - `cached-fresh` — last evidence on disk is within the freshness window (default 14 days)
45
+ - `cached-stale` — last evidence on disk is older than the freshness window; warn user
46
+ - `not-present-for-project` — boundaries explicitly disable this source for the project (e.g. `boundaries.ado.area_paths: []`)
47
+ - `attempted-but-blocked — <reason>` — concrete reason (auth, throttling, source unavailable)
48
+ - `available-but-not-yet-ingested` — a retrieval path was checked and concrete remaining work was identified
49
+
50
+ Carrying forward an old bootstrap state without re-checking is not allowed. If you don't know, the disposition is `unknown — gate not walked`.
51
+
52
+ ## Rendering the gate
53
+
54
+ In any synthesized output (state files, ask-project answers, consolidated reports), include a small Source Basis block:
55
+
56
+ ```
57
+ ## Source Basis (gate walked YYYY-MM-DD HH:MM)
58
+
59
+ | Source | Disposition | Notes |
60
+ |---|---|---|
61
+ | CRM | retrieved | 1 record, 12 annotations |
62
+ | ADO | retrieved | engagement #97007 + 7 children, 34 comments |
63
+ | Email | cached-fresh | last pull 2026-05-09 |
64
+ | Teams chats | attempted-but-blocked — throttled-tooManyRequests | retry in next refresh |
65
+ | OneNote | retrieved | 17 pages, 0 failed |
66
+ | SharePoint | not-present-for-project | boundaries.sharepoint.sites: [] |
67
+ | Transcripts | cached-stale (last 21d) | refresh recommended |
68
+ ```
69
+
70
+ ## "Full view" claim rule
71
+
72
+ Do NOT describe the answer as a "full picture", "complete view", "grounded customer state", or equivalent **unless** every applicable source category in the gate has a disposition of `retrieved`, `cached-fresh`, or `not-present-for-project`. Anything else means the view has known gaps — say so.
73
+
74
+ ## Cross-workflow rule
75
+
76
+ This gate applies even when the task is framed as:
77
+ - "synthesize this"
78
+ - "draft the executive summary"
79
+ - "produce the follow-on artifact"
80
+ - "what should we do next"
81
+ - "give me the top 3 risks"
82
+
83
+ If the output characterizes customer reality, walk the gate first.
84
+
85
+ ## Citation rule
86
+
87
+ Every material claim in a gated output must carry an inline citation. Per `citation-ledger.instructions.md`. If a claim is based only on CRM and lacks non-CRM confirmation, label it per `evidence-confidence-ladder.instructions.md` (likely `internal-only`).
88
+
89
+ ## Intent
90
+
91
+ Stop ad-hoc questions from skipping OneNote / email / transcripts / ADO discussions just because the question matched a quick-answer pattern. The gate is cheap to walk (most categories will be `cached-fresh` if a recent refresh ran) and expensive to skip.
@@ -0,0 +1,134 @@
1
+ ---
2
+ applyTo:
3
+ - "plugin/skills/bootstrap-project/**"
4
+ - "plugin/skills/refresh-project/**"
5
+ - "plugin/skills/pull-*/**"
6
+ priority: HARD
7
+ ---
8
+
9
+ # M365 ID Registry — discover once, consume deterministically
10
+
11
+ **Doctrine:** Bootstrap discovers; refresh consumes. Refresh runs MUST NOT re-discover canonical M365 identifiers — that is the source of "it worked the first time but not the second" non-determinism.
12
+
13
+ ## The registry
14
+
15
+ `<engagement-root>/.project-evidence/m365/m365-mutable.json#knownSections.<projectKey>` is the **single source of truth** for canonical M365 identifiers per project.
16
+
17
+ Schema (populate every key the source supports):
18
+
19
+ ```jsonc
20
+ "<projectKey>": {
21
+ // OneNote
22
+ "one_sectionName": "<displayName>.one",
23
+ "one_sectionFileId": "<wdsectionfileid GUID>", // primary, extracted from Doc.aspx URL fragment
24
+ "one_sectionGroupId": "<wdsectiongroupid GUID>", // when boundary is a section group
25
+ "one_sectionOneNoteGuid": "<wdsectiononenoteguid GUID>", // alternate
26
+ "one_sectionPath": "/<group>/<section>.one",
27
+ "one_sectionWebUrl": "<full Doc.aspx URL>",
28
+ "one_notebookSourceDoc": "<notebook sourceDoc GUID>",
29
+ "one_notebookName": "<notebook display name>", // browser path needs display name
30
+ "one_notebookSpoBaseUrl": "https://<tenant>.sharepoint(-df)?.com/personal/<upn>", // browser path
31
+ "one_pages": [ // per-page retry registry (dual-ID schema, pull-onenote v2.6.0)
32
+ {
33
+ "title": "<page title>",
34
+ "wdpartid": "<SharePoint search-index page GUID — used by WorkIQ>",
35
+ "webPageId": "<OneNote-for-Web page GUID — used by browser scrape>",
36
+ "lastModified": "<as reported by source>",
37
+ "last_status": "captured | user-pasted | auth-required | workiq-degraded | BODY-NOT-EXPOSED | short-suspect | enumeration-only",
38
+ "captured_via": "browser | workiq | user-paste",
39
+ "attempts": 0,
40
+ "last_attempt_at": "<ISO-8601>",
41
+ "snapshot_path": "Evidence/<alias>/onenote/snapshot/pages/<safe-title>.md",
42
+ "captured_at": "<ISO-8601, only when last_status ∈ {captured, user-pasted}>"
43
+ }
44
+ ],
45
+ // Email
46
+ "emailContext": "Inbox/<folder-path>",
47
+ // Teams
48
+ "teamsChatContext": {
49
+ "chatHints": ["..."],
50
+ "channelHints": ["..."],
51
+ "participantHints": ["..."]
52
+ },
53
+ // SharePoint
54
+ "sp_siteId": "<siteId>",
55
+ "sp_webId": "<webId>",
56
+ "sp_listId": "<listId>",
57
+ "sp_path": "/<site>/<library>/<folder>",
58
+ // CRM
59
+ "crm_envUrl": "<env>.crm.dynamics.com",
60
+ "crm_entitySet": "<entityset>",
61
+ "crm_recordId": "<guid>",
62
+ "crm_requestId": "<FE-YYYY-NNNNNN>",
63
+ // ADO
64
+ "ado_org": "<orgName>",
65
+ "ado_project": "<projectName>",
66
+ "ado_engagementId": "<int>",
67
+ "ado_workItemIds": [<int>, ...],
68
+ // Misc — user-curated link list (pull-misc v0.1.0+)
69
+ "misc_links": [ // per-link retry registry
70
+ {
71
+ "type": "loop | web | learn | pdf | github | file | onenote | sharepoint | ado",
72
+ "owner": "<as in external-links.txt>",
73
+ "title": "<as in external-links.txt>",
74
+ "url": "<as in external-links.txt>",
75
+ "notes": "<as in external-links.txt>",
76
+ "last_status": "captured | placeholder | auth-required | fetch-failed | skipped-binary | removed | not-yet-attempted | delegated",
77
+ "captured_via": "browser | http | file | delegated",
78
+ "delegated_to": "pull-onenote | pull-sharepoint | pull-ado",
79
+ "http_status": 200,
80
+ "content_type": "text/html",
81
+ "char_count": 12345,
82
+ "etag": "<HTTP ETag>",
83
+ "last_modified_http":"<HTTP Last-Modified>",
84
+ "attempts": 0,
85
+ "last_attempt_at": "<ISO-8601>",
86
+ "captured_at": "<ISO-8601, only when last_status=captured>",
87
+ "snapshot_path": "Evidence/<alias>/misc/snapshot/<safe-type>__<safe-title>.md"
88
+ }
89
+ ]
90
+ }
91
+ ```
92
+
93
+ ## Bootstrap contract (HARD)
94
+
95
+ For every enabled source, bootstrap MUST:
96
+
97
+ 1. **Probe** WorkIQ / source-native API with the user-supplied seed (folder name, channel name, request id, work item id) using the per-source discovery procedure in `pull-<source>/SKILL.md` § "Bootstrap discovery".
98
+ 2. **Validate** by re-issuing the source's Step A enumerate query against the resolved ID. The resolved ID is accepted ONLY if the validate query returns ≥ 1 row.
99
+ 3. **Persist** the resolved IDs to `m365-mutable.json#knownSections.<projectKey>` AND mirror them into the corresponding `boundaries.<source>.*` keys in `<project>/integrations.yml`.
100
+ 4. **Record** one line per source in `bootstrap-status.md`: `<source>: resolved <key>=<value> via seed "<seed>" (<count> items enumerated)`.
101
+ 5. If discovery fails after trying all alternate identifiers documented in the per-source SKILL, write the source as `disabled` in `integrations.yml`, park the question in `OPEN-QUESTIONS-DRAFT.md` (or `State/09_open-questions.md`), and continue. Never write speculative or partial IDs.
102
+
103
+ ## Refresh contract (HARD)
104
+
105
+ Every refresh MUST:
106
+
107
+ 1. **Read** `m365-mutable.json#knownSections.<projectKey>` first. If the entry is missing or the per-source key is empty → DO NOT probe. Re-dispatch through `bootstrap-project` for that source's discovery only, then resume.
108
+ 2. **Pass the canonical IDs to each pull-* skill in the form that skill's WorkIQ queries actually use.** Different sources need different forms:
109
+ - **OneNote (corrected v3.8.0):** PRIMARY path is browser-scrape via Playwright with persisted profile (returns reliable verbatim bodies — 16/16 captured for HCA on 2026-05-14 vs WorkIQ's 1/18). FALLBACK path is WorkIQ natural-language by display name (used only when Playwright profile is auth-expired). Per-page identifiers are stored in BOTH forms: `webPageId` (used by browser-scrape navigation) AND `wdpartid` (used by WorkIQ correlation and stream events). See `pull-onenote/SKILL.md` v2.6.0 § "Empirical contract" and `learnings/onenote.md` 2026-05-14 for proof. The v3.7.8 wdsectionfileid-filter doctrine and the v3.7.9 WorkIQ-primary doctrine are both retracted.
110
+ - **Email / Teams / SharePoint / CRM / ADO:** the registry IDs are passed as documented in each pull-* skill — typically as Graph IDs in API calls, not WorkIQ prose.
111
+ - **Misc (pull-misc v0.1.0+):** the link list is the user-curated `<project>/external-links.txt` file. Refresh re-parses the file every run, matches existing `misc_links[]` entries by `(type, url)` tuple, marks deleted entries as `removed` (preserves snapshot), creates new entries as `not-yet-attempted`, and routes per-type to runner branches (browser for loop, http for web/learn/docs/pdf/github, file for local, delegated for onenote/sharepoint/ado). See `pull-misc/SKILL.md` § "Step A — enumerate".
112
+ 3. **Never re-discover.** A refresh that probes WorkIQ with seeds (folder name, channel name) instead of canonical IDs is a defect. The only exception is the cleanup-on-resolution path documented in `cleanup-on-resolution.instructions.md`, which UPSERTS newly-resolved IDs into the registry mid-run.
113
+
114
+ ### Browser-fields self-heal exception (kushi v3.10.0+, OneNote-only)
115
+
116
+ OneNote requires FIVE registry fields to drive the Playwright runner — not just the WorkIQ `wdsectionfileid`. Pre-doctrine registry entries (bootstrapped before kushi v3.10.0) and entries written from synthesized URL templates are missing or wrong on `one_notebookSourceDoc`, `one_notebookSpoBaseUrl`, and `one_sectionWebUrl`. Refresh MAY (and MUST) dispatch `plugin/skills/pull-onenote/scripts/recapture-section-url.mjs` mid-run when these fields are absent. This is **not** re-discovery — `wdsectionfileid` is preserved if already present. It is a one-time backfill via user URL paste, cached forever after.
117
+
118
+ The script's `--check` mode is the gate; the interactive mode is the heal. See `pull-onenote/SKILL.md` Pre-flight C for the contract.
119
+
120
+ 4. **Cite** the registry path in the per-user refresh report: `Resolved IDs sourced from m365-mutable.json#knownSections.<projectKey> (last_updated: <ts>)`.
121
+
122
+ ## Anti-patterns (HARD-rule violations)
123
+
124
+ 1. ❌ Refresh probes WorkIQ for `"List sections in OneNote notebook"` instead of reading `one_sectionFileId` from the registry.
125
+ 2. ❌ Bootstrap persists an ID without validating it via the source's Step A enumerate query.
126
+ 3. ❌ Pull-* skill uses the wrong WorkIQ phrasing for the source. For OneNote specifically: using `wdsectionfileid = <id>` as filter syntax routes WorkIQ to summary mode — the working WorkIQ pattern is natural-language naming `one_sectionName` and notebook display name. But per `pull-onenote/SKILL.md` v2.6.0, browser-scrape is the PRIMARY path; WorkIQ is fallback only.
127
+ 6. ❌ A pull-* skill silently drops pages/items that returned BODY-NOT-EXPOSED, auth-required, or workiq-degraded instead of registering them for retry. Per-page retry registries (e.g. `one_pages[]` for OneNote) are the durable state that survives across refreshes — without them, refresh runs cannot tell pending-retry from never-attempted.
128
+ 7. ❌ A pull-* skill stores only ONE form of an identifier when the registry doctrine requires multiple forms. For OneNote specifically: `one_pages[]` entries MUST persist BOTH `webPageId` (browser navigation) AND `wdpartid` (WorkIQ correlation) when both are observed. Storing only one creates a single-path lock-in that the empirical record (browser-vs-WorkIQ retrieval gap) explicitly forbids.
129
+ 4. ❌ Bootstrap writes a partial / speculative ID with a `_note` field instead of marking the source disabled.
130
+ 5. ❌ Refresh "rediscovers" because it didn't find the project key — must re-dispatch through bootstrap, not improvise.
131
+
132
+ ## Self-check enforcement
133
+
134
+ `plugin/skills/self-check/run.ps1` D12 (v3.7.8 / retuned v3.7.9 / extended v3.8.0) verifies that each `pull-*/SKILL.md` cites `m365-id-registry.instructions.md` at least once and contains source-specific contract tokens. For `pull-onenote` v2.6.0 the required tokens are: `m365-id-registry`, `one_pages`, `webPageId`, `auth-required`, `playwright-profile` — these prove the skill carries the dual-ID retry registry + browser-primary contract.