본문으로 건너뛰기

이름·ID·참조

사용자와 SDK는 읽을 수 있는 semantic key를 사용하고, 저장·권한·동시성은 opaque 내부 reference를 사용합니다.

종류역할
semantic keygirder_review, resistance_check코드·UI·MCP에서 읽고 쓰는 stable 이름
immutable refrevisionRef, artifactRef, documentRefportable content를 digest로 고정
infrastructure IDUUIDv7, database key저장과 동시성 처리
display labelGirder review번역·사용자 표시

Core semantic key grammar와 scope

CORE public semantic key는 ASCII lower_snake_case를 사용합니다. 문법은 ^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$, 길이는 1~128 ASCII 문자입니다. 입력을 case-fold하거나 Unicode normalize하지 않고 문법과 다른 입력을 거부합니다. 아래 열아홉 행이 닫힌 CORE 집합이며 다른 domain key를 이 표에 추가하지 않습니다.

keyunique scope
workspaceKeyOrganizationstructural_team
projectKeyWorkspacebridge_package
reportKeyProjectgirder_review
flowKeyProject 또는 packagegirder_check
connectionKeyReportgirder_check
blockKeyReportdesign_basis
fieldKeyReport block 또는 typed Recordspan
slotKeyReport blockutilization
tableKeyReportload_cases
rowKeyReport tableuls_01
functionKeypackagegirder_resistance
componentKeypackagemodel_analysis
nodeKeyFlowresistance_check
groupKeyFlowmember_check
subflowKeyFlowsection_properties
portKeyFunction, Component 또는 Flow interfaceutilization
settingKeyComponentDescriptoranalysis_case
mappingKeyReport Flow connectionspan_to_input
surfaceKeyAppSurfaceDescriptorbearing_check
runKeyProjectnightly_batch
resultKeyRundeflection_table

Python local variable, Canvas 순서, label, DOM 위치와 file path는 semantic identity에 포함하지 않습니다.

Project가 소유하는 Report 또는 Flow target에는 scope.kind = "project", workspaceKeyprojectKey가 항상 필요합니다. Tool session이 현재 Project를 열고 있어도 이 세 field를 생략하거나 hidden current Project로 보완하지 않습니다. Local draft와 package dependency는 각각 documentdependency scope를 사용합니다.

이 규칙은 Tool·command 경계를 넘는 standalone semantic target에 적용합니다. Exact Report나 Flow 안에 저장되는 Node target, Report result slot과 input binding은 owning revision에 상대적인 nested reference입니다. 이를 단독으로 Tool에 전달할 때는 owning Report 또는 Flow의 full scoped target을 함께 보냅니다.

Domain semantic key ownership

Plan 12 section 7.1이 추가로 이름 붙인 다음 일곱 key는 CORE key가 아닙니다. 각 key의 문법과 uniqueness는 owning domain record가 소유하며, CORE 표로 승격하지 않습니다.

domain keyowning record
calculationKeyEngineeringCalculation
valueKeyEngineeringCalculation
equationKeyReferenceEquation
checkKeyEngineeringCalculation
publicationKeyPublication
templateKeyTemplateRelease
listingKeyCatalogListing

Opaque handles

runRef, snapshotReflocalFileRef는 semantic key 또는 content digest가 아닌 opaque handle입니다.

handleissuer
runRefRuntime ledger
snapshotRefResult store
localFileRefPrivileged desktop host

Local Recent 항목은 원본 절대 경로 대신 localFileRef를 나릅니다. privileged desktop host만 그것을 해석하며, renderer, Report/PXFLOW 문서, MCP, AI context, telemetry, support bundle과 Cloud API는 그 값을 읽지 않고 그대로 나릅니다.

json
{
  "localFileRef": "issued-local-file-handle"
}

세 handle의 내부 형식은 client에 명시하지 않습니다. Client는 발급된 값을 exact하게 복사할 수만 있고 parse하거나 prefix·UUID·digest 규칙을 추측하거나 새 값을 구성하면 안 됩니다. 이 표는 lower_snake_case semantic-key 표와 분리된 별도 public contract입니다.

Public content-digest references

revisionRef, artifactRef, documentRef의 wire grammar는 모두 sha256:<64 lowercase hexadecimal characters>입니다. 정규식으로는 ^sha256:[0-9a-f]{64}$이며 uppercase hex, bare UUID와 mutable latest handle을 거부합니다. 내부 UUIDv7 revisionId는 database identity일 뿐 public wire나 portable artifact에 절대 나타나지 않습니다.

.pxreport.flowConnections는 exact Flow revision을 고정합니다. Portable package는 server 없이도 immutability를 검증하고 다른 host로 옮길 수 있어야 하므로 public ref가 content immutability를 스스로 증명해야 합니다. 이 결정은 artifact revision을 UUIDv7로만 설명하고 SHA-256을 별도 content-addressed object로 제한했던 Plan 12 sections 7.1과 7.4를 명시적으로 교정합니다.

