@synap-core/workspace-templates 0.29.0 → 0.31.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.
Files changed (44) hide show
  1. package/README.md +12 -4
  2. package/dist/{define-DqoItRiR.d.ts → define-DHDi8C33.d.ts} +19 -18
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +594 -241
  5. package/dist/index.js.map +1 -1
  6. package/dist/wire.d.ts +1 -1
  7. package/package.json +1 -1
  8. package/src/brand-library.yaml +0 -6
  9. package/src/builder-dev-fold.template.test.ts +2 -3
  10. package/src/builder-dev-playbooks.template.test.ts +7 -5
  11. package/src/builder.yaml +162 -32
  12. package/src/business-model.yaml +20 -1
  13. package/src/civic-france.yaml +9 -0
  14. package/src/content-creation.yaml +1 -1
  15. package/src/content-os.yaml +22 -18
  16. package/src/crm-absorbs-outreach.template.test.ts +1 -1
  17. package/src/crm-build-plan.template.test.ts +1 -1
  18. package/src/crm.yaml +5 -14
  19. package/src/decisions-wave.template.test.ts +7 -5
  20. package/src/define.primary-surface.test.ts +9 -0
  21. package/src/define.ts +4 -1
  22. package/src/finance.yaml +10 -6
  23. package/src/foundation.yaml +1 -2
  24. package/src/hr.yaml +3 -2
  25. package/src/intent.test.ts +44 -3
  26. package/src/internal-runbook.yaml +0 -1
  27. package/src/kanban-grouping.test.ts +72 -0
  28. package/src/legal.yaml +4 -4
  29. package/src/lifecycle-coverage.test.ts +7 -64
  30. package/src/lifecycle-declarations.test.ts +70 -74
  31. package/src/marketing.yaml +4 -3
  32. package/src/meetings-knowledge.yaml +1 -2
  33. package/src/operations.yaml +13 -9
  34. package/src/process-contract.validate.test.ts +40 -55
  35. package/src/project-management.yaml +2 -2
  36. package/src/publish-official-lib.test.ts +3 -2
  37. package/src/research-base.yaml +22 -15
  38. package/src/research-decision.yaml +18 -2
  39. package/src/ship-a-change.template.test.ts +3 -2
  40. package/src/social.yaml +4 -1
  41. package/src/start.test.ts +22 -0
  42. package/src/templates.ts +490 -185
  43. package/src/types.ts +28 -18
  44. package/src/validate.ts +143 -77
package/dist/wire.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { g as PackageDefinitionOutput, X as WorkspaceDefinitionInput } from './define-DqoItRiR.js';
1
+ import { g as PackageDefinitionOutput, X as WorkspaceDefinitionInput } from './define-DHDi8C33.js';
2
2
  import '@synap-core/types/presentation';
3
3
  import '@synap-core/types/space-brief';
4
4
  import '@synap-core/types/capability-intents';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synap-core/workspace-templates",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "type": "module",
5
5
  "description": "Canonical workspace definitions — YAML source + typed exports for browser, backend, CLI, and marketplace",
