mishkan-harness 0.2.0 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -172
- package/bin/mishkan.js +677 -16
- package/docs/design/MISHKAN_decisions.md +450 -8
- package/docs/design/MISHKAN_harness_design.md +1 -33
- package/docs/design/MISHKAN_observability.md +13 -9
- package/docs/engineer/profile-readable.md +201 -0
- package/docs/engineer/profile.md +754 -0
- package/docs/research/graphify-token-saving-poc.md +108 -0
- package/docs/usage/09-workflows.md +74 -4
- package/docs/usage/10-observability.md +37 -13
- package/docs/usage/11-graphify.md +264 -0
- package/docs/usage/12-skill-discovery.md +294 -0
- package/docs/usage/README.md +5 -3
- package/package.json +1 -1
- package/payload/install/settings.hooks.json +24 -0
- package/payload/mishkan/AGENT_SPEC.md +25 -7
- package/payload/mishkan/agents/ahikam.md +4 -2
- package/payload/mishkan/agents/aholiab.md +4 -2
- package/payload/mishkan/agents/asaph.md +5 -2
- package/payload/mishkan/agents/baruch.md +19 -2
- package/payload/mishkan/agents/benaiah.md +4 -2
- package/payload/mishkan/agents/bezalel.md +4 -2
- package/payload/mishkan/agents/caleb.md +4 -2
- package/payload/mishkan/agents/deborah.md +4 -2
- package/payload/mishkan/agents/elasah.md +4 -2
- package/payload/mishkan/agents/eliashib.md +4 -2
- package/payload/mishkan/agents/ezra.md +4 -2
- package/payload/mishkan/agents/hanun.md +5 -2
- package/payload/mishkan/agents/hiram.md +5 -2
- package/payload/mishkan/agents/hizkiah.md +5 -2
- package/payload/mishkan/agents/huldah.md +4 -2
- package/payload/mishkan/agents/huram.md +4 -2
- package/payload/mishkan/agents/hushai.md +5 -2
- package/payload/mishkan/agents/igal.md +4 -2
- package/payload/mishkan/agents/ira.md +5 -2
- package/payload/mishkan/agents/jahaziel.md +5 -2
- package/payload/mishkan/agents/jakin.md +4 -2
- package/payload/mishkan/agents/jehonathan.md +5 -2
- package/payload/mishkan/agents/jehoshaphat.md +4 -2
- package/payload/mishkan/agents/joab.md +5 -2
- package/payload/mishkan/agents/joah.md +5 -2
- package/payload/mishkan/agents/maaseiah.md +4 -2
- package/payload/mishkan/agents/meremoth.md +5 -2
- package/payload/mishkan/agents/meshullam.md +5 -2
- package/payload/mishkan/agents/nathan.md +5 -2
- package/payload/mishkan/agents/nehemiah.md +4 -2
- package/payload/mishkan/agents/obed.md +4 -2
- package/payload/mishkan/agents/oholiab.md +5 -2
- package/payload/mishkan/agents/palal.md +5 -2
- package/payload/mishkan/agents/phinehas.md +4 -2
- package/payload/mishkan/agents/rehum.md +4 -2
- package/payload/mishkan/agents/salma.md +5 -2
- package/payload/mishkan/agents/seraiah.md +4 -2
- package/payload/mishkan/agents/shallum.md +5 -2
- package/payload/mishkan/agents/shaphan.md +4 -2
- package/payload/mishkan/agents/shemaiah.md +4 -2
- package/payload/mishkan/agents/shevna.md +5 -2
- package/payload/mishkan/agents/uriah.md +5 -2
- package/payload/mishkan/agents/zaccur.md +4 -2
- package/payload/mishkan/agents/zadok.md +5 -2
- package/payload/mishkan/agents/zerubbabel.md +4 -2
- package/payload/mishkan/commands/code-graph.md +35 -0
- package/payload/mishkan/commands/eval-baruch.md +57 -0
- package/payload/mishkan/commands/mishkan-org-reference.md +58 -0
- package/payload/mishkan/commands/mishkan-resume.md +19 -5
- package/payload/mishkan/commands/mishkan-skills-misses.md +47 -0
- package/payload/mishkan/commands/mishkan-skills-reindex.md +33 -0
- package/payload/mishkan/commands/skills.md +35 -0
- package/payload/mishkan/commands/sprint-close.md +3 -1
- package/payload/mishkan/hooks/pre-tool-knowledge-route.sh +231 -0
- package/payload/mishkan/hooks/pre-tool-task-skill-route.sh +122 -0
- package/payload/mishkan/hooks/session-start-skill-index.sh +35 -0
- package/payload/mishkan/observability/schema.json +1 -1
- package/payload/mishkan/observability/watch/src/mishkan_watch/__main__.py +84 -2
- package/payload/mishkan/observability/watch/src/mishkan_watch/app.py +64 -3
- package/payload/mishkan/observability/watch/src/mishkan_watch/org_data.py +79 -0
- package/payload/mishkan/observability/watch/src/mishkan_watch/skills_data.py +267 -0
- package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/agents.py +33 -1
- package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/knowledge.py +118 -9
- package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/live.py +102 -2
- package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/org.py +139 -0
- package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/skills.py +187 -0
- package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/usage.py +377 -0
- package/payload/mishkan/observability/watch/src/mishkan_watch/tabs/workflows.py +199 -27
- package/payload/mishkan/observability/watch/src/mishkan_watch/theme.tcss +78 -4
- package/payload/mishkan/observability/watchd/src/mishkan_watchd/__main__.py +36 -6
- package/payload/mishkan/observability/watchd/src/mishkan_watchd/sources/bus_tail.py +16 -3
- package/payload/mishkan/observability/watchd/src/mishkan_watchd/sources/graphify_tail.py +220 -0
- package/payload/mishkan/observability/watchd/src/mishkan_watchd/sources/worktree_poll.py +13 -2
- package/payload/mishkan/observability/watchd/src/mishkan_watchd/state.py +157 -3
- package/payload/mishkan/observability/watchd/tests/test_state.py +6 -2
- package/payload/mishkan/org/org.json +141 -0
- package/payload/mishkan/scripts/pre-commit-eval-gate.sh +50 -0
- package/payload/mishkan/scripts/skill-discovery-indexer.py +462 -0
- package/payload/mishkan/scripts/skill-discovery-misses.py +173 -0
- package/payload/mishkan/scripts/skill-discovery-router.py +457 -0
- package/payload/mishkan/scripts/skill-discovery-smoke.sh +156 -0
- package/payload/mishkan/skills/graphify-query-craft/SKILL.md +162 -0
- package/payload/mishkan/skills/mishkan-init/SKILL.md +15 -0
- package/payload/mishkan/skills/skill-discovery/SKILL.md +120 -0
- package/payload/mishkan/templates/case-node.schema.json +1 -0
- package/payload/mishkan/templates/observability-log.schema.json +1 -0
- package/payload/mishkan/workflows/README.md +78 -13
- package/payload/mishkan/workflows/chosheb-feature-ship.js +75 -0
- package/payload/mishkan/workflows/migdal-dr-drill.js +94 -0
- package/payload/mishkan/workflows/migdal-infra-change.js +67 -0
- package/payload/mishkan/workflows/mishkan-blast-radius.js +144 -0
- package/payload/mishkan/workflows/mishkan-init.js +58 -0
- package/payload/mishkan/workflows/mishkan-knowledge-gap-discovery.js +121 -0
- package/payload/mishkan/workflows/mishkan-standards-rollout.js +153 -0
- package/payload/mishkan/workflows/mishmar-security-gate.js +83 -0
- package/payload/mishkan/workflows/panim-ds-rollout.js +83 -0
- package/payload/mishkan/workflows/sefer-release-notes.js +85 -0
- package/payload/mishkan/workflows/yasad-data-migration-wave.js +78 -0
- package/payload/mishkan/workflows/yasad-schema-evolution.js +76 -0
- package/payload/mishkan/templates/user-CLAUDE.md +0 -62
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: graphify-query-craft
|
|
3
|
+
description: |
|
|
4
|
+
Use `graphify query "<question>"` to traverse the project's code-structure
|
|
5
|
+
graph for structural questions ("who calls X", "what depends on Y", "where
|
|
6
|
+
is the entry point") at ~1.8k tokens per query — 88.1× cheaper than
|
|
7
|
+
lifting the full source tree into context (verified on MISHKAN harness,
|
|
8
|
+
POC 2026-06-07). Use BEFORE grep / Read on source files whenever the
|
|
9
|
+
question is about code STRUCTURE rather than code SEMANTICS.
|
|
10
|
+
For every code-touching agent across the dev teams (per D-009 amended scope, 2026-06-07): Yasad backend (Hizkiah, Nathan, Zadok, Shallum, Uriah), Panim frontend (Salma, Oholiab, Asaph, Jahaziel), Chosheb UI (Hiram), Mishmar code-security (Ira, Joab, Hushai), Migdal infra-code (Palal, Meshullam, Meremoth, Hanun), Sefer documentation (Joah, Shevna, Jehonathan).
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Graphify query craft
|
|
14
|
+
|
|
15
|
+
## When to call
|
|
16
|
+
|
|
17
|
+
The crisp test from D-008's epistemological frontier:
|
|
18
|
+
|
|
19
|
+
> **Structure question → Graphify.**
|
|
20
|
+
> **Semantic question → Cognee work.**
|
|
21
|
+
|
|
22
|
+
Examples of **structure** questions you should answer with a `graphify
|
|
23
|
+
query` BEFORE reading any file:
|
|
24
|
+
|
|
25
|
+
- "Who calls `process_payment`?"
|
|
26
|
+
- "What depends on the `User` model?"
|
|
27
|
+
- "Where is the main entry point?"
|
|
28
|
+
- "What is the call graph for the auth flow?"
|
|
29
|
+
- "What are the god nodes in this codebase?"
|
|
30
|
+
- "What connects the data layer to the API?"
|
|
31
|
+
- "Show me everything that imports `pandas`."
|
|
32
|
+
|
|
33
|
+
Examples of **semantic** questions that go to Cognee work, not Graphify:
|
|
34
|
+
|
|
35
|
+
- "Why was X deprecated?" → ADR in Cognee work
|
|
36
|
+
- "What did we decide about Y last sprint?" → decision in Cognee work
|
|
37
|
+
- "How does the team handle Z?" → runbook in Cognee work
|
|
38
|
+
|
|
39
|
+
If you can't tell which side of the line you're on, prefer Graphify
|
|
40
|
+
first — its answer is cheaper and structurally precise. Cognee work is
|
|
41
|
+
the right second hop when the Graphify answer is structurally correct
|
|
42
|
+
but the engineer needs the WHY.
|
|
43
|
+
|
|
44
|
+
## How to call
|
|
45
|
+
|
|
46
|
+
The graphify CLI lives outside Claude Code (installed via
|
|
47
|
+
`uv tool install "graphifyy>=0.8.33"` — pin matters: 0.8.33 fixed the
|
|
48
|
+
test-file-orphan bug; earlier 0.8.x silently dropped test edges).
|
|
49
|
+
It writes graphs into `<project>/graphify-out/` and the queries
|
|
50
|
+
traverse `graphify-out/graph.json`.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# First, make sure the graph is current — fast on warm cache:
|
|
54
|
+
graphify update .
|
|
55
|
+
|
|
56
|
+
# Then ask the question:
|
|
57
|
+
graphify query "who calls process_payment"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Pick the right traversal
|
|
61
|
+
|
|
62
|
+
- **`query`** (default BFS, ~2k tokens) — for "what surrounds this
|
|
63
|
+
concept" questions. Fans out from the seed.
|
|
64
|
+
- **`query --dfs`** — for **tracing a flow** when you already know the
|
|
65
|
+
entry node. Returns the call chain rather than the surrounding cluster.
|
|
66
|
+
Example: `graphify query "process_payment" --dfs` walks the call chain
|
|
67
|
+
from `process_payment` outward, single-thread.
|
|
68
|
+
- **`affected <node> --depth N --relations calls,imports`** — reverse
|
|
69
|
+
BFS. Pre-commit blast-radius check. Use BEFORE editing a function
|
|
70
|
+
whose downstream impact you don't fully know.
|
|
71
|
+
- **`path A B`** — directional shortest path. Add `--calls "[A]-->[B]"`
|
|
72
|
+
to constrain to a specific edge family. Answers "does X ever reach Y?"
|
|
73
|
+
without grep.
|
|
74
|
+
- **`explain <node>`** — node + neighbors + community context. Use when
|
|
75
|
+
you have a known symbol and want a quick map of its surroundings —
|
|
76
|
+
cheaper than `query`.
|
|
77
|
+
|
|
78
|
+
### Always pass `--context` explicitly
|
|
79
|
+
|
|
80
|
+
Graphify's heuristic edge-type detection is brittle on mixed-language
|
|
81
|
+
repos (well-documented community gotcha). When you know the question is
|
|
82
|
+
structural-calls, say so:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
graphify query "who handles payment events" --context call --context import
|
|
86
|
+
graphify affected "User" --relations imports
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This consistently outperforms heuristic-detection on the MISHKAN harness
|
|
90
|
+
and avoids the "why didn't it find that obvious caller" trap.
|
|
91
|
+
|
|
92
|
+
### Budget is rarely the dial you want
|
|
93
|
+
|
|
94
|
+
Default `--budget 2000` stays near 2k tokens even on 500k-word corpora.
|
|
95
|
+
Raising past ~8k almost always means **wrong seed** rather than budget
|
|
96
|
+
shortage. If the answer feels thin, re-seed (better question) before
|
|
97
|
+
re-budgeting.
|
|
98
|
+
|
|
99
|
+
The output is plain text that lists the graph path + the relevant
|
|
100
|
+
`file:line` citations. Cite them in your answer — per D-008
|
|
101
|
+
"citation discipline":
|
|
102
|
+
|
|
103
|
+
> When an agent answers from Graphify, it cites the graph node id and
|
|
104
|
+
> the source `file:line`. No "according to the graph" without an id.
|
|
105
|
+
|
|
106
|
+
## Cite, then optionally Read
|
|
107
|
+
|
|
108
|
+
A Graphify answer typically narrows the relevant set from "the whole
|
|
109
|
+
repo" (158k tokens) to "5-10 file:line citations" (~1.8k tokens). When
|
|
110
|
+
the engineer needs prose context for ONE of those citations, THEN you
|
|
111
|
+
Read that single file. The savings come from not Read-ing the other 200
|
|
112
|
+
files just to find the relevant ones.
|
|
113
|
+
|
|
114
|
+
Worked example, full flow:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
1. Engineer: "Refactor process_payment to use the new TransactionContext."
|
|
118
|
+
|
|
119
|
+
2. You (Hizkiah / Salma / Nathan / Zadok / Oholiab):
|
|
120
|
+
$ graphify query "who calls process_payment"
|
|
121
|
+
→ 7 file:line citations returned, ~1.8k tokens spent.
|
|
122
|
+
|
|
123
|
+
3. You: Read the 7 cited files (selective, not bulk).
|
|
124
|
+
|
|
125
|
+
4. You: Edit each call site to thread TransactionContext.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Without Graphify, step 2 becomes "grep recursively + Read every match"
|
|
129
|
+
which on a 158k-token corpus is ~80k+ tokens minimum and frequently
|
|
130
|
+
misses indirect dispatch.
|
|
131
|
+
|
|
132
|
+
## What graphify CAN'T do
|
|
133
|
+
|
|
134
|
+
- It does not understand call dispatch via dynamic strings (`getattr`,
|
|
135
|
+
`eval`, `dict-of-callables`). Those edges are invisible.
|
|
136
|
+
- It does not capture runtime configuration (env vars, feature flags).
|
|
137
|
+
Those are not in the AST.
|
|
138
|
+
- It does not understand cross-language boundaries (a Python call to a
|
|
139
|
+
Node script via subprocess). Each language's AST is its own island.
|
|
140
|
+
|
|
141
|
+
When the question requires those, fall back to grep + Read with a
|
|
142
|
+
narrowed file set, or escalate to Cognee work for the documented
|
|
143
|
+
intent.
|
|
144
|
+
|
|
145
|
+
## Fail-open
|
|
146
|
+
|
|
147
|
+
If `graphify-out/graph.json` is missing or stale, run `graphify update
|
|
148
|
+
.` first (sub-second on warm cache). If the project doesn't use
|
|
149
|
+
Graphify at all (no `graphify-out/` dir), proceed with grep + Read as
|
|
150
|
+
normal — no graph means no Graphify query path, that's fine.
|
|
151
|
+
|
|
152
|
+
## Reference
|
|
153
|
+
|
|
154
|
+
- D-008 — three-store knowledge surface (Graphify · Cognee work · Cognee
|
|
155
|
+
curated). The epistemological frontier between the three is the source
|
|
156
|
+
of "which question goes where". See `docs/design/MISHKAN_decisions.md`.
|
|
157
|
+
- D-009 — graph-first PreToolUse advisory hook for the five code-writing
|
|
158
|
+
specialists. The hook will, in Phase 2, surface a one-line reminder if
|
|
159
|
+
you do a structural Read without consulting Graphify first.
|
|
160
|
+
- POC report — `docs/research/graphify-token-saving-poc.md` (88.1×
|
|
161
|
+
average reduction, verified on MISHKAN harness 2026-06-07).
|
|
162
|
+
- Upstream Graphify — https://github.com/safishamsi/graphify.
|
|
@@ -46,6 +46,21 @@ to Y4NN before the first doc is written — the plan is the scope contract for i
|
|
|
46
46
|
the team rules from `~/.claude/mishkan/rules/*` → `.claude/rules/*` for
|
|
47
47
|
path-scoped loading, and `~/.claude/mishkan/templates/mcp.json` → `./.mcp.json`
|
|
48
48
|
so agents can reach the Cognee knowledge-graph MCP.
|
|
49
|
+
10. **Automated — Graphify code graph** (the third store of the knowledge stack,
|
|
50
|
+
per D-008): if `graphify` is on PATH (`uv tool install graphifyy` provides
|
|
51
|
+
it), run an initial scan so the project has a structure graph from Sprint
|
|
52
|
+
S0 onwards. Otherwise skip with a one-line note — the agent fleet still
|
|
53
|
+
works; the graph populates the first time Hizkiah / Salma / Nathan / Zadok /
|
|
54
|
+
Oholiab runs `graphify update .` mid-sprint.
|
|
55
|
+
```bash
|
|
56
|
+
if command -v graphify >/dev/null 2>&1; then
|
|
57
|
+
graphify update . || echo "mishkan-init: graphify scan failed, skipping (project will scan on first structural query)"
|
|
58
|
+
fi
|
|
59
|
+
```
|
|
60
|
+
The output `graphify-out/` is gitignored by convention — re-derivable, no
|
|
61
|
+
need to commit. The MISHKAN observability daemon's `graphify_tail` source
|
|
62
|
+
will start emitting `graphify_scan` / `graphify_query` events for the
|
|
63
|
+
Knowledge tab as soon as the graph exists.
|
|
49
64
|
|
|
50
65
|
## Outputs
|
|
51
66
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-discovery
|
|
3
|
+
description: Universal skill-discovery layer for the main session. Routes a task to the most relevant installed skills across MISHKAN, the user's ~/.claude/skills, plugin-bundled skills, and project-local skills. Returns three buckets — must_load, should_consider, adjacent — capped at 13 entries total. Advisory only; the model decides what to actually load. Use when a task arrives and you suspect a relevant skill exists but you cannot remember its name, when the surface of installed skills has grown past what fits in working memory, or when /skills is invoked explicitly.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# skill-discovery — main-session router
|
|
7
|
+
|
|
8
|
+
> The harness has dozens of installed skills across four roots. This layer
|
|
9
|
+
> answers one question for the main session: *given this task, which skills
|
|
10
|
+
> should I be aware of right now?* It does **not** load skills; it surfaces
|
|
11
|
+
> them. The loading decision remains with the model.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## When to invoke
|
|
16
|
+
|
|
17
|
+
- A new task arrives and the relevant skill name is not immediately obvious.
|
|
18
|
+
- The user types `/skills` (the slash command runs this skill directly).
|
|
19
|
+
- A workflow declares `relevant_skill_categories` and asks for skill candidates
|
|
20
|
+
before its first stage runs.
|
|
21
|
+
- You catch yourself about to do work you suspect a skill already encodes —
|
|
22
|
+
ask the router before improvising.
|
|
23
|
+
|
|
24
|
+
**Do not invoke** when the right skill is already named in the request, or
|
|
25
|
+
when the work is trivial enough that no skill applies (a one-line edit, a
|
|
26
|
+
direct git command, a clear file read).
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## How to invoke
|
|
31
|
+
|
|
32
|
+
Run the router script with the task description on `--task` (or piped on
|
|
33
|
+
stdin). The router reads the universal index at
|
|
34
|
+
`~/.claude/mishkan/skill-discovery/index.json` and emits a 3-bucket JSON.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
python3 ~/.claude/mishkan/scripts/skill-discovery-router.py \
|
|
38
|
+
--task "<one-paragraph task summary>" \
|
|
39
|
+
[--workflow <workflow-name>] \
|
|
40
|
+
[--relevant-categories cat1,cat2]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
If the index is missing or stale, run the indexer first (it is also wired to
|
|
44
|
+
session-boot via `--stat-only`):
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
python3 ~/.claude/mishkan/scripts/skill-discovery-indexer.py --rebuild
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Interpreting the three buckets
|
|
53
|
+
|
|
54
|
+
The router returns three buckets, hard-capped at **13 entries total**:
|
|
55
|
+
|
|
56
|
+
| Bucket | Cap | Semantics | What you do |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| `must_load` | ≤ 3 | Score ≥ threshold_high; strong trigger match | Load these into context; treat them as the directly-relevant skills for the task. |
|
|
59
|
+
| `should_consider` | ≤ 5 | Mid-band score; partial match | Skim the description; load if the work clearly intersects. Prefer keeping these *as references* over auto-loading them. |
|
|
60
|
+
| `adjacent` | ≤ 5 | Low score but same category | Awareness only; mention if relevant; do not load by default. |
|
|
61
|
+
|
|
62
|
+
**Bias rule.** When the count is tight (e.g. must_load is full but a
|
|
63
|
+
should_consider entry looks more relevant than a borderline must_load entry),
|
|
64
|
+
prefer enriching should_consider rather than padding must_load. The cost of
|
|
65
|
+
loading a wrong skill is higher than the cost of skipping a marginal one.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Trust asymmetry — load only what you trust for the work
|
|
70
|
+
|
|
71
|
+
Each entry carries an `origin` field: `mishkan`, `user`, `plugin`, `project`.
|
|
72
|
+
|
|
73
|
+
- `mishkan` entries are harness-authored and trusted by default.
|
|
74
|
+
- `user` / `plugin` / `project` entries are third-party and carry a `trust`
|
|
75
|
+
warning in the router output.
|
|
76
|
+
|
|
77
|
+
**Rule.** Never auto-load a non-MISHKAN skill for a stateful operation
|
|
78
|
+
(anything in y4nn-standards §5: `git push`, SSH to production, `docker exec`
|
|
79
|
+
on prod, `sudo`, schema migration, log forensics). Surface them; ask Y4NN
|
|
80
|
+
before loading.
|
|
81
|
+
|
|
82
|
+
For generative work (boilerplate, doc draft, refactor sketch), non-MISHKAN
|
|
83
|
+
skills can be loaded once you've read the description and judged the fit.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Name collisions
|
|
88
|
+
|
|
89
|
+
The indexer enforces precedence order at index time:
|
|
90
|
+
**mishkan → user → plugin → project**. Collisions are recorded in
|
|
91
|
+
`index.json.meta.collisions` (a shadowed skill is not silently dropped — it
|
|
92
|
+
is logged). If you suspect a collision is shadowing the skill you want, run
|
|
93
|
+
`/mishkan-skills-reindex` and inspect `meta.collisions`.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Failure mode — fail-open
|
|
98
|
+
|
|
99
|
+
If the router returns empty buckets, the request is recorded in
|
|
100
|
+
`~/.claude/mishkan/skill-discovery/misses.jsonl` for later tuning. Continue
|
|
101
|
+
the task without the discovery layer — the absence of a router result is not
|
|
102
|
+
a blocker.
|
|
103
|
+
|
|
104
|
+
If the index is missing or unreadable, the router returns
|
|
105
|
+
`stale_rebuild_needed: true` and `warnings: ["index_missing_or_unreadable"]`.
|
|
106
|
+
Run `/mishkan-skills-reindex` and retry.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Phase 1 scope (canary)
|
|
111
|
+
|
|
112
|
+
This skill is wired in two places only in Phase 1:
|
|
113
|
+
|
|
114
|
+
1. The `/skills` slash command — invokes the router on the current task.
|
|
115
|
+
2. The `mishkan-init` workflow — calls the router in an early phase as an
|
|
116
|
+
advisory hint to Bezalel before doc generation.
|
|
117
|
+
|
|
118
|
+
Other workflows route through their own craft skills as before. Phase 2 will
|
|
119
|
+
broaden integration once the canary has produced enough misses-log signal
|
|
120
|
+
to tune thresholds.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"$id": "mishkan://templates/case-node.schema.json",
|
|
4
4
|
"title": "MISHKAN Case Node",
|
|
5
5
|
"description": "Written to Cognee when an agent solves a problem using a curated resource (design §8).",
|
|
6
|
+
"$comment": "SPEC-ONLY artifact. No runtime validator enforces this schema today — it is the canonical shape referenced from MISHKAN_harness_design.md and MISHKAN_ontology.md. To enforce at write time, plumb it through scripts/validate-research-log.sh or a Cognee write hook.",
|
|
6
7
|
"type": "object",
|
|
7
8
|
"additionalProperties": false,
|
|
8
9
|
"required": ["type", "team", "agent", "problem_class", "resource_applied", "resolution", "outcome", "sprint", "task"],
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"$id": "mishkan://templates/observability-log.schema.json",
|
|
4
4
|
"title": "MISHKAN Observability Log Entry",
|
|
5
5
|
"description": "One entry per agent tool call, emitted by the PostToolUse hook (design §10).",
|
|
6
|
+
"$comment": "SPEC-ONLY artifact. The PostToolUse hook produces lines matching this shape but no runtime validator enforces it — the producer's discipline is the contract. To enforce, add a check in post-tool-observe.sh or a periodic conform pass.",
|
|
6
7
|
"type": "object",
|
|
7
8
|
"additionalProperties": false,
|
|
8
9
|
"required": ["agent", "team", "sprint", "session", "tool_calls", "outcome", "timestamp"],
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# MISHKAN workflows
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
more of the nine canonical workflow
|
|
3
|
+
Eighteen dynamic-workflow scripts — ten org-level + eight team-level —
|
|
4
|
+
that codify the orchestrations where parallel scale + repeatability
|
|
5
|
+
justify a script. Each maps to one or more of the nine canonical workflow
|
|
6
|
+
patterns from
|
|
6
7
|
[Anthropic's reference](https://code.claude.com/docs/en/workflows) and the
|
|
7
8
|
[community patterns catalogue](https://github.com/ray-amjad/claude-code-workflow-creator/blob/main/references/patterns.md).
|
|
8
9
|
|
|
@@ -20,25 +21,85 @@ These run from the **main session only** (subagents cannot invoke
|
|
|
20
21
|
| [`mishkan-architecture-panel.js`](mishkan-architecture-panel.js) | judge panel + impact-fanout + synthesis | Architecture decisions with a wide answer space; 3 Nathan runs from cost/scale/simplicity priors; Zadok+Phinehas+Shallum score; Bezalel synthesises | High-leverage architecture decisions |
|
|
21
22
|
| [`mishkan-release-readiness.js`](mishkan-release-readiness.js) | barrier `parallel()` + structured pass/fail + nested workflow | Pre-deploy gate: tests + security + dependency + SLO + pipeline shape, all at once → single go/no-go | Before every staging-to-prod deploy |
|
|
22
23
|
| [`mishkan-init.js`](mishkan-init.js) | pipeline with overlap (PRD → SRS → CONTRACT+ARCH in parallel → THREAT+C4 in parallel → settle) | Cut project init from hours to minutes without violating the sequence rule | Once per project at `/mishkan-init` |
|
|
24
|
+
| [`mishkan-blast-radius.js`](mishkan-blast-radius.js) | Graphify discovery + 3-lens orthogonal verify + synthesis | "What does this change actually touch?" Refactor blast-radius with three load-bearing lenses (caller-side / data-contract / runtime-behavior) so false positives drop before scheduling | Before editing a function whose downstream impact is uncertain; gated by `/plan` |
|
|
25
|
+
| [`mishkan-knowledge-gap-discovery.js`](mishkan-knowledge-gap-discovery.js) | parallel probe + **loop-until-dry** + research fan-out | Probe Cognee work for expected concepts; the only candidate that legitimately needs loop-until-X — confirm gaps via paraphrase retries before dispatching research | Sprint close (optional barrier step) or after `/sefer-pull` |
|
|
26
|
+
| [`mishkan-standards-rollout.js`](mishkan-standards-rollout.js) | pipeline (translate → verify) + barrier + judge panel (Bezalel + scope-conditional reviewers) | When a new rule lands in `y4nn-standards.md`, it propagates per-team with translation, drift verification, and CTO ratification — closes the silent failure mode of rules drift | When a new standard ships; BEFORE the rule is considered live across the fleet |
|
|
23
27
|
|
|
24
28
|
## The patterns each script uses
|
|
25
29
|
|
|
26
30
|
| Pattern | Used by |
|
|
27
31
|
|---|---|
|
|
28
|
-
| Fan-out → synthesize | `codebase-audit`, `release-readiness`, `architecture-panel` |
|
|
29
|
-
| Pipeline (overlapping) | `deep-research`, `migration-wave`, `init` |
|
|
30
|
-
| Barrier `parallel()` | `sprint-close`, `release-readiness`, `architecture-panel` (Vote stage) |
|
|
32
|
+
| Fan-out → synthesize | `codebase-audit`, `release-readiness`, `architecture-panel`, `blast-radius` |
|
|
33
|
+
| Pipeline (overlapping) | `deep-research`, `migration-wave`, `init`, `standards-rollout` |
|
|
34
|
+
| Barrier `parallel()` | `sprint-close`, `release-readiness`, `architecture-panel` (Vote stage), `knowledge-gap-discovery`, `standards-rollout` |
|
|
31
35
|
| Adversarial verification (3-vote refute) | `deep-research`, `codebase-audit` |
|
|
32
|
-
|
|
|
36
|
+
| Orthogonal 3-lens verify (caller / data / runtime) | `blast-radius` |
|
|
37
|
+
| Judge panel | `architecture-panel`, `migration-wave` (2-reviewer accept), `standards-rollout` (Bezalel + scope-conditional) |
|
|
33
38
|
| Nested workflow | `release-readiness` → `codebase-audit` |
|
|
34
|
-
| Loop-until-X |
|
|
39
|
+
| Loop-until-X | `knowledge-gap-discovery` (paraphrase-retries to confirm gaps before research) |
|
|
40
|
+
|
|
41
|
+
## Team-level catalogue
|
|
42
|
+
|
|
43
|
+
Eight team-level workflows codified per ADR D-010 (cap 4/team, PM+CTO
|
|
44
|
+
co-owned). Invoked through the Team Lead's craft skill.
|
|
45
|
+
|
|
46
|
+
| Script | Pattern combo | Real problem it solves | Team |
|
|
47
|
+
|---|---|---|---|
|
|
48
|
+
| [`chosheb-feature-ship.js`](chosheb-feature-ship.js) | barrier + synthesis | Design → handoff package complete (DS fit + a11y + assets + QA) | Chosheb |
|
|
49
|
+
| [`panim-ds-rollout.js`](panim-ds-rollout.js) | pipeline + worktree + judge panel | Design token change propagated to all consumers with a11y + regression review | Panim |
|
|
50
|
+
| [`yasad-data-migration-wave.js`](yasad-data-migration-wave.js) | pipeline + 4-lens judge panel | Wave of DB migrations, per-table reviewed (contracts/perf/security/tests) | Yasad |
|
|
51
|
+
| [`yasad-schema-evolution.js`](yasad-schema-evolution.js) | pipeline + per-phase judge panel | Phased schema change with zero-downtime invariants + per-phase rollback | Yasad |
|
|
52
|
+
| [`mishmar-security-gate.js`](mishmar-security-gate.js) | barrier + 3-vote adversarial refute | Security gate on sensitive surface (auth/payment/PII), 3 orthogonal lenses | Mishmar |
|
|
53
|
+
| [`migdal-infra-change.js`](migdal-infra-change.js) | barrier + 5-lens panel | Infra change validated by design/systems/devops/observability/health lenses | Migdal |
|
|
54
|
+
| [`migdal-dr-drill.js`](migdal-dr-drill.js) | pipeline + per-step judge panel | DR drill — enumerate, simulate, verify, RTO/RPO measurement, gap report | Migdal |
|
|
55
|
+
| [`sefer-release-notes.js`](sefer-release-notes.js) | pipeline + per-category fan-out + style synthesis | Release notes assembled from git log per category with style-guide application | Sefer |
|
|
56
|
+
|
|
57
|
+
Spare slots (Chosheb 3, Panim 3, Yasad 2, Mishmar 3, Migdal 2, Sefer 3)
|
|
58
|
+
are deliberately open; candidates compete for them at PM+CTO review.
|
|
59
|
+
|
|
60
|
+
## Portfolio governance — D-010
|
|
61
|
+
|
|
62
|
+
The portfolio is **PM + CTO co-owned** with hard caps and an anti-pattern
|
|
63
|
+
canon (ADR D-010, 2026-06-07). Nehemiah owns scope, delivery, recurrence
|
|
64
|
+
justification; Bezalel owns orchestration shape, schema contracts, quality
|
|
65
|
+
bar. New workflows land through joint review — not ad hoc.
|
|
66
|
+
|
|
67
|
+
**Hard caps.** 10 org-level (full) + 4 per team (varies). To add, retire.
|
|
68
|
+
**Soft retirement.** Workflows that fire < 2× in 3 sprints surface at
|
|
69
|
+
`/sprint-close` for PM+CTO retirement vote; default is `workflows/proposed/`.
|
|
70
|
+
|
|
71
|
+
The June 2026 portfolio review produced the org-level additions
|
|
72
|
+
(`blast-radius`, `knowledge-gap-discovery`, `standards-rollout`), the
|
|
73
|
+
org-level removal (`multi-perspective-review` was theatre vs the existing
|
|
74
|
+
`architecture-panel`), the eight team-level workflows above, and the
|
|
75
|
+
anti-patterns below.
|
|
76
|
+
|
|
77
|
+
### Anti-patterns to avoid (D-010)
|
|
78
|
+
|
|
79
|
+
1. **Skill-in-workflow-clothing.** Linear sequence, no parallelism, no
|
|
80
|
+
termination predicate, no panel — that's a skill, not a workflow.
|
|
81
|
+
2. **Workflow calling workflow without a contract.** Nested workflows
|
|
82
|
+
are valid (cf. `release-readiness` → `codebase-audit`) only when the
|
|
83
|
+
inner workflow's output schema is consumed structurally. Free-form
|
|
84
|
+
nesting hides token cost and breaks retry semantics.
|
|
85
|
+
3. **Judge panels with non-orthogonal reviewers.** If two reviewers in
|
|
86
|
+
a panel share 70%+ of their evaluation criteria, the panel is
|
|
87
|
+
theatre. Each lens must be load-bearing and distinct (`blast-radius`
|
|
88
|
+
enforces this with caller-side / data-contract / runtime-behavior).
|
|
89
|
+
4. **Workflow-as-status-page.** Orchestration that fans out to gather
|
|
90
|
+
state without synthesis is a dashboard query, not a workflow. If the
|
|
91
|
+
synthesis stage is missing or trivial, the work belongs in
|
|
92
|
+
observability, not in `Workflow()`.
|
|
35
93
|
|
|
36
94
|
## Cost discipline
|
|
37
95
|
|
|
38
96
|
Workflows are expensive. The community baseline is **3–6 workflows per
|
|
39
|
-
production team**.
|
|
40
|
-
|
|
41
|
-
|
|
97
|
+
production team**. The MISHKAN hard cap is **10 org-level + 4 per team**
|
|
98
|
+
(current count: 10 org + 8 team across 6 teams = 18 total). Adding more
|
|
99
|
+
typically means either (a) the new use case is better served by Task
|
|
100
|
+
delegation or a skill, or (b) an existing workflow should be retired —
|
|
101
|
+
soft-retirement happens after a workflow fires < 2× across 3 sprints,
|
|
102
|
+
under PM+CTO review.
|
|
42
103
|
|
|
43
104
|
Cost expectations per run (subagent-tokens, rough orders of
|
|
44
105
|
magnitude):
|
|
@@ -52,6 +113,9 @@ magnitude):
|
|
|
52
113
|
| `mishkan-architecture-panel` | medium | 3 proposals × 3 reviewers + synthesis |
|
|
53
114
|
| `mishkan-release-readiness` | low-medium | 7–8 parallel checks; nested audit if enabled |
|
|
54
115
|
| `mishkan-init` | medium | 6 artefacts pipelined |
|
|
116
|
+
| `mishkan-blast-radius` | medium | `sites × 3 lenses` + discovery + synthesis; short-circuits on empty graph |
|
|
117
|
+
| `mishkan-knowledge-gap-discovery` | medium-high | probe × N concepts + loop-until-dry rephrasings + research fan-out per gap |
|
|
118
|
+
| `mishkan-standards-rollout` | low-medium | 6 translations + 6 verifications + 1-3 ratifiers (scope-conditional) |
|
|
55
119
|
|
|
56
120
|
Run on a small slice first (one directory; one phase) before
|
|
57
121
|
committing to a full wave.
|
|
@@ -76,8 +140,9 @@ Don't, unless:
|
|
|
76
140
|
3. The repeatability is real (same orchestration each time, just different inputs).
|
|
77
141
|
|
|
78
142
|
Otherwise: Task fan-out from the main session is the right answer.
|
|
79
|
-
The
|
|
80
|
-
all three bars
|
|
143
|
+
The 10 org-level + 8 team-level workflows above were picked precisely
|
|
144
|
+
because each clears all three bars; the portfolio is capped at 10 + 4
|
|
145
|
+
per team per ADR D-010.
|
|
81
146
|
|
|
82
147
|
## Constraints (reminders)
|
|
83
148
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// chosheb-feature-ship — design → handoff package complete to Panim.
|
|
2
|
+
//
|
|
3
|
+
// A Figma / design intent + feature context goes in; a complete handoff
|
|
4
|
+
// package comes out: design system fit, a11y/SEO audit, asset exports,
|
|
5
|
+
// QA visual matrix. Replaces the back-and-forth ping-pong that currently
|
|
6
|
+
// burns 2-3 days per feature.
|
|
7
|
+
//
|
|
8
|
+
// Pattern: barrier `parallel()` per dimension + synthesis.
|
|
9
|
+
// Per ADR D-010 anti-pattern check:
|
|
10
|
+
// - skill-in-workflow-clothing: no — 4 dimensions in parallel, panel.
|
|
11
|
+
// - workflow-calling-workflow-without-contract: no — no nesting.
|
|
12
|
+
// - non-orthogonal panel: no — DS-fit / a11y / assets / QA are distinct
|
|
13
|
+
// evaluation domains.
|
|
14
|
+
// - workflow-as-status-page: no — synthesis stage produces handoff doc.
|
|
15
|
+
|
|
16
|
+
export const meta = {
|
|
17
|
+
name: "chosheb-feature-ship",
|
|
18
|
+
description: "Design → complete handoff package for Panim (DS fit + a11y + assets + QA).",
|
|
19
|
+
whenToUse: "When Chosheb has a converged design and Huram needs to start implementation.",
|
|
20
|
+
phases: [{ title: "Audit" }, { title: "Package" }],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const design = args?.design_ref;
|
|
24
|
+
const feature = args?.feature_context;
|
|
25
|
+
if (!design) throw new Error("args.design_ref is required (Figma URL / asset path)");
|
|
26
|
+
if (!feature) throw new Error("args.feature_context is required (1-paragraph feature description)");
|
|
27
|
+
|
|
28
|
+
const AUDIT_SCHEMA = {
|
|
29
|
+
type: "object",
|
|
30
|
+
required: ["ready", "blockers"],
|
|
31
|
+
properties: {
|
|
32
|
+
ready: { type: "boolean" },
|
|
33
|
+
blockers: { type: "array", items: { type: "string" } },
|
|
34
|
+
deliverables: { type: "array", items: { type: "string" } },
|
|
35
|
+
notes: { type: "string" },
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
phase("Audit");
|
|
40
|
+
const LENSES = [
|
|
41
|
+
{ key: "ds-fit", agent: "aholiab", prompt: "Design system fit: does this design reuse existing tokens / components / patterns? List net-new additions to the DS." },
|
|
42
|
+
{ key: "a11y", agent: "asaph", prompt: "Accessibility + SEO audit: contrast ratios, keyboard flow, ARIA needs, semantic structure, meta requirements." },
|
|
43
|
+
{ key: "assets", agent: "obed", prompt: "Asset preparation: list required exports (svg/png/webp per breakpoint), sizes, naming, optimisation notes." },
|
|
44
|
+
{ key: "qa", agent: "jahaziel", prompt: "Visual QA matrix: states (default/hover/active/disabled/error), breakpoints, edge cases, browser/device coverage." },
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const audits = await parallel(LENSES.map(L => () =>
|
|
48
|
+
agent(
|
|
49
|
+
`Feature: ${feature}\nDesign: ${design}\nYour lens: ${L.prompt}\nReturn the schema.`,
|
|
50
|
+
{ schema: AUDIT_SCHEMA, label: `audit:${L.key}`, agentType: L.agent, phase: "Audit" },
|
|
51
|
+
).then(a => ({ ...L, ...a }))
|
|
52
|
+
));
|
|
53
|
+
|
|
54
|
+
const valid = audits.filter(Boolean);
|
|
55
|
+
const allBlockers = valid.flatMap(a => a.blockers ?? []);
|
|
56
|
+
const allReady = valid.every(a => a.ready);
|
|
57
|
+
|
|
58
|
+
phase("Package");
|
|
59
|
+
const handoff = await agent(
|
|
60
|
+
`Chosheb → Panim handoff package. Feature: ${feature}. Audits: ${JSON.stringify(valid.map(a => ({lens: a.key, ready: a.ready, deliverables: a.deliverables, notes: a.notes})))}. ` +
|
|
61
|
+
`Produce a structured handoff document: design summary, DS additions list, a11y checklist, asset manifest, QA matrix, open questions. Markdown.`,
|
|
62
|
+
{ label: "package-handoff", agentType: "aholiab", phase: "Package" },
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
feature_context: feature,
|
|
67
|
+
design_ref: design,
|
|
68
|
+
audits: valid,
|
|
69
|
+
ready_to_ship: allReady,
|
|
70
|
+
blockers: allBlockers,
|
|
71
|
+
handoff_document: handoff,
|
|
72
|
+
summary: allReady
|
|
73
|
+
? `Handoff package ready. ${valid.length}/4 lenses passed. Hand to Huram (Panim).`
|
|
74
|
+
: `Handoff BLOCKED. ${allBlockers.length} blockers across ${valid.length} lenses. Resolve before handoff.`,
|
|
75
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// migdal-dr-drill — disaster recovery drill orchestration.
|
|
2
|
+
//
|
|
3
|
+
// A DR scenario (region loss, DB corruption, secret leak, control-plane
|
|
4
|
+
// outage) is specified; the workflow orchestrates the drill: enumerate
|
|
5
|
+
// recovery steps, simulate per step, verify each via independent observer,
|
|
6
|
+
// measure RTO/RPO against target. Synthesises a drill report with gaps.
|
|
7
|
+
//
|
|
8
|
+
// Pattern: pipeline (enumerate → simulate → verify) + barrier + judge panel.
|
|
9
|
+
// ADR D-010 check:
|
|
10
|
+
// - parallelism: simulation step × independent observer per step.
|
|
11
|
+
// - panel orthogonality: Palal (systems-level recovery) + Hanun (operational
|
|
12
|
+
// observability during drill) + Rehum (health/safety post-recovery).
|
|
13
|
+
// - synthesis: RTO/RPO measurement + gap list.
|
|
14
|
+
|
|
15
|
+
export const meta = {
|
|
16
|
+
name: "migdal-dr-drill",
|
|
17
|
+
description: "Disaster recovery drill — enumerate steps, simulate, verify, measure RTO/RPO, report gaps.",
|
|
18
|
+
whenToUse: "Quarterly DR exercise, or after any infra change that affects recovery topology.",
|
|
19
|
+
phases: [{ title: "Plan" }, { title: "Simulate" }, { title: "Report" }],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const scenario = args?.scenario;
|
|
23
|
+
const rtoTarget = args?.rto_target_minutes ?? 30;
|
|
24
|
+
const rpoTarget = args?.rpo_target_minutes ?? 5;
|
|
25
|
+
const project = args?.project ?? ".";
|
|
26
|
+
if (!scenario) throw new Error("args.scenario is required (e.g. 'primary-region-loss' | 'db-corruption' | 'secret-leak')");
|
|
27
|
+
|
|
28
|
+
const PLAN_SCHEMA = {
|
|
29
|
+
type: "object", required: ["steps"],
|
|
30
|
+
properties: { steps: { type: "array", items: { type: "object", required: ["order", "action", "expected_outcome"], properties: { order:{type:"integer"}, action:{type:"string"}, expected_outcome:{type:"string"}, depends_on:{type:"array", items:{type:"integer"}} } } } },
|
|
31
|
+
};
|
|
32
|
+
const VERIFY_SCHEMA = {
|
|
33
|
+
type: "object", required: ["verified", "rationale"],
|
|
34
|
+
properties: { verified:{type:"boolean"}, rationale:{type:"string"}, gap:{type:"string"}, time_estimate_minutes:{type:"number"} },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
phase("Plan");
|
|
38
|
+
const plan = await agent(
|
|
39
|
+
`DR scenario: ${scenario}. Project: ${project}. RTO target: ${rtoTarget}min, RPO target: ${rpoTarget}min. Enumerate the recovery steps in order with dependencies. Return the schema.`,
|
|
40
|
+
{ schema: PLAN_SCHEMA, label: "plan-recovery", agentType: "palal" },
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const steps = plan?.steps ?? [];
|
|
44
|
+
log(`DR plan: ${steps.length} recovery steps.`);
|
|
45
|
+
|
|
46
|
+
phase("Simulate");
|
|
47
|
+
const OBSERVERS = [
|
|
48
|
+
{ key: "systems", agent: "palal", prompt: "Systems lens: does this step actually recover the targeted system? Hidden dependencies?" },
|
|
49
|
+
{ key: "ops", agent: "hanun", prompt: "Operations lens: are the runbooks ready, secrets accessible, on-call awake, monitoring live during this step?" },
|
|
50
|
+
{ key: "health", agent: "rehum", prompt: "Health lens: post-step health checks, data-integrity probes, success criteria. Is the system actually healthy after?" },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const simulated = await parallel(steps.map(S => () =>
|
|
54
|
+
parallel(OBSERVERS.map(O => () =>
|
|
55
|
+
agent(
|
|
56
|
+
`DR scenario: ${scenario}. Step ${S.order}: ${S.action} (expected: ${S.expected_outcome}). Your lens: ${O.prompt} Default verified=false if uncertain.`,
|
|
57
|
+
{ schema: VERIFY_SCHEMA, label: `simulate:${O.key}:step${S.order}`, agentType: O.agent, phase: "Simulate" },
|
|
58
|
+
)
|
|
59
|
+
)).then(verdicts => {
|
|
60
|
+
const valid = verdicts.filter(Boolean);
|
|
61
|
+
const verifiedCount = valid.filter(v => v.verified).length;
|
|
62
|
+
const times = valid.map(v => v.time_estimate_minutes ?? 0).filter(t => t > 0);
|
|
63
|
+
const meanTime = times.length ? times.reduce((a,b)=>a+b, 0) / times.length : 0;
|
|
64
|
+
return { step: S, verdicts: valid, verified_count: verifiedCount, all_verified: verifiedCount === OBSERVERS.length, gaps: valid.map(v => v.gap).filter(Boolean), time_minutes: meanTime };
|
|
65
|
+
})
|
|
66
|
+
));
|
|
67
|
+
|
|
68
|
+
phase("Report");
|
|
69
|
+
const totalTime = simulated.reduce((a, s) => a + (s.time_minutes ?? 0), 0);
|
|
70
|
+
const allGaps = simulated.flatMap(s => s.gaps);
|
|
71
|
+
const failedSteps = simulated.filter(s => !s.all_verified);
|
|
72
|
+
|
|
73
|
+
const rtoMet = totalTime <= rtoTarget;
|
|
74
|
+
const passes = failedSteps.length === 0;
|
|
75
|
+
|
|
76
|
+
const report = await agent(
|
|
77
|
+
`DR drill report. Scenario: ${scenario}. ${steps.length} steps, ${failedSteps.length} failed verification. Estimated RTO: ${totalTime.toFixed(1)}min vs target ${rtoTarget}min. Gaps: ${JSON.stringify(allGaps)}. Produce a markdown report: executive summary, per-step status, gap remediation list.`,
|
|
78
|
+
{ label: "produce-report", agentType: "rehum", phase: "Report" },
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
scenario,
|
|
83
|
+
rto_target_minutes: rtoTarget,
|
|
84
|
+
rto_estimate_minutes: totalTime,
|
|
85
|
+
rto_met: rtoMet,
|
|
86
|
+
steps_total: steps.length,
|
|
87
|
+
steps_passed: simulated.filter(s => s.all_verified).length,
|
|
88
|
+
gaps: allGaps,
|
|
89
|
+
report,
|
|
90
|
+
decision: passes && rtoMet ? "ready" : "not-ready",
|
|
91
|
+
summary: passes && rtoMet
|
|
92
|
+
? `DR drill PASS. ${steps.length}/${steps.length} steps verified. RTO ${totalTime.toFixed(1)}min ≤ ${rtoTarget}min target.`
|
|
93
|
+
: `DR drill FAIL. ${failedSteps.length} unverified steps${rtoMet ? "" : `, RTO ${totalTime.toFixed(1)}min > ${rtoTarget}min target`}. ${allGaps.length} gaps to address.`,
|
|
94
|
+
};
|