Report target

json
{
  "scope": {
    "kind": "project",
    "workspaceKey": "structural_team",
    "projectKey": "bridge_package"
  },
  "reportKey": "girder_review",
  "revisionRef": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}

Report block과 typed value 위치는 target 뒤에 stable key를 이어서 지정합니다.

json
{
  "scope": {
    "kind": "project",
    "workspaceKey": "structural_team",
    "projectKey": "bridge_package"
  },
  "reportKey": "girder_review",
  "revisionRef": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "value": {
    "blockKey": "design_basis",
    "fieldKey": "span"
  }
}

Flow input에 저장하는 표 선택은 tableKey, stable rowKeys, exact rowKey mapping과 source→input fields mapping으로 지정합니다. 화면의 행 번호와 현재 정렬 순서는 selection identity가 아닙니다.

Managed Flow target

json
{
  "scope": {
    "kind": "project",
    "workspaceKey": "structural_team",
    "projectKey": "bridge_package"
  },
  "flowKey": "girder_check",
  "revisionRef": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}

Run, Report connection, Publication과 dependency는 exact immutable revisionRef를 고정합니다. UI가 최신 draft를 보여 줄 때도 저장된 target ref는 해당 revision을 계속 가리킵니다.

Local session target

열려 있는 Local document는 trusted host가 발급한 session handle을 사용합니다.

json
{
  "scope": {
    "kind": "document",
    "documentRef": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
  },
  "flowKey": "girder_check",
  "revisionRef": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}

documentRef는 현재 document의 content digest입니다. Trusted host는 이 digest를 현재 session의 authorized document에 resolve하고, Save와 Run application service가 OS permission과 current file identity를 다시 확인합니다. Session permission handle은 portable target에 저장하지 않습니다.

Package dependency target

json
{
  "scope": {
    "kind": "dependency",
    "packageKey": "section_flows",
    "packageVersion": "1.4.0",
    "packageDigest": "sha256:package-digest"
  },
  "flowKey": "section_properties",
  "revisionRef": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}

Dependency target은 package version과 digest를 함께 고정합니다. Component dependency required 상태에서는 exact dependency를 설치하거나 접근 권한을 받은 뒤 같은 target을 resolve합니다.

Flow public port target

Report Workbench는 Flow-level public input/result를 선택합니다.

json
{
  "flow": {
    "scope": {
      "kind": "project",
      "workspaceKey": "structural_team",
      "projectKey": "bridge_package"
    },
    "flowKey": "girder_check",
    "revisionRef": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
  },
  "port": {
    "direction": "input",
    "portKey": "span"
  }
}
  • Flow input/result: scope + flowKey + revisionRef + direction + portKey
  • Node input/result: 위 Flow ref + nodeKey + direction + portKey
  • Report connection: Flow-level public port target만 사용
  • Flow 내부 binding: Node-level port target 또는 Flow boundary target 사용

Canvas handle ID와 연결선 ID는 public target에 포함하지 않습니다.

Report Flow connection identity

Report에서 같은 Flow를 사용하는 한 연결은 connectionKey로 찾습니다.

json
{
  "report": {
    "scope": {
      "kind": "project",
      "workspaceKey": "structural_team",
      "projectKey": "bridge_package"
    },
    "reportKey": "girder_review",
    "revisionRef": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  },
  "connectionKey": "girder_check",
  "flowTarget": {
    "scope": {
      "kind": "project",
      "workspaceKey": "structural_team",
      "projectKey": "bridge_package"
    },
    "flowKey": "girder_check",
    "revisionRef": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
  }
}

Input/result mapping의 stable identity는 connection 안에서 유일한 mappingKey입니다. portKey, source와 target은 mapping의 의미를 구성하며, 이 의미가 바뀌면 connection의 mappingGeneration을 증가시킵니다. Source와 target은 Report의 stable blockKey, fieldKey, tableKey, rowKeyslotKey를 사용합니다.

Report의 connectionKey는 Flow 내부 Node와 binding identity를 복제하지 않습니다. Flow revision이 내부 구조 전체를 고정하고 Report는 public boundary만 참조합니다.

Canvas Node target ref

flow.node("node_key", target)의 target은 두 variant 중 하나입니다. Project가 소유하는 Python 계산도 @px.function(key="...", ...)으로 등록하고 FunctionRef로 materialize합니다.

FunctionRef

json
{
  "kind": "function",
  "publisher": "pipelinexlab",
  "packageKey": "structural_checks",
  "packageVersion": "2.3.0",
  "packageDigest": "sha256:package-digest",
  "releaseByteDigest": "sha256:release-digest",
  "descriptorDigest": "sha256:function-descriptor-digest",
  "functionKey": "girder_resistance",
  "functionVersion": "4.0.0"
}

