--- name: domain-modeling-studio description: Collaboratively model an existing codebase with a human using an editable offline HTML diagram spanning business-flow, architecture (module-dependency neighborhood), and ROP function-flow layers, with drill-down between them. Use for code-grounded domain modeling, reviewing current versus proposed business flows, mapping the module neighborhood a flow touches, tracing a function's success/failure/recovery control flow, or incorporating diagram feedback into a glossary, BDD drafts, and implementation candidates. Not a whole-repository architecture overview or an implementation workflow. --- # Domain Modeling Studio Investigate the code; let the human correct the model. Deliver an editable, offline HTML review workspace and keep verified behavior separate from proposed business rules. Read [dependencies and source](references/dependencies.md) before starting. Confirm that Node.js 20+ and the separate `domain-modeling` skill are available before collecting evidence; stop and report the missing dependency if either is absent. Keep model JSON, evidence, generated reports, and review HTML in task-owned scratch outside this installed plugin; the generator resolves its bundled template from the loaded script. ## Establish the evidence Use the named repository and a bounded business flow. If only a repository is given, inspect its glossary, entry points, domain code, and tests, then recommend a small complete flow. Ask only for decisions the code cannot settle. Honor that repository's worktree and document ownership rules. Pin the source commit with its complete 40- or 64-character hexadecimal Git ID. Identify local uncommitted changes explicitly when they affect the evidence. Read each cited implementation and its relevant callers/tests; a filename or function name alone is not evidence of behavior. Existing domain terms take precedence over synonyms. Keep credentials, invitation secrets, real customer data, and unrelated source out of the model. Read [the model contract](references/model.md), then create a session-owned JSON file in the target repository's task scratch directory. Build the current flow with file/symbol/revision evidence on nodes and relationships. Mark deductions `inference`; use `code` only where implementation was inspected. Tests read are evidence about intended checks, not proof that those checks ran. Missing events or aggregate boundaries remain explicit hypotheses rather than invented implementation facts. Initialize `proposed` from `current`. Incorporate requested changes there, with stable IDs, change reasons and unresolved questions. A human's desired rule is `agreement` or `proposal`, never proof of current code. Populate all four deliverables: model/evidence, glossary, Gherkin drafts, and implementation candidates. Gherkin must follow the actual conditions and paths investigated, including known exceptions; never pair arbitrary first nodes into a scenario. Once architecture or function-flow nodes exist in the model, revisit all four deliverables so they reflect those layers too, not only the business flow. ## Generate the architecture layer Scope architecture nodes to only the module(s) the chosen business flow actually touches, plus their import/require dependency neighbors one hop out; never scan the whole repository (see the [scope contract](references/architecture-scope.md)). Run the neighborhood scanner — `node /scripts/generate-architecture.mjs ` — passing the business-flow-touched files as seeds and the same pinned commit as `revision`; it resolves relative imports into `MODULE` nodes and everything else into `EXTERNAL` nodes, and never scans a resolved neighbor's own imports, so the result is bounded to seeds plus one hop by construction. The scanner reads whatever is currently on disk at each seed path and stamps the passed `revision` onto that evidence without checking the two actually match; before running it, confirm the working tree has no uncommitted changes to the seeds (or their resolved neighbors) that would make the scanned content diverge from the pinned revision — commit first, or disclose the divergence explicitly, rather than letting the evidence imply a revision it wasn't actually scanned from. The scanner is a single-line text scan of import/require-like statements, not a type-aware resolver: it misses multi-line or grouped import blocks, and it cannot see a runtime-loaded resource that never appears as an import/require statement (e.g. a template file opened via `readFile`). When such a dependency matters to the flow, cite it as business-flow evidence instead of inventing an architecture edge for it. Every node and edge the scanner produces carries `origin: inference` (a lightweight text match, never proof of a runtime dependency); a human confirming the relationship against source upgrades it to `code`, with evidence — `agreement` stays reserved for a business decision, which a scanned import relationship is not. An architecture node's `drillInto` may only name a node inside its own function-flow layer graph, never a business-flow node directly. Leaving `drillInto` unset is the ordinary case, not an open question — not every node needs one (`references/model.md`): an `EXTERNAL` node, or a one-hop neighbor this session isn't modeling at function-flow depth, has no graph to point into. Only add an `unresolved` entry when this session specifically intended a drill-down for that module — because it is itself under active function-flow investigation — but could not settle a target yet. ## Generate the function-flow layer Build a function-flow layer node only from the actual implementation; a function or file name is not evidence of its control flow. Assign `kind` per [ROP semantics](references/rop-semantics.md): `STAGE` for a success-only continuation; `FAILURE_HANDLER` for an operation that receives a failure and stays a failure (`mapError`/`map_err` and similar conversions); `RECOVERY` for an operation that can turn a matching failure back into success, drawing both its recovery-success and recovery-failure outcomes; `BYPASS` for a failure that reaches an in-scope handler without matching it; `TERMINATION` for a path's end; `OUTSIDE_TYPED_ERROR` for defects, interruptions, panics, or syntax the typed-error model does not cover. A bypass with no dispatching source line (e.g. an unmatched `catchTag`) is synthetic: `origin: inference`, no evidence. A bypass that is itself an executed non-recovering arm (e.g. Rust's `other => Err(other)`) is real source: `origin: code`, with evidence. Set each function-flow node's `drillInto` to the business-flow node it implements or affects. For TypeScript Effect code, first collect syntax evidence with the ast-grep helper: `python3 /scripts/extract-typescript.py` (see [TypeScript syntax evidence](references/typescript-evidence.md) and [Effect semantics](references/effect-ts.md)). This path needs Python 3 and `ast-grep`; the other modeling paths need neither. Record the helper's `status`: `ok` means the returned nodes are syntax evidence to check against source (an empty `nodes` array only means the scan found none of the selected constructs, never a failure); `unavailable` (ast-grep missing) or `failed` (extraction could not be completed or verified) mean the helper produced no usable evidence — continue building the node from source reading rather than leaving it unmodeled or treating the empty result as a failure. There is no separate schema field for this: the helper's own output (`evidence.json`, kept alongside the session model per [TypeScript syntax evidence](references/typescript-evidence.md)) is the record of `status`/`reason`; if `unavailable`/`failed` leaves a node's control flow unconfirmed from source reading alone, add an entry to the document's `unresolved` array naming the concrete reason, rather than modeling it as if source reading had settled it. For Rust and other languages without an extraction helper, build the function-flow layer from source reading only, using [Rust Result semantics](references/rust.md) (or the closest source-reading discipline for that language). Fold what these layers establish into the four deliverables: add glossary terms confirmed while naming a module or a function's control flow; ground Gherkin scenarios only in conditions and branches actually confirmed in the function-flow layer, including known exceptions such as a bypass or a scoped recovery, and never synthesize an untested combination; cite the affected module and function as evidence on any implementation change candidate an architecture or function-flow finding motivates; and keep the model page's evidence, change reasons and unresolved questions naming architecture and function-flow findings alongside business-flow ones. ## Generate and review Run with Node (runtime has no npm dependencies): ```sh node /scripts/render.mjs ``` The generator validates the input and uses the committed, self-contained template. Use new output names for revisions; it refuses to overwrite files. Inspect validation failures and fix the model rather than weakening validation. Read the generated artifacts for consistency with the source and requested flow. For interactive review, follow the browser opening, private serving, and ownership steps in [Open the sheet for the human](../ui-grill-with-docs/SKILL.md#open-the-sheet-for-the-human), using this session's generated HTML as the sheet. Replace its session/round check with the model's `sessionId` and `revision`, verified in the visible browser before reporting success. Keep the page available for feedback; the delivered HTML remains self-contained. Link the HTML. Ask the human to review, directly edit the proposed model, add comments, and paste **指摘・モデルをコピー** into chat. The current model accepts layout adjustments; corrections to its business content are comments for code re-investigation. The diagram's handles and inspector support edits; the inspector offers keyboard alternatives. Diagram and comment edits are undoable. Dictionary/BDD/change-candidate corrections go through feedback, then the agent regenerates them from the reviewed model. ## Incorporate submitted feedback A browser draft or successful clipboard write is not a submitted answer. Use the actual chat payload `domain-studio-feedback-v1`; check its session, document revision, repository revision, and `exportId` against the active round before acting. Stale or conflicting payloads require reconciliation with the human. Re-investigate each correction against the source. Keep the human's layout, stable IDs, surviving metadata and comments. Preserve removed nodes/edges in `retired`, including incident edges, so their comments remain attributable. Do not regenerate IDs from labels or silently drop unresolved feedback. Keep each prior unresolved question verbatim, or record its exact text, resolution reason and evidence in `resolutions` (see the model contract); carry earlier resolution records forward. Keep the repository commit pinned for the round-trip. A requested source rebase requires explicit agreement and a separate session after preserving the old records, not an automatic update. If semantics change, reconsider associated glossary entries, scenarios and implementation candidates. Emit a new revision with `basedOn: { revision: , exportId: }`. Preserve `revisionHistory` and append the submitted revision; never reuse a past revision. Carry the submitted edits forward, explain accepted/rejected/unresolved changes, and reset `needsReview` only after reviewing all derived artifacts. The human imports the new plain model JSON using **JSONを読み込む**, or opens the new HTML. Unsent changes, reused revision IDs, and missing review records are protected; ask for a fresh submitted export rather than bypassing the conflict guard. If re-investigation supersedes a human semantic edit, provide the matching target, field, before/after values, reason and evidence in `editResolutions` (model contract), retaining earlier entries. Imports retain earlier evidence, comments and retired records, and preserve human-adjusted geometry. Explain contradictory citations in unresolved notes instead of silently erasing them. The **JSONを保存** backup preserves the current document, including a comment still being typed. Copy and import also incorporate that pending comment before checking the update baseline. Loading a backup explicitly asks the human to download the current contents before restoring. Neither a backup nor a draft is permission to accept a proposed business rule. ## Finish the modeling session Confirm the agreed model and remaining unknowns. Use `domain-modeling` to integrate only agreed vocabulary into the target repository's existing `GLOSSARY.md` (or context-specific glossary); follow its ADR criteria. Create the four artifacts in a session-owned directory with the generator. Present scenarios as drafts with current/proposed and confirmed/draft status, and separate code-reading evidence from test execution results. Report the source revision, resulting files, unresolved questions, and checks actually performed. Implementation candidates remain a separate implementation task. Retain the agreed records; clean up only session-owned temporary files with the user's authorization. No automatic code changes, issue creation, or deployment follow from a modeling review. ## Maintaining the editor The standalone template and notices in `dist/` ship with the skill. `src/` is the editable source. `node scripts/build.mjs` uses the pinned package lock in a fresh temporary directory, leaving npm dependencies outside the chezmoi-deployed tree. Rebuild the template after source changes. Run `node --test tests/*.test.mjs` (model, architecture-generation and real-content coverage) and the browser workflows in `tests/browser.mjs` and `tests/browser-real-content.mjs` (their environment requirements are at the top of each). Verify offline `file:` loading, actual edits/undo/restore, clipboard failure and baseline conflicts before replacing the template. The `tests/browser.mjs` fixture is deliberately fictional; `tests/browser-real-content.mjs` instead drives the layer-selector drilldown against a model produced by actually running `generateArchitecture` and the function-flow procedure, so the two never drift apart in shape. Private pilot data belongs in the target task's scratch directory.