6
6
  "repository": {
@@ -1171,8 +1171,6 @@ playbooks:
1171
1171
  Deprecating an asset is a person's call.
1172
1172
  subjectProfile:
1173
1173
  profileSlug: brand-asset
1174
- statusProperty: asset-status
1175
- humanOnlyStatuses: [deprecated]
1176
1174
  params:
1177
1175
  - { name: asset, type: entity, label: Brand asset, required: true }
1178
1176
  executor: is-agent
@@ -1212,8 +1210,6 @@ playbooks:
1212
1210
  is checked against. Retiring a guide is a person's call.
1213
1211
  subjectProfile:
1214
1212
  profileSlug: brand-voice-guide
1215
- statusProperty: voice-status
1216
- humanOnlyStatuses: [deprecated]
1217
1213
  params:
1218
1214
  - { name: guide, type: entity, label: Brand voice guide, required: true }
1219
1215
  executor: is-agent
@@ -1249,8 +1245,6 @@ playbooks:
1249
1245
  guideline is a person's call.
1250
1246
  subjectProfile:
1251
1247
  profileSlug: content-guideline
1252
- statusProperty: guideline-status
1253
- humanOnlyStatuses: [deprecated]
1254
1248
  params:
1255
1249
  - { name: guideline, type: entity, label: Content guideline, required: true }
1256
1250
  executor: is-agent
@@ -45,9 +45,8 @@ const INTRINSIC_COLUMNS = new Set(["title"]);
45
45
  type View = {
46
46
  name: string;
47
47
  scopeProfileSlug?: string;
48
- groupBy?: string;
49
48
  sortBy?: string;
50
- config?: { columns?: unknown[] };
49
+ config?: { columns?: unknown[]; groupByField?: string };
51
50
  };
52
51
 
53
52
  const def = toWorkspaceDefinition("builder-workspace");
@@ -70,7 +69,7 @@ describe("builder-workspace — dev-dashboard fold (R7)", () => {
70
69
  expect(props.size, `${name} scopes "${scope}" which declares no properties`).toBeGreaterThan(0);
71
70
 
72
71
  const named = [
73
- view!.groupBy,
72
+ view!.config?.groupByField,
74
73
  view!.sortBy,
75
74
  ...((view!.config?.columns as string[] | undefined) ?? []),
76
75
  ].filter((s): s is string => typeof s === "string");
@@ -35,16 +35,18 @@ describe("builder dev playbooks", () => {
35
35
  expect(pb?.subjectProfile?.activators).toBeUndefined();
36
36
  });
37
37
 
38
- it.each(DEV_PLAYBOOKS)("%s names a statusProperty wherever a stage moves a status", (name) => {
39
- const pb = find(name);
40
- const moves = (pb?.stages ?? []).some((s) => s.subjectStatus);
41
- if (moves) expect(pb?.subjectProfile?.statusProperty).toBeTruthy();
38
+ // One model decision 4 (7 Nov 2026): the process follows the kind's declared
39
+ // lifecycle — no statusProperty, and no end move (decision of 6 Nov).
40
+ it.each(DEV_PLAYBOOKS)("%s follows its kind's lifecycle and declares no end move", (name) => {
41
+ const pb = find(name) as Record<string, any> | undefined;
42
+ expect(pb?.subjectProfile?.statusProperty).toBeUndefined();
43
+ expect(pb?.subjectProfile?.onEnd).toBeUndefined();
44
+ expect(pb?.humanOnlyStatuses).toBeUndefined();
42
45
  });
43
46
 
44
47
  it("Fix a bug works the core `issue` kind through its declared lifecycle", () => {
45
48
  const pb = find("Fix a bug");
46
49
  expect(pb?.subjectProfile?.profileSlug).toBe("issue");
47
- expect(pb?.subjectProfile?.statusProperty).toBe("issueStatus");
48
50
  const issue = (getWorkspaceTemplate("builder-workspace")?.profiles ?? []).find((p) => p.slug === "issue") as
49
51
  | { lifecycle?: { property: string; options: { key: string; category: string }[] } }
50
52
  | undefined;
package/src/builder.yaml CHANGED
@@ -46,6 +46,8 @@ meta:
46
46
  # What this space PRODUCES (homes): the purpose word, then its kinds/roles.
47
47
  intent:
48
48
  label: Product
49
+ # The ONE primary output (One model decision 3): the feature is what the dev loop ships (Build a change works one).
50
+ primary: devplane_feature
49
51
  produces:
50
52
  - profile: devplane_feature
51
53
  - profile: devplane_story
@@ -720,6 +722,12 @@ profiles:
720
722
  icon: alert-triangle
721
723
  color: red
722
724
  description: A production incident with severity, status, and root cause tracking
725
+ lifecycle:
726
+ property: incidentStatus
727
+ options:
728
+ - { key: open, category: open }
729
+ - { key: investigating, category: active }
730
+ - { key: resolved, category: done }
723
731
  properties:
724
732
  - slug: severity
725
733
  label: Severity
@@ -1033,10 +1041,10 @@ profiles:
1033
1041
  # `issue` is a CORE kind: the pod seeds it on every pod (ensure-system-profiles.ts,
1034
1042
  # "an open bug or problem" → issue) with its ONE lifecycle `issueStatus`
1035
1043
  # (ensure-system-lifecycles.ts). Declared here to match the seed exactly, the way
1036
- # research-base declares `research`, so the Fix a bug playbook can name its
1037
- # statusProperty. Pod-local extras (severity, night-shift-run) are not core: not here.
1044
+ # research-base declares `research`, so the Fix a bug playbook follows its
1045
+ # lifecycle. Pod-local extras (severity, night-shift-run) are not core: not here.
1038
1046
  # ONE deviation from the seed: `wont_fix` is humanOnly (a person decides an issue
1039
- # is not worth fixing), which the playbook's humanOnlyStatuses below requires.
1047
+ # is not worth fixing).
1040
1048
  - slug: issue
1041
1049
  displayName: Issue
1042
1050
  icon: bug
@@ -1062,6 +1070,77 @@ profiles:
1062
1070
  inputType: textarea
1063
1071
  constraints: { maxLength: 5000 }
1064
1072
 
1073
+ # A problem with our own product or process, worked by "Fix a finding" below.
1074
+ # Declared as the founder's pod holds it (pod-local profile 0f1eb707, founder
1075
+ # decision on card catalog-home, session 7416a988, 7 Nov 2026): pod-wide rows,
1076
+ # so a finding filed from any space is one list. Property slugs are the live
1077
+ # ones (`supersededby` included) so a reconcile onto that pod adds nothing. Two
1078
+ # differences, both from the catalog's coverage rules: `wont_fix` and
1079
+ # `superseded` are humanOnly (an agent's move into a lost option proposes
1080
+ # anyway), and the unlabelled legacy `ek-claim` is left out. Not research-base's `finding` (a validated fact with a claim and a
1081
+ # confidence): that slug clash is plan b38e5e64 decision 5, a rename of the
1082
+ # Research kind that waits on a data conversion.
1083
+ - slug: finding
1084
+ displayName: Finding
1085
+ icon: bug
1086
+ color: "#F97316"
1087
+ description: A problem report or feedback item, with a severity, raised against our own product or process. Moves open → fixing → fixed → verified, or won't fix / superseded.
1088
+ scope: shared
1089
+ entityScope: pod
1090
+ profileKind: kind
1091
+ lifecycle:
1092
+ property: status
1093
+ options:
1094
+ - { key: open, category: open }
1095
+ - { key: fixing, category: active }
1096
+ - { key: fixed, category: done }
1097
+ - { key: verified, category: done }
1098
+ - { key: wont_fix, category: lost, humanOnly: true }
1099
+ - { key: superseded, category: lost, humanOnly: true }
1100
+ properties:
1101
+ - slug: status
1102
+ label: Status
1103
+ valueType: string
1104
+ inputType: select
1105
+ enumValues: [open, fixing, fixed, verified, wont_fix, superseded]
1106
+ constraints: { defaultValue: open }
1107
+ - slug: severity
1108
+ label: Severity
1109
+ valueType: string
1110
+ inputType: select
1111
+ enumValues: [low, medium, high, critical]
1112
+ - slug: area
1113
+ label: Product area
1114
+ valueType: string
1115
+ inputType: text
1116
+ description: "Where it hurts: pod, mcp, bridge, cli, relay, browser, pod-admin, control-plane, governance, infra, process."
1117
+ - slug: evidence
1118
+ label: Evidence
1119
+ valueType: string
1120
+ inputType: textarea
1121
+ constraints: { maxLength: 2000 }
1122
+ description: Proposal, session, file:line, log line or URL that shows it.
1123
+ - slug: summary
1124
+ label: Summary
1125
+ valueType: string
1126
+ inputType: text
1127
+ constraints: { maxLength: 500 }
1128
+ - slug: description
1129
+ label: Description
1130
+ valueType: string
1131
+ inputType: textarea
1132
+ constraints: { maxLength: 5000 }
1133
+ - slug: content
1134
+ label: Content
1135
+ valueType: string
1136
+ inputType: textarea
1137
+ constraints: { maxLength: 50000 }
1138
+ - slug: supersededby
1139
+ label: Superseded by
1140
+ valueType: entity_id
1141
+ inputType: entity_select
1142
+ description: "The record that replaced this finding: the canonical finding it duplicates, or the correct diagnosis when this one was wrong. Recall leaves a superseded finding out."
1143
+
1065
1144
  - slug: skill
1066
1145
  displayName: Skill
1067
1146
  icon: zap
@@ -1226,6 +1305,13 @@ profiles:
1226
1305
  icon: workflow
1227
1306
  color: blue
1228
1307
  description: A user flow or business process — a sequence of steps through system components
1308
+ lifecycle:
1309
+ property: workflowStatus
1310
+ options:
1311
+ - { key: documented, category: open }
1312
+ - { key: in-progress, category: active }
1313
+ - { key: needs-review, category: active }
1314
+ - { key: complete, category: done }
1229
1315
  properties:
1230
1316
  - slug: workflowStatus
1231
1317
  label: Status
@@ -1446,9 +1532,40 @@ views:
1446
1532
  slug: task-board
1447
1533
  type: kanban
1448
1534
  scopeProfileSlug: task
1449
- groupBy: task-status
1535
+ config:
1536
+ groupByField: task-status
1450
1537
  defaultView: true
1451
1538
  description: "All delegated tasks by status: Backlog → Queued → Running → Review → Done."
1539
+ # The flow boards (One model §8 item 3): each produced kind on a board grouped
1540
+ # by its lifecycle — columns are its states, a drag is the governed status move.
1541
+ - name: Feature Board
1542
+ slug: feature-board
1543
+ type: kanban
1544
+ scopeProfileSlug: devplane_feature
1545
+ description: Features by stage, Idea to Shipped.
1546
+ config:
1547
+ groupByField: featureStatus
1548
+ - name: Story Board
1549
+ slug: story-board
1550
+ type: kanban
1551
+ scopeProfileSlug: devplane_story
1552
+ description: User stories by status, Draft to Done.
1553
+ config:
1554
+ groupByField: storyStatus
1555
+ - name: Issue Board
1556
+ slug: issue-board
1557
+ type: kanban
1558
+ scopeProfileSlug: issue
1559
+ description: Bugs and problems by status, Open to Fixed.
1560
+ config:
1561
+ groupByField: issueStatus
1562
+ - name: Design Board
1563
+ slug: design-board
1564
+ type: kanban
1565
+ scopeProfileSlug: ui-design
1566
+ description: Designs by status, from draft to implemented.
1567
+ config:
1568
+ groupByField: design-status
1452
1569
  - name: Deployments
1453
1570
  type: calendar
1454
1571
  scopeProfileSlug: devplane_deployment
@@ -1476,13 +1593,15 @@ views:
1476
1593
  slug: service-health
1477
1594
  type: kanban
1478
1595
  scopeProfileSlug: devplane_service
1479
- groupBy: serviceStatus
1596
+ config:
1597
+ groupByField: serviceStatus
1480
1598
  description: Every service by health — healthy, degraded, down, maintenance.
1481
1599
  - name: Services by Type
1482
1600
  slug: services-by-type
1483
1601
  type: kanban
1484
1602
  scopeProfileSlug: devplane_service
1485
- groupBy: serviceType
1603
+ config:
1604
+ groupByField: serviceType
1486
1605
  description: Services grouped by what they are — API, worker, cron, database, cache, queue.
1487
1606
  - name: Deploy Timeline
1488
1607
  slug: deploy-timeline
@@ -1617,10 +1736,8 @@ playbooks:
1617
1736
  (update_entity with expectedStatus); never invent a status.
1618
1737
  subjectProfile:
1619
1738
  profileSlug: ui-design
1620
- statusProperty: design-status
1621
1739
  # No stage owns these: `approved` and `archived` are a person's call
1622
1740
  # (humanOnly on the lifecycle).
1623
- humanOnlyStatuses: [approved, archived]
1624
1741
  activators:
1625
1742
  - { on: manual, mode: propose }
1626
1743
  params:
@@ -1928,8 +2045,7 @@ playbooks:
1928
2045
  # THE DEV LOOP AS STORED CONFIG (plan v5 T2, 2026-10-27). One change = one
1929
2046
  # session on its feature: shaped → building → PR opened → checks green →
1930
2047
  # merged → deployed to lab → dogfooded → criteria verified. It FOLLOWS the
1931
- # feature's declared lifecycle (`featureStatus`, named as statusProperty, no
1932
- # second status): Shape writes spec, Build in_progress, PR opened in_review,
2048
+ # feature's declared lifecycle (`featureStatus`, no second status): Shape writes spec, Build in_progress, PR opened in_review,
1933
2049
  # Verify done (an agent's move into done proposes). The stages after PR
1934
2050
  # opened carry no status — the feature stays In review until it ships.
1935
2051
  #
@@ -1974,10 +2090,8 @@ playbooks:
1974
2090
  NEEDS-DOGFOOD.
1975
2091
  subjectProfile:
1976
2092
  profileSlug: devplane_feature
1977
- statusProperty: featureStatus
1978
2093
  # No stage owns these: Idea is before the change is shaped, Dropped is a
1979
2094
  # person's call (humanOnly on the lifecycle).
1980
- humanOnlyStatuses: [backlog, cancelled]
1981
2095
  activators:
1982
2096
  - { on: enters_status, status: spec, mode: propose, maxPendingApprovals: 5 }
1983
2097
  - { on: manual, mode: propose }
@@ -2121,24 +2235,18 @@ playbooks:
2121
2235
  # THE SIX DEV PLAYBOOKS (decision d05, founder instruction 2026-11-05): Build a
2122
2236
  # change, Fix a bug, Investigate, Review a change, Maintain, Fix main red.
2123
2237
  # Mirrored field by field from the six draft playbook proposals filed on the Builder
2124
- # pod (stored shape; humanOnlyStatuses lifted to the top-level wire spelling).
2238
+ # pod (stored shape). No end moves (decision of 6 Nov 2026): a cancelled or failed
2239
+ # session leaves its subject where it is.
2125
2240
  # ALL `status: draft` and NO activators: a pod keeps its own draft/active
2126
2241
  # choice on later template updates, and a person turns each on.
2127
2242
 
2128
2243
  # --- Build a change ---
2129
2244
  - name: Build a change
2130
- description: 'Dev set (decision d05), key: build. Works one feature (devplane_feature) from shaped criteria to a verified change on main; its stages follow the feature''s lifecycle (spec, in_progress, in_review, done), and a cancelled or failed session puts the feature back to spec so nothing is left half-claimed. One feature per session, never two subjects (founder default, 2026-11-05). A quick change is this playbook with size small (no plan); a night shift run is this playbook with unattended true. No activators until binding is turned on; the shape would be {on: enters_status, status: spec, size: per_thing, mode: propose}, the trigger Ship a change uses today. Reuses Ship a change (2c5aa553) stage text and evidence keys; absorbs AI Dev Session and Quick change once they are re-pointed. Draft until the founder activates it.'
2245
+ description: 'Dev set (decision d05), key: build. Works one feature (devplane_feature) from shaped criteria to a verified change on main; its stages follow the feature''s lifecycle (spec, in_progress, in_review, done); a cancelled or failed session leaves the feature where it is. One feature per session, never two subjects (founder default, 2026-11-05). A quick change is this playbook with size small (no plan); a night shift run is this playbook with unattended true. No activators until binding is turned on; the shape would be {on: enters_status, status: spec, size: per_thing, mode: propose}, the trigger Ship a change uses today. Reuses Ship a change (2c5aa553) stage text and evidence keys; absorbs AI Dev Session and Quick change once they are re-pointed. Draft until the founder activates it.'
2131
2246
  goalTemplate: 'Build {feature} through one session and one PR per repo (or gated commits on main in a private repo), size {size}. SHAPE: write the end state and 2-5 binary criteria on this session (plan skill, skipped when size is small). BUILD: branch <type>/<slug> from origin/main in your own worktree, commit in verified slices, run the smallest gate that answers with its negative control, quote the output. LAND: follow the land stages (Change proposed, Checks green, Landed on main, Deployed to lab, Dogfooded, Criteria verified). Unattended: {unattended}. When unattended is true, ask no person, stop at a draft PR or a gated branch, never merge, push main or deploy, and post one "Look at first:" paragraph in the room.'
2132
2247
  scope: session
2133
2248
  subjectProfile:
2134
- onEnd:
2135
- failed: spec
2136
- cancelled: spec
2137
2249
  profileSlug: devplane_feature
2138
- statusProperty: featureStatus
2139
- humanOnlyStatuses:
2140
- - backlog
2141
- - cancelled
2142
2250
  params:
2143
2251
  - name: feature
2144
2252
  type: entity
@@ -2293,21 +2401,11 @@ playbooks:
2293
2401
 
2294
2402
  # --- Fix a bug ---
2295
2403
  - name: Fix a bug
2296
- description: 'Dev set (decision d05), key: fix. Works an issue at its root: reproduce it with a failing test, fix the canonical path, a clean-context review, then the shared land stages. Its stages follow the issue''s lifecycle (open, investigating, fixed); a cancelled or failed session puts the issue back to open, as Fix a finding does. Small fixes may be batched (founder default, 2026-11-05): several issues in one session, one as the subject and the rest as session targets; today a stage moves only the subject, and the session end moves the subject and every target still open. No activators until binding is turned on; a batch would be {on: count, status: open, min: 3} or {on: schedule, cron, status: open} (both one session per moment). A night shift run is this playbook with unattended true. Reuses Bugfix (8c335e2e), Night shift: build an issue (c101dd75) and Ship a change (2c5aa553). Draft until the founder activates it.'
2404
+ description: 'Dev set (decision d05), key: fix. Works an issue at its root: reproduce it with a failing test, fix the canonical path, a clean-context review, then the shared land stages. Its stages follow the issue''s lifecycle (open, investigating, fixed); a cancelled or failed session leaves the issue where it is, as Fix a finding does. Small fixes may be batched (founder default, 2026-11-05): several issues in one session, one as the subject and the rest as session targets; today a stage moves only the subject. No activators until binding is turned on; a batch would be {on: count, status: open, min: 3} or {on: schedule, cron, status: open} (both one session per moment). A night shift run is this playbook with unattended true. Reuses Bugfix (8c335e2e), Night shift: build an issue (c101dd75) and Ship a change (2c5aa553). Draft until the founder activates it.'
2297
2405
  goalTemplate: 'Fix the issue {issue} at its root and prove it with a test that fails before the fix and passes after. REPRODUCE (recall first, smallest reproduction, root cause file:line), FIX on the canonical path in your own worktree, a clean-context REVIEW, then LAND through the shared land stages (Change proposed, Checks green, Landed on main, Deployed to lab, Dogfooded, Criteria verified). Unattended: {unattended}. When unattended is true, ask no person, stop at a draft PR or a gated branch, never merge, push main or deploy; if no code fix is right, write the root cause as a pod document; post one "Look at first:" paragraph in the room.'
2298
2406
  scope: session
2299
2407
  subjectProfile:
2300
- onEnd:
2301
- failed: open
2302
- cancelled: open
2303
2408
  profileSlug: issue
2304
- statusProperty: issueStatus
2305
- # Added to the pod draft (it has none; the catalog's lifecycle-coverage check
2306
- # needs every option owned): `open` is where an issue starts and a failed or
2307
- # cancelled session returns it (onEnd), `wont_fix` is a person's call.
2308
- humanOnlyStatuses:
2309
- - open
2310
- - wont_fix
2311
2409
  params:
2312
2410
  - name: issue
2313
2411
  type: entity
@@ -2853,6 +2951,38 @@ playbooks:
2853
2951
  statement: Every criterion of the session is graded with its evidence, and nothing unverified is reported as verified.
2854
2952
  description: 'Shared land stage. Never report unverified work as verified. File the lesson, decision or finding the work produced (engineering-memory skill, rule dogfood-journal). Close what you opened: asks answered or withdrawn, worktree removed once merged, then synap_complete_session. Tools: synap_update_session, synap_capture, synap_complete_session. Gate: none. Model tier: quick (advisory until a tier field exists).'
2855
2953
 
2954
+ # Founder's pod playbook 18abd1ea, as it runs since 6 Nov 2026: no onEnd
2955
+ # (decision f06dc507: a cancelled or failed session leaves its finding where it
2956
+ # is); it follows the kind's lifecycle (backend#853).
2957
+ # The two pod automations that move it (PR merged → merged, deployed →
2958
+ # verified) are not shipped: their session_update step scopes on
2959
+ # `whenPlaybookId`, a pod uuid, and there is no catalog-stable reference yet.
2960
+ - name: Fix a finding
2961
+ description: "Work one finding (a problem with Synap itself) until its fix is live. The session's stages move the finding: fixing while the work runs, fixed when the fix is merged, verified once it runs on the pod. A cancelled or failed session leaves the finding where it is."
2962
+ goalTemplate: Fix the finding and see the fix live
2963
+ scope: session
2964
+ subjectProfile:
2965
+ profileSlug: finding
2966
+ params: []
2967
+ executor: is-agent
2968
+ status: active
2969
+ stages:
2970
+ - key: fix
2971
+ name: Fix it
2972
+ goal: Find the root cause and ship the fix as a gated PR or commit
2973
+ category: started
2974
+ subjectStatus: fixing
2975
+ - key: merged
2976
+ name: Fix merged
2977
+ goal: The fix is on main (a merged PR or a gated commit)
2978
+ category: started
2979
+ subjectStatus: fixed
2980
+ - key: verified
2981
+ name: Live and verified
2982
+ goal: The fix runs on the pod (its build contains the fix) and the finding no longer happens
2983
+ category: completed
2984
+ subjectStatus: verified
2985
+
2856
2986
  onboarding:
2857
2987
  goal: Capture the real engineering surface — the apps that are shipped, where their code lives, what runs behind them, where they deploy, and what's in flight — so the workspace mirrors what the team actually builds and runs, not a generic template.
2858
2988
  framing: >
@@ -76,6 +76,15 @@ profiles:
76
76
  displayName: Question
77
77
  icon: help-circle
78
78
  profileKind: kind
79
+ # The pod seeds this lifecycle on every pod (ensure-system-lifecycles.ts);
80
+ # declared here to match the seed exactly, so a playbook can follow it.
81
+ lifecycle:
82
+ property: questionStatus
83
+ options:
84
+ - { key: open, category: open }
85
+ - { key: exploring, category: active }
86
+ - { key: answered, category: done }
87
+ - { key: abandoned, category: lost }
79
88
  properties:
80
89
  - slug: questionStatus
81
90
  label: Status
@@ -91,6 +100,15 @@ profiles:
91
100
  displayName: Decision
92
101
  icon: gavel
93
102
  profileKind: kind
103
+ # The pod seeds this lifecycle on every pod (ensure-system-lifecycles.ts);
104
+ # declared here to match the seed exactly, so a playbook can follow it.
105
+ lifecycle:
106
+ property: decisionStatus
107
+ options:
108
+ - { key: proposed, category: open }
109
+ - { key: accepted, category: done }
110
+ - { key: superseded, category: lost }
111
+ - { key: rejected, category: lost }
94
112
  properties:
95
113
  - slug: decisionStatus
96
114
  label: Status
@@ -312,7 +330,8 @@ views:
312
330
  slug: business-model-open-questions
313
331
  type: kanban
314
332
  scopeProfileSlug: question
315
- groupBy: questionStatus
333
+ config:
334
+ groupByField: questionStatus
316
335
  description: The nine component questions and everything they spawned, by status.
317
336
 
318
337
  # ── Seeds: the interrogation, not fake data ────────────────────────────────
@@ -39,6 +39,15 @@ profiles:
39
39
  icon: help-circle
40
40
  color: blue
41
41
  description: An open question driving a civic-data investigation.
42
+ # The pod seeds this lifecycle on every pod (ensure-system-lifecycles.ts);
43
+ # declared here to match the seed exactly, so a playbook can follow it.
44
+ lifecycle:
45
+ property: questionStatus
46
+ options:
47
+ - { key: open, category: open }
48
+ - { key: exploring, category: active }
49
+ - { key: answered, category: done }
50
+ - { key: abandoned, category: lost }
42
51
  properties:
43
52
  - slug: questionStatus
44
53
  label: Status
@@ -115,7 +115,7 @@ views:
115
115
  scopeProfileSlug: content-program
116
116
  description: Programs grouped by status — a running scoreboard for the content operation.
117
117
  config:
118
- groupBy: status
118
+ groupByField: status
119
119
 
120
120
  onboarding:
121
121
  goal: >
@@ -28,7 +28,6 @@ meta:
28
28
  label: Content
29
29
  promise: Every post from idea to published, on one calendar.
30
30
  suggestFor: [writer, creator, marketer, musician, photographer]
31
- profile: post
32
31
  views: [content-posts, content-calendar]
33
32
  example:
34
33
  - { title: "Why we left spreadsheets", values: { post-status: Idea, post-format: Article } }
@@ -46,6 +45,8 @@ meta:
46
45
  # What this space PRODUCES (homes): the purpose word, then its kinds/roles.
47
46
  intent:
48
47
  label: Content
48
+ # The ONE primary output (One model decision 3): a published post is what the editorial flow produces (Produce Content).
49
+ primary: post
49
50
  produces:
50
51
  - profile: post
51
52
  - profile: newsletter
@@ -713,6 +714,13 @@ profiles:
713
714
  color: "#0EA5E9"
714
715
  description: "An ordered run of posts that teaches one thing end to end — the curriculum axis of the content engine."
715
716
  scope: WORKSPACE
717
+ lifecycle:
718
+ property: series-status
719
+ options:
720
+ - { key: Planned, category: open }
721
+ - { key: Running, category: active }
722
+ - { key: Complete, category: done }
723
+ - { key: Abandoned, category: lost }
716
724
  properties:
717
725
  - slug: series-status
718
726
  label: Status
@@ -1551,7 +1559,8 @@ views:
1551
1559
  slug: content-posts
1552
1560
  type: kanban
1553
1561
  scopeProfileSlug: post
1554
- groupBy: post-status
1562
+ config:
1563
+ groupByField: post-status
1555
1564
  description: Content posts by status.
1556
1565
  # The editorial calendar — the "it lands on a calendar" promise. Posts render
1557
1566
  # on a month grid keyed on their Publish Date. The calendar renderer resolves
@@ -1600,7 +1609,8 @@ views:
1600
1609
  slug: content-newsletters
1601
1610
  type: kanban
1602
1611
  scopeProfileSlug: newsletter
1603
- groupBy: newsletter-status
1612
+ config:
1613
+ groupByField: newsletter-status
1604
1614
  description: Newsletter issues by status.
1605
1615
  # ⚠️ NO `Journey Board` (matrix) view here — DELIBERATE, do not "restore" it.
1606
1616
  # A coverage grid is the right idea and this is the wrong substrate today:
@@ -1806,15 +1816,15 @@ entityLinks:
1806
1816
  # `subjectProfile` binds a playbook to a kind so the Capture → Session matcher
1807
1817
  # (playbooks.subject_profile->>'profileSlug') can offer it when one is captured.
1808
1818
  #
1809
- # THE PROCESS CONTRACT (lifecycle-bound playbooks). `subjectProfile.statusProperty`
1810
- # names the kind's lifecycle select (`post-status`); each stage's `subjectStatus`
1811
- # is the value that stage IS — advancing into the stage writes it to the subject
1812
- # (governed), and the subject entering it advances an open run to the stage.
1813
- # `humanOnlyStatuses` lists the values no stage owns because a person sets them.
1819
+ # THE PROCESS CONTRACT (lifecycle-bound playbooks). A playbook FOLLOWS the kind's
1820
+ # declared lifecycle (`post-status`); each stage's `subjectStatus` is the value
1821
+ # that stage IS — advancing into the stage writes it to the subject (governed),
1822
+ # and the subject entering it advances an open run to the stage. A value no stage
1823
+ # owns is derived by the pod; a person-only value is `humanOnly` on the lifecycle.
1814
1824
  # `activators` are DECLARATIONS the pod compiles into governed propose-mode rules
1815
1825
  # at install — never hand-written `automations:`. `relationToSubject` is the edge
1816
1826
  # written output → subject when a slot is satisfied. Validated by validate.ts
1817
- # (`checkProcessContract`) and lifecycle-coverage.test.ts.
1827
+ # (`checkProcessContract`).
1818
1828
  playbooks:
1819
1829
  - name: Produce Content
1820
1830
  # ONE playbook for every format (plan W3.3): text / visual / video are
@@ -1868,10 +1878,8 @@ playbooks:
1868
1878
  by a person at Publish.
1869
1879
  subjectProfile:
1870
1880
  profileSlug: post
1871
- statusProperty: post-status
1872
1881
  # Idea is where a capture lands and Archived is a person's call — no stage
1873
1882
  # owns either. The activator below starts the run once the post is Briefed.
1874
- humanOnlyStatuses: [Idea, Archived]
1875
1883
  activators:
1876
1884
  - { on: enters_status, status: Briefed, mode: propose }
1877
1885
  params:
@@ -2158,8 +2166,7 @@ playbooks:
2158
2166
 
2159
2167
  # One take, several videos (D2, D3, 29 Oct). The take is a content-asset of
2160
2168
  # Kind recording; it has no lifecycle (its state is derived from what was
2161
- # made from it), so this process declares no statusProperty and its stages
2162
- # move no status. The person decides at Keep, through one question per
2169
+ # made from it), so its stages move no status. The person decides at Keep, through one question per
2163
2170
  # proposed piece (a slot ask: the door Content Studio and Relay answer), not
2164
2171
  # a stage gate: keeping a piece commits nothing outside the pod, and the raw
2165
2172
  # take is never touched. The per-piece slots are declared by the agent as
@@ -2321,8 +2328,8 @@ playbooks:
2321
2328
  # never one run per post (a subject-bound playbook's `schedule:` field fans
2322
2329
  # out per entity; an activator's `schedule` and a per_moment `manual` do
2323
2330
  # not: api `run-playbook.ts` runWorkerBatch). The `subjectProfile` names the
2324
- # kind those workers read; there are no stages and no `statusProperty`, so it
2325
- # never moves a post's status.
2331
+ # kind those workers read; there are no stages, so it never moves a post's
2332
+ # status.
2326
2333
  # Run by hand ("Re-plan" on Content Studio's calendar, or the pod's button)
2327
2334
  # and once a week (founder, report 22fec5ee §6, 3 Nov 2026). The weekly one
2328
2335
  # compiles to a governed rule the owner can pause on the pod; both propose
@@ -2455,7 +2462,6 @@ playbooks:
2455
2462
  and link it derived_from the original. Never republish the original as is.
2456
2463
  subjectProfile:
2457
2464
  profileSlug: post
2458
- statusProperty: post-status
2459
2465
  activators:
2460
2466
  # A copy or repost sent for another account (post-copy-of) is not repurposed: its original is.
2461
2467
  - { on: enters_status, status: Published, mode: propose, unless: { property: post-copy-of, present: true } }
@@ -2480,8 +2486,6 @@ playbooks:
2480
2486
  a person confirms it went out.
2481
2487
  subjectProfile:
2482
2488
  profileSlug: newsletter
2483
- statusProperty: newsletter-status
2484
- humanOnlyStatuses: [Archived]
2485
2489
  params:
2486
2490
  - { name: newsletter, type: entity, label: Newsletter issue, required: true }
2487
2491
  executor: is-agent
@@ -114,7 +114,7 @@ describe("CRM absorbs Outreach & Comms", () => {
114
114
  expect((reply.stages ?? []).map((s) => s.subjectStatus).filter(Boolean)).toEqual(["replied", "bounced", "no_response"]);
115
115
 
116
116
  const outreach = playbookOf("Personalized Outreach");
117
- expect(outreach.subjectProfile).toMatchObject({ profileSlug: "campaign", statusProperty: "campaign-status" });
117
+ expect(outreach.subjectProfile).toEqual({ profileSlug: "campaign" });
118
118
  expect(outputsOf(outreach)).toEqual([
119
119
  { kind: "messaging", label: "Proposed first messages", relationToSubject: "none" },
120
120
  ]);
@@ -88,7 +88,7 @@ describe("CRM build plan — catalog changes", () => {
88
88
 
89
89
  it("A6: one follow-up process drafts proposed messages on weekdays; no outreach process opens a deal", () => {
90
90
  const pb = playbookOf(crm, "Follow up on leads in outreach");
91
- expect(pb.subjectProfile).toMatchObject({ profileSlug: "lead", statusProperty: "leadStage" });
91
+ expect(pb.subjectProfile).toEqual({ profileSlug: "lead" });
92
92
  expect(pb.activators).toContainEqual({ on: "schedule", cron: "0 7 * * 1-5", status: "outreach", mode: "propose" });
93
93
  expect(outputsOf(pb).map((o) => o.kind)).toEqual(["messaging"]);
94
94
  expect(pb.stages?.at(-1)).toMatchObject({ key: "send", gate: { kind: "human" } });