본문으로 건너뛰기

실행과 결과

PipelineXLab에서 계산을 실행하는 대상은 저장된 Flow revision 하나입니다. SDK, PXFLOW Studio, Report Workbench와 MCP 중 어디서 Run을 시작해도 같은 Flow, input, Node와 result 계약을 사용합니다.

서드파티 Component의 현재 실행 경계

이 문서는 admission을 통과한 target의 검증·실행·artifact·recovery 의미를 정의합니다. 현재 V1 production의 서드파티 Component install admission과 activation은 exact ProjectScope { kind: "project", workspaceKey, projectKey } isolation과 execution-trust closure가 모두 닫힐 때까지 계약상 차단합니다. 현재 installer에는 실행 bytes를 분리해 보관하는 inactive quarantine 상태가 없고, 두 production gate도 구현 완료 상태가 아닙니다. 따라서 아래 package diagnostic이나 recovery 의미를 현재 서드파티 package 설치·실행 명령으로 해석하지 않습니다. 정확한 blocker는 Component container V2와 서드파티 Node UI가 소유합니다.

Runtime은 px.Report 또는 Report Workbench가 .pxreport.flowConnections에 저장한 source를 typed Flow input payload로 만들고, connection이 고정한 exact Flow revision을 일반 Flow Run으로 실행합니다. 결과는 immutable ResultSnapshot에 저장한 뒤 Report의 result 위치에 읽기 전용으로 표시합니다.

실행 경계

객체역할사용자가 보는 곳
Flow revision실행할 Node·binding·setting을 고정Save history
Run고정된 Flow와 input으로 수행한 한 번의 실행Run panel, Project Activity
TaskRuntime이 Node 계산을 처리하는 내부 작업Run detail의 진단·진행 정보
Attemptworker가 Task를 시도한 내부 기록오류 상세 또는 audit
ResultSnapshotRun이 확정한 변경 불가능한 named result와 provenanceResult panel

Report connection은 별도 실행 종류를 만들지 않습니다. 같은 connectionKey의 input mapping과 result mapping은 ordinary Flow Run 하나와 그 ResultSnapshot을 공유합니다. 공개 실행 단위와 실행 용어는 Run입니다. Activity와 Batch는 여러 ordinary Run을 함께 표시하거나 계획하는 grouping이며 Run을 대신 소유하지 않습니다.

SDK, Studio, Report와 MCP는 같은 Run을 만듭니다

SDK

python
from pipelinexlab import px


client = px.Client(workspace="engineering", project="bridge_design")
run = client.run(
    girder_design,
    span=24.0,
    design_cases=design_cases,
)
snapshot = run.wait()
utilization = snapshot.results.governing_utilization

위 예제처럼 client.run(flow, **inputs)를 호출하면 Flow의 public input을 SDK에서 직접 전달합니다. Report에 저장한 connection은 client.run(connection)으로 실행하며, .pxreport의 input mapping이 입력을 공급하고 result mapping이 Report의 표시 위치를 결정합니다. 두 호출은 모두 고정된 Flow revision으로 ordinary Run 하나를 만듭니다.

PXFLOW Studio

Report Workbench

Report Workbench는 exact flowTarget.revisionRef, mapped input port key와 requested result port key를 ordinary Run command로 보냅니다. .pxreport는 queue, Task, Attempt와 worker 상태를 저장하지 않습니다.

MCP

네 경로 모두 exact Flow target, immutable revision, input port key와 requested result key를 사용합니다. 브라우저에서 열려 있는 draft나 이름이 비슷한 최신 Flow를 Runtime이 추측하지 않습니다.

Run command

사용자용 command는 semantic target과 expected revision을 전달합니다.

json
{
  "commandId": "client-generated-idempotency-key",
  "target": {
    "scope": {
      "kind": "project",
      "workspaceKey": "structural_team",
      "projectKey": "bridge_package"
    },
    "flowKey": "girder_design",
    "revisionRef": "<immutable Flow revision ref>"
  },
  "inputs": {
    "span": {
      "type": { "kind": "float64" },
      "unit": "m",
      "value": 24.0
    }
  },
  "requestedResults": ["governing_utilization"],
  "reason": "user"
}
  • 같은 command body와 commandId를 재전송하는 transport retry는 idempotent하며 이미 만든 같은 Run을 반환합니다. 같은 commandId에 다른 body를 보내면 충돌로 거부합니다.
  • 사용자가 Run again을 선택하는 것은 retry가 아니라 새 실행 의도이므로, input과 revision이 같더라도 새 commandId와 새 Run을 만듭니다.
  • inputs의 key는 exact Flow input portKey입니다.
  • inputs member는 필수이며 public input이 없는 Flow에는 빈 object를 보냅니다. 각 값은 RFC-003 TypeDescriptor, canonical value, 그리고 선언된 경우 exact unit을 가진 닫힌 object입니다. Runtime은 exact saved Flow revision과 한 번 검증한 canonical payload bytes를 filesystem CAS에 저장하고, ledger와 worker에는 RFC-002 public digest reference만 전달합니다.
  • Flow InputPort의 optional required member가 없으면 기존 V1 의미를 보존해 required입니다. required: false인 input만 payload에서 생략할 수 있습니다. Constraint grammar v1은 allowedValues 하나로 닫혀 있으며, type·unit 확인 뒤 canonical submitted value가 그 목록에 없으면 RunInputConstraintViolation(portKey)로 Run 생성 전에 거부합니다. Kind 목록은 schema, core와 contract lock을 함께 바꾸는 additive update로만 늘리며 expression이나 코드를 받지 않습니다.
  • Exact saved Flow revision에 typeDefinitions가 있으면 record input은 그 closure의 field 이름, field TypeDescriptor, required와 nullable까지 검증합니다. Closure를 생략한 기존 V1 revision은 호환성을 위해 object 경계 검증을 유지하며, Runtime input이나 다른 revision에서 definition을 추론하지 않습니다.
  • effect가 있는 실행은 trusted host가 발급한 별도 approval을 요구할 수 있습니다.
  • SDK, UI와 MCP client가 내부 artifact ID나 worker Task를 만들지 않습니다.

Application service는 권한과 revision을 확인한 뒤 Runtime 전용 pinned DTO로 해석합니다.

json
{
  "commandId": "client-generated-idempotency-key",
  "target": {
    "artifactRef": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
    "revisionRef": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
    "flowKey": "girder_design"
  },
  "inputs": {
    "span": {
      "type": { "kind": "float64" },
      "unit": "m",
      "value": 24.0
    }
  },
  "requestedResults": ["governing_utilization"],
  "reason": "user"
}

이 DTO는 application service와 Runtime 사이의 내부 계약입니다.

Report connection에서 Run을 만드는 순서

  • 같은 flowConnection의 여러 Report source는 각각 서로 다른 Flow input에 mapping되어 한 Run의 input payload에 함께 들어갑니다. 같은 source를 서로 다른 input에 재사용할 수도 있습니다.
  • 한 Run 기준 같은 Flow input에 active source가 둘 이상일 수 없습니다. scalar들을 하나의 input으로 암묵적으로 merge하지 않고 explicit Record/List/Table을 전달하거나 Flow/subflow 안에서 조합합니다.
  • 한 Run은 여러 named result를 만들 수 있고, 한 named result는 별도 resultMapping으로 여러 Report target에 표시할 수 있습니다. 단, 한 Report semantic slot/field에는 active mapping이 하나만 허용되며 여러 result를 한 slot에 덮어쓰지 않습니다.
  • Record/Table projection은 explicit field mapping을 사용하고 Table은 stable row-key mapping도 사용합니다.
  • 한 Report가 서로 다른 Flow connection을 사용하면 connection마다 독립된 ordinary Flow Run을 만듭니다. 여러 connection은 resource budget 안에서 bounded parallel로 실행될 수 있고 완료 순서는 지정되지 않습니다.
  • Report Activity는 한 사용자 동작 아래 Run을 묶어 표시할 뿐 실행 owner, transaction, dependency 또는 ordering boundary가 아닙니다. 각 connection의 Run을 따로 취소하고 재시도합니다.
  • Report source, Flow revision 또는 mapping이 바뀌면 기존 projection을 Stale로 표시하고 새 Run이 완료될 때까지 마지막 accepted Result의 provenance를 유지합니다.
  • Report connection, ordinary Flow Run과 ResultSnapshot이 공개 실행 계층 전체를 이룹니다.

Report는 connection 배열 순서, 화면 배치, Activity group 또는 result mapping을 근거로 Flow connection 사이의 dependency나 순서를 추론하지 않습니다. connection B가 A의 result를 필요로 하면 하나의 Flow 또는 명시적 subflow composition에서 dependency를 선언하고 합성된 public input/result boundary를 Report에 공개합니다.

전체 mapping schema는 Report와 Flow 공개 포트 연결을 따릅니다.

Report Run isolation과 current Result

Report connection Run은 dispatch할 때 다음 intent를 immutable하게 고정합니다.

isolation 항목고정하는 값
Report sourceexact immutable reportRevisionRef
connection과 mappingsconnectionKey + exact mappingGeneration; target owner는 stable mappingKey로 식별
Flow targetexact immutable flowTarget.revisionRef
input payloadtype·unit·shape, Record field, List 순서, Table stable row key를 포함한 canonical input digest
commandProject scope의 idempotency key인 commandId
projection intentaccepted single-Run 또는 whole-Batch command마다 한 번 증가하는 projectionIntentGeneration
Batch childbatchKey, stable caseKey와 그 case의 current childRunKey

Runtime projection ledger가 소유 Project scope 안의 (reportKey, connectionKey) pair별 current projectionIntentGeneration을 소유합니다. pair는 Workspace·Project 경계를 넘지 않으므로 다른 Project가 같은 reportKey·connectionKey 이름을 쓰더라도 generation과 target은 독립입니다. .pxreport에는 저장하지 않으며, application service는 commandId idempotency 확인과 새 generation 등록을 원자적으로 처리합니다.

canonical input digest preimage는 RFC-002와 공동 소유합니다. exact typed input projection의 object key를 ascending으로 정렬한 뒤 RFC 8785 JCS를 적용하고 SHA-256으로 digest하며, RFC-004가 별도의 정렬·canonicalization 규칙을 만들지 않습니다. Flow input portKey, type·unit·shape와 value/reference는 이 exact projection의 provenance로 남고 typed List의 semantic item 순서는 유지됩니다. 화면 selection, Report block 순서, mapping JSON 배열 순서, Table 표시 sort와 label은 실행 identity가 아닙니다. mapping identity와 cardinality의 exact 규칙은 mapping cardinality를 따릅니다.

public content reference는 RFC-002의 sha256:<lowercase hex> 규칙을 그대로 사용합니다. runRefsnapshotRef도 RFC-002가 정한 opaque handle이므로 client가 parsing하거나 새로 만들지 않습니다. 이 문서는 그 reference 형식이나 preimage field allowlist를 다시 정의하지 않습니다.

Report target의 current projection을 교체하는 작업은 해당 target에 기록된 current intent를 expected value로 비교하는 CAS입니다. Run이 끝났을 때 pinned Report revision, connectionKey, mappingGeneration, target owner mappingKey, Flow revision, canonical input digest와 이 Run의 projectionIntentGeneration이 현재 intent와 모두 exact match할 때만 그 ResultSnapshot을 current로 승격합니다.

새 mapping 저장이나 새 Run again intent가 먼저 current가 됐다면, 늦게 완료된 이전 Run의 ResultSnapshot은 history와 provenance에는 계속 남지만 현재 Report projection을 교체할 수 없습니다. 이 규칙은 성공 완료 순서와 네트워크 delivery 순서가 달라도 마지막 도착 값을 current로 잘못 선택하지 않게 합니다. commandId retry는 같은 Run을 반환하지만, 같은 connection의 재실행은 항상 새 commandId, 새 Run과 새 projectionIntentGeneration을 만든다는 규칙도 그대로 적용됩니다.

검증과 실행 순서

Run을 만들기 전에 다음을 확인합니다.

  1. target과 revision을 현재 principal이 읽고 실행할 수 있는지 확인합니다.
  2. 필요한 Function/package target과 exact ref·version이 Project의 admitted installed closure에서 resolve되는지 확인합니다. 현재 서드파티 Component는 위 P0 closure가 닫히지 않았으므로 install이나 activation으로 복구하지 않고 여기서 fail closed합니다.
  3. required input, type, unit, shape와 Node setting을 검증합니다.
  4. Function·Component의 capability와 실행 정책을 Project 정책과 비교합니다.
  5. dependency DAG와 요청 result에 필요한 upstream closure를 계획합니다.
  6. 승인된 범위에서 Task를 실행하고 결과를 조립합니다.

실패한 검증을 건너뛰고 일부 Node만 임의 실행하지 않습니다. 서로 의존하지 않는 branch는 resource budget 안에서 병렬로 실행할 수 있습니다.

Run 상태

text
Created ─→ Validating ─→ Queued ─→ Running ─→ Succeeded
   │           │            │          ├─→ Failed
   │           ├─→ Failed   ├─→ Failed ├─→ Cancelled
   └─→ Cancelled            │          └─→ Indeterminate
               └─→ Cancelled└─→ Cancelled
상태의미
Createdcommand를 접수하고 revision을 확인하는 중
Validating계약·권한·capability를 검사하는 중
Queued실행 자원을 기다리는 중
Running하나 이상의 Task가 실행 중
Succeeded요청한 result가 정상 확정됨
Failedusable result를 확정하지 못함
Cancelled취소가 terminal 상태로 확정됨
Indeterminate외부 effect 결과를 안전하게 판정할 수 없어 확인이 필요함

Partial success는 ordinary Run 상태가 아니라 explicit Batch의 aggregate summary입니다. 성공·실패·취소한 child Run은 각각 위 terminal 상태와 immutable Result를 유지합니다.

브라우저 연결이 끊기거나 창을 닫아도 durable Run 상태는 Runtime ledger가 소유합니다. 다시 열면 run_get과 Run panel이 같은 기록을 읽습니다.

Report projection outcome sidecar

계산 성공(Succeeded)과 Report 반영은 별개입니다. Report connection으로 접수된 Run은 접수 transaction에서 durable projection outcome 행을 함께 만들고, run_get과 Report 제출 응답의 data.projection sidecar가 그 행을 읽습니다. projection이 없는 일반 Flow Run은 null입니다. sidecar는 closed object이며 member는 다음 여섯 개입니다.

member의미
stateclosed 3종: pending, applied, refused
snapshotRef계산 성공 commit이 채우는 immutable ResultSnapshot; 그 전에는 null
reportRevisionRefapplied가 실제로 만든 exact immutable Report revision; 그 외 null
refusalReasonclosed reason token; applied는 null
diagnosticsrefused가 가질 수 있는 schema-valid RFC-003 Diagnostic 배열; 그 외 빈 배열
detail표시용 문장; 분기 입력이 아님

appliedrefused는 terminal이며 자동으로 재처리하지 않습니다. 새 실행은 새 intent입니다. pending은 일시 장애의 마지막 structured reason을 남길 수 있으나 state는 pending을 유지하며, supervisor가 시작 시와 정상 poll에서 pending이고 계산 snapshot이 durable한 Run만 bounded query로 재처리합니다. 재처리는 계산 재실행이 아니고, superseded 판정 전에 exact command receipt를 먼저 읽어 이미 반영된 결과를 applied로 복원합니다.

refusalReason은 closed enum입니다: reportProjectionReportChanged, reportProjectionSuperseded, reportProjectionResultMissing, reportProjectionValueUnavailable, computationFailed, computationCancelled, computationIndeterminate, 그리고 pending 전용 transient note storageUnavailable. 계산 실패·취소·Indeterminate로 반영할 결과가 없으면 그 실행 의미의 computation* reason으로 refused가 기록됩니다. reason은 원인 발생 지점에서 선택되며 표시 문장에서 복원하지 않습니다.

완전한 transition matrix

driversystem은 Runtime·scheduler·worker admission 같은 신뢰된 system actor를 뜻합니다. user-or-system은 권한 있는 사용자 command와 정책·parent cancellation 같은 system command가 모두 같은 cancel 전이를 요청할 수 있다는 뜻입니다.

fromtodriverprecondition
CreatedValidatingsystemcommand가 접수되고 immutable 실행 intent가 기록됨
CreatedCancelleduser-or-system취소가 validation 시작 전에 접수됨
ValidatingQueuedsystem계약·권한·capability 검증이 모두 성공함
ValidatingFailedsystem계약·권한·capability 검증 중 하나가 실패함
ValidatingCancelleduser-or-system취소가 queue admission 전에 접수됨
QueuedRunningsystemworker admission이 성공하고 current lease와 fence가 발급됨
QueuedFailedsystemadmission이 거부됨
QueuedCancelleduser-or-system취소가 실행 시작 전에 접수됨
RunningSucceededsystem모든 required Task가 완료되고 requested result가 확정됨
RunningFailedsystem실행 실패로 usable result를 확정할 수 없음
RunningCancelleduser-or-systemactive Task 취소가 terminal로 확정됨
RunningIndeterminatesystem실행된 effect의 외부 결과를 안전하게 판정할 수 없음
  • 근거: Cancelled는 실행 전에도 사용자 intent 또는 system policy를 즉시 닫을 수 있어야 하고, validation failure와 admission rejection은 worker 실행 전 Failed로 확정해야 합니다. Effect가 실제로 실행되기 전에는 결과가 undecidable할 수 없으므로 IndeterminateRunning에서만 도달합니다.
  • 성능·확장 영향: 12개의 닫힌 edge를 상수 lookup으로 검사하므로 state history를 검색하지 않습니다. Early cancel/fail은 불필요한 queue·worker 점유를 피하고 terminal write 한 번으로 끝납니다.
  • Fail-closed: 표에 없는 edge, terminal state를 벗어나는 edge, 허용되지 않은 driver 또는 충족되지 않은 precondition은 state를 바꾸지 않고 거부합니다.

terminal diagnostic

terminal state는 RFC-003의 accepted 66-code registry를 인용하며 새 PX_ code를 만들지 않습니다.

terminal stateRFC-003 diagnostic 규칙
Succeededterminal error diagnostic 없음
Failed실패를 일으킨 exact code를 보존합니다. validation은 PX_REPORT_CONNECTION_NOT_FOUND, PX_REPORT_FLOW_REVISION_NOT_FOUND, PX_REPORT_MAPPING_SOURCE_NOT_FOUND, PX_REPORT_MAPPING_TARGET_NOT_FOUND, PX_REPORT_MAPPING_CONFLICT, PX_REPORT_MAPPING_INCOMPATIBLE, PX_REPORT_TABLE_ROW_KEY_INVALID, PX_AMBIGUOUS_TARGET, PX_TARGET_NOT_FOUND, PX_PACKAGE_NOT_INSTALLED, PX_PACKAGE_VERSION_MISMATCH, PX_PACKAGE_CATALOG_UNAVAILABLE, PX_PACKAGE_ACCESS_DENIED, PX_FUNCTION_NOT_FOUND, PX_FUNCTION_VERSION_MISMATCH, PX_COMPONENT_NOT_FOUND, PX_COMPONENT_CONTRACT_MISMATCH, PX_COMPONENT_UNRESOLVED, PX_PUBLIC_MODULE_INVALID, PX_DEPENDENCY_RESOLUTION_FAILED, PX_REQUIRED_INPUT_UNBOUND, PX_PORT_NOT_FOUND, PX_PORT_DIRECTION_MISMATCH, PX_TYPE_INCOMPATIBLE, PX_UNIT_INCOMPATIBLE, PX_CARDINALITY_AMBIGUOUS, PX_FORMULA_REFERENCE_NOT_FOUND, PX_FORMULA_OPERATOR_UNSUPPORTED, PX_FORMULA_SHAPE_INCOMPATIBLE, PX_FORMULA_DOMAIN_ERROR, PX_FORMULA_COMPLEXITY_LIMIT, PX_SOLVER_CONFIGURATION_INVALID, PX_SOLVER_DID_NOT_CONVERGE, PX_FLOW_CYCLE, PX_GROUP_INVALID, PX_PERMISSION_DENIED, PX_CAPABILITY_DENIED 중 applicable code를 사용합니다. Queued admission rejection은 PX_RESOURCE_LIMIT, Running failure는 applicable PX_RESOURCE_LIMIT, PX_FUNCTION_FAILED, PX_COMPONENT_FAILED, PX_RESULT_NOT_FOUND를 사용합니다.
CancelledRFC-003에 없는 synthetic cancellation code를 만들지 않고 terminal state와 durable transition record로 표현
IndeterminatePX_EFFECT_INDETERMINATE

Diagnostic envelope, exact params key set, retryable과 params digest는 모두 RFC-003이 소유합니다. RFC-004는 terminal과 originating diagnostic의 관계만 고정합니다.

취소와 재시도

  • Cancel은 새 Task 시작을 막고 active Task에 취소를 전달합니다.

  • 이미 확정된 immutable snapshot이나 이전 Run 기록은 수정하지 않습니다.

  • worker death와 temporary resource exhaustion 같은 transient infrastructure failure만 같은 Task 안의 새 Attempt로 자동 재시도합니다. 한 Task는 최초 Attempt를 포함해 최대 3 Attempt, 즉 최대 두 번의 retry만 가집니다.

  • input, Node setting, dependency 또는 Flow revision 중 하나라도 바뀌면 새 Attempt가 아니라 새 Run을 만듭니다. 같은 intent를 사용자가 명시적으로 Run again하는 경우도 새 command와 새 Run입니다.

  • RFC-003 Diagnostic의 retryable=false는 자동 재시도하지 않습니다.

  • effect 결과가 불명확한 Indeterminate 상태는 자동 재시도하지 않습니다.

  • Report Activity에 같이 표시된 Run이나 Batch의 child Run도 각각 독립적으로 cancel/retry합니다. 한 Run의 취소·재시도가 sibling Run의 state나 ResultSnapshot을 수정하지 않습니다.

  • 근거: 짧은 infrastructure fault는 intent를 바꾸지 않으므로 같은 Task의 새 Attempt로 남기되, 실행 의미가 바뀐 작업을 retry history 안에 숨기지 않습니다. 3 Attempt는 최초 실행과 최대 두 번의 recovery 기회를 제공합니다.

  • 성능·확장 영향: Task 하나가 소비하는 execution work와 Attempt history를 최악의 경우에도 단일 Attempt의 3배로 제한해 retry storm과 무한 provenance 증가를 막습니다.

  • Fail-closed: 네 번째 Attempt, non-transient 자동 retry, retryable=false 또는 Indeterminate 자동 retry는 거부합니다.

Task lease와 fence

  • lease duration은 60초이고 20초마다 renew합니다. 두 번의 renewal을 연속으로 놓치면 마지막으로 관찰한 renewal 뒤 40초에 expiry를 선언합니다.

  • fence는 Task마다 단조 증가하는 int64입니다. 새 lease owner를 정할 때 current fence보다 엄격히 큰 값을 발급합니다.

  • completion의 fence가 Task current fence보다 낮으면 stale completion으로 거부하며 authoritative Attempt completion이나 current Result가 될 수 없습니다.

  • int64가 overflow할 상황에서는 wrap하지 않고 새 lease ownership을 거부합니다.

  • 근거: 60초 lease는 짧은 network partition을 견디면서도 두 번의 20초 renewal이 빠지면 dead worker를 40초 안에 reclaim할 수 있게 합니다.

  • 성능·확장 영향: active leased Task가 N개이면 steady-state renewal write는 대략 초당 N/20개이고, dead worker reclaim latency는 40초입니다. int64 fence는 고정 8-byte 저장과 상수 비교를 사용합니다.

  • Fail-closed: lease expiry, fence 감소·재사용·overflow 또는 current fence보다 낮은 completion은 result를 확정하거나 projection을 바꾸지 못합니다.

Indeterminate effect reconciliation

  • Indeterminate Run을 닫으려면 principal이 explicit reconcile-effect capability를 가져야 합니다. ordinary Project administration만으로는 충분하지 않습니다.

  • evidence는 external-system lookup result이며 source, lookupTime, externalIdentifier를 모두 가집니다.

  • durable reconciliation record는 original Attempt reference, reconciling principal, evidence reference와 applied | not-applied outcome을 보존합니다.

  • automatic retry는 계속 금지되고 reconciliation 전에는 Run Result를 current로 승격하지 않습니다.

  • 근거: 외부 effect의 실제 적용 여부는 별도 권한을 가진 principal이 출처와 시각, external identifier가 있는 조회 결과로만 닫아야 중복 effect와 권한 우회를 막을 수 있습니다.

  • 성능·확장 영향: external lookup과 durable write 한 번은 Indeterminate Run에만 발생해 normal execution hot path를 늘리지 않습니다. 대신 reconciliation이 끝날 때까지 current Result availability를 의도적으로 지연합니다.

  • Fail-closed: capability, evidence member 또는 허용 outcome이 하나라도 없으면 reconciliation을 거부하고 Run을 Indeterminate와 non-current 상태로 유지합니다.

Runtime ledger의 Effect와 Attempt row는 조회·저장 순서를 의미로 공개하지 않습니다. 독자는 물리 row 순서나 query 결과 순서를 실행 인과·감사 순서로 사용하면 안 됩니다. Attempt의 ordinal은 같은 Task 안의 retry 번호일 뿐 ledger ordering 보장이 아니며, 이 결정을 위해 별도 ordinal을 추가하지 않습니다. 이는 audit와 outbox가 append 순서를 관찰 가능한 의미로 공개하지 않는 원칙과 같습니다.

V1은 Effect record와 Attempt ledger를 하나의 보존 정책으로 전수 보존하고 purge를 제공하지 않습니다. expiry, retention class 또는 delete API가 없는 현재 구현을 그대로 계약화하며, 존재하지 않는 purge 기능이나 보존 기간을 약속하지 않습니다.

runRef, taskRef, attemptRef, effectRef는 caller-issued opaque value입니다. Runtime은 private representation을 가진 caller-issued ref type을 통해 받은 값을 보존할 뿐 새 값을 mint하지 못하며, compile-fail mutation case가 private construction 경계를 지킵니다. byte-identical round-trip test는 보존을 확인하고, 구조적 경계가 non-minting의 보편 부정을 맡습니다.

durable Runtime performance budget의 형상은 runLatency(p50/p95/p99), attemptLatency(p50/p95/p99), transactionRate, rowMutationAmplification, storageAmplification, batchCaseCountMax, batchLatency(p50/p95/p99)와 measurement/CPU/disk/DB version profile입니다. 모든 budget 값은 released hardware profile과 SQLite/PostgreSQL별 반복 benchmark가 생길 때까지 deferred입니다. 현재 관측된 Run 8 transaction, Attempt 2 transaction과 6+R row mutation, Batch C+2 mutation과 C read, C=1/10/100은 cost shape이며 budget이 아닙니다.

Table input과 반복

Canvas의 Node 수와 실행 데이터의 행 수를 혼동하지 않습니다.

Flow port실행 의미
px.Table[RecordType]Table 값 하나를 한 번의 Flow Run input으로 전달
list[T]list 값 하나를 한 번의 Flow Run input으로 전달
scalarscalar 한 값을 한 번의 Flow Run input으로 전달

Collection input은 item 또는 row 수와 관계없이 ordinary Run 하나입니다. 행별 계산이 필요하면 Node body가 typed Table을 명시적으로 처리하거나, 사용자가 Batch Run을 만들어 같은 Flow revision을 여러 input set으로 실행합니다. Report table selection만으로 행마다 Canvas Node나 숨은 Run을 만들지 않습니다.

explicit Batch Run

Batch는 새 execution kind가 아니라 ordinary child Run들의 명시적 grouping입니다. 다음 예에서 case_check{case_key: string, utilization: float, passed: bool} Record를 반환하는 public named result이고, batch_results는 같은 세 field를 가진 Report result table입니다. merge는 이 target을 소유하는 exact Report mapping identity도 함께 고정합니다.

json
{
  "batchKey": "girder_cases_2026_08_02",
  "flowRevisionRef": "sha256:flow-revision-digest",
  "boundedParallelism": 4,
  "cases": [
    {"caseKey": "uls_01", "inputs": {"case_key": "uls_01", "span": 24.0}},
    {"caseKey": "uls_02", "inputs": {"case_key": "uls_02", "span": 30.0}}
  ],
  "merge": {
    "connectionKey": "girder_case_batch",
    "mappingGeneration": 3,
    "resultMapping": {
      "mappingKey": "case_check_to_batch_results",
      "portKey": "case_check",
      "target": {
        "kind": "reportTableResult",
        "tableKey": "batch_results",
        "rowKey": {
          "resultFieldKey": "case_key",
          "targetFieldKey": "case_key"
        },
        "fields": [
          {
            "resultFieldKey": "utilization",
            "targetFieldKey": "utilization"
          },
          {
            "resultFieldKey": "passed",
            "targetFieldKey": "passed"
          }
        ]
      }
    }
  }
}
Batch 규칙계약
child identity각 case는 Batch 안에서 unique stable caseKey를 가지며 ordinary Run 하나를 생성
schedulingresource budget 안에서 bounded parallel; child completion order는 unspecified
controlchild Run별 cancel/retry; retry하지 않은 sibling state는 변경하지 않음
partial success실패·취소 case와 성공 case를 함께 보존하고 성공 ResultSnapshot을 폐기하지 않음
mergeexplicit result/field mapping과 stable caseKey 또는 result row key로만 결합

Batch result를 row index, selection order 또는 completion order로 zip하지 않습니다. accepted whole-Batch command는 connection의 projectionIntentGeneration을 한 번만 증가시키고 모든 최초 child Run이 그 값을 공유합니다. sibling child launch는 generation을 다시 증가시키지 않습니다.

Runtime Batch ledger는 (batchKey, caseKey) → currentChildRunKey를 소유합니다. 한 case를 재시도하면 그 case의 current key만 새 child Run으로 교체합니다. child completion은 shared projectionIntentGeneration이 connection의 current intent이고, 완료한 Run key가 해당 caseKeycurrentChildRunKey와 같을 때만 current projection을 교체합니다. 이전 child ResultSnapshot은 history로 유지하고 sibling Result는 invalidation하지 않습니다.

부분 실행을 지원하는 Runtime은 stable row key를 이용해 성공 fragment와 실패 진단을 구분할 수 있지만, 최종 ResultSnapshot에는 어떤 input과 row가 포함됐는지 정확히 기록해야 합니다. Report Table 연결의 source/merge 예는 Report Table 연결과 여러 case를 따릅니다.

DAG, Task와 cache

Runtime은 요청 result에 필요한 Node dependency closure를 계산합니다. 서로 의존하지 않는 Node는 bounded parallel로 실행할 수 있고, downstream Node는 필요한 upstream result가 확정된 뒤 실행합니다.

완료된 Node result는 다음 조건이 모두 같을 때만 재사용할 수 있습니다.

  • exact target release 또는 project source digest
  • Flow revision의 Node setting과 binding 의미
  • canonical input와 upstream result digest
  • type·unit 변환, seed, algorithm과 result contract
  • explicit cache policy와 실행 environment lock

nondeterministic, effectful 또는 외부 mutable 상태에 의존하는 결과는 동일성을 증명하지 못하면 재사용하지 않습니다.

Python 실행 환경 고정의 현재 범위

실행 환경의 identity는 설치 경로가 아니라 Python implementation/version/ABI/platform, Runtime 배포물 digest, 실행에 영향을 주는 파일 closure의 content digest와 전체 package pin으로 구분합니다. 직접 의존성뿐 아니라 전이 의존성의 변경도 별도 환경으로 취급합니다.

2026-09-12 현재 Core에 환경 lock의 canonical identity와 직접 의존성 대조가 추가됐습니다. Runtime host에는 명시적인 환경 파일 범위의 content 검사와 Worker 시작 전 재검사도 추가됐습니다. content 검사가 설정된 Worker는 같은 process의 Python/package metadata도 계산 소스 전달 전에 Core의 lock과 대조합니다. 내부 Run 제출에 환경 lock이 지정되면 Run과 같은 transaction에 저장하고, 재제출·Attempt 재시작에서도 최초 lock을 유지합니다. Worker는 지정 환경과 Run의 lock이 다르면 실행을 거절하며, 환경이 고정된 Component cache는 기존 환경 미지정 cache와 구분합니다. 명시적인 로컬 host 환경 설정이 있으면 자동 시작 Runtime이 배포물 digest와 환경 파일 범위를 검증하고 직접 Flow·Report connection·Batch의 Run에 같은 환경을 고정합니다. 이 설정은 host 내부 구성으로, Run 요청에서 경로나 임의 환경을 선택하는 공개 API가 아닙니다. wire 0.3.0에서는 handshake가 host의 환경 digest를 확인합니다. 로컬 host 환경 설정이 있으면 SDK는 경로를 제외한 lock을 요구 조건으로 보내고, Runtime이 Core 기준으로 비교합니다. 이미 실행 중인 supervisor라도 환경이 다르거나 설정되지 않았으면 px.Client(...)PX_RUNTIME_INCOMPATIBLE로 거절됩니다. 새 설정 파일로 기존 supervisor의 환경을 바꾸지는 않습니다. 환경 설정이 없는 Client는 이전 wire와 계속 협상할 수 있습니다. 내부에는 원본 변경과 분리된 내용 복사본을 검증·보관하는 기반도 추가됐습니다. 명시적인 내부 실행 경로는 version 2 환경 lock의 Linux/glibc CPython launch profile로 복사한 interpreter·stdlib·지정 module path·native library를 연결합니다. 실행 전과 결과 확정 전에 복사본을 검사하며, 시작 시 ambient site나 .pth 코드는 실행하지 않습니다. version 1 lock의 기존 bytes와 identity는 유지합니다. 내부 host store는 검증한 복사본과 경로를 제외한 manifest를 영속 보관하고, 원본 없이 기대한 lock으로 다시 읽습니다. 손상된 보관본을 현재 환경으로 대체하지 않으며 마지막 handle 종료 후에도 보존합니다. 로컬 SDK 자동 시작은 version 2 launch가 설정되면 authority database 파일명에 .python-environments를 붙인 host store에서 복사본을 선택합니다. 최초에는 선언한 원본을 검증·보관하며, 이후 재시작은 원본 interpreter가 삭제돼도 보관본을 다시 사용합니다. 새 Run은 시작 시 선택한 환경에 고정되고, 과거 Attempt는 자신의 pin에 해당하는 보관본을 사용합니다. 필요한 환경이 없거나 손상됐거나 현재 Runtime 배포물과 맞지 않으면 실행을 거절합니다. version 1은 기존 파일 검사와 venv 실행 경로를 유지합니다. 환경 준비/설치와 실행은 구분되며, Run 요청을 받아 패키지를 설치하지 않습니다. Project Function은 non-empty exact dependency lock을 저장할 수 있습니다. Runtime은 저장된 Function revision의 lock을 Run에 고정된 환경 inventory와 대조하고, 외부 dependency가 있으면 검증된 보관본의 고정 launch를 요구합니다. 단순 version 1 observation은 이 실행 조건을 충족하지 않습니다. 누락·버전 불일치·환경 부재는 source 실행 전에 구조화된 진단으로 거절합니다. 현재 공개 SDK에 환경 등록 API가 추가된 것은 아니며, lock 값만 제출해서 실행 권한을 얻을 수 없습니다. 임의 외부 패키지나 모든 scientific library가 이 환경에서 실행된다고 보장하지 않습니다.

