@synap-core/workspace-templates 0.12.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +483 -0
- package/automations/bookmark-enrichment.automation.json +321 -0
- package/automations/github-pr-events.automation.json +505 -0
- package/automations/mail-feed.automation.json +86 -0
- package/automations/ship-a-change-checks-green.automation.json +106 -0
- package/automations/ship-a-change-checks-red.automation.json +106 -0
- package/automations/ship-a-change-deployed.automation.json +56 -0
- package/automations/ship-a-change-pr-merged.automation.json +110 -0
- package/automations/ship-a-change-pr-opened.automation.json +104 -0
- package/automations/url-bookmark-capture.automation.json +132 -0
- package/capabilities/agency-skills.capability.json +157 -0
- package/capabilities/apify.capability.json +265 -0
- package/capabilities/apollo.capability.json +120 -0
- package/capabilities/arch-backend.capability.json +97 -0
- package/capabilities/arch-client-intelligence.capability.json +401 -0
- package/capabilities/backblaze-b2.capability.json +205 -0
- package/capabilities/cal-com.capability.json +266 -0
- package/capabilities/canva.capability.json +274 -0
- package/capabilities/claude-code-routines.capability.json +172 -0
- package/capabilities/claude-managed-agents.capability.json +215 -0
- package/capabilities/client-comms-report.capability.json +246 -0
- package/capabilities/content-idea-to-production.capability.json +29 -0
- package/capabilities/datagouv.capability.json +315 -0
- package/capabilities/discord-bot.capability.json +157 -0
- package/capabilities/dropbox.capability.json +281 -0
- package/capabilities/exa.capability.json +109 -0
- package/capabilities/fal-ai.capability.json +83 -0
- package/capabilities/fal-media-lab.capability.json +158 -0
- package/capabilities/fireflies.capability.json +191 -0
- package/capabilities/freellmapi.capability.json +114 -0
- package/capabilities/generic-apikey.capability.json +92 -0
- package/capabilities/github-merge.capability.json +99 -0
- package/capabilities/github-read.capability.json +325 -0
- package/capabilities/governance-tighten-recommender.capability.json +81 -0
- package/capabilities/jev.capability.json +226 -0
- package/capabilities/lead-conversion-enrollment.capability.json +246 -0
- package/capabilities/mail-feed.capability.json +277 -0
- package/capabilities/mailgun.capability.json +52 -0
- package/capabilities/nango-google.capability.json +639 -0
- package/capabilities/notion.capability.json +417 -0
- package/capabilities/omniroute.capability.json +137 -0
- package/capabilities/posthog-analytics.capability.json +258 -0
- package/capabilities/postiz.capability.json +467 -0
- package/capabilities/proactive-digest.capability.json +190 -0
- package/capabilities/proton.capability.json +288 -0
- package/capabilities/replicate-rvm.capability.json +97 -0
- package/capabilities/research-methods.capability.json +57 -0
- package/capabilities/shopify.capability.json +395 -0
- package/capabilities/slack.capability.json +369 -0
- package/capabilities/stripe.capability.json +420 -0
- package/capabilities/telegram-bridge.capability.json +56 -0
- package/capabilities/treg.capability.json +102 -0
- package/capabilities/unipile-linkedin.capability.json +471 -0
- package/capabilities/vercel.capability.json +424 -0
- package/dist/define-CPS0n8BV.d.ts +1331 -0
- package/dist/index.d.ts +174 -900
- package/dist/index.js +26148 -23931
- package/dist/index.js.map +1 -1
- package/dist/wire.d.ts +222 -0
- package/dist/wire.js +77 -0
- package/dist/wire.js.map +1 -0
- package/package.json +27 -4
- package/packs/bookmark-views-pack.json +33 -0
- package/packs/crm-pack.json +76 -0
- package/packs/customer-profile.json +28 -0
- package/packs/deep-research.playbook.json +30 -0
- package/packs/event-views-pack.json +33 -0
- package/packs/habit-profile.json +27 -0
- package/packs/hr-pack.json +54 -0
- package/packs/invoice-profile.json +28 -0
- package/packs/knowledge-base-pack.json +56 -0
- package/packs/meeting-profile.json +29 -0
- package/packs/product-profile.json +30 -0
- package/packs/project-management-pack.json +49 -0
- package/packs/recipe-profile.json +29 -0
- package/packs/task-views-pack.json +39 -0
- package/retired.yaml +136 -0
- package/skills/app-factory-build-slice/SKILL.md +70 -0
- package/skills/app-factory-build-slice.catalog.json +17 -0
- package/skills/app-factory-design-canvas/SKILL.md +96 -0
- package/skills/app-factory-design-canvas.catalog.json +17 -0
- package/skills/app-factory-design-review/SKILL.md +99 -0
- package/skills/app-factory-design-review.catalog.json +18 -0
- package/skills/app-factory-research/SKILL.md +123 -0
- package/skills/app-factory-research.catalog.json +17 -0
- package/skills/bookmark-enrichment/SKILL.md +40 -0
- package/skills/carousel-format/carousel-format.skill.json +18 -0
- package/skills/collage-broll/collage-broll.skill.json +20 -0
- package/skills/content-taste/content-taste.skill.json +18 -0
- package/skills/creative-director/creative-director.skill.json +18 -0
- package/skills/design-critique/SKILL.md +135 -0
- package/skills/design-critique.catalog.json +12 -0
- package/skills/designing-with-real-components/SKILL.md +140 -0
- package/skills/designing-with-real-components.catalog.json +12 -0
- package/skills/edit-loop/edit-loop.skill.json +25 -0
- package/skills/facecam-edit/facecam-edit.skill.json +24 -0
- package/skills/mapping-the-server/SKILL.md +54 -0
- package/skills/math-explainer-manimgx/math-explainer-manimgx.skill.json +20 -0
- package/skills/motion-quality-gates/motion-quality-gates.skill.json +20 -0
- package/skills/open-design-edit/open-design-edit.skill.json +24 -0
- package/skills/reading-client-progress/SKILL.md +65 -0
- package/skills/routing-to-channels/SKILL.md +54 -0
- package/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
- package/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
- package/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
- package/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
- package/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
- package/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
- package/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
- package/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
- package/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
- package/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
- package/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
- package/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
- package/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
- package/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
- package/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
- package/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
- package/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
- package/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
- package/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
- package/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
- package/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
- package/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
- package/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
- package/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
- package/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
- package/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
- package/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
- package/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
- package/skills/video-direction/video-direction.skill.json +20 -0
- package/skills/video-style-vocabulary/video-style-vocabulary.skill.json +20 -0
- package/skills/video-toolbox/video-toolbox.skill.json +20 -0
- package/src/__fixtures__/lifecycle-presets.flat-before.json +205 -0
- package/src/agency-os.yaml +122 -0
- package/src/agent-os-skill-slugs.test.ts +65 -0
- package/src/apify-social-reader.test.ts +317 -0
- package/src/base.yaml +85 -39
- package/src/blockchain-ecosystem.yaml +1 -0
- package/src/brand-library.yaml +525 -14
- package/src/builder-dev-fold.template.test.ts +113 -0
- package/src/builder.yaml +779 -91
- package/src/business-model-catalog-description.test.ts +47 -0
- package/src/business-model-grp.template.test.ts +214 -0
- package/src/business-model.yaml +296 -49
- package/src/catalog-safety.test.ts +198 -0
- package/src/catalog.template-items.test.ts +75 -0
- package/src/catalog.ts +66 -2
- package/src/concept-guard.test.ts +28 -8
- package/src/concept-guard.ts +2 -2
- package/src/content-creation.template.test.ts +52 -0
- package/src/content-creation.yaml +192 -0
- package/src/content-os.edit-loop.template.test.ts +210 -0
- package/src/content-os.publish-due-posts.template.test.ts +261 -0
- package/src/content-os.template.test.ts +322 -0
- package/src/content-os.video-takes.template.test.ts +338 -0
- package/src/content-os.work-a-take.template.test.ts +125 -0
- package/src/content-os.yaml +1830 -39
- package/src/content-studio-retired.template.test.ts +82 -0
- package/src/corpus-flow-validity.test.ts +4 -5
- package/src/crm-absorbs-outreach.template.test.ts +117 -0
- package/src/crm-build-plan.template.test.ts +128 -0
- package/src/crm-lists.template.test.ts +96 -0
- package/src/crm-messages-cadence.template.test.ts +164 -0
- package/src/crm-one-send-door.template.test.ts +65 -0
- package/src/crm.yaml +1456 -181
- package/src/decisions-wave.template.test.ts +186 -0
- package/src/define.ts +130 -17
- package/src/design-to-implementation.template.test.ts +94 -0
- package/src/domain-template-type.test.ts +75 -0
- package/src/ecosystem.yaml +27 -66
- package/src/enterprise-os.yaml +10 -134
- package/src/facecam-edit.audio-studio.test.ts +188 -0
- package/src/fal-generate-image.test.ts +200 -0
- package/src/fal-media-lab-pod-files.test.ts +180 -0
- package/src/finance.yaml +254 -1
- package/src/foundation.yaml +78 -38
- package/src/frame-host-modules.d.mts +6 -0
- package/src/frame-host-modules.mjs +58 -0
- package/src/generate.mjs +9 -3
- package/src/github-merge.test.ts +210 -0
- package/src/grants.yaml +46 -17
- package/src/hr.yaml +39 -6
- package/src/index.ts +36 -1
- package/src/intent.test.ts +161 -0
- package/src/internal-runbook.yaml +19 -1
- package/src/jev.test.ts +356 -0
- package/src/legal.yaml +33 -1
- package/src/life-os.yaml +51 -240
- package/src/lifecycle-coverage.test.ts +124 -0
- package/src/lifecycle-declarations.test.ts +252 -0
- package/src/lifecycle-presets.test.ts +468 -0
- package/src/lifecycle-presets.ts +494 -0
- package/src/lifecycle-stuck.test.ts +46 -0
- package/src/lifecycle-waits.parity.test.ts +319 -0
- package/src/marketing.yaml +108 -4
- package/src/meetings-knowledge.yaml +18 -0
- package/src/networking.yaml +23 -2
- package/src/operations.yaml +304 -4
- package/src/pipeline-views.template.test.ts +88 -0
- package/src/playbook-goal-placeholders.test.ts +57 -0
- package/src/postiz-contract.test.ts +134 -0
- package/src/presentation-declarations.test.ts +174 -0
- package/src/process-contract.validate.test.ts +352 -0
- package/src/project-management.yaml +39 -740
- package/src/publish-body.d.mts +29 -0
- package/src/publish-body.mjs +74 -0
- package/src/publish-body.test.ts +74 -0
- package/src/publish-official-lib.test.ts +176 -0
- package/src/replicate-rvm.test.ts +504 -0
- package/src/research-base.yaml +119 -20
- package/src/research-decision.yaml +60 -3
- package/src/reserved-profile-slugs.test.ts +83 -0
- package/src/retired-goal-kinds.test.ts +58 -0
- package/src/role-reference-and-step-domain.test.ts +192 -0
- package/src/seed-obligation.test.ts +1 -6
- package/src/send-message-maps.test.ts +227 -0
- package/src/shared-role-ssot.test.ts +40 -2
- package/src/ship-a-change.template.test.ts +177 -0
- package/src/skills.test.ts +170 -0
- package/src/social.yaml +85 -27
- package/src/space-packages.freshness.test.ts +97 -0
- package/src/space-packages.generated.ts +40 -0
- package/src/space-packages.test.ts +125 -0
- package/src/space-packages.ts +73 -0
- package/src/start.test.ts +188 -0
- package/src/task-intents.test.ts +293 -0
- package/src/templates.ts +20851 -21496
- package/src/types.ts +443 -60
- package/src/unipile-publish-post.test.ts +162 -0
- package/src/validate-flow.drift.test.ts +2 -3
- package/src/validate-flow.ts +22 -2
- package/src/validate-onboarding.test.ts +59 -0
- package/src/validate.test.ts +71 -4
- package/src/validate.ts +1335 -7
- package/src/wire-core.ts +231 -0
- package/src/wire.test.ts +159 -0
- package/src/wire.ts +107 -0
- package/src/agent-fleet.yaml +0 -1645
- package/src/business-developer.template.test.ts +0 -351
- package/src/business-developer.yaml +0 -860
- package/src/content-studio.yaml +0 -361
- package/src/dev-dashboard.yaml +0 -990
- package/src/outreach-comms.yaml +0 -486
- package/src/the-arch.yaml +0 -201
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Business Model package is LISTED as what it is: a track template.
|
|
3
|
+
*
|
|
4
|
+
* GRP agent-XP diagnosis 2026-09-28: CP `market_search` served the package as
|
|
5
|
+
* "Foundation" / "Adds business-model interrogation to the strategic
|
|
6
|
+
* substrate…" — the overlay TARGET's workspace name and description — so an
|
|
7
|
+
* agent looking for "the business-model method" never learned it runs as a
|
|
8
|
+
* track on a project. The peer fix took displayName from `meta.name`; this
|
|
9
|
+
* pins the other half: the catalog description is the package's own
|
|
10
|
+
* `meta.description`, and it names the track template.
|
|
11
|
+
*
|
|
12
|
+
* Does NOT cover: what an already-published CP row says (needs a publish).
|
|
13
|
+
*/
|
|
14
|
+
import { describe, expect, it } from "vitest";
|
|
15
|
+
import { getWorkspaceTemplate, toPackageDefinition } from "./index.js";
|
|
16
|
+
import { toOfficialPublishBody } from "./publish-body.mjs";
|
|
17
|
+
|
|
18
|
+
describe("business-model catalog text", () => {
|
|
19
|
+
const tpl = getWorkspaceTemplate("business-model")!;
|
|
20
|
+
const pd = toPackageDefinition("business-model");
|
|
21
|
+
|
|
22
|
+
it("meta.description names the track template the pack ships", () => {
|
|
23
|
+
const track = (tpl.playbooks ?? []).find(
|
|
24
|
+
(p) => (p as { scope?: string }).scope === "project"
|
|
25
|
+
);
|
|
26
|
+
expect(track?.name, "the pack ships a project-scoped playbook").toBeTruthy();
|
|
27
|
+
expect(tpl.meta.description).toContain(`${track!.name}:`);
|
|
28
|
+
expect(tpl.meta.description).toMatch(/track template you run on a project/);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("the package definition carries meta.description beside the workspace's own", () => {
|
|
32
|
+
expect(pd._meta.description).toBe(tpl.meta.description);
|
|
33
|
+
// The install copy stays the workspace's description — only the listing changes.
|
|
34
|
+
expect(pd.description).toBe(tpl.workspace.description);
|
|
35
|
+
expect(pd._meta.description).not.toBe(pd.description);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("the official publisher lists the package's description, not the overlay target's", () => {
|
|
39
|
+
// Behavioural: the REAL body builder publish-official.mjs calls (it used to
|
|
40
|
+
// be a source-regex over the script, which broke the moment the builder
|
|
41
|
+
// moved into src/publish-body.mjs).
|
|
42
|
+
const body = toOfficialPublishBody(pd, "vendor-x");
|
|
43
|
+
expect(body.description).toBe(tpl.meta.description);
|
|
44
|
+
expect(body.description).not.toBe(pd.description);
|
|
45
|
+
expect(body.displayName).toBe(tpl.meta.name);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* business-model.yaml IS the canonical GRP (concept consolidation W4a;
|
|
3
|
+
* seed set switched by founder decision A, 2026-09-28).
|
|
4
|
+
*
|
|
5
|
+
* GRP = Génération · Rémunération · Partage. The nine seeded questions are the
|
|
6
|
+
* founder's LIVE pod-level set (workspaceId NULL, tags grp/method-question),
|
|
7
|
+
* read from the pod on 2026-09-28 and pinned below — NOT the later "GRP #1 … #9"
|
|
8
|
+
* set W4a first copied. That list is the evidence, not a convenience: the seed
|
|
9
|
+
* dedupe key is `${kind}:${title}` (services/definition-seeds.ts, target
|
|
10
|
+
* workspace OR the user's pod-wide rows), so a reworded title seeds a SECOND set
|
|
11
|
+
* beside the live one instead of adopting it. If the founder renames a live
|
|
12
|
+
* question, this list and the YAML move together.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, expect, it } from "vitest";
|
|
16
|
+
import { WORKSPACE_TEMPLATES } from "./templates.js";
|
|
17
|
+
import type { TemplatePlaybook } from "./types.js";
|
|
18
|
+
|
|
19
|
+
const bm = WORKSPACE_TEMPLATES["business-model"]!;
|
|
20
|
+
|
|
21
|
+
const P = "Porteur — what does the founder bring that cannot be hired, and what does the venture require of them personally?";
|
|
22
|
+
const VP = "Value proposition — for whom is this indispensable, and what do they stop doing once they have it?";
|
|
23
|
+
const VF = "Value fabrication — what is the chain that actually produces the value, and which link do we own?";
|
|
24
|
+
const RS = "Revenue sources — who pays, for which unit, and why that unit rather than another?";
|
|
25
|
+
const VAP = "Volume and pricing — what volume at what price clears the cost base, and is that volume reachable in this market?";
|
|
26
|
+
const PF = "Performance — which number tells us the model works, and what observation would falsify it?";
|
|
27
|
+
const ST = "Stakeholders — who must say yes for this to exist, and what does each of them need in return?";
|
|
28
|
+
const CV = "Conventions — which rules bind us, who enforces them, and which are mandatory rather than advisory?";
|
|
29
|
+
const EC = "Ecosystem — what does the venture give back, and what breaks if we extract without returning?";
|
|
30
|
+
|
|
31
|
+
/** Live title → its pillar (the live tag) and the method step that answers it. */
|
|
32
|
+
const LIVE_GRP: Array<[title: string, pillar: string, step: string]> = [
|
|
33
|
+
[P, "generation", "porteur"],
|
|
34
|
+
[VP, "generation", "offer_buyer"],
|
|
35
|
+
[VF, "generation", "offer_buyer"],
|
|
36
|
+
[RS, "remuneration", "money_means"],
|
|
37
|
+
[VAP, "remuneration", "money_means"],
|
|
38
|
+
[PF, "remuneration", "refutation"],
|
|
39
|
+
[ST, "sharing", "conventions_cost"],
|
|
40
|
+
[CV, "sharing", "conventions_cost"],
|
|
41
|
+
[EC, "sharing", "conventions_cost"],
|
|
42
|
+
];
|
|
43
|
+
const LIVE_GRP_TITLES = LIVE_GRP.map(([t]) => t);
|
|
44
|
+
const PILLAR_RANK: Record<string, number> = { generation: 0, remuneration: 1, sharing: 2 };
|
|
45
|
+
/** The three cycles the live questions' own descriptions name ("Circular: …"). */
|
|
46
|
+
const NAMED_BACK_EDGES = [
|
|
47
|
+
[VP, CV],
|
|
48
|
+
[P, ST],
|
|
49
|
+
[VAP, PF],
|
|
50
|
+
];
|
|
51
|
+
const PILLARS = ["generation", "remuneration", "sharing"];
|
|
52
|
+
const pillarOf = (tags: unknown): string => {
|
|
53
|
+
const hit = (tags as string[]).filter((t) => PILLARS.includes(t));
|
|
54
|
+
expect(hit, `exactly one pillar tag in ${JSON.stringify(tags)}`).toHaveLength(1);
|
|
55
|
+
return hit[0]!;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const playbook = (name: string): TemplatePlaybook => {
|
|
59
|
+
const pb = (bm.playbooks ?? []).find((p) => p.name === name);
|
|
60
|
+
expect(pb, `playbook "${name}"`).toBeDefined();
|
|
61
|
+
return pb!;
|
|
62
|
+
};
|
|
63
|
+
const profile = (slug: string) => {
|
|
64
|
+
const p = bm.profiles.find((x) => x.slug === slug);
|
|
65
|
+
expect(p, `profile "${slug}"`).toBeDefined();
|
|
66
|
+
return p!;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
describe("business-model = the canonical GRP", () => {
|
|
70
|
+
it("seeds exactly the nine live G·R·P questions, verbatim, with unique dedupe keys", () => {
|
|
71
|
+
const seeds = bm.seedEntities ?? [];
|
|
72
|
+
expect(seeds.map((s) => s.title)).toEqual(LIVE_GRP_TITLES);
|
|
73
|
+
expect(seeds.every((s) => s.profileSlug === "question")).toBe(true);
|
|
74
|
+
const keys = seeds.map((s) => `${s.profileSlug}:${s.title}`);
|
|
75
|
+
expect(new Set(keys).size).toBe(keys.length);
|
|
76
|
+
for (const s of seeds) {
|
|
77
|
+
const p = s.properties ?? {};
|
|
78
|
+
// The question text IS the title on the live rows.
|
|
79
|
+
expect(p.title, s.title).toBe(s.title);
|
|
80
|
+
// Every live row carries a 190–405 char description.
|
|
81
|
+
expect(String(p.description ?? "").length, s.title).toBeGreaterThan(150);
|
|
82
|
+
expect(p.tags, s.title).toEqual(expect.arrayContaining(["business-model", "grp", "method-question"]));
|
|
83
|
+
expect(p.questionStatus, s.title).toBe("open");
|
|
84
|
+
// Nothing the live set does not carry (wedge-stage left with the "GRP #" set).
|
|
85
|
+
expect(Object.keys(p).sort(), s.title).toEqual(["description", "questionStatus", "tags", "title"]);
|
|
86
|
+
}
|
|
87
|
+
expect(seeds.some((s) => /^GRP #/.test(s.title))).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("each seed's pillar is its live tag, three per pillar", () => {
|
|
91
|
+
const seeds = bm.seedEntities ?? [];
|
|
92
|
+
expect(seeds.map((s) => [s.title, pillarOf(s.properties?.tags)])).toEqual(
|
|
93
|
+
LIVE_GRP.map(([t, pillar]) => [t, pillar])
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("each question is named by exactly the step that answers it (suggestedTasks)", () => {
|
|
98
|
+
const m = playbook("Business Model (GRP)");
|
|
99
|
+
for (const [title, , step] of LIVE_GRP) {
|
|
100
|
+
const naming = (m.stages ?? []).filter((s) => s.suggestedTasks?.includes(title)).map((s) => s.key);
|
|
101
|
+
expect(naming, title).toEqual([step]);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("rests_on follows Génération → Rémunération → Partage, plus only the named cycles", () => {
|
|
106
|
+
const pillar = new Map(LIVE_GRP.map(([t, p]) => [t, p]));
|
|
107
|
+
const rels = bm.suggestedRelations ?? [];
|
|
108
|
+
expect(rels.every((r) => r.type === "rests_on")).toBe(true);
|
|
109
|
+
const has = (src: string, tgt: string) =>
|
|
110
|
+
rels.some((r) => r.sourceRef === src && r.targetRef === tgt);
|
|
111
|
+
// The ONLY cycles are the three the live descriptions name (as 2-cycles).
|
|
112
|
+
const cycleEdges = rels
|
|
113
|
+
.filter((r) => has(r.targetRef, r.sourceRef))
|
|
114
|
+
.map((r) => [r.sourceRef, r.targetRef].sort().join("|"));
|
|
115
|
+
expect([...new Set(cycleEdges)].sort()).toEqual(
|
|
116
|
+
NAMED_BACK_EDGES.map((e) => [...e].sort().join("|")).sort()
|
|
117
|
+
);
|
|
118
|
+
// Outside those cycles, an edge never rests on a LATER pillar.
|
|
119
|
+
for (const r of rels) {
|
|
120
|
+
if (has(r.targetRef, r.sourceRef)) continue;
|
|
121
|
+
expect(
|
|
122
|
+
PILLAR_RANK[pillar.get(r.sourceRef)!]! >= PILLAR_RANK[pillar.get(r.targetRef)!]!,
|
|
123
|
+
`${r.sourceRef} -> ${r.targetRef}`
|
|
124
|
+
).toBe(true);
|
|
125
|
+
}
|
|
126
|
+
// Every pillar step is wired: R rests on G, P rests on R (or G).
|
|
127
|
+
const crosses = (from: string, to: string) =>
|
|
128
|
+
rels.some((r) => pillar.get(r.sourceRef) === from && pillar.get(r.targetRef) === to);
|
|
129
|
+
expect(crosses("remuneration", "generation")).toBe(true);
|
|
130
|
+
expect(crosses("sharing", "remuneration")).toBe(true);
|
|
131
|
+
const keys = rels.map((r) => `${r.sourceRef}|${r.targetRef}`);
|
|
132
|
+
expect(new Set(keys).size).toBe(keys.length);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("every suggested relation joins two seeded questions", () => {
|
|
136
|
+
const titles = new Set((bm.seedEntities ?? []).map((s) => s.title));
|
|
137
|
+
const rels = bm.suggestedRelations ?? [];
|
|
138
|
+
expect(rels.length).toBeGreaterThan(0);
|
|
139
|
+
for (const r of rels) {
|
|
140
|
+
expect(titles.has(r.sourceRef), r.sourceRef).toBe(true);
|
|
141
|
+
expect(titles.has(r.targetRef), r.targetRef).toBe(true);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("ships the method as a 6-step TRACK template with one domain per step", () => {
|
|
146
|
+
const m = playbook("Business Model (GRP)");
|
|
147
|
+
expect(m.scope).toBe("project");
|
|
148
|
+
expect(m.stages?.map((s) => [s.key, s.domain])).toEqual([
|
|
149
|
+
["porteur", "foundation"],
|
|
150
|
+
["offer_buyer", "foundation"],
|
|
151
|
+
["conventions_cost", "foundation"],
|
|
152
|
+
["money_means", "finance"],
|
|
153
|
+
["refutation", "research-base"],
|
|
154
|
+
["maintain", "foundation"],
|
|
155
|
+
]);
|
|
156
|
+
expect(m.stages?.filter((s) => s.indefinite).map((s) => s.key)).toEqual(["maintain"]);
|
|
157
|
+
for (const s of m.stages ?? []) {
|
|
158
|
+
expect(s.category, s.key).toBe("started");
|
|
159
|
+
expect(s.goal, s.key).toBeTruthy();
|
|
160
|
+
expect(s.suggestedTasks?.length, s.key).toBeGreaterThan(0);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("the session template it replaced is gone; the Deprecation Check joined (D4)", () => {
|
|
165
|
+
const names = (bm.playbooks ?? []).map((p) => p.name);
|
|
166
|
+
expect(names).not.toContain("Business Model Interrogation");
|
|
167
|
+
const dc = playbook("GRP Deprecation Check");
|
|
168
|
+
expect(dc.scope).toBeUndefined(); // a work template
|
|
169
|
+
expect(dc.stages?.map((s) => s.key)).toEqual([
|
|
170
|
+
"detect_impact",
|
|
171
|
+
"notify_owners",
|
|
172
|
+
"plan_update",
|
|
173
|
+
"verify",
|
|
174
|
+
]);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("grp-interrogation role joins (D4) and says GRP = Génération · Rémunération · Partage; wedge-stage left", () => {
|
|
178
|
+
const role = profile("grp-interrogation");
|
|
179
|
+
expect(role.profileKind).toBe("role");
|
|
180
|
+
expect(role.applicableKinds).toEqual(["question"]);
|
|
181
|
+
expect(role.properties.map((p) => p.slug).sort()).toEqual([
|
|
182
|
+
"evidence_quality",
|
|
183
|
+
"grp_domain",
|
|
184
|
+
"interrogation_number",
|
|
185
|
+
]);
|
|
186
|
+
expect(role.description).toContain("GRP = Génération · Rémunération · Partage");
|
|
187
|
+
expect(role.description).not.toMatch(/Growth|Research Positioning/);
|
|
188
|
+
expect(profile("question").properties.map((p) => p.slug)).not.toContain("wedge-stage");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("convention + projection are pod-wide kinds", () => {
|
|
192
|
+
for (const slug of ["convention", "projection"]) {
|
|
193
|
+
const p = profile(slug);
|
|
194
|
+
expect(p.scope, slug).toBe("shared");
|
|
195
|
+
expect(p.entityScope, slug).toBe("pod");
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("D3: no shortcut on question; the convention shortcut opens the method", () => {
|
|
200
|
+
const aps = bm.actionPlacements ?? [];
|
|
201
|
+
expect(aps.filter((a) => a.profileSlug === "question")).toEqual([]);
|
|
202
|
+
const names = new Set((bm.playbooks ?? []).map((p) => p.name));
|
|
203
|
+
for (const a of aps) expect(names.has(a.ref), a.ref).toBe(true);
|
|
204
|
+
expect(aps.find((a) => a.profileSlug === "convention")?.ref).toBe("Business Model (GRP)");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("the packs carry it (D8: workspace templates only)", () => {
|
|
208
|
+
for (const pack of ["enterprise-os"]) {
|
|
209
|
+
const deps = (WORKSPACE_TEMPLATES[pack]?.dependencies ?? []).map((d) => d.slug);
|
|
210
|
+
expect(deps, pack).toContain("business-model");
|
|
211
|
+
expect(deps, pack).not.toContain("enterprise-os");
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
});
|