Skip to content

feat(intent): export DDD model as contract-shaped intent.json - #8

Open
tango238 wants to merge 2 commits into
mainfrom
feat/emit-intent
Open

feat(intent): export DDD model as contract-shaped intent.json#8
tango238 wants to merge 2 commits into
mainfrom
feat/emit-intent

Conversation

@tango238

Copy link
Copy Markdown
Owner

Why

distill-ddd owns intent ("what we meant to build"). Downstream tools — notably crawl-kit's verification layer — need that intent as data, not prose. This adds the "emit at the source" boundary: the skill stays independent and only a contract-shaped JSON crosses over. Markdown stays the human artifact; intent.json is its machine-readable twin.

What

scripts/emit_intent.py reads docs/domain/*.md and emits:

{
  "concepts":         [ { "name", "kind", "context", "aliases", "attributes" } ],   // id seeding
  "events":           [ { "name", "aggregate", "context", "trigger", "properties", "consumer" } ],
  "stateTransitions": [ { "aggregate", "context", "from", "to", "trigger", "event" } ]
}

The diff axis that actually matters for intent↔structure is events + state transitions (domain behaviour is too fine-grained to diff mechanically), so the payload leads with those. concepts is a superset of the legacy glossary fixture ({ "concepts": [...] }), so existing consumers keep working.

  • eventsdomain-events.md
  • stateTransitions ← each aggregate's explicit **状態遷移**: block in aggregates.md
  • conceptsaggregates.md headings, aliases enriched from glossary.md

State transitions are decided interactively, not guessed

Rather than have the exporter heuristically parse arrows out of prose, transitions are confirmed with the user during the aggregates phase:

  • references/phase-aggregates.md: new Step 3.5 (elicit states + transitions) and a **状態**: / **状態遷移**: template block with the canonical line shape - {from} → {to} : \{trigger}` → `{event}``.
  • The exporter reads that explicit block deterministically. Stateless aggregates are marked **状態遷移**: なし.

Tests

scripts/test_emit_intent.py — 7 stdlib-only tests (no pytest), matching the publish toolchain convention. Covers events, explicit transitions (both and 発行 forms), the "なし" case, glossary alias enrichment, end-to-end, and missing-file tolerance.

$ python3 scripts/test_emit_intent.py
7 passed

No regression in test_diagrams.py. Verified end-to-end on a real model (crawl-kit/docs/domain): 7 concepts, 9 events parsed cleanly.

…tent.json

Export docs/domain/*.md to a machine-readable intent.json so downstream tools
(crawl-kit's verification layer) can consume intent as data, not prose — the
"emit at the source" boundary.

The diff axis that matters is events + state transitions (domain behaviour is
too fine-grained to diff mechanically), so the payload leads with those plus a
thin concept list for canonical-id seeding. Shape is a superset of the legacy
glossary fixture, so existing consumers keep working.

State transitions are decided INTERACTIVELY during the aggregates phase (new
Step 3.5 + a `**状態遷移**:` template block), not guessed from prose, so the
export is deterministic. The exporter reads that explicit block.

- scripts/emit_intent.py: parser + CLI (stdlib only, JP/EN labels)
- scripts/test_emit_intent.py: 7 stdlib tests (events, transitions, glossary)
- references/phase-aggregates.md: Step 3.5 + 状態/状態遷移 template
- SKILL.md: Intent Export section

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e5651d479

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/emit_intent.py Outdated
Comment on lines +205 to +209
if not b:
continue
indent, rest = len(b.group("indent")), b.group("rest")
if indent == 0:
collecting_transitions = labelled_bullet(rest, *L_TRANSITIONS) == ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Parse the documented transition block shape

When aggregates.md follows the new template in references/phase-aggregates.md:116-117 (**状態遷移**: followed by unindented - from → to ...), this parser never emits any transition: the non-bullet section label is skipped before this block, and then the actual transition bullet reaches the indent == 0 path here and disables collection instead of parsing it. As a result, docs produced by the skill's own template export an empty stateTransitions array, removing the advertised verification oracle.

Useful? React with 👍 / 👎.

Comment thread scripts/emit_intent.py
cells = [c.strip() for c in line.strip().strip("|").split("|")]
if len(cells) < 2:
continue
term, english = cells[0], cells[1]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict glossary parsing to term/English tables

For any glossary that includes the template's later コンテキスト横断の注意点 or コードとの不整合 tables, this line blindly treats column 2 as the English name and adds bogus concepts such as a definition string or コード上の名前. That pollutes intent.json's concepts and can seed incorrect canonical IDs; the parser needs to recognize only the actual 用語 | 英語 | 定義 / Term | English | ... tables before appending rows.

Useful? React with 👍 / 👎.

… prose

The exporter only began collecting a "**状態遷移**:" block when the label's
value was exactly empty, so an annotated label
("状態遷移: (コード由来…)") silently dropped its sub-bullets. Start
collecting whenever the label is present. Adds a regression test (an
events-less, code-derived ConceptState block with trailing prose).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant