# Bone Flow #023 - API

Version: 1.0.79  
Status: Release Ready Candidate

Browser global API を示します。

## BoneFlowLexer

- `normalizeSource(value)`
- `splitLines(source)`
- `lineColumnAt(source, offset)`
- `sourceRef(source, startOffset, endOffset)`
- `stripInlineComment(line)`
- `decodeQuoted(value)`
- `lex(value)`

## BoneFlowParser

- `parse(source)`
- `parseEndpointToken(text, index, absBase)`
- `parseConnector(text, index)`
- `parseOptions(inner)`
- `canonicalDirective(line)`
- `endpointKey(endpoint)`
- `ID_RE`

## BoneFlowDefinition

- `DEFAULTS`
- `normalizeType(type)`
- `normalizeFieldType(type)`
- `build(astOrSource)`
- `toCanonical(working, options?)`
- `promoteAutoIds(working)`
- `generateCanonicalSource(definition)`
- `quoteText(value)`
- `quoteJointLabel(value)`
- `clone(value)`

Working Definition の `runtime` JSON representation は `{}` です。Parser内部の exact refs/source は runtime object の non-enumerable metadata として保持し、正式Working JSONを汚染しません。

## BoneFlowValidation

- `validate(working, options?)`
- `semanticErrors(working)`
- `validateCanonicalSchema(definition)`
- `validateCanonicalSemantics(definition, options?)`
- `registryTypes(options?)`

## BoneFlowShapeAdapter

- `init(options)`
- `create(node, position)`
- `update(node, position)`
- `remove(id)`
- `get(id)`
- `getBounds(id)`
- `getPorts(id)`
- `findPortAtClientPoint(clientX, clientY, role)`
- `setDropTarget(candidate)`
- `resolveEndpoint(endpoint, side, joint)
- `setSelected(id)`
- `setPortVisible(enabled)`
- `setPosition(id, position)`
- `setViewport(viewport)`
- `clear()`

Canonical null Comment/Tooltip は #021 fallbackを意味として使わないよう、disabled/hidden + empty text へ明示マッピングします。

## BoneFlowJointAdapter

- `init(options)`
- `render(working, layout, shapeAdapter)`
- `renderDiagnostic(...)`
- `refreshInteractions()`
- `setViewport(viewport)
- `clear()`
- `getDiagnostics()`

#002 API は locked actual artifact の引数/副作用に合わせて adapter 内で使用します。Intersection は style batch ごとに dedicated SVG を作ります。

## BoneFlowLayout

- `compute(working, options?)`
- `tarjan(nodes, edges)`

## BoneFlowRenderer

- `init(options)`
- `render(working)`
- `refreshGeometry(working?)`
- `refreshInteractions()`
- `setViewport(viewport)
- `clear()`
- `getDependencyMap()`
- `serializeSvg(theme?)`

## BoneFlowWorkspace

- `defaults(flowId, flowKey)`
- `normalizeSource(source)`
- `sha256Text(text)`
- `sourceHash(source)`
- `recoveryChecksum(record)`
- `collisionKey(oldFlowKey, candidate, currentSourceHash)`
- `candidateKey(flowId, fileName, sessionUUID)`
- `openDb()`
- `atomicRekey(oldKey, candidate, currentSourceHash, recovery, workspace, options?)`
- `saveRecovery(record)` / `loadRecovery(flowKey)` / `deleteRecovery(flowKey)`
- `saveWorkspace(workspace)` / `loadWorkspace(flowKey)` / `deleteWorkspace(flowKey)`
- `listRecovery()` / `purgeRecoveries(maxRecords, maxAgeDays)`
- `validateWorkspace(workspace)`
- `debounce(fn, ms)`
- `uuid()`

## BoneFlowEditor

- `version` = `1.0.35`
- `create(root)` → `BoneFlowEditor.App`
- `App` class

`await BoneFlowEditor.create(document.getElementById('bf023-app')).init()` で起動します。

主要 App operation は Source transaction を経由します: validation/render、Flow/Node/Field/Joint property patch、rename、Undo/Redo、New/Open/Save/Save As、JSON import/export、Workspace import/export、SVG/PNG export、Recovery flush。


### #002 v1.1.29 integration
`BoneJoint.resolveRoute()`, `resolvePortRoles()`, `resolvePortRole()`, and `validatePortConnection()` are required. #023 passes actual #021 Shape port positions plus source/target Shape bounds to #002. Orthogonal routing enables Shape Avoidance with 12px padding. #023 exposes effective `IN / OUT / RETURN` roles without rewriting #021's original DOM contract.


### v1.0.34 interactive editing

- Shape body drag is owned by #023. Drag preview calls `BoneFlowRenderer.refreshGeometry()` and release commits `manual x/y` back to Source.
- Joint selection is performed by #023 interaction hit paths; endpoint handles use #002 reconnect/disconnect state APIs and #002 routing for the preview line.
- `BoneFlowEditor.App.applyJointEndpoint(id, side, port)` synchronizes a dropped compatible Port back to Source. Shared/chained endpoint syntax is normalized to independent canonical Joint statements before patching so one visual endpoint edit cannot mutate adjacent Joints implicitly.
- #021 remains unmodified; Port coordinates/roles are obtained through `BoneFlowShapeAdapter`.

### v1.0.34 Joint selection / anchored quick menu

`BoneFlowJointAdapter` keeps geometry hit-testing as fallback, but the rendered Joint hit path, endpoint circles, and persistent `≡` affordance are now real pointer targets. `beginPointer(event)` first resolves `event.composedPath()` metadata, so visible controls do not depend on approximate coordinate matching. Clicking either the Joint route or a connection endpoint selects it and renders a bright selection overlay, two endpoint handles, and one persistent `≡` affordance.

`openContextMenu(event)` provides the same quick menu from right-click on a Joint. `BoneFlowRenderer.openJointContextMenu(event)` exposes it to the Preview surface. The editor callback `onJointMenu(id, point)` anchors the menu beside the selected Joint `≡`. The menu edits `routeStyle`, `lineColor`, `animation`, Joint Label, and `orthogonalClearance` by synchronizing the `.bflow` Source. Rendering remains delegated to #002 v1.1.29.

During endpoint reconnect, `BoneFlowShapeAdapter.setReconnectCandidates(role, active)` highlights every compatible #021 Port, `findPortAtClientPoint()` uses a larger snap radius, and only the non-dragged endpoint handle remains at its original position. The dragged endpoint is represented by a moving reconnect grip at the pointer/candidate Port.

### v1.0.34 reconnect interaction details
`BoneFlowJointAdapter.beginPointer(event)` first consumes direct Shadow-DOM metadata from the Joint hit path, endpoint handle, or ≡ affordance. Endpoint drag uses the Preview as pointer-capture surface, suppresses Preview pan, highlights compatible #021 Ports through `BoneFlowShapeAdapter.setReconnectCandidates(role, true)`, and performs a final `findPortAtClientPoint()` lookup on pointer-up.

`BoneFlowRenderer.openJointContextMenu(event)` provides the same selected-Joint menu through right-click/contextmenu and uses the Joint's ≡ anchor for adjacent placement.

## v1.0.34 selected-Joint endpoint gesture

`BoneFlowJointAdapter.beginPointer(event)` は、選択済みJoint上の押下をJoint endpoint gestureとして処理します。押下位置に近い `source(FROM)` / `target(TO)` をarmし、ドラッグ閾値を超えた場合のみ #002 reconnectへ移行します。`getDiagnostics()` は `armedEndpoint` と `endpointGestureActive` を返します。


## v1.0.34 reconnect endpoint display correction

- 再接続ドラッグ中は通常のJoint endpoint handleを全て非表示にする。
- 再接続Previewレイヤーだけが固定端点1個と移動端点1個を描画する。
- 固定端点は元の実Port中心へ固定し、移動端点はpointerへ追従し、候補Portへ入った場合はその実Port中心へ吸着する。
- ドラッグPreviewではDirection Markerを出さず、操作点と方向Markerを混同させない。
- 未吸着の移動端点には旧Port方向を流用せず、候補Portへ吸着した時だけそのPort方向をroutingへ渡す。

## v1.0.34 reconnect candidate API

`BoneFlowShapeAdapter.getReconnectCandidatePositions(role)` は、現在描画されている #021 Shape の実Portから、指定roleに接続可能な物理positionを返します。Flow Editorはこの値をFROM/TOガイド表示に使用し、Port位置を独自に推測しません。


## v1.0.34 RETURN / Shape Avoidance API integration

- `BoneFlowShapeAdapter.getPorts(id)` returns an **effective** `role` for Shape-level Ports and preserves the original #021 role as `rawRole`.
- For a normal TB Shape, effective roles are `TOP=IN / RIGHT=RETURN / BOTTOM=OUT / LEFT=RETURN`.
- `DECISION` keeps the formal #021 branch outputs (`RIGHT=OUT`, `BOTTOM=OUT`) while unused Shape ports may be `RETURN`.
- `BoneFlowRenderer` validates each resolved endpoint pair with `BoneJoint.validatePortConnection()`.
- `BoneFlowJointAdapter` passes `sourceShapeBounds`, `targetShapeBounds`, `shapeAvoidanceEnabled=true`, and `shapeAvoidancePadding=12` to #002 v1.1.29.
- Reconnect compatibility is delegated to #002 v1.1.32: `OUT -> IN`, `OUT -> RETURN`, and `RETURN -> RETURN` are valid. `OUT -> OUT` and `RETURN -> IN` are rejected. Candidate ports are pair-aware from the fixed endpoint.

## v1.0.34 Flow Settings API

`BoneFlowEditor.App#applyFlowSettings(values)` は9個のフロー-level directiveを一括検証・一括Source patchし、単一のHistory entryとしてcommitします。UIの「フロー設定」ミニメニューはこのAPIのみを使用します。