Component target

json
{
  "kind": "component",
  "publisher": "pipelinexlab",
  "packageKey": "structural_analysis",
  "packageVersion": "1.0.0",
  "packageDigest": "sha256:package-digest",
  "releaseByteDigest": "sha256:release-digest",
  "componentKey": "model_analysis",
  "componentContractVersion": 1
}

ComponentRef

json
{
  "publisher": "pipelinexlab",
  "packageKey": "structural_analysis",
  "packageVersion": "1.0.0",
  "packageDigest": "sha256:package-digest",
  "releaseByteDigest": "sha256:release-digest",
  "componentKey": "model_analysis",
  "componentContractVersion": 1
}

FunctionRef는 package와 Function version뿐 아니라 package bytes, verified marketplace release envelope와 FunctionDescriptor digest를 함께 고정합니다. Component target 예시는 serialized outer NodeTarget::Component이며 discriminator kind: "component" 뒤에 7-field ComponentRef를 flatten한 8-member variant입니다. 현재 내부 ComponentRef는 install 뒤 product resolver가 exact V1 release/declaration을 찾는 7-field join key이며, kind나 verified presentation resource를 포함하지 않습니다. 두 shape를 모두 ComponentRef라고 부르거나 서로 대체하지 않습니다. production Canvas는 이 target을 read-only unsupported로 표시합니다. Project-owned @px.function도 materialization 과정에서 같은 exact FunctionRef shape를 사용하며 source path나 Python symbol을 별도 target variant로 저장하지 않습니다. functionKeycomponentKey는 각각 @px.function(key="...", ...), @px.component(key="...", ...)에 명시한 stable key입니다. Python symbol을 rename해도 이 key를 유지하면 저장 identity가 바뀌지 않습니다. 다중 선언 container와 host-rendered projection은 Node presentation과 third-party UIcontract_only V2입니다.

External Subflow reference

다른 module이 export한 Flow는 flow.subflow(...)의 external reference로 저장합니다.

json
{
  "subflowKey": "section_properties",
  "target": {
    "kind": "flow",
    "scope": {
      "kind": "dependency",
      "packageKey": "section_flows",
      "packageVersion": "1.4.0",
      "packageDigest": "sha256:package-digest"
    },
    "flowKey": "section_properties",
    "revisionRef": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
    "semanticDigest": "sha256:semantic-digest"
  }
}

Caller에서는 read-only nested Flow로 열고 Edit source Flow로 owning scope를 엽니다. 이 object는 .pxflow.externalSubflows[]에 저장하며 regular Node의 target union에 넣지 않습니다.

Group identity

Group은 같은 Flow 안의 groupKey와 member nodeKey로 식별합니다.

json
{
  "groupKey": "member_check",
  "members": ["load_effect", "resistance_check"]
}

Group은 member Node identity와 connection endpoint를 그대로 유지합니다.

Run과 Result reference

Run은 exact Flow revision과 input digest를 가집니다. Result는 Run의 named result key 또는 immutable snapshot ref로 찾습니다.

json
{
  "runRef": "issued-runtime-handle",
  "snapshotRef": "issued-result-handle",
  "resultKey": "utilization"
}

Report result mapping은 connectionKey, Flow portKey와 Report destination을 저장하고, 표시할 값은 immutable Result snapshot에서 읽습니다. 큰 result resource는 snapshot과 result key에서 발급한 permission-checked resource ref를 사용합니다.

Component artifact reference

Component가 만든 artifact는 source Flow Run과 producing Node를 가리킵니다.

json
{
  "artifactRef": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
  "artifactKind": "analysis-model",
  "source": {
    "runRef": "issued-runtime-handle",
    "nodeKey": "model_analysis",
    "resultKey": "model"
  }
}

Artifact 설정을 바꾸려면 source Component Node를 편집하고 새 Flow revision과 Run을 만듭니다.

App Surface identity

Standalone App Surface는 surfaceKey를 사용합니다.

json
{
  "adapterCategory": "app_surface",
  "formatKey": "streamlit",
  "surfaceKey": "bearing_check"
}

App Surface와 Component editor가 각 descriptor와 renderer registry에서 resolve하는 동작은 계획입니다. 현재 production Flow reader에는 Component renderer/modal/editor bridge가 없습니다.

Rename

