Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
---
id: TASK-562
title: Export a selection of components as a plan and import it as drafts
status: To Do
assignee: []
status: Done
Comment thread
MrLesk marked this conversation as resolved.
assignee:
- '@codex'
created_date: '2026-10-07 23:16'
updated_date: '2026-10-08 15:31'
updated_date: '2026-10-09 08:02'
labels:
- senior
dependencies: []
Expand All @@ -19,6 +20,18 @@ references:
- relationship-markdown
- docs/component-markdown.md
- docs/product-model.md
modified_files:
- src/plan.ts
- src/relationship-markdown.ts
- src/authoring.ts
- src/write-commands.ts
- src/viewers/web/data.ts
- src/viewers/web/map-session.ts
- src/viewers/web/authoring.ts
- src/viewers/web/organisms/writes.ts
- docs/plans.md
- docs/component-markdown.md
- groma/systems/groma-md/containers/cli/components/plan.md
type: feature
ordinal: 2
---
Expand All @@ -33,18 +46,44 @@ Build on drafts (src/draft.ts, src/accept.ts, draft records in src/architecture-

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 groma plan export <ids...> --to <path> writes a plan bundle in the OKF profile: the selected elements with status draft and their overviews, the relationships between them as draft rows, the flows that lie entirely within the selection, and the parents they need by id only. The Markdown contract documents the bundle.
- [ ] #2 groma plan import <path> [--parent <id>] creates the elements as ghosts at the paths they will keep, the relationships as draft rows, and a draft record named after the plan that tags every imported element. Ids are kept. A colliding id or a missing parent fails the whole import with a message naming it, and nothing is written.
- [x] #1 groma plan export <ids...> --to <path> writes a plan bundle in the OKF profile: the selected elements with status draft and their overviews, the relationships between them as draft rows, the flows that lie entirely within the selection, and the parents they need by id only. The Markdown contract documents the bundle.
- [x] #2 groma plan import <path> [--parent <id>] creates the elements as ghosts at the paths they will keep, the relationships as draft rows, and a draft record named after the plan that tags every imported element. Ids are kept. A colliding id or a missing parent fails the whole import with a message naming it, and nothing is written.
- [ ] #3 On the web map, a multi-selection of components offers Export as plan beside Group as and Combine into, and the bundle is written into the repository or downloaded.
- [ ] #4 After an import, a scan matches the ghosts when their code arrives and groma accept works unchanged. Existing draft behaviour and its tests stay as they are.
- [ ] #5 A round trip works: a plan exported from one fixture repository and imported into an empty one yields equal elements, relationships and overviews.
- [ ] #6 groma plan without arguments prints what a plan is and the two commands, and docs/ gets a page with an example plan.
- [x] #4 After an import, a scan matches the ghosts when their code arrives and groma accept works unchanged. Existing draft behaviour and its tests stay as they are.
- [x] #5 A round trip works: a plan exported from one fixture repository and imported into an empty one yields equal elements, relationships and overviews.
- [x] #6 groma plan without arguments prints what a plan is and the two commands, and docs/ gets a page with an example plan.
<!-- AC:END -->

## Definition of Done
<!-- DOD:BEGIN -->
- [ ] #1 Acceptance criteria have objective verification evidence.
- [ ] #2 Relevant checks pass and changes remain task-scoped.
- [ ] #3 Public contracts or documentation are updated when behavior changes.
- [ ] #4 Implementation Plan reflects the final approach; correction history and verification are recorded in Implementation Notes.
- [x] #3 Public contracts or documentation are updated when behavior changes.
- [x] #4 Implementation Plan reflects the final approach; correction history and verification are recorded in Implementation Notes.
<!-- DOD:END -->

## Implementation Plan

<!-- SECTION:PLAN:BEGIN -->
1. Implement a portable OKF directory bundle containing selected draft concepts, concept-linked draft relationships, internal flows, and external parent IDs. Use existing Markdown emitters, canonical paths and locked writes; validate the complete import before saving. 2. Register plan export/import/help commands and add a repository-path export action beside web multi-selection controls. 3. Document the profile and an example. Keep scan matching and element acceptance unchanged. 4. Review the diff and update the architecture via groma scan. No installs, builds, tests or commits per stage instructions; unexecuted verification will be reported rather than claimed.
<!-- SECTION:PLAN:END -->

## Implementation Notes

<!-- SECTION:NOTES:BEGIN -->
Added the plan bundle and import/export path, CLI help, live multi-selection export, and docs/plans.md. Verified bare plan help with bun src/cli.ts plan (the global groma command points to the separately installed package). No installs, builds or test runners have been run. Existing scanner and accept implementations and their tests remain unchanged.

CLI walkthrough using a temporary copy of test/fixtures/flows: exported service, api, entry, worker, requester and journal; imported into an empty initialized destination. Inspection found 6 equal element meanings/overviews, 4 equal relationship meanings, and 1 equal ordered flow, excluding intentional status/code/draft differences. Reimport failed naming the existing request-plan draft; all destination file hashes remained unchanged. The imported entry view renders its four incoming/outgoing draft relationships.

A two-component export lists only api as its required parent and omits the external flow. Import into an empty initialized architecture failed naming api. After drafting a destination system/container with existing commands, importing that same bundle with --parent application succeeded at the destination canonical paths. The cold simplicity review found no blocking defects or necessary simplifications.

Extended the temporary CLI walkthrough with source files and the configured local TypeScript scanner. Scan reported matched 2, entry acquired src/entry.ts while staying draft, and accept entry succeeded unchanged. Existing draft tests were neither changed nor run. Implementer specification/quality review and the separate final complexity review found no blocking supported-flow defect. Live browser interaction remains unverified because no browser/build/test run was performed.

Repository groma scan completed: created 1, refreshed 111, matched 0, findings 38. Curated the task-owned plan component in the Groma application as Architecture plans, under Architecture records; existing unrelated agents architecture changes were left alone. git diff --check passed for the touched files. Browser export is implemented via the existing selection controls and shared write route, but AC 3 remains unchecked pending actual browser interaction. No installs, builds, test runners, commits or task-status changes were performed.
<!-- SECTION:NOTES:END -->

## Final Summary

<!-- SECTION:FINAL_SUMMARY:BEGIN -->
Implemented portable OKF plan export/import, whole-import ID and parent validation, canonical ghost placement with a named draft, concept-linked draft relationships and internal flows, CLI help, live browser multi-selection export, documentation and the Architecture plans map component. CLI walkthrough verified equal element/relationship/flow meaning after round trip, parent override, rejection without partial writes, and scan/accept of imported ghosts. AC 3 browser interaction remains unverified; builds and test suites were not run per instruction.
<!-- SECTION:FINAL_SUMMARY:END -->
43 changes: 43 additions & 0 deletions docs/component-markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,3 +444,46 @@ TypeScript, NestJS, and PostgreSQL.

The live [groma.md system](../groma/systems/groma/system.md) and
[MVP draft](../groma/drafts/mvp.md) are a complete package example.


## Plan bundles

A plan is an OKF 0.2 bundle containing a selected architecture fragment. Its
root `index.md` uses the normal `okf_version: "0.2"` declaration and Markdown
links. The supporting `plan.md` record has `type: Groma Plan`, a standard
`title`, outcome prose, and `groma.parents`, a list of required external parent
IDs. It has no C4 identity, containment level, or box on the map. It is a
Groma application-profile record, not a type required by OKF or C4.

Selected C4 documents retain their IDs, types, titles, descriptions,
technologies, parent IDs and overviews, with `status: draft`. Code ownership,
map layout, groups and previous draft tags are omitted. Only selected elements
are copied; unselected parents appear by ID only. Documents use the normal C4
paths relative to the bundle, and the parent IDs remain authoritative.

Relationships within the selection become authored rows under
`## Draft relationships`, using links to the selected concept documents.
Unlike current code relationships, planned relationships may link internal
software concepts without source files. They remain draft rows when scanning
or accepting an element. This permits architecture outcomes to be described
before implementation exists. The existing exact-file rules for current code
relationships are unchanged.

Flows are included only when every step's endpoints are selected. Their
ordinary linked Steps tables retain order and actions. A plan carries no
implementation steps: a flow describes an architecture scenario.

`groma plan export <ids...> --to <directory>` creates a new bundle directory;
its basename supplies the plan title. `groma plan import <directory>
[--parent <id>]` imports into an initialized architecture. Without `--parent`,
all referenced parents must already exist. With it, external parent references
are replaced by that existing destination parent. Import validates the complete
result before writing, including ID collisions and normal containment rules.
It preserves IDs, writes ghosts at their canonical destination paths, and tags
each with a new draft record named after the plan. A self-contained selection
including its system and containers can be imported into an empty initialized
architecture. Existing scanner matching and element acceptance remain in use.

Ordinary Markdown readers can browse the bundle and read outcomes and linked
collaborations. Groma interprets parent resolution, draft lifecycle and the
plan record. See [Share architecture plans](plans.md) for an example.
77 changes: 77 additions & 0 deletions docs/plans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Share architecture plans

A plan shares an intended architecture without source ownership or map layout.
Export the elements you want, then import them in another initialized Groma
project. Imported elements are ghosts under one draft record.

```sh
# In the source repository, select two components.
groma plan export checkout payments --to plans/payment-plan

# In the destination repository, use its existing application container.
groma plan import ../source/plans/payment-plan --parent application
```

On the live browser map, select several components and use **Export as plan**
beside **Group as** and **Combine into**. Enter a new directory relative to the
repository; Groma writes the same bundle as the CLI.

The directory name becomes the plan title. Export requires a new directory.
The bundle contains an OKF `index.md`, a `plan.md` record, selected element
Markdown files, and flows whose steps stay entirely inside the selection.
Unselected parents are referenced by ID and must already exist at import.
`--parent` replaces these references with an existing destination parent;
normal C4 containment rules still apply. To carry a complete architecture into
an empty initialized project, explicitly select its system and containers as
well as its components.

An example `plan.md`:

```markdown
---
type: Groma Plan
title: payment-plan
groma:
parents:
- source-application
---

Architecture to implement.
```

The selected `checkout` document remains normal architecture Markdown:

```markdown
---
type: C4 Component
title: Checkout
status: draft
groma:
id: checkout
parent: source-application
---

Collects an order and asks Payments to authorize it.

## Draft relationships

| Source | Target | Description | Technology |
| --- | --- | --- | --- |
| [checkout](checkout.md) | [payments](payments.md) | Requests authorization | HTTPS |
```

Both component documents live together at their source architecture paths
inside the bundle. Their parent is an ID reference, not a copied container.
Import computes their destination paths from the destination parent, keeps
IDs and overviews, and adds `groma.draft: payment-plan`. It also creates
`drafts/payment-plan.md`. Relationships remain draft rows with concept links.

A colliding element, flow or draft ID, or a missing parent, rejects the whole
import before any architecture document is written. Import never renames IDs.

Implement the imported responsibilities in source, run `groma scan`, and use
`groma accept <id>` for each matched ghost. The existing scanner matching rules
apply; import does not invent source paths or force a match. Scanning and
accepting elements do not accept their planned relationships.

The [Markdown contract](component-markdown.md#plan-bundles) defines the format.
15 changes: 15 additions & 0 deletions groma/systems/groma-md/containers/cli/components/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
type: C4 Component
title: Architecture plans
status: stable
groma:
id: plan
parent: cli
code:
- scanner: typescript
file: src/plan.ts
group: Architecture records
description: Shares selected architecture as portable OKF drafts
---

Exports selected C4 responsibilities, their internal relationships and flows as ordinary OKF Markdown without source ownership or layout. Import resolves existing parents, validates IDs and the complete architecture before saving, and writes ghosts at their canonical paths under one named draft record. The shared authoring API exposes the same operation to command-line users and browser multi-selection. Scanner matching and element acceptance retain their existing responsibilities.
3 changes: 3 additions & 0 deletions src/authoring.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { exportPlan, importPlan } from './plan.ts'
import { addThing } from './add.ts'
import type { AddInput } from './add.ts'
import { acceptGhost } from './accept.ts'
Expand Down Expand Up @@ -50,6 +51,8 @@ function protectedWrite<Write extends (root: string, input: never) => Promise<un

/** The writes the web shares with the CLI. Storage protects the complete operation, including its first read. */
export const writes = {
exportPlan: protectedWrite(exportPlan),
importPlan: protectedWrite(importPlan),
draft: protectedWrite(draftThing),
add: protectedWrite(addThing),
edit: protectedWrite(editArchitecture),
Expand Down
Loading
Loading