## v1.0.35 Error diagnostic adapter

`BoneFlowJointAdapter.renderDiagnostic()` は #002 Bone Joint v1.1.29 の `drawLine()` / `drawError()` を使用し、Error Flowでも通常Jointと同じgeometry metadataを渡す。

- `sourcePortPosition`
- `targetPortPosition`
- `sourceShapeBounds`
- `targetShapeBounds`
- `targetAvailable`
- `connectionEstablished`
- `origin`
- `animationEnabled / animationSpeed`
- `shapeAvoidanceEnabled / shapeAvoidancePadding`

Source側が不存在の場合も、#002の正式なreverse-trace規則に合わせて `x1/y1` は実在Target endpoint、`x2/y2` はmissing Source側stub終端とする。`origin=target` は座標順と一致させる。

`FIELD_TYPE_MISMATCH` のCompatibility markerは `drawLine()` の戻りSVG Pathに対する `getTotalLength()` / `getPointAtLength()` で最終Path上の中央を取得し、#002 v1.1.29 `drawCompatibilityMarker()` へ渡す。#023独自のJoint Path/Marker生成は行わない。


## v1.0.36 Error CASE layout / direction transition

- LR / RL: CASE groups are arranged horizontally.
- TB / BT: CASE groups are arranged vertically.
- Inside every Error CASE, TABLE_DETAIL Shape copies remain horizontal so FIELD IN/OUT keep the #021 fixed left/right geometry.
- Error preview waits for #021 Shape geometry to settle before resolving diagnostic Field ports after a direction change.


## v1.0.37 FIELD endpoint contract

`BoneFlowShapeAdapter` resolves FIELD selectors by the #021 raw FIELD role and its fixed semantic position before any generic effective-role fallback: IN/LEFT, OUT/RIGHT. Direction finalization performs Fit first and then `BoneFlowRenderer.refreshGeometry()` so #002 receives the final actual #021 Port coordinates.


## v1.0.39 Shape Adapter geometry readiness