Rename은 key와 모든 in-scope reference를 한 transaction에서 바꿉니다.

  • Report의 block·field·slot key 변경은 input/result mapping을 함께 갱신합니다.
  • Flow public port key 변경은 연결된 Report 영향 분석을 먼저 보여 줍니다.
  • Function/Component public key 변경은 새 package contract version을 요구합니다.
  • Flow 안의 Node, Group과 port key 변경은 impact plan을 먼저 보여 줍니다.
  • 완료된 Run과 Result snapshot의 과거 provenance는 당시 key를 유지합니다.
  • SDK-linked source는 source-safe diff 뒤 rematerialize합니다.

Copy와 import

  • Copy는 새 managed identity와 revision history를 만듭니다.
  • Imported Flow dependency는 exact package와 revision reference를 유지합니다.
  • Portable Project import는 digest, key conflict와 package availability를 먼저 검사합니다.
  • Label이 비슷한 기존 object와의 병합은 사용자가 exact target을 선택해 수행합니다.

DerivationOperation은 내부 ledger record이며 정확히 derivationOperationId, operationKind, sourceScope, destinationScope, artifactMappings, remapDigest, createdAt을 가집니다. ImportReceipt도 내부 ledger record이며 정확히 importReceiptId, derivationOperationRef, sourcePackageDigest, destinationScope, artifactMappings, remapDigest, outcome, createdAt을 가집니다. 두 record는 additional member를 허용하지 않습니다.

remapDigest preimage는 operationKind, sourceScope, destinationScope, artifactMappings만 포함합니다. 각 mapping은 sourceArtifactId, sourceRevisionRef, destinationArtifactId, destinationRevisionRef의 닫힌 shape이고 sourceArtifactId ascending으로 정렬한 뒤 RFC 8785 JCS를 적용합니다. 중복 sourceArtifactId 입력은 digest를 만들기 전에 fail-closed로 거부하며 caller order나 tie-breaker 의미를 부여하지 않습니다. Record ID, actor/session state, createdAtremapDigest 자체는 preimage 밖입니다. Copy, exact dependency import와 portable Project remap의 승인 case는 identity-digest.v1.remap.json이 소유합니다.

Digest preimage allowlists

모든 digest는 SHA-256을 사용합니다. byteDigestexactUncompressedBytes 한 field의 raw bytes, semanticDigestdirectArtifact 한 field의 parsed direct artifact 전체를 RFC 8785 JCS로 canonicalize한 bytes를 preimage로 사용합니다. directArtifact 전체에는 layout, presentation, metadata와 extensions가 포함되지만 digest와 signature field는 포함되지 않습니다.

executionDigest의 닫힌 field allowlist는 다음 열두 field입니다: prompt, runtimeObservableDescription, runtimeObservableDefault, runtimeObservablePolicy, componentCodeDigest, environmentDigest, lockDigest, imageDigest, inputBlobDigest, externalDatasetRevision, seed, algorithm. 적용 가능한 field만 field-name ascending으로 정렬한 object를 만들고 RFC 8785 JCS를 적용합니다. Viewport, Node position과 panel state는 이 object에 들어가지 않습니다. 같은 digest만으로 cache를 허가하지 않으며 nondeterministic 또는 effectful target은 owning target contract의 explicit cache policy가 추가로 필요합니다.

세 digest class 모두 revision envelope의 artifactId, revisionId, generation, ancestry (parentRevisionIds)를 preimage 밖에 둡니다. 따라서 public revisionRef는 내부 UUID나 mutable generation이 아니라 canonical content 자체를 증명합니다. Class별 닫힌 allowlist, inside/outside 판정과 valid/invalid case는 identity-digest.v1.preimages.json이 소유합니다.

Diagnostic params digest preimage는 key를 ascending으로 정렬한 뒤 RFC 8785 JCS를 적용한 bytes입니다. 이 규칙은 accepted RFC-003과 공동 소유하며 두 contract에서 byte-for-byte 동일해야 합니다.

V1은 첫 production version입니다. 이전 production identity/digest profile과 migration function은 없으며, 이 문서도 version-specific migration을 발명하지 않습니다.

Independent digest correctness

RFC-002 correctness gate는 contract와 fixture에서 별도로 작성한 no-dependency stdlib-Python 최소 재구현을 Rust core 결과와 비교합니다. WASM, Python wheel과 TypeScript harness는 같은 Rust core의 binding fidelity를 증명하지만 독립 correctness oracle로 세지 않습니다.

불변식

  1. 사용자는 semantic key를 읽고 Runtime은 authorized immutable ref를 실행합니다.
  2. Label, path, Canvas 위치와 DOM 위치는 identity에서 분리합니다.
  3. 일반 Canvas Node target은 explicit stable key를 가진 FunctionRef 또는 ComponentRef입니다.
  4. External Subflow는 regular Node target과 구분된 exact Flow ref입니다.
  5. Report connection은 Flow public port만 참조하고 .pxreport가 소유합니다.
  6. Report result position은 immutable Result snapshot을 읽습니다.

이어서 보기