중첩 Subflow도 exact revision과 semantic digest를 확인하고 그 안의 Function·Component를 동일한 material 검증 경로에 연결합니다. 같은 target의 문서는 한 번만 읽습니다. 현재 host 수집 한도는 하위 문서 1,024개와 합계 16 MiB의 JCS 문서 내용이며, evaluator와 같은 깊이 8 제한을 사용합니다. 한도 초과는 PX_RESOURCE_LIMIT으로 거절하며 일부 문서만 실행하지 않습니다. 이 한도는 실행 자원 정책이며 저장 문서 schema의 크기 제한이나 새 codec version이 아닙니다.

ResultSnapshot

ResultSnapshot은 다음을 함께 보존합니다.

  • exact Run과 Flow revision
  • resolved input digest
  • named result의 type, unit, shape와 값 또는 resource reference
  • target package·Function·Component version
  • Task·Attempt와 진단 provenance
  • partial result라면 성공·실패 범위

Result는 읽기 전용입니다. 값을 바꾸려면 source, input, Node setting 또는 binding을 수정하고 새 revision을 저장한 뒤 다시 Run합니다.

한 Run의 ResultSnapshot은 result key로 구분한 named result를 여러 개 보존할 수 있습니다. Result form은 다음 계약을 사용합니다.

result form저장·projection 계약
scalartext, integer/decimal/float, boolean, date/time/datetime, duration, enum, nullable scalarexact type·unit과 값
Recordtyped 구조체explicit stable field key와 field contract
Listlist[T]item contract와 의미 있는 순서
Tablepx.Table[Record]explicit field contract와 stable row key
artifact·binaryfile, image, PDF, model, binary datasetinline bytes 대신 immutable resource reference 가능
evidencecitation/evidence payloadschema와 source provenance를 보존하는 읽기 전용 view
calculation trace단계별 calculation tracestable step identity를 보존하는 읽기 전용 view

하나의 named result는 별도 resultMapping을 통해 여러 Report target에 projection할 수 있습니다. 반대로 하나의 Report semantic slot/field에는 active result mapping 하나만 허용됩니다. Record와 Table을 target에 표시할 때는 explicit field mapping을 사용하고, Table row는 stable row key로 결합합니다. 여러 result를 한 slot에 merge하려면 Flow/subflow가 그 합성을 수행하고 새 named result를 공개해야 합니다.

큰 Table, model, image와 binary artifact는 값을 inline으로 복제하지 않고 summary와 권한이 검사되는 resource link로 노출할 수 있습니다.

Component artifact

Component가 artifact result를 선언하면 다른 named result와 같은 Run에 속합니다. 이 절은 admission을 통과한 Component target의 result semantics이며, 현재 차단된 서드파티 Component의 install이나 execution을 활성화하지 않습니다.

생성 시점소유자
분석 모델 artifact저장된 Flow를 Run해당 Component result
image·PDF artifactComponent result 또는 명시적 export해당 Component와 ResultSnapshot provenance

Component artifact도 같은 Flow Run의 named result입니다. Report Workbench는 Flow가 public result로 공개한 호환 artifact를 reportArtifactSlot에 projection할 수 있습니다.

결과 파일과 Report 첨부의 보관

Flow 뷰어나 Report 본문에서 그림을 제거하는 것은 원본 파일의 삭제 명령이 아닙니다. 과거 Report 리비전의 본문 첨부와 attachment registry 참조는 새 리비전을 저장해도 유지하며, 다른 Project가 같은 bytes를 사용하면 각 Project의 참조를 따로 기록합니다. 첨부 참조 기록은 문서 저장·import와 함께 확정되므로 저장 실패가 새 참조만 남기지 않습니다. Report에 반영된 Run artifact도 같은 목록에 포함합니다. 슬롯에 저장한 파일 descriptor가 named result의 digest와 일치하는지 확인하고, 원본 파일을 과거 리비전 조회와 export/import에 유지합니다. 슬롯의 허용 MIME과 결과가 맞지 않으면 Report 반영은 거절하며 계산 성공이나 원래 Run 파일은 유지합니다.