`BoneFlowShapeAdapter.whenReady()` は #021 stylesheet と `document.fonts.ready` を待機します。`diagnosticGeometrySnapshot()` は Error CASE の Shape bounds / FIELD Port geometry の安定判定に使用します。


## v1.0.40 #002 pixel coordinate compatibility

`BoneJoint.drawLine()` v1.1.29 recalculates the destination SVG `viewBox` from `getBoundingClientRect()`. In the Flow Editor the Joint SVG is inside a zoomed world, so the returned size already contains the workspace zoom. #023 therefore converts logical endpoint coordinates, Shape bounds, clearance and avoidance padding into the #002 pixel coordinate space before calling `drawLine()` / `drawError()`. `renderIntersections()` remains in logical world coordinates because it does not perform this viewBox normalization.


## v1.0.48 Error marker integration with #002 Joint

Error Flow diagnostics use the existing #002 v1.1.29 APIs without modifying #002.

`BoneFlowJointAdapter.renderDiagnostic()` now renders both parts into the same Joint base SVG:

- Joint path: `BoneJoint.drawLine(baseSvg, ...)`
- CASE1-3 Error marker: `BoneJoint.drawError(baseSvg, ...)`（形状は#002 Marker設定に委譲）
- FIELD_TYPE_MISMATCH marker: `BoneJoint.drawCompatibilityMarker(baseSvg, ...)`（Warning=黄色輪郭△ / Error=赤×）

The separate marker SVG remains available for normal endpoint markers, but Error Flow diagnostic × markers are not placed there.

For `FIELD_TYPE_MISMATCH`, the marker position is obtained from the final #002 path using `getTotalLength()` / `getPointAtLength()`, then #002 `BoneJoint.drawCompatibilityMarker()` adds the directional compatibility marker to that same SVG.


## v1.0.48 Curve Side delegation

`requested.curveSide` / `resolved.curveSide` accept `auto | left | right`. `BoneFlowJointAdapter` passes the resolved value directly to #002 v1.1.29 for `drawLine()`, `resolveRoute()`, reconnect preview, and intersection rendering.


## v1.0.51 #002 v1.1.32 dependency contract

`BoneFlowJointAdapter` continues to delegate path calculation and marker rendering to #002 v1.1.32. For Curve rendering it passes actual endpoint coordinates, `sourceShapeBounds`, `targetShapeBounds`, `sourcePortPosition`, `targetPortPosition`, `curveSide`, Shape Avoidance settings, and connection state without introducing a #023-specific Curve algorithm.

RETURN re-output presentation is derived from the #002 role model while physical selectors remain canonical RETURN positions. `RETURN` text is not rendered; the active send position alone is presented as `OUT`.


## v1.0.51 physical avoidance bounds

`BoneFlowShapeAdapter.getBounds(id)` remains the outer #021 element/layout rectangle. `getAvoidanceBounds(id)` derives the physical Shape boundary from the actual non-FIELD LEFT/RIGHT/TOP/BOTTOM Port centers. `resolveEndpoint()` returns this physical rectangle as `bounds`, and `BoneFlowRenderer` passes it to #002 as `sourceShapeBounds` / `targetShapeBounds`. Reconnect previews use the same physical bounds.

## v1.0.51 Bounds object aliases

`BoneFlowShapeAdapter.getBounds()`, `getAvoidanceBounds()`, and related logical/diagnostic bounds return a consistent rectangle contract containing `x`, `y`, `left`, `top`, `width`, `height`, `right`, and `bottom`. `left` aliases `x`; `top` aliases `y`. Physical avoidance bounds continue to use actual #021 Shape Port boundary centers.

## v1.0.52 RETURN display label contract

`BoneFlowShapeAdapter` keeps the canonical physical RETURN selector unchanged. When a physical RETURN Port becomes the active source of a RETURN→RETURN connection, the adapter renders exactly one visible `OUT` label at that physical Port position, hides the former OUT label, and never renders visible `RETURN` text.


## v1.0.55 Decision label contract

