Report와 Flow 공개 포트 연결
Report와 Flow는 서로 독립된 문서이며 Flow의 public input과 result를 경계로 연결됩니다. Report 연결은 Python SDK의 px.Report 또는 Report Workbench에서 작성할 수 있습니다.
Report 작성값과 표시 위치는 .pxreport가 소유합니다. Flow의 Node와 내부 연결은 .pxflow 또는 SDK source가 소유합니다. Runtime은 연결이 고정한 Flow revision을 실행하고 immutable ResultSnapshot을 만듭니다.
세 소유자를 구분합니다
| 소유자 | 저장하는 것 | 편집하는 화면·문법 |
|---|---|---|
| Report | 본문, 작성값·표, Flow target, input/result mapping | px.Report, Report Workbench, .pxreport |
| Flow | public input/result, Node, Node input binding | PXFLOW Studio, Python SDK |
| Runtime | Flow Run, immutable result와 provenance | Run·Result |
flow.connect(...)는 current Flow 안의 source port와 destination port를 연결합니다. Report source를 Flow input에 연결하거나 Flow result를 Report 위치에 표시하는 관계는 flow.connect(...)가 아니라 .pxreport.flowConnections에 저장합니다.
Report page setup setting
Page geometry는 Flow connection이나 Node setting이 아니라 Report마다 하나씩 가지는 closed Page setup setting입니다. Required member와 default는 다음과 같습니다.
{
"pageSize": "A4",
"orientation": "portrait",
"margins": {
"top": "18",
"right": "16",
"bottom": "18",
"left": "16"
}
}pageSize는 closed enumA4 | Letter입니다. Default는A4이고 portrait 물리 크기는 각각210 × 297 mm,215.9 × 279.4 mm입니다. V1 authority가 이름 붙인 size는 이 둘뿐입니다.orientation은 closed enumportrait | landscape이며 default는portrait입니다.landscape는 width와 height를 바꿉니다.margins는top,right,bottom,left의 closed object입니다. 각 값은 mm 단위의 RFC-003 canonicaldecimalstring이고 precision 최대 38, scale 0 이상 18 이하, 값0이상105mm 이하입니다.- Default
18/16/18/16mm는 사용자가 이미 보던 공개 output specification을 보존합니다.15mm는 production 상수가 아니라 사용자가 선택할 수 있는 범위 안의 값입니다.
0은 full-page body를 허용하면서 negative margin을 닫습니다. 105는 두 supported size 중 가장 작은 edge인 A4 210 mm의 절반이라, arbitrary printer preset을 추가하지 않고 범위를 고정하며 별도의 zero-body 검사를 의미 있게 유지합니다. 두 size, 두 orientation과 네 bounded decimal을 검사하므로 validation은 O(1)이고 precision 38/scale 18은 각 margin 연산의 자릿수를 bounded하게 합니다. 다만 좁은 body는 줄바꿈과 output page 수를 늘리므로 이 상한과 default geometry는 pagination 처리량 약속이 아니며 page-count resource budget은 별도로 fail closed합니다.
Orientation을 반영한 물리 width/height에서 마주 보는 margin 합을 뺀 body width와 height는 모두 0보다 커야 합니다. 그렇지 않으면 /pageSetup/margins의 기존 RFC-003 core diagnostic PX_RESOURCE_LIMIT으로 Page setup 전체를 거부합니다. Unknown enum, non-canonical decimal, 범위 밖 값과 non-positive body는 clamp, default fallback, 다른 size 대체 없이 저장·Run·output 전에 거부합니다. Page setup 변경은 Report revision/output 의미만 바꾸며 Flow revision, public port, mapping identity, mappingGeneration 또는 Result value를 바꾸지 않습니다.
Durable Page setup 주소는 stable workspaceKey + projectKey + reportKey와 canonical setting key page_setup으로 고정하며 revisionRef를 포함하지 않습니다. Read는 value와 opaque version을 함께 반환하고 write는 그 version을 사용하는 compare-and-set만 허용합니다. Blind overwrite는 금지합니다. Version conflict는 stored value와 사용자 draft를 모두 보존하며, 명시적 해결 전에는 retry하지 않습니다.
Flow author가 공개 포트를 정의합니다
from pipelinexlab import px
from project_functions.girder import check_resistance
flow = px.Flow(
"girder_check",
label="Girder check",
description="Checks girder demand against resistance.",
)
span = flow.input(
"span",
float,
unit="m",
description="Clear span.",
)
check = flow.node("resistance_check", check_resistance)
flow.connect(span, check.inputs.span)
flow.result(
"utilization",
check.results.utilization,
description="Demand divided by resistance.",
)| SDK 선언 | PXFLOW Studio | Report Workbench |
|---|---|---|
flow.input("span", ...) | Flow boundary의 span input | input mapping의 destination |
flow.connect(span, check.inputs.span) | Canvas의 내부 연결선 | Overview에서 읽기 전용으로 확인 |
flow.result("utilization", ...) | Flow boundary의 utilization result | result mapping의 source |
Report 연결은 SDK-linked Flow의 Python source를 수정하지 않습니다. PXFLOW-native Flow에도 Report block key나 문서 경로를 추가하지 않습니다. 두 작성 방식은 materialize된 같은 public port 계약을 Report Workbench에 제공합니다.
Report에서 두 방향을 연결합니다
Python에서는 report = px.Report(...)로 Report 객체를 만들고, connection = report.connect_flow(...)로 Connected Flow handle을 받습니다. 이 handle의 .bind()와 .show()로 두 방향을 연결합니다. Workbench의 Add Flow, Use report input, Show result도 같은 .pxreport.flowConnections를 갱신합니다.
from pipelinexlab import px
from project_flows.girder_check import flow
report = px.Report("girder_review", title="Girder review")
basis = report.section("design_basis", title="Design basis")
report_span = basis.value("span", 12.0, unit="m")
summary = report.section("summary", title="Summary")
utilization_slot = summary.result_slot("utilization", label="Utilization")
connection = report.connect_flow("strength_check", flow)
connection.bind("span_input", report_span, to=flow.inputs.span)
connection.show(
"utilization_result",
flow.results.utilization,
at=utilization_slot,
)
if __name__ == "__main__":
report.save()작성값 또는 새 Connected Table을 Flow input에 연결
새 connected table은 빈 문단의 caret에서 @로 만들고 Connection → Table mapping에서 field·row mapping을 편집합니다. 기존 ordinary 표 범위를 @로 직접 승격하는 경로는 계획 단계입니다. 기존 text나 number는 선택해 새 connected input의 초기값으로 사용할 수 있습니다. report.save() 또는 Workbench의 Save가 draft mapping을 .pxreport revision에 저장합니다.
한 connection에 여러 input mapping을 추가하면 같은 Flow Run의 input payload로 함께 전달됩니다. 한 Report source를 여러 서로 다른 Flow input에 재사용하거나, 여러 Report source를 각각 다른 Flow input에 연결할 수 있습니다. 연결을 저장해도 Flow Canvas의 Node와 내부 연결은 바뀌지 않습니다.
Flow result를 Report 위치에 표시
결과 위치는 ResultSnapshot의 값을 읽기 전용으로 projection합니다. Report authored cell에 결과를 복사해 원본처럼 저장하지 않습니다.
.pxreport.flowConnections
아래는 Report revision에서 연결 부분만 펼친 excerpt입니다. 전체 13-member root와 schemaVersion: 1 dispatch는 .pxreport top-level이 소유합니다. 연결 배열 자체는 sibling flowConnectionsSchemaVersion: 1로 독립 dispatch합니다.
{
"schemaVersion": 1,
"flowConnectionsSchemaVersion": 1,
"flowConnections": [
{
"connectionKey": "girder_check",
"mappingGeneration": 7,
"flowTarget": {
"scope": {
"kind": "project",
"workspaceKey": "structural_team",
"projectKey": "bridge_design"
},
"flowKey": "girder_check",
"revisionRef": "sha256:flow-revision-digest"
},
"inputMappings": [
{
"mappingKey": "span_input",
"portKey": "span",
"source": {
"kind": "reportValue",
"blockKey": "design_basis",
"fieldKey": "span"
}
}
],
"resultMappings": [
{
"mappingKey": "utilization_result",
"portKey": "utilization",
"target": {
"kind": "reportResultSlot",
"blockKey": "check_summary",
"slotKey": "utilization"
}
}
],
"runPolicy": "manual"
}
]
}flowConnectionsSchemaVersion의 V1 supported set은 integer [1]입니다. 값이 없거나 integer가 아니거나 지원하지 않는 버전이면 PX_SCHEMA_UNSUPPORTED_VERSION을 반환하고 원본 bytes를 보존한 read-only recovery만 허용하며 편집, 실행과 저장을 차단합니다.
runPolicy의 V1 closed set은 manual 하나뿐입니다. automatic, onChange, stale 같은 값을 추론하거나 별칭으로 받아들이지 않습니다. manual은 연결 저장·mapping 변경·Report 저장이 Run을 시작하지 않고, 사용자가 명시한 Runtime run, run_many 또는 run_batch command만 Run을 시작한다는 뜻입니다.
identity와 pin
connectionKey는 한 Report 안에서 유일한 stablelower_snake_casekey입니다.mappingKey는 해당 connection의 input/result mapping 전체에서 유일하고 각 mapping을 계속 식별하는 stablelower_snake_casekey입니다. 배열 순서를 바꾸거나 label을 고쳐도 바뀌지 않습니다. 삭제한 key를 다른 의미로 재사용하지 않습니다.- mapping을 추가·삭제하거나 source, target, port, composite field/row-key 또는 pinned Flow revision 의미를 바꾸면 connection의
mappingGeneration을 단조 증가시킵니다. flowTarget.scope는 Workspace와 Project를,flowTarget.revisionRef는 exact Flow와 immutable revision을 고정합니다.portKey는 해당 revision이 공개한 exact input 또는 result key입니다.blockKey,fieldKey,tableKey,rowKeys와slotKey는 Report direct object의 stable semantic key입니다.- 화면 label, A1 좌표, DOM path, 현재 selection과 배열 순서를 identity로 사용하지 않습니다.
input source closed union
source.kind | 필요한 semantic address | 전달하는 값 |
|---|---|---|
reportValue | blockKey, fieldKey; Record이면 explicit source→input fields | number, text, bool, date/time, duration, enum 등 typed scalar, typed Record 또는 typed List 하나 |
reportTableSelection | tableKey, stable rowKeys, explicit source→input fields와 row-key mapping | typed Table 하나 |
reportAttachment | attachmentKey | file, binary 또는 artifact reference |
reportValue의 List는 declared item contract와 순서를 보존합니다. Record와 Table은 이름이나 column 순서로 field를 맞추지 않습니다. 각 source field와 Flow input field를 명시적으로 연결하고, Table은 source row key가 input Record의 어느 stable row-key field가 되는지도 저장합니다.
{
"mappingKey": "load_cases_input",
"portKey": "cases",
"source": {
"kind": "reportTableSelection",
"tableKey": "design_loads",
"rowKeys": ["uls_01", "uls_02"],
"rowKey": {
"sourceFieldKey": "case_key",
"inputFieldKey": "case_key"
},
"fields": [
{
"sourceFieldKey": "permanent_load",
"inputFieldKey": "permanent_g"
},
{
"sourceFieldKey": "variable_load",
"inputFieldKey": "variable_q"
}
]
}
}Attachment source는 Report attachment owner의 stable key만 참조합니다. media type, size와 content digest는 attachment record가 소유합니다.
{
"mappingKey": "analysis_model_input",
"portKey": "model_file",
"source": {
"kind": "reportAttachment",
"attachmentKey": "analysis_model"
}
}result target closed union
target.kind | 필요한 semantic address | 표시 방식 |
|---|---|---|
reportResultSlot | blockKey, slotKey; Record이면 explicit result→target fields | scalar, typed Record 또는 typed List의 inline/block projection |
reportTableResult | tableKey, explicit result→target fields와 stable row-key mapping | 읽기 전용 result table |
reportArtifactSlot | blockKey, slotKey | file·image·PDF·model·binary, evidence 또는 calculation trace의 읽기 전용 resource projection |
Record와 Table result의 field/row-key shape는 다음과 같습니다. fields를 생략하거나 현재 column 순서로 대응시키지 않습니다.
[
{
"mappingKey": "summary_record_result",
"portKey": "summary",
"target": {
"kind": "reportResultSlot",
"blockKey": "check_summary",
"slotKey": "summary",
"fields": [
{
"resultFieldKey": "utilization",
"targetFieldKey": "utilization"
},
{
"resultFieldKey": "passed",
"targetFieldKey": "passed"
}
]
}
},
{
"mappingKey": "checks_table_result",
"portKey": "checks",
"target": {
"kind": "reportTableResult",
"tableKey": "check_results",
"rowKey": {
"resultFieldKey": "case_key",
"targetFieldKey": "case_key"
},
"fields": [
{
"resultFieldKey": "utilization",
"targetFieldKey": "utilization"
},
{
"resultFieldKey": "passed",
"targetFieldKey": "passed"
}
]
}
}
]inputMappings와 resultMappings에는 value bytes를 복제하지 않습니다. input 값은 Report block/cell이, result 값은 immutable ResultSnapshot이 각각 소유합니다.
각 immutable .pxreport revision은 같은 revision의 inputProjections에 source 쪽 typed 값을 함께 저장합니다. root는 reportValues, reportTables, reportAttachments 세 map으로 닫혀 있습니다. Table projection은 Table/Record type, Record field descriptor와 row-key를 담은 typeDefinitions, complete row value를 포함하고, attachment projection은 artifact type, filesystem CAS의 RFC-002 PublicDigestRef value, mediaType, supervisor가 잰 size를 포함합니다. Python은 connection이 가리키는 이 exact source projection을 그대로 인증된 제품 경로에 보내며 destination Flow type을 source type으로 대체하지 않습니다. Core만 exact saved Flow revision과 field/row-key/type/unit을 한 번 비교하고, 일치한 뒤 ordinary RunInputPayload를 만들어 filesystem CAS에 저장합니다.
입력의 원본은 values의 typed value, tables의 table과 명시적 cell override, attachments의 CAS 참조입니다. 본문에 배치된 동일 입력 field·table·attachment는 이 원본과 같은 값을 표시해야 합니다. 일반 본문 텍스트와 결과 projection을 입력으로 추측하지 않습니다. Core는 최종 저장 revision과 파일 decode에서 표시값·원본· inputProjections의 일치를 검사하며, 불일치한 파일을 임의로 보정하지 않습니다. UpsertReportValue와 SetReportTableCells는 해당 본문 표시도 함께 갱신합니다. 본문과 입력을 함께 바꾸는 명령 묶음은 최종 상태에서 검사하고 원자적으로 적용합니다.
{
"inputProjections": {
"reportValues": {},
"reportTables": {
"design_loads": {
"type": {
"kind": "table",
"row": { "kind": "record", "recordKey": "design_loads" }
},
"typeDefinitions": {
"records": [
{
"recordKey": "design_loads",
"fields": [
{
"fieldKey": "case_key",
"type": { "kind": "string" },
"required": true,
"nullable": false
},
{
"fieldKey": "permanent_load",
"type": { "kind": "float64" },
"required": true,
"nullable": false
}
],
"rowKeyField": "case_key"
}
]
},
"value": [
{ "case_key": "uls_01", "permanent_load": 860.0 }
]
}
},
"reportAttachments": {
"analysis_model": {
"type": { "kind": "artifact" },
"value": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"mediaType": "application/pdf",
"size": 2048
}
}
}
}mapping cardinality
Input mapping의 cardinality는 한 Run에 들어가는 exact Flow input을 기준으로 검증합니다.
| 구성 | 허용 여부 | 계약 |
|---|---|---|
| Report source 하나 → 서로 다른 Flow input 여러 개 | 허용 | 같은/다른 connection의 input마다 별도 inputMapping과 stable mappingKey를 저장 |
| Report source 여러 개 → 서로 다른 Flow input | 허용 | 같은 connection의 한 input payload로 materialize |
| active source 여러 개 → 같은 Flow input 하나 | 금지 | mapping 배열 순서로 덮어쓰기·merge하지 않음 |
| scalar 여러 개 → 하나의 composite input | 직접 fan-in 금지 | explicit Record/List/Table source를 만들거나 Flow/subflow 안에서 조합 |
한 Flow input에는 한 Run 기준 active producer가 정확히 하나여야 합니다. 저장된 mapping과 명시적 Run-time input도 같은 port에 동시에 값을 제공할 수 없습니다.
Result mapping의 cardinality는 Report semantic target slot/field를 기준으로 검증합니다.
| 구성 | 허용 여부 | 계약 |
|---|---|---|
| Run 하나 → named result 여러 개 | 허용 | 한 ResultSnapshot이 여러 result를 이름으로 보존 |
| named result 하나 → Report target 여러 개 | 허용 | target마다 별도 resultMapping과 stable mappingKey를 저장 |
| active result 여러 개 → 같은 Report slot/field | 금지 | 일반 slot은 연결 시 검증; 표는 아래의 실제 행·열 규칙 적용 |
| Record/Table result → composite target | 조건부 허용 | field mapping을 모두 명시하고 Table은 stable row-key mapping도 명시 |
따라서 같은 result를 요약 block과 상세 표에 각각 표시할 수 있습니다. 일반 slot은 Report 전체에서 단일 mapping 소유권을 유지합니다. 표의 서로 다른 connection은 열을 공유해도 실제 행이 다르면 각각 적용할 수 있으며, 같은 행의 서로 다른 값 열도 공유 식별 열을 보존하며 적용합니다. 동시에 실행한 결과가 같은 셀을 바꾸면 먼저 적용된 값을 보존하고 뒤의 적용을 거절합니다. 최신 보고서를 확인하고 명시적으로 다시 실행하는 경우는 새로운 적용 요청입니다. 한 connection 내부의 중복 목적지 mapping은 계속 금지합니다. 여러 result를 하나의 표시값으로 합쳐야 하면 Flow/subflow에서 명시적으로 합성한 named result를 공개합니다.
실행 순서
한 flowConnection의 모든 mapping은 같은 ordinary Flow Run을 공유합니다. 다른 connection은 각각 독립된 ordinary Run을 만듭니다. 한 사용자 동작으로 여러 connection을 시작하면 Runtime은 resource budget 안에서 bounded parallel로 실행할 수 있으며 완료 순서는 지정되지 않습니다. Report Activity는 독립 Run을 한곳에 표시하는 grouping일 뿐 실행 owner, dependency·ordering, transaction 또는 merge boundary가 아닙니다. 각 Run은 따로 취소하고 재시도합니다.
Report는 connection 배열 순서, 화면 위치 또는 result mapping을 근거로 connection 사이의 dependency나 실행 순서를 추론하지 않습니다. 한 계산이 다른 계산의 result를 필요로 하면 그 dependency를 하나의 Flow 또는 명시적 subflow composition 안에 만들고 하나의 public boundary로 Report에 공개합니다.
source 값, Flow revision 또는 mapping이 바뀌면 기존 projection은 Stale로 표시합니다. 새 Run이 완료될 때까지 마지막 accepted Result와 provenance를 읽기 전용으로 유지합니다.
Run isolation과 current projection
Report connection에서 만든 Run은 다음 intent를 실행 시작 시점에 고정합니다.
| pinned intent 항목 | exact identity |
|---|---|
| Report | immutable reportRevisionRef |
| connection과 mappings | connectionKey + exact mappingGeneration; 각 target owner는 stable mappingKey로 식별 |
| Flow | immutable flowTarget.revisionRef |
| materialized inputs | type·unit·shape와 composite key를 포함한 canonical input digest |
| command | Project scope의 idempotency key인 commandId |
| projection intent | accepted single-Run 또는 whole-Batch command마다 한 번 증가하는 projectionIntentGeneration |
| Batch child | batchKey, stable caseKey와 그 case의 current childRunKey |
projectionIntentGeneration은 .pxreport field가 아닙니다. Runtime projection ledger가 (reportKey, connectionKey)별 current projection intent로 소유하며, application service는 commandId idempotency 확인과 새 generation 등록을 하나의 원자적 transaction으로 처리합니다.
canonical digest는 Flow input portKey 순으로 canonicalize한 type·unit·shape·value/reference와 Record field key, List 순서, Table stable row key·mapped field를 포함합니다. 현재 화면 selection, Table 표시 정렬 또는 mapping JSON 배열 순서는 digest 의미가 아닙니다. typed List의 semantic item 순서는 input 의미와 digest에 포함됩니다.
같은 launch identity와 commandId를 그대로 재전송하는 transport retry는 idempotent하며 같은 Run을 돌려줍니다. 같은 commandId에 다른 identity/payload를 보내면 conflict로 거부합니다. 사용자가 같은 connection에서 Run again을 선택하면 input과 revision이 같더라도 새 commandId, 새 Run과 새 projectionIntentGeneration을 current intent로 기록합니다.
각 result target의 current projection은 위 pinned intent를 expected value로 사용하는 CAS로만 교체합니다. completion 시 현재 Report의 target owner mappingKey, mappingGeneration과 이 Run의 projectionIntentGeneration까지 모두 exact match해야 합니다. 늦게 도착한 이전 Run의 ResultSnapshot은 immutable history로 남지만 이 CAS가 실패하면 현재 projection을 덮어쓸 수 없습니다. 실행과 결과의 isolation 계약을 따릅니다.
Table과 여러 case
| Report source | Flow input | 실행 |
|---|---|---|
| cell 하나 | scalar | 값 하나로 Flow Run 1회 |
| N rows × 1 field | list[T] 또는 호환 Table | collection 하나로 Flow Run 1회 |
| N rows × M fields | px.Table[Record] | Table 값 하나로 Flow Run 1회 |
| N rows × 1 field | scalar | 연결 전 shape 오류 |
Table selection과 List는 collection 값 하나입니다. 행·item 수와 관계없이 ordinary Run 하나를 만들며, 행 수만큼 Node, connection 또는 Run을 자동 생성하지 않습니다.
여러 scalar case를 각각 실행하려면 사용자가 Batch Run을 명시적으로 만듭니다. Batch는 stable caseKey를 가진 ordinary child Run들의 grouping이며, 각 child는 같은 pinned Flow revision에 case별 input을 전달합니다. child Run은 bounded parallel로 실행될 수 있고 완료 순서는 지정되지 않으며, 독립적으로 취소·재시도됩니다. 일부 child가 실패해도 성공 child의 ResultSnapshot은 보존하는 partial success가 가능합니다. result merge는 실행 전에 선언한 caseKey 또는 result Table의 stable row key와 explicit field mapping으로만 수행하며, row index나 완료 순서로 zip하지 않습니다.
accepted whole-Batch command는 connection의 projectionIntentGeneration을 한 번만 증가시키고 모든 최초 child Run이 그 값을 공유합니다. Runtime Batch ledger는 (batchKey, caseKey) → currentChildRunKey를 소유합니다. 한 case를 retry하면 해당 key만 새 child Run으로 바꾸며 sibling intent는 유지합니다. child Result는 shared generation이 여전히 connection의 current intent이고 완료한 Run이 해당 case의 currentChildRunKey일 때만 current projection에 merge됩니다. 자세한 계약은 Report Table 연결과 여러 case를 따릅니다.
검증
저장 전 다음 조건을 함께 확인합니다.
connectionKey와 각 stablemappingKey가 유일하고mappingGeneration이 유효합니다.- exact Flow revision과 public port가 존재합니다.
- source와 input의 type·unit·shape·nullability가 호환됩니다.
- required Flow input에 mapping 또는 명시적 Run-time input이 있습니다.
- result type과 Report target presentation이 호환됩니다.
- 한 Flow input을 두 active source가 동시에 소유하지 않습니다.
- 한 Report semantic target slot/field를 두 active result mapping이 동시에 소유하지 않습니다. 표에서는 semantic target을
tableKey × rowKey × fieldKey로 판정합니다. 서로 다른 connection이 같은 표를 연결할 수 있지만 row identity field는 일치해야 합니다. 실제 결과 행이 정해진 뒤 Runtime이 목적지 셀과 출처를 비교합니다. 다른 행·열과 본문 변경은 보존하고, 실행 접수 후 같은 목적지·입력·매핑·Flow pin이 변경되거나 연결이 삭제되면 늦은 결과를 적용하지 않습니다. Batch도 initial revision의 Report 입력과 해당 case 목적지를 기준으로 검사합니다. 거절해도 immutable 실행 snapshot은 남습니다. 최신 Report를 다시 열어 변경을 확인한 뒤 명시적으로 재실행하며, 자동 병합하거나 마지막 완료 결과를 무조건 선택하지 않습니다. 일반 슬롯과 한 연결 내부 중복 매핑 금지는 그대로입니다..pxreportroot와 connection schema version은 바뀌지 않습니다. - Record/Table field mapping과 stable row-key mapping이 완전합니다.
- 현재 principal에게 Report edit, Flow read/run과 Result read 권한이 있습니다.
| 상태 | Report Workbench 동작 |
|---|---|
| Flow 또는 public port 변경 | 영향받는 mapping과 exact target을 보여 주고 Review update |
| type·unit·shape 불일치 | source와 port 계약을 나란히 보여 주고 호환 후보 선택 |
| 권한 필요 | 연결 위치를 보존하고 Request access |
| revision을 찾지 못함 | 마지막 verified contract를 읽기 전용으로 유지하고 Choose revision |
| stale result | 바뀐 source 또는 Flow를 표시하고 Run again |
비슷한 label의 다른 Flow나 port로 자동 재연결하지 않습니다.
SDK-linked와 PXFLOW-native
| Flow 작성 방식 | Flow owner | Report 연결 owner |
|---|---|---|
| SDK-linked | Python source + lock | .pxreport.flowConnections |
| PXFLOW-native | .pxflow | .pxreport.flowConnections |
Report에서 mapping을 편집할 때 Flow source를 생성하거나 수정하지 않습니다. Flow public port 계약을 변경할 때는 owning Flow source 또는 .pxflow를 수정하고 새 revision을 저장한 뒤, 연결된 Report의 영향을 검토합니다.
AI·MCP command
AI와 MCP는 Report Workbench와 같은 typed command를 사용합니다.
SetReportFlowInputSource
SetReportFlowResultTarget
RemoveReportFlowMapping
RunReportFlowConnection
RunReportFlowBatchApply 전 preview에 Report source, Flow destination, type·unit·shape, exact revision과 영향받는 Report 위치를 표시합니다. 화면 좌표나 label 유사도로 target을 추측하지 않습니다.