현재 추가된 보관 기록은 자동 파일 회수의 완료를 뜻하지 않습니다. 기존 파일의 참조를 확인할 수 없으면 보존하며, 전체 Run/snapshot 보관과 파생 문서 자원까지 포함하는 최종 회수 연결은 후속 구현 대상입니다. 파일 digest만으로 읽기 권한이나 삭제 권한을 얻지는 않습니다.

오류와 복구

문제확인할 위치복구
Component package unavailableNode header, Project dependenciesexact target·raw settings를 read-only로 보존하고 진단 확인; 후속 activation closure 승인 뒤에만 같은 ProjectScope의 exact admitted release를 resolve
input type·unit 불일치input port, Validate panel연결 또는 input 수정
stale revisionRun plan, Save state최신 draft 검토 후 Save·Run
권한 또는 capability 부족Run detail권한·승인 경로 확인
worker 일시 오류Attempt detailretry 가능 여부 확인
큰 result 접근 실패Result resource권한과 resource expiry 확인

진단은 code, exact path, expected/current 정보와 가능한 recovery action을 가집니다. SDK, Studio와 MCP에서 문구가 달라도 같은 code와 path를 사용합니다. PX_PACKAGE_NOT_INSTALLED와 package-version recovery는 target contract 의미이며 current V1 production 서드파티 installer를 호출하라는 사용자 동작이 아닙니다.

서버 개인 가입 계정의 V1 이용 자격

서버는 개인 가입으로 생성된 계정의 새 편집·실행 요청에서 현재 V1 이용 자격을 확인합니다. 자격이 없거나 회수됐으면 PX_PERMISSION_DENIEDrequiredPermission: "activeV1Entitlement"를 반환합니다. 기존 토큰이 유효하거나 같은 command의 영수증이 있어도 이 요청 입구 검사를 건너뛰지 않습니다. requiredPermission: "authenticatedPrincipal"과 구분하며 재로그인만으로 회수된 자격이 복원된다고 해석하지 않습니다. 저장소를 확인할 수 없으면 HTTP 503으로 구분합니다.

이 검사는 Project 권한을 부여하지 않습니다. 저장된 Flow·Run 조회와 실행 취소에는 기존 membership·Project 권한 검사를 유지합니다. 개인 가입 외 계정의 제품 정책, 서명 offline lease와 공개 배포 완료는 이 검사와 별도입니다.

접수된 Run의 실행 직전 권한 확인

서버 Worker는 실행할 Task를 확보한 뒤 최초 제출자의 현재 상태와 멤버십, 개인 가입 계정의 V1 이용 자격을 다시 확인합니다. Run을 소유한 Project와 실제 Flow가 속한 Project의 run.execute 권한도 현재 시각으로 확인합니다. 대기 중 회수되거나 만료됐다면 계산을 시작하지 않고 Run을 Failed로 기록합니다. run_get의 진단으로 사유를 조회할 수 있으며 조회 자체의 권한은 필요합니다.

PX_PERMISSION_DENIEDrequiredPermission은 이용 자격이면 activeV1Entitlement, 실행 권한이면 run.execute, 제출자의 현재 상태·멤버십이면 activeRunSubmitterMembership입니다. 과거 기록에서 제출자를 알 수 없으면 authenticatedRunSubmitter로 거절하며 현재 로그인 사용자로 대체하지 않습니다. 권한 저장소를 확인할 수 없으면 PX_EXECUTION_INFRASTRUCTURE_FAILED, stage: "workerStart", reason: "authorizationUnavailable"로 실패를 기록합니다.

이 실패는 자동으로 계산을 재시도하지 않습니다. 문제를 해결한 뒤 새 실행 요청으로 진행합니다. 이미 실행 중인 계산의 강제 중단이나 이미 계산된 결과의 복구를 이 검사로 대신하지 않습니다. Report 읽기·편집·결과 반영 권한 전체를 다시 검사한다는 의미도 아니며, 기존 요청 입구와 결과 반영 경계는 유지합니다.

구현 불변식

  1. Run은 하나의 immutable Flow revision을 실행합니다.
  2. Report Workbench가 시작한 실행도 같은 ordinary Flow Run 계약을 사용합니다.
  3. ResultSnapshot은 생성 뒤 수정하지 않습니다.
  4. UI selection, canvas 좌표와 열린 modal은 실행 의미가 아닙니다.
  5. Runtime은 mutable head, local path나 비슷한 label을 target으로 추측하지 않습니다.
  6. Report result 위치는 immutable ResultSnapshot을 projection하며 editable authored value로 복사하지 않습니다.
  7. 공개 실행 단위와 실행 용어는 Run입니다.
  8. 여러 Report connection과 Batch child는 독립된 ordinary Run입니다. grouping은 dependency, completion order 또는 shared cancel/retry를 암시하지 않습니다.
  9. Report current projection은 pinned Report revision, connectionKey, mappingGeneration, target owner mappingKey, Flow revision, canonical input digest와 projectionIntentGeneration의 CAS가 exact match할 때만 교체합니다.
  10. whole Batch는 connection projection generation 하나를 공유합니다. Batch child projection은 추가로 (batchKey, caseKey)currentChildRunKey가 일치해야 하며 case retry가 sibling Result를 invalidation하지 않습니다.
  11. current V1 production의 서드파티 Component install admission과 activation은 exact ProjectScope data-path isolation만으로 열지 않고 Project authorization과 execution-trust closure가 닫힐 때까지 fail closed합니다. inactive quarantine이 없는 현재 installer를 recovery 경로로 사용하지 않습니다.

Lease expiry 뒤 settlement

Delivery renewcomplete는 current Task, owner, fence와 unexpired lease를 모두 요구합니다. Lease가 만료된 holder는 먼저 reacquire해야 하며 stale authority에 추가로 의미를 주는 검사는 reacquisition 시점의 fence 검사뿐입니다.

이어서 보기