`BoneFlowShapeAdapter` passes #021 Decision labels from `joint.branchKey`, not `joint.label`. Branch-key text is literal and not normalized to YES / NO. The first source-defined keyed branch uses RIGHT OUT and the second uses BOTTOM OUT. Branch-key text is offset from the outgoing Joint path (RIGHT label above the horizontal exit; BOTTOM label to the right of the vertical exit). Optional Joint comments remain independent #002 path labels.


## v1.0.57 Export APIs

- `BoneFlowEditor.App#exportSource()` — downloads normalized current Source as `.bflow`.
- `BoneFlowEditor.App#exportSvg()` — exports standalone SVG with Joint animation preserved (`animation:true`) and resolved SVG paint styles inlined.
- `BoneFlowEditor.App#exportPng()` — exports a static PNG snapshot from `animation:false` serialization.
- `BoneFlowRenderer.serializeSvg(theme, { animation:true })` preserves SVG/SMIL animation and inlines computed Shape/Joint paint styles for standalone rendering.
- `BoneFlowRenderer.serializeSvg(theme, { animation:false })` removes SMIL animation nodes and moving flow indicators for PNG rasterization only. Live Preview state is not mutated.


## v1.0.60 Export UI exposure

`App#exportSource()`, `App#exportSvg()`, and `App#exportPng()` remain the same APIs. Their controls are now permanently exposed in the top toolbar so export does not depend on the Definition / JSON accordion state.

## v1.0.62 Transparent image export contract

`BoneFlowRenderer.serializeSvg(theme, options)` keeps the existing API signature for compatibility, but exported root SVG background is transparent for every theme. The serializer does not insert a background rectangle and marks the root with `data-bf023-export-background="transparent"`.

`BoneFlowEditor.App#exportPng()` rasterizes the static SVG on an alpha-enabled 2D canvas after `clearRect()`. It must not call `fillRect()` for an export background.



## v1.0.65 Diagnostic export support

`BoneFlowRenderer.serializeSvg()` は通常Nodeに加え、Error Flow PreviewのDiagnostic Shape copyとCASE見出しを同じSVGへ直列化します。Export範囲はShape、CASE見出し、Joint/error markerの実描画範囲を統合して決定します。

Shape AdapterのExport用参照API:

- `getDiagnostic(viewKey)` — CASE PreviewのDiagnostic Shape entryを取得。
- `getCaseLabel(key)` — CASE見出しDOMを取得。
- `getCaseLabelBounds(key)` — CASE見出しの論理座標Boundsを取得。

## v1.0.62 Input Guide UI

UI enhancement APIs:

- `showInputGuide()` — 入力ガイドを開く。
- `hideInputGuide()` — 入力ガイドを閉じる。
- `renderGuideShapeCatalog()` — #021 `BoneShape.list()` / `BoneShape.registry.shapes` を読み、#021 `BoneShape.create()` で実Shape画像一覧をShadow Root内へ生成する。
- `guideShapeSnippet(type)` — Shape TYPEに対応する `.bflow` Node例を返す。
- `insertGuideSnippet(snippet)` — Source Editorの現在カーソル位置へガイド例を挿入し、通常のSource再解析を起動する。

Shape Geometryは#021へ委譲し、Input Guide用に#023側で再実装しない。

## v1.0.65 SVG logical coordinate contract

`BoneFlowRenderer.serializeSvg()` serializes both Shape and Joint in Preview logical coordinates. Workspace zoom/pan is not baked into exported geometry.


## v1.0.78 Joint color Caller boundary

Joint quick-menu color UI uses `BoneColorPicker.attachCaller(trigger, boneInput, options)` with `allowedKinds: ["solid"]`. The RETURN value is normalized by the existing `applyJointMenuProperty(id, "lineColor", value)` path. The persistent Joint contract remains `#RRGGBB`; the existing text field remains editable. #023 does not inspect or position #040 internal Overlay / Tooltip DOM.

## v1.0.79 dependency bootstrap contract

The #023 bootstrap treats #022 v1.0.8 and #040 v1.0.15 as minimum compatible versions within the same major.minor line. Higher patch versions remain valid only when the required Public API